Merge "Add thread safety analysis annotations."
diff --git a/adb/Android.mk b/adb/Android.mk
index 1f6f194..ae03593 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -350,11 +350,11 @@
-D_GNU_SOURCE \
-Wno-deprecated-declarations \
+LOCAL_CFLAGS += -DALLOW_ADBD_ROOT=$(if $(filter userdebug eng,$(TARGET_BUILD_VARIANT)),1,0)
LOCAL_CFLAGS += -DALLOW_ADBD_NO_AUTH=$(if $(filter userdebug eng,$(TARGET_BUILD_VARIANT)),1,0)
ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
LOCAL_CFLAGS += -DALLOW_ADBD_DISABLE_VERITY=1
-LOCAL_CFLAGS += -DALLOW_ADBD_ROOT=1
endif
LOCAL_MODULE := adbd
diff --git a/adb/daemon/main.cpp b/adb/daemon/main.cpp
index 1c94298..e0629ab 100644
--- a/adb/daemon/main.cpp
+++ b/adb/daemon/main.cpp
@@ -49,17 +49,23 @@
static const char* root_seclabel = nullptr;
+static inline bool is_device_unlocked() {
+ return "orange" == android::base::GetProperty("ro.boot.verifiedbootstate", "");
+}
+
static void drop_capabilities_bounding_set_if_needed(struct minijail *j) {
-#if defined(ALLOW_ADBD_ROOT)
- if (__android_log_is_debuggable()) {
- return;
+ if (ALLOW_ADBD_ROOT || is_device_unlocked()) {
+ if (__android_log_is_debuggable()) {
+ return;
+ }
}
-#endif
minijail_capbset_drop(j, CAP_TO_MASK(CAP_SETUID) | CAP_TO_MASK(CAP_SETGID));
}
static bool should_drop_privileges() {
-#if defined(ALLOW_ADBD_ROOT)
+ // "adb root" not allowed, always drop privileges.
+ if (!ALLOW_ADBD_ROOT && !is_device_unlocked()) return true;
+
// The properties that affect `adb root` and `adb unroot` are ro.secure and
// ro.debuggable. In this context the names don't make the expected behavior
// particularly obvious.
@@ -89,9 +95,6 @@
}
return drop;
-#else
- return true; // "adb root" not allowed, always drop privileges.
-#endif // ALLOW_ADBD_ROOT
}
static void drop_privileges(int server_port) {
@@ -158,7 +161,10 @@
// descriptor will always be open.
adbd_cloexec_auth_socket();
- if (ALLOW_ADBD_NO_AUTH && !android::base::GetBoolProperty("ro.adb.secure", false)) {
+ // Respect ro.adb.secure in userdebug/eng builds (ALLOW_ADBD_NO_AUTH), or when the
+ // device is unlocked.
+ if ((ALLOW_ADBD_NO_AUTH || is_device_unlocked()) &&
+ !android::base::GetBoolProperty("ro.adb.secure", false)) {
auth_required = false;
}
diff --git a/debuggerd/crasher/crasher.cpp b/debuggerd/crasher/crasher.cpp
index 6970201..f57349b 100644
--- a/debuggerd/crasher/crasher.cpp
+++ b/debuggerd/crasher/crasher.cpp
@@ -134,6 +134,14 @@
free(buf); // GCC is smart enough to warn about this, but we're doing it deliberately.
}
+noinline void leak() {
+ while (true) {
+ void* mapping =
+ mmap(nullptr, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ static_cast<volatile char*>(mapping)[0] = 'a';
+ }
+}
+
noinline void sigsegv_non_null() {
int* a = (int *)(&do_action);
*a = 42;
@@ -160,8 +168,8 @@
fprintf(stderr, " stack-overflow recurse until the stack overflows\n");
fprintf(stderr, " nostack crash with a NULL stack pointer\n");
fprintf(stderr, "\n");
- fprintf(stderr, " heap-corruption cause a libc abort by corrupting the heap\n");
fprintf(stderr, " heap-usage cause a libc abort by abusing a heap function\n");
+ fprintf(stderr, " leak leak memory until we get OOM-killed\n");
fprintf(stderr, "\n");
fprintf(stderr, " abort call abort()\n");
fprintf(stderr, " assert call assert() without a function\n");
@@ -265,6 +273,8 @@
return pthread_join(0, nullptr);
} else if (!strcasecmp(arg, "heap-usage")) {
abuse_heap();
+ } else if (!strcasecmp(arg, "leak")) {
+ leak();
} else if (!strcasecmp(arg, "SIGSEGV-unmapped")) {
char* map = reinterpret_cast<char*>(mmap(nullptr, sizeof(int), PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0));
diff --git a/debuggerd/libdebuggerd/test/tombstone_test.cpp b/debuggerd/libdebuggerd/test/tombstone_test.cpp
index 325210d..6be59e7 100644
--- a/debuggerd/libdebuggerd/test/tombstone_test.cpp
+++ b/debuggerd/libdebuggerd/test/tombstone_test.cpp
@@ -220,21 +220,21 @@
map.start = 0xa434000;
map.end = 0xa435000;
map.offset = 0x1000;
- map.load_base = 0xd000;
+ map.load_bias = 0xd000;
map.flags = PROT_WRITE;
map_mock_->AddMap(map);
map.start = 0xa534000;
map.end = 0xa535000;
map.offset = 0x3000;
- map.load_base = 0x2000;
+ map.load_bias = 0x2000;
map.flags = PROT_EXEC;
map_mock_->AddMap(map);
map.start = 0xa634000;
map.end = 0xa635000;
map.offset = 0;
- map.load_base = 0;
+ map.load_bias = 0;
map.flags = PROT_READ | PROT_WRITE | PROT_EXEC;
map.name = "/system/lib/fake.so";
map_mock_->AddMap(map);
@@ -244,20 +244,20 @@
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
- const char* expected_dump = \
-"\nmemory map:\n"
+ const char* expected_dump =
+ "\nmemory map:\n"
#if defined(__LP64__)
-" 00000000'0a234000-00000000'0a234fff --- 0 1000\n"
-" 00000000'0a334000-00000000'0a334fff r-- f000 1000\n"
-" 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load base 0xd000)\n"
-" 00000000'0a534000-00000000'0a534fff --x 3000 1000 (load base 0x2000)\n"
-" 00000000'0a634000-00000000'0a634fff rwx 0 1000 /system/lib/fake.so\n";
+ " 00000000'0a234000-00000000'0a234fff --- 0 1000\n"
+ " 00000000'0a334000-00000000'0a334fff r-- f000 1000\n"
+ " 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load bias 0xd000)\n"
+ " 00000000'0a534000-00000000'0a534fff --x 3000 1000 (load bias 0x2000)\n"
+ " 00000000'0a634000-00000000'0a634fff rwx 0 1000 /system/lib/fake.so\n";
#else
-" 0a234000-0a234fff --- 0 1000\n"
-" 0a334000-0a334fff r-- f000 1000\n"
-" 0a434000-0a434fff -w- 1000 1000 (load base 0xd000)\n"
-" 0a534000-0a534fff --x 3000 1000 (load base 0x2000)\n"
-" 0a634000-0a634fff rwx 0 1000 /system/lib/fake.so\n";
+ " 0a234000-0a234fff --- 0 1000\n"
+ " 0a334000-0a334fff r-- f000 1000\n"
+ " 0a434000-0a434fff -w- 1000 1000 (load bias 0xd000)\n"
+ " 0a534000-0a534fff --x 3000 1000 (load bias 0x2000)\n"
+ " 0a634000-0a634fff rwx 0 1000 /system/lib/fake.so\n";
#endif
ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
@@ -274,21 +274,21 @@
map.start = 0xa434000;
map.end = 0xa435000;
map.offset = 0x1000;
- map.load_base = 0xd000;
+ map.load_bias = 0xd000;
map.flags = PROT_WRITE;
map_mock_->AddMap(map);
map.start = 0xa534000;
map.end = 0xa535000;
map.offset = 0x3000;
- map.load_base = 0x2000;
+ map.load_bias = 0x2000;
map.flags = PROT_EXEC;
map_mock_->AddMap(map);
map.start = 0xa634000;
map.end = 0xa635000;
map.offset = 0;
- map.load_base = 0;
+ map.load_bias = 0;
map.flags = PROT_READ | PROT_WRITE | PROT_EXEC;
map.name = "/system/lib/fake.so";
map_mock_->AddMap(map);
@@ -304,18 +304,18 @@
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
- const char* expected_dump = \
-"\nmemory map: (fault address prefixed with --->)\n"
+ const char* expected_dump =
+ "\nmemory map: (fault address prefixed with --->)\n"
#if defined(__LP64__)
-"--->Fault address falls at 00000000'00001000 before any mapped regions\n"
-" 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load base 0xd000)\n"
-" 00000000'0a534000-00000000'0a534fff --x 3000 1000 (load base 0x2000)\n"
-" 00000000'0a634000-00000000'0a634fff rwx 0 1000 /system/lib/fake.so\n";
+ "--->Fault address falls at 00000000'00001000 before any mapped regions\n"
+ " 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load bias 0xd000)\n"
+ " 00000000'0a534000-00000000'0a534fff --x 3000 1000 (load bias 0x2000)\n"
+ " 00000000'0a634000-00000000'0a634fff rwx 0 1000 /system/lib/fake.so\n";
#else
-"--->Fault address falls at 00001000 before any mapped regions\n"
-" 0a434000-0a434fff -w- 1000 1000 (load base 0xd000)\n"
-" 0a534000-0a534fff --x 3000 1000 (load base 0x2000)\n"
-" 0a634000-0a634fff rwx 0 1000 /system/lib/fake.so\n";
+ "--->Fault address falls at 00001000 before any mapped regions\n"
+ " 0a434000-0a434fff -w- 1000 1000 (load bias 0xd000)\n"
+ " 0a534000-0a534fff --x 3000 1000 (load bias 0x2000)\n"
+ " 0a634000-0a634fff rwx 0 1000 /system/lib/fake.so\n";
#endif
ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
@@ -332,21 +332,21 @@
map.start = 0xa434000;
map.end = 0xa435000;
map.offset = 0x1000;
- map.load_base = 0xd000;
+ map.load_bias = 0xd000;
map.flags = PROT_WRITE;
map_mock_->AddMap(map);
map.start = 0xa534000;
map.end = 0xa535000;
map.offset = 0x3000;
- map.load_base = 0x2000;
+ map.load_bias = 0x2000;
map.flags = PROT_EXEC;
map_mock_->AddMap(map);
map.start = 0xa634000;
map.end = 0xa635000;
map.offset = 0;
- map.load_base = 0;
+ map.load_bias = 0;
map.flags = PROT_READ | PROT_WRITE | PROT_EXEC;
map.name = "/system/lib/fake.so";
map_mock_->AddMap(map);
@@ -362,18 +362,18 @@
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
- const char* expected_dump = \
-"\nmemory map: (fault address prefixed with --->)\n"
+ const char* expected_dump =
+ "\nmemory map: (fault address prefixed with --->)\n"
#if defined(__LP64__)
-" 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load base 0xd000)\n"
-"--->Fault address falls at 00000000'0a533000 between mapped regions\n"
-" 00000000'0a534000-00000000'0a534fff --x 3000 1000 (load base 0x2000)\n"
-" 00000000'0a634000-00000000'0a634fff rwx 0 1000 /system/lib/fake.so\n";
+ " 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load bias 0xd000)\n"
+ "--->Fault address falls at 00000000'0a533000 between mapped regions\n"
+ " 00000000'0a534000-00000000'0a534fff --x 3000 1000 (load bias 0x2000)\n"
+ " 00000000'0a634000-00000000'0a634fff rwx 0 1000 /system/lib/fake.so\n";
#else
-" 0a434000-0a434fff -w- 1000 1000 (load base 0xd000)\n"
-"--->Fault address falls at 0a533000 between mapped regions\n"
-" 0a534000-0a534fff --x 3000 1000 (load base 0x2000)\n"
-" 0a634000-0a634fff rwx 0 1000 /system/lib/fake.so\n";
+ " 0a434000-0a434fff -w- 1000 1000 (load bias 0xd000)\n"
+ "--->Fault address falls at 0a533000 between mapped regions\n"
+ " 0a534000-0a534fff --x 3000 1000 (load bias 0x2000)\n"
+ " 0a634000-0a634fff rwx 0 1000 /system/lib/fake.so\n";
#endif
ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
@@ -390,21 +390,21 @@
map.start = 0xa434000;
map.end = 0xa435000;
map.offset = 0x1000;
- map.load_base = 0xd000;
+ map.load_bias = 0xd000;
map.flags = PROT_WRITE;
map_mock_->AddMap(map);
map.start = 0xa534000;
map.end = 0xa535000;
map.offset = 0x3000;
- map.load_base = 0x2000;
+ map.load_bias = 0x2000;
map.flags = PROT_EXEC;
map_mock_->AddMap(map);
map.start = 0xa634000;
map.end = 0xa635000;
map.offset = 0;
- map.load_base = 0;
+ map.load_bias = 0;
map.flags = PROT_READ | PROT_WRITE | PROT_EXEC;
map.name = "/system/lib/fake.so";
map_mock_->AddMap(map);
@@ -420,16 +420,16 @@
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
- const char* expected_dump = \
-"\nmemory map: (fault address prefixed with --->)\n"
+ const char* expected_dump =
+ "\nmemory map: (fault address prefixed with --->)\n"
#if defined(__LP64__)
-" 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load base 0xd000)\n"
-"--->00000000'0a534000-00000000'0a534fff --x 3000 1000 (load base 0x2000)\n"
-" 00000000'0a634000-00000000'0a634fff rwx 0 1000 /system/lib/fake.so\n";
+ " 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load bias 0xd000)\n"
+ "--->00000000'0a534000-00000000'0a534fff --x 3000 1000 (load bias 0x2000)\n"
+ " 00000000'0a634000-00000000'0a634fff rwx 0 1000 /system/lib/fake.so\n";
#else
-" 0a434000-0a434fff -w- 1000 1000 (load base 0xd000)\n"
-"--->0a534000-0a534fff --x 3000 1000 (load base 0x2000)\n"
-" 0a634000-0a634fff rwx 0 1000 /system/lib/fake.so\n";
+ " 0a434000-0a434fff -w- 1000 1000 (load bias 0xd000)\n"
+ "--->0a534000-0a534fff --x 3000 1000 (load bias 0x2000)\n"
+ " 0a634000-0a634fff rwx 0 1000 /system/lib/fake.so\n";
#endif
ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
@@ -446,21 +446,21 @@
map.start = 0xa434000;
map.end = 0xa435000;
map.offset = 0x1000;
- map.load_base = 0xd000;
+ map.load_bias = 0xd000;
map.flags = PROT_WRITE;
map_mock_->AddMap(map);
map.start = 0xa534000;
map.end = 0xa535000;
map.offset = 0x3000;
- map.load_base = 0x2000;
+ map.load_bias = 0x2000;
map.flags = PROT_EXEC;
map_mock_->AddMap(map);
map.start = 0xa634000;
map.end = 0xa635000;
map.offset = 0;
- map.load_base = 0;
+ map.load_bias = 0;
map.flags = PROT_READ | PROT_WRITE | PROT_EXEC;
map.name = "/system/lib/fake.so";
map_mock_->AddMap(map);
@@ -480,18 +480,18 @@
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
- const char* expected_dump = \
-"\nmemory map: (fault address prefixed with --->)\n"
+ const char* expected_dump =
+ "\nmemory map: (fault address prefixed with --->)\n"
#if defined(__LP64__)
-" 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load base 0xd000)\n"
-" 00000000'0a534000-00000000'0a534fff --x 3000 1000 (load base 0x2000)\n"
-" 00000000'0a634000-00000000'0a634fff rwx 0 1000 /system/lib/fake.so\n"
-"--->Fault address falls at 00001234'5a534040 after any mapped regions\n";
+ " 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load bias 0xd000)\n"
+ " 00000000'0a534000-00000000'0a534fff --x 3000 1000 (load bias 0x2000)\n"
+ " 00000000'0a634000-00000000'0a634fff rwx 0 1000 /system/lib/fake.so\n"
+ "--->Fault address falls at 00001234'5a534040 after any mapped regions\n";
#else
-" 0a434000-0a434fff -w- 1000 1000 (load base 0xd000)\n"
-" 0a534000-0a534fff --x 3000 1000 (load base 0x2000)\n"
-" 0a634000-0a634fff rwx 0 1000 /system/lib/fake.so\n"
-"--->Fault address falls at 0f534040 after any mapped regions\n";
+ " 0a434000-0a434fff -w- 1000 1000 (load bias 0xd000)\n"
+ " 0a534000-0a534fff --x 3000 1000 (load bias 0x2000)\n"
+ " 0a634000-0a634fff rwx 0 1000 /system/lib/fake.so\n"
+ "--->Fault address falls at 0f534040 after any mapped regions\n";
#endif
ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
@@ -508,7 +508,7 @@
map.start = 0xa434000;
map.end = 0xa435000;
map.offset = 0x1000;
- map.load_base = 0xd000;
+ map.load_bias = 0xd000;
map.flags = PROT_WRITE;
map_mock_->AddMap(map);
@@ -520,12 +520,12 @@
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
- const char* expected_dump = \
-"\nmemory map:\n"
+ const char* expected_dump =
+ "\nmemory map:\n"
#if defined(__LP64__)
-" 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load base 0xd000)\n";
+ " 00000000'0a434000-00000000'0a434fff -w- 1000 1000 (load bias 0xd000)\n";
#else
-" 0a434000-0a434fff -w- 1000 1000 (load base 0xd000)\n";
+ " 0a434000-0a434fff -w- 1000 1000 (load bias 0xd000)\n";
#endif
ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index 996d714..0113131 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -466,11 +466,11 @@
line += " (BuildId: " + build_id + ")";
}
}
- if (it->load_base != 0) {
+ if (it->load_bias != 0) {
if (space_needed) {
line += ' ';
}
- line += StringPrintf(" (load base 0x%" PRIxPTR ")", it->load_base);
+ line += StringPrintf(" (load bias 0x%" PRIxPTR ")", it->load_bias);
}
_LOG(log, logtype::MAPS, "%s\n", line.c_str());
}
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index 80def73..dd8bad9 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -40,6 +40,7 @@
LOCAL_MODULE_TAGS := debug
LOCAL_MODULE_HOST_OS := darwin linux windows
LOCAL_CFLAGS += -Wall -Wextra -Werror -Wunreachable-code
+LOCAL_REQUIRED_MODULES := mke2fs e2fsdroid
LOCAL_SRC_FILES_linux := usb_linux.cpp
LOCAL_STATIC_LIBRARIES_linux := libselinux
@@ -85,6 +86,8 @@
include $(BUILD_HOST_EXECUTABLE)
my_dist_files := $(LOCAL_BUILT_MODULE)
+my_dist_files += $(HOST_OUT_EXECUTABLES)/mke2fs$(HOST_EXECUTABLE_SUFFIX)
+my_dist_files += $(HOST_OUT_EXECUTABLES)/e2fsdroid$(HOST_EXECUTABLE_SUFFIX)
ifeq ($(HOST_OS),linux)
my_dist_files += $(HOST_LIBRARY_PATH)/libf2fs_fmt_host_dyn$(HOST_SHLIB_SUFFIX)
endif
diff --git a/fastboot/fs.cpp b/fastboot/fs.cpp
index 99ca7dd..f3c000e 100644
--- a/fastboot/fs.cpp
+++ b/fastboot/fs.cpp
@@ -10,14 +10,22 @@
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
+#ifndef WIN32
+#include <sys/wait.h>
+#endif
#include <unistd.h>
+#include <vector>
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
#include <android-base/unique_fd.h>
#include <ext4_utils/make_ext4fs.h>
#include <sparse/sparse.h>
+using android::base::StringPrintf;
using android::base::unique_fd;
+#ifdef WIN32
static int generate_ext4_image(const char* fileName, long long partSize, const std::string& initial_dir,
unsigned eraseBlkSize, unsigned logicalBlkSize)
{
@@ -34,6 +42,84 @@
}
return 0;
}
+#else
+static int exec_e2fs_cmd(const char* path, char* const argv[]) {
+ int status;
+ pid_t child;
+ if ((child = fork()) == 0) {
+ setenv("MKE2FS_CONFIG", "", 1);
+ execvp(path, argv);
+ _exit(EXIT_FAILURE);
+ }
+ if (child < 0) {
+ fprintf(stderr, "%s failed with fork %s\n", path, strerror(errno));
+ return -1;
+ }
+ if (TEMP_FAILURE_RETRY(waitpid(child, &status, 0)) == -1) {
+ fprintf(stderr, "%s failed with waitpid %s\n", path, strerror(errno));
+ return -1;
+ }
+ int ret = -1;
+ if (WIFEXITED(status)) {
+ ret = WEXITSTATUS(status);
+ if (ret != 0) {
+ fprintf(stderr, "%s failed with status %d\n", path, ret);
+ }
+ }
+ return ret;
+}
+
+static int generate_ext4_image(const char* fileName, long long partSize,
+ const std::string& initial_dir, unsigned eraseBlkSize,
+ unsigned logicalBlkSize) {
+ static constexpr int block_size = 4096;
+ const std::string exec_dir = android::base::GetExecutableDirectory();
+
+ const std::string mke2fs_path = exec_dir + "/mke2fs";
+ std::vector<const char*> mke2fs_args = {mke2fs_path.c_str(), "-t", "ext4", "-b"};
+
+ std::string block_size_str = std::to_string(block_size);
+ mke2fs_args.push_back(block_size_str.c_str());
+
+ std::string ext_attr = "android_sparse";
+ if (eraseBlkSize != 0 && logicalBlkSize != 0) {
+ int raid_stride = logicalBlkSize / block_size;
+ int raid_stripe_width = eraseBlkSize / block_size;
+ // stride should be the max of 8kb and logical block size
+ if (logicalBlkSize != 0 && logicalBlkSize < 8192) raid_stride = 8192 / block_size;
+ ext_attr += StringPrintf(",stride=%d,stripe-width=%d", raid_stride, raid_stripe_width);
+ }
+ mke2fs_args.push_back("-E");
+ mke2fs_args.push_back(ext_attr.c_str());
+ mke2fs_args.push_back(fileName);
+
+ std::string size_str = std::to_string(partSize / block_size);
+ mke2fs_args.push_back(size_str.c_str());
+ mke2fs_args.push_back(nullptr);
+
+ int ret = exec_e2fs_cmd(mke2fs_args[0], const_cast<char**>(mke2fs_args.data()));
+ if (ret != 0) {
+ fprintf(stderr, "mke2fs failed: %d\n", ret);
+ return -1;
+ }
+
+ if (initial_dir.empty()) {
+ return 0;
+ }
+
+ const std::string e2fsdroid_path = exec_dir + "/e2fsdroid";
+ std::vector<const char*> e2fsdroid_args = {e2fsdroid_path.c_str(), "-f", initial_dir.c_str(),
+ fileName, nullptr};
+
+ ret = exec_e2fs_cmd(e2fsdroid_args[0], const_cast<char**>(e2fsdroid_args.data()));
+ if (ret != 0) {
+ fprintf(stderr, "e2fsdroid failed: %d\n", ret);
+ return -1;
+ }
+
+ return 0;
+}
+#endif
#ifdef USE_F2FS
static int generate_f2fs_image(const char* fileName, long long partSize, const std::string& initial_dir,
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index cc81074..874189a 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -79,13 +79,15 @@
FS_STAT_E2FSCK_F_ALWAYS = 0x0004,
FS_STAT_UNCLEAN_SHUTDOWN = 0x0008,
FS_STAT_QUOTA_ENABLED = 0x0010,
- FS_STAT_TUNE2FS_FAILED = 0x0020,
FS_STAT_RO_MOUNT_FAILED = 0x0040,
FS_STAT_RO_UNMOUNT_FAILED = 0x0080,
FS_STAT_FULL_MOUNT_FAILED = 0x0100,
FS_STAT_E2FSCK_FAILED = 0x0200,
FS_STAT_E2FSCK_FS_FIXED = 0x0400,
FS_STAT_EXT4_INVALID_MAGIC = 0x0800,
+ FS_STAT_TOGGLE_QUOTAS_FAILED = 0x10000,
+ FS_STAT_SET_RESERVED_BLOCKS_FAILED = 0x20000,
+ FS_STAT_ENABLE_ENCRYPTION_FAILED = 0x40000,
};
// TODO: switch to inotify()
@@ -117,10 +119,16 @@
}
}
+static bool is_extfs(const std::string& fs_type) {
+ return fs_type == "ext4" || fs_type == "ext3" || fs_type == "ext2";
+}
+
static bool should_force_check(int fs_stat) {
- return fs_stat & (FS_STAT_E2FSCK_F_ALWAYS | FS_STAT_UNCLEAN_SHUTDOWN | FS_STAT_QUOTA_ENABLED |
- FS_STAT_TUNE2FS_FAILED | FS_STAT_RO_MOUNT_FAILED | FS_STAT_RO_UNMOUNT_FAILED |
- FS_STAT_FULL_MOUNT_FAILED | FS_STAT_E2FSCK_FAILED);
+ return fs_stat &
+ (FS_STAT_E2FSCK_F_ALWAYS | FS_STAT_UNCLEAN_SHUTDOWN | FS_STAT_QUOTA_ENABLED |
+ FS_STAT_RO_MOUNT_FAILED | FS_STAT_RO_UNMOUNT_FAILED | FS_STAT_FULL_MOUNT_FAILED |
+ FS_STAT_E2FSCK_FAILED | FS_STAT_TOGGLE_QUOTAS_FAILED |
+ FS_STAT_SET_RESERVED_BLOCKS_FAILED | FS_STAT_ENABLE_ENCRYPTION_FAILED);
}
static void check_fs(const char *blk_device, char *fs_type, char *target, int *fs_stat)
@@ -133,7 +141,7 @@
const char* e2fsck_forced_argv[] = {E2FSCK_BIN, "-f", "-y", blk_device};
/* Check for the types of filesystems we know how to check */
- if (!strcmp(fs_type, "ext2") || !strcmp(fs_type, "ext3") || !strcmp(fs_type, "ext4")) {
+ if (is_extfs(fs_type)) {
if (*fs_stat & FS_STAT_EXT4_INVALID_MAGIC) { // will fail, so do not try
return;
}
@@ -231,186 +239,214 @@
return;
}
-/* Function to read the primary superblock */
-static int read_super_block(int fd, struct ext4_super_block *sb)
-{
- off64_t ret;
-
- ret = lseek64(fd, 1024, SEEK_SET);
- if (ret < 0)
- return ret;
-
- ret = read(fd, sb, sizeof(*sb));
- if (ret < 0)
- return ret;
- if (ret != sizeof(*sb))
- return ret;
-
- return 0;
-}
-
-static ext4_fsblk_t ext4_blocks_count(struct ext4_super_block *es)
-{
+static ext4_fsblk_t ext4_blocks_count(const struct ext4_super_block* es) {
return ((ext4_fsblk_t)le32_to_cpu(es->s_blocks_count_hi) << 32) |
- le32_to_cpu(es->s_blocks_count_lo);
+ le32_to_cpu(es->s_blocks_count_lo);
}
-static ext4_fsblk_t ext4_r_blocks_count(struct ext4_super_block *es)
-{
+static ext4_fsblk_t ext4_r_blocks_count(const struct ext4_super_block* es) {
return ((ext4_fsblk_t)le32_to_cpu(es->s_r_blocks_count_hi) << 32) |
- le32_to_cpu(es->s_r_blocks_count_lo);
+ le32_to_cpu(es->s_r_blocks_count_lo);
}
-static int do_quota_with_shutdown_check(char *blk_device, char *fs_type,
- struct fstab_rec *rec, int *fs_stat)
-{
- int force_check = 0;
- if (!strcmp(fs_type, "ext4")) {
- /*
- * Some system images do not have tune2fs for licensing reasons
- * Detect these and skip reserve blocks.
- */
- if (access(TUNE2FS_BIN, X_OK)) {
- LERROR << "Not running " << TUNE2FS_BIN << " on "
- << blk_device << " (executable not in system image)";
- } else {
- const char* arg1 = nullptr;
- const char* arg2 = nullptr;
- int status = 0;
- int ret = 0;
- android::base::unique_fd fd(
- TEMP_FAILURE_RETRY(open(blk_device, O_RDONLY | O_CLOEXEC)));
- if (fd >= 0) {
- struct ext4_super_block sb;
- ret = read_super_block(fd, &sb);
- if (ret < 0) {
- PERROR << "Can't read '" << blk_device << "' super block";
- return force_check;
- }
- if (sb.s_magic != EXT4_SUPER_MAGIC) {
- LINFO << "Invalid ext4 magic:0x" << std::hex << sb.s_magic << "," << blk_device;
- *fs_stat |= FS_STAT_EXT4_INVALID_MAGIC;
- return 0; // not a valid fs, tune2fs, fsck, and mount will all fail.
- }
- *fs_stat |= FS_STAT_IS_EXT4;
- LINFO << "superblock s_max_mnt_count:" << sb.s_max_mnt_count << "," << blk_device;
- if (sb.s_max_mnt_count == 0xffff) { // -1 (int16) in ext2, but uint16 in ext4
- *fs_stat |= FS_STAT_NEW_IMAGE_VERSION;
- }
- if ((sb.s_feature_incompat & EXT4_FEATURE_INCOMPAT_RECOVER) != 0 ||
- (sb.s_state & EXT4_VALID_FS) == 0) {
- LINFO << __FUNCTION__ << "(): was not clealy shutdown, state flag:"
- << std::hex << sb.s_state
- << "incompat flag:" << std::hex << sb.s_feature_incompat;
- force_check = 1;
- *fs_stat |= FS_STAT_UNCLEAN_SHUTDOWN;
- }
- int has_quota = (sb.s_feature_ro_compat
- & cpu_to_le32(EXT4_FEATURE_RO_COMPAT_QUOTA)) != 0;
- int want_quota = fs_mgr_is_quota(rec) != 0;
-
- if (has_quota == want_quota) {
- LINFO << "Requested quota status is match on " << blk_device;
- return force_check;
- } else if (want_quota) {
- LINFO << "Enabling quota on " << blk_device;
- arg1 = "-Oquota";
- arg2 = "-Qusrquota,grpquota";
- force_check = 1;
- *fs_stat |= FS_STAT_QUOTA_ENABLED;
- } else {
- LINFO << "Disabling quota on " << blk_device;
- arg1 = "-Q^usrquota,^grpquota";
- arg2 = "-O^quota";
- }
- } else {
- PERROR << "Failed to open '" << blk_device << "'";
- return force_check;
- }
-
- const char *tune2fs_argv[] = {
- TUNE2FS_BIN,
- arg1,
- arg2,
- blk_device,
- };
- ret = android_fork_execvp_ext(ARRAY_SIZE(tune2fs_argv),
- const_cast<char **>(tune2fs_argv),
- &status, true, LOG_KLOG | LOG_FILE,
- true, NULL, NULL, 0);
- if (ret < 0) {
- /* No need to check for error in fork, we can't really handle it now */
- LERROR << "Failed trying to run " << TUNE2FS_BIN;
- *fs_stat |= FS_STAT_TUNE2FS_FAILED;
- }
- }
- }
- return force_check;
+static bool is_ext4_superblock_valid(const struct ext4_super_block* es) {
+ if (es->s_magic != EXT4_SUPER_MAGIC) return false;
+ if (es->s_rev_level != EXT4_DYNAMIC_REV && es->s_rev_level != EXT4_GOOD_OLD_REV) return false;
+ if (EXT4_INODES_PER_GROUP(es) == 0) return false;
+ return true;
}
-static void do_reserved_size(char *blk_device, char *fs_type, struct fstab_rec *rec, int *fs_stat)
-{
- /* Check for the types of filesystems we know how to check */
- if (!strcmp(fs_type, "ext2") || !strcmp(fs_type, "ext3") || !strcmp(fs_type, "ext4")) {
- /*
- * Some system images do not have tune2fs for licensing reasons
- * Detect these and skip reserve blocks.
- */
- if (access(TUNE2FS_BIN, X_OK)) {
- LERROR << "Not running " << TUNE2FS_BIN << " on "
- << blk_device << " (executable not in system image)";
+// Read the primary superblock from an ext4 filesystem. On failure return
+// false. If it's not an ext4 filesystem, also set FS_STAT_EXT4_INVALID_MAGIC.
+static bool read_ext4_superblock(const char* blk_device, struct ext4_super_block* sb, int* fs_stat) {
+ android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(blk_device, O_RDONLY | O_CLOEXEC)));
+
+ if (fd < 0) {
+ PERROR << "Failed to open '" << blk_device << "'";
+ return false;
+ }
+
+ if (pread(fd, sb, sizeof(*sb), 1024) != sizeof(*sb)) {
+ PERROR << "Can't read '" << blk_device << "' superblock";
+ return false;
+ }
+
+ if (!is_ext4_superblock_valid(sb)) {
+ LINFO << "Invalid ext4 superblock on '" << blk_device << "'";
+ // not a valid fs, tune2fs, fsck, and mount will all fail.
+ *fs_stat |= FS_STAT_EXT4_INVALID_MAGIC;
+ return false;
+ }
+ *fs_stat |= FS_STAT_IS_EXT4;
+ LINFO << "superblock s_max_mnt_count:" << sb->s_max_mnt_count << "," << blk_device;
+ if (sb->s_max_mnt_count == 0xffff) { // -1 (int16) in ext2, but uint16 in ext4
+ *fs_stat |= FS_STAT_NEW_IMAGE_VERSION;
+ }
+ return true;
+}
+
+// Some system images do not have tune2fs for licensing reasons.
+// Detect these and skip running it.
+static bool tune2fs_available(void) {
+ return access(TUNE2FS_BIN, X_OK) == 0;
+}
+
+static bool run_tune2fs(const char* argv[], int argc) {
+ int ret;
+
+ ret = android_fork_execvp_ext(argc, const_cast<char**>(argv), nullptr, true,
+ LOG_KLOG | LOG_FILE, true, nullptr, nullptr, 0);
+ return ret == 0;
+}
+
+// Enable/disable quota support on the filesystem if needed.
+static void tune_quota(const char* blk_device, const struct fstab_rec* rec,
+ const struct ext4_super_block* sb, int* fs_stat) {
+ bool has_quota = (sb->s_feature_ro_compat & cpu_to_le32(EXT4_FEATURE_RO_COMPAT_QUOTA)) != 0;
+ bool want_quota = fs_mgr_is_quota(rec) != 0;
+
+ if (has_quota == want_quota) {
+ return;
+ }
+
+ if (!tune2fs_available()) {
+ LERROR << "Unable to " << (want_quota ? "enable" : "disable") << " quotas on " << blk_device
+ << " because " TUNE2FS_BIN " is missing";
+ return;
+ }
+
+ const char* argv[] = {TUNE2FS_BIN, nullptr, nullptr, blk_device};
+
+ if (want_quota) {
+ LINFO << "Enabling quotas on " << blk_device;
+ argv[1] = "-Oquota";
+ argv[2] = "-Qusrquota,grpquota";
+ *fs_stat |= FS_STAT_QUOTA_ENABLED;
+ } else {
+ LINFO << "Disabling quotas on " << blk_device;
+ argv[1] = "-O^quota";
+ argv[2] = "-Q^usrquota,^grpquota";
+ }
+
+ if (!run_tune2fs(argv, ARRAY_SIZE(argv))) {
+ LERROR << "Failed to run " TUNE2FS_BIN " to " << (want_quota ? "enable" : "disable")
+ << " quotas on " << blk_device;
+ *fs_stat |= FS_STAT_TOGGLE_QUOTAS_FAILED;
+ }
+}
+
+// Set the number of reserved filesystem blocks if needed.
+static void tune_reserved_size(const char* blk_device, const struct fstab_rec* rec,
+ const struct ext4_super_block* sb, int* fs_stat) {
+ if (!(rec->fs_mgr_flags & MF_RESERVEDSIZE)) {
+ return;
+ }
+
+ // The size to reserve is given in the fstab, but we won't reserve more
+ // than 2% of the filesystem.
+ const uint64_t max_reserved_blocks = ext4_blocks_count(sb) * 0.02;
+ uint64_t reserved_blocks = rec->reserved_size / EXT4_BLOCK_SIZE(sb);
+
+ if (reserved_blocks > max_reserved_blocks) {
+ LWARNING << "Reserved blocks " << reserved_blocks << " is too large; "
+ << "capping to " << max_reserved_blocks;
+ reserved_blocks = max_reserved_blocks;
+ }
+
+ if (ext4_r_blocks_count(sb) == reserved_blocks) {
+ return;
+ }
+
+ if (!tune2fs_available()) {
+ LERROR << "Unable to set the number of reserved blocks on " << blk_device
+ << " because " TUNE2FS_BIN " is missing";
+ return;
+ }
+
+ char buf[32];
+ const char* argv[] = {TUNE2FS_BIN, "-r", buf, blk_device};
+
+ snprintf(buf, sizeof(buf), "%" PRIu64, reserved_blocks);
+ LINFO << "Setting reserved block count on " << blk_device << " to " << reserved_blocks;
+ if (!run_tune2fs(argv, ARRAY_SIZE(argv))) {
+ LERROR << "Failed to run " TUNE2FS_BIN " to set the number of reserved blocks on "
+ << blk_device;
+ *fs_stat |= FS_STAT_SET_RESERVED_BLOCKS_FAILED;
+ }
+}
+
+// Enable file-based encryption if needed.
+static void tune_encrypt(const char* blk_device, const struct fstab_rec* rec,
+ const struct ext4_super_block* sb, int* fs_stat) {
+ bool has_encrypt = (sb->s_feature_incompat & cpu_to_le32(EXT4_FEATURE_INCOMPAT_ENCRYPT)) != 0;
+ bool want_encrypt = fs_mgr_is_file_encrypted(rec) != 0;
+
+ if (has_encrypt || !want_encrypt) {
+ return;
+ }
+
+ if (!tune2fs_available()) {
+ LERROR << "Unable to enable ext4 encryption on " << blk_device
+ << " because " TUNE2FS_BIN " is missing";
+ return;
+ }
+
+ const char* argv[] = {TUNE2FS_BIN, "-Oencrypt", blk_device};
+
+ LINFO << "Enabling ext4 encryption on " << blk_device;
+ if (!run_tune2fs(argv, ARRAY_SIZE(argv))) {
+ LERROR << "Failed to run " TUNE2FS_BIN " to enable "
+ << "ext4 encryption on " << blk_device;
+ *fs_stat |= FS_STAT_ENABLE_ENCRYPTION_FAILED;
+ }
+}
+
+//
+// Prepare the filesystem on the given block device to be mounted.
+//
+// If the "check" option was given in the fstab record, or it seems that the
+// filesystem was uncleanly shut down, we'll run fsck on the filesystem.
+//
+// If needed, we'll also enable (or disable) filesystem features as specified by
+// the fstab record.
+//
+static int prepare_fs_for_mount(const char* blk_device, const struct fstab_rec* rec) {
+ int fs_stat = 0;
+
+ if (is_extfs(rec->fs_type)) {
+ struct ext4_super_block sb;
+
+ if (read_ext4_superblock(blk_device, &sb, &fs_stat)) {
+ if ((sb.s_feature_incompat & EXT4_FEATURE_INCOMPAT_RECOVER) != 0 ||
+ (sb.s_state & EXT4_VALID_FS) == 0) {
+ LINFO << "Filesystem on " << blk_device << " was not cleanly shutdown; "
+ << "state flags: 0x" << std::hex << sb.s_state << ", "
+ << "incompat feature flags: 0x" << std::hex << sb.s_feature_incompat;
+ fs_stat |= FS_STAT_UNCLEAN_SHUTDOWN;
+ }
+
+ // Note: quotas should be enabled before running fsck.
+ tune_quota(blk_device, rec, &sb, &fs_stat);
} else {
- LINFO << "Running " << TUNE2FS_BIN << " on " << blk_device;
-
- int status = 0;
- int ret = 0;
- unsigned long reserved_blocks = 0;
- android::base::unique_fd fd(
- TEMP_FAILURE_RETRY(open(blk_device, O_RDONLY | O_CLOEXEC)));
- if (fd >= 0) {
- struct ext4_super_block sb;
- ret = read_super_block(fd, &sb);
- if (ret < 0) {
- PERROR << "Can't read '" << blk_device << "' super block";
- return;
- }
- reserved_blocks = rec->reserved_size / EXT4_BLOCK_SIZE(&sb);
- unsigned long reserved_threshold = ext4_blocks_count(&sb) * 0.02;
- if (reserved_threshold < reserved_blocks) {
- LWARNING << "Reserved blocks " << reserved_blocks
- << " is too large";
- reserved_blocks = reserved_threshold;
- }
-
- if (ext4_r_blocks_count(&sb) == reserved_blocks) {
- LINFO << "Have reserved same blocks";
- return;
- }
- } else {
- PERROR << "Failed to open '" << blk_device << "'";
- return;
- }
-
- char buf[16] = {0};
- snprintf(buf, sizeof (buf), "-r %lu", reserved_blocks);
- const char *tune2fs_argv[] = {
- TUNE2FS_BIN,
- buf,
- blk_device,
- };
-
- ret = android_fork_execvp_ext(ARRAY_SIZE(tune2fs_argv),
- const_cast<char **>(tune2fs_argv),
- &status, true, LOG_KLOG | LOG_FILE,
- true, NULL, NULL, 0);
-
- if (ret < 0) {
- /* No need to check for error in fork, we can't really handle it now */
- LERROR << "Failed trying to run " << TUNE2FS_BIN;
- *fs_stat |= FS_STAT_TUNE2FS_FAILED;
- }
+ return fs_stat;
}
}
+
+ if ((rec->fs_mgr_flags & MF_CHECK) ||
+ (fs_stat & (FS_STAT_UNCLEAN_SHUTDOWN | FS_STAT_QUOTA_ENABLED))) {
+ check_fs(blk_device, rec->fs_type, rec->mount_point, &fs_stat);
+ }
+
+ if (is_extfs(rec->fs_type) && (rec->fs_mgr_flags & (MF_RESERVEDSIZE | MF_FILEENCRYPTION))) {
+ struct ext4_super_block sb;
+
+ if (read_ext4_superblock(blk_device, &sb, &fs_stat)) {
+ tune_reserved_size(blk_device, rec, &sb, &fs_stat);
+ tune_encrypt(blk_device, rec, &sb, &fs_stat);
+ }
+ }
+
+ return fs_stat;
}
static void remove_trailing_slashes(char *n)
@@ -559,10 +595,7 @@
continue;
}
- int fs_stat = 0;
- int force_check = do_quota_with_shutdown_check(fstab->recs[i].blk_device,
- fstab->recs[i].fs_type,
- &fstab->recs[i], &fs_stat);
+ int fs_stat = prepare_fs_for_mount(fstab->recs[i].blk_device, &fstab->recs[i]);
if (fs_stat & FS_STAT_EXT4_INVALID_MAGIC) {
LERROR << __FUNCTION__ << "(): skipping mount, invalid ext4, mountpoint="
<< fstab->recs[i].mount_point << " rec[" << i
@@ -570,15 +603,6 @@
mount_errno = EINVAL; // continue bootup for FDE
continue;
}
- if ((fstab->recs[i].fs_mgr_flags & MF_CHECK) || force_check) {
- check_fs(fstab->recs[i].blk_device, fstab->recs[i].fs_type,
- fstab->recs[i].mount_point, &fs_stat);
- }
-
- if (fstab->recs[i].fs_mgr_flags & MF_RESERVEDSIZE) {
- do_reserved_size(fstab->recs[i].blk_device, fstab->recs[i].fs_type,
- &fstab->recs[i], &fs_stat);
- }
int retry_count = 2;
while (retry_count-- > 0) {
@@ -804,9 +828,7 @@
}
/* Translate LABEL= file system labels into block devices */
- if (!strcmp(fstab->recs[i].fs_type, "ext2") ||
- !strcmp(fstab->recs[i].fs_type, "ext3") ||
- !strcmp(fstab->recs[i].fs_type, "ext4")) {
+ if (is_extfs(fstab->recs[i].fs_type)) {
int tret = translate_ext_labels(&fstab->recs[i]);
if (tret < 0) {
LERROR << "Could not translate label to block device";
@@ -1025,18 +1047,7 @@
continue;
}
- int fs_stat = 0;
- int force_check = do_quota_with_shutdown_check(n_blk_device, fstab->recs[i].fs_type,
- &fstab->recs[i], &fs_stat);
-
- if ((fstab->recs[i].fs_mgr_flags & MF_CHECK) || force_check) {
- check_fs(n_blk_device, fstab->recs[i].fs_type,
- fstab->recs[i].mount_point, &fs_stat);
- }
-
- if (fstab->recs[i].fs_mgr_flags & MF_RESERVEDSIZE) {
- do_reserved_size(n_blk_device, fstab->recs[i].fs_type, &fstab->recs[i], &fs_stat);
- }
+ int fs_stat = prepare_fs_for_mount(n_blk_device, &fstab->recs[i]);
if (fstab->recs[i].fs_mgr_flags & MF_AVB) {
if (!avb_handle) {
diff --git a/fs_mgr/fs_mgr_boot_config.cpp b/fs_mgr/fs_mgr_boot_config.cpp
index ab5beed..9117667 100644
--- a/fs_mgr/fs_mgr_boot_config.cpp
+++ b/fs_mgr/fs_mgr_boot_config.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <string>
+
#include <android-base/file.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
@@ -51,9 +53,11 @@
// lastly, check the device tree
if (is_dt_compatible()) {
std::string file_name = kAndroidDtDir + "/" + key;
- // DT entries terminate with '\0' but so do the properties
if (android::base::ReadFileToString(file_name, out_val)) {
- return true;
+ if (!out_val->empty()) {
+ out_val->pop_back(); // Trims the trailing '\0' out.
+ return true;
+ }
}
}
diff --git a/fs_mgr/fs_mgr_format.cpp b/fs_mgr/fs_mgr_format.cpp
index 5705f93..a03d92c 100644
--- a/fs_mgr/fs_mgr_format.cpp
+++ b/fs_mgr/fs_mgr_format.cpp
@@ -86,13 +86,15 @@
static int format_f2fs(char *fs_blkdev)
{
- char * args[3];
+ char * args[5];
int pid;
int rc = 0;
- args[0] = (char *)"/sbin/mkfs.f2fs";
- args[1] = fs_blkdev;
- args[2] = (char *)0;
+ args[0] = (char *)"/system/bin/make_f2fs";
+ args[1] = (char *)"-f";
+ args[2] = (char *)"-O encrypt";
+ args[3] = fs_blkdev;
+ args[4] = (char *)0;
pid = fork();
if (pid < 0) {
@@ -100,7 +102,7 @@
}
if (!pid) {
/* This doesn't return */
- execv("/sbin/mkfs.f2fs", args);
+ execv(args[0], args);
exit(1);
}
for(;;) {
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 7a41b14..b68875b 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -810,32 +810,26 @@
return fstab->fs_mgr_flags & MF_NOEMULATEDSD;
}
-int fs_mgr_is_notrim(struct fstab_rec *fstab)
-{
+int fs_mgr_is_notrim(const struct fstab_rec* fstab) {
return fstab->fs_mgr_flags & MF_NOTRIM;
}
-int fs_mgr_is_formattable(struct fstab_rec *fstab)
-{
+int fs_mgr_is_formattable(const struct fstab_rec* fstab) {
return fstab->fs_mgr_flags & (MF_FORMATTABLE);
}
-int fs_mgr_is_slotselect(struct fstab_rec *fstab)
-{
+int fs_mgr_is_slotselect(const struct fstab_rec* fstab) {
return fstab->fs_mgr_flags & MF_SLOTSELECT;
}
-int fs_mgr_is_nofail(struct fstab_rec *fstab)
-{
+int fs_mgr_is_nofail(const struct fstab_rec* fstab) {
return fstab->fs_mgr_flags & MF_NOFAIL;
}
-int fs_mgr_is_latemount(struct fstab_rec *fstab)
-{
+int fs_mgr_is_latemount(const struct fstab_rec* fstab) {
return fstab->fs_mgr_flags & MF_LATEMOUNT;
}
-int fs_mgr_is_quota(struct fstab_rec *fstab)
-{
+int fs_mgr_is_quota(const struct fstab_rec* fstab) {
return fstab->fs_mgr_flags & MF_QUOTA;
}
diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp
index 5de0903..7f8e1e2 100644
--- a/fs_mgr/fs_mgr_verity.cpp
+++ b/fs_mgr/fs_mgr_verity.cpp
@@ -841,9 +841,15 @@
// verify the signature on the table
if (verify_verity_signature(verity) < 0) {
+ // Allow signature verification error when the device is unlocked
+ if (fs_mgr_is_device_unlocked()) {
+ retval = FS_MGR_SETUP_VERITY_SKIPPED;
+ LWARNING << "Allow signature verification error when the device is unlocked";
+ goto out;
+ }
if (params.mode == VERITY_MODE_LOGGING) {
// the user has been warned, allow mounting without dm-verity
- retval = FS_MGR_SETUP_VERITY_SUCCESS;
+ retval = FS_MGR_SETUP_VERITY_SKIPPED;
goto out;
}
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
index 3ea4e03..17e1fb1 100644
--- a/fs_mgr/include_fstab/fstab/fstab.h
+++ b/fs_mgr/include_fstab/fstab/fstab.h
@@ -80,12 +80,12 @@
const char* fs_mgr_get_file_encryption_mode(const struct fstab_rec* fstab);
int fs_mgr_is_convertible_to_fbe(const struct fstab_rec* fstab);
int fs_mgr_is_noemulatedsd(const struct fstab_rec* fstab);
-int fs_mgr_is_notrim(struct fstab_rec* fstab);
-int fs_mgr_is_formattable(struct fstab_rec* fstab);
-int fs_mgr_is_slotselect(struct fstab_rec* fstab);
-int fs_mgr_is_nofail(struct fstab_rec* fstab);
-int fs_mgr_is_latemount(struct fstab_rec* fstab);
-int fs_mgr_is_quota(struct fstab_rec* fstab);
+int fs_mgr_is_notrim(const struct fstab_rec* fstab);
+int fs_mgr_is_formattable(const struct fstab_rec* fstab);
+int fs_mgr_is_slotselect(const struct fstab_rec* fstab);
+int fs_mgr_is_nofail(const struct fstab_rec* fstab);
+int fs_mgr_is_latemount(const struct fstab_rec* fstab);
+int fs_mgr_is_quota(const struct fstab_rec* fstab);
__END_DECLS
diff --git a/gatekeeperd/SoftGateKeeper.h b/gatekeeperd/SoftGateKeeper.h
index cb02a6f..92d1752 100644
--- a/gatekeeperd/SoftGateKeeper.h
+++ b/gatekeeperd/SoftGateKeeper.h
@@ -26,8 +26,8 @@
}
#include <android-base/memory.h>
-#include <UniquePtr.h>
#include <gatekeeper/gatekeeper.h>
+#include <nativehelper/UniquePtr.h>
#include <iostream>
#include <unordered_map>
diff --git a/gatekeeperd/SoftGateKeeperDevice.h b/gatekeeperd/SoftGateKeeperDevice.h
index 3463c29..229f9a9 100644
--- a/gatekeeperd/SoftGateKeeperDevice.h
+++ b/gatekeeperd/SoftGateKeeperDevice.h
@@ -19,7 +19,7 @@
#include "SoftGateKeeper.h"
-#include <UniquePtr.h>
+#include <nativehelper/UniquePtr.h>
using namespace gatekeeper;
diff --git a/gatekeeperd/tests/gatekeeper_test.cpp b/gatekeeperd/tests/gatekeeper_test.cpp
index 47a8bfa..b3aea7b 100644
--- a/gatekeeperd/tests/gatekeeper_test.cpp
+++ b/gatekeeperd/tests/gatekeeper_test.cpp
@@ -19,7 +19,7 @@
#include <gtest/gtest.h>
#include <hardware/hw_auth_token.h>
-#include <UniquePtr.h>
+#include <nativehelper/UniquePtr.h>
#include "../SoftGateKeeper.h"
diff --git a/init/Android.bp b/init/Android.bp
index fce424e..8294598 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -94,6 +94,10 @@
name: "init",
defaults: ["init_defaults"],
+ required: [
+ "e2fsdroid",
+ "mke2fs",
+ ],
static_executable: true,
srcs: [
"bootchart.cpp",
@@ -153,6 +157,7 @@
"init_test.cpp",
"property_service_test.cpp",
"service_test.cpp",
+ "ueventd_test.cpp",
"util_test.cpp",
],
shared_libs: [
diff --git a/init/Android.mk b/init/Android.mk
index 6cd47f4..db0eb48 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -30,6 +30,10 @@
init_options += -DLOG_UEVENTS=0
+ifeq ($(TARGET_USER_MODE_LINUX), true)
+ init_cflags += -DUSER_MODE_LINUX
+endif
+
init_cflags += \
$(init_options) \
-Wall -Wextra \
@@ -73,6 +77,7 @@
libcutils \
libbase \
libc \
+ libseccomp_policy \
libselinux \
liblog \
libcrypto_utils \
@@ -85,6 +90,10 @@
libavb \
libkeyutils \
+LOCAL_REQUIRED_MODULES := \
+ e2fsdroid \
+ mke2fs \
+
# Create symlinks.
LOCAL_POST_INSTALL_CMD := $(hide) mkdir -p $(TARGET_ROOT_OUT)/sbin; \
ln -sf ../init $(TARGET_ROOT_OUT)/sbin/ueventd; \
diff --git a/init/README.md b/init/README.md
index 422fdad..f3b57bc 100644
--- a/init/README.md
+++ b/init/README.md
@@ -260,6 +260,18 @@
> Sets the child's /proc/self/oom\_score\_adj to the specified value,
which must range from -1000 to 1000.
+`memcg.swappiness <value>`
+> Sets the child's memory.swappiness to the specified value (only if memcg is mounted),
+ which must be equal or greater than 0.
+
+`memcg.soft_limit_in_bytes <value>`
+> Sets the child's memory.soft_limit_in_bytes to the specified value (only if memcg is mounted),
+ which must be equal or greater than 0.
+
+`memcg.limit_in_bytes <value>`
+> Sets the child's memory.limit_in_bytes to the specified value (only if memcg is mounted),
+ which must be equal or greater than 0.
+
`shutdown <shutdown_behavior>`
> Set shutdown behavior of the service process. When this is not specified,
the service is killed during shutdown process by using SIGTERM and SIGKILL.
diff --git a/init/init.cpp b/init/init.cpp
index bf251ff..7fbc3b7 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -23,6 +23,7 @@
#include <inttypes.h>
#include <libgen.h>
#include <paths.h>
+#include <seccomp_policy.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
@@ -391,7 +392,10 @@
int ret = -1;
/* values are arch-dependent */
-#if defined(__aarch64__)
+#if defined(USER_MODE_LINUX)
+ /* uml does not support mmap_rnd_bits */
+ ret = 0;
+#elif defined(__aarch64__)
/* arm64 supports 18 - 33 bits depending on pagesize and VA_SIZE */
if (set_mmap_rnd_bits_min(33, 24, false)
&& set_mmap_rnd_bits_min(16, 16, true)) {
@@ -551,6 +555,15 @@
return 0;
}
+static void global_seccomp() {
+ import_kernel_cmdline(false, [](const std::string& key, const std::string& value, bool in_qemu) {
+ if (key == "androidboot.seccomp" && value == "global" && !set_global_seccomp_filter()) {
+ LOG(ERROR) << "Failed to globally enable seccomp!";
+ panic();
+ }
+ });
+}
+
static void selinux_init_all_handles(void)
{
sehandle = selinux_android_file_context_handle();
@@ -896,8 +909,8 @@
selinux_android_restorecon("/dev/block", SELINUX_ANDROID_RESTORECON_RECURSE);
selinux_android_restorecon("/dev/device-mapper", 0);
- selinux_android_restorecon("/sbin/mke2fs", 0);
- selinux_android_restorecon("/sbin/e2fsdroid", 0);
+ selinux_android_restorecon("/sbin/mke2fs_static", 0);
+ selinux_android_restorecon("/sbin/e2fsdroid_static", 0);
}
// Set the UDC controller for the ConfigFS USB Gadgets.
@@ -1001,6 +1014,9 @@
SetInitAvbVersionInRecovery();
+ // Enable seccomp if global boot option was passed (otherwise it is enabled in zygote).
+ global_seccomp();
+
// Set up SELinux, loading the SELinux policy.
selinux_initialize(true);
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 969caec..17e3576 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -234,7 +234,13 @@
LOG(INFO) << "mount entry " << mentry->mnt_fsname << ":" << mentry->mnt_dir << " opts "
<< mentry->mnt_opts << " type " << mentry->mnt_type;
} else if (MountEntry::IsBlockDevice(*mentry) && hasmntopt(mentry, "rw")) {
- blockDevPartitions->emplace(blockDevPartitions->begin(), *mentry);
+ std::string mount_dir(mentry->mnt_dir);
+ // These are R/O partitions changed to R/W after adb remount.
+ // Do not umount them as shutdown critical services may rely on them.
+ if (mount_dir != "/" && mount_dir != "/system" && mount_dir != "/vendor" &&
+ mount_dir != "/oem") {
+ blockDevPartitions->emplace(blockDevPartitions->begin(), *mentry);
+ }
} else if (MountEntry::IsEmulatedDevice(*mentry)) {
emulatedPartitions->emplace(emulatedPartitions->begin(), *mentry);
}
@@ -318,11 +324,11 @@
UmountStat stat = UmountPartitions(timeout - t.duration());
if (stat != UMOUNT_STAT_SUCCESS) {
LOG(INFO) << "umount timeout, last resort, kill all and try";
- if (DUMP_ON_UMOUNT_FAILURE) DumpUmountDebuggingInfo(false);
+ if (DUMP_ON_UMOUNT_FAILURE) DumpUmountDebuggingInfo(true);
KillAllProcesses();
// even if it succeeds, still it is timeout and do not run fsck with all processes killed
- UmountPartitions(0ms);
- if (DUMP_ON_UMOUNT_FAILURE) DumpUmountDebuggingInfo(true);
+ UmountStat st = UmountPartitions(0ms);
+ if ((st != UMOUNT_STAT_SUCCESS) && DUMP_ON_UMOUNT_FAILURE) DumpUmountDebuggingInfo(false);
}
if (stat == UMOUNT_STAT_SUCCESS && runFsck) {
@@ -335,13 +341,6 @@
return stat;
}
-static void __attribute__((noreturn)) DoThermalOff() {
- LOG(WARNING) << "Thermal system shutdown";
- sync();
- RebootSystem(ANDROID_RB_THERMOFF, "");
- abort();
-}
-
void DoReboot(unsigned int cmd, const std::string& reason, const std::string& rebootTarget,
bool runFsck) {
Timer t;
@@ -350,19 +349,25 @@
android::base::WriteStringToFile(StringPrintf("%s\n", reason.c_str()), LAST_REBOOT_REASON_FILE,
S_IRUSR | S_IWUSR, AID_SYSTEM, AID_SYSTEM);
- if (cmd == ANDROID_RB_THERMOFF) { // do not wait if it is thermal
- DoThermalOff();
- abort();
+ bool is_thermal_shutdown = false;
+ if (cmd == ANDROID_RB_THERMOFF) {
+ is_thermal_shutdown = true;
+ runFsck = false;
}
- auto shutdown_timeout = 0s;
+ auto shutdown_timeout = 0ms;
if (!SHUTDOWN_ZERO_TIMEOUT) {
- constexpr unsigned int shutdown_timeout_default = 6;
- auto shutdown_timeout_property =
- android::base::GetUintProperty("ro.build.shutdown_timeout", shutdown_timeout_default);
- shutdown_timeout = std::chrono::seconds(shutdown_timeout_property);
+ if (is_thermal_shutdown) {
+ constexpr unsigned int thermal_shutdown_timeout = 1;
+ shutdown_timeout = std::chrono::seconds(thermal_shutdown_timeout);
+ } else {
+ constexpr unsigned int shutdown_timeout_default = 6;
+ auto shutdown_timeout_property = android::base::GetUintProperty(
+ "ro.build.shutdown_timeout", shutdown_timeout_default);
+ shutdown_timeout = std::chrono::seconds(shutdown_timeout_property);
+ }
}
- LOG(INFO) << "Shutdown timeout: " << shutdown_timeout.count() << " seconds";
+ LOG(INFO) << "Shutdown timeout: " << shutdown_timeout.count() << " ms";
// keep debugging tools until non critical ones are all gone.
const std::set<std::string> kill_after_apps{"tombstoned", "logd", "adbd"};
@@ -389,7 +394,7 @@
// optional shutdown step
// 1. terminate all services except shutdown critical ones. wait for delay to finish
- if (shutdown_timeout > 0s) {
+ if (shutdown_timeout > 0ms) {
LOG(INFO) << "terminating init services";
// Ask all services to terminate except shutdown critical ones.
@@ -398,8 +403,8 @@
});
int service_count = 0;
- // Up to half as long as shutdown_timeout or 3 seconds, whichever is lower.
- auto termination_wait_timeout = std::min((shutdown_timeout + 1s) / 2, 3s);
+ // Only wait up to half of timeout here
+ auto termination_wait_timeout = shutdown_timeout / 2;
while (t.duration() < termination_wait_timeout) {
ServiceManager::GetInstance().ReapAnyOutstandingChildren();
@@ -451,7 +456,7 @@
UmountStat stat = TryUmountAndFsck(runFsck, shutdown_timeout - t.duration());
// Follow what linux shutdown is doing: one more sync with little bit delay
sync();
- std::this_thread::sleep_for(100ms);
+ if (!is_thermal_shutdown) std::this_thread::sleep_for(100ms);
LogShutdownTime(stat, &t);
// Reboot regardless of umount status. If umount fails, fsck after reboot will fix it.
RebootSystem(cmd, rebootTarget);
@@ -494,10 +499,8 @@
}
}
} else if (command == "thermal-shutdown") { // no additional parameter allowed
+ // run_fsck is false to avoid delay
cmd = ANDROID_RB_THERMOFF;
- // Do not queue "shutdown" trigger since we want to shutdown immediately
- DoReboot(cmd, command, reboot_target, run_fsck);
- return true;
} else {
command_invalid = true;
}
diff --git a/init/service.cpp b/init/service.cpp
index 7a657c8..fc64db6 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -156,24 +156,7 @@
}
Service::Service(const std::string& name, const std::vector<std::string>& args)
- : name_(name),
- classnames_({"default"}),
- flags_(0),
- pid_(0),
- crash_count_(0),
- uid_(0),
- gid_(0),
- namespace_flags_(0),
- seclabel_(""),
- onrestart_(false, "<Service '" + name + "' onrestart>", 0),
- keychord_id_(0),
- ioprio_class_(IoSchedClass_NONE),
- ioprio_pri_(0),
- priority_(0),
- oom_score_adjust_(-1000),
- args_(args) {
- onrestart_.InitSingleTrigger("onrestart");
-}
+ : Service(name, 0, 0, 0, {}, 0, 0, "", args) {}
Service::Service(const std::string& name, unsigned flags, uid_t uid, gid_t gid,
const std::vector<gid_t>& supp_gids, const CapSet& capabilities,
@@ -196,6 +179,9 @@
ioprio_pri_(0),
priority_(0),
oom_score_adjust_(-1000),
+ swappiness_(-1),
+ soft_limit_in_bytes_(-1),
+ limit_in_bytes_(-1),
args_(args) {
onrestart_.InitSingleTrigger("onrestart");
}
@@ -491,6 +477,30 @@
return true;
}
+bool Service::ParseMemcgSwappiness(const std::vector<std::string>& args, std::string* err) {
+ if (!ParseInt(args[1], &swappiness_, 0)) {
+ *err = "swappiness value must be equal or greater than 0";
+ return false;
+ }
+ return true;
+}
+
+bool Service::ParseMemcgLimitInBytes(const std::vector<std::string>& args, std::string* err) {
+ if (!ParseInt(args[1], &limit_in_bytes_, 0)) {
+ *err = "limit_in_bytes value must be equal or greater than 0";
+ return false;
+ }
+ return true;
+}
+
+bool Service::ParseMemcgSoftLimitInBytes(const std::vector<std::string>& args, std::string* err) {
+ if (!ParseInt(args[1], &soft_limit_in_bytes_, 0)) {
+ *err = "soft_limit_in_bytes value must be equal or greater than 0";
+ return false;
+ }
+ return true;
+}
+
bool Service::ParseSeclabel(const std::vector<std::string>& args, std::string* err) {
seclabel_ = args[1];
return true;
@@ -609,6 +619,12 @@
{"onrestart", {1, kMax, &Service::ParseOnrestart}},
{"oom_score_adjust",
{1, 1, &Service::ParseOomScoreAdjust}},
+ {"memcg.swappiness",
+ {1, 1, &Service::ParseMemcgSwappiness}},
+ {"memcg.soft_limit_in_bytes",
+ {1, 1, &Service::ParseMemcgSoftLimitInBytes}},
+ {"memcg.limit_in_bytes",
+ {1, 1, &Service::ParseMemcgLimitInBytes}},
{"namespace", {1, 2, &Service::ParseNamespace}},
{"seclabel", {1, 1, &Service::ParseSeclabel}},
{"setenv", {2, 2, &Service::ParseSetenv}},
@@ -795,6 +811,24 @@
if (errno != 0) {
PLOG(ERROR) << "createProcessGroup(" << uid_ << ", " << pid_ << ") failed for service '"
<< name_ << "'";
+ } else {
+ if (swappiness_ != -1) {
+ if (!setProcessGroupSwappiness(uid_, pid_, swappiness_)) {
+ PLOG(ERROR) << "setProcessGroupSwappiness failed";
+ }
+ }
+
+ if (soft_limit_in_bytes_ != -1) {
+ if (!setProcessGroupSoftLimit(uid_, pid_, soft_limit_in_bytes_)) {
+ PLOG(ERROR) << "setProcessGroupSoftLimit failed";
+ }
+ }
+
+ if (limit_in_bytes_ != -1) {
+ if (!setProcessGroupLimit(uid_, pid_, limit_in_bytes_)) {
+ PLOG(ERROR) << "setProcessGroupLimit failed";
+ }
+ }
}
if ((flags_ & SVC_EXEC) != 0) {
diff --git a/init/service.h b/init/service.h
index f682abd..62a3299 100644
--- a/init/service.h
+++ b/init/service.h
@@ -134,6 +134,9 @@
bool ParseOneshot(const std::vector<std::string>& args, std::string* err);
bool ParseOnrestart(const std::vector<std::string>& args, std::string* err);
bool ParseOomScoreAdjust(const std::vector<std::string>& args, std::string* err);
+ bool ParseMemcgLimitInBytes(const std::vector<std::string>& args, std::string* err);
+ bool ParseMemcgSoftLimitInBytes(const std::vector<std::string>& args, std::string* err);
+ bool ParseMemcgSwappiness(const std::vector<std::string>& args, std::string* err);
bool ParseNamespace(const std::vector<std::string>& args, std::string* err);
bool ParseSeclabel(const std::vector<std::string>& args, std::string* err);
bool ParseSetenv(const std::vector<std::string>& args, std::string* err);
@@ -181,6 +184,10 @@
int oom_score_adjust_;
+ int swappiness_;
+ int soft_limit_in_bytes_;
+ int limit_in_bytes_;
+
bool process_cgroup_empty_ = false;
std::vector<std::string> args_;
diff --git a/init/ueventd_test.cpp b/init/ueventd_test.cpp
new file mode 100644
index 0000000..4d9a1fa
--- /dev/null
+++ b/init/ueventd_test.cpp
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <linux/futex.h>
+#include <pthread.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <string>
+#include <thread>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/scopeguard.h>
+#include <android-base/test_utils.h>
+#include <gtest/gtest.h>
+#include <selinux/selinux.h>
+
+using namespace std::string_literals;
+
+template <typename T, typename F>
+void WriteFromMultipleThreads(std::vector<std::pair<std::string, T>>& files_and_parameters,
+ F function) {
+ auto num_threads = files_and_parameters.size();
+ pthread_barrier_t barrier;
+ pthread_barrier_init(&barrier, nullptr, num_threads);
+ auto barrier_destroy =
+ android::base::make_scope_guard([&barrier]() { pthread_barrier_destroy(&barrier); });
+
+ auto make_thread_function = [&function, &barrier](const auto& file, const auto& parameter) {
+ return [&]() {
+ function(parameter);
+ pthread_barrier_wait(&barrier);
+ android::base::WriteStringToFile("<empty>", file);
+ };
+ };
+
+ std::vector<std::thread> threads;
+ // TODO(b/63712782): Structured bindings + templated containers are broken in clang :(
+ // for (const auto& [file, parameter] : files_and_parameters) {
+ for (const auto& pair : files_and_parameters) {
+ const auto& file = pair.first;
+ const auto& parameter = pair.second;
+ threads.emplace_back(std::thread(make_thread_function(file, parameter)));
+ }
+
+ for (auto& thread : threads) {
+ thread.join();
+ }
+}
+
+TEST(ueventd, setegid_IsPerThread) {
+ if (getuid() != 0) {
+ GTEST_LOG_(INFO) << "Skipping test, must be run as root.";
+ return;
+ }
+
+ TemporaryDir dir;
+
+ gid_t gid = 0;
+ std::vector<std::pair<std::string, gid_t>> files_and_gids;
+ std::generate_n(std::back_inserter(files_and_gids), 100, [&gid, &dir]() {
+ gid++;
+ return std::pair(dir.path + "/gid_"s + std::to_string(gid), gid);
+ });
+
+ WriteFromMultipleThreads(files_and_gids, [](gid_t gid) { EXPECT_EQ(0, setegid(gid)); });
+
+ for (const auto& [file, expected_gid] : files_and_gids) {
+ struct stat info;
+ ASSERT_EQ(0, stat(file.c_str(), &info));
+ EXPECT_EQ(expected_gid, info.st_gid);
+ }
+}
+
+TEST(ueventd, setfscreatecon_IsPerThread) {
+ if (getuid() != 0) {
+ GTEST_LOG_(INFO) << "Skipping test, must be run as root.";
+ return;
+ }
+ if (!is_selinux_enabled() || security_getenforce() == 1) {
+ GTEST_LOG_(INFO) << "Skipping test, SELinux must be enabled and in permissive mode.";
+ return;
+ }
+
+ const char* const contexts[] = {
+ "u:object_r:audio_device:s0",
+ "u:object_r:sensors_device:s0",
+ "u:object_r:video_device:s0"
+ "u:object_r:zero_device:s0",
+ };
+
+ TemporaryDir dir;
+ std::vector<std::pair<std::string, std::string>> files_and_contexts;
+ for (const char* context : contexts) {
+ files_and_contexts.emplace_back(dir.path + "/context_"s + context, context);
+ }
+
+ WriteFromMultipleThreads(files_and_contexts, [](const std::string& context) {
+ EXPECT_EQ(0, setfscreatecon(context.c_str()));
+ });
+
+ for (const auto& [file, expected_context] : files_and_contexts) {
+ char* file_context;
+ ASSERT_GT(getfilecon(file.c_str(), &file_context), 0);
+ EXPECT_EQ(expected_context, file_context);
+ freecon(file_context);
+ }
+}
diff --git a/libbacktrace/Backtrace.cpp b/libbacktrace/Backtrace.cpp
index e46d353..81f5e32 100644
--- a/libbacktrace/Backtrace.cpp
+++ b/libbacktrace/Backtrace.cpp
@@ -84,10 +84,8 @@
}
std::string Backtrace::FormatFrameData(const backtrace_frame_data_t* frame) {
- uintptr_t relative_pc;
std::string map_name;
if (BacktraceMap::IsValid(frame->map)) {
- relative_pc = BacktraceMap::GetRelativePc(frame->map, frame->pc);
if (!frame->map.name.empty()) {
map_name = frame->map.name.c_str();
if (map_name[0] == '[' && map_name[map_name.size() - 1] == ']') {
@@ -99,10 +97,9 @@
}
} else {
map_name = "<unknown>";
- relative_pc = frame->pc;
}
- std::string line(StringPrintf("#%02zu pc %" PRIPTR " ", frame->num, relative_pc));
+ std::string line(StringPrintf("#%02zu pc %" PRIPTR " ", frame->num, frame->rel_pc));
line += map_name;
// Special handling for non-zero offset maps, we need to print that
// information.
diff --git a/libbacktrace/UnwindCurrent.cpp b/libbacktrace/UnwindCurrent.cpp
index 3c509e6..2c87fa8 100644
--- a/libbacktrace/UnwindCurrent.cpp
+++ b/libbacktrace/UnwindCurrent.cpp
@@ -133,6 +133,11 @@
backtrace_frame_data_t* prev = &frames_.at(num_frames-1);
prev->stack_size = frame->sp - prev->sp;
}
+ if (BacktraceMap::IsValid(frame->map)) {
+ frame->rel_pc = frame->pc - frame->map.start + frame->map.load_bias;
+ } else {
+ frame->rel_pc = frame->pc;
+ }
num_frames++;
} else {
num_ignore_frames--;
diff --git a/libbacktrace/UnwindMap.cpp b/libbacktrace/UnwindMap.cpp
index af79562..0b8232b 100644
--- a/libbacktrace/UnwindMap.cpp
+++ b/libbacktrace/UnwindMap.cpp
@@ -57,7 +57,7 @@
map.start = unw_map.start;
map.end = unw_map.end;
map.offset = unw_map.offset;
- map.load_base = unw_map.load_base;
+ map.load_bias = unw_map.load_base;
map.flags = unw_map.flags;
map.name = unw_map.path;
@@ -106,7 +106,7 @@
map.start = unw_map.start;
map.end = unw_map.end;
map.offset = unw_map.offset;
- map.load_base = unw_map.load_base;
+ map.load_bias = unw_map.load_base;
map.flags = unw_map.flags;
map.name = unw_map.path;
diff --git a/libbacktrace/UnwindPtrace.cpp b/libbacktrace/UnwindPtrace.cpp
index 42ac1bc..87282ef 100644
--- a/libbacktrace/UnwindPtrace.cpp
+++ b/libbacktrace/UnwindPtrace.cpp
@@ -135,6 +135,11 @@
}
FillInMap(frame->pc, &frame->map);
+ if (BacktraceMap::IsValid(frame->map)) {
+ frame->rel_pc = frame->pc - frame->map.start + frame->map.load_bias;
+ } else {
+ frame->rel_pc = frame->pc;
+ }
frame->func_name = GetFunctionName(frame->pc, &frame->func_offset, &frame->map);
diff --git a/libbacktrace/backtrace_offline_test.cpp b/libbacktrace/backtrace_offline_test.cpp
index 465b3f9..16b1d79 100644
--- a/libbacktrace/backtrace_offline_test.cpp
+++ b/libbacktrace/backtrace_offline_test.cpp
@@ -167,9 +167,9 @@
// 2. Dump maps
for (auto it = map->begin(); it != map->end(); ++it) {
testdata += android::base::StringPrintf(
- "map: start: %" PRIxPTR " end: %" PRIxPTR " offset: %" PRIxPTR
- " load_base: %" PRIxPTR " flags: %d name: %s\n",
- it->start, it->end, it->offset, it->load_base, it->flags, it->name.c_str());
+ "map: start: %" PRIxPTR " end: %" PRIxPTR " offset: %" PRIxPTR " load_bias: %" PRIxPTR
+ " flags: %d name: %s\n",
+ it->start, it->end, it->offset, it->load_bias, it->flags, it->name.c_str());
}
// 3. Dump registers
testdata += android::base::StringPrintf("registers: %zu ", sizeof(arg.unw_context));
@@ -246,9 +246,9 @@
backtrace_map_t& map = testdata->maps.back();
int pos;
sscanf(line.c_str(),
- "map: start: %" SCNxPTR " end: %" SCNxPTR " offset: %" SCNxPTR
- " load_base: %" SCNxPTR " flags: %d name: %n",
- &map.start, &map.end, &map.offset, &map.load_base, &map.flags, &pos);
+ "map: start: %" SCNxPTR " end: %" SCNxPTR " offset: %" SCNxPTR " load_bias: %" SCNxPTR
+ " flags: %d name: %n",
+ &map.start, &map.end, &map.offset, &map.load_bias, &map.flags, &pos);
map.name = android::base::Trim(line.substr(pos));
} else if (android::base::StartsWith(line, "registers:")) {
size_t size;
@@ -392,8 +392,8 @@
// The last frame is outside of libart.so
ASSERT_EQ(testdata.symbols.size() + 1, backtrace->NumFrames());
for (size_t i = 0; i + 1 < backtrace->NumFrames(); ++i) {
- uintptr_t vaddr_in_file = backtrace->GetFrame(i)->pc - testdata.maps[0].start +
- testdata.maps[0].load_base;
+ uintptr_t vaddr_in_file =
+ backtrace->GetFrame(i)->pc - testdata.maps[0].start + testdata.maps[0].load_bias;
std::string name = FunctionNameForAddress(vaddr_in_file, testdata.symbols);
ASSERT_EQ(name, testdata.symbols[i].name);
}
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
index fb463b0..1ec6a45 100644
--- a/libbacktrace/backtrace_test.cpp
+++ b/libbacktrace/backtrace_test.cpp
@@ -784,6 +784,7 @@
backtrace_frame_data_t frame;
frame.num = 1;
frame.pc = 2;
+ frame.rel_pc = 2;
frame.sp = 0;
frame.stack_size = 0;
frame.func_offset = 0;
@@ -799,9 +800,10 @@
// Check map name empty, but exists.
frame.pc = 0xb0020;
+ frame.rel_pc = 0x20;
frame.map.start = 0xb0000;
frame.map.end = 0xbffff;
- frame.map.load_base = 0;
+ frame.map.load_bias = 0;
#if defined(__LP64__)
EXPECT_EQ("#01 pc 0000000000000020 <anonymous:00000000000b0000>",
#else
@@ -813,7 +815,7 @@
frame.pc = 0xc0020;
frame.map.start = 0xc0000;
frame.map.end = 0xcffff;
- frame.map.load_base = 0;
+ frame.map.load_bias = 0;
frame.map.name = "[anon:thread signal stack]";
#if defined(__LP64__)
EXPECT_EQ("#01 pc 0000000000000020 [anon:thread signal stack:00000000000c0000]",
@@ -824,6 +826,7 @@
// Check relative pc is set and map name is set.
frame.pc = 0x12345679;
+ frame.rel_pc = 0x12345678;
frame.map.name = "MapFake";
frame.map.start = 1;
frame.map.end = 1;
@@ -852,9 +855,10 @@
#endif
backtrace->FormatFrameData(&frame));
- // Check func_name is set, func offset is non-zero, and load_base is non-zero.
+ // Check func_name is set, func offset is non-zero, and load_bias is non-zero.
+ frame.rel_pc = 0x123456dc;
frame.func_offset = 645;
- frame.map.load_base = 100;
+ frame.map.load_bias = 100;
#if defined(__LP64__)
EXPECT_EQ("#01 pc 00000000123456dc MapFake (ProcFake+645)",
#else
@@ -1737,9 +1741,13 @@
FinishRemoteProcess(pid);
}
-TEST(libbacktrace, unwind_remote_through_signal_using_handler) { UnwindThroughSignal(false); }
+TEST(libbacktrace, unwind_remote_through_signal_using_handler) {
+ UnwindThroughSignal(false);
+}
-TEST(libbacktrace, unwind_remote_through_signal_using_action) { UnwindThroughSignal(true); }
+TEST(libbacktrace, unwind_remote_through_signal_using_action) {
+ UnwindThroughSignal(true);
+}
#if defined(ENABLE_PSS_TESTS)
#include "GetPss.h"
diff --git a/libbacktrace/include/backtrace/Backtrace.h b/libbacktrace/include/backtrace/Backtrace.h
index 4f73a65..b919e81 100644
--- a/libbacktrace/include/backtrace/Backtrace.h
+++ b/libbacktrace/include/backtrace/Backtrace.h
@@ -55,6 +55,7 @@
struct backtrace_frame_data_t {
size_t num; // The current fame number.
uintptr_t pc; // The absolute pc.
+ uintptr_t rel_pc; // The relative pc.
uintptr_t sp; // The top of the stack.
size_t stack_size; // The size of the stack, zero indicate an unknown stack size.
backtrace_map_t map; // The map associated with the given pc.
diff --git a/libbacktrace/include/backtrace/BacktraceMap.h b/libbacktrace/include/backtrace/BacktraceMap.h
index 8ab0dfa..02a50f7 100644
--- a/libbacktrace/include/backtrace/BacktraceMap.h
+++ b/libbacktrace/include/backtrace/BacktraceMap.h
@@ -41,7 +41,7 @@
uintptr_t start = 0;
uintptr_t end = 0;
uintptr_t offset = 0;
- uintptr_t load_base = 0;
+ uintptr_t load_bias = 0;
int flags = 0;
std::string name;
};
@@ -95,14 +95,6 @@
return map.end > 0;
}
- static uintptr_t GetRelativePc(const backtrace_map_t& map, uintptr_t pc) {
- if (IsValid(map)) {
- return pc - map.start + map.load_base;
- } else {
- return pc;
- }
- }
-
protected:
BacktraceMap(pid_t pid);
diff --git a/libmemunreachable/Android.bp b/libmemunreachable/Android.bp
index cdac76b..826a576 100644
--- a/libmemunreachable/Android.bp
+++ b/libmemunreachable/Android.bp
@@ -26,6 +26,7 @@
defaults: ["libmemunreachable_defaults"],
srcs: [
"Allocator.cpp",
+ "Binder.cpp",
"HeapWalker.cpp",
"LeakFolding.cpp",
"LeakPipe.cpp",
@@ -84,3 +85,18 @@
},
},
}
+
+cc_test {
+ name: "memunreachable_binder_test",
+ defaults: ["libmemunreachable_defaults"],
+ srcs: [
+ "tests/Binder_test.cpp",
+ "tests/MemUnreachable_test.cpp",
+ ],
+ shared_libs: [
+ "libbinder",
+ "libhwbinder",
+ "libmemunreachable",
+ "libutils",
+ ],
+}
diff --git a/libmemunreachable/Binder.cpp b/libmemunreachable/Binder.cpp
new file mode 100644
index 0000000..60512a3
--- /dev/null
+++ b/libmemunreachable/Binder.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sys/cdefs.h>
+#include <unistd.h>
+
+#include <functional>
+
+#include "Binder.h"
+#include "log.h"
+
+__BEGIN_DECLS
+
+// Weak undefined references to the symbols in libbinder and libhwbinder
+// so that libmemunreachable can call them in processes that have them
+// loaded without requiring libmemunreachable to have dependencies on them.
+ssize_t __attribute__((weak)) getBinderKernelReferences(size_t, uintptr_t*);
+ssize_t __attribute__((weak)) getHWBinderKernelReferences(size_t, uintptr_t*);
+
+__END_DECLS
+
+namespace android {
+
+static bool BinderReferencesToVector(allocator::vector<uintptr_t>& refs,
+ std::function<ssize_t(size_t, uintptr_t*)> fn) {
+ if (fn == nullptr) {
+ return true;
+ }
+
+ size_t size = refs.size();
+
+ do {
+ refs.resize(size);
+
+ ssize_t ret = fn(refs.size(), refs.data());
+ if (ret < 0) {
+ return false;
+ }
+
+ size = ret;
+ } while (size > refs.size());
+
+ refs.resize(size);
+ return true;
+}
+
+bool BinderReferences(allocator::vector<uintptr_t>& refs) {
+ refs.clear();
+
+ allocator::vector<uintptr_t> binder_refs{refs.get_allocator()};
+ if (BinderReferencesToVector(refs, getBinderKernelReferences)) {
+ refs.insert(refs.end(), binder_refs.begin(), binder_refs.end());
+ } else {
+ MEM_ALOGE("getBinderKernelReferences failed");
+ }
+
+ allocator::vector<uintptr_t> hwbinder_refs{refs.get_allocator()};
+ if (BinderReferencesToVector(hwbinder_refs, getHWBinderKernelReferences)) {
+ refs.insert(refs.end(), hwbinder_refs.begin(), hwbinder_refs.end());
+ } else {
+ MEM_ALOGE("getHWBinderKernelReferences failed");
+ }
+
+ return true;
+}
+
+} // namespace android
diff --git a/libunwindstack/Log.h b/libmemunreachable/Binder.h
similarity index 65%
copy from libunwindstack/Log.h
copy to libmemunreachable/Binder.h
index 2d01aa8..bf4fd3e 100644
--- a/libunwindstack/Log.h
+++ b/libmemunreachable/Binder.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,12 +14,15 @@
* limitations under the License.
*/
-#ifndef _LIBUNWINDSTACK_LOG_H
-#define _LIBUNWINDSTACK_LOG_H
+#ifndef LIBMEMUNREACHABLE_BINDER_H_
+#define LIBMEMUNREACHABLE_BINDER_H_
-#include <stdint.h>
+#include "Allocator.h"
-void log_to_stdout(bool enable);
-void log(uint8_t indent, const char* format, ...);
+namespace android {
-#endif // _LIBUNWINDSTACK_LOG_H
+bool BinderReferences(allocator::vector<uintptr_t>& refs);
+
+} // namespace android
+
+#endif // LIBMEMUNREACHABLE_BINDER_H_
diff --git a/libmemunreachable/MemUnreachable.cpp b/libmemunreachable/MemUnreachable.cpp
index a1f74c3..5e062fd 100644
--- a/libmemunreachable/MemUnreachable.cpp
+++ b/libmemunreachable/MemUnreachable.cpp
@@ -28,6 +28,7 @@
#include <backtrace.h>
#include "Allocator.h"
+#include "Binder.h"
#include "HeapWalker.h"
#include "Leak.h"
#include "LeakFolding.h"
@@ -53,7 +54,8 @@
MemUnreachable(pid_t pid, Allocator<void> allocator)
: pid_(pid), allocator_(allocator), heap_walker_(allocator_) {}
bool CollectAllocations(const allocator::vector<ThreadInfo>& threads,
- const allocator::vector<Mapping>& mappings);
+ const allocator::vector<Mapping>& mappings,
+ const allocator::vector<uintptr_t>& refs);
bool GetUnreachableMemory(allocator::vector<Leak>& leaks, size_t limit, size_t* num_leaks,
size_t* leak_bytes);
size_t Allocations() { return heap_walker_.Allocations(); }
@@ -82,7 +84,8 @@
}
bool MemUnreachable::CollectAllocations(const allocator::vector<ThreadInfo>& threads,
- const allocator::vector<Mapping>& mappings) {
+ const allocator::vector<Mapping>& mappings,
+ const allocator::vector<uintptr_t>& refs) {
MEM_ALOGI("searching process %d for allocations", pid_);
allocator::vector<Mapping> heap_mappings{mappings};
allocator::vector<Mapping> anon_mappings{mappings};
@@ -118,6 +121,8 @@
heap_walker_.Root(thread_it->regs);
}
+ heap_walker_.Root(refs);
+
MEM_ALOGI("searching done");
return true;
@@ -282,6 +287,7 @@
ThreadCapture thread_capture(parent_pid, heap);
allocator::vector<ThreadInfo> thread_info(heap);
allocator::vector<Mapping> mappings(heap);
+ allocator::vector<uintptr_t> refs(heap);
// ptrace all the threads
if (!thread_capture.CaptureThreads()) {
@@ -301,6 +307,11 @@
return 1;
}
+ if (!BinderReferences(refs)) {
+ continue_parent_sem.Post();
+ return 1;
+ }
+
// malloc must be enabled to call fork, at_fork handlers take the same
// locks as ScopedDisableMalloc. All threads are paused in ptrace, so
// memory state is still consistent. Unfreeze the original thread so it
@@ -326,7 +337,7 @@
MemUnreachable unreachable{parent_pid, heap};
- if (!unreachable.CollectAllocations(thread_info, mappings)) {
+ if (!unreachable.CollectAllocations(thread_info, mappings, refs)) {
_exit(2);
}
size_t num_allocations = unreachable.Allocations();
diff --git a/libmemunreachable/tests/Binder_test.cpp b/libmemunreachable/tests/Binder_test.cpp
new file mode 100644
index 0000000..6e85d5a
--- /dev/null
+++ b/libmemunreachable/tests/Binder_test.cpp
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <signal.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <binder/Binder.h>
+#include <binder/IBinder.h>
+#include <binder/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <binder/ProcessState.h>
+
+#include <gtest/gtest.h>
+
+#include "Allocator.h"
+#include "Binder.h"
+
+namespace android {
+
+static const String16 service_name("test.libmemunreachable_binder");
+
+class BinderService : public BBinder {
+ public:
+ BinderService() = default;
+ virtual ~BinderService() = default;
+
+ virtual status_t onTransact(uint32_t /*code*/, const Parcel& data, Parcel* reply,
+ uint32_t /*flags*/ = 0) {
+ reply->writeStrongBinder(ref);
+ ref = data.readStrongBinder();
+ return 0;
+ }
+
+ private:
+ sp<IBinder> ref;
+};
+
+class BinderObject : public BBinder {
+ public:
+ BinderObject() = default;
+ ~BinderObject() = default;
+};
+
+class ServiceProcess {
+ public:
+ ServiceProcess() : child_(0) {}
+ ~ServiceProcess() { Stop(); }
+
+ bool Run() {
+ pid_t ret = fork();
+ if (ret < 0) {
+ return false;
+ } else if (ret == 0) {
+ // child
+ _exit(Service());
+ } else {
+ // parent
+ child_ = ret;
+ return true;
+ }
+ }
+
+ bool Stop() {
+ if (child_ > 0) {
+ if (kill(child_, SIGTERM)) {
+ return false;
+ }
+ int status = 0;
+ if (TEMP_FAILURE_RETRY(waitpid(child_, &status, 0)) != child_) {
+ return false;
+ }
+ child_ = 0;
+ return WIFEXITED(status) && WEXITSTATUS(status) == 0;
+ }
+
+ return true;
+ }
+
+ int Service() {
+ sp<ProcessState> proc{ProcessState::self()};
+ sp<IServiceManager> sm = defaultServiceManager();
+ if (sm == nullptr) {
+ fprintf(stderr, "Failed to get service manager\n");
+ return 1;
+ }
+ if (sm->addService(service_name, new BinderService()) != OK) {
+ fprintf(stderr, "Failed to add test service\n");
+ return 1;
+ }
+ proc->startThreadPool();
+ pause();
+ return 0;
+ }
+
+ private:
+ pid_t child_;
+};
+
+class BinderTest : public ::testing::Test {
+ protected:
+ ServiceProcess service_process_;
+};
+
+TEST_F(BinderTest, binder) {
+ ServiceProcess service_process;
+ ASSERT_TRUE(service_process.Run());
+
+ sp<IServiceManager> sm = defaultServiceManager();
+ ASSERT_TRUE(sm != nullptr);
+
+ // A small sleep allows the service to start, which
+ // prevents a longer sleep in getService.
+ usleep(100000);
+
+ sp<IBinder> service = sm->getService(service_name);
+ ASSERT_TRUE(service != nullptr);
+
+ sp<IBinder> binder{new BinderObject()};
+
+ Parcel send;
+ Parcel reply;
+
+ send.writeStrongBinder(binder);
+ status_t rv = service->transact(0, send, &reply);
+ ASSERT_EQ(static_cast<status_t>(OK), rv);
+
+ Heap heap;
+ allocator::vector<uintptr_t> refs{heap};
+
+ ASSERT_TRUE(BinderReferences(refs));
+
+ bool found_ref = false;
+ for (auto ref : refs) {
+ if (ref == reinterpret_cast<uintptr_t>(binder.get())) {
+ found_ref = true;
+ }
+ }
+
+ ASSERT_TRUE(found_ref);
+}
+
+} // namespace android
diff --git a/libmetricslogger/Android.bp b/libmetricslogger/Android.bp
index 38859d1..26a041a 100644
--- a/libmetricslogger/Android.bp
+++ b/libmetricslogger/Android.bp
@@ -31,7 +31,6 @@
// -----------------------------------------------------------------------------
cc_library_shared {
name: "libmetricslogger",
- vendor_available: true,
srcs: metricslogger_lib_src_files,
defaults: ["metricslogger_defaults"],
}
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index 36a2e44..7ccd7db 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -15,7 +15,7 @@
*/
#include "nativeloader/native_loader.h"
-#include "ScopedUtfChars.h"
+#include <nativehelper/ScopedUtfChars.h>
#include <dlfcn.h>
#ifdef __ANDROID__
diff --git a/libprocessgroup/include/processgroup/processgroup.h b/libprocessgroup/include/processgroup/processgroup.h
index f0c3795..9fa4154 100644
--- a/libprocessgroup/include/processgroup/processgroup.h
+++ b/libprocessgroup/include/processgroup/processgroup.h
@@ -33,6 +33,10 @@
int createProcessGroup(uid_t uid, int initialPid);
+bool setProcessGroupSwappiness(uid_t uid, int initialPid, int swappiness);
+bool setProcessGroupSoftLimit(uid_t uid, int initialPid, int64_t softLimitInBytes);
+bool setProcessGroupLimit(uid_t uid, int initialPid, int64_t limitInBytes);
+
void removeAllProcessGroups(void);
__END_DECLS
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index 9b8248e..8526b3a 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -35,12 +35,15 @@
#include <set>
#include <thread>
+#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
#include <private/android_filesystem_config.h>
#include <processgroup/processgroup.h>
+using android::base::WriteStringToFile;
+
using namespace std::chrono_literals;
#define MEM_CGROUP_PATH "/dev/memcg/apps"
@@ -402,22 +405,40 @@
strlcat(path, PROCESSGROUP_CGROUP_PROCS_FILE, sizeof(path));
- int fd = open(path, O_WRONLY);
- if (fd == -1) {
- int ret = -errno;
- PLOG(ERROR) << "Failed to open " << path;
- return ret;
- }
-
- char pid[PROCESSGROUP_MAX_PID_LEN + 1] = {0};
- int len = snprintf(pid, sizeof(pid), "%d", initialPid);
-
int ret = 0;
- if (write(fd, pid, len) < 0) {
+ if (!WriteStringToFile(std::to_string(initialPid), path)) {
ret = -errno;
- PLOG(ERROR) << "Failed to write '" << pid << "' to " << path;
+ PLOG(ERROR) << "Failed to write '" << initialPid << "' to " << path;
}
- close(fd);
return ret;
}
+
+static bool setProcessGroupValue(uid_t uid, int pid, const char* fileName, int64_t value) {
+ char path[PROCESSGROUP_MAX_PATH_LEN] = {0};
+ if (strcmp(getCgroupRootPath(), MEM_CGROUP_PATH)) {
+ PLOG(ERROR) << "Memcg is not mounted." << path;
+ return false;
+ }
+
+ convertUidPidToPath(path, sizeof(path), uid, pid);
+ strlcat(path, fileName, sizeof(path));
+
+ if (!WriteStringToFile(std::to_string(value), path)) {
+ PLOG(ERROR) << "Failed to write '" << value << "' to " << path;
+ return false;
+ }
+ return true;
+}
+
+bool setProcessGroupSwappiness(uid_t uid, int pid, int swappiness) {
+ return setProcessGroupValue(uid, pid, "/memory.swappiness", swappiness);
+}
+
+bool setProcessGroupSoftLimit(uid_t uid, int pid, int64_t soft_limit_in_bytes) {
+ return setProcessGroupValue(uid, pid, "/memory.soft_limit_in_bytes", soft_limit_in_bytes);
+}
+
+bool setProcessGroupLimit(uid_t uid, int pid, int64_t limit_in_bytes) {
+ return setProcessGroupValue(uid, pid, "/memory.limit_in_bytes", limit_in_bytes);
+}
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index a6044c8..04c4cfa 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -44,6 +44,7 @@
cc_library {
name: "libunwindstack",
defaults: ["libunwindstack_flags"],
+ export_include_dirs: ["include"],
srcs: [
"ArmExidx.cpp",
@@ -114,6 +115,7 @@
"tests/MemoryRangeTest.cpp",
"tests/MemoryRemoteTest.cpp",
"tests/MemoryTest.cpp",
+ "tests/RegsStepIfSignalHandlerTest.cpp",
"tests/RegsTest.cpp",
"tests/SymbolsTest.cpp",
"tests/UnwindTest.cpp",
@@ -150,10 +152,10 @@
}
//-------------------------------------------------------------------------
-// Utility Executables
+// Tools
//-------------------------------------------------------------------------
cc_defaults {
- name: "libunwindstack_executables",
+ name: "libunwindstack_tools",
defaults: ["libunwindstack_flags"],
shared_libs: [
@@ -161,18 +163,40 @@
"libbase",
"liblzma",
],
+}
- static_libs: [
- "liblog",
+cc_binary {
+ name: "unwind",
+ defaults: ["libunwindstack_tools"],
+
+ srcs: [
+ "tools/unwind.cpp",
],
+
+ target: {
+ linux: {
+ host_ldlibs: [
+ "-lrt",
+ ],
+ },
+ },
}
cc_binary {
name: "unwind_info",
- defaults: ["libunwindstack_executables"],
+ defaults: ["libunwindstack_tools"],
srcs: [
- "unwind_info.cpp",
+ "tools/unwind_info.cpp",
+ ],
+}
+
+cc_binary {
+ name: "unwind_symbols",
+ defaults: ["libunwindstack_tools"],
+
+ srcs: [
+ "tools/unwind_symbols.cpp",
],
}
diff --git a/libunwindstack/ArmExidx.cpp b/libunwindstack/ArmExidx.cpp
index 5c7caca..fed3e0e 100644
--- a/libunwindstack/ArmExidx.cpp
+++ b/libunwindstack/ArmExidx.cpp
@@ -21,12 +21,15 @@
#include <android-base/stringprintf.h>
+#include <unwindstack/Log.h>
+#include <unwindstack/Memory.h>
+#include <unwindstack/Regs.h>
+
#include "ArmExidx.h"
#include "Check.h"
-#include "Log.h"
#include "Machine.h"
-#include "Memory.h"
-#include "Regs.h"
+
+namespace unwindstack {
void ArmExidx::LogRawData() {
std::string log_str("Raw Data:");
@@ -684,3 +687,5 @@
while (Decode());
return status_ == ARM_STATUS_FINISH;
}
+
+} // namespace unwindstack
diff --git a/libunwindstack/ArmExidx.h b/libunwindstack/ArmExidx.h
index 8c7f15a..f4361d4 100644
--- a/libunwindstack/ArmExidx.h
+++ b/libunwindstack/ArmExidx.h
@@ -21,6 +21,8 @@
#include <deque>
+namespace unwindstack {
+
// Forward declarations.
class Memory;
class RegsArm;
@@ -105,4 +107,6 @@
bool pc_set_ = false;
};
+} // namespace unwindstack
+
#endif // _LIBUNWINDSTACK_ARM_EXIDX_H
diff --git a/libunwindstack/Check.h b/libunwindstack/Check.h
index e0c48c7..2d216d7 100644
--- a/libunwindstack/Check.h
+++ b/libunwindstack/Check.h
@@ -19,7 +19,9 @@
#include <stdlib.h>
-#include "Log.h"
+#include <unwindstack/Log.h>
+
+namespace unwindstack {
#define CHECK(assertion) \
if (__builtin_expect(!(assertion), false)) { \
@@ -27,4 +29,6 @@
abort(); \
}
+} // namespace unwindstack
+
#endif // _LIBUNWINDSTACK_ERROR_H
diff --git a/libunwindstack/DwarfCfa.cpp b/libunwindstack/DwarfCfa.cpp
index 006f039..b1d55ba 100644
--- a/libunwindstack/DwarfCfa.cpp
+++ b/libunwindstack/DwarfCfa.cpp
@@ -23,12 +23,15 @@
#include <android-base/stringprintf.h>
+#include <unwindstack/DwarfLocation.h>
+#include <unwindstack/Log.h>
+
#include "DwarfCfa.h"
#include "DwarfEncoding.h"
-#include "DwarfMemory.h"
+#include "DwarfError.h"
#include "DwarfOp.h"
-#include "DwarfStructs.h"
-#include "Log.h"
+
+namespace unwindstack {
template <typename AddressType>
constexpr typename DwarfCfa<AddressType>::process_func DwarfCfa<AddressType>::kCallbackTable[64];
@@ -711,3 +714,5 @@
// Explicitly instantiate DwarfCfa.
template class DwarfCfa<uint32_t>;
template class DwarfCfa<uint64_t>;
+
+} // namespace unwindstack
diff --git a/libunwindstack/DwarfCfa.h b/libunwindstack/DwarfCfa.h
index 42ebae1..62b9b7a 100644
--- a/libunwindstack/DwarfCfa.h
+++ b/libunwindstack/DwarfCfa.h
@@ -24,10 +24,13 @@
#include <type_traits>
#include <vector>
+#include <unwindstack/DwarfLocation.h>
+#include <unwindstack/DwarfMemory.h>
+#include <unwindstack/DwarfStructs.h>
+
#include "DwarfError.h"
-#include "DwarfLocation.h"
-#include "DwarfMemory.h"
-#include "DwarfStructs.h"
+
+namespace unwindstack {
// DWARF Standard home: http://dwarfstd.org/
// This code is based on DWARF 4: http://http://dwarfstd.org/doc/DWARF4.pdf
@@ -252,4 +255,6 @@
};
};
+} // namespace unwindstack
+
#endif // _LIBUNWINDSTACK_DWARF_CFA_H
diff --git a/libunwindstack/DwarfDebugFrame.cpp b/libunwindstack/DwarfDebugFrame.cpp
index 3ac02fc..5707596 100644
--- a/libunwindstack/DwarfDebugFrame.cpp
+++ b/libunwindstack/DwarfDebugFrame.cpp
@@ -19,11 +19,14 @@
#include <algorithm>
+#include <unwindstack/DwarfStructs.h>
+#include <unwindstack/Memory.h>
+
#include "DwarfDebugFrame.h"
-#include "DwarfMemory.h"
-#include "DwarfSection.h"
-#include "DwarfStructs.h"
-#include "Memory.h"
+#include "DwarfEncoding.h"
+#include "DwarfError.h"
+
+namespace unwindstack {
template <typename AddressType>
bool DwarfDebugFrame<AddressType>::Init(uint64_t offset, uint64_t size) {
@@ -309,3 +312,5 @@
// Explicitly instantiate DwarfDebugFrame.
template class DwarfDebugFrame<uint32_t>;
template class DwarfDebugFrame<uint64_t>;
+
+} // namespace unwindstack
diff --git a/libunwindstack/DwarfDebugFrame.h b/libunwindstack/DwarfDebugFrame.h
index 320368c..6a6178e 100644
--- a/libunwindstack/DwarfDebugFrame.h
+++ b/libunwindstack/DwarfDebugFrame.h
@@ -21,7 +21,9 @@
#include <vector>
-#include "DwarfSection.h"
+#include <unwindstack/DwarfSection.h>
+
+namespace unwindstack {
template <typename AddressType>
class DwarfDebugFrame : public DwarfSectionImpl<AddressType> {
@@ -73,4 +75,6 @@
std::vector<FdeInfo> fdes_;
};
+} // namespace unwindstack
+
#endif // _LIBUNWINDSTACK_DWARF_DEBUG_FRAME_H
diff --git a/libunwindstack/DwarfEhFrame.cpp b/libunwindstack/DwarfEhFrame.cpp
index 937b6bd..d0b35c3 100644
--- a/libunwindstack/DwarfEhFrame.cpp
+++ b/libunwindstack/DwarfEhFrame.cpp
@@ -16,12 +16,14 @@
#include <stdint.h>
+#include <unwindstack/DwarfStructs.h>
+#include <unwindstack/Memory.h>
+
#include "Check.h"
#include "DwarfEhFrame.h"
-#include "DwarfMemory.h"
-#include "DwarfSection.h"
-#include "DwarfStructs.h"
-#include "Memory.h"
+#include "DwarfError.h"
+
+namespace unwindstack {
template <typename AddressType>
bool DwarfEhFrame<AddressType>::Init(uint64_t offset, uint64_t size) {
@@ -211,3 +213,5 @@
// Explicitly instantiate DwarfEhFrame.
template class DwarfEhFrame<uint32_t>;
template class DwarfEhFrame<uint64_t>;
+
+} // namespace unwindstack
diff --git a/libunwindstack/DwarfEhFrame.h b/libunwindstack/DwarfEhFrame.h
index e6909ed..4207b42 100644
--- a/libunwindstack/DwarfEhFrame.h
+++ b/libunwindstack/DwarfEhFrame.h
@@ -19,7 +19,9 @@
#include <stdint.h>
-#include "DwarfSection.h"
+#include <unwindstack/DwarfSection.h>
+
+namespace unwindstack {
// Forward declarations.
class Memory;
@@ -86,4 +88,6 @@
std::unordered_map<uint64_t, FdeInfo> fde_info_;
};
+} // namespace unwindstack
+
#endif // _LIBUNWINDSTACK_DWARF_EH_FRAME_H
diff --git a/libunwindstack/DwarfEncoding.h b/libunwindstack/DwarfEncoding.h
index 0ff3b8c..20db222 100644
--- a/libunwindstack/DwarfEncoding.h
+++ b/libunwindstack/DwarfEncoding.h
@@ -19,6 +19,8 @@
#include <stdint.h>
+namespace unwindstack {
+
enum DwarfEncoding : uint8_t {
DW_EH_PE_omit = 0xff,
@@ -44,4 +46,6 @@
DW_EH_PE_block = 0x0f,
};
+} // namespace unwindstack
+
#endif // _LIBUNWINDSTACK_DWARF_ENCODING_H
diff --git a/libunwindstack/DwarfError.h b/libunwindstack/DwarfError.h
index c00f17d..54199b8 100644
--- a/libunwindstack/DwarfError.h
+++ b/libunwindstack/DwarfError.h
@@ -19,6 +19,8 @@
#include <stdint.h>
+namespace unwindstack {
+
enum DwarfError : uint8_t {
DWARF_ERROR_NONE,
DWARF_ERROR_MEMORY_INVALID,
@@ -31,4 +33,6 @@
DWARF_ERROR_UNSUPPORTED_VERSION,
};
+} // namespace unwindstack
+
#endif // _LIBUNWINDSTACK_DWARF_ERROR_H
diff --git a/libunwindstack/DwarfMemory.cpp b/libunwindstack/DwarfMemory.cpp
index a984fc6..b6e0412 100644
--- a/libunwindstack/DwarfMemory.cpp
+++ b/libunwindstack/DwarfMemory.cpp
@@ -18,10 +18,13 @@
#include <string>
+#include <unwindstack/DwarfMemory.h>
+#include <unwindstack/Memory.h>
+
#include "Check.h"
#include "DwarfEncoding.h"
-#include "DwarfMemory.h"
-#include "Memory.h"
+
+namespace unwindstack {
bool DwarfMemory::ReadBytes(void* dst, size_t num_bytes) {
if (!memory_->Read(cur_offset_, dst, num_bytes)) {
@@ -246,3 +249,5 @@
template bool DwarfMemory::ReadEncodedValue<uint32_t>(uint8_t, uint64_t*);
template bool DwarfMemory::ReadEncodedValue<uint64_t>(uint8_t, uint64_t*);
+
+} // namespace unwindstack
diff --git a/libunwindstack/DwarfOp.cpp b/libunwindstack/DwarfOp.cpp
index 507ca08..b3fd0df 100644
--- a/libunwindstack/DwarfOp.cpp
+++ b/libunwindstack/DwarfOp.cpp
@@ -22,12 +22,15 @@
#include <android-base/stringprintf.h>
+#include <unwindstack/DwarfMemory.h>
+#include <unwindstack/Log.h>
+#include <unwindstack/Memory.h>
+#include <unwindstack/Regs.h>
+
#include "DwarfError.h"
-#include "DwarfMemory.h"
#include "DwarfOp.h"
-#include "Log.h"
-#include "Memory.h"
-#include "Regs.h"
+
+namespace unwindstack {
template <typename AddressType>
constexpr typename DwarfOp<AddressType>::OpCallback DwarfOp<AddressType>::kCallbackTable[256];
@@ -460,3 +463,5 @@
// Explicitly instantiate DwarfOp.
template class DwarfOp<uint32_t>;
template class DwarfOp<uint64_t>;
+
+} // namespace unwindstack
diff --git a/libunwindstack/DwarfOp.h b/libunwindstack/DwarfOp.h
index 0f4b36d..c29bf35 100644
--- a/libunwindstack/DwarfOp.h
+++ b/libunwindstack/DwarfOp.h
@@ -25,6 +25,9 @@
#include <vector>
#include "DwarfEncoding.h"
+#include "DwarfError.h"
+
+namespace unwindstack {
enum DwarfVersion : uint8_t {
DWARF_VERSION_2 = 2,
@@ -1633,4 +1636,6 @@
};
};
+} // namespace unwindstack
+
#endif // _LIBUNWINDSTACK_DWARF_OP_H
diff --git a/libunwindstack/DwarfSection.cpp b/libunwindstack/DwarfSection.cpp
index 4c98aa3..1234eb1 100644
--- a/libunwindstack/DwarfSection.cpp
+++ b/libunwindstack/DwarfSection.cpp
@@ -16,16 +16,22 @@
#include <stdint.h>
+#include <unwindstack/DwarfLocation.h>
+#include <unwindstack/DwarfMemory.h>
+#include <unwindstack/DwarfSection.h>
+#include <unwindstack/DwarfStructs.h>
+#include <unwindstack/Log.h>
+#include <unwindstack/Memory.h>
+#include <unwindstack/Regs.h>
+
#include "DwarfCfa.h"
+#include "DwarfEncoding.h"
#include "DwarfError.h"
-#include "DwarfLocation.h"
-#include "DwarfMemory.h"
#include "DwarfOp.h"
-#include "DwarfSection.h"
-#include "DwarfStructs.h"
-#include "Log.h"
-#include "Memory.h"
-#include "Regs.h"
+
+namespace unwindstack {
+
+DwarfSection::DwarfSection(Memory* memory) : memory_(memory), last_error_(DWARF_ERROR_NONE) {}
const DwarfFde* DwarfSection::GetFdeFromPc(uint64_t pc) {
uint64_t fde_offset;
@@ -42,6 +48,7 @@
}
bool DwarfSection::Step(uint64_t pc, Regs* regs, Memory* process_memory) {
+ last_error_ = DWARF_ERROR_NONE;
const DwarfFde* fde = GetFdeFromPc(pc);
if (fde == nullptr || fde->cie == nullptr) {
last_error_ = DWARF_ERROR_ILLEGAL_STATE;
@@ -248,6 +255,9 @@
last_error_ = DWARF_ERROR_MEMORY_INVALID;
return false;
}
+ // Set the default for the lsda encoding.
+ cie->lsda_encoding = DW_EH_PE_omit;
+
if (length32 == static_cast<uint32_t>(-1)) {
// 64 bit Cie
uint64_t length64;
@@ -541,3 +551,5 @@
// Explicitly instantiate DwarfSectionImpl
template class DwarfSectionImpl<uint32_t>;
template class DwarfSectionImpl<uint64_t>;
+
+} // namespace unwindstack
diff --git a/libunwindstack/Elf.cpp b/libunwindstack/Elf.cpp
index ad1447a..4fc7c67 100644
--- a/libunwindstack/Elf.cpp
+++ b/libunwindstack/Elf.cpp
@@ -23,12 +23,17 @@
#define LOG_TAG "unwind"
#include <log/log.h>
-#include "Elf.h"
-#include "ElfInterface.h"
+#include <unwindstack/Elf.h>
+#include <unwindstack/ElfInterface.h>
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Memory.h>
+#include <unwindstack/Regs.h>
+
#include "ElfInterfaceArm.h"
#include "Machine.h"
-#include "Memory.h"
-#include "Regs.h"
+#include "Symbols.h"
+
+namespace unwindstack {
bool Elf::Init() {
if (!memory_) {
@@ -71,6 +76,37 @@
}
}
+bool Elf::GetSoname(std::string* name) {
+ return valid_ && interface_->GetSoname(name);
+}
+
+uint64_t Elf::GetRelPc(uint64_t pc, const MapInfo* map_info) {
+ uint64_t load_bias = 0;
+ if (valid()) {
+ load_bias = interface_->load_bias();
+ }
+
+ return pc - map_info->start + load_bias + map_info->elf_offset;
+}
+
+bool Elf::GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) {
+ return valid_ && (interface_->GetFunctionName(addr, name, func_offset) ||
+ (gnu_debugdata_interface_ &&
+ gnu_debugdata_interface_->GetFunctionName(addr, name, func_offset)));
+}
+
+bool Elf::Step(uint64_t rel_pc, Regs* regs, Memory* process_memory) {
+ return valid_ && (regs->StepIfSignalHandler(rel_pc, this, process_memory) ||
+ interface_->Step(rel_pc, regs, process_memory) ||
+ (gnu_debugdata_interface_ &&
+ gnu_debugdata_interface_->Step(rel_pc, regs, process_memory)));
+}
+
+uint64_t Elf::GetLoadBias() {
+ if (!valid_) return 0;
+ return interface_->load_bias();
+}
+
bool Elf::IsValidElf(Memory* memory) {
if (memory == nullptr) {
return false;
@@ -112,24 +148,27 @@
machine_type_ = e_machine;
if (e_machine == EM_ARM) {
interface.reset(new ElfInterfaceArm(memory));
- } else {
+ } else if (e_machine == EM_386) {
interface.reset(new ElfInterface32(memory));
+ } else {
+ ALOGI("32 bit elf that is neither arm nor x86: e_machine = %d\n", e_machine);
+ return nullptr;
}
} else if (class_type_ == ELFCLASS64) {
Elf64_Half e_machine;
if (!memory->Read(EI_NIDENT + sizeof(Elf64_Half), &e_machine, sizeof(e_machine))) {
return nullptr;
}
-
if (e_machine != EM_AARCH64 && e_machine != EM_X86_64) {
// Unsupported.
ALOGI("64 bit elf that is neither aarch64 nor x86_64: e_machine = %d\n", e_machine);
return nullptr;
}
-
machine_type_ = e_machine;
interface.reset(new ElfInterface64(memory));
}
return interface.release();
}
+
+} // namespace unwindstack
diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp
index 7d38ee0..75abc85 100644
--- a/libunwindstack/ElfInterface.cpp
+++ b/libunwindstack/ElfInterface.cpp
@@ -24,15 +24,18 @@
#include <Xz.h>
#include <XzCrc64.h>
+#include <unwindstack/DwarfSection.h>
+#include <unwindstack/ElfInterface.h>
+#include <unwindstack/Log.h>
+#include <unwindstack/Memory.h>
+#include <unwindstack/Regs.h>
+
#include "DwarfDebugFrame.h"
#include "DwarfEhFrame.h"
-#include "DwarfSection.h"
-#include "ElfInterface.h"
-#include "Log.h"
-#include "Memory.h"
-#include "Regs.h"
#include "Symbols.h"
+namespace unwindstack {
+
ElfInterface::~ElfInterface() {
for (auto symbol : symbols_) {
delete symbol;
@@ -387,3 +390,5 @@
uint64_t*);
template bool ElfInterface::GetFunctionNameWithTemplate<Elf64_Sym>(uint64_t, std::string*,
uint64_t*);
+
+} // namespace unwindstack
diff --git a/libunwindstack/ElfInterfaceArm.cpp b/libunwindstack/ElfInterfaceArm.cpp
index bab84cc..66bc51f 100644
--- a/libunwindstack/ElfInterfaceArm.cpp
+++ b/libunwindstack/ElfInterfaceArm.cpp
@@ -17,12 +17,14 @@
#include <elf.h>
#include <stdint.h>
+#include <unwindstack/Memory.h>
+#include <unwindstack/Regs.h>
+
#include "ArmExidx.h"
-#include "ElfInterface.h"
#include "ElfInterfaceArm.h"
#include "Machine.h"
-#include "Memory.h"
-#include "Regs.h"
+
+namespace unwindstack {
bool ElfInterfaceArm::FindEntry(uint32_t pc, uint64_t* entry_offset) {
if (start_offset_ == 0 || total_entries_ == 0) {
@@ -127,3 +129,5 @@
}
return false;
}
+
+} // namespace unwindstack
diff --git a/libunwindstack/ElfInterfaceArm.h b/libunwindstack/ElfInterfaceArm.h
index ece694f..1f4e8cb 100644
--- a/libunwindstack/ElfInterfaceArm.h
+++ b/libunwindstack/ElfInterfaceArm.h
@@ -23,8 +23,10 @@
#include <iterator>
#include <unordered_map>
-#include "ElfInterface.h"
-#include "Memory.h"
+#include <unwindstack/ElfInterface.h>
+#include <unwindstack/Memory.h>
+
+namespace unwindstack {
class ElfInterfaceArm : public ElfInterface32 {
public:
@@ -87,4 +89,6 @@
std::unordered_map<size_t, uint32_t> addrs_;
};
+} // namespace unwindstack
+
#endif // _LIBUNWINDSTACK_ELF_INTERFACE_ARM_H
diff --git a/libunwindstack/Log.cpp b/libunwindstack/Log.cpp
index faeb66c..436e23c 100644
--- a/libunwindstack/Log.cpp
+++ b/libunwindstack/Log.cpp
@@ -25,7 +25,9 @@
#include <android-base/stringprintf.h>
-#include "Log.h"
+#include <unwindstack/Log.h>
+
+namespace unwindstack {
static bool g_print_to_stdout = false;
@@ -51,3 +53,5 @@
}
va_end(args);
}
+
+} // namespace unwindstack
diff --git a/libunwindstack/Machine.h b/libunwindstack/Machine.h
index bcc3788..1fb9309 100644
--- a/libunwindstack/Machine.h
+++ b/libunwindstack/Machine.h
@@ -19,6 +19,8 @@
#include <stdint.h>
+namespace unwindstack {
+
enum ArmReg : uint16_t {
ARM_REG_R0 = 0,
ARM_REG_R1,
@@ -134,4 +136,6 @@
X86_64_REG_PC = X86_64_REG_RIP,
};
+} // namespace unwindstack
+
#endif // _LIBUNWINDSTACK_MACHINE_H
diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp
index d7b483d..d0e1216 100644
--- a/libunwindstack/MapInfo.cpp
+++ b/libunwindstack/MapInfo.cpp
@@ -20,10 +20,12 @@
#include <memory>
#include <string>
-#include "Elf.h"
-#include "MapInfo.h"
-#include "Maps.h"
-#include "Memory.h"
+#include <unwindstack/Elf.h>
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Maps.h>
+#include <unwindstack/Memory.h>
+
+namespace unwindstack {
Memory* MapInfo::CreateMemory(pid_t pid) {
if (end <= start) {
@@ -86,3 +88,5 @@
// don't try to reinit the object.
return elf;
}
+
+} // namespace unwindstack
diff --git a/libunwindstack/Maps.cpp b/libunwindstack/Maps.cpp
index b869918..8a90423 100644
--- a/libunwindstack/Maps.cpp
+++ b/libunwindstack/Maps.cpp
@@ -29,7 +29,11 @@
#include <string>
#include <vector>
-#include "Maps.h"
+#include <unwindstack/Elf.h>
+#include <unwindstack/Maps.h>
+#include <unwindstack/Memory.h>
+
+namespace unwindstack {
MapInfo* Maps::Find(uint64_t pc) {
if (maps_.empty()) {
@@ -196,3 +200,5 @@
}
return true;
}
+
+} // namespace unwindstack
diff --git a/libunwindstack/Memory.cpp b/libunwindstack/Memory.cpp
index 9e46509..8c36055 100644
--- a/libunwindstack/Memory.cpp
+++ b/libunwindstack/Memory.cpp
@@ -28,7 +28,11 @@
#include <android-base/unique_fd.h>
-#include "Memory.h"
+#include <unwindstack/Memory.h>
+
+#include "Check.h"
+
+namespace unwindstack {
bool Memory::ReadString(uint64_t addr, std::string* string, uint64_t max_read) {
string->clear();
@@ -245,6 +249,11 @@
return true;
}
+MemoryRange::MemoryRange(Memory* memory, uint64_t begin, uint64_t end)
+ : memory_(memory), begin_(begin), length_(end - begin) {
+ CHECK(end > begin);
+}
+
bool MemoryRange::Read(uint64_t addr, void* dst, size_t size) {
uint64_t max_read;
if (__builtin_add_overflow(addr, size, &max_read) || max_read > length_) {
@@ -253,3 +262,5 @@
// The check above guarantees that addr + begin_ will not overflow.
return memory_->Read(addr + begin_, dst, size);
}
+
+} // namespace unwindstack
diff --git a/libunwindstack/Regs.cpp b/libunwindstack/Regs.cpp
index 92b6e22..dea7b87 100644
--- a/libunwindstack/Regs.cpp
+++ b/libunwindstack/Regs.cpp
@@ -21,24 +21,17 @@
#include <vector>
+#include <unwindstack/Elf.h>
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Memory.h>
+#include <unwindstack/Regs.h>
+
#include "Check.h"
-#include "Elf.h"
-#include "ElfInterface.h"
#include "Machine.h"
-#include "MapInfo.h"
-#include "Regs.h"
#include "Ucontext.h"
#include "User.h"
-template <typename AddressType>
-uint64_t RegsImpl<AddressType>::GetRelPc(Elf* elf, const MapInfo* map_info) {
- uint64_t load_bias = 0;
- if (elf->valid()) {
- load_bias = elf->interface()->load_bias();
- }
-
- return pc_ - map_info->start + load_bias + map_info->elf_offset;
-}
+namespace unwindstack {
template <typename AddressType>
bool RegsImpl<AddressType>::GetReturnAddressFromDefault(Memory* memory, uint64_t* value) {
@@ -265,49 +258,51 @@
return regs;
}
+void RegsX86::SetFromUcontext(x86_ucontext_t* ucontext) {
+ // Put the registers in the expected order.
+ regs_[X86_REG_EDI] = ucontext->uc_mcontext.edi;
+ regs_[X86_REG_ESI] = ucontext->uc_mcontext.esi;
+ regs_[X86_REG_EBP] = ucontext->uc_mcontext.ebp;
+ regs_[X86_REG_ESP] = ucontext->uc_mcontext.esp;
+ regs_[X86_REG_EBX] = ucontext->uc_mcontext.ebx;
+ regs_[X86_REG_EDX] = ucontext->uc_mcontext.edx;
+ regs_[X86_REG_ECX] = ucontext->uc_mcontext.ecx;
+ regs_[X86_REG_EAX] = ucontext->uc_mcontext.eax;
+ regs_[X86_REG_EIP] = ucontext->uc_mcontext.eip;
+ SetFromRaw();
+}
+
static Regs* CreateFromX86Ucontext(void* ucontext) {
x86_ucontext_t* x86_ucontext = reinterpret_cast<x86_ucontext_t*>(ucontext);
RegsX86* regs = new RegsX86();
- // Put the registers in the expected order.
- (*regs)[X86_REG_GS] = x86_ucontext->uc_mcontext.gs;
- (*regs)[X86_REG_FS] = x86_ucontext->uc_mcontext.fs;
- (*regs)[X86_REG_ES] = x86_ucontext->uc_mcontext.es;
- (*regs)[X86_REG_DS] = x86_ucontext->uc_mcontext.ds;
- (*regs)[X86_REG_EDI] = x86_ucontext->uc_mcontext.edi;
- (*regs)[X86_REG_ESI] = x86_ucontext->uc_mcontext.esi;
- (*regs)[X86_REG_EBP] = x86_ucontext->uc_mcontext.ebp;
- (*regs)[X86_REG_ESP] = x86_ucontext->uc_mcontext.esp;
- (*regs)[X86_REG_EBX] = x86_ucontext->uc_mcontext.ebx;
- (*regs)[X86_REG_EDX] = x86_ucontext->uc_mcontext.edx;
- (*regs)[X86_REG_ECX] = x86_ucontext->uc_mcontext.ecx;
- (*regs)[X86_REG_EAX] = x86_ucontext->uc_mcontext.eax;
- (*regs)[X86_REG_EIP] = x86_ucontext->uc_mcontext.eip;
- regs->SetFromRaw();
+ regs->SetFromUcontext(x86_ucontext);
return regs;
}
+void RegsX86_64::SetFromUcontext(x86_64_ucontext_t* ucontext) {
+ // R8-R15
+ memcpy(®s_[X86_64_REG_R8], &ucontext->uc_mcontext.r8, 8 * sizeof(uint64_t));
+
+ // Rest of the registers.
+ regs_[X86_64_REG_RDI] = ucontext->uc_mcontext.rdi;
+ regs_[X86_64_REG_RSI] = ucontext->uc_mcontext.rsi;
+ regs_[X86_64_REG_RBP] = ucontext->uc_mcontext.rbp;
+ regs_[X86_64_REG_RBX] = ucontext->uc_mcontext.rbx;
+ regs_[X86_64_REG_RDX] = ucontext->uc_mcontext.rdx;
+ regs_[X86_64_REG_RAX] = ucontext->uc_mcontext.rax;
+ regs_[X86_64_REG_RCX] = ucontext->uc_mcontext.rcx;
+ regs_[X86_64_REG_RSP] = ucontext->uc_mcontext.rsp;
+ regs_[X86_64_REG_RIP] = ucontext->uc_mcontext.rip;
+
+ SetFromRaw();
+}
+
static Regs* CreateFromX86_64Ucontext(void* ucontext) {
x86_64_ucontext_t* x86_64_ucontext = reinterpret_cast<x86_64_ucontext_t*>(ucontext);
RegsX86_64* regs = new RegsX86_64();
- // Put the registers in the expected order.
-
- // R8-R15
- memcpy(&(*regs)[X86_64_REG_R8], &x86_64_ucontext->uc_mcontext.r8, 8 * sizeof(uint64_t));
-
- // Rest of the registers.
- (*regs)[X86_64_REG_RDI] = x86_64_ucontext->uc_mcontext.rdi;
- (*regs)[X86_64_REG_RSI] = x86_64_ucontext->uc_mcontext.rsi;
- (*regs)[X86_64_REG_RBP] = x86_64_ucontext->uc_mcontext.rbp;
- (*regs)[X86_64_REG_RBX] = x86_64_ucontext->uc_mcontext.rbx;
- (*regs)[X86_64_REG_RDX] = x86_64_ucontext->uc_mcontext.rdx;
- (*regs)[X86_64_REG_RAX] = x86_64_ucontext->uc_mcontext.rax;
- (*regs)[X86_64_REG_RCX] = x86_64_ucontext->uc_mcontext.rcx;
- (*regs)[X86_64_REG_RSP] = x86_64_ucontext->uc_mcontext.rsp;
- (*regs)[X86_64_REG_RIP] = x86_64_ucontext->uc_mcontext.rip;
-
- regs->SetFromRaw();
+ regs->SetFromUcontext(x86_64_ucontext);
return regs;
}
@@ -354,3 +349,192 @@
#endif
return regs;
}
+
+bool RegsArm::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) {
+ uint32_t data;
+ Memory* elf_memory = elf->memory();
+ // Read from elf memory since it is usually more expensive to read from
+ // process memory.
+ if (!elf_memory->Read(rel_pc, &data, sizeof(data))) {
+ return false;
+ }
+
+ uint64_t offset = 0;
+ if (data == 0xe3a07077 || data == 0xef900077 || data == 0xdf002777) {
+ // non-RT sigreturn call.
+ // __restore:
+ //
+ // Form 1 (arm):
+ // 0x77 0x70 mov r7, #0x77
+ // 0xa0 0xe3 svc 0x00000000
+ //
+ // Form 2 (arm):
+ // 0x77 0x00 0x90 0xef svc 0x00900077
+ //
+ // Form 3 (thumb):
+ // 0x77 0x27 movs r7, #77
+ // 0x00 0xdf svc 0
+ if (!process_memory->Read(sp(), &data, sizeof(data))) {
+ return false;
+ }
+ if (data == 0x5ac3c35a) {
+ // SP + uc_mcontext offset + r0 offset.
+ offset = sp() + 0x14 + 0xc;
+ } else {
+ // SP + r0 offset
+ offset = sp() + 0xc;
+ }
+ } else if (data == 0xe3a070ad || data == 0xef9000ad || data == 0xdf0027ad) {
+ // RT sigreturn call.
+ // __restore_rt:
+ //
+ // Form 1 (arm):
+ // 0xad 0x70 mov r7, #0xad
+ // 0xa0 0xe3 svc 0x00000000
+ //
+ // Form 2 (arm):
+ // 0xad 0x00 0x90 0xef svc 0x009000ad
+ //
+ // Form 3 (thumb):
+ // 0xad 0x27 movs r7, #ad
+ // 0x00 0xdf svc 0
+ if (!process_memory->Read(sp(), &data, sizeof(data))) {
+ return false;
+ }
+ if (data == sp() + 8) {
+ // SP + 8 + sizeof(siginfo_t) + uc_mcontext_offset + r0 offset
+ offset = sp() + 8 + 0x80 + 0x14 + 0xc;
+ } else {
+ // SP + sizeof(siginfo_t) + uc_mcontext_offset + r0 offset
+ offset = sp() + 0x80 + 0x14 + 0xc;
+ }
+ }
+ if (offset == 0) {
+ return false;
+ }
+
+ if (!process_memory->Read(offset, regs_.data(), sizeof(uint32_t) * ARM_REG_LAST)) {
+ return false;
+ }
+ SetFromRaw();
+ return true;
+}
+
+bool RegsArm64::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) {
+ uint64_t data;
+ Memory* elf_memory = elf->memory();
+ // Read from elf memory since it is usually more expensive to read from
+ // process memory.
+ if (!elf_memory->Read(rel_pc, &data, sizeof(data))) {
+ return false;
+ }
+
+ // Look for the kernel sigreturn function.
+ // __kernel_rt_sigreturn:
+ // 0xd2801168 mov x8, #0x8b
+ // 0xd4000001 svc #0x0
+ if (data != 0xd4000001d2801168ULL) {
+ return false;
+ }
+
+ // SP + sizeof(siginfo_t) + uc_mcontext offset + X0 offset.
+ if (!process_memory->Read(sp() + 0x80 + 0xb0 + 0x08, regs_.data(),
+ sizeof(uint64_t) * ARM64_REG_LAST)) {
+ return false;
+ }
+
+ SetFromRaw();
+ return true;
+}
+
+bool RegsX86::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) {
+ uint64_t data;
+ Memory* elf_memory = elf->memory();
+ // Read from elf memory since it is usually more expensive to read from
+ // process memory.
+ if (!elf_memory->Read(rel_pc, &data, sizeof(data))) {
+ return false;
+ }
+
+ if (data == 0x80cd00000077b858ULL) {
+ // Without SA_SIGINFO set, the return sequence is:
+ //
+ // __restore:
+ // 0x58 pop %eax
+ // 0xb8 0x77 0x00 0x00 0x00 movl 0x77,%eax
+ // 0xcd 0x80 int 0x80
+ //
+ // SP points at arguments:
+ // int signum
+ // struct sigcontext (same format as mcontext)
+ struct x86_mcontext_t context;
+ if (!process_memory->Read(sp() + 4, &context, sizeof(context))) {
+ return false;
+ }
+ regs_[X86_REG_EBP] = context.ebp;
+ regs_[X86_REG_ESP] = context.esp;
+ regs_[X86_REG_EBX] = context.ebx;
+ regs_[X86_REG_EDX] = context.edx;
+ regs_[X86_REG_ECX] = context.ecx;
+ regs_[X86_REG_EAX] = context.eax;
+ regs_[X86_REG_EIP] = context.eip;
+ SetFromRaw();
+ return true;
+ } else if ((data & 0x00ffffffffffffffULL) == 0x0080cd000000adb8ULL) {
+ // With SA_SIGINFO set, the return sequence is:
+ //
+ // __restore_rt:
+ // 0xb8 0xad 0x00 0x00 0x00 movl 0xad,%eax
+ // 0xcd 0x80 int 0x80
+ //
+ // SP points at arguments:
+ // int signum
+ // siginfo*
+ // ucontext*
+
+ // Get the location of the sigcontext data.
+ uint32_t ptr;
+ if (!process_memory->Read(sp() + 8, &ptr, sizeof(ptr))) {
+ return false;
+ }
+ // Only read the portion of the data structure we care about.
+ x86_ucontext_t x86_ucontext;
+ if (!process_memory->Read(ptr + 0x14, &x86_ucontext.uc_mcontext, sizeof(x86_mcontext_t))) {
+ return false;
+ }
+ SetFromUcontext(&x86_ucontext);
+ return true;
+ }
+ return false;
+}
+
+bool RegsX86_64::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) {
+ uint64_t data;
+ Memory* elf_memory = elf->memory();
+ // Read from elf memory since it is usually more expensive to read from
+ // process memory.
+ if (!elf_memory->Read(rel_pc, &data, sizeof(data)) || data != 0x0f0000000fc0c748) {
+ return false;
+ }
+
+ uint16_t data2;
+ if (!elf_memory->Read(rel_pc + 8, &data2, sizeof(data2)) || data2 != 0x0f05) {
+ return false;
+ }
+
+ // __restore_rt:
+ // 0x48 0xc7 0xc0 0x0f 0x00 0x00 0x00 mov $0xf,%rax
+ // 0x0f 0x05 syscall
+ // 0x0f nopl 0x0($rax)
+
+ // Read the mcontext data from the stack.
+ // sp points to the ucontext data structure, read only the mcontext part.
+ x86_64_ucontext_t x86_64_ucontext;
+ if (!process_memory->Read(sp() + 0x28, &x86_64_ucontext.uc_mcontext, sizeof(x86_64_mcontext_t))) {
+ return false;
+ }
+ SetFromUcontext(&x86_64_ucontext);
+ return true;
+}
+
+} // namespace unwindstack
diff --git a/libunwindstack/Symbols.cpp b/libunwindstack/Symbols.cpp
index edc2187..42d816a 100644
--- a/libunwindstack/Symbols.cpp
+++ b/libunwindstack/Symbols.cpp
@@ -19,10 +19,13 @@
#include <string>
+#include <unwindstack/Memory.h>
+
#include "Check.h"
-#include "Memory.h"
#include "Symbols.h"
+namespace unwindstack {
+
Symbols::Symbols(uint64_t offset, uint64_t size, uint64_t entry_size, uint64_t str_offset,
uint64_t str_size)
: cur_offset_(offset),
@@ -108,3 +111,5 @@
// Instantiate all of the needed template functions.
template bool Symbols::GetName<Elf32_Sym>(uint64_t, uint64_t, Memory*, std::string*, uint64_t*);
template bool Symbols::GetName<Elf64_Sym>(uint64_t, uint64_t, Memory*, std::string*, uint64_t*);
+
+} // namespace unwindstack
diff --git a/libunwindstack/Symbols.h b/libunwindstack/Symbols.h
index 3c0d033..689144b 100644
--- a/libunwindstack/Symbols.h
+++ b/libunwindstack/Symbols.h
@@ -22,6 +22,8 @@
#include <string>
#include <vector>
+namespace unwindstack {
+
// Forward declaration.
class Memory;
@@ -61,4 +63,6 @@
std::vector<Info> symbols_;
};
+} // namespace unwindstack
+
#endif // _LIBUNWINDSTACK_SYMBOLS_H
diff --git a/libunwindstack/Ucontext.h b/libunwindstack/Ucontext.h
index 95ba682..22f6a89 100644
--- a/libunwindstack/Ucontext.h
+++ b/libunwindstack/Ucontext.h
@@ -31,6 +31,8 @@
#include <stdint.h>
+namespace unwindstack {
+
//-------------------------------------------------------------------
// ARM ucontext structures
//-------------------------------------------------------------------
@@ -168,13 +170,15 @@
// Only care about the registers, skip everything else.
};
-typedef struct x86_64_ucontext {
+struct x86_64_ucontext_t {
uint64_t uc_flags; // unsigned long
uint64_t uc_link; // struct ucontext*
x86_64_stack_t uc_stack;
x86_64_mcontext_t uc_mcontext;
// Nothing else is used, so don't define it.
-} x86_64_ucontext_t;
+};
//-------------------------------------------------------------------
+} // namespace unwindstack
+
#endif // _LIBUNWINDSTACK_UCONTEXT_H
diff --git a/libunwindstack/User.h b/libunwindstack/User.h
index a695467..53f7e50 100644
--- a/libunwindstack/User.h
+++ b/libunwindstack/User.h
@@ -29,6 +29,8 @@
#ifndef _LIBUNWINDSTACK_USER_H
#define _LIBUNWINDSTACK_USER_H
+namespace unwindstack {
+
struct x86_user_regs {
uint32_t ebx;
uint32_t ecx;
@@ -93,4 +95,6 @@
// The largest user structure.
constexpr size_t MAX_USER_REGS_SIZE = sizeof(arm64_user_regs) + 10;
+} // namespace unwindstack
+
#endif // _LIBUNWINDSTACK_USER_H
diff --git a/libunwindstack/DwarfLocation.h b/libunwindstack/include/unwindstack/DwarfLocation.h
similarity index 95%
rename from libunwindstack/DwarfLocation.h
rename to libunwindstack/include/unwindstack/DwarfLocation.h
index 062d125..3467e6a 100644
--- a/libunwindstack/DwarfLocation.h
+++ b/libunwindstack/include/unwindstack/DwarfLocation.h
@@ -21,6 +21,8 @@
#include <unordered_map>
+namespace unwindstack {
+
enum DwarfLocationEnum : uint8_t {
DWARF_LOCATION_INVALID = 0,
DWARF_LOCATION_UNDEFINED,
@@ -38,4 +40,6 @@
typedef std::unordered_map<uint16_t, DwarfLocation> dwarf_loc_regs_t;
+} // namespace unwindstack
+
#endif // _LIBUNWINDSTACK_DWARF_LOCATION_H
diff --git a/libunwindstack/DwarfMemory.h b/libunwindstack/include/unwindstack/DwarfMemory.h
similarity index 97%
rename from libunwindstack/DwarfMemory.h
rename to libunwindstack/include/unwindstack/DwarfMemory.h
index a304dd9..8dd8d2b 100644
--- a/libunwindstack/DwarfMemory.h
+++ b/libunwindstack/include/unwindstack/DwarfMemory.h
@@ -19,6 +19,8 @@
#include <stdint.h>
+namespace unwindstack {
+
// Forward declarations.
class Memory;
@@ -69,4 +71,6 @@
uint64_t text_offset_ = static_cast<uint64_t>(-1);
};
+} // namespace unwindstack
+
#endif // _LIBUNWINDSTACK_DWARF_MEMORY_H
diff --git a/libunwindstack/DwarfSection.h b/libunwindstack/include/unwindstack/DwarfSection.h
similarity index 93%
rename from libunwindstack/DwarfSection.h
rename to libunwindstack/include/unwindstack/DwarfSection.h
index e617601..a97ca2b 100644
--- a/libunwindstack/DwarfSection.h
+++ b/libunwindstack/include/unwindstack/DwarfSection.h
@@ -22,18 +22,20 @@
#include <iterator>
#include <unordered_map>
-#include "DwarfError.h"
-#include "DwarfLocation.h"
-#include "DwarfMemory.h"
-#include "DwarfStructs.h"
+#include <unwindstack/DwarfLocation.h>
+#include <unwindstack/DwarfMemory.h>
+#include <unwindstack/DwarfStructs.h>
+
+namespace unwindstack {
// Forward declarations.
+enum DwarfError : uint8_t;
class Memory;
class Regs;
class DwarfSection {
public:
- DwarfSection(Memory* memory) : memory_(memory) {}
+ DwarfSection(Memory* memory);
virtual ~DwarfSection() = default;
class iterator : public std::iterator<std::bidirectional_iterator_tag, DwarfFde*> {
@@ -102,7 +104,7 @@
protected:
DwarfMemory memory_;
- DwarfError last_error_ = DWARF_ERROR_NONE;
+ DwarfError last_error_;
uint64_t fde_count_;
std::unordered_map<uint64_t, DwarfFde> fde_entries_;
@@ -134,4 +136,6 @@
AddressType* value);
};
+} // namespace unwindstack
+
#endif // _LIBUNWINDSTACK_DWARF_SECTION_H
diff --git a/libunwindstack/DwarfStructs.h b/libunwindstack/include/unwindstack/DwarfStructs.h
similarity index 92%
rename from libunwindstack/DwarfStructs.h
rename to libunwindstack/include/unwindstack/DwarfStructs.h
index 87182c9..4b481f0 100644
--- a/libunwindstack/DwarfStructs.h
+++ b/libunwindstack/include/unwindstack/DwarfStructs.h
@@ -21,12 +21,12 @@
#include <vector>
-#include "DwarfEncoding.h"
+namespace unwindstack {
struct DwarfCie {
uint8_t version = 0;
- uint8_t fde_address_encoding = DW_EH_PE_absptr;
- uint8_t lsda_encoding = DW_EH_PE_omit;
+ uint8_t fde_address_encoding = 0;
+ uint8_t lsda_encoding = 0;
uint8_t segment_size = 0;
std::vector<char> augmentation_string;
uint64_t personality_handler = 0;
@@ -49,4 +49,6 @@
constexpr uint16_t CFA_REG = static_cast<uint16_t>(-1);
+} // namespace unwindstack
+
#endif // _LIBUNWINDSTACK_DWARF_STRUCTS_H
diff --git a/libunwindstack/Elf.h b/libunwindstack/include/unwindstack/Elf.h
similarity index 75%
rename from libunwindstack/Elf.h
rename to libunwindstack/include/unwindstack/Elf.h
index cff9dc4..d89a746 100644
--- a/libunwindstack/Elf.h
+++ b/libunwindstack/include/unwindstack/Elf.h
@@ -22,14 +22,17 @@
#include <memory>
#include <string>
-#include "ElfInterface.h"
-#include "Memory.h"
+#include <unwindstack/ElfInterface.h>
+#include <unwindstack/Memory.h>
#if !defined(EM_AARCH64)
#define EM_AARCH64 183
#endif
+namespace unwindstack {
+
// Forward declaration.
+struct MapInfo;
class Regs;
class Elf {
@@ -41,24 +44,18 @@
void InitGnuDebugdata();
- bool GetSoname(std::string* name) {
- return valid_ && interface_->GetSoname(name);
- }
+ bool GetSoname(std::string* name);
- bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) {
- return valid_ && (interface_->GetFunctionName(addr, name, func_offset) ||
- (gnu_debugdata_interface_ &&
- gnu_debugdata_interface_->GetFunctionName(addr, name, func_offset)));
- }
+ bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset);
- bool Step(uint64_t rel_pc, Regs* regs, Memory* process_memory) {
- return valid_ && (interface_->Step(rel_pc, regs, process_memory) ||
- (gnu_debugdata_interface_ &&
- gnu_debugdata_interface_->Step(rel_pc, regs, process_memory)));
- }
+ uint64_t GetRelPc(uint64_t pc, const MapInfo* map_info);
+
+ bool Step(uint64_t rel_pc, Regs* regs, Memory* process_memory);
ElfInterface* CreateInterfaceFromMemory(Memory* memory);
+ uint64_t GetLoadBias();
+
bool valid() { return valid_; }
uint32_t machine_type() { return machine_type_; }
@@ -84,4 +81,6 @@
std::unique_ptr<ElfInterface> gnu_debugdata_interface_;
};
+} // namespace unwindstack
+
#endif // _LIBUNWINDSTACK_ELF_H
diff --git a/libunwindstack/ElfInterface.h b/libunwindstack/include/unwindstack/ElfInterface.h
similarity index 97%
rename from libunwindstack/ElfInterface.h
rename to libunwindstack/include/unwindstack/ElfInterface.h
index d0d0d28..5cac0d3 100644
--- a/libunwindstack/ElfInterface.h
+++ b/libunwindstack/include/unwindstack/ElfInterface.h
@@ -25,7 +25,9 @@
#include <unordered_map>
#include <vector>
-#include "DwarfSection.h"
+#include <unwindstack/DwarfSection.h>
+
+namespace unwindstack {
// Forward declarations.
class Memory;
@@ -166,4 +168,6 @@
}
};
+} // namespace unwindstack
+
#endif // _LIBUNWINDSTACK_ELF_INTERFACE_H
diff --git a/libunwindstack/Log.h b/libunwindstack/include/unwindstack/Log.h
similarity index 93%
rename from libunwindstack/Log.h
rename to libunwindstack/include/unwindstack/Log.h
index 2d01aa8..aa1219c 100644
--- a/libunwindstack/Log.h
+++ b/libunwindstack/include/unwindstack/Log.h
@@ -19,7 +19,11 @@
#include <stdint.h>
+namespace unwindstack {
+
void log_to_stdout(bool enable);
void log(uint8_t indent, const char* format, ...);
+} // namespace unwindstack
+
#endif // _LIBUNWINDSTACK_LOG_H
diff --git a/libunwindstack/MapInfo.h b/libunwindstack/include/unwindstack/MapInfo.h
similarity index 95%
rename from libunwindstack/MapInfo.h
rename to libunwindstack/include/unwindstack/MapInfo.h
index 79a2ada..2a97dde 100644
--- a/libunwindstack/MapInfo.h
+++ b/libunwindstack/include/unwindstack/MapInfo.h
@@ -21,6 +21,8 @@
#include <string>
+namespace unwindstack {
+
// Forward declarations.
class Elf;
class Memory;
@@ -42,4 +44,6 @@
Elf* GetElf(pid_t pid, bool init_gnu_debugdata = false);
};
+} // namespace unwindstack
+
#endif // _LIBUNWINDSTACK_MAP_INFO_H
diff --git a/libunwindstack/Maps.h b/libunwindstack/include/unwindstack/Maps.h
similarity index 96%
rename from libunwindstack/Maps.h
rename to libunwindstack/include/unwindstack/Maps.h
index 239b64a..0b02739 100644
--- a/libunwindstack/Maps.h
+++ b/libunwindstack/include/unwindstack/Maps.h
@@ -23,8 +23,9 @@
#include <string>
#include <vector>
-#include "Elf.h"
-#include "MapInfo.h"
+#include <unwindstack/MapInfo.h>
+
+namespace unwindstack {
// Special flag to indicate a map is in /dev/. However, a map in
// /dev/ashmem/... does not set this flag.
@@ -104,4 +105,6 @@
bool Parse() override;
};
+} // namespace unwindstack
+
#endif // _LIBUNWINDSTACK_MAPS_H
diff --git a/libunwindstack/Memory.h b/libunwindstack/include/unwindstack/Memory.h
similarity index 89%
rename from libunwindstack/Memory.h
rename to libunwindstack/include/unwindstack/Memory.h
index e353cab..0c05266 100644
--- a/libunwindstack/Memory.h
+++ b/libunwindstack/include/unwindstack/Memory.h
@@ -24,7 +24,7 @@
#include <string>
#include <vector>
-#include "Check.h"
+namespace unwindstack {
class Memory {
public:
@@ -47,13 +47,9 @@
return Read(offset, field, size);
}
- inline bool Read32(uint64_t addr, uint32_t* dst) {
- return Read(addr, dst, sizeof(uint32_t));
- }
+ inline bool Read32(uint64_t addr, uint32_t* dst) { return Read(addr, dst, sizeof(uint32_t)); }
- inline bool Read64(uint64_t addr, uint64_t* dst) {
- return Read(addr, dst, sizeof(uint64_t));
- }
+ inline bool Read64(uint64_t addr, uint64_t* dst) { return Read(addr, dst, sizeof(uint64_t)); }
};
class MemoryBuffer : public Memory {
@@ -129,10 +125,7 @@
class MemoryRange : public Memory {
public:
- MemoryRange(Memory* memory, uint64_t begin, uint64_t end)
- : memory_(memory), begin_(begin), length_(end - begin) {
- CHECK(end > begin);
- }
+ MemoryRange(Memory* memory, uint64_t begin, uint64_t end);
virtual ~MemoryRange() { delete memory_; }
bool Read(uint64_t addr, void* dst, size_t size) override;
@@ -143,4 +136,6 @@
uint64_t length_;
};
+} // namespace unwindstack
+
#endif // _LIBUNWINDSTACK_MEMORY_H
diff --git a/libunwindstack/Regs.h b/libunwindstack/include/unwindstack/Regs.h
similarity index 83%
rename from libunwindstack/Regs.h
rename to libunwindstack/include/unwindstack/Regs.h
index a7567d8..78e2c0d 100644
--- a/libunwindstack/Regs.h
+++ b/libunwindstack/include/unwindstack/Regs.h
@@ -21,9 +21,14 @@
#include <vector>
+namespace unwindstack {
+
// Forward declarations.
class Elf;
struct MapInfo;
+class Memory;
+struct x86_ucontext_t;
+struct x86_64_ucontext_t;
class Regs {
public:
@@ -50,10 +55,10 @@
virtual bool GetReturnAddressFromDefault(Memory* memory, uint64_t* value) = 0;
- virtual uint64_t GetRelPc(Elf* elf, const MapInfo* map_info) = 0;
-
virtual uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) = 0;
+ virtual bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) = 0;
+
virtual void SetFromRaw() = 0;
uint16_t sp_reg() { return sp_reg_; }
@@ -77,8 +82,6 @@
: Regs(total_regs, sp_reg, return_loc), regs_(total_regs) {}
virtual ~RegsImpl() = default;
- uint64_t GetRelPc(Elf* elf, const MapInfo* map_info) override;
-
bool GetReturnAddressFromDefault(Memory* memory, uint64_t* value) override;
uint64_t pc() override { return pc_; }
@@ -105,6 +108,8 @@
uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override;
void SetFromRaw() override;
+
+ bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override;
};
class RegsArm64 : public RegsImpl<uint64_t> {
@@ -115,6 +120,8 @@
uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override;
void SetFromRaw() override;
+
+ bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override;
};
class RegsX86 : public RegsImpl<uint32_t> {
@@ -125,6 +132,10 @@
uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override;
void SetFromRaw() override;
+
+ bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override;
+
+ void SetFromUcontext(x86_ucontext_t* ucontext);
};
class RegsX86_64 : public RegsImpl<uint64_t> {
@@ -135,6 +146,12 @@
uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override;
void SetFromRaw() override;
+
+ bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override;
+
+ void SetFromUcontext(x86_64_ucontext_t* ucontext);
};
+} // namespace unwindstack
+
#endif // _LIBUNWINDSTACK_REGS_H
diff --git a/libunwindstack/RegsGetLocal.h b/libunwindstack/include/unwindstack/RegsGetLocal.h
similarity index 98%
rename from libunwindstack/RegsGetLocal.h
rename to libunwindstack/include/unwindstack/RegsGetLocal.h
index 8e6d04c..ffec213 100644
--- a/libunwindstack/RegsGetLocal.h
+++ b/libunwindstack/include/unwindstack/RegsGetLocal.h
@@ -29,6 +29,8 @@
#ifndef _LIBUNWINDSTACK_REGS_GET_LOCAL_H
#define _LIBUNWINDSTACK_REGS_GET_LOCAL_H
+namespace unwindstack {
+
#if defined(__arm__)
inline void RegsGetLocal(Regs* regs) {
@@ -97,4 +99,6 @@
#endif
+} // namespace unwindstack
+
#endif // _LIBUNWINDSTACK_REGS_GET_LOCAL_H
diff --git a/libunwindstack/tests/ArmExidxDecodeTest.cpp b/libunwindstack/tests/ArmExidxDecodeTest.cpp
index 4fff48e..94cb493 100644
--- a/libunwindstack/tests/ArmExidxDecodeTest.cpp
+++ b/libunwindstack/tests/ArmExidxDecodeTest.cpp
@@ -23,13 +23,16 @@
#include <gtest/gtest.h>
+#include <unwindstack/Log.h>
+#include <unwindstack/Regs.h>
+
#include "ArmExidx.h"
-#include "Regs.h"
-#include "Log.h"
#include "LogFake.h"
#include "MemoryFake.h"
+namespace unwindstack {
+
class ArmExidxDecodeTest : public ::testing::TestWithParam<std::string> {
protected:
void Init(Memory* process_memory = nullptr) {
@@ -1092,3 +1095,5 @@
}
INSTANTIATE_TEST_CASE_P(, ArmExidxDecodeTest, ::testing::Values("logging", "no_logging"));
+
+} // namespace unwindstack
diff --git a/libunwindstack/tests/ArmExidxExtractTest.cpp b/libunwindstack/tests/ArmExidxExtractTest.cpp
index aed75bf..caad131 100644
--- a/libunwindstack/tests/ArmExidxExtractTest.cpp
+++ b/libunwindstack/tests/ArmExidxExtractTest.cpp
@@ -21,12 +21,15 @@
#include <gtest/gtest.h>
+#include <unwindstack/Log.h>
+
#include "ArmExidx.h"
-#include "Log.h"
#include "LogFake.h"
#include "MemoryFake.h"
+namespace unwindstack {
+
class ArmExidxExtractTest : public ::testing::Test {
protected:
void SetUp() override {
@@ -329,3 +332,5 @@
ASSERT_TRUE(exidx_->ExtractEntryData(0x5000));
ASSERT_EQ("4 unwind Raw Data: 0x11 0x22 0x33 0xb0\n", GetFakeLogPrint());
}
+
+} // namespace unwindstack
diff --git a/libunwindstack/tests/DwarfCfaLogTest.cpp b/libunwindstack/tests/DwarfCfaLogTest.cpp
index 967c2c2..b17ca33 100644
--- a/libunwindstack/tests/DwarfCfaLogTest.cpp
+++ b/libunwindstack/tests/DwarfCfaLogTest.cpp
@@ -23,15 +23,18 @@
#include <android-base/stringprintf.h>
#include <gtest/gtest.h>
+#include <unwindstack/DwarfLocation.h>
+#include <unwindstack/DwarfMemory.h>
+#include <unwindstack/DwarfStructs.h>
+#include <unwindstack/Log.h>
+
#include "DwarfCfa.h"
-#include "DwarfLocation.h"
-#include "DwarfMemory.h"
-#include "DwarfStructs.h"
-#include "Log.h"
#include "LogFake.h"
#include "MemoryFake.h"
+namespace unwindstack {
+
template <typename TypeParam>
class DwarfCfaLogTest : public ::testing::Test {
protected:
@@ -812,3 +815,5 @@
typedef ::testing::Types<uint32_t, uint64_t> DwarfCfaLogTestTypes;
INSTANTIATE_TYPED_TEST_CASE_P(, DwarfCfaLogTest, DwarfCfaLogTestTypes);
+
+} // namespace unwindstack
diff --git a/libunwindstack/tests/DwarfCfaTest.cpp b/libunwindstack/tests/DwarfCfaTest.cpp
index 687af7d..73a67ac 100644
--- a/libunwindstack/tests/DwarfCfaTest.cpp
+++ b/libunwindstack/tests/DwarfCfaTest.cpp
@@ -21,15 +21,19 @@
#include <gtest/gtest.h>
+#include <unwindstack/DwarfLocation.h>
+#include <unwindstack/DwarfMemory.h>
+#include <unwindstack/DwarfStructs.h>
+#include <unwindstack/Log.h>
+
#include "DwarfCfa.h"
-#include "DwarfLocation.h"
-#include "DwarfMemory.h"
-#include "DwarfStructs.h"
-#include "Log.h"
+#include "DwarfError.h"
#include "LogFake.h"
#include "MemoryFake.h"
+namespace unwindstack {
+
template <typename TypeParam>
class DwarfCfaTest : public ::testing::Test {
protected:
@@ -957,3 +961,5 @@
typedef ::testing::Types<uint32_t, uint64_t> DwarfCfaTestTypes;
INSTANTIATE_TYPED_TEST_CASE_P(, DwarfCfaTest, DwarfCfaTestTypes);
+
+} // namespace unwindstack
diff --git a/libunwindstack/tests/DwarfDebugFrameTest.cpp b/libunwindstack/tests/DwarfDebugFrameTest.cpp
index 94a9974..69813e5 100644
--- a/libunwindstack/tests/DwarfDebugFrameTest.cpp
+++ b/libunwindstack/tests/DwarfDebugFrameTest.cpp
@@ -21,11 +21,14 @@
#include "DwarfDebugFrame.h"
#include "DwarfEncoding.h"
+#include "DwarfError.h"
#include "LogFake.h"
#include "MemoryFake.h"
#include "RegsFake.h"
+namespace unwindstack {
+
template <typename TypeParam>
class MockDwarfDebugFrame : public DwarfDebugFrame<TypeParam> {
public:
@@ -454,3 +457,5 @@
typedef ::testing::Types<uint32_t, uint64_t> DwarfDebugFrameTestTypes;
INSTANTIATE_TYPED_TEST_CASE_P(, DwarfDebugFrameTest, DwarfDebugFrameTestTypes);
+
+} // namespace unwindstack
diff --git a/libunwindstack/tests/DwarfEhFrameTest.cpp b/libunwindstack/tests/DwarfEhFrameTest.cpp
index 4e538d4..e9501e3 100644
--- a/libunwindstack/tests/DwarfEhFrameTest.cpp
+++ b/libunwindstack/tests/DwarfEhFrameTest.cpp
@@ -21,11 +21,14 @@
#include "DwarfEhFrame.h"
#include "DwarfEncoding.h"
+#include "DwarfError.h"
#include "LogFake.h"
#include "MemoryFake.h"
#include "RegsFake.h"
+namespace unwindstack {
+
template <typename TypeParam>
class MockDwarfEhFrame : public DwarfEhFrame<TypeParam> {
public:
@@ -407,3 +410,5 @@
typedef ::testing::Types<uint32_t, uint64_t> DwarfEhFrameTestTypes;
INSTANTIATE_TYPED_TEST_CASE_P(, DwarfEhFrameTest, DwarfEhFrameTestTypes);
+
+} // namespace unwindstack
diff --git a/libunwindstack/tests/DwarfMemoryTest.cpp b/libunwindstack/tests/DwarfMemoryTest.cpp
index b7df8f7..08fe7cf 100644
--- a/libunwindstack/tests/DwarfMemoryTest.cpp
+++ b/libunwindstack/tests/DwarfMemoryTest.cpp
@@ -21,10 +21,12 @@
#include <gtest/gtest.h>
-#include "DwarfMemory.h"
+#include <unwindstack/DwarfMemory.h>
#include "MemoryFake.h"
+namespace unwindstack {
+
class DwarfMemoryTest : public ::testing::Test {
protected:
void SetUp() override {
@@ -494,3 +496,5 @@
ASSERT_TRUE(dwarf_mem_->AdjustEncodedValue(0x40, &value));
ASSERT_EQ(0x14234U, value);
}
+
+} // namespace unwindstack
diff --git a/libunwindstack/tests/DwarfOpLogTest.cpp b/libunwindstack/tests/DwarfOpLogTest.cpp
index d18aad0..234d1c9 100644
--- a/libunwindstack/tests/DwarfOpLogTest.cpp
+++ b/libunwindstack/tests/DwarfOpLogTest.cpp
@@ -21,14 +21,17 @@
#include <gtest/gtest.h>
+#include <unwindstack/DwarfMemory.h>
+#include <unwindstack/Log.h>
+#include <unwindstack/Regs.h>
+
#include "DwarfError.h"
-#include "DwarfMemory.h"
#include "DwarfOp.h"
-#include "Log.h"
-#include "Regs.h"
#include "MemoryFake.h"
+namespace unwindstack {
+
template <typename TypeParam>
class DwarfOpLogTest : public ::testing::Test {
protected:
@@ -66,3 +69,5 @@
typedef ::testing::Types<uint32_t, uint64_t> DwarfOpLogTestTypes;
INSTANTIATE_TYPED_TEST_CASE_P(, DwarfOpLogTest, DwarfOpLogTestTypes);
+
+} // namespace unwindstack
diff --git a/libunwindstack/tests/DwarfOpTest.cpp b/libunwindstack/tests/DwarfOpTest.cpp
index 20c488a..47a40cf 100644
--- a/libunwindstack/tests/DwarfOpTest.cpp
+++ b/libunwindstack/tests/DwarfOpTest.cpp
@@ -21,14 +21,17 @@
#include <gtest/gtest.h>
+#include <unwindstack/DwarfMemory.h>
+#include <unwindstack/Log.h>
+
#include "DwarfError.h"
-#include "DwarfMemory.h"
#include "DwarfOp.h"
-#include "Log.h"
#include "MemoryFake.h"
#include "RegsFake.h"
+namespace unwindstack {
+
template <typename TypeParam>
class DwarfOpTest : public ::testing::Test {
protected:
@@ -1579,3 +1582,5 @@
typedef ::testing::Types<uint32_t, uint64_t> DwarfOpTestTypes;
INSTANTIATE_TYPED_TEST_CASE_P(, DwarfOpTest, DwarfOpTestTypes);
+
+} // namespace unwindstack
diff --git a/libunwindstack/tests/DwarfSectionImplTest.cpp b/libunwindstack/tests/DwarfSectionImplTest.cpp
index 71b114a..b871539 100644
--- a/libunwindstack/tests/DwarfSectionImplTest.cpp
+++ b/libunwindstack/tests/DwarfSectionImplTest.cpp
@@ -19,12 +19,17 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
-#include "DwarfSection.h"
+#include <unwindstack/DwarfSection.h>
+
+#include "DwarfEncoding.h"
+#include "DwarfError.h"
#include "LogFake.h"
#include "MemoryFake.h"
#include "RegsFake.h"
+namespace unwindstack {
+
template <typename TypeParam>
class MockDwarfSectionImpl : public DwarfSectionImpl<TypeParam> {
public:
@@ -830,3 +835,5 @@
typedef ::testing::Types<uint32_t, uint64_t> DwarfSectionImplTestTypes;
INSTANTIATE_TYPED_TEST_CASE_P(, DwarfSectionImplTest, DwarfSectionImplTestTypes);
+
+} // namespace unwindstack
diff --git a/libunwindstack/tests/DwarfSectionTest.cpp b/libunwindstack/tests/DwarfSectionTest.cpp
index 20f0e2a..fc67063 100644
--- a/libunwindstack/tests/DwarfSectionTest.cpp
+++ b/libunwindstack/tests/DwarfSectionTest.cpp
@@ -19,10 +19,12 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
-#include "DwarfSection.h"
+#include <unwindstack/DwarfSection.h>
#include "MemoryFake.h"
+namespace unwindstack {
+
class MockDwarfSection : public DwarfSection {
public:
MockDwarfSection(Memory* memory) : DwarfSection(memory) {}
@@ -158,3 +160,5 @@
ASSERT_TRUE(mock_section.Step(0x1000, nullptr, &process));
}
+
+} // namespace unwindstack
diff --git a/libunwindstack/tests/ElfInterfaceArmTest.cpp b/libunwindstack/tests/ElfInterfaceArmTest.cpp
index 67c9a6b..c7ef4a1 100644
--- a/libunwindstack/tests/ElfInterfaceArmTest.cpp
+++ b/libunwindstack/tests/ElfInterfaceArmTest.cpp
@@ -20,12 +20,15 @@
#include <vector>
+#include <unwindstack/Regs.h>
+
#include "ElfInterfaceArm.h"
#include "Machine.h"
-#include "Regs.h"
#include "MemoryFake.h"
+namespace unwindstack {
+
class ElfInterfaceArmTest : public ::testing::Test {
protected:
void SetUp() override {
@@ -370,3 +373,5 @@
ASSERT_EQ(0x10U, regs.pc());
ASSERT_EQ(0x10U, regs[ARM_REG_PC]);
}
+
+} // namespace unwindstack
diff --git a/libunwindstack/tests/ElfInterfaceTest.cpp b/libunwindstack/tests/ElfInterfaceTest.cpp
index 0f56ba8..acb7320 100644
--- a/libunwindstack/tests/ElfInterfaceTest.cpp
+++ b/libunwindstack/tests/ElfInterfaceTest.cpp
@@ -20,7 +20,9 @@
#include <gtest/gtest.h>
-#include "ElfInterface.h"
+#include <unwindstack/ElfInterface.h>
+
+#include "DwarfEncoding.h"
#include "ElfInterfaceArm.h"
#include "MemoryFake.h"
@@ -33,6 +35,8 @@
#define EM_AARCH64 183
#endif
+namespace unwindstack {
+
class ElfInterfaceTest : public ::testing::Test {
protected:
void SetUp() override {
@@ -921,3 +925,5 @@
TEST_F(ElfInterfaceTest, init_section_headers_offsets64) {
InitSectionHeadersOffsets<Elf64_Ehdr, Elf64_Shdr, ElfInterface64>();
}
+
+} // namespace unwindstack
diff --git a/libunwindstack/tests/ElfTest.cpp b/libunwindstack/tests/ElfTest.cpp
index bf0823b..ed1be3b 100644
--- a/libunwindstack/tests/ElfTest.cpp
+++ b/libunwindstack/tests/ElfTest.cpp
@@ -22,15 +22,19 @@
#include <gtest/gtest.h>
-#include "Elf.h"
+#include <unwindstack/Elf.h>
+#include <unwindstack/MapInfo.h>
#include "ElfTestUtils.h"
+#include "LogFake.h"
#include "MemoryFake.h"
#if !defined(PT_ARM_EXIDX)
#define PT_ARM_EXIDX 0x70000001
#endif
+namespace unwindstack {
+
class ElfTest : public ::testing::Test {
protected:
void SetUp() override {
@@ -128,6 +132,32 @@
ASSERT_FALSE(elf.Step(0, nullptr, nullptr));
}
+TEST_F(ElfTest, elf32_invalid_machine) {
+ Elf elf(memory_);
+
+ InitElf32(EM_PPC);
+
+ ResetLogs();
+ ASSERT_FALSE(elf.Init());
+
+ ASSERT_EQ("", GetFakeLogBuf());
+ ASSERT_EQ("4 unwind 32 bit elf that is neither arm nor x86: e_machine = 20\n\n",
+ GetFakeLogPrint());
+}
+
+TEST_F(ElfTest, elf64_invalid_machine) {
+ Elf elf(memory_);
+
+ InitElf64(EM_PPC64);
+
+ ResetLogs();
+ ASSERT_FALSE(elf.Init());
+
+ ASSERT_EQ("", GetFakeLogBuf());
+ ASSERT_EQ("4 unwind 64 bit elf that is neither aarch64 nor x86_64: e_machine = 21\n\n",
+ GetFakeLogPrint());
+}
+
TEST_F(ElfTest, elf_arm) {
Elf elf(memory_);
@@ -237,3 +267,33 @@
elf.InitGnuDebugdata();
ASSERT_TRUE(elf.gnu_debugdata_interface() != nullptr);
}
+
+class MockElf : public Elf {
+ public:
+ MockElf(Memory* memory) : Elf(memory) {}
+ virtual ~MockElf() = default;
+
+ void set_valid(bool valid) { valid_ = valid; }
+ void set_elf_interface(ElfInterface* interface) { interface_.reset(interface); }
+};
+
+TEST_F(ElfTest, rel_pc) {
+ MockElf elf(memory_);
+
+ ElfInterface* interface = new ElfInterface32(memory_);
+ elf.set_elf_interface(interface);
+
+ elf.set_valid(true);
+ interface->set_load_bias(0);
+ MapInfo map_info{.start = 0x1000, .end = 0x2000};
+
+ ASSERT_EQ(0x101U, elf.GetRelPc(0x1101, &map_info));
+
+ interface->set_load_bias(0x3000);
+ ASSERT_EQ(0x3101U, elf.GetRelPc(0x1101, &map_info));
+
+ elf.set_valid(false);
+ ASSERT_EQ(0x101U, elf.GetRelPc(0x1101, &map_info));
+}
+
+} // namespace unwindstack
diff --git a/libunwindstack/tests/ElfTestUtils.cpp b/libunwindstack/tests/ElfTestUtils.cpp
index 81064dd..069386b 100644
--- a/libunwindstack/tests/ElfTestUtils.cpp
+++ b/libunwindstack/tests/ElfTestUtils.cpp
@@ -31,6 +31,8 @@
#include "ElfTestUtils.h"
+namespace unwindstack {
+
template <typename Ehdr>
void TestInitEhdr(Ehdr* ehdr, uint32_t elf_class, uint32_t machine_type) {
memset(ehdr, 0, sizeof(Ehdr));
@@ -136,3 +138,5 @@
TestCopyFuncType);
template void TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(uint32_t, uint32_t, bool,
TestCopyFuncType);
+
+} // namespace unwindstack
diff --git a/libunwindstack/tests/ElfTestUtils.h b/libunwindstack/tests/ElfTestUtils.h
index 4fd3bbc..6ef00e1 100644
--- a/libunwindstack/tests/ElfTestUtils.h
+++ b/libunwindstack/tests/ElfTestUtils.h
@@ -19,6 +19,8 @@
#include <functional>
+namespace unwindstack {
+
typedef std::function<void(uint64_t, const void*, size_t)> TestCopyFuncType;
template <typename Ehdr>
@@ -28,4 +30,6 @@
void TestInitGnuDebugdata(uint32_t elf_class, uint32_t machine_type, bool init_gnu_debudata,
TestCopyFuncType copy_func);
+} // namespace unwindstack
+
#endif // _LIBUNWINDSTACK_TESTS_ELF_TEST_UTILS_H
diff --git a/libunwindstack/tests/LogFake.cpp b/libunwindstack/tests/LogFake.cpp
index 411594a..537ccaf 100644
--- a/libunwindstack/tests/LogFake.cpp
+++ b/libunwindstack/tests/LogFake.cpp
@@ -25,7 +25,6 @@
#include "LogFake.h"
// Forward declarations.
-class Backtrace;
struct EventTagMap;
struct AndroidLogEntry;
@@ -33,6 +32,8 @@
std::string g_fake_log_print;
+namespace unwindstack {
+
void ResetLogs() {
g_fake_log_buf = "";
g_fake_log_print = "";
@@ -46,6 +47,8 @@
return g_fake_log_print;
}
+} // namespace unwindstack
+
extern "C" int __android_log_buf_write(int bufId, int prio, const char* tag, const char* msg) {
g_fake_log_buf += std::to_string(bufId) + ' ' + std::to_string(prio) + ' ';
g_fake_log_buf += tag;
diff --git a/libunwindstack/tests/LogFake.h b/libunwindstack/tests/LogFake.h
index 006d393..e1dc50d 100644
--- a/libunwindstack/tests/LogFake.h
+++ b/libunwindstack/tests/LogFake.h
@@ -19,8 +19,12 @@
#include <string>
+namespace unwindstack {
+
void ResetLogs();
std::string GetFakeLogBuf();
std::string GetFakeLogPrint();
+} // namespace unwindstack
+
#endif // _LIBUNWINDSTACK_TESTS_LOG_FAKE_H
diff --git a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
index b82c841..9e45e78 100644
--- a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
+++ b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
@@ -30,9 +30,11 @@
#include <android-base/test_utils.h>
#include <gtest/gtest.h>
-#include "Elf.h"
-#include "MapInfo.h"
-#include "Memory.h"
+#include <unwindstack/Elf.h>
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Memory.h>
+
+namespace unwindstack {
class MapInfoCreateMemoryTest : public ::testing::Test {
protected:
@@ -203,3 +205,5 @@
kill(pid, SIGKILL);
ASSERT_EQ(pid, wait(nullptr));
}
+
+} // namespace unwindstack
diff --git a/libunwindstack/tests/MapInfoGetElfTest.cpp b/libunwindstack/tests/MapInfoGetElfTest.cpp
index fc36cc6..abfa172 100644
--- a/libunwindstack/tests/MapInfoGetElfTest.cpp
+++ b/libunwindstack/tests/MapInfoGetElfTest.cpp
@@ -30,9 +30,13 @@
#include <android-base/test_utils.h>
#include <gtest/gtest.h>
-#include "Elf.h"
+#include <unwindstack/Elf.h>
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Memory.h>
+
#include "ElfTestUtils.h"
-#include "MapInfo.h"
+
+namespace unwindstack {
class MapInfoGetElfTest : public ::testing::Test {
protected:
@@ -138,3 +142,5 @@
EXPECT_EQ(ELFCLASS64, elf->class_type());
EXPECT_TRUE(elf->gnu_debugdata_interface() != nullptr);
}
+
+} // namespace unwindstack
diff --git a/libunwindstack/tests/MapsTest.cpp b/libunwindstack/tests/MapsTest.cpp
index 7eb9bae..9430cf3 100644
--- a/libunwindstack/tests/MapsTest.cpp
+++ b/libunwindstack/tests/MapsTest.cpp
@@ -20,7 +20,9 @@
#include <android-base/test_utils.h>
#include <gtest/gtest.h>
-#include "Maps.h"
+#include <unwindstack/Maps.h>
+
+namespace unwindstack {
TEST(MapsTest, parse_permissions) {
BufferMaps maps(
@@ -235,3 +237,5 @@
ASSERT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, info->flags);
ASSERT_EQ("/system/lib/fake5.so", info->name);
}
+
+} // namespace unwindstack
diff --git a/libunwindstack/tests/MemoryBufferTest.cpp b/libunwindstack/tests/MemoryBufferTest.cpp
index af3d6b9..50a8a1b 100644
--- a/libunwindstack/tests/MemoryBufferTest.cpp
+++ b/libunwindstack/tests/MemoryBufferTest.cpp
@@ -18,10 +18,12 @@
#include <gtest/gtest.h>
-#include "Memory.h"
+#include <unwindstack/Memory.h>
#include "LogFake.h"
+namespace unwindstack {
+
class MemoryBufferTest : public ::testing::Test {
protected:
void SetUp() override {
@@ -75,3 +77,5 @@
ASSERT_FALSE(memory_->Read(UINT64_MAX - 100, buffer.data(), 200));
}
+
+} // namespace unwindstack
diff --git a/libunwindstack/tests/MemoryFake.cpp b/libunwindstack/tests/MemoryFake.cpp
index afb1029..2026acc 100644
--- a/libunwindstack/tests/MemoryFake.cpp
+++ b/libunwindstack/tests/MemoryFake.cpp
@@ -21,6 +21,8 @@
#include "MemoryFake.h"
+namespace unwindstack {
+
void MemoryFake::SetMemory(uint64_t addr, const void* memory, size_t length) {
const uint8_t* src = reinterpret_cast<const uint8_t*>(memory);
for (size_t i = 0; i < length; i++, addr++) {
@@ -44,3 +46,5 @@
}
return true;
}
+
+} // namespace unwindstack
diff --git a/libunwindstack/tests/MemoryFake.h b/libunwindstack/tests/MemoryFake.h
index 70ef30a..d374261 100644
--- a/libunwindstack/tests/MemoryFake.h
+++ b/libunwindstack/tests/MemoryFake.h
@@ -23,7 +23,9 @@
#include <vector>
#include <unordered_map>
-#include "Memory.h"
+#include <unwindstack/Memory.h>
+
+namespace unwindstack {
class MemoryFake : public Memory {
public:
@@ -87,4 +89,6 @@
}
};
+} // namespace unwindstack
+
#endif // _LIBUNWINDSTACK_TESTS_MEMORY_FAKE_H
diff --git a/libunwindstack/tests/MemoryFileTest.cpp b/libunwindstack/tests/MemoryFileTest.cpp
index aa7a23a..a204bae 100644
--- a/libunwindstack/tests/MemoryFileTest.cpp
+++ b/libunwindstack/tests/MemoryFileTest.cpp
@@ -21,7 +21,9 @@
#include <android-base/file.h>
#include <gtest/gtest.h>
-#include "Memory.h"
+#include <unwindstack/Memory.h>
+
+namespace unwindstack {
class MemoryFileTest : public ::testing::Test {
protected:
@@ -269,3 +271,5 @@
ASSERT_EQ(2, read_buffer[i]) << "Failed at byte " << i;
}
}
+
+} // namespace unwindstack
diff --git a/libunwindstack/tests/MemoryLocalTest.cpp b/libunwindstack/tests/MemoryLocalTest.cpp
index ab999da..73eebdd 100644
--- a/libunwindstack/tests/MemoryLocalTest.cpp
+++ b/libunwindstack/tests/MemoryLocalTest.cpp
@@ -21,7 +21,9 @@
#include <gtest/gtest.h>
-#include "Memory.h"
+#include <unwindstack/Memory.h>
+
+namespace unwindstack {
TEST(MemoryLocalTest, read) {
std::vector<uint8_t> src(1024);
@@ -64,3 +66,5 @@
uint64_t value;
ASSERT_FALSE(local.Read(reinterpret_cast<uint64_t>(&value), dst.data(), SIZE_MAX));
}
+
+} // namespace unwindstack
diff --git a/libunwindstack/tests/MemoryRangeTest.cpp b/libunwindstack/tests/MemoryRangeTest.cpp
index 469afcc..6d1366c 100644
--- a/libunwindstack/tests/MemoryRangeTest.cpp
+++ b/libunwindstack/tests/MemoryRangeTest.cpp
@@ -22,10 +22,12 @@
#include <gtest/gtest.h>
-#include "Memory.h"
+#include <unwindstack/Memory.h>
#include "MemoryFake.h"
+namespace unwindstack {
+
TEST(MemoryRangeTest, read) {
std::vector<uint8_t> src(1024);
memset(src.data(), 0x4c, 1024);
@@ -70,3 +72,5 @@
std::unique_ptr<MemoryRange> overflow(new MemoryRange(new MemoryFakeAlwaysReadZero, 100, 200));
ASSERT_FALSE(overflow->Read(UINT64_MAX - 10, buffer.data(), 100));
}
+
+} // namespace unwindstack
diff --git a/libunwindstack/tests/MemoryRemoteTest.cpp b/libunwindstack/tests/MemoryRemoteTest.cpp
index 7210786..f8965b2 100644
--- a/libunwindstack/tests/MemoryRemoteTest.cpp
+++ b/libunwindstack/tests/MemoryRemoteTest.cpp
@@ -31,10 +31,12 @@
#include <android-base/file.h>
#include <gtest/gtest.h>
-#include "Memory.h"
+#include <unwindstack/Memory.h>
#include "MemoryFake.h"
+namespace unwindstack {
+
class MemoryRemoteTest : public ::testing::Test {
protected:
static uint64_t NanoTime() {
@@ -164,3 +166,5 @@
kill(pid, SIGKILL);
ASSERT_EQ(pid, wait(nullptr));
}
+
+} // namespace unwindstack
diff --git a/libunwindstack/tests/MemoryTest.cpp b/libunwindstack/tests/MemoryTest.cpp
index 51b5d7d..4a9ed9f 100644
--- a/libunwindstack/tests/MemoryTest.cpp
+++ b/libunwindstack/tests/MemoryTest.cpp
@@ -22,10 +22,12 @@
#include <gtest/gtest.h>
-#include "Memory.h"
+#include <unwindstack/Memory.h>
#include "MemoryFake.h"
+namespace unwindstack {
+
TEST(MemoryTest, read32) {
MemoryFakeAlwaysReadZero memory;
@@ -124,3 +126,5 @@
ASSERT_TRUE(memory.ReadString(0, &dst_name));
ASSERT_EQ("short", dst_name);
}
+
+} // namespace unwindstack
diff --git a/libunwindstack/tests/RegsFake.h b/libunwindstack/tests/RegsFake.h
index c57954c..6669d7d 100644
--- a/libunwindstack/tests/RegsFake.h
+++ b/libunwindstack/tests/RegsFake.h
@@ -19,7 +19,10 @@
#include <stdint.h>
-#include "Regs.h"
+#include <unwindstack/Memory.h>
+#include <unwindstack/Regs.h>
+
+namespace unwindstack {
template <typename TypeParam>
class RegsFake : public RegsImpl<TypeParam> {
@@ -28,10 +31,12 @@
: RegsImpl<TypeParam>(total_regs, sp_reg, Regs::Location(Regs::LOCATION_UNKNOWN, 0)) {}
virtual ~RegsFake() = default;
- uint64_t GetRelPc(Elf*, const MapInfo*) override { return 0; }
uint64_t GetAdjustedPc(uint64_t, Elf*) override { return 0; }
void SetFromRaw() override {}
+ bool StepIfSignalHandler(uint64_t, Elf*, Memory*) override { return false; }
bool GetReturnAddressFromDefault(Memory*, uint64_t*) { return false; }
};
+} // namespace unwindstack
+
#endif // _LIBUNWINDSTACK_TESTS_REGS_FAKE_H
diff --git a/libunwindstack/tests/RegsStepIfSignalHandlerTest.cpp b/libunwindstack/tests/RegsStepIfSignalHandlerTest.cpp
new file mode 100644
index 0000000..85192d5
--- /dev/null
+++ b/libunwindstack/tests/RegsStepIfSignalHandlerTest.cpp
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+
+#include <gtest/gtest.h>
+
+#include <unwindstack/Elf.h>
+#include <unwindstack/Regs.h>
+
+#include "Machine.h"
+
+#include "MemoryFake.h"
+
+namespace unwindstack {
+
+class RegsStepIfSignalHandlerTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ elf_memory_ = new MemoryFake;
+ elf_.reset(new Elf(elf_memory_));
+ }
+
+ void ArmStepIfSignalHandlerNonRt(uint32_t pc_data);
+ void ArmStepIfSignalHandlerRt(uint32_t pc_data);
+
+ MemoryFake* elf_memory_;
+ MemoryFake process_memory_;
+ std::unique_ptr<Elf> elf_;
+};
+
+void RegsStepIfSignalHandlerTest::ArmStepIfSignalHandlerNonRt(uint32_t pc_data) {
+ uint64_t addr = 0x1000;
+ RegsArm regs;
+ regs[ARM_REG_PC] = 0x5000;
+ regs[ARM_REG_SP] = addr;
+ regs.SetFromRaw();
+
+ elf_memory_->SetData32(0x5000, pc_data);
+
+ for (uint64_t index = 0; index <= 30; index++) {
+ process_memory_.SetData32(addr + index * 4, index * 0x10);
+ }
+
+ ASSERT_TRUE(regs.StepIfSignalHandler(0x5000, elf_.get(), &process_memory_));
+ EXPECT_EQ(0x100U, regs[ARM_REG_SP]);
+ EXPECT_EQ(0x120U, regs[ARM_REG_PC]);
+ EXPECT_EQ(0x100U, regs.sp());
+ EXPECT_EQ(0x120U, regs.pc());
+}
+
+TEST_F(RegsStepIfSignalHandlerTest, arm_step_if_signal_handler_non_rt) {
+ // Form 1
+ ArmStepIfSignalHandlerNonRt(0xe3a07077);
+
+ // Form 2
+ ArmStepIfSignalHandlerNonRt(0xef900077);
+
+ // Form 3
+ ArmStepIfSignalHandlerNonRt(0xdf002777);
+}
+
+void RegsStepIfSignalHandlerTest::ArmStepIfSignalHandlerRt(uint32_t pc_data) {
+ uint64_t addr = 0x1000;
+ RegsArm regs;
+ regs[ARM_REG_PC] = 0x5000;
+ regs[ARM_REG_SP] = addr;
+ regs.SetFromRaw();
+
+ elf_memory_->SetData32(0x5000, pc_data);
+
+ for (uint64_t index = 0; index <= 100; index++) {
+ process_memory_.SetData32(addr + index * 4, index * 0x10);
+ }
+
+ ASSERT_TRUE(regs.StepIfSignalHandler(0x5000, elf_.get(), &process_memory_));
+ EXPECT_EQ(0x350U, regs[ARM_REG_SP]);
+ EXPECT_EQ(0x370U, regs[ARM_REG_PC]);
+ EXPECT_EQ(0x350U, regs.sp());
+ EXPECT_EQ(0x370U, regs.pc());
+}
+
+TEST_F(RegsStepIfSignalHandlerTest, arm_step_if_signal_handler_rt) {
+ // Form 1
+ ArmStepIfSignalHandlerRt(0xe3a070ad);
+
+ // Form 2
+ ArmStepIfSignalHandlerRt(0xef9000ad);
+
+ // Form 3
+ ArmStepIfSignalHandlerRt(0xdf0027ad);
+}
+
+TEST_F(RegsStepIfSignalHandlerTest, arm64_step_if_signal_handler) {
+ uint64_t addr = 0x1000;
+ RegsArm64 regs;
+ regs[ARM64_REG_PC] = 0x8000;
+ regs[ARM64_REG_SP] = addr;
+ regs.SetFromRaw();
+
+ elf_memory_->SetData64(0x8000, 0xd4000001d2801168ULL);
+
+ for (uint64_t index = 0; index <= 100; index++) {
+ process_memory_.SetData64(addr + index * 8, index * 0x10);
+ }
+
+ ASSERT_TRUE(regs.StepIfSignalHandler(0x8000, elf_.get(), &process_memory_));
+ EXPECT_EQ(0x460U, regs[ARM64_REG_SP]);
+ EXPECT_EQ(0x470U, regs[ARM64_REG_PC]);
+ EXPECT_EQ(0x460U, regs.sp());
+ EXPECT_EQ(0x470U, regs.pc());
+}
+
+TEST_F(RegsStepIfSignalHandlerTest, x86_step_if_signal_handler_no_siginfo) {
+ uint64_t addr = 0xa00;
+ RegsX86 regs;
+ regs[X86_REG_EIP] = 0x4100;
+ regs[X86_REG_ESP] = addr;
+ regs.SetFromRaw();
+
+ elf_memory_->SetData64(0x4100, 0x80cd00000077b858ULL);
+ for (uint64_t index = 0; index <= 25; index++) {
+ process_memory_.SetData32(addr + index * 4, index * 0x10);
+ }
+
+ ASSERT_TRUE(regs.StepIfSignalHandler(0x4100, elf_.get(), &process_memory_));
+ EXPECT_EQ(0x70U, regs[X86_REG_EBP]);
+ EXPECT_EQ(0x80U, regs[X86_REG_ESP]);
+ EXPECT_EQ(0x90U, regs[X86_REG_EBX]);
+ EXPECT_EQ(0xa0U, regs[X86_REG_EDX]);
+ EXPECT_EQ(0xb0U, regs[X86_REG_ECX]);
+ EXPECT_EQ(0xc0U, regs[X86_REG_EAX]);
+ EXPECT_EQ(0xf0U, regs[X86_REG_EIP]);
+ EXPECT_EQ(0x80U, regs.sp());
+ EXPECT_EQ(0xf0U, regs.pc());
+}
+
+TEST_F(RegsStepIfSignalHandlerTest, x86_step_if_signal_handler_siginfo) {
+ uint64_t addr = 0xa00;
+ RegsX86 regs;
+ regs[X86_REG_EIP] = 0x4100;
+ regs[X86_REG_ESP] = addr;
+ regs.SetFromRaw();
+
+ elf_memory_->SetData64(0x4100, 0x0080cd000000adb8ULL);
+ addr += 8;
+ // Pointer to ucontext data.
+ process_memory_.SetData32(addr, 0x8100);
+
+ addr = 0x8100;
+ for (uint64_t index = 0; index <= 30; index++) {
+ process_memory_.SetData32(addr + index * 4, index * 0x10);
+ }
+
+ ASSERT_TRUE(regs.StepIfSignalHandler(0x4100, elf_.get(), &process_memory_));
+ EXPECT_EQ(0xb0U, regs[X86_REG_EBP]);
+ EXPECT_EQ(0xc0U, regs[X86_REG_ESP]);
+ EXPECT_EQ(0xd0U, regs[X86_REG_EBX]);
+ EXPECT_EQ(0xe0U, regs[X86_REG_EDX]);
+ EXPECT_EQ(0xf0U, regs[X86_REG_ECX]);
+ EXPECT_EQ(0x100U, regs[X86_REG_EAX]);
+ EXPECT_EQ(0x130U, regs[X86_REG_EIP]);
+ EXPECT_EQ(0xc0U, regs.sp());
+ EXPECT_EQ(0x130U, regs.pc());
+}
+
+TEST_F(RegsStepIfSignalHandlerTest, x86_64_step_if_signal_handler) {
+ uint64_t addr = 0x500;
+ RegsX86_64 regs;
+ regs[X86_64_REG_RIP] = 0x7000;
+ regs[X86_64_REG_RSP] = addr;
+ regs.SetFromRaw();
+
+ elf_memory_->SetData64(0x7000, 0x0f0000000fc0c748);
+ elf_memory_->SetData16(0x7008, 0x0f05);
+
+ for (uint64_t index = 0; index <= 30; index++) {
+ process_memory_.SetData64(addr + index * 8, index * 0x10);
+ }
+
+ ASSERT_TRUE(regs.StepIfSignalHandler(0x7000, elf_.get(), &process_memory_));
+ EXPECT_EQ(0x140U, regs[X86_64_REG_RSP]);
+ EXPECT_EQ(0x150U, regs[X86_64_REG_RIP]);
+ EXPECT_EQ(0x140U, regs.sp());
+ EXPECT_EQ(0x150U, regs.pc());
+}
+
+} // namespace unwindstack
diff --git a/libunwindstack/tests/RegsTest.cpp b/libunwindstack/tests/RegsTest.cpp
index dde42de..e6de56a 100644
--- a/libunwindstack/tests/RegsTest.cpp
+++ b/libunwindstack/tests/RegsTest.cpp
@@ -18,13 +18,15 @@
#include <gtest/gtest.h>
-#include "Elf.h"
-#include "ElfInterface.h"
-#include "MapInfo.h"
-#include "Regs.h"
+#include <unwindstack/Elf.h>
+#include <unwindstack/ElfInterface.h>
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Regs.h>
#include "MemoryFake.h"
+namespace unwindstack {
+
class ElfFake : public Elf {
public:
ElfFake(Memory* memory) : Elf(memory) { valid_ = true; }
@@ -58,6 +60,7 @@
uint64_t GetAdjustedPc(uint64_t, Elf*) override { return 0; }
void SetFromRaw() override {}
+ bool StepIfSignalHandler(uint64_t, Elf*, Memory*) override { return false; }
};
class RegsTest : public ::testing::Test {
@@ -70,10 +73,7 @@
}
template <typename AddressType>
- void regs_rel_pc();
-
- template <typename AddressType>
- void regs_return_address_register();
+ void RegsReturnAddressRegister();
ElfInterfaceFake* elf_interface_;
MemoryFake* memory_;
@@ -127,27 +127,7 @@
}
template <typename AddressType>
-void RegsTest::regs_rel_pc() {
- RegsTestImpl<AddressType> regs(30, 12);
-
- elf_interface_->set_load_bias(0);
- MapInfo map_info{.start = 0x1000, .end = 0x2000};
- regs.set_pc(0x1101);
- ASSERT_EQ(0x101U, regs.GetRelPc(elf_.get(), &map_info));
- elf_interface_->set_load_bias(0x3000);
- ASSERT_EQ(0x3101U, regs.GetRelPc(elf_.get(), &map_info));
-}
-
-TEST_F(RegsTest, regs32_rel_pc) {
- regs_rel_pc<uint32_t>();
-}
-
-TEST_F(RegsTest, regs64_rel_pc) {
- regs_rel_pc<uint64_t>();
-}
-
-template <typename AddressType>
-void RegsTest::regs_return_address_register() {
+void RegsTest::RegsReturnAddressRegister() {
RegsTestImpl<AddressType> regs(20, 10, Regs::Location(Regs::LOCATION_REGISTER, 5));
regs[5] = 0x12345;
@@ -157,11 +137,11 @@
}
TEST_F(RegsTest, regs32_return_address_register) {
- regs_return_address_register<uint32_t>();
+ RegsReturnAddressRegister<uint32_t>();
}
TEST_F(RegsTest, regs64_return_address_register) {
- regs_return_address_register<uint64_t>();
+ RegsReturnAddressRegister<uint64_t>();
}
TEST_F(RegsTest, regs32_return_address_sp_offset) {
@@ -250,19 +230,19 @@
MapInfo map_info{.start = 0x1000, .end = 0x2000};
regs_arm.set_pc(0x1500);
- ASSERT_EQ(0x500U, regs_arm.GetRelPc(&invalid_elf, &map_info));
+ ASSERT_EQ(0x500U, invalid_elf.GetRelPc(regs_arm.pc(), &map_info));
ASSERT_EQ(0x500U, regs_arm.GetAdjustedPc(0x500U, &invalid_elf));
regs_arm64.set_pc(0x1600);
- ASSERT_EQ(0x600U, regs_arm64.GetRelPc(&invalid_elf, &map_info));
+ ASSERT_EQ(0x600U, invalid_elf.GetRelPc(regs_arm64.pc(), &map_info));
ASSERT_EQ(0x600U, regs_arm64.GetAdjustedPc(0x600U, &invalid_elf));
regs_x86.set_pc(0x1700);
- ASSERT_EQ(0x700U, regs_x86.GetRelPc(&invalid_elf, &map_info));
+ ASSERT_EQ(0x700U, invalid_elf.GetRelPc(regs_x86.pc(), &map_info));
ASSERT_EQ(0x700U, regs_x86.GetAdjustedPc(0x700U, &invalid_elf));
regs_x86_64.set_pc(0x1800);
- ASSERT_EQ(0x800U, regs_x86_64.GetRelPc(&invalid_elf, &map_info));
+ ASSERT_EQ(0x800U, invalid_elf.GetRelPc(regs_x86_64.pc(), &map_info));
ASSERT_EQ(0x800U, regs_x86_64.GetAdjustedPc(0x800U, &invalid_elf));
}
@@ -305,3 +285,5 @@
EXPECT_EQ(0x1200000000U, x86_64.sp());
EXPECT_EQ(0x4900000000U, x86_64.pc());
}
+
+} // namespace unwindstack
diff --git a/libunwindstack/tests/SymbolsTest.cpp b/libunwindstack/tests/SymbolsTest.cpp
index a0a21e6..da258a6 100644
--- a/libunwindstack/tests/SymbolsTest.cpp
+++ b/libunwindstack/tests/SymbolsTest.cpp
@@ -32,10 +32,13 @@
#include <android-base/test_utils.h>
#include <gtest/gtest.h>
-#include "Memory.h"
+#include <unwindstack/Memory.h>
+
#include "MemoryFake.h"
#include "Symbols.h"
+namespace unwindstack {
+
template <typename TypeParam>
class SymbolsTest : public ::testing::Test {
protected:
@@ -333,3 +336,5 @@
typedef ::testing::Types<Elf32_Sym, Elf64_Sym> SymbolsTestTypes;
INSTANTIATE_TYPED_TEST_CASE_P(, SymbolsTest, SymbolsTestTypes);
+
+} // namespace unwindstack
diff --git a/libunwindstack/tests/UnwindTest.cpp b/libunwindstack/tests/UnwindTest.cpp
index 7497b65..3c69e2a 100644
--- a/libunwindstack/tests/UnwindTest.cpp
+++ b/libunwindstack/tests/UnwindTest.cpp
@@ -30,26 +30,54 @@
#include <sstream>
#include <string>
#include <thread>
+#include <vector>
-#include "Elf.h"
-#include "MapInfo.h"
-#include "Maps.h"
-#include "Memory.h"
-#include "Regs.h"
-#include "RegsGetLocal.h"
+#include <unwindstack/Elf.h>
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Maps.h>
+#include <unwindstack/Memory.h>
+#include <unwindstack/Regs.h>
+#include <unwindstack/RegsGetLocal.h>
+
+namespace unwindstack {
static std::atomic_bool g_ready(false);
static volatile bool g_ready_for_remote = false;
+static volatile bool g_signal_ready_for_remote = false;
static std::atomic_bool g_finish(false);
static std::atomic_uintptr_t g_ucontext;
-static void Signal(int, siginfo_t*, void* sigcontext) {
+static std::vector<const char*> kFunctionOrder{"InnerFunction", "MiddleFunction", "OuterFunction"};
+
+static std::vector<const char*> kFunctionSignalOrder{"SignalInnerFunction", "SignalMiddleFunction",
+ "SignalOuterFunction", "InnerFunction",
+ "MiddleFunction", "OuterFunction"};
+
+static void SignalHandler(int, siginfo_t*, void* sigcontext) {
g_ucontext = reinterpret_cast<uintptr_t>(sigcontext);
while (!g_finish.load()) {
}
}
-static std::string ErrorMsg(const char** function_names, size_t index,
+extern "C" void SignalInnerFunction() {
+ g_signal_ready_for_remote = true;
+ while (!g_finish.load()) {
+ }
+}
+
+extern "C" void SignalMiddleFunction() {
+ SignalInnerFunction();
+}
+
+extern "C" void SignalOuterFunction() {
+ SignalMiddleFunction();
+}
+
+static void SignalCallerHandler(int, siginfo_t*, void*) {
+ SignalOuterFunction();
+}
+
+static std::string ErrorMsg(const std::vector<const char*>& function_names, size_t index,
std::stringstream& unwind_stream) {
return std::string(
"Unwind completed without finding all frames\n"
@@ -57,10 +85,8 @@
function_names[index] + "\n" + "Unwind data:\n" + unwind_stream.str();
}
-static void VerifyUnwind(pid_t pid, Memory* memory, Maps* maps, Regs* regs) {
- const char* function_names[] = {
- "InnerFunction", "MiddleFunction", "OuterFunction",
- };
+static void VerifyUnwind(pid_t pid, Memory* memory, Maps* maps, Regs* regs,
+ std::vector<const char*>& function_names) {
size_t function_name_index = 0;
std::stringstream unwind_stream;
@@ -71,7 +97,7 @@
ASSERT_TRUE(map_info != nullptr) << ErrorMsg(function_names, function_name_index, unwind_stream);
Elf* elf = map_info->GetElf(pid, true);
- uint64_t rel_pc = regs->GetRelPc(elf, map_info);
+ uint64_t rel_pc = elf->GetRelPc(regs->pc(), map_info);
uint64_t adjusted_rel_pc = rel_pc;
if (frame_num != 0) {
adjusted_rel_pc = regs->GetAdjustedPc(rel_pc, elf);
@@ -89,8 +115,7 @@
uint64_t func_offset;
if (elf->GetFunctionName(adjusted_rel_pc, &name, &func_offset)) {
if (name == function_names[function_name_index]) {
- function_name_index++;
- if (function_name_index == sizeof(function_names) / sizeof(const char*)) {
+ if (++function_name_index == function_names.size()) {
return;
}
}
@@ -114,7 +139,7 @@
RegsGetLocal(regs.get());
MemoryLocal memory;
- VerifyUnwind(getpid(), &memory, &maps, regs.get());
+ VerifyUnwind(getpid(), &memory, &maps, regs.get(), kFunctionOrder);
} else {
g_ready_for_remote = true;
g_ready = true;
@@ -135,6 +160,37 @@
OuterFunction(true);
}
+void WaitForRemote(pid_t pid, uint64_t addr, bool leave_attached, bool* completed) {
+ *completed = false;
+ // Need to sleep before attempting first ptrace. Without this, on the
+ // host it becomes impossible to attach and ptrace set errno to EPERM.
+ usleep(1000);
+ for (size_t i = 0; i < 100; i++) {
+ ASSERT_EQ(0, ptrace(PTRACE_ATTACH, pid, 0, 0));
+ for (size_t j = 0; j < 100; j++) {
+ siginfo_t si;
+ if (ptrace(PTRACE_GETSIGINFO, pid, 0, &si) == 0) {
+ MemoryRemote memory(pid);
+ // Read the remote value to see if we are ready.
+ bool value;
+ if (memory.Read(addr, &value, sizeof(value)) && value) {
+ *completed = true;
+ break;
+ }
+ }
+ usleep(1000);
+ }
+ if (leave_attached && *completed) {
+ break;
+ }
+ ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0));
+ if (*completed) {
+ break;
+ }
+ usleep(1000);
+ }
+}
+
TEST(UnwindTest, remote) {
pid_t pid;
if ((pid = fork()) == 0) {
@@ -143,31 +199,9 @@
}
ASSERT_NE(-1, pid);
- bool ready = false;
- uint64_t addr = reinterpret_cast<uint64_t>(&g_ready_for_remote);
- for (size_t i = 0; i < 100; i++) {
- ASSERT_EQ(0, ptrace(PTRACE_ATTACH, pid, 0, 0));
- for (size_t j = 0; j < 100; j++) {
- siginfo_t si;
- if (ptrace(PTRACE_GETSIGINFO, pid, 0, &si) == 0) {
- // Check to see if process is ready to be unwound.
- MemoryRemote memory(pid);
- // Read the remote value to see if we are ready.
- bool value;
- if (memory.Read(addr, &value, sizeof(value)) && value) {
- ready = true;
- break;
- }
- }
- usleep(1000);
- }
- if (ready) {
- break;
- }
- ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0));
- usleep(1000);
- }
- ASSERT_TRUE(read) << "Timed out waiting for remote process to be ready.";
+ bool completed;
+ WaitForRemote(pid, reinterpret_cast<uint64_t>(&g_ready_for_remote), true, &completed);
+ ASSERT_TRUE(completed) << "Timed out waiting for remote process to be ready.";
RemoteMaps maps(pid);
ASSERT_TRUE(maps.Parse());
@@ -176,7 +210,7 @@
std::unique_ptr<Regs> regs(Regs::RemoteGet(pid, &machine_type));
ASSERT_TRUE(regs.get() != nullptr);
- VerifyUnwind(pid, &memory, &maps, regs.get());
+ VerifyUnwind(pid, &memory, &maps, regs.get(), kFunctionOrder);
ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0));
@@ -193,7 +227,7 @@
struct sigaction act, oldact;
memset(&act, 0, sizeof(act));
- act.sa_sigaction = Signal;
+ act.sa_sigaction = SignalHandler;
act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
ASSERT_EQ(0, sigaction(SIGUSR1, &act, &oldact));
// Wait for the tid to get set.
@@ -205,12 +239,11 @@
}
ASSERT_NE(0, tid.load());
// Portable tgkill method.
- ASSERT_EQ(0, syscall(__NR_tgkill, getpid(), tid.load(), SIGUSR1)) << "Failed because "
- << strerror(errno);
+ ASSERT_EQ(0, syscall(__NR_tgkill, getpid(), tid.load(), SIGUSR1)) << "Error: " << strerror(errno);
// Wait for context data.
void* ucontext;
- for (size_t i = 0; i < 200; i++) {
+ for (size_t i = 0; i < 2000; i++) {
ucontext = reinterpret_cast<void*>(g_ucontext.load());
if (ucontext != nullptr) {
break;
@@ -224,10 +257,60 @@
std::unique_ptr<Regs> regs(Regs::CreateFromUcontext(Regs::GetMachineType(), ucontext));
MemoryLocal memory;
- VerifyUnwind(tid.load(), &memory, &maps, regs.get());
+ VerifyUnwind(tid.load(), &memory, &maps, regs.get(), kFunctionOrder);
ASSERT_EQ(0, sigaction(SIGUSR1, &oldact, nullptr));
g_finish = true;
thread.join();
}
+
+static void RemoteThroughSignal(unsigned int sa_flags) {
+ g_ready = false;
+ g_signal_ready_for_remote = false;
+ g_finish = false;
+
+ pid_t pid;
+ if ((pid = fork()) == 0) {
+ struct sigaction act, oldact;
+ memset(&act, 0, sizeof(act));
+ act.sa_sigaction = SignalCallerHandler;
+ act.sa_flags = SA_RESTART | SA_ONSTACK | sa_flags;
+ ASSERT_EQ(0, sigaction(SIGUSR1, &act, &oldact));
+
+ OuterFunction(false);
+ exit(0);
+ }
+ ASSERT_NE(-1, pid);
+
+ bool completed;
+ WaitForRemote(pid, reinterpret_cast<uint64_t>(&g_ready_for_remote), false, &completed);
+ ASSERT_TRUE(completed) << "Timed out waiting for remote process to be ready.";
+ ASSERT_EQ(0, kill(pid, SIGUSR1));
+ WaitForRemote(pid, reinterpret_cast<uint64_t>(&g_signal_ready_for_remote), true, &completed);
+ ASSERT_TRUE(completed) << "Timed out waiting for remote process to be in signal handler.";
+
+ RemoteMaps maps(pid);
+ ASSERT_TRUE(maps.Parse());
+ MemoryRemote memory(pid);
+ uint32_t machine_type;
+ std::unique_ptr<Regs> regs(Regs::RemoteGet(pid, &machine_type));
+ ASSERT_TRUE(regs.get() != nullptr);
+
+ VerifyUnwind(pid, &memory, &maps, regs.get(), kFunctionSignalOrder);
+
+ ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0));
+
+ kill(pid, SIGKILL);
+ ASSERT_EQ(pid, wait(nullptr));
+}
+
+TEST(UnwindTest, remote_through_signal) {
+ RemoteThroughSignal(0);
+}
+
+TEST(UnwindTest, remote_through_signal_sa_siginfo) {
+ RemoteThroughSignal(SA_SIGINFO);
+}
+
+} // namespace unwindstack
diff --git a/libunwindstack/tools/unwind.cpp b/libunwindstack/tools/unwind.cpp
new file mode 100644
index 0000000..642105a
--- /dev/null
+++ b/libunwindstack/tools/unwind.cpp
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <elf.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <string>
+
+#include <unwindstack/Elf.h>
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Maps.h>
+#include <unwindstack/Memory.h>
+#include <unwindstack/Regs.h>
+
+static bool Attach(pid_t pid) {
+ if (ptrace(PTRACE_ATTACH, pid, 0, 0) == -1) {
+ return false;
+ }
+
+ // Allow at least 1 second to attach properly.
+ for (size_t i = 0; i < 1000; i++) {
+ siginfo_t si;
+ if (ptrace(PTRACE_GETSIGINFO, pid, 0, &si) == 0) {
+ return true;
+ }
+ usleep(1000);
+ }
+ printf("%d: Failed to stop.\n", pid);
+ return false;
+}
+
+static bool Detach(pid_t pid) {
+ return ptrace(PTRACE_DETACH, pid, 0, 0) == 0;
+}
+
+void DoUnwind(pid_t pid) {
+ unwindstack::RemoteMaps remote_maps(pid);
+ if (!remote_maps.Parse()) {
+ printf("Failed to parse map data.\n");
+ return;
+ }
+
+ uint32_t machine_type;
+ unwindstack::Regs* regs = unwindstack::Regs::RemoteGet(pid, &machine_type);
+ if (regs == nullptr) {
+ printf("Unable to get remote reg data\n");
+ return;
+ }
+
+ bool bits32 = true;
+ printf("ABI: ");
+ switch (machine_type) {
+ case EM_ARM:
+ printf("arm");
+ break;
+ case EM_386:
+ printf("x86");
+ break;
+ case EM_AARCH64:
+ printf("arm64");
+ bits32 = false;
+ break;
+ case EM_X86_64:
+ printf("x86_64");
+ bits32 = false;
+ break;
+ default:
+ printf("unknown\n");
+ return;
+ }
+ printf("\n");
+
+ unwindstack::MemoryRemote remote_memory(pid);
+ for (size_t frame_num = 0; frame_num < 64; frame_num++) {
+ if (regs->pc() == 0) {
+ break;
+ }
+ unwindstack::MapInfo* map_info = remote_maps.Find(regs->pc());
+ if (map_info == nullptr) {
+ printf("Failed to find map data for the pc\n");
+ break;
+ }
+
+ unwindstack::Elf* elf = map_info->GetElf(pid, true);
+
+ uint64_t rel_pc = elf->GetRelPc(regs->pc(), map_info);
+ uint64_t adjusted_rel_pc = rel_pc;
+ // Don't need to adjust the first frame pc.
+ if (frame_num != 0) {
+ adjusted_rel_pc = regs->GetAdjustedPc(rel_pc, elf);
+ }
+
+ std::string name;
+ if (bits32) {
+ printf(" #%02zu pc %08" PRIx64, frame_num, adjusted_rel_pc);
+ } else {
+ printf(" #%02zu pc %016" PRIx64, frame_num, adjusted_rel_pc);
+ }
+ if (!map_info->name.empty()) {
+ printf(" %s", map_info->name.c_str());
+ if (map_info->elf_offset != 0) {
+ printf(" (offset 0x%" PRIx64 ")", map_info->elf_offset);
+ }
+ } else {
+ printf(" <anonymous:%" PRIx64 ">", map_info->offset);
+ }
+ uint64_t func_offset;
+ if (elf->GetFunctionName(adjusted_rel_pc, &name, &func_offset)) {
+ printf(" (%s", name.c_str());
+ if (func_offset != 0) {
+ printf("+%" PRId64, func_offset);
+ }
+ printf(")");
+ }
+ printf("\n");
+
+ if (!elf->Step(rel_pc + map_info->elf_offset, regs, &remote_memory)) {
+ break;
+ }
+ }
+}
+
+int main(int argc, char** argv) {
+ if (argc != 2) {
+ printf("Usage: unwind <PID>\n");
+ return 1;
+ }
+
+ pid_t pid = atoi(argv[1]);
+ if (!Attach(pid)) {
+ printf("Failed to attach to pid %d: %s\n", pid, strerror(errno));
+ return 1;
+ }
+
+ DoUnwind(pid);
+
+ Detach(pid);
+
+ return 0;
+}
diff --git a/libunwindstack/unwind_info.cpp b/libunwindstack/tools/unwind_info.cpp
similarity index 92%
rename from libunwindstack/unwind_info.cpp
rename to libunwindstack/tools/unwind_info.cpp
index da1522b..66a9439 100644
--- a/libunwindstack/unwind_info.cpp
+++ b/libunwindstack/tools/unwind_info.cpp
@@ -21,17 +21,20 @@
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
-#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/types.h>
#include <unistd.h>
+#include <unwindstack/DwarfSection.h>
+#include <unwindstack/DwarfStructs.h>
+#include <unwindstack/Elf.h>
+#include <unwindstack/ElfInterface.h>
+#include <unwindstack/Log.h>
+
#include "ArmExidx.h"
-#include "DwarfSection.h"
-#include "DwarfStructs.h"
-#include "Elf.h"
-#include "ElfInterface.h"
#include "ElfInterfaceArm.h"
-#include "Log.h"
+
+namespace unwindstack {
void DumpArm(ElfInterfaceArm* interface) {
if (interface == nullptr) {
@@ -100,31 +103,12 @@
}
}
-int main(int argc, char** argv) {
- if (argc != 2) {
- printf("Need to pass the name of an elf file to the program.\n");
- return 1;
- }
-
- struct stat st;
- if (stat(argv[1], &st) == -1) {
- printf("Cannot stat %s: %s\n", argv[1], strerror(errno));
- return 1;
- }
- if (!S_ISREG(st.st_mode)) {
- printf("%s is not a regular file.\n", argv[1]);
- return 1;
- }
- if (S_ISDIR(st.st_mode)) {
- printf("%s is a directory.\n", argv[1]);
- return 1;
- }
-
+int GetElfInfo(const char* file) {
// Send all log messages to stdout.
log_to_stdout(true);
MemoryFileAtOffset* memory = new MemoryFileAtOffset;
- if (!memory->Init(argv[1], 0)) {
+ if (!memory->Init(file, 0)) {
// Initializatation failed.
printf("Failed to init\n");
return 1;
@@ -132,7 +116,7 @@
Elf elf(memory);
if (!elf.Init() || !elf.valid()) {
- printf("%s is not a valid elf file.\n", argv[1]);
+ printf("%s is not a valid elf file.\n", file);
return 1;
}
@@ -177,3 +161,24 @@
return 0;
}
+
+} // namespace unwindstack
+
+int main(int argc, char** argv) {
+ if (argc != 2) {
+ printf("Need to pass the name of an elf file to the program.\n");
+ return 1;
+ }
+
+ struct stat st;
+ if (stat(argv[1], &st) == -1) {
+ printf("Cannot stat %s: %s\n", argv[1], strerror(errno));
+ return 1;
+ }
+ if (!S_ISREG(st.st_mode)) {
+ printf("%s is not a regular file.\n", argv[1]);
+ return 1;
+ }
+
+ return unwindstack::GetElfInfo(argv[1]);
+}
diff --git a/libunwindstack/tools/unwind_symbols.cpp b/libunwindstack/tools/unwind_symbols.cpp
new file mode 100644
index 0000000..b757c1e
--- /dev/null
+++ b/libunwindstack/tools/unwind_symbols.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <elf.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <unwindstack/Elf.h>
+#include <unwindstack/Log.h>
+#include <unwindstack/Memory.h>
+
+int main(int argc, char** argv) {
+ if (argc != 2) {
+ printf("Need to pass the name of an elf file to the program.\n");
+ return 1;
+ }
+
+ struct stat st;
+ if (stat(argv[1], &st) == -1) {
+ printf("Cannot stat %s: %s\n", argv[1], strerror(errno));
+ return 1;
+ }
+ if (!S_ISREG(st.st_mode)) {
+ printf("%s is not a regular file.\n", argv[1]);
+ return 1;
+ }
+
+ // Send all log messages to stdout.
+ unwindstack::log_to_stdout(true);
+
+ unwindstack::MemoryFileAtOffset* memory = new unwindstack::MemoryFileAtOffset;
+ if (!memory->Init(argv[1], 0)) {
+ printf("Failed to init\n");
+ return 1;
+ }
+
+ unwindstack::Elf elf(memory);
+ if (!elf.Init() || !elf.valid()) {
+ printf("%s is not a valid elf file.\n", argv[1]);
+ return 1;
+ }
+
+ switch (elf.machine_type()) {
+ case EM_ARM:
+ printf("ABI: arm\n");
+ break;
+ case EM_AARCH64:
+ printf("ABI: arm64\n");
+ break;
+ case EM_386:
+ printf("ABI: x86\n");
+ break;
+ case EM_X86_64:
+ printf("ABI: x86_64\n");
+ break;
+ default:
+ printf("ABI: unknown\n");
+ return 1;
+ }
+
+ // This is a crude way to get the symbols in order.
+ std::string name;
+ uint64_t load_bias = elf.interface()->load_bias();
+ for (const auto& entry : elf.interface()->pt_loads()) {
+ uint64_t start = entry.second.offset + load_bias;
+ uint64_t end = entry.second.table_size + load_bias;
+ for (uint64_t addr = start; addr < end; addr += 4) {
+ std::string cur_name;
+ uint64_t func_offset;
+ if (elf.GetFunctionName(addr, &cur_name, &func_offset)) {
+ if (cur_name != name) {
+ printf("<0x%" PRIx64 "> Function: %s\n", addr - func_offset, cur_name.c_str());
+ }
+ name = cur_name;
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/libutils/Android.bp b/libutils/Android.bp
index 0125eac..fbfb7c2 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -53,7 +53,6 @@
"FileMap.cpp",
"JenkinsHash.cpp",
"LinearTransform.cpp",
- "Log.cpp",
"NativeHandle.cpp",
"Printer.cpp",
"PropertyMap.cpp",
diff --git a/libutils/Log.cpp b/libutils/Log.cpp
deleted file mode 100644
index bffb56e..0000000
--- a/libutils/Log.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "Log"
-
-#include <utils/Log.h>
-#include <utils/Timers.h>
-
-namespace android {
-
-LogIfSlow::LogIfSlow(const char* tag, android_LogPriority priority,
- int timeoutMillis, const char* message) :
- mTag(tag), mPriority(priority), mTimeoutMillis(timeoutMillis), mMessage(message),
- mStart(systemTime(SYSTEM_TIME_BOOTTIME)) {
-}
-
-LogIfSlow::~LogIfSlow() {
- int durationMillis = nanoseconds_to_milliseconds(systemTime(SYSTEM_TIME_BOOTTIME) - mStart);
- if (durationMillis > mTimeoutMillis) {
- LOG_PRI(mPriority, mTag, "%s: %dms", mMessage, durationMillis);
- }
-}
-
-} // namespace android
diff --git a/libutils/include/utils/Log.h b/libutils/include/utils/Log.h
index 5276a49..42e03e7 100644
--- a/libutils/include/utils/Log.h
+++ b/libutils/include/utils/Log.h
@@ -1,72 +1,7 @@
-/*
- * Copyright (C) 2005 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
+// DO NOT INCLUDE ANYTHING NEW IN THIS FILE.
-//
-// C/C++ logging functions. See the logging documentation for API details.
-//
-// We'd like these to be available from C code (in case we import some from
-// somewhere), so this has a C interface.
-//
-// The output will be correct when the log file is shared between multiple
-// threads and/or multiple processes so long as the operating system
-// supports O_APPEND. These calls have mutex-protected data structures
-// and so are NOT reentrant. Do not use LOG in a signal handler.
-//
-#ifndef _LIBS_UTILS_LOG_H
-#define _LIBS_UTILS_LOG_H
-
-#include <sys/types.h>
+// <log/log.h> has replaced this file and all changes should go there instead.
+// This path remains strictly to include that header as there are thousands of
+// references to <utils/Log.h> in the tree.
#include <log/log.h>
-
-#ifdef __cplusplus
-
-namespace android {
-
-/*
- * A very simple utility that yells in the log when an operation takes too long.
- */
-class LogIfSlow {
-public:
- LogIfSlow(const char* tag, android_LogPriority priority,
- int timeoutMillis, const char* message);
- ~LogIfSlow();
-
-private:
- const char* const mTag;
- const android_LogPriority mPriority;
- const int mTimeoutMillis;
- const char* const mMessage;
- const int64_t mStart;
-};
-
-/*
- * Writes the specified debug log message if this block takes longer than the
- * specified number of milliseconds to run. Includes the time actually taken.
- *
- * {
- * ALOGD_IF_SLOW(50, "Excessive delay doing something.");
- * doSomething();
- * }
- */
-#define ALOGD_IF_SLOW(timeoutMillis, message) \
- android::LogIfSlow _logIfSlow(LOG_TAG, ANDROID_LOG_DEBUG, timeoutMillis, message);
-
-} // namespace android
-
-#endif // __cplusplus
-
-#endif // _LIBS_UTILS_LOG_H
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index e9ef9cc..f64196f 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -1638,7 +1638,7 @@
logcat_panic(context, HELP_FALSE, "read: unexpected length.\n");
break;
}
- logcat_panic(context, HELP_FALSE, "logcat read failure");
+ logcat_panic(context, HELP_FALSE, "logcat read failure\n");
break;
}
diff --git a/rootdir/init.rc b/rootdir/init.rc
index d3a1d17..9301743 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -376,6 +376,20 @@
# create basic filesystem structure
mkdir /data/misc 01771 system misc
+ mkdir /data/misc/recovery 0770 system log
+ copy /data/misc/recovery/default.prop /data/misc/recovery/default.prop.1
+ chmod 0440 /data/misc/recovery/default.prop.1
+ chown system log /data/misc/recovery/default.prop.1
+ copy /default.prop /data/misc/recovery/default.prop
+ chmod 0440 /data/misc/recovery/default.prop
+ chown system log /data/misc/recovery/default.prop
+ mkdir /data/misc/recovery/proc 0770 system log
+ copy /data/misc/recovery/proc/version /data/misc/recovery/proc/version.1
+ chmod 0440 /data/misc/recovery/proc/version.1
+ chown system log /data/misc/recovery/proc/version.1
+ copy /proc/version /data/misc/recovery/proc/version
+ chmod 0440 /data/misc/recovery/proc/version
+ chown system log /data/misc/recovery/proc/version
mkdir /data/misc/bluedroid 02770 bluetooth bluetooth
# Fix the access permissions and group ownership for 'bt_config.conf'
chmod 0660 /data/misc/bluedroid/bt_config.conf
diff --git a/trusty/keymaster/trusty_keymaster_device_test.cpp b/trusty/keymaster/trusty_keymaster_device_test.cpp
index 3bb5430..e8f5c0b 100644
--- a/trusty/keymaster/trusty_keymaster_device_test.cpp
+++ b/trusty/keymaster/trusty_keymaster_device_test.cpp
@@ -16,8 +16,8 @@
#include <algorithm>
#include <fstream>
-#include <UniquePtr.h>
#include <gtest/gtest.h>
+#include <nativehelper/UniquePtr.h>
#include <openssl/engine.h>
#include <hardware/keymaster0.h>