Merge "Add force_suspend function"
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index 7fec47d..fb8a205 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -195,6 +195,7 @@
"libcutils",
"libdebuggerd_client",
"liblog",
+ "libminijail",
"libnativehelper"
],
diff --git a/debuggerd/Android.mk b/debuggerd/Android.mk
new file mode 100644
index 0000000..3bc1742
--- /dev/null
+++ b/debuggerd/Android.mk
@@ -0,0 +1,23 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := crash_dump.policy
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MULTILIB := both
+
+ifeq ($(TARGET_ARCH), $(filter $(TARGET_ARCH), arm arm64))
+LOCAL_MODULE_STEM_32 := crash_dump.arm.policy
+LOCAL_MODULE_STEM_64 := crash_dump.arm64.policy
+endif
+
+ifeq ($(TARGET_ARCH), $(filter $(TARGET_ARCH), x86 x86_64))
+LOCAL_MODULE_STEM_32 := crash_dump.x86.policy
+LOCAL_MODULE_STEM_64 := crash_dump.x86_64.policy
+endif
+
+LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/seccomp_policy
+LOCAL_SRC_FILES_arm := seccomp_policy/crash_dump.arm.policy
+LOCAL_SRC_FILES_arm64 := seccomp_policy/crash_dump.arm64.policy
+LOCAL_SRC_FILES_x86 := seccomp_policy/crash_dump.x86.policy
+LOCAL_SRC_FILES_x86_64 := seccomp_policy/crash_dump.x86_64.policy
+include $(BUILD_PREBUILT)
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index 939f4d2..f8b4bad 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -41,6 +41,9 @@
#include <cutils/sockets.h>
#include <gtest/gtest.h>
+#include <libminijail.h>
+#include <scoped_minijail.h>
+
#include "debuggerd/handler.h"
#include "protocol.h"
#include "tombstoned/tombstoned.h"
@@ -76,9 +79,8 @@
return value; \
}()
-#define ASSERT_BACKTRACE_FRAME(result, frame_name) \
- ASSERT_MATCH(result, R"(#\d\d pc [0-9a-f]+\s+ /system/lib)" ARCH_SUFFIX \
- R"(/libc.so \()" frame_name R"(\+)")
+#define ASSERT_BACKTRACE_FRAME(result, frame_name) \
+ ASSERT_MATCH(result, R"(#\d\d pc [0-9a-f]+\s+ \S+ \()" frame_name R"(\+)");
static void tombstoned_intercept(pid_t target_pid, unique_fd* intercept_fd, unique_fd* output_fd,
InterceptStatus* status, DebuggerdDumpType intercept_type) {
@@ -565,6 +567,141 @@
ASSERT_BACKTRACE_FRAME(result, "tgkill");
}
+static const char* const kDebuggerdSeccompPolicy =
+ "/system/etc/seccomp_policy/crash_dump." ABI_STRING ".policy";
+
+pid_t seccomp_fork() {
+ unique_fd policy_fd(open(kDebuggerdSeccompPolicy, O_RDONLY | O_CLOEXEC));
+ if (policy_fd == -1) {
+ LOG(FATAL) << "failed to open policy " << kDebuggerdSeccompPolicy;
+ }
+
+ ScopedMinijail jail{minijail_new()};
+ if (!jail) {
+ LOG(FATAL) << "failed to create minijail";
+ }
+
+ minijail_no_new_privs(jail.get());
+ minijail_log_seccomp_filter_failures(jail.get());
+ minijail_use_seccomp_filter(jail.get());
+ minijail_parse_seccomp_filters_from_fd(jail.get(), policy_fd.release());
+
+ pid_t result = fork();
+ if (result == -1) {
+ return result;
+ } else if (result != 0) {
+ return result;
+ }
+
+ // Spawn and detach a thread that spins forever.
+ std::atomic<bool> thread_ready(false);
+ std::thread thread([&jail, &thread_ready]() {
+ minijail_enter(jail.get());
+ thread_ready = true;
+ for (;;)
+ ;
+ });
+ thread.detach();
+
+ while (!thread_ready) {
+ continue;
+ }
+
+ minijail_enter(jail.get());
+ return result;
+}
+
+TEST_F(CrasherTest, seccomp_crash) {
+ int intercept_result;
+ unique_fd output_fd;
+
+ StartProcess([]() { abort(); }, &seccomp_fork);
+
+ StartIntercept(&output_fd);
+ FinishCrasher();
+ AssertDeath(SIGABRT);
+ FinishIntercept(&intercept_result);
+ ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
+
+ std::string result;
+ ConsumeFd(std::move(output_fd), &result);
+ ASSERT_BACKTRACE_FRAME(result, "abort");
+}
+
+__attribute__((noinline)) extern "C" bool raise_debugger_signal(DebuggerdDumpType dump_type) {
+ siginfo_t siginfo;
+ siginfo.si_code = SI_QUEUE;
+ siginfo.si_pid = getpid();
+ siginfo.si_uid = getuid();
+
+ if (dump_type != kDebuggerdNativeBacktrace && dump_type != kDebuggerdTombstone) {
+ PLOG(FATAL) << "invalid dump type";
+ }
+
+ siginfo.si_value.sival_int = dump_type == kDebuggerdNativeBacktrace;
+
+ if (syscall(__NR_rt_tgsigqueueinfo, getpid(), gettid(), DEBUGGER_SIGNAL, &siginfo) != 0) {
+ PLOG(ERROR) << "libdebuggerd_client: failed to send signal to self";
+ return false;
+ }
+
+ return true;
+}
+
+TEST_F(CrasherTest, seccomp_tombstone) {
+ int intercept_result;
+ unique_fd output_fd;
+
+ static const auto dump_type = kDebuggerdTombstone;
+ StartProcess(
+ []() {
+ raise_debugger_signal(dump_type);
+ _exit(0);
+ },
+ &seccomp_fork);
+
+ StartIntercept(&output_fd, dump_type);
+ FinishCrasher();
+ AssertDeath(0);
+ FinishIntercept(&intercept_result);
+ ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
+
+ std::string result;
+ ConsumeFd(std::move(output_fd), &result);
+ ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
+}
+
+TEST_F(CrasherTest, seccomp_backtrace) {
+ int intercept_result;
+ unique_fd output_fd;
+
+ static const auto dump_type = kDebuggerdNativeBacktrace;
+ StartProcess(
+ []() {
+ raise_debugger_signal(dump_type);
+ _exit(0);
+ },
+ &seccomp_fork);
+
+ StartIntercept(&output_fd, dump_type);
+ FinishCrasher();
+ AssertDeath(0);
+ FinishIntercept(&intercept_result);
+ ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
+
+ std::string result;
+ ConsumeFd(std::move(output_fd), &result);
+ ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
+}
+
+TEST_F(CrasherTest, seccomp_crash_logcat) {
+ StartProcess([]() { abort(); }, &seccomp_fork);
+ FinishCrasher();
+
+ // Make sure we don't get SIGSYS when trying to dump a crash to logcat.
+ AssertDeath(SIGABRT);
+}
+
TEST_F(CrasherTest, competing_tracer) {
int intercept_result;
unique_fd output_fd;
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h b/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h
index 198c48b..be90d0f 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h
@@ -40,16 +40,16 @@
/* Creates a tombstone file and writes the crash dump to it. */
void engrave_tombstone(int tombstone_fd, BacktraceMap* map, const OpenFilesList* open_files,
pid_t pid, pid_t tid, const std::string& process_name,
- const std::map<pid_t, std::string>& threads, uintptr_t abort_msg_address,
+ const std::map<pid_t, std::string>& threads, uint64_t abort_msg_address,
std::string* amfd_data);
-void engrave_tombstone_ucontext(int tombstone_fd, uintptr_t abort_msg_address, siginfo_t* siginfo,
+void engrave_tombstone_ucontext(int tombstone_fd, uint64_t abort_msg_address, siginfo_t* siginfo,
ucontext_t* ucontext);
void engrave_tombstone(android::base::unique_fd output_fd, BacktraceMap* map,
unwindstack::Memory* process_memory,
const std::map<pid_t, ThreadInfo>& thread_info, pid_t target_thread,
- uintptr_t abort_msg_address, OpenFilesList* open_files,
+ uint64_t abort_msg_address, OpenFilesList* open_files,
std::string* amfd_data);
#endif // _DEBUGGERD_TOMBSTONE_H
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
index c5abfe2..0f049fd 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
@@ -68,7 +68,7 @@
class Memory;
}
-void dump_memory(log_t* log, unwindstack::Memory* backtrace, uintptr_t addr, const char* fmt, ...);
+void dump_memory(log_t* log, unwindstack::Memory* backtrace, uint64_t addr, const char* fmt, ...);
void read_with_default(const char* path, char* buf, size_t len, const char* default_value);
diff --git a/debuggerd/libdebuggerd/test/tombstone_test.cpp b/debuggerd/libdebuggerd/test/tombstone_test.cpp
index 1e3a10f..421ce43 100644
--- a/debuggerd/libdebuggerd/test/tombstone_test.cpp
+++ b/debuggerd/libdebuggerd/test/tombstone_test.cpp
@@ -437,9 +437,9 @@
map_mock_->AddMap(map);
#if defined(__LP64__)
- uintptr_t addr = 0x12345a534040UL;
+ uint64_t addr = 0x12345a534040UL;
#else
- uintptr_t addr = 0xf534040UL;
+ uint64_t addr = 0xf534040UL;
#endif
dump_all_maps(&log_, map_mock_.get(), nullptr, addr);
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index 89a125b..7d85602 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -127,7 +127,7 @@
}
static void dump_stack_segment(log_t* log, BacktraceMap* backtrace_map, Memory* process_memory,
- uintptr_t* sp, size_t words, int label) {
+ uint64_t* sp, size_t words, int label) {
// Read the data all at once.
word_t stack_data[words];
@@ -144,18 +144,18 @@
} else {
line += " ";
}
- line += StringPrintf("%" PRIPTR " %" PRIPTR, *sp, stack_data[i]);
+ line += StringPrintf("%" PRIPTR " %" PRIPTR, *sp, static_cast<uint64_t>(stack_data[i]));
backtrace_map_t map;
backtrace_map->FillIn(stack_data[i], &map);
if (BacktraceMap::IsValid(map) && !map.name.empty()) {
line += " " + map.name;
- uintptr_t offset = 0;
+ uint64_t offset = 0;
std::string func_name = backtrace_map->GetFunctionName(stack_data[i], &offset);
if (!func_name.empty()) {
line += " (" + func_name;
if (offset) {
- line += StringPrintf("+%" PRIuPTR, offset);
+ line += StringPrintf("+%" PRIu64, offset);
}
line += ')';
}
@@ -185,7 +185,7 @@
first--;
// Dump a few words before the first frame.
- word_t sp = frames[first].sp - STACK_WORDS * sizeof(word_t);
+ uint64_t sp = frames[first].sp - STACK_WORDS * sizeof(word_t);
dump_stack_segment(log, backtrace_map, process_memory, &sp, STACK_WORDS, -1);
// Dump a few words from all successive frames.
@@ -213,19 +213,19 @@
}
}
-static std::string get_addr_string(uintptr_t addr) {
+static std::string get_addr_string(uint64_t addr) {
std::string addr_str;
#if defined(__LP64__)
addr_str = StringPrintf("%08x'%08x",
static_cast<uint32_t>(addr >> 32),
static_cast<uint32_t>(addr & 0xffffffff));
#else
- addr_str = StringPrintf("%08x", addr);
+ addr_str = StringPrintf("%08x", static_cast<uint32_t>(addr));
#endif
return addr_str;
}
-static void dump_abort_message(log_t* log, Memory* process_memory, uintptr_t address) {
+static void dump_abort_message(log_t* log, Memory* process_memory, uint64_t address) {
if (address == 0) {
return;
}
@@ -251,7 +251,7 @@
_LOG(log, logtype::HEADER, "Abort message: '%s'\n", msg);
}
-static void dump_all_maps(log_t* log, BacktraceMap* map, Memory* process_memory, uintptr_t addr) {
+static void dump_all_maps(log_t* log, BacktraceMap* map, Memory* process_memory, uint64_t addr) {
bool print_fault_address_marker = addr;
ScopedBacktraceMapIteratorLock lock(map);
@@ -301,7 +301,7 @@
} else {
line += '-';
}
- line += StringPrintf(" %8" PRIxPTR " %8" PRIxPTR, entry->offset, entry->end - entry->start);
+ line += StringPrintf(" %8" PRIx64 " %8" PRIx64, entry->offset, entry->end - entry->start);
bool space_needed = true;
if (entry->name.length() > 0) {
space_needed = false;
@@ -315,7 +315,7 @@
if (space_needed) {
line += ' ';
}
- line += StringPrintf(" (load bias 0x%" PRIxPTR ")", entry->load_bias);
+ line += StringPrintf(" (load bias 0x%" PRIx64 ")", entry->load_bias);
}
_LOG(log, logtype::MAPS, "%s\n", line.c_str());
}
@@ -335,9 +335,9 @@
const std::vector<std::pair<std::string, uint64_t>>& registers) {
std::string output;
for (auto& [name, value] : registers) {
- output += android::base::StringPrintf(" %-3s %0*" PRIxPTR, name.c_str(),
+ output += android::base::StringPrintf(" %-3s %0*" PRIx64, name.c_str(),
static_cast<int>(2 * sizeof(void*)),
- static_cast<uintptr_t>(value));
+ static_cast<uint64_t>(value));
}
_LOG(log, logtype::REGISTERS, " %s\n", output.c_str());
@@ -389,7 +389,7 @@
}
static bool dump_thread(log_t* log, BacktraceMap* map, Memory* process_memory,
- const ThreadInfo& thread_info, uintptr_t abort_msg_address,
+ const ThreadInfo& thread_info, uint64_t abort_msg_address,
bool primary_thread) {
UNUSED(process_memory);
log->current_tid = thread_info.tid;
@@ -425,10 +425,10 @@
if (primary_thread) {
dump_memory_and_code(log, process_memory, thread_info.registers.get());
if (map) {
- uintptr_t addr = 0;
+ uint64_t addr = 0;
siginfo_t* si = thread_info.siginfo;
if (signal_has_si_addr(si->si_signo, si->si_code)) {
- addr = reinterpret_cast<uintptr_t>(si->si_addr);
+ addr = reinterpret_cast<uint64_t>(si->si_addr);
}
dump_all_maps(log, map, process_memory, addr);
}
@@ -572,7 +572,7 @@
dump_log_file(log, pid, "main", tail);
}
-void engrave_tombstone_ucontext(int tombstone_fd, uintptr_t abort_msg_address, siginfo_t* siginfo,
+void engrave_tombstone_ucontext(int tombstone_fd, uint64_t abort_msg_address, siginfo_t* siginfo,
ucontext_t* ucontext) {
pid_t pid = getpid();
pid_t tid = gettid();
@@ -614,7 +614,7 @@
void engrave_tombstone(unique_fd output_fd, BacktraceMap* map, Memory* process_memory,
const std::map<pid_t, ThreadInfo>& threads, pid_t target_thread,
- uintptr_t abort_msg_address, OpenFilesList* open_files,
+ uint64_t abort_msg_address, OpenFilesList* open_files,
std::string* amfd_data) {
// don't copy log messages to tombstone unless this is a dev device
bool want_logs = android::base::GetBoolProperty("ro.debuggable", false);
diff --git a/debuggerd/libdebuggerd/utility.cpp b/debuggerd/libdebuggerd/utility.cpp
index 247d806..3ac98f5 100644
--- a/debuggerd/libdebuggerd/utility.cpp
+++ b/debuggerd/libdebuggerd/utility.cpp
@@ -124,7 +124,7 @@
#define MEMORY_BYTES_TO_DUMP 256
#define MEMORY_BYTES_PER_LINE 16
-void dump_memory(log_t* log, unwindstack::Memory* memory, uintptr_t addr, const char* fmt, ...) {
+void dump_memory(log_t* log, unwindstack::Memory* memory, uint64_t addr, const char* fmt, ...) {
std::string log_msg;
va_list ap;
va_start(ap, fmt);
@@ -159,7 +159,7 @@
bytes &= ~(sizeof(uintptr_t) - 1);
}
- uintptr_t start = 0;
+ uint64_t start = 0;
bool skip_2nd_read = false;
if (bytes == 0) {
// In this case, we might want to try another read at the beginning of
@@ -206,7 +206,7 @@
std::string ascii;
for (size_t i = 0; i < MEMORY_BYTES_PER_LINE / sizeof(uintptr_t); i++) {
if (current >= start && current + sizeof(uintptr_t) <= total_bytes) {
- android::base::StringAppendF(&logline, " %" PRIPTR, *data_ptr);
+ android::base::StringAppendF(&logline, " %" PRIPTR, static_cast<uint64_t>(*data_ptr));
// Fill out the ascii string from the data.
uint8_t* ptr = reinterpret_cast<uint8_t*>(data_ptr);
diff --git a/debuggerd/seccomp_policy/crash_dump.arm.policy b/debuggerd/seccomp_policy/crash_dump.arm.policy
new file mode 100644
index 0000000..c64e288
--- /dev/null
+++ b/debuggerd/seccomp_policy/crash_dump.arm.policy
@@ -0,0 +1,37 @@
+read: 1
+write: 1
+exit: 1
+rt_sigreturn: 1
+sigreturn: 1
+exit_group: 1
+clock_gettime: 1
+gettimeofday: 1
+futex: 1
+getrandom: 1
+getpid: 1
+gettid: 1
+ppoll: 1
+pipe2: 1
+openat: 1
+dup: 1
+close: 1
+lseek: 1
+getdents64: 1
+faccessat: 1
+recvmsg: 1
+process_vm_readv: 1
+tgkill: 1
+rt_sigprocmask: 1
+rt_tgsigqueueinfo: 1
+prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == 0x53564d41
+madvise: 1
+mprotect: arg2 in PROT_READ|PROT_WRITE
+munmap: 1
+getuid32: 1
+fstat64: 1
+mmap2: arg2 in PROT_READ|PROT_WRITE
+sigaction: 1
+geteuid32: 1
+getgid32: 1
+getegid32: 1
+getgroups32: 1
diff --git a/debuggerd/seccomp_policy/crash_dump.arm64.policy b/debuggerd/seccomp_policy/crash_dump.arm64.policy
new file mode 100644
index 0000000..0c689bb
--- /dev/null
+++ b/debuggerd/seccomp_policy/crash_dump.arm64.policy
@@ -0,0 +1,36 @@
+read: 1
+write: 1
+exit: 1
+rt_sigreturn: 1
+exit_group: 1
+clock_gettime: 1
+gettimeofday: 1
+futex: 1
+getrandom: 1
+getpid: 1
+gettid: 1
+ppoll: 1
+pipe2: 1
+openat: 1
+dup: 1
+close: 1
+lseek: 1
+getdents64: 1
+faccessat: 1
+recvmsg: 1
+process_vm_readv: 1
+tgkill: 1
+rt_sigprocmask: 1
+rt_tgsigqueueinfo: 1
+prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == 0x53564d41
+madvise: 1
+mprotect: arg2 in PROT_READ|PROT_WRITE
+munmap: 1
+getuid: 1
+fstat: 1
+mmap: arg2 in PROT_READ|PROT_WRITE
+rt_sigaction: 1
+geteuid: 1
+getgid: 1
+getegid: 1
+getgroups: 1
diff --git a/debuggerd/seccomp_policy/crash_dump.policy.def b/debuggerd/seccomp_policy/crash_dump.policy.def
new file mode 100644
index 0000000..dadffac
--- /dev/null
+++ b/debuggerd/seccomp_policy/crash_dump.policy.def
@@ -0,0 +1,64 @@
+// SECCOMP_MODE_STRICT
+read: 1
+write: 1
+exit: 1
+rt_sigreturn: 1
+#if !defined(__LP64__)
+sigreturn: 1
+#endif
+
+exit_group: 1
+clock_gettime: 1
+gettimeofday: 1
+futex: 1
+getrandom: 1
+getpid: 1
+gettid: 1
+
+ppoll: 1
+pipe2: 1
+openat: 1
+dup: 1
+close: 1
+lseek: 1
+getdents64: 1
+faccessat: 1
+recvmsg: 1
+
+process_vm_readv: 1
+
+tgkill: 1
+rt_sigprocmask: 1
+rt_tgsigqueueinfo: 1
+
+#define PR_SET_VMA 0x53564d41
+prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == PR_SET_VMA
+
+madvise: 1
+mprotect: arg2 in PROT_READ|PROT_WRITE
+munmap: 1
+
+#if defined(__LP64__)
+getuid: 1
+fstat: 1
+mmap: arg2 in PROT_READ|PROT_WRITE
+rt_sigaction: 1
+#else
+getuid32: 1
+fstat64: 1
+mmap2: arg2 in PROT_READ|PROT_WRITE
+sigaction: 1
+#endif
+
+// Needed for logging.
+#if defined(__LP64__)
+geteuid: 1
+getgid: 1
+getegid: 1
+getgroups: 1
+#else
+geteuid32: 1
+getgid32: 1
+getegid32: 1
+getgroups32: 1
+#endif
diff --git a/debuggerd/seccomp_policy/crash_dump.x86.policy b/debuggerd/seccomp_policy/crash_dump.x86.policy
new file mode 100644
index 0000000..c64e288
--- /dev/null
+++ b/debuggerd/seccomp_policy/crash_dump.x86.policy
@@ -0,0 +1,37 @@
+read: 1
+write: 1
+exit: 1
+rt_sigreturn: 1
+sigreturn: 1
+exit_group: 1
+clock_gettime: 1
+gettimeofday: 1
+futex: 1
+getrandom: 1
+getpid: 1
+gettid: 1
+ppoll: 1
+pipe2: 1
+openat: 1
+dup: 1
+close: 1
+lseek: 1
+getdents64: 1
+faccessat: 1
+recvmsg: 1
+process_vm_readv: 1
+tgkill: 1
+rt_sigprocmask: 1
+rt_tgsigqueueinfo: 1
+prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == 0x53564d41
+madvise: 1
+mprotect: arg2 in PROT_READ|PROT_WRITE
+munmap: 1
+getuid32: 1
+fstat64: 1
+mmap2: arg2 in PROT_READ|PROT_WRITE
+sigaction: 1
+geteuid32: 1
+getgid32: 1
+getegid32: 1
+getgroups32: 1
diff --git a/debuggerd/seccomp_policy/crash_dump.x86_64.policy b/debuggerd/seccomp_policy/crash_dump.x86_64.policy
new file mode 100644
index 0000000..0c689bb
--- /dev/null
+++ b/debuggerd/seccomp_policy/crash_dump.x86_64.policy
@@ -0,0 +1,36 @@
+read: 1
+write: 1
+exit: 1
+rt_sigreturn: 1
+exit_group: 1
+clock_gettime: 1
+gettimeofday: 1
+futex: 1
+getrandom: 1
+getpid: 1
+gettid: 1
+ppoll: 1
+pipe2: 1
+openat: 1
+dup: 1
+close: 1
+lseek: 1
+getdents64: 1
+faccessat: 1
+recvmsg: 1
+process_vm_readv: 1
+tgkill: 1
+rt_sigprocmask: 1
+rt_tgsigqueueinfo: 1
+prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == 0x53564d41
+madvise: 1
+mprotect: arg2 in PROT_READ|PROT_WRITE
+munmap: 1
+getuid: 1
+fstat: 1
+mmap: arg2 in PROT_READ|PROT_WRITE
+rt_sigaction: 1
+geteuid: 1
+getgid: 1
+getegid: 1
+getgroups: 1
diff --git a/debuggerd/seccomp_policy/generate.sh b/debuggerd/seccomp_policy/generate.sh
new file mode 100755
index 0000000..8c58b05
--- /dev/null
+++ b/debuggerd/seccomp_policy/generate.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+set -ex
+
+cd "$(dirname "$0")"
+CPP='cpp -undef -E -P crash_dump.policy.def'
+$CPP -D__arm__ -o crash_dump.arm.policy
+$CPP -D__aarch64__ -D__LP64__ -o crash_dump.arm64.policy
+$CPP -D__i386__ -o crash_dump.x86.policy
+$CPP -D__x86_64__ -D__LP64__ -o crash_dump.x86_64.policy
diff --git a/fastboot/bootimg_utils.cpp b/fastboot/bootimg_utils.cpp
index c1028ef..62a26b3 100644
--- a/fastboot/bootimg_utils.cpp
+++ b/fastboot/bootimg_utils.cpp
@@ -28,13 +28,15 @@
#include "bootimg_utils.h"
+#include "fastboot.h"
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-void bootimg_set_cmdline(boot_img_hdr* h, const char* cmdline)
-{
- strcpy((char*) h->cmdline, cmdline);
+void bootimg_set_cmdline(boot_img_hdr* h, const char* cmdline) {
+ if (strlen(cmdline) >= sizeof(h->cmdline)) die("command line too large: %zu", strlen(cmdline));
+ strcpy(reinterpret_cast<char*>(h->cmdline), cmdline);
}
boot_img_hdr* mkbootimg(void* kernel, int64_t kernel_size, off_t kernel_offset,
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 6175f59..536d64e 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -447,8 +447,11 @@
if (kdata == nullptr) die("cannot load '%s': %s", kernel.c_str(), strerror(errno));
// Is this actually a boot image?
+ if (ksize < static_cast<int64_t>(sizeof(boot_img_hdr))) {
+ die("cannot load '%s': too short", kernel.c_str());
+ }
if (!memcmp(kdata, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
- if (cmdline) bootimg_set_cmdline((boot_img_hdr*) kdata, cmdline);
+ if (cmdline) bootimg_set_cmdline(reinterpret_cast<boot_img_hdr*>(kdata), cmdline);
if (!ramdisk.empty()) die("cannot boot a boot.img *and* ramdisk");
diff --git a/init/Android.bp b/init/Android.bp
index 2fea359..6c80ee6 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -58,6 +58,34 @@
cppflags: ["-DUSER_MODE_LINUX"],
}
},
+ static_libs: [
+ "libbootloader_message",
+ "libfs_mgr",
+ "libfec",
+ "libfec_rs",
+ "libhidl-gen-utils",
+ "libsquashfs_utils",
+ "liblogwrap",
+ "libext4_utils",
+ "libcutils",
+ "libbase",
+ "libc",
+ "libseccomp_policy",
+ "libselinux",
+ "liblog",
+ "libcrypto_utils",
+ "libcrypto",
+ "libc++_static",
+ "libdl",
+ "libsparse",
+ "libz",
+ "libprocessgroup",
+ "libavb",
+ "libkeyutils",
+ "libprotobuf-cpp-lite",
+ "libpropertyinfoserializer",
+ "libpropertyinfoparser",
+ ],
}
cc_library_static {
@@ -65,39 +93,38 @@
defaults: ["init_defaults"],
srcs: [
"action.cpp",
+ "bootchart.cpp",
+ "builtins.cpp",
"capabilities.cpp",
"descriptors.cpp",
"devices.cpp",
"firmware_handler.cpp",
"import_parser.cpp",
+ "init.cpp",
+ "init_first_stage.cpp",
+ "keychords.cpp",
"log.cpp",
"parser.cpp",
"persistent_properties.cpp",
"persistent_properties.proto",
"property_service.cpp",
+ "property_type.cpp",
+ "reboot.cpp",
"security.cpp",
"selinux.cpp",
"service.cpp",
+ "sigchld_handler.cpp",
"subcontext.cpp",
"subcontext.proto",
"rlimit_parser.cpp",
"tokenizer.cpp",
"uevent_listener.cpp",
+ "ueventd.cpp",
"ueventd_parser.cpp",
"util.cpp",
+ "watchdogd.cpp",
],
whole_static_libs: ["libcap"],
- static_libs: [
- "libbase",
- "libhidl-gen-utils",
- "libselinux",
- "liblog",
- "libprocessgroup",
- "libfs_mgr",
- "libprotobuf-cpp-lite",
- "libpropertyinfoserializer",
- "libpropertyinfoparser",
- ],
include_dirs: [
"system/core/mkbootimg",
],
@@ -124,42 +151,7 @@
"make_f2fs",
],
static_executable: true,
- srcs: [
- "bootchart.cpp",
- "builtins.cpp",
- "init.cpp",
- "init_first_stage.cpp",
- "keychords.cpp",
- "reboot.cpp",
- "sigchld_handler.cpp",
- "ueventd.cpp",
- "watchdogd.cpp",
- ],
- static_libs: [
- "libinit",
- "libbootloader_message",
- "libfs_mgr",
- "libfec",
- "libfec_rs",
- "libhidl-gen-utils",
- "libsquashfs_utils",
- "liblogwrap",
- "libext4_utils",
- "libcutils",
- "libbase",
- "libc",
- "libselinux",
- "liblog",
- "libcrypto_utils",
- "libcrypto",
- "libc++_static",
- "libdl",
- "libsparse",
- "libz",
- "libprocessgroup",
- "libavb",
- "libkeyutils",
- ],
+ srcs: ["main.cpp"],
symlinks: [
"sbin/ueventd",
"sbin/watchdogd",
@@ -173,11 +165,13 @@
cc_test {
name: "init_tests",
defaults: ["init_defaults"],
+ static_executable: true,
srcs: [
"devices_test.cpp",
"init_test.cpp",
"persistent_properties_test.cpp",
"property_service_test.cpp",
+ "property_type_test.cpp",
"result_test.cpp",
"rlimit_parser_test.cpp",
"service_test.cpp",
@@ -185,36 +179,17 @@
"ueventd_test.cpp",
"util_test.cpp",
],
- shared_libs: [
- "libbase",
- "libcutils",
- ],
- static_libs: [
- "libinit",
- "libhidl-gen-utils",
- "libselinux",
- "libcrypto",
- "libprotobuf-cpp-lite",
- "libpropertyinfoparser",
- ],
+ static_libs: ["libinit"],
}
cc_benchmark {
name: "init_benchmarks",
+ static_executable: true,
defaults: ["init_defaults"],
srcs: [
"subcontext_benchmark.cpp",
],
- shared_libs: [
- "libbase",
- "libcutils",
- ],
- static_libs: [
- "libinit",
- "libselinux",
- "libcrypto",
- "libprotobuf-cpp-lite",
- ],
+ static_libs: ["libinit"],
}
subdirs = ["*"]
diff --git a/init/Android.mk b/init/Android.mk
index 5239366..c4a6a50 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -41,16 +41,7 @@
include $(CLEAR_VARS)
LOCAL_CPPFLAGS := $(init_cflags)
-LOCAL_SRC_FILES:= \
- bootchart.cpp \
- builtins.cpp \
- init.cpp \
- init_first_stage.cpp \
- keychords.cpp \
- reboot.cpp \
- sigchld_handler.cpp \
- ueventd.cpp \
- watchdogd.cpp \
+LOCAL_SRC_FILES := main.cpp
LOCAL_MODULE:= init
diff --git a/init/action.cpp b/init/action.cpp
index 16ecdcd..ba03e66 100644
--- a/init/action.cpp
+++ b/init/action.cpp
@@ -21,6 +21,7 @@
#include <android-base/properties.h>
#include <android-base/strings.h>
+#include "stable_properties.h"
#include "util.h"
using android::base::Join;
@@ -134,6 +135,25 @@
}
}
+static bool IsActionableProperty(Subcontext* subcontext, const std::string& prop_name) {
+ static bool enabled =
+ android::base::GetBoolProperty("ro.actionable_compatible_property.enabled", false);
+
+ if (subcontext == nullptr || !enabled) {
+ return true;
+ }
+
+ if (kExportedActionableProperties.count(prop_name) == 1) {
+ return true;
+ }
+ for (const auto& prefix : kPartnerPrefixes) {
+ if (android::base::StartsWith(prop_name, prefix)) {
+ return true;
+ }
+ }
+ return false;
+}
+
Result<Success> Action::ParsePropertyTrigger(const std::string& trigger) {
const static std::string prop_str("property:");
std::string prop_name(trigger.substr(prop_str.length()));
@@ -145,6 +165,10 @@
std::string prop_value(prop_name.substr(equal_pos + 1));
prop_name.erase(equal_pos);
+ if (!IsActionableProperty(subcontext_, prop_name)) {
+ return Error() << "unexported property tigger found: " << prop_name;
+ }
+
if (auto [it, inserted] = property_triggers_.emplace(prop_name, prop_value); !inserted) {
return Error() << "multiple property triggers found for same property";
}
diff --git a/init/init.cpp b/init/init.cpp
index 571da7c..95f272b 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -746,7 +746,3 @@
} // namespace init
} // namespace android
-
-int main(int argc, char** argv) {
- android::init::main(argc, argv);
-}
diff --git a/init/init.h b/init/init.h
index b757c1d..ff7bdeb 100644
--- a/init/init.h
+++ b/init/init.h
@@ -47,6 +47,8 @@
void ResetWaitForProp();
+int main(int argc, char** argv);
+
} // namespace init
} // namespace android
diff --git a/init/main.cpp b/init/main.cpp
new file mode 100644
index 0000000..9ed451b
--- /dev/null
+++ b/init/main.cpp
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2018 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 "init.h"
+
+int main(int argc, char** argv) {
+ android::init::main(argc, argv);
+}
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 7aa94b0..79f7f25 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -58,6 +58,7 @@
#include "init.h"
#include "persistent_properties.h"
+#include "property_type.h"
#include "util.h"
using android::base::ReadFileToString;
@@ -95,14 +96,9 @@
LOG(FATAL) << "Failed to load serialized property info file";
}
}
-static bool check_mac_perms(const std::string& name, char* sctx, struct ucred* cr) {
- if (!sctx) {
- return false;
- }
-
- const char* target_context = nullptr;
- property_info_area->GetPropertyInfo(name.c_str(), &target_context, nullptr);
- if (target_context == nullptr) {
+static bool CheckMacPerms(const std::string& name, const char* target_context,
+ const char* source_context, struct ucred* cr) {
+ if (!target_context || !source_context) {
return false;
}
@@ -111,29 +107,12 @@
audit_data.name = name.c_str();
audit_data.cr = cr;
- bool has_access =
- (selinux_check_access(sctx, target_context, "property_service", "set", &audit_data) == 0);
+ bool has_access = (selinux_check_access(source_context, target_context, "property_service",
+ "set", &audit_data) == 0);
return has_access;
}
-static int check_control_mac_perms(const char *name, char *sctx, struct ucred *cr)
-{
- /*
- * Create a name prefix out of ctl.<service name>
- * The new prefix allows the use of the existing
- * property service backend labeling while avoiding
- * mislabels based on true property prefixes.
- */
- char ctl_name[PROP_VALUE_MAX+4];
- int ret = snprintf(ctl_name, sizeof(ctl_name), "ctl.%s", name);
-
- if (ret < 0 || (size_t) ret >= sizeof(ctl_name))
- return 0;
-
- return check_mac_perms(ctl_name, sctx, cr);
-}
-
bool is_legal_property_name(const std::string& name) {
size_t namelen = name.size();
@@ -422,52 +401,70 @@
struct ucred cr = socket.cred();
char* source_ctx = nullptr;
getpeercon(socket.socket(), &source_ctx);
+ std::string source_context = source_ctx;
+ freecon(source_ctx);
if (StartsWith(name, "ctl.")) {
- if (check_control_mac_perms(value.c_str(), source_ctx, &cr)) {
+ // ctl. properties have their name ctl.<action> and their value is the name of the service to
+ // apply that action to. Permissions for these actions are based on the service, so we must
+ // create a fake name of ctl.<service> to check permissions.
+ auto control_string = "ctl." + value;
+ const char* target_context = nullptr;
+ const char* type = nullptr;
+ property_info_area->GetPropertyInfo(control_string.c_str(), &target_context, &type);
+ if (!CheckMacPerms(control_string, target_context, source_context.c_str(), &cr)) {
+ LOG(ERROR) << "sys_prop(" << cmd_name << "): Unable to " << (name.c_str() + 4)
+ << " service ctl [" << value << "]"
+ << " uid:" << cr.uid << " gid:" << cr.gid << " pid:" << cr.pid;
+ if (!legacy_protocol) {
+ socket.SendUint32(PROP_ERROR_HANDLE_CONTROL_MESSAGE);
+ }
+ return;
+ }
+
handle_control_message(name.c_str() + 4, value.c_str());
if (!legacy_protocol) {
- socket.SendUint32(PROP_SUCCESS);
+ socket.SendUint32(PROP_SUCCESS);
}
- } else {
- LOG(ERROR) << "sys_prop(" << cmd_name << "): Unable to " << (name.c_str() + 4)
- << " service ctl [" << value << "]"
- << " uid:" << cr.uid
- << " gid:" << cr.gid
- << " pid:" << cr.pid;
- if (!legacy_protocol) {
- socket.SendUint32(PROP_ERROR_HANDLE_CONTROL_MESSAGE);
- }
- }
} else {
- if (check_mac_perms(name, source_ctx, &cr)) {
+ const char* target_context = nullptr;
+ const char* type = nullptr;
+ property_info_area->GetPropertyInfo(name.c_str(), &target_context, &type);
+ if (!CheckMacPerms(name, target_context, source_context.c_str(), &cr)) {
+ LOG(ERROR) << "sys_prop(" << cmd_name << "): permission denied uid:" << cr.uid
+ << " name:" << name;
+ if (!legacy_protocol) {
+ socket.SendUint32(PROP_ERROR_PERMISSION_DENIED);
+ }
+ return;
+ }
+ if (type == nullptr || !CheckType(type, value)) {
+ LOG(ERROR) << "sys_prop(" << cmd_name << "): type check failed, type: '"
+ << (type ?: "(null)") << "' value: '" << value << "'";
+ if (!legacy_protocol) {
+ socket.SendUint32(PROP_ERROR_INVALID_VALUE);
+ }
+ return;
+ }
// sys.powerctl is a special property that is used to make the device reboot. We want to log
// any process that sets this property to be able to accurately blame the cause of a shutdown.
if (name == "sys.powerctl") {
- std::string cmdline_path = StringPrintf("proc/%d/cmdline", cr.pid);
- std::string process_cmdline;
- std::string process_log_string;
- if (ReadFileToString(cmdline_path, &process_cmdline)) {
- // Since cmdline is null deliminated, .c_str() conveniently gives us just the process path.
- process_log_string = StringPrintf(" (%s)", process_cmdline.c_str());
- }
- LOG(INFO) << "Received sys.powerctl='" << value << "' from pid: " << cr.pid
- << process_log_string;
+ std::string cmdline_path = StringPrintf("proc/%d/cmdline", cr.pid);
+ std::string process_cmdline;
+ std::string process_log_string;
+ if (ReadFileToString(cmdline_path, &process_cmdline)) {
+ // Since cmdline is null deliminated, .c_str() conveniently gives us just the process path.
+ process_log_string = StringPrintf(" (%s)", process_cmdline.c_str());
+ }
+ LOG(INFO) << "Received sys.powerctl='" << value << "' from pid: " << cr.pid
+ << process_log_string;
}
uint32_t result = property_set(name, value);
if (!legacy_protocol) {
- socket.SendUint32(result);
+ socket.SendUint32(result);
}
- } else {
- LOG(ERROR) << "sys_prop(" << cmd_name << "): permission denied uid:" << cr.uid << " name:" << name;
- if (!legacy_protocol) {
- socket.SendUint32(PROP_ERROR_PERMISSION_DENIED);
- }
- }
}
-
- freecon(source_ctx);
}
static void handle_property_set_fd() {
@@ -764,9 +761,10 @@
}
LoadPropertyInfoFromFile("/nonplat_property_contexts", &property_infos);
}
+
auto serialized_contexts = std::string();
auto error = std::string();
- if (!BuildTrie(property_infos, "u:object_r:default_prop:s0", "\\s*", &serialized_contexts,
+ if (!BuildTrie(property_infos, "u:object_r:default_prop:s0", "string", &serialized_contexts,
&error)) {
LOG(ERROR) << "Unable to serialize property contexts: " << error;
return;
diff --git a/init/property_type.cpp b/init/property_type.cpp
new file mode 100644
index 0000000..249b12b
--- /dev/null
+++ b/init/property_type.cpp
@@ -0,0 +1,81 @@
+//
+// 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 "property_type.h"
+
+#include <android-base/parsedouble.h>
+#include <android-base/parseint.h>
+#include <android-base/strings.h>
+
+using android::base::ParseDouble;
+using android::base::ParseInt;
+using android::base::ParseUint;
+using android::base::Split;
+
+namespace android {
+namespace init {
+
+bool CheckType(const std::string& type_string, const std::string& value) {
+ auto type_strings = Split(type_string, " ");
+ if (type_strings.empty()) {
+ return false;
+ }
+ auto type = type_strings[0];
+
+ if (type == "string") {
+ return true;
+ }
+ if (type == "bool") {
+ return value == "true" || value == "false" || value == "1" || value == "0";
+ }
+ if (type == "int") {
+ int64_t parsed;
+ return ParseInt(value, &parsed);
+ }
+ if (type == "uint") {
+ uint64_t parsed;
+ if (value.empty() || value.front() == '-') {
+ return false;
+ }
+ return ParseUint(value, &parsed);
+ }
+ if (type == "double") {
+ double parsed;
+ return ParseDouble(value.c_str(), &parsed);
+ }
+ if (type == "size") {
+ auto it = value.begin();
+ while (it != value.end() && isdigit(*it)) {
+ it++;
+ }
+ if (it == value.begin() || it == value.end() || (*it != 'g' && *it != 'k' && *it != 'm')) {
+ return false;
+ }
+ it++;
+ return it == value.end();
+ }
+ if (type == "enum") {
+ for (auto it = std::next(type_strings.begin()); it != type_strings.end(); ++it) {
+ if (*it == value) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+} // namespace init
+} // namespace android
diff --git a/init/property_type.h b/init/property_type.h
new file mode 100644
index 0000000..c889e16
--- /dev/null
+++ b/init/property_type.h
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+#ifndef _INIT_PROPERTY_TYPE_H
+#define _INIT_PROPERTY_TYPE_H
+
+#include <string>
+
+namespace android {
+namespace init {
+
+bool CheckType(const std::string& type_string, const std::string& value);
+
+} // namespace init
+} // namespace android
+
+#endif
diff --git a/init/property_type_test.cpp b/init/property_type_test.cpp
new file mode 100644
index 0000000..068bccc
--- /dev/null
+++ b/init/property_type_test.cpp
@@ -0,0 +1,95 @@
+/*
+ * 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 "property_type.h"
+
+#include <gtest/gtest.h>
+
+namespace android {
+namespace init {
+
+TEST(property_type, CheckType_string) {
+ EXPECT_TRUE(CheckType("string", ""));
+ EXPECT_TRUE(CheckType("string", "-234"));
+ EXPECT_TRUE(CheckType("string", "234"));
+ EXPECT_TRUE(CheckType("string", "true"));
+ EXPECT_TRUE(CheckType("string", "false"));
+ EXPECT_TRUE(CheckType("string", "45645634563456345634563456"));
+ EXPECT_TRUE(CheckType("string", "some other string"));
+}
+
+TEST(property_type, CheckType_int) {
+ EXPECT_FALSE(CheckType("int", ""));
+ EXPECT_FALSE(CheckType("int", "abc"));
+ EXPECT_FALSE(CheckType("int", "-abc"));
+ EXPECT_TRUE(CheckType("int", "0"));
+ EXPECT_TRUE(CheckType("int", std::to_string(std::numeric_limits<int64_t>::min())));
+ EXPECT_TRUE(CheckType("int", std::to_string(std::numeric_limits<int64_t>::max())));
+ EXPECT_TRUE(CheckType("int", "123"));
+ EXPECT_TRUE(CheckType("int", "-123"));
+}
+
+TEST(property_type, CheckType_uint) {
+ EXPECT_FALSE(CheckType("uint", ""));
+ EXPECT_FALSE(CheckType("uint", "abc"));
+ EXPECT_FALSE(CheckType("uint", "-abc"));
+ EXPECT_TRUE(CheckType("uint", "0"));
+ EXPECT_TRUE(CheckType("uint", std::to_string(std::numeric_limits<uint64_t>::max())));
+ EXPECT_TRUE(CheckType("uint", "123"));
+ EXPECT_FALSE(CheckType("uint", "-123"));
+}
+
+TEST(property_type, CheckType_double) {
+ EXPECT_FALSE(CheckType("double", ""));
+ EXPECT_FALSE(CheckType("double", "abc"));
+ EXPECT_FALSE(CheckType("double", "-abc"));
+ EXPECT_TRUE(CheckType("double", "0.0"));
+ EXPECT_TRUE(CheckType("double", std::to_string(std::numeric_limits<double>::min())));
+ EXPECT_TRUE(CheckType("double", std::to_string(std::numeric_limits<double>::max())));
+ EXPECT_TRUE(CheckType("double", "123.1"));
+ EXPECT_TRUE(CheckType("double", "-123.1"));
+}
+
+TEST(property_type, CheckType_size) {
+ EXPECT_FALSE(CheckType("size", ""));
+ EXPECT_FALSE(CheckType("size", "ab"));
+ EXPECT_FALSE(CheckType("size", "abcd"));
+ EXPECT_FALSE(CheckType("size", "0"));
+
+ EXPECT_TRUE(CheckType("size", "512g"));
+ EXPECT_TRUE(CheckType("size", "512k"));
+ EXPECT_TRUE(CheckType("size", "512m"));
+
+ EXPECT_FALSE(CheckType("size", "512gggg"));
+ EXPECT_FALSE(CheckType("size", "512mgk"));
+ EXPECT_FALSE(CheckType("size", "g"));
+ EXPECT_FALSE(CheckType("size", "m"));
+}
+
+TEST(property_type, CheckType_enum) {
+ EXPECT_FALSE(CheckType("enum abc", ""));
+ EXPECT_FALSE(CheckType("enum abc", "ab"));
+ EXPECT_FALSE(CheckType("enum abc", "abcd"));
+ EXPECT_FALSE(CheckType("enum 123 456 789", "0"));
+
+ EXPECT_TRUE(CheckType("enum abc", "abc"));
+ EXPECT_TRUE(CheckType("enum 123 456 789", "123"));
+ EXPECT_TRUE(CheckType("enum 123 456 789", "456"));
+ EXPECT_TRUE(CheckType("enum 123 456 789", "789"));
+}
+
+} // namespace init
+} // namespace android
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 21086dc..a88a42d 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -137,25 +137,12 @@
// Turn off backlight while we are performing power down cleanup activities.
static void TurnOffBacklight() {
- static constexpr char OFF[] = "0";
-
- android::base::WriteStringToFile(OFF, "/sys/class/leds/lcd-backlight/brightness");
-
- static const char backlightDir[] = "/sys/class/backlight";
- std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(backlightDir), closedir);
- if (!dir) {
+ Service* service = ServiceList::GetInstance().FindService("blank_screen");
+ if (service == nullptr) {
+ LOG(WARNING) << "cannot find blank_screen in TurnOffBacklight";
return;
}
-
- struct dirent* dp;
- while ((dp = readdir(dir.get())) != nullptr) {
- if (((dp->d_type != DT_DIR) && (dp->d_type != DT_LNK)) || (dp->d_name[0] == '.')) {
- continue;
- }
-
- std::string fileName = StringPrintf("%s/%s/brightness", backlightDir, dp->d_name);
- android::base::WriteStringToFile(OFF, fileName);
- }
+ service->Start();
}
static void ShutdownVold() {
@@ -316,8 +303,6 @@
std::vector<MountEntry> block_devices;
std::vector<MountEntry> emulated_devices;
- TurnOffBacklight(); // this part can take time. save power.
-
if (runFsck && !FindPartitionsToUmount(&block_devices, &emulated_devices, false)) {
return UMOUNT_STAT_ERROR;
}
@@ -397,6 +382,11 @@
}
}
+ // remaining operations (specifically fsck) may take a substantial duration
+ if (cmd == ANDROID_RB_POWEROFF || is_thermal_shutdown) {
+ TurnOffBacklight();
+ }
+
Service* bootAnim = ServiceList::GetInstance().FindService("bootanim");
Service* surfaceFlinger = ServiceList::GetInstance().FindService("surfaceflinger");
if (bootAnim != nullptr && surfaceFlinger != nullptr && surfaceFlinger->IsRunning()) {
diff --git a/init/stable_properties.h b/init/stable_properties.h
new file mode 100644
index 0000000..8219838
--- /dev/null
+++ b/init/stable_properties.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#ifndef _INIT_STABLE_PROPERTIES_H
+#define _INIT_STABLE_PROPERTIES_H
+
+#include <set>
+#include <string>
+
+namespace android {
+namespace init {
+
+static constexpr const char* kPartnerPrefixes[] = {
+ "init.svc.vendor.", "ro.vendor.", "persist.vendor.", "vendor.",
+ "init.svc.odm.", "ro.odm.", "persist.odm.", "odm.",
+};
+
+static const std::set<std::string> kExportedActionableProperties = {
+ "init.svc.zygote", "persist.bluetooth.btsnoopenable",
+ "persist.sys.crash_rcu", "persist.sys.zram_enabled",
+ "ro.boot.revision", "ro.bootmode",
+ "ro.build.type", "sys.boot_completed",
+ "sys.retaildemo.enabled", "sys.shutdown.requested",
+ "sys.usb.config", "sys.usb.configfs",
+ "sys.usb.ffs.mtp.ready", "sys.usb.ffs.ready",
+ "sys.user.0.ce_available", "sys.vdso",
+ "vts.native_server.on",
+};
+
+} // namespace init
+} // namespace android
+
+#endif
diff --git a/init/subcontext.h b/init/subcontext.h
index 262440d..5601b80 100644
--- a/init/subcontext.h
+++ b/init/subcontext.h
@@ -25,6 +25,7 @@
#include <android-base/unique_fd.h>
#include "builtins.h"
+#include "result.h"
#include "system/core/init/subcontext.pb.h"
namespace android {
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index 9eaeae8..d9eed76 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -50,9 +50,6 @@
"BacktracePtrace.cpp",
"thread_utils.c",
"ThreadEntry.cpp",
- "UnwindCurrent.cpp",
- "UnwindMap.cpp",
- "UnwindPtrace.cpp",
"UnwindStack.cpp",
"UnwindStackMap.cpp",
]
diff --git a/libbacktrace/Backtrace.cpp b/libbacktrace/Backtrace.cpp
index 5bb6edc..1195e5f 100644
--- a/libbacktrace/Backtrace.cpp
+++ b/libbacktrace/Backtrace.cpp
@@ -30,8 +30,6 @@
#include <demangle.h>
#include "BacktraceLog.h"
-#include "UnwindCurrent.h"
-#include "UnwindPtrace.h"
#include "UnwindStack.h"
#include "thread_utils.h"
@@ -55,7 +53,7 @@
}
}
-std::string Backtrace::GetFunctionName(uintptr_t pc, uintptr_t* offset, const backtrace_map_t* map) {
+std::string Backtrace::GetFunctionName(uint64_t pc, uint64_t* offset, const backtrace_map_t* map) {
backtrace_map_t map_value;
if (map == nullptr) {
FillInMap(pc, &map_value);
@@ -68,7 +66,7 @@
return demangle(GetFunctionNameRaw(pc, offset).c_str());
}
-bool Backtrace::VerifyReadWordArgs(uintptr_t ptr, word_t* out_value) {
+bool Backtrace::VerifyReadWordArgs(uint64_t ptr, word_t* out_value) {
if (ptr & (sizeof(word_t)-1)) {
BACK_LOGW("invalid pointer %p", reinterpret_cast<void*>(ptr));
*out_value = static_cast<word_t>(-1);
@@ -105,12 +103,12 @@
// Special handling for non-zero offset maps, we need to print that
// information.
if (frame->map.offset != 0) {
- line += " (offset " + StringPrintf("0x%" PRIxPTR, frame->map.offset) + ")";
+ line += " (offset " + StringPrintf("0x%" PRIx64, frame->map.offset) + ")";
}
if (!frame->func_name.empty()) {
line += " (" + frame->func_name;
if (frame->func_offset) {
- line += StringPrintf("+%" PRIuPTR, frame->func_offset);
+ line += StringPrintf("+%" PRIu64, frame->func_offset);
}
line += ')';
}
@@ -118,7 +116,7 @@
return line;
}
-void Backtrace::FillInMap(uintptr_t pc, backtrace_map_t* map) {
+void Backtrace::FillInMap(uint64_t pc, backtrace_map_t* map) {
if (map_ != nullptr) {
map_->FillIn(pc, map);
}
diff --git a/libbacktrace/BacktraceCurrent.cpp b/libbacktrace/BacktraceCurrent.cpp
index 474d099..d61b281 100644
--- a/libbacktrace/BacktraceCurrent.cpp
+++ b/libbacktrace/BacktraceCurrent.cpp
@@ -36,7 +36,7 @@
#include "ThreadEntry.h"
#include "thread_utils.h"
-bool BacktraceCurrent::ReadWord(uintptr_t ptr, word_t* out_value) {
+bool BacktraceCurrent::ReadWord(uint64_t ptr, word_t* out_value) {
if (!VerifyReadWordArgs(ptr, out_value)) {
return false;
}
@@ -53,7 +53,7 @@
}
}
-size_t BacktraceCurrent::Read(uintptr_t addr, uint8_t* buffer, size_t bytes) {
+size_t BacktraceCurrent::Read(uint64_t addr, uint8_t* buffer, size_t bytes) {
backtrace_map_t map;
FillInMap(addr, &map);
if (!BacktraceMap::IsValid(map) || !(map.flags & PROT_READ)) {
diff --git a/libbacktrace/BacktraceCurrent.h b/libbacktrace/BacktraceCurrent.h
index 072ffd2..60a9117 100644
--- a/libbacktrace/BacktraceCurrent.h
+++ b/libbacktrace/BacktraceCurrent.h
@@ -40,9 +40,9 @@
BacktraceCurrent(pid_t pid, pid_t tid, BacktraceMap* map) : Backtrace(pid, tid, map) {}
virtual ~BacktraceCurrent() {}
- size_t Read(uintptr_t addr, uint8_t* buffer, size_t bytes) override;
+ size_t Read(uint64_t addr, uint8_t* buffer, size_t bytes) override;
- bool ReadWord(uintptr_t ptr, word_t* out_value) override;
+ bool ReadWord(uint64_t ptr, word_t* out_value) override;
bool Unwind(size_t num_ignore_frames, ucontext_t* ucontext) override;
diff --git a/libbacktrace/BacktraceMap.cpp b/libbacktrace/BacktraceMap.cpp
index 0f1ae11..2a657b8 100644
--- a/libbacktrace/BacktraceMap.cpp
+++ b/libbacktrace/BacktraceMap.cpp
@@ -38,7 +38,7 @@
BacktraceMap::~BacktraceMap() {
}
-void BacktraceMap::FillIn(uintptr_t addr, backtrace_map_t* map) {
+void BacktraceMap::FillIn(uint64_t addr, backtrace_map_t* map) {
ScopedBacktraceMapIteratorLock lock(this);
for (auto it = begin(); it != end(); ++it) {
const backtrace_map_t* entry = *it;
diff --git a/libbacktrace/BacktraceOffline.cpp b/libbacktrace/BacktraceOffline.cpp
index 30845a2..a056716 100644
--- a/libbacktrace/BacktraceOffline.cpp
+++ b/libbacktrace/BacktraceOffline.cpp
@@ -57,7 +57,7 @@
uint64_t hdr_vaddr;
uint64_t vaddr;
uint64_t fde_table_offset;
- uintptr_t min_func_vaddr;
+ uint64_t min_func_vaddr;
std::vector<uint8_t> hdr_data;
std::vector<uint8_t> data;
};
@@ -221,8 +221,8 @@
frames_.resize(num_frames + 1);
backtrace_frame_data_t* frame = &frames_[num_frames];
frame->num = num_frames;
- frame->pc = static_cast<uintptr_t>(pc);
- frame->sp = static_cast<uintptr_t>(sp);
+ frame->pc = static_cast<uint64_t>(pc);
+ frame->sp = static_cast<uint64_t>(sp);
frame->stack_size = 0;
if (num_frames > 0) {
@@ -253,12 +253,12 @@
return true;
}
-bool BacktraceOffline::ReadWord(uintptr_t ptr, word_t* out_value) {
+bool BacktraceOffline::ReadWord(uint64_t ptr, word_t* out_value) {
size_t bytes_read = Read(ptr, reinterpret_cast<uint8_t*>(out_value), sizeof(word_t));
return bytes_read == sizeof(word_t);
}
-size_t BacktraceOffline::Read(uintptr_t addr, uint8_t* buffer, size_t bytes) {
+size_t BacktraceOffline::Read(uint64_t addr, uint8_t* buffer, size_t bytes) {
// Normally, libunwind needs stack information and call frame information to do remote unwinding.
// If call frame information is stored in .debug_frame, libunwind can read it from file
// by itself. If call frame information is stored in .eh_frame, we need to provide data in
@@ -386,9 +386,8 @@
proc_info->start_ip = *it;
proc_info->format = UNW_INFO_FORMAT_ARM_EXIDX;
proc_info->unwind_info = reinterpret_cast<void*>(
- static_cast<uintptr_t>(index * sizeof(ArmIdxEntry) +
- debug_frame->arm_exidx.exidx_vaddr +
- debug_frame->min_vaddr));
+ static_cast<uint64_t>(index * sizeof(ArmIdxEntry) + debug_frame->arm_exidx.exidx_vaddr +
+ debug_frame->min_vaddr));
eh_frame_hdr_space_.Clear();
eh_frame_space_.Clear();
// Prepare arm_exidx space and arm_extab space.
@@ -595,7 +594,7 @@
return result;
}
-std::string BacktraceOffline::GetFunctionNameRaw(uintptr_t, uintptr_t* offset) {
+std::string BacktraceOffline::GetFunctionNameRaw(uint64_t, uint64_t* offset) {
// We don't have enough information to support this. And it is expensive.
*offset = 0;
return "";
diff --git a/libbacktrace/BacktraceOffline.h b/libbacktrace/BacktraceOffline.h
index fcde379..e028cd8 100644
--- a/libbacktrace/BacktraceOffline.h
+++ b/libbacktrace/BacktraceOffline.h
@@ -57,9 +57,9 @@
bool Unwind(size_t num_ignore_frames, ucontext_t* context) override;
- bool ReadWord(uintptr_t ptr, word_t* out_value) override;
+ bool ReadWord(uint64_t ptr, word_t* out_value) override;
- size_t Read(uintptr_t addr, uint8_t* buffer, size_t bytes) override;
+ size_t Read(uint64_t addr, uint8_t* buffer, size_t bytes) override;
bool FindProcInfo(unw_addr_space_t addr_space, uint64_t ip, unw_proc_info_t* proc_info,
int need_unwind_info);
@@ -67,7 +67,7 @@
bool ReadReg(size_t reg_index, uint64_t* value);
protected:
- std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) override;
+ std::string GetFunctionNameRaw(uint64_t pc, uint64_t* offset) override;
DebugFrameInfo* GetDebugFrameInFile(const std::string& filename);
bool cache_file_;
diff --git a/libbacktrace/BacktracePtrace.cpp b/libbacktrace/BacktracePtrace.cpp
index fd8b713..bf6b16f 100644
--- a/libbacktrace/BacktracePtrace.cpp
+++ b/libbacktrace/BacktracePtrace.cpp
@@ -31,7 +31,7 @@
#include "thread_utils.h"
#if !defined(__APPLE__)
-static bool PtraceRead(pid_t tid, uintptr_t addr, word_t* out_value) {
+static bool PtraceRead(pid_t tid, uint64_t addr, word_t* out_value) {
// ptrace() returns -1 and sets errno when the operation fails.
// To disambiguate -1 from a valid result, we clear errno beforehand.
errno = 0;
@@ -43,7 +43,7 @@
}
#endif
-bool BacktracePtrace::ReadWord(uintptr_t ptr, word_t* out_value) {
+bool BacktracePtrace::ReadWord(uint64_t ptr, word_t* out_value) {
#if defined(__APPLE__)
BACK_LOGW("MacOS does not support reading from another pid.");
return false;
@@ -62,7 +62,7 @@
#endif
}
-size_t BacktracePtrace::Read(uintptr_t addr, uint8_t* buffer, size_t bytes) {
+size_t BacktracePtrace::Read(uint64_t addr, uint8_t* buffer, size_t bytes) {
#if defined(__APPLE__)
BACK_LOGW("MacOS does not support reading from another pid.");
return 0;
diff --git a/libbacktrace/BacktracePtrace.h b/libbacktrace/BacktracePtrace.h
index d110b48..1ae3adf 100644
--- a/libbacktrace/BacktracePtrace.h
+++ b/libbacktrace/BacktracePtrace.h
@@ -29,9 +29,9 @@
BacktracePtrace(pid_t pid, pid_t tid, BacktraceMap* map) : Backtrace(pid, tid, map) {}
virtual ~BacktracePtrace() {}
- size_t Read(uintptr_t addr, uint8_t* buffer, size_t bytes) override;
+ size_t Read(uint64_t addr, uint8_t* buffer, size_t bytes) override;
- bool ReadWord(uintptr_t ptr, word_t* out_value) override;
+ bool ReadWord(uint64_t ptr, word_t* out_value) override;
};
#endif // _LIBBACKTRACE_BACKTRACE_PTRACE_H
diff --git a/libbacktrace/UnwindCurrent.cpp b/libbacktrace/UnwindCurrent.cpp
deleted file mode 100644
index 3ccf13c..0000000
--- a/libbacktrace/UnwindCurrent.cpp
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright (C) 2013 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 <ucontext.h>
-
-#include <memory>
-#include <string>
-
-#define UNW_LOCAL_ONLY
-#include <libunwind.h>
-
-#include <android-base/logging.h>
-#include <backtrace/Backtrace.h>
-
-#include "BacktraceLog.h"
-#include "UnwindCurrent.h"
-
-std::string UnwindCurrent::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
- if (!initialized_) {
- // If init local is not called, then trying to get a function name will
- // fail, so try to initialize first.
- std::unique_ptr<unw_cursor_t> cursor(new unw_cursor_t);
- if (unw_init_local(cursor.get(), &context_) < 0) {
- return "";
- }
- initialized_ = true;
- }
-
- *offset = 0;
- char buf[512];
- unw_word_t value;
- if (unw_get_proc_name_by_ip(unw_local_addr_space, pc, buf, sizeof(buf),
- &value, &context_) >= 0 && buf[0] != '\0') {
- *offset = static_cast<uintptr_t>(value);
- return buf;
- }
- return "";
-}
-
-void UnwindCurrent::GetUnwContextFromUcontext(const ucontext_t* ucontext) {
- unw_tdep_context_t* unw_context = reinterpret_cast<unw_tdep_context_t*>(&context_);
-
-#if defined(__arm__)
- unw_context->regs[0] = ucontext->uc_mcontext.arm_r0;
- unw_context->regs[1] = ucontext->uc_mcontext.arm_r1;
- unw_context->regs[2] = ucontext->uc_mcontext.arm_r2;
- unw_context->regs[3] = ucontext->uc_mcontext.arm_r3;
- unw_context->regs[4] = ucontext->uc_mcontext.arm_r4;
- unw_context->regs[5] = ucontext->uc_mcontext.arm_r5;
- unw_context->regs[6] = ucontext->uc_mcontext.arm_r6;
- unw_context->regs[7] = ucontext->uc_mcontext.arm_r7;
- unw_context->regs[8] = ucontext->uc_mcontext.arm_r8;
- unw_context->regs[9] = ucontext->uc_mcontext.arm_r9;
- unw_context->regs[10] = ucontext->uc_mcontext.arm_r10;
- unw_context->regs[11] = ucontext->uc_mcontext.arm_fp;
- unw_context->regs[12] = ucontext->uc_mcontext.arm_ip;
- unw_context->regs[13] = ucontext->uc_mcontext.arm_sp;
- unw_context->regs[14] = ucontext->uc_mcontext.arm_lr;
- unw_context->regs[15] = ucontext->uc_mcontext.arm_pc;
-#else
- unw_context->uc_mcontext = ucontext->uc_mcontext;
-#endif
-}
-
-bool UnwindCurrent::UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) {
- if (ucontext == nullptr) {
- int ret = unw_getcontext(&context_);
- if (ret < 0) {
- BACK_LOGW("unw_getcontext failed %d", ret);
- error_.error_code = BACKTRACE_UNWIND_ERROR_SETUP_FAILED;
- return false;
- }
- } else {
- GetUnwContextFromUcontext(ucontext);
- }
-
- // The cursor structure is pretty large, do not put it on the stack.
- std::unique_ptr<unw_cursor_t> cursor(new unw_cursor_t);
- int ret = unw_init_local(cursor.get(), &context_);
- if (ret < 0) {
- BACK_LOGW("unw_init_local failed %d", ret);
- error_.error_code = BACKTRACE_UNWIND_ERROR_SETUP_FAILED;
- return false;
- }
- initialized_ = true;
-
- size_t num_frames = 0;
- do {
- unw_word_t pc;
- ret = unw_get_reg(cursor.get(), UNW_REG_IP, &pc);
- if (ret < 0) {
- BACK_LOGW("Failed to read IP %d", ret);
- break;
- }
- unw_word_t sp;
- ret = unw_get_reg(cursor.get(), UNW_REG_SP, &sp);
- if (ret < 0) {
- BACK_LOGW("Failed to read SP %d", ret);
- break;
- }
-
- frames_.resize(num_frames+1);
- backtrace_frame_data_t* frame = &frames_.at(num_frames);
- frame->num = num_frames;
- frame->pc = static_cast<uintptr_t>(pc);
- frame->sp = static_cast<uintptr_t>(sp);
- frame->stack_size = 0;
-
- FillInMap(frame->pc, &frame->map);
- // Check to see if we should skip this frame because it's coming
- // from within the library, and we are doing a local unwind.
- if (ucontext != nullptr || num_frames != 0 || !DiscardFrame(*frame)) {
- if (num_ignore_frames == 0) {
- // GetFunctionName is an expensive call, only do it if we are
- // keeping the frame.
- frame->func_name = GetFunctionName(frame->pc, &frame->func_offset, &frame->map);
- if (num_frames > 0) {
- // Set the stack size for the previous frame.
- 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--;
- // Set the number of frames to zero to remove the frame added
- // above. By definition, if we still have frames to ignore
- // there should only be one frame in the vector.
- CHECK(num_frames == 0);
- frames_.resize(0);
- }
- }
- // If the pc is in a device map, then don't try to step.
- if (frame->map.flags & PROT_DEVICE_MAP) {
- break;
- }
- // Verify the sp is not in a device map too.
- backtrace_map_t map;
- FillInMap(frame->sp, &map);
- if (map.flags & PROT_DEVICE_MAP) {
- break;
- }
- ret = unw_step (cursor.get());
- } while (ret > 0 && num_frames < MAX_BACKTRACE_FRAMES);
-
- return true;
-}
diff --git a/libbacktrace/UnwindCurrent.h b/libbacktrace/UnwindCurrent.h
deleted file mode 100644
index 3656104..0000000
--- a/libbacktrace/UnwindCurrent.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2013 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.
- */
-
-#ifndef _LIBBACKTRACE_UNWIND_CURRENT_H
-#define _LIBBACKTRACE_UNWIND_CURRENT_H
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <ucontext.h>
-
-#include <string>
-
-#include <backtrace/Backtrace.h>
-#include <backtrace/BacktraceMap.h>
-
-#include "BacktraceCurrent.h"
-
-#define UNW_LOCAL_ONLY
-#include <libunwind.h>
-
-class UnwindCurrent : public BacktraceCurrent {
- public:
- UnwindCurrent(pid_t pid, pid_t tid, BacktraceMap* map) : BacktraceCurrent(pid, tid, map) {}
- virtual ~UnwindCurrent() {}
-
- std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) override;
-
- private:
- void GetUnwContextFromUcontext(const ucontext_t* ucontext);
-
- bool UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) override;
-
- unw_context_t context_;
-
- bool initialized_ = false;
-};
-
-#endif // _LIBBACKTRACE_UNWIND_CURRENT_H
diff --git a/libbacktrace/UnwindMap.cpp b/libbacktrace/UnwindMap.cpp
index 3cab0d1..798c769 100644
--- a/libbacktrace/UnwindMap.cpp
+++ b/libbacktrace/UnwindMap.cpp
@@ -134,7 +134,7 @@
return (map_created_ = (unw_map_local_create() == 0)) && GenerateMap();;
}
-void UnwindMapLocal::FillIn(uintptr_t addr, backtrace_map_t* map) {
+void UnwindMapLocal::FillIn(uint64_t addr, backtrace_map_t* map) {
BacktraceMap::FillIn(addr, map);
if (!IsValid(*map)) {
// Check to see if the underlying map changed and regenerate the map
diff --git a/libbacktrace/UnwindMap.h b/libbacktrace/UnwindMap.h
index 6ffdafd..15544e8 100644
--- a/libbacktrace/UnwindMap.h
+++ b/libbacktrace/UnwindMap.h
@@ -55,7 +55,7 @@
bool Build() override;
- void FillIn(uintptr_t addr, backtrace_map_t* map) override;
+ void FillIn(uint64_t addr, backtrace_map_t* map) override;
void LockIterator() override { pthread_rwlock_rdlock(&map_lock_); }
void UnlockIterator() override { pthread_rwlock_unlock(&map_lock_); }
diff --git a/libbacktrace/UnwindPtrace.cpp b/libbacktrace/UnwindPtrace.cpp
deleted file mode 100644
index 2155b8a..0000000
--- a/libbacktrace/UnwindPtrace.cpp
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Copyright (C) 2013 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 <sys/types.h>
-#include <ucontext.h>
-
-#include <libunwind.h>
-#include <libunwind-ptrace.h>
-
-#include <backtrace/Backtrace.h>
-#include <backtrace/BacktraceMap.h>
-
-#include "BacktraceLog.h"
-#include "UnwindMap.h"
-#include "UnwindPtrace.h"
-
-UnwindPtrace::UnwindPtrace(pid_t pid, pid_t tid, BacktraceMap* map)
- : BacktracePtrace(pid, tid, map), addr_space_(nullptr), upt_info_(nullptr) {
-}
-
-UnwindPtrace::~UnwindPtrace() {
- if (upt_info_) {
- _UPT_destroy(upt_info_);
- upt_info_ = nullptr;
- }
-
- if (addr_space_) {
- // Remove the map from the address space before destroying it.
- // It will be freed in the UnwindMap destructor.
- unw_map_set(addr_space_, nullptr);
-
- unw_destroy_addr_space(addr_space_);
- addr_space_ = nullptr;
- }
-}
-
-bool UnwindPtrace::Init() {
- if (upt_info_) {
- return true;
- }
-
- if (addr_space_) {
- // If somehow the addr_space_ gets initialized but upt_info_ doesn't,
- // then that indicates there is some kind of failure.
- return false;
- }
-
- addr_space_ = unw_create_addr_space(&_UPT_accessors, 0);
- if (!addr_space_) {
- BACK_LOGW("unw_create_addr_space failed.");
- error_.error_code = BACKTRACE_UNWIND_ERROR_SETUP_FAILED;
- return false;
- }
-
- UnwindMap* map = static_cast<UnwindMap*>(GetMap());
- unw_map_set(addr_space_, map->GetMapCursor());
-
- upt_info_ = reinterpret_cast<struct UPT_info*>(_UPT_create(Tid()));
- if (!upt_info_) {
- BACK_LOGW("Failed to create upt info.");
- error_.error_code = BACKTRACE_UNWIND_ERROR_SETUP_FAILED;
- return false;
- }
-
- return true;
-}
-
-bool UnwindPtrace::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) {
- if (GetMap() == nullptr) {
- // Without a map object, we can't do anything.
- error_.error_code = BACKTRACE_UNWIND_ERROR_MAP_MISSING;
- return false;
- }
-
- error_.error_code = BACKTRACE_UNWIND_NO_ERROR;
-
- if (ucontext) {
- BACK_LOGW("Unwinding from a specified context not supported yet.");
- error_.error_code = BACKTRACE_UNWIND_ERROR_UNSUPPORTED_OPERATION;
- return false;
- }
-
- if (!Init()) {
- return false;
- }
-
- unw_cursor_t cursor;
- int ret = unw_init_remote(&cursor, addr_space_, upt_info_);
- if (ret < 0) {
- BACK_LOGW("unw_init_remote failed %d", ret);
- error_.error_code = BACKTRACE_UNWIND_ERROR_SETUP_FAILED;
- return false;
- }
-
- size_t num_frames = 0;
- do {
- unw_word_t pc;
- ret = unw_get_reg(&cursor, UNW_REG_IP, &pc);
- if (ret < 0) {
- BACK_LOGW("Failed to read IP %d", ret);
- break;
- }
- unw_word_t sp;
- ret = unw_get_reg(&cursor, UNW_REG_SP, &sp);
- if (ret < 0) {
- BACK_LOGW("Failed to read SP %d", ret);
- break;
- }
-
- if (num_ignore_frames == 0) {
- frames_.resize(num_frames+1);
- backtrace_frame_data_t* frame = &frames_.at(num_frames);
- frame->num = num_frames;
- frame->pc = static_cast<uintptr_t>(pc);
- frame->sp = static_cast<uintptr_t>(sp);
- frame->stack_size = 0;
-
- if (num_frames > 0) {
- backtrace_frame_data_t* prev = &frames_.at(num_frames-1);
- prev->stack_size = frame->sp - prev->sp;
- }
-
- 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);
-
- num_frames++;
- // If the pc is in a device map, then don't try to step.
- if (frame->map.flags & PROT_DEVICE_MAP) {
- break;
- }
- } else {
- // If the pc is in a device map, then don't try to step.
- backtrace_map_t map;
- FillInMap(pc, &map);
- if (map.flags & PROT_DEVICE_MAP) {
- break;
- }
- num_ignore_frames--;
- }
- // Verify the sp is not in a device map.
- backtrace_map_t map;
- FillInMap(sp, &map);
- if (map.flags & PROT_DEVICE_MAP) {
- break;
- }
- ret = unw_step (&cursor);
- } while (ret > 0 && num_frames < MAX_BACKTRACE_FRAMES);
-
- return true;
-}
-
-std::string UnwindPtrace::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
- if (!Init()) {
- return "";
- }
-
- *offset = 0;
- char buf[512];
- unw_word_t value;
- if (unw_get_proc_name_by_ip(addr_space_, pc, buf, sizeof(buf), &value,
- upt_info_) >= 0 && buf[0] != '\0') {
- *offset = static_cast<uintptr_t>(value);
- return buf;
- }
- return "";
-}
diff --git a/libbacktrace/UnwindPtrace.h b/libbacktrace/UnwindPtrace.h
deleted file mode 100644
index 4688110..0000000
--- a/libbacktrace/UnwindPtrace.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2013 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.
- */
-
-#ifndef _LIBBACKTRACE_UNWIND_PTRACE_H
-#define _LIBBACKTRACE_UNWIND_PTRACE_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <string>
-
-#ifdef UNW_LOCAL_ONLY
-#undef UNW_LOCAL_ONLY
-#endif
-#include <libunwind.h>
-
-#include "BacktracePtrace.h"
-
-class UnwindPtrace : public BacktracePtrace {
- public:
- UnwindPtrace(pid_t pid, pid_t tid, BacktraceMap* map);
- virtual ~UnwindPtrace();
-
- bool Unwind(size_t num_ignore_frames, ucontext_t* ucontext) override;
-
- std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) override;
-
- private:
- bool Init();
-
- unw_addr_space_t addr_space_;
- struct UPT_info* upt_info_;
-};
-
-#endif // _LIBBACKTRACE_UNWIND_PTRACE_H
diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp
index b0345a1..bbfbdda 100644
--- a/libbacktrace/UnwindStack.cpp
+++ b/libbacktrace/UnwindStack.cpp
@@ -70,6 +70,7 @@
back_frame->rel_pc = frame->rel_pc;
back_frame->pc = frame->pc;
back_frame->sp = frame->sp;
+ back_frame->dex_pc = frame->dex_pc;
back_frame->func_name = demangle(frame->function_name.c_str());
back_frame->func_offset = frame->function_offset;
@@ -88,7 +89,7 @@
UnwindStackCurrent::UnwindStackCurrent(pid_t pid, pid_t tid, BacktraceMap* map)
: BacktraceCurrent(pid, tid, map) {}
-std::string UnwindStackCurrent::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
+std::string UnwindStackCurrent::GetFunctionNameRaw(uint64_t pc, uint64_t* offset) {
return GetMap()->GetFunctionName(pc, offset);
}
@@ -111,7 +112,7 @@
UnwindStackPtrace::UnwindStackPtrace(pid_t pid, pid_t tid, BacktraceMap* map)
: BacktracePtrace(pid, tid, map), memory_(pid) {}
-std::string UnwindStackPtrace::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
+std::string UnwindStackPtrace::GetFunctionNameRaw(uint64_t pc, uint64_t* offset) {
return GetMap()->GetFunctionName(pc, offset);
}
@@ -127,6 +128,6 @@
return Backtrace::Unwind(regs.get(), GetMap(), &frames_, num_ignore_frames, nullptr);
}
-size_t UnwindStackPtrace::Read(uintptr_t addr, uint8_t* buffer, size_t bytes) {
+size_t UnwindStackPtrace::Read(uint64_t addr, uint8_t* buffer, size_t bytes) {
return memory_.Read(addr, buffer, bytes);
}
diff --git a/libbacktrace/UnwindStack.h b/libbacktrace/UnwindStack.h
index ee2a706..498ad4e 100644
--- a/libbacktrace/UnwindStack.h
+++ b/libbacktrace/UnwindStack.h
@@ -32,7 +32,7 @@
UnwindStackCurrent(pid_t pid, pid_t tid, BacktraceMap* map);
virtual ~UnwindStackCurrent() = default;
- std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) override;
+ std::string GetFunctionNameRaw(uint64_t pc, uint64_t* offset) override;
bool UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) override;
};
@@ -44,9 +44,9 @@
bool Unwind(size_t num_ignore_frames, ucontext_t* context) override;
- std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset);
+ std::string GetFunctionNameRaw(uint64_t pc, uint64_t* offset);
- size_t Read(uintptr_t addr, uint8_t* buffer, size_t bytes) override;
+ size_t Read(uint64_t addr, uint8_t* buffer, size_t bytes) override;
private:
unwindstack::MemoryRemote memory_;
diff --git a/libbacktrace/UnwindStackMap.cpp b/libbacktrace/UnwindStackMap.cpp
index 93406dc..60c7952 100644
--- a/libbacktrace/UnwindStackMap.cpp
+++ b/libbacktrace/UnwindStackMap.cpp
@@ -57,7 +57,7 @@
map.end = map_info->end;
map.offset = map_info->offset;
// Set to -1 so that it is demand loaded.
- map.load_bias = static_cast<uintptr_t>(-1);
+ map.load_bias = static_cast<uint64_t>(-1);
map.flags = map_info->flags;
map.name = map_info->name;
@@ -67,9 +67,9 @@
return true;
}
-void UnwindStackMap::FillIn(uintptr_t addr, backtrace_map_t* map) {
+void UnwindStackMap::FillIn(uint64_t addr, backtrace_map_t* map) {
BacktraceMap::FillIn(addr, map);
- if (map->load_bias != static_cast<uintptr_t>(-1)) {
+ if (map->load_bias != static_cast<uint64_t>(-1)) {
return;
}
@@ -93,7 +93,7 @@
return map_info->GetLoadBias(process_memory_);
}
-std::string UnwindStackMap::GetFunctionName(uintptr_t pc, uintptr_t* offset) {
+std::string UnwindStackMap::GetFunctionName(uint64_t pc, uint64_t* offset) {
*offset = 0;
unwindstack::Maps* maps = stack_maps();
diff --git a/libbacktrace/UnwindStackMap.h b/libbacktrace/UnwindStackMap.h
index 12c5909..6b98809 100644
--- a/libbacktrace/UnwindStackMap.h
+++ b/libbacktrace/UnwindStackMap.h
@@ -33,9 +33,9 @@
bool Build() override;
- void FillIn(uintptr_t addr, backtrace_map_t* map) override;
+ void FillIn(uint64_t addr, backtrace_map_t* map) override;
- virtual std::string GetFunctionName(uintptr_t pc, uintptr_t* offset) override;
+ virtual std::string GetFunctionName(uint64_t pc, uint64_t* offset) override;
virtual std::shared_ptr<unwindstack::Memory> GetProcessMemory() override final;
unwindstack::Maps* stack_maps() { return stack_maps_.get(); }
diff --git a/libbacktrace/backtrace_offline_test.cpp b/libbacktrace/backtrace_offline_test.cpp
index e92bc61..e2a7441 100644
--- a/libbacktrace/backtrace_offline_test.cpp
+++ b/libbacktrace/backtrace_offline_test.cpp
@@ -75,20 +75,20 @@
struct FunctionSymbol {
std::string name;
- uintptr_t start;
- uintptr_t end;
+ uint64_t start;
+ uint64_t end;
};
static std::vector<FunctionSymbol> GetFunctionSymbols() {
std::vector<FunctionSymbol> symbols = {
{"unknown_start", 0, 0},
- {"test_level_one", reinterpret_cast<uintptr_t>(&test_level_one), 0},
- {"test_level_two", reinterpret_cast<uintptr_t>(&test_level_two), 0},
- {"test_level_three", reinterpret_cast<uintptr_t>(&test_level_three), 0},
- {"test_level_four", reinterpret_cast<uintptr_t>(&test_level_four), 0},
- {"test_recursive_call", reinterpret_cast<uintptr_t>(&test_recursive_call), 0},
- {"test_get_context_and_wait", reinterpret_cast<uintptr_t>(&test_get_context_and_wait), 0},
- {"unknown_end", static_cast<uintptr_t>(-1), static_cast<uintptr_t>(-1)},
+ {"test_level_one", reinterpret_cast<uint64_t>(&test_level_one), 0},
+ {"test_level_two", reinterpret_cast<uint64_t>(&test_level_two), 0},
+ {"test_level_three", reinterpret_cast<uint64_t>(&test_level_three), 0},
+ {"test_level_four", reinterpret_cast<uint64_t>(&test_level_four), 0},
+ {"test_recursive_call", reinterpret_cast<uint64_t>(&test_recursive_call), 0},
+ {"test_get_context_and_wait", reinterpret_cast<uint64_t>(&test_get_context_and_wait), 0},
+ {"unknown_end", static_cast<uint64_t>(-1), static_cast<uint64_t>(-1)},
};
std::sort(
symbols.begin(), symbols.end(),
@@ -141,7 +141,7 @@
const size_t stack_size = 16 * 1024;
void* stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
ASSERT_NE(MAP_FAILED, stack);
- uintptr_t stack_addr = reinterpret_cast<uintptr_t>(stack);
+ uint64_t stack_addr = reinterpret_cast<uint64_t>(stack);
pthread_attr_t attr;
ASSERT_EQ(0, pthread_attr_init(&attr));
ASSERT_EQ(0, pthread_attr_setstack(&attr, reinterpret_cast<void*>(stack), stack_size));
@@ -174,8 +174,8 @@
for (auto it = map->begin(); it != map->end(); ++it) {
const backtrace_map_t* entry = *it;
testdata +=
- android::base::StringPrintf("map: start: %" PRIxPTR " end: %" PRIxPTR " offset: %" PRIxPTR
- " load_bias: %" PRIxPTR " flags: %d name: %s\n",
+ android::base::StringPrintf("map: start: %" PRIx64 " end: %" PRIx64 " offset: %" PRIx64
+ " load_bias: %" PRIx64 " flags: %d name: %s\n",
entry->start, entry->end, entry->offset, entry->load_bias,
entry->flags, entry->name.c_str());
}
@@ -194,9 +194,9 @@
// 5. Dump function symbols
std::vector<FunctionSymbol> function_symbols = GetFunctionSymbols();
for (const auto& symbol : function_symbols) {
- testdata += android::base::StringPrintf(
- "function: start: %" PRIxPTR " end: %" PRIxPTR" name: %s\n",
- symbol.start, symbol.end, symbol.name.c_str());
+ testdata +=
+ android::base::StringPrintf("function: start: %" PRIx64 " end: %" PRIx64 " name: %s\n",
+ symbol.start, symbol.end, symbol.name.c_str());
}
ASSERT_TRUE(android::base::WriteStringToFile(testdata, "offline_testdata"));
@@ -204,7 +204,7 @@
// Return the name of the function which matches the address. Although we don't know the
// exact end of each function, it is accurate enough for the tests.
-static std::string FunctionNameForAddress(uintptr_t addr,
+static std::string FunctionNameForAddress(uint64_t addr,
const std::vector<FunctionSymbol>& symbols) {
for (auto& symbol : symbols) {
if (addr >= symbol.start && addr < symbol.end) {
@@ -240,7 +240,7 @@
backtrace_map_t& map = testdata->maps.back();
int pos;
sscanf(line.c_str(),
- "map: start: %" SCNxPTR " end: %" SCNxPTR " offset: %" SCNxPTR " load_bias: %" SCNxPTR
+ "map: start: %" SCNx64 " end: %" SCNx64 " offset: %" SCNx64 " load_bias: %" SCNx64
" flags: %d name: %n",
&map.start, &map.end, &map.offset, &map.load_bias, &map.flags, &pos);
map.name = android::base::Trim(line.substr(pos));
@@ -302,9 +302,8 @@
testdata->symbols.resize(testdata->symbols.size() + 1);
FunctionSymbol& symbol = testdata->symbols.back();
int pos;
- sscanf(line.c_str(),
- "function: start: %" SCNxPTR " end: %" SCNxPTR " name: %n",
- &symbol.start, &symbol.end, &pos);
+ sscanf(line.c_str(), "function: start: %" SCNx64 " end: %" SCNx64 " name: %n", &symbol.start,
+ &symbol.end, &pos);
symbol.name = line.substr(pos);
}
}
@@ -342,7 +341,7 @@
ASSERT_TRUE(backtrace->Unwind(0, &ucontext));
// Collect pc values of the call stack frames.
- std::vector<uintptr_t> pc_values;
+ std::vector<uint64_t> pc_values;
for (size_t i = 0; i < backtrace->NumFrames(); ++i) {
pc_values.push_back(backtrace->GetFrame(i)->pc);
}
@@ -420,7 +419,7 @@
ASSERT_EQ(testdata.symbols.size(), backtrace->NumFrames());
for (size_t i = 0; i < backtrace->NumFrames(); ++i) {
- uintptr_t vaddr_in_file =
+ uint64_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 57b7553..10152f7 100644
--- a/libbacktrace/backtrace_test.cpp
+++ b/libbacktrace/backtrace_test.cpp
@@ -745,8 +745,8 @@
delete back_map;
ASSERT_FALSE(BacktraceMap::IsValid(map));
- ASSERT_EQ(static_cast<uintptr_t>(0), map.start);
- ASSERT_EQ(static_cast<uintptr_t>(0), map.end);
+ ASSERT_EQ(static_cast<uint64_t>(0), map.start);
+ ASSERT_EQ(static_cast<uint64_t>(0), map.end);
ASSERT_EQ(0, map.flags);
ASSERT_EQ("", map.name);
}
@@ -851,8 +851,8 @@
}
struct map_test_t {
- uintptr_t start;
- uintptr_t end;
+ uint64_t start;
+ uint64_t end;
};
static bool map_sort(map_test_t i, map_test_t j) { return i.start < j.start; }
@@ -863,7 +863,7 @@
}
std::string map_txt;
for (auto map : maps) {
- map_txt += android::base::StringPrintf("%" PRIxPTR "-%" PRIxPTR "\n", map.start, map.end);
+ map_txt += android::base::StringPrintf("%" PRIx64 "-%" PRIx64 "\n", map.start, map.end);
}
return map_txt;
}
@@ -875,7 +875,7 @@
std::string map_txt;
for (const backtrace_map_t* map : *maps) {
map_txt += android::base::StringPrintf(
- "%" PRIxPTR "-%" PRIxPTR " flags: 0x%x offset: 0x%" PRIxPTR " load_bias: 0x%" PRIxPTR,
+ "%" PRIx64 "-%" PRIx64 " flags: 0x%x offset: 0x%" PRIx64 " load_bias: 0x%" PRIx64,
map->start, map->end, map->flags, map->offset, map->load_bias);
if (!map->name.empty()) {
map_txt += ' ' + map->name;
@@ -894,7 +894,7 @@
std::vector<map_test_t> test_maps;
while (fgets(buffer, sizeof(buffer), map_file)) {
map_test_t map;
- ASSERT_EQ(2, sscanf(buffer, "%" SCNxPTR "-%" SCNxPTR " ", &map.start, &map.end));
+ ASSERT_EQ(2, sscanf(buffer, "%" SCNx64 "-%" SCNx64 " ", &map.start, &map.end));
test_maps.push_back(map);
}
fclose(map_file);
@@ -984,7 +984,7 @@
return nullptr;
}
-static void RunReadTest(Backtrace* backtrace, uintptr_t read_addr) {
+static void RunReadTest(Backtrace* backtrace, uint64_t read_addr) {
size_t pagesize = static_cast<size_t>(sysconf(_SC_PAGE_SIZE));
// Create a page of data to use to do quick compares.
@@ -1035,15 +1035,15 @@
std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), thread_data.tid));
ASSERT_TRUE(backtrace.get() != nullptr);
- RunReadTest(backtrace.get(), reinterpret_cast<uintptr_t>(thread_data.data));
+ RunReadTest(backtrace.get(), reinterpret_cast<uint64_t>(thread_data.data));
android_atomic_acquire_store(0, &thread_data.state);
ASSERT_TRUE(WaitForNonZero(&thread_data.state, 10));
}
-volatile uintptr_t g_ready = 0;
-volatile uintptr_t g_addr = 0;
+volatile uint64_t g_ready = 0;
+volatile uint64_t g_addr = 0;
static void ForkedReadTest() {
// Create two map pages.
@@ -1063,7 +1063,7 @@
// Set up a simple pattern in memory.
InitMemory(memory, pagesize);
- g_addr = reinterpret_cast<uintptr_t>(memory);
+ g_addr = reinterpret_cast<uint64_t>(memory);
g_ready = 1;
while (1) {
@@ -1089,17 +1089,15 @@
std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, pid));
ASSERT_TRUE(backtrace.get() != nullptr);
- uintptr_t read_addr;
- size_t bytes_read = backtrace->Read(reinterpret_cast<uintptr_t>(&g_ready),
- reinterpret_cast<uint8_t*>(&read_addr),
- sizeof(uintptr_t));
- ASSERT_EQ(sizeof(uintptr_t), bytes_read);
+ uint64_t read_addr;
+ size_t bytes_read = backtrace->Read(reinterpret_cast<uint64_t>(&g_ready),
+ reinterpret_cast<uint8_t*>(&read_addr), sizeof(uint64_t));
+ ASSERT_EQ(sizeof(uint64_t), bytes_read);
if (read_addr) {
// The forked process is ready to be read.
- bytes_read = backtrace->Read(reinterpret_cast<uintptr_t>(&g_addr),
- reinterpret_cast<uint8_t*>(&read_addr),
- sizeof(uintptr_t));
- ASSERT_EQ(sizeof(uintptr_t), bytes_read);
+ bytes_read = backtrace->Read(reinterpret_cast<uint64_t>(&g_addr),
+ reinterpret_cast<uint8_t*>(&read_addr), sizeof(uint64_t));
+ ASSERT_EQ(sizeof(uint64_t), bytes_read);
RunReadTest(backtrace.get(), read_addr);
@@ -1173,7 +1171,7 @@
struct stat buf;
ASSERT_TRUE(stat(tmp_so_name, &buf) != -1);
- uintptr_t map_size = buf.st_size;
+ uint64_t map_size = buf.st_size;
int fd = open(tmp_so_name, O_RDONLY);
ASSERT_TRUE(fd != -1);
@@ -1192,11 +1190,10 @@
backtrace->Unwind(0);
// Loop through the entire map, and get every function we can find.
- map_size += reinterpret_cast<uintptr_t>(map);
+ map_size += reinterpret_cast<uint64_t>(map);
std::string last_func;
- for (uintptr_t read_addr = reinterpret_cast<uintptr_t>(map);
- read_addr < map_size; read_addr += 4) {
- uintptr_t offset;
+ for (uint64_t read_addr = reinterpret_cast<uint64_t>(map); read_addr < map_size; read_addr += 4) {
+ uint64_t offset;
std::string func_name = backtrace->GetFunctionName(read_addr, &offset);
if (!func_name.empty() && last_func != func_name) {
found_functions.push_back(func_name);
@@ -1204,7 +1201,7 @@
last_func = func_name;
}
- ASSERT_TRUE(munmap(map, map_size - reinterpret_cast<uintptr_t>(map)) == 0);
+ ASSERT_TRUE(munmap(map, map_size - reinterpret_cast<uint64_t>(map)) == 0);
VerifyFunctionsFound(found_functions);
}
@@ -1217,7 +1214,7 @@
struct stat buf;
ASSERT_TRUE(stat(tmp_so_name, &buf) != -1);
- uintptr_t map_size = buf.st_size;
+ uint64_t map_size = buf.st_size;
pid_t pid;
if ((pid = fork()) == 0) {
@@ -1240,7 +1237,7 @@
exit(0);
}
- g_addr = reinterpret_cast<uintptr_t>(map);
+ g_addr = reinterpret_cast<uint64_t>(map);
g_ready = 1;
while (true) {
usleep(US_PER_MSEC);
@@ -1260,10 +1257,14 @@
std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, BACKTRACE_CURRENT_THREAD));
ASSERT_TRUE(backtrace.get() != nullptr);
- uintptr_t read_addr;
- ASSERT_EQ(sizeof(uintptr_t), backtrace->Read(reinterpret_cast<uintptr_t>(&g_ready), reinterpret_cast<uint8_t*>(&read_addr), sizeof(uintptr_t)));
+ uint64_t read_addr;
+ ASSERT_EQ(sizeof(uint64_t),
+ backtrace->Read(reinterpret_cast<uint64_t>(&g_ready),
+ reinterpret_cast<uint8_t*>(&read_addr), sizeof(uint64_t)));
if (read_addr) {
- ASSERT_EQ(sizeof(uintptr_t), backtrace->Read(reinterpret_cast<uintptr_t>(&g_addr), reinterpret_cast<uint8_t*>(&read_addr), sizeof(uintptr_t)));
+ ASSERT_EQ(sizeof(uint64_t),
+ backtrace->Read(reinterpret_cast<uint64_t>(&g_addr),
+ reinterpret_cast<uint8_t*>(&read_addr), sizeof(uint64_t)));
// Needed before GetFunctionName will work.
backtrace->Unwind(0);
@@ -1272,7 +1273,7 @@
map_size += read_addr;
std::string last_func;
for (; read_addr < map_size; read_addr += 4) {
- uintptr_t offset;
+ uint64_t offset;
std::string func_name = backtrace->GetFunctionName(read_addr, &offset);
if (!func_name.empty() && last_func != func_name) {
found_functions.push_back(func_name);
@@ -1295,7 +1296,7 @@
VerifyFunctionsFound(found_functions);
}
-static bool FindFuncFrameInBacktrace(Backtrace* backtrace, uintptr_t test_func, size_t* frame_num) {
+static bool FindFuncFrameInBacktrace(Backtrace* backtrace, uint64_t test_func, size_t* frame_num) {
backtrace_map_t map;
backtrace->FillInMap(test_func, &map);
if (!BacktraceMap::IsValid(map)) {
@@ -1314,7 +1315,7 @@
return false;
}
-static void VerifyUnreadableElfFrame(Backtrace* backtrace, uintptr_t test_func, size_t frame_num) {
+static void VerifyUnreadableElfFrame(Backtrace* backtrace, uint64_t test_func, size_t frame_num) {
ASSERT_LT(backtrace->NumFrames(), static_cast<size_t>(MAX_BACKTRACE_FRAMES))
<< DumpFrames(backtrace);
@@ -1322,11 +1323,12 @@
// Make sure that there is at least one more frame above the test func call.
ASSERT_LT(frame_num, backtrace->NumFrames()) << DumpFrames(backtrace);
- uintptr_t diff = backtrace->GetFrame(frame_num)->pc - test_func;
+ uint64_t diff = backtrace->GetFrame(frame_num)->pc - test_func;
ASSERT_LT(diff, 200U) << DumpFrames(backtrace);
}
-static void VerifyUnreadableElfBacktrace(uintptr_t test_func) {
+static void VerifyUnreadableElfBacktrace(void* func) {
+ uint64_t test_func = reinterpret_cast<uint64_t>(func);
std::unique_ptr<Backtrace> backtrace(Backtrace::Create(BACKTRACE_CURRENT_PROCESS,
BACKTRACE_CURRENT_THREAD));
ASSERT_TRUE(backtrace.get() != nullptr);
@@ -1339,7 +1341,7 @@
VerifyUnreadableElfFrame(backtrace.get(), test_func, frame_num);
}
-typedef int (*test_func_t)(int, int, int, int, void (*)(uintptr_t), uintptr_t);
+typedef int (*test_func_t)(int, int, int, int, void (*)(void*), void*);
TEST(libbacktrace, unwind_through_unreadable_elf_local) {
const char* tmp_so_name = CopySharedLibrary();
@@ -1352,8 +1354,8 @@
test_func = reinterpret_cast<test_func_t>(dlsym(lib_handle, "test_level_one"));
ASSERT_TRUE(test_func != nullptr);
- ASSERT_NE(test_func(1, 2, 3, 4, VerifyUnreadableElfBacktrace,
- reinterpret_cast<uintptr_t>(test_func)), 0);
+ ASSERT_NE(test_func(1, 2, 3, 4, VerifyUnreadableElfBacktrace, reinterpret_cast<void*>(test_func)),
+ 0);
ASSERT_TRUE(dlclose(lib_handle) == 0);
}
@@ -1391,10 +1393,9 @@
ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError().error_code);
size_t frame_num;
- if (FindFuncFrameInBacktrace(backtrace.get(),
- reinterpret_cast<uintptr_t>(test_func), &frame_num)) {
-
- VerifyUnreadableElfFrame(backtrace.get(), reinterpret_cast<uintptr_t>(test_func), frame_num);
+ if (FindFuncFrameInBacktrace(backtrace.get(), reinterpret_cast<uint64_t>(test_func),
+ &frame_num)) {
+ VerifyUnreadableElfFrame(backtrace.get(), reinterpret_cast<uint64_t>(test_func), frame_num);
done = true;
}
@@ -1426,8 +1427,8 @@
ASSERT_TRUE(backtrace.get() != nullptr);
// Verify that trying to get a function name before doing an unwind works.
- uintptr_t cur_func_offset = reinterpret_cast<uintptr_t>(&test_level_one) + 1;
- size_t offset;
+ uint64_t cur_func_offset = reinterpret_cast<uint64_t>(&test_level_one) + 1;
+ uint64_t offset;
ASSERT_NE(std::string(""), backtrace->GetFunctionName(cur_func_offset, &offset));
}
@@ -1439,14 +1440,14 @@
std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, pid));
// Verify that trying to get a function name before doing an unwind works.
- uintptr_t cur_func_offset = reinterpret_cast<uintptr_t>(&test_level_one) + 1;
- size_t offset;
+ uint64_t cur_func_offset = reinterpret_cast<uint64_t>(&test_level_one) + 1;
+ uint64_t offset;
ASSERT_NE(std::string(""), backtrace->GetFunctionName(cur_func_offset, &offset));
FinishRemoteProcess(pid);
}
-static void SetUcontextSp(uintptr_t sp, ucontext_t* ucontext) {
+static void SetUcontextSp(uint64_t sp, ucontext_t* ucontext) {
#if defined(__arm__)
ucontext->uc_mcontext.arm_sp = sp;
#elif defined(__aarch64__)
@@ -1462,7 +1463,7 @@
#endif
}
-static void SetUcontextPc(uintptr_t pc, ucontext_t* ucontext) {
+static void SetUcontextPc(uint64_t pc, ucontext_t* ucontext) {
#if defined(__arm__)
ucontext->uc_mcontext.arm_pc = pc;
#elif defined(__aarch64__)
@@ -1478,7 +1479,7 @@
#endif
}
-static void SetUcontextLr(uintptr_t lr, ucontext_t* ucontext) {
+static void SetUcontextLr(uint64_t lr, ucontext_t* ucontext) {
#if defined(__arm__)
ucontext->uc_mcontext.arm_lr = lr;
#elif defined(__aarch64__)
@@ -1513,7 +1514,7 @@
}
static void UnwindFromDevice(Backtrace* backtrace, void* device_map) {
- uintptr_t device_map_uint = reinterpret_cast<uintptr_t>(device_map);
+ uint64_t device_map_uint = reinterpret_cast<uint64_t>(device_map);
backtrace_map_t map;
backtrace->FillInMap(device_map_uint, &map);
@@ -1521,12 +1522,12 @@
ASSERT_EQ(PROT_DEVICE_MAP, map.flags & PROT_DEVICE_MAP);
// Quick sanity checks.
- size_t offset;
+ uint64_t offset;
ASSERT_EQ(std::string(""), backtrace->GetFunctionName(device_map_uint, &offset));
ASSERT_EQ(std::string(""), backtrace->GetFunctionName(device_map_uint, &offset, &map));
ASSERT_EQ(std::string(""), backtrace->GetFunctionName(0, &offset));
- uintptr_t cur_func_offset = reinterpret_cast<uintptr_t>(&test_level_one) + 1;
+ uint64_t cur_func_offset = reinterpret_cast<uint64_t>(&test_level_one) + 1;
// Now verify the device map flag actually causes the function name to be empty.
backtrace->FillInMap(cur_func_offset, &map);
ASSERT_TRUE((map.flags & PROT_DEVICE_MAP) == 0);
@@ -1539,7 +1540,7 @@
// Create a context that has the pc in the device map, but the sp
// in a non-device map.
memset(&ucontext, 0, sizeof(ucontext));
- SetUcontextSp(reinterpret_cast<uintptr_t>(&ucontext), &ucontext);
+ SetUcontextSp(reinterpret_cast<uint64_t>(&ucontext), &ucontext);
SetUcontextPc(device_map_uint, &ucontext);
SetUcontextLr(cur_func_offset, &ucontext);
@@ -1549,7 +1550,7 @@
ASSERT_EQ(1U, backtrace->NumFrames());
const backtrace_frame_data_t* frame = backtrace->GetFrame(0);
ASSERT_EQ(device_map_uint, frame->pc);
- ASSERT_EQ(reinterpret_cast<uintptr_t>(&ucontext), frame->sp);
+ ASSERT_EQ(reinterpret_cast<uint64_t>(&ucontext), frame->sp);
// Check what happens when skipping the first frame.
ASSERT_TRUE(backtrace->Unwind(1, &ucontext));
@@ -1669,7 +1670,7 @@
std::unique_ptr<BacktraceMap> map(map_create_func(pid, false));
std::unique_ptr<Backtrace> backtrace(create_func(pid, pid, map.get()));
- size_t bytes_read = backtrace->Read(reinterpret_cast<uintptr_t>(const_cast<int*>(&value)),
+ size_t bytes_read = backtrace->Read(reinterpret_cast<uint64_t>(const_cast<int*>(&value)),
reinterpret_cast<uint8_t*>(&read_value), sizeof(read_value));
ASSERT_EQ(sizeof(read_value), bytes_read);
diff --git a/libbacktrace/include/backtrace/Backtrace.h b/libbacktrace/include/backtrace/Backtrace.h
index 5922664..1b8ad19 100644
--- a/libbacktrace/include/backtrace/Backtrace.h
+++ b/libbacktrace/include/backtrace/Backtrace.h
@@ -26,11 +26,11 @@
#include <backtrace/backtrace_constants.h>
#include <backtrace/BacktraceMap.h>
-#if __LP64__
-#define PRIPTR "016" PRIxPTR
+#if defined(__LP64__)
+#define PRIPTR "016" PRIx64
typedef uint64_t word_t;
#else
-#define PRIPTR "08" PRIxPTR
+#define PRIPTR "08" PRIx64
typedef uint32_t word_t;
#endif
@@ -77,13 +77,15 @@
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.
+ uint64_t pc; // The absolute pc.
+ uint64_t rel_pc; // The relative pc.
+ uint64_t sp; // The top of the stack.
size_t stack_size; // The size of the stack, zero indicate an unknown stack size.
+ uint64_t dex_pc; // If non-zero, the Dex PC for the ART interpreter.
backtrace_map_t map; // The map associated with the given pc.
std::string func_name; // The function name associated with this pc, NULL if not found.
- uintptr_t func_offset; // pc relative to the start of the function, only valid if func_name is not NULL.
+ uint64_t func_offset; // pc relative to the start of the function, only valid if func_name is not
+ // NULL.
};
#if defined(__APPLE__)
@@ -138,20 +140,20 @@
// Get the function name and offset into the function given the pc.
// If the string is empty, then no valid function name was found,
// or the pc is not in any valid map.
- virtual std::string GetFunctionName(uintptr_t pc, uintptr_t* offset,
+ virtual std::string GetFunctionName(uint64_t pc, uint64_t* offset,
const backtrace_map_t* map = NULL);
// Fill in the map data associated with the given pc.
- virtual void FillInMap(uintptr_t pc, backtrace_map_t* map);
+ virtual void FillInMap(uint64_t pc, backtrace_map_t* map);
// Read the data at a specific address.
- virtual bool ReadWord(uintptr_t ptr, word_t* out_value) = 0;
+ virtual bool ReadWord(uint64_t ptr, word_t* out_value) = 0;
// Read arbitrary data from a specific address. If a read request would
// span from one map to another, this call only reads up until the end
// of the current map.
// Returns the total number of bytes actually read.
- virtual size_t Read(uintptr_t addr, uint8_t* buffer, size_t bytes) = 0;
+ virtual size_t Read(uint64_t addr, uint8_t* buffer, size_t bytes) = 0;
// Create a string representing the formatted line of backtrace information
// for a single frame.
@@ -188,9 +190,9 @@
// The name returned is not demangled, GetFunctionName() takes care of
// demangling the name.
- virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) = 0;
+ virtual std::string GetFunctionNameRaw(uint64_t pc, uint64_t* offset) = 0;
- virtual bool VerifyReadWordArgs(uintptr_t ptr, word_t* out_value);
+ virtual bool VerifyReadWordArgs(uint64_t ptr, word_t* out_value);
bool BuildMap();
diff --git a/libbacktrace/include/backtrace/BacktraceMap.h b/libbacktrace/include/backtrace/BacktraceMap.h
index 4ae68dd..4d020e6 100644
--- a/libbacktrace/include/backtrace/BacktraceMap.h
+++ b/libbacktrace/include/backtrace/BacktraceMap.h
@@ -39,10 +39,10 @@
static constexpr int PROT_DEVICE_MAP = 0x8000;
struct backtrace_map_t {
- uintptr_t start = 0;
- uintptr_t end = 0;
- uintptr_t offset = 0;
- uintptr_t load_bias = 0;
+ uint64_t start = 0;
+ uint64_t end = 0;
+ uint64_t offset = 0;
+ uint64_t load_bias = 0;
int flags = 0;
std::string name;
};
@@ -91,7 +91,7 @@
return nullptr;
}
backtrace_map_t* map = &map_->maps_[index_];
- if (map->load_bias == static_cast<uintptr_t>(-1)) {
+ if (map->load_bias == static_cast<uint64_t>(-1)) {
map->load_bias = map_->GetLoadBias(index_);
}
return map;
@@ -106,15 +106,15 @@
iterator end() { return iterator(this, maps_.size()); }
// Fill in the map data structure for the given address.
- virtual void FillIn(uintptr_t addr, backtrace_map_t* map);
+ virtual void FillIn(uint64_t addr, backtrace_map_t* map);
// Only supported with the new unwinder.
- virtual std::string GetFunctionName(uintptr_t /*pc*/, uintptr_t* /*offset*/) { return ""; }
+ virtual std::string GetFunctionName(uint64_t /*pc*/, uint64_t* /*offset*/) { return ""; }
virtual std::shared_ptr<unwindstack::Memory> GetProcessMemory() { return nullptr; }
// The flags returned are the same flags as used by the mmap call.
// The values are PROT_*.
- int GetFlags(uintptr_t pc) {
+ int GetFlags(uint64_t pc) {
backtrace_map_t map;
FillIn(pc, &map);
if (IsValid(map)) {
@@ -123,9 +123,9 @@
return PROT_NONE;
}
- bool IsReadable(uintptr_t pc) { return GetFlags(pc) & PROT_READ; }
- bool IsWritable(uintptr_t pc) { return GetFlags(pc) & PROT_WRITE; }
- bool IsExecutable(uintptr_t pc) { return GetFlags(pc) & PROT_EXEC; }
+ bool IsReadable(uint64_t pc) { return GetFlags(pc) & PROT_READ; }
+ bool IsWritable(uint64_t pc) { return GetFlags(pc) & PROT_WRITE; }
+ bool IsExecutable(uint64_t pc) { return GetFlags(pc) & PROT_EXEC; }
// In order to use the iterators on this object, a caller must
// call the LockIterator and UnlockIterator function to guarantee
diff --git a/liblog/Android.bp b/liblog/Android.bp
index eae0b10..7d9e306 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -80,6 +80,10 @@
address: false,
},
},
+ android_arm: {
+ // TODO: This is to work around b/24465209. Remove after root cause is fixed
+ ldflags: ["-Wl,--hash-style=both"],
+ },
windows: {
srcs: ["uio.c"],
enabled: true,
diff --git a/libunwindstack/DwarfSection.cpp b/libunwindstack/DwarfSection.cpp
index 0954187..91d855b 100644
--- a/libunwindstack/DwarfSection.cpp
+++ b/libunwindstack/DwarfSection.cpp
@@ -34,6 +34,8 @@
namespace unwindstack {
+constexpr uint64_t DEX_PC_REG = 0x20444558;
+
DwarfSection::DwarfSection(Memory* memory) : memory_(memory), last_error_(DWARF_ERROR_NONE) {}
const DwarfFde* DwarfSection::GetFdeFromPc(uint64_t pc) {
@@ -98,6 +100,84 @@
}
template <typename AddressType>
+struct EvalInfo {
+ const dwarf_loc_regs_t* loc_regs;
+ const DwarfCie* cie;
+ RegsImpl<AddressType>* cur_regs;
+ Memory* regular_memory;
+ AddressType cfa;
+ bool return_address_undefined = false;
+ uint64_t reg_map = 0;
+ AddressType reg_values[64];
+};
+
+template <typename AddressType>
+bool DwarfSectionImpl<AddressType>::EvalRegister(const DwarfLocation* loc, uint32_t reg,
+ AddressType* reg_ptr, void* info) {
+ EvalInfo<AddressType>* eval_info = reinterpret_cast<EvalInfo<AddressType>*>(info);
+ Memory* regular_memory = eval_info->regular_memory;
+ switch (loc->type) {
+ case DWARF_LOCATION_OFFSET:
+ if (!regular_memory->ReadFully(eval_info->cfa + loc->values[0], reg_ptr, sizeof(AddressType))) {
+ last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ return false;
+ }
+ break;
+ case DWARF_LOCATION_VAL_OFFSET:
+ *reg_ptr = eval_info->cfa + loc->values[0];
+ break;
+ case DWARF_LOCATION_REGISTER: {
+ uint32_t cur_reg = loc->values[0];
+ if (cur_reg >= eval_info->cur_regs->total_regs()) {
+ last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
+ return false;
+ }
+ AddressType* cur_reg_ptr = &(*eval_info->cur_regs)[cur_reg];
+ const auto& entry = eval_info->loc_regs->find(cur_reg);
+ if (entry != eval_info->loc_regs->end()) {
+ if (!(eval_info->reg_map & (1 << cur_reg))) {
+ eval_info->reg_map |= 1 << cur_reg;
+ eval_info->reg_values[cur_reg] = *cur_reg_ptr;
+ if (!EvalRegister(&entry->second, cur_reg, cur_reg_ptr, eval_info)) {
+ return false;
+ }
+ }
+
+ // Use the register value from before any evaluations.
+ *reg_ptr = eval_info->reg_values[cur_reg] + loc->values[1];
+ } else {
+ *reg_ptr = *cur_reg_ptr + loc->values[1];
+ }
+ break;
+ }
+ case DWARF_LOCATION_EXPRESSION:
+ case DWARF_LOCATION_VAL_EXPRESSION: {
+ AddressType value;
+ if (!EvalExpression(*loc, eval_info->cie->version, regular_memory, &value)) {
+ return false;
+ }
+ if (loc->type == DWARF_LOCATION_EXPRESSION) {
+ if (!regular_memory->ReadFully(value, reg_ptr, sizeof(AddressType))) {
+ last_error_ = DWARF_ERROR_MEMORY_INVALID;
+ return false;
+ }
+ } else {
+ *reg_ptr = value;
+ }
+ break;
+ }
+ case DWARF_LOCATION_UNDEFINED:
+ if (reg == eval_info->cie->return_address_register) {
+ eval_info->return_address_undefined = true;
+ }
+ default:
+ break;
+ }
+
+ return true;
+}
+
+template <typename AddressType>
bool DwarfSectionImpl<AddressType>::Eval(const DwarfCie* cie, Memory* regular_memory,
const dwarf_loc_regs_t& loc_regs, Regs* regs,
bool* finished) {
@@ -114,9 +194,13 @@
return false;
}
+ // Always set the dex pc to zero when evaluating.
+ cur_regs->set_dex_pc(0);
+
AddressType prev_cfa = regs->sp();
- AddressType cfa;
+ EvalInfo<AddressType> eval_info{
+ .loc_regs = &loc_regs, .cie = cie, .regular_memory = regular_memory, .cur_regs = cur_regs};
const DwarfLocation* loc = &cfa_entry->second;
// Only a few location types are valid for the cfa.
switch (loc->type) {
@@ -129,11 +213,11 @@
// pointer register does not have any associated location
// information, use the current cfa value.
if (regs->sp_reg() == loc->values[0] && loc_regs.count(regs->sp_reg()) == 0) {
- cfa = prev_cfa;
+ eval_info.cfa = prev_cfa;
} else {
- cfa = (*cur_regs)[loc->values[0]];
+ eval_info.cfa = (*cur_regs)[loc->values[0]];
}
- cfa += loc->values[1];
+ eval_info.cfa += loc->values[1];
break;
case DWARF_LOCATION_EXPRESSION:
case DWARF_LOCATION_VAL_EXPRESSION: {
@@ -142,12 +226,12 @@
return false;
}
if (loc->type == DWARF_LOCATION_EXPRESSION) {
- if (!regular_memory->ReadFully(value, &cfa, sizeof(AddressType))) {
+ if (!regular_memory->ReadFully(value, &eval_info.cfa, sizeof(AddressType))) {
last_error_ = DWARF_ERROR_MEMORY_INVALID;
return false;
}
} else {
- cfa = value;
+ eval_info.cfa = value;
}
break;
}
@@ -156,81 +240,38 @@
return false;
}
- // This code is not guaranteed to work in cases where a register location
- // is a double indirection to the actual value. For example, if r3 is set
- // to r5 + 4, and r5 is set to CFA + 4, then this won't necessarily work
- // because it does not guarantee that r5 is evaluated before r3.
- // Check that this case does not exist, and error if it does.
- bool return_address_undefined = false;
for (const auto& entry : loc_regs) {
- uint16_t reg = entry.first;
+ uint32_t reg = entry.first;
// Already handled the CFA register.
if (reg == CFA_REG) continue;
- if (reg >= cur_regs->total_regs()) {
- // Skip this unknown register.
+ AddressType* reg_ptr;
+ AddressType dex_pc = 0;
+ if (reg == DEX_PC_REG) {
+ // Special register that indicates this is a dex pc.
+ dex_pc = 0;
+ reg_ptr = &dex_pc;
+ } else if (reg >= cur_regs->total_regs() || eval_info.reg_map & (1 << reg)) {
+ // Skip this unknown register, or a register that has already been
+ // processed.
continue;
+ } else {
+ reg_ptr = &(*cur_regs)[reg];
+ eval_info.reg_map |= 1 << reg;
+ eval_info.reg_values[reg] = *reg_ptr;
}
- const DwarfLocation* loc = &entry.second;
- switch (loc->type) {
- case DWARF_LOCATION_OFFSET:
- if (!regular_memory->ReadFully(cfa + loc->values[0], &(*cur_regs)[reg],
- sizeof(AddressType))) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
- return false;
- }
- break;
- case DWARF_LOCATION_VAL_OFFSET:
- (*cur_regs)[reg] = cfa + loc->values[0];
- break;
- case DWARF_LOCATION_REGISTER: {
- uint16_t cur_reg = loc->values[0];
- if (cur_reg >= cur_regs->total_regs()) {
- last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
- return false;
- }
- if (loc_regs.find(cur_reg) != loc_regs.end()) {
- // This is a double indirection, a register definition references
- // another register which is also defined as something other
- // than a register.
- log(0,
- "Invalid indirection: register %d references register %d which is "
- "not a plain register.\n",
- reg, cur_reg);
- last_error_ = DWARF_ERROR_ILLEGAL_STATE;
- return false;
- }
- (*cur_regs)[reg] = (*cur_regs)[cur_reg] + loc->values[1];
- break;
- }
- case DWARF_LOCATION_EXPRESSION:
- case DWARF_LOCATION_VAL_EXPRESSION: {
- AddressType value;
- if (!EvalExpression(*loc, cie->version, regular_memory, &value)) {
- return false;
- }
- if (loc->type == DWARF_LOCATION_EXPRESSION) {
- if (!regular_memory->ReadFully(value, &(*cur_regs)[reg], sizeof(AddressType))) {
- last_error_ = DWARF_ERROR_MEMORY_INVALID;
- return false;
- }
- } else {
- (*cur_regs)[reg] = value;
- }
- break;
- }
- case DWARF_LOCATION_UNDEFINED:
- if (reg == cie->return_address_register) {
- return_address_undefined = true;
- }
- default:
- break;
+ if (!EvalRegister(&entry.second, reg, reg_ptr, &eval_info)) {
+ return false;
+ }
+
+ if (reg == DEX_PC_REG) {
+ cur_regs->set_dex_pc(dex_pc);
}
}
// Find the return address location.
- if (return_address_undefined) {
+ if (eval_info.return_address_undefined) {
cur_regs->set_pc(0);
} else {
cur_regs->set_pc((*cur_regs)[cie->return_address_register]);
@@ -239,7 +280,7 @@
// If the pc was set to zero, consider this the final frame.
*finished = (cur_regs->pc() == 0) ? true : false;
- cur_regs->set_sp(cfa);
+ cur_regs->set_sp(eval_info.cfa);
return true;
}
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index b0a1c0c..d711772 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -40,6 +40,7 @@
frame->num = frame_num;
frame->sp = regs_->sp();
frame->rel_pc = adjusted_rel_pc;
+ frame->dex_pc = regs_->dex_pc();
if (map_info == nullptr) {
frame->pc = regs_->pc();
diff --git a/libunwindstack/include/unwindstack/DwarfLocation.h b/libunwindstack/include/unwindstack/DwarfLocation.h
index 3467e6a..0881182 100644
--- a/libunwindstack/include/unwindstack/DwarfLocation.h
+++ b/libunwindstack/include/unwindstack/DwarfLocation.h
@@ -38,7 +38,7 @@
uint64_t values[2];
};
-typedef std::unordered_map<uint16_t, DwarfLocation> dwarf_loc_regs_t;
+typedef std::unordered_map<uint32_t, DwarfLocation> dwarf_loc_regs_t;
} // namespace unwindstack
diff --git a/libunwindstack/include/unwindstack/DwarfSection.h b/libunwindstack/include/unwindstack/DwarfSection.h
index 10be6b4..e0004aa 100644
--- a/libunwindstack/include/unwindstack/DwarfSection.h
+++ b/libunwindstack/include/unwindstack/DwarfSection.h
@@ -132,6 +132,8 @@
const DwarfFde* GetFdeFromIndex(size_t index) override;
+ bool EvalRegister(const DwarfLocation* loc, uint32_t reg, AddressType* reg_ptr, void* info);
+
bool Eval(const DwarfCie* cie, Memory* regular_memory, const dwarf_loc_regs_t& loc_regs,
Regs* regs, bool* finished) override;
diff --git a/libunwindstack/include/unwindstack/Regs.h b/libunwindstack/include/unwindstack/Regs.h
index 1904d4d..a5ba7a0 100644
--- a/libunwindstack/include/unwindstack/Regs.h
+++ b/libunwindstack/include/unwindstack/Regs.h
@@ -57,6 +57,9 @@
virtual uint64_t pc() = 0;
virtual uint64_t sp() = 0;
+ uint64_t dex_pc() { return dex_pc_; }
+ void set_dex_pc(uint64_t dex_pc) { dex_pc_ = dex_pc; }
+
virtual uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) = 0;
virtual bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) = 0;
@@ -79,6 +82,7 @@
uint16_t total_regs_;
uint16_t sp_reg_;
Location return_loc_;
+ uint64_t dex_pc_ = 0;
};
template <typename AddressType>
diff --git a/libunwindstack/include/unwindstack/Unwinder.h b/libunwindstack/include/unwindstack/Unwinder.h
index 5adec4f..32858ae 100644
--- a/libunwindstack/include/unwindstack/Unwinder.h
+++ b/libunwindstack/include/unwindstack/Unwinder.h
@@ -41,6 +41,7 @@
uint64_t rel_pc;
uint64_t pc;
uint64_t sp;
+ uint64_t dex_pc;
std::string function_name;
uint64_t function_offset;
diff --git a/libunwindstack/tests/DwarfSectionImplTest.cpp b/libunwindstack/tests/DwarfSectionImplTest.cpp
index d54b0bf..dfd2ce0 100644
--- a/libunwindstack/tests/DwarfSectionImplTest.cpp
+++ b/libunwindstack/tests/DwarfSectionImplTest.cpp
@@ -266,13 +266,67 @@
regs.set_pc(0x100);
regs.set_sp(0x2000);
+ regs[1] = 0x100;
+ regs[3] = 0x300;
regs[8] = 0x10;
loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}};
- loc_regs[1] = DwarfLocation{DWARF_LOCATION_REGISTER, {3, 0}};
- loc_regs[9] = DwarfLocation{DWARF_LOCATION_REGISTER, {1, 0}};
+ loc_regs[1] = DwarfLocation{DWARF_LOCATION_REGISTER, {3, 1}};
+ loc_regs[9] = DwarfLocation{DWARF_LOCATION_REGISTER, {1, 2}};
bool finished;
- ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
- EXPECT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->section_->last_error());
+ ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
+ EXPECT_EQ(0x301U, regs[1]);
+ EXPECT_EQ(0x300U, regs[3]);
+ EXPECT_EQ(0x10U, regs[8]);
+ EXPECT_EQ(0x102U, regs[9]);
+}
+
+TYPED_TEST_P(DwarfSectionImplTest, Eval_register_reference_chain) {
+ DwarfCie cie{.return_address_register = 5};
+ RegsImplFake<TypeParam> regs(10, 9);
+ dwarf_loc_regs_t loc_regs;
+
+ regs.set_pc(0x100);
+ regs.set_sp(0x2000);
+ regs[0] = 0x10;
+ regs[1] = 0x20;
+ regs[2] = 0x30;
+ regs[3] = 0x40;
+ regs[4] = 0x50;
+ regs[5] = 0x60;
+ regs[8] = 0x20;
+ loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}};
+ loc_regs[1] = DwarfLocation{DWARF_LOCATION_REGISTER, {0, 1}};
+ loc_regs[2] = DwarfLocation{DWARF_LOCATION_REGISTER, {1, 2}};
+ loc_regs[3] = DwarfLocation{DWARF_LOCATION_REGISTER, {2, 3}};
+ loc_regs[4] = DwarfLocation{DWARF_LOCATION_REGISTER, {3, 4}};
+ loc_regs[5] = DwarfLocation{DWARF_LOCATION_REGISTER, {4, 5}};
+ bool finished;
+ ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
+ EXPECT_EQ(0x10U, regs[0]);
+ EXPECT_EQ(0x11U, regs[1]);
+ EXPECT_EQ(0x22U, regs[2]);
+ EXPECT_EQ(0x33U, regs[3]);
+ EXPECT_EQ(0x44U, regs[4]);
+ EXPECT_EQ(0x55U, regs[5]);
+ EXPECT_EQ(0x20U, regs[8]);
+}
+
+TYPED_TEST_P(DwarfSectionImplTest, Eval_dex_pc) {
+ DwarfCie cie{.return_address_register = 5};
+ RegsImplFake<TypeParam> regs(10, 9);
+ dwarf_loc_regs_t loc_regs;
+
+ regs.set_pc(0x100);
+ regs.set_sp(0x2000);
+ regs[0] = 0x10;
+ regs[8] = 0x20;
+ loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}};
+ loc_regs[0x20444558] = DwarfLocation{DWARF_LOCATION_REGISTER, {0, 1}};
+ bool finished;
+ ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
+ EXPECT_EQ(0x10U, regs[0]);
+ EXPECT_EQ(0x20U, regs[8]);
+ EXPECT_EQ(0x11U, regs.dex_pc());
}
TYPED_TEST_P(DwarfSectionImplTest, Eval_invalid_register) {
@@ -840,11 +894,11 @@
DwarfSectionImplTest, Eval_cfa_expr_eval_fail, Eval_cfa_expr_no_stack,
Eval_cfa_expr_is_register, Eval_cfa_expr, Eval_cfa_val_expr, Eval_bad_regs, Eval_no_cfa,
Eval_cfa_bad, Eval_cfa_register_prev, Eval_cfa_register_from_value, Eval_double_indirection,
- Eval_invalid_register, Eval_different_reg_locations, Eval_return_address_undefined,
- Eval_pc_zero, Eval_return_address, Eval_ignore_large_reg_loc, Eval_reg_expr, Eval_reg_val_expr,
- GetCie_fail_should_not_cache, GetCie_32_version_check, GetCie_negative_data_alignment_factor,
- GetCie_64_no_augment, GetCie_augment, GetCie_version_3, GetCie_version_4,
- GetFdeFromOffset_fail_should_not_cache, GetFdeFromOffset_32_no_augment,
+ Eval_register_reference_chain, Eval_dex_pc, Eval_invalid_register, Eval_different_reg_locations,
+ Eval_return_address_undefined, Eval_pc_zero, Eval_return_address, Eval_ignore_large_reg_loc,
+ Eval_reg_expr, Eval_reg_val_expr, GetCie_fail_should_not_cache, GetCie_32_version_check,
+ GetCie_negative_data_alignment_factor, GetCie_64_no_augment, GetCie_augment, GetCie_version_3,
+ GetCie_version_4, GetFdeFromOffset_fail_should_not_cache, GetFdeFromOffset_32_no_augment,
GetFdeFromOffset_32_no_augment_non_zero_segment_size, GetFdeFromOffset_32_augment,
GetFdeFromOffset_64_no_augment, GetFdeFromOffset_cached, GetCfaLocationInfo_cie_not_cached,
GetCfaLocationInfo_cie_cached, Log);
diff --git a/libunwindstack/tools/unwind.cpp b/libunwindstack/tools/unwind.cpp
index 07e48af..33e5527 100644
--- a/libunwindstack/tools/unwind.cpp
+++ b/libunwindstack/tools/unwind.cpp
@@ -96,8 +96,13 @@
unwinder.Unwind();
// Print the frames.
+ const std::vector<unwindstack::FrameData>& frames = unwinder.frames();
for (size_t i = 0; i < unwinder.NumFrames(); i++) {
printf("%s\n", unwinder.FormatFrame(i).c_str());
+ const unwindstack::FrameData* frame = &frames[i];
+ if (frame->dex_pc != 0) {
+ printf(" dex pc %" PRIx64 "\n", frame->dex_pc);
+ }
}
}
diff --git a/libutils/Android.bp b/libutils/Android.bp
index 6b50f0c..3bca6c8 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -43,8 +43,8 @@
},
}
-cc_library {
- name: "libutils",
+cc_defaults {
+ name: "libutils_defaults",
vendor_available: true,
vndk: {
enabled: true,
@@ -52,29 +52,6 @@
},
host_supported: true,
- srcs: [
- "CallStack.cpp",
- "FileMap.cpp",
- "JenkinsHash.cpp",
- "NativeHandle.cpp",
- "Printer.cpp",
- "PropertyMap.cpp",
- "RefBase.cpp",
- "SharedBuffer.cpp",
- "Static.cpp",
- "StopWatch.cpp",
- "String8.cpp",
- "String16.cpp",
- "StrongPointer.cpp",
- "SystemClock.cpp",
- "Threads.cpp",
- "Timers.cpp",
- "Tokenizer.cpp",
- "Unicode.cpp",
- "VectorImpl.cpp",
- "misc.cpp",
- ],
-
cflags: ["-Wall", "-Werror"],
include_dirs: ["external/safe-iop/include"],
header_libs: [
@@ -96,14 +73,9 @@
target: {
android: {
- srcs: [
- "Trace.cpp",
- ],
-
cflags: ["-fvisibility=protected"],
shared_libs: [
- "libbacktrace",
"libcutils",
"libdl",
"libvndksupport",
@@ -113,12 +85,6 @@
misc_undefined: ["integer"],
},
},
- linux: {
- srcs: [
- "Looper.cpp",
- "ProcessCallStack.cpp",
- ],
- },
host: {
cflags: ["-DLIBUTILS_NATIVE=1"],
@@ -148,6 +114,75 @@
},
}
+cc_library {
+ name: "libutils",
+ defaults: ["libutils_defaults"],
+
+ srcs: [
+ "FileMap.cpp",
+ "JenkinsHash.cpp",
+ "NativeHandle.cpp",
+ "Printer.cpp",
+ "PropertyMap.cpp",
+ "RefBase.cpp",
+ "SharedBuffer.cpp",
+ "Static.cpp",
+ "StopWatch.cpp",
+ "String8.cpp",
+ "String16.cpp",
+ "StrongPointer.cpp",
+ "SystemClock.cpp",
+ "Threads.cpp",
+ "Timers.cpp",
+ "Tokenizer.cpp",
+ "Unicode.cpp",
+ "VectorImpl.cpp",
+ "misc.cpp",
+ ],
+
+ target: {
+ android: {
+ srcs: [
+ "Trace.cpp",
+ ],
+ },
+ linux: {
+ srcs: [
+ "Looper.cpp",
+ ],
+ },
+ },
+}
+
+cc_library {
+ name: "libutilscallstack",
+ defaults: ["libutils_defaults"],
+
+ srcs: [
+ "CallStack.cpp",
+ ],
+
+ arch: {
+ mips: {
+ cflags: ["-DALIGN_DOUBLE"],
+ },
+ },
+
+ target: {
+ android: {
+ shared_libs: [
+ "libutils",
+ "libbacktrace",
+ ],
+ },
+ linux: {
+ srcs: [
+ "ProcessCallStack.cpp",
+ ],
+ },
+ },
+}
+
// Include subdirectory makefiles
// ============================================================
diff --git a/property_service/libpropertyinfoserializer/property_info_file.cpp b/property_service/libpropertyinfoserializer/property_info_file.cpp
index bf96d88..2cdc62d 100644
--- a/property_service/libpropertyinfoserializer/property_info_file.cpp
+++ b/property_service/libpropertyinfoserializer/property_info_file.cpp
@@ -1,9 +1,26 @@
+//
+// 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 <property_info_serializer/property_info_serializer.h>
#include <android-base/strings.h>
#include "space_tokenizer.h"
+using android::base::Join;
using android::base::Split;
using android::base::StartsWith;
using android::base::Trim;
@@ -11,6 +28,34 @@
namespace android {
namespace properties {
+namespace {
+
+bool IsTypeValid(const std::vector<std::string>& type_strings) {
+ if (type_strings.empty()) {
+ return false;
+ }
+
+ // There must be at least one string following 'enum'
+ if (type_strings[0] == "enum") {
+ return type_strings.size() > 1;
+ }
+
+ // There should not be any string following any other types.
+ if (type_strings.size() != 1) {
+ return false;
+ }
+
+ // Check that the type matches one of remaining valid types.
+ static const char* const no_parameter_types[] = {"string", "bool", "int",
+ "uint", "double", "size"};
+ for (const auto& type : no_parameter_types) {
+ if (type_strings[0] == type) {
+ return true;
+ }
+ }
+ return false;
+}
+
bool ParsePropertyInfoLine(const std::string& line, PropertyInfoEntry* out, std::string* error) {
auto tokenizer = SpaceTokenizer(line);
@@ -26,14 +71,28 @@
return false;
}
- // It is not an error to not find these, as older files will not contain them.
+ // It is not an error to not find exact_match or a type, as older files will not contain them.
auto exact_match = tokenizer.GetNext();
- auto type = tokenizer.GetRemaining();
+ // We reformat type to be space deliminated regardless of the input whitespace for easier storage
+ // and subsequent parsing.
+ auto type_strings = std::vector<std::string>{};
+ auto type = tokenizer.GetNext();
+ while (!type.empty()) {
+ type_strings.emplace_back(type);
+ type = tokenizer.GetNext();
+ }
- *out = {property, context, type, exact_match == "exact"};
+ if (!type_strings.empty() && !IsTypeValid(type_strings)) {
+ *error = "Type '" + Join(type_strings, " ") + "' is not valid";
+ return false;
+ }
+
+ *out = {property, context, Join(type_strings, " "), exact_match == "exact"};
return true;
}
+} // namespace
+
void ParsePropertyInfoFile(const std::string& file_contents,
std::vector<PropertyInfoEntry>* property_infos,
std::vector<std::string>* errors) {
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 6ea598d..6a1872f 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -459,6 +459,7 @@
# For security reasons, /data/local/tmp should always be empty.
# Do not place files or directories in /data/local/tmp
mkdir /data/local/tmp 0771 shell shell
+ mkdir /data/local/traces 0777 shell shell
mkdir /data/data 0771 system system
mkdir /data/app-private 0771 system system
mkdir /data/app-ephemeral 0771 system system