Loading debuggerd/debuggerd_test.cpp +17 −10 Original line number Diff line number Diff line Loading @@ -1409,6 +1409,16 @@ __attribute__((noinline)) extern "C" bool raise_debugger_signal(DebuggerdDumpTyp return true; } extern "C" void foo() { LOG(INFO) << "foo"; std::this_thread::sleep_for(1s); } extern "C" void bar() { LOG(INFO) << "bar"; std::this_thread::sleep_for(1s); } TEST_F(CrasherTest, seccomp_tombstone) { int intercept_result; unique_fd output_fd; Loading @@ -1416,6 +1426,11 @@ TEST_F(CrasherTest, seccomp_tombstone) { static const auto dump_type = kDebuggerdTombstone; StartProcess( []() { std::thread a(foo); std::thread b(bar); std::this_thread::sleep_for(100ms); raise_debugger_signal(dump_type); _exit(0); }, Loading @@ -1430,16 +1445,8 @@ TEST_F(CrasherTest, seccomp_tombstone) { std::string result; ConsumeFd(std::move(output_fd), &result); ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal"); } extern "C" void foo() { LOG(INFO) << "foo"; std::this_thread::sleep_for(1s); } extern "C" void bar() { LOG(INFO) << "bar"; std::this_thread::sleep_for(1s); ASSERT_BACKTRACE_FRAME(result, "foo"); ASSERT_BACKTRACE_FRAME(result, "bar"); } TEST_F(CrasherTest, seccomp_backtrace) { Loading debuggerd/handler/debuggerd_fallback.cpp +17 −44 Original line number Diff line number Diff line Loading @@ -98,32 +98,6 @@ static void debuggerd_fallback_tombstone(int output_fd, int proto_fd, ucontext_t __linker_disable_fallback_allocator(); } static void iterate_siblings(bool (*callback)(pid_t, int), int output_fd) { pid_t current_tid = gettid(); char buf[BUFSIZ]; snprintf(buf, sizeof(buf), "/proc/%d/task", current_tid); DIR* dir = opendir(buf); if (!dir) { async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to open %s: %s", buf, strerror(errno)); return; } struct dirent* ent; while ((ent = readdir(dir))) { char* end; long tid = strtol(ent->d_name, &end, 10); if (end == ent->d_name || *end != '\0') { continue; } if (tid != current_tid) { callback(tid, output_fd); } } closedir(dir); } static bool forward_output(int src_fd, int dst_fd, pid_t expected_tid) { // Make sure the thread actually got the signal. struct pollfd pfd = { Loading Loading @@ -216,21 +190,21 @@ static void trace_handler(siginfo_t* info, ucontext_t* ucontext) { } // Only allow one thread to perform a trace at a time. static pthread_mutex_t trace_mutex = PTHREAD_MUTEX_INITIALIZER; int ret = pthread_mutex_trylock(&trace_mutex); if (ret != 0) { async_safe_format_log(ANDROID_LOG_INFO, "libc", "pthread_mutex_try_lock failed: %s", strerror(ret)); static std::mutex trace_mutex; if (!trace_mutex.try_lock()) { async_safe_format_log(ANDROID_LOG_INFO, "libc", "trace lock failed"); return; } std::lock_guard<std::mutex> scoped_lock(trace_mutex, std::adopt_lock); // Fetch output fd from tombstoned. unique_fd tombstone_socket, output_fd; if (!tombstoned_connect(getpid(), &tombstone_socket, &output_fd, nullptr, kDebuggerdNativeBacktrace)) { async_safe_format_log(ANDROID_LOG_ERROR, "libc", "missing crash_dump_fallback() in selinux policy?"); goto exit; return; } dump_backtrace_header(output_fd.get()); Loading @@ -239,15 +213,15 @@ static void trace_handler(siginfo_t* info, ucontext_t* ucontext) { debuggerd_fallback_trace(output_fd.get(), ucontext); // Send a signal to all of our siblings, asking them to dump their stack. iterate_siblings( [](pid_t tid, int output_fd) { pid_t current_tid = gettid(); if (!iterate_tids(current_tid, [&output_fd](pid_t tid) { // Use a pipe, to be able to detect situations where the thread gracefully exits before // receiving our signal. unique_fd pipe_read, pipe_write; if (!Pipe(&pipe_read, &pipe_write)) { async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to create pipe: %s", strerror(errno)); return false; return; } uint64_t expected = pack_thread_fd(-1, -1); Loading @@ -257,7 +231,7 @@ static void trace_handler(siginfo_t* info, ucontext_t* ucontext) { async_safe_format_log(ANDROID_LOG_ERROR, "libc", "thread %d is already outputting to fd %d?", tid, fd); close(sent_fd); return false; return; } siginfo_t siginfo = {}; Loading @@ -269,10 +243,10 @@ static void trace_handler(siginfo_t* info, ucontext_t* ucontext) { if (syscall(__NR_rt_tgsigqueueinfo, getpid(), tid, BIONIC_SIGNAL_DEBUGGER, &siginfo) != 0) { async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to send trace signal to %d: %s", tid, strerror(errno)); return false; return; } bool success = forward_output(pipe_read.get(), output_fd, tid); bool success = forward_output(pipe_read.get(), output_fd.get(), tid); if (!success) { async_safe_format_log(ANDROID_LOG_ERROR, "libc", "timeout expired while waiting for thread %d to dump", tid); Loading @@ -288,15 +262,14 @@ static void trace_handler(siginfo_t* info, ucontext_t* ucontext) { } } return true; }, output_fd.get()); return; })) { async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to open /proc/%d/task: %s", current_tid, strerror(errno)); } dump_backtrace_footer(output_fd.get()); tombstoned_notify_completion(tombstone_socket.get()); exit: pthread_mutex_unlock(&trace_mutex); } static void crash_handler(siginfo_t* info, ucontext_t* ucontext, void* abort_message) { Loading debuggerd/libdebuggerd/tombstone.cpp +28 −9 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ #include <stddef.h> #include <stdio.h> #include <stdlib.h> #include <sys/prctl.h> #include <sys/types.h> #include <unistd.h> Loading Loading @@ -73,22 +74,40 @@ void engrave_tombstone_ucontext(int tombstone_fd, int proto_fd, uint64_t abort_m std::map<pid_t, ThreadInfo> threads; threads[tid] = ThreadInfo{ .registers = std::move(regs), .uid = uid, .tid = tid, .thread_name = std::move(thread_name), .pid = pid, .command_line = std::move(command_line), .selinux_label = std::move(selinux_label), .registers = std::move(regs), .uid = uid, .tid = tid, .thread_name = std::move(thread_name), .pid = pid, .command_line = std::move(command_line), .selinux_label = std::move(selinux_label), .siginfo = siginfo, #if defined(__aarch64__) // Only supported on aarch64 for now. .tagged_addr_ctrl = prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0), .pac_enabled_keys = prctl(PR_PAC_GET_ENABLED_KEYS, 0, 0, 0, 0), #endif }; if (pid == tid) { const ThreadInfo& thread = threads[pid]; if (!iterate_tids(pid, [&threads, &thread](pid_t tid) { threads[tid] = ThreadInfo{ .uid = thread.uid, .tid = tid, .pid = thread.pid, .command_line = thread.command_line, .thread_name = get_thread_name(tid), .tagged_addr_ctrl = thread.tagged_addr_ctrl, .pac_enabled_keys = thread.pac_enabled_keys, }; })) { async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, "failed to open /proc/%d/task: %s", pid, strerror(errno)); } } unwindstack::UnwinderFromPid unwinder(kMaxFrames, pid, unwindstack::Regs::CurrentArch()); auto process_memory = unwindstack::Memory::CreateProcessMemoryCached(getpid()); unwinder.SetProcessMemory(process_memory); if (!unwinder.Init()) { async_safe_fatal("failed to init unwinder object"); async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, "failed to init unwinder object"); return; } ProcessInfo process_info; Loading debuggerd/libdebuggerd/tombstone_proto.cpp +106 −82 Original line number Diff line number Diff line Loading @@ -48,6 +48,7 @@ #include <android/log.h> #include <bionic/macros.h> #include <bionic/reserved_signals.h> #include <log/log.h> #include <log/log_read.h> #include <log/logprint.h> Loading Loading @@ -346,20 +347,17 @@ void fill_in_backtrace_frame(BacktraceFrame* f, const unwindstack::FrameData& fr f->set_build_id(frame.map_info->GetPrintableBuildID()); } static void dump_thread(Tombstone* tombstone, unwindstack::Unwinder* unwinder, const ThreadInfo& thread_info, bool memory_dump = false) { Thread thread; thread.set_id(thread_info.tid); thread.set_name(thread_info.thread_name); thread.set_tagged_addr_ctrl(thread_info.tagged_addr_ctrl); thread.set_pac_enabled_keys(thread_info.pac_enabled_keys); static void dump_registers(unwindstack::Unwinder* unwinder, const std::unique_ptr<unwindstack::Regs>& regs, Thread& thread, bool memory_dump) { if (regs == nullptr) { return; } unwindstack::Maps* maps = unwinder->GetMaps(); unwindstack::Memory* memory = unwinder->GetProcessMemory().get(); thread_info.registers->IterateRegisters( [&thread, memory_dump, maps, memory](const char* name, uint64_t value) { regs->IterateRegisters([&thread, memory_dump, maps, memory](const char* name, uint64_t value) { Register r; r.set_name(name); r.set_u64(value); Loading @@ -378,18 +376,11 @@ static void dump_thread(Tombstone* tombstone, unwindstack::Unwinder* unwinder, constexpr size_t kNumTagsAroundRegister = kNumBytesAroundRegister / kTagGranuleSize; char buf[kNumBytesAroundRegister]; uint8_t tags[kNumTagsAroundRegister]; size_t start_offset = 0; ssize_t bytes = dump_memory(buf, sizeof(buf), tags, sizeof(tags), &value, memory); if (bytes == -1) { return; } dump.set_begin_address(value); if (start_offset + bytes > sizeof(buf)) { async_safe_fatal("dump_memory overflowed? start offset = %zu, bytes read = %zd", start_offset, bytes); } dump.set_memory(buf, bytes); bool has_tags = false; Loading @@ -408,25 +399,31 @@ static void dump_thread(Tombstone* tombstone, unwindstack::Unwinder* unwinder, *thread.add_memory_dump() = std::move(dump); } }); } static void log_unwinder_error(unwindstack::Unwinder* unwinder) { if (unwinder->LastErrorCode() == unwindstack::ERROR_NONE) { return; } std::unique_ptr<unwindstack::Regs> regs_copy(thread_info.registers->Clone()); unwinder->SetRegs(regs_copy.get()); unwinder->Unwind(); if (unwinder->NumFrames() == 0) { async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, "failed to unwind"); if (unwinder->LastErrorCode() != unwindstack::ERROR_NONE) { async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, " error code: %s", unwinder->LastErrorCodeString()); async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, " error address: 0x%" PRIx64, unwinder->LastErrorAddress()); } } else { static void dump_thread_backtrace(unwindstack::Unwinder* unwinder, Thread& thread) { if (unwinder->NumFrames() == 0) { async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, "failed to unwind"); log_unwinder_error(unwinder); return; } if (unwinder->elf_from_memory_not_file()) { auto backtrace_note = thread.mutable_backtrace_note(); *backtrace_note->Add() = "Function names and BuildId information is missing for some frames due"; *backtrace_note->Add() = "to unreadable libraries. For unwinds of apps, only shared libraries"; *backtrace_note->Add() = "to unreadable libraries. For unwinds of apps, only shared libraries"; *backtrace_note->Add() = "found under the lib/ directory are readable."; *backtrace_note->Add() = "On this device, run setenforce 0 to make the libraries readable."; } Loading @@ -437,13 +434,39 @@ static void dump_thread(Tombstone* tombstone, unwindstack::Unwinder* unwinder, } } auto& threads = *tombstone->mutable_threads(); threads[thread_info.tid] = thread; static void dump_thread(Tombstone* tombstone, unwindstack::Unwinder* unwinder, const ThreadInfo& thread_info, bool memory_dump = false) { Thread thread; thread.set_id(thread_info.tid); thread.set_name(thread_info.thread_name); thread.set_tagged_addr_ctrl(thread_info.tagged_addr_ctrl); thread.set_pac_enabled_keys(thread_info.pac_enabled_keys); if (thread_info.pid == getpid() && thread_info.pid != thread_info.tid) { // Fallback path for non-main thread, doing unwind from running process. unwindstack::ThreadUnwinder thread_unwinder(kMaxFrames, unwinder->GetMaps()); if (!thread_unwinder.Init()) { async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, "Unable to initialize ThreadUnwinder object."); log_unwinder_error(&thread_unwinder); return; } std::unique_ptr<unwindstack::Regs> initial_regs; thread_unwinder.UnwindWithSignal(BIONIC_SIGNAL_BACKTRACE, thread_info.tid, &initial_regs); dump_registers(&thread_unwinder, initial_regs, thread, memory_dump); dump_thread_backtrace(&thread_unwinder, thread); } else { dump_registers(unwinder, thread_info.registers, thread, memory_dump); std::unique_ptr<unwindstack::Regs> regs_copy(thread_info.registers->Clone()); unwinder->SetRegs(regs_copy.get()); unwinder->Unwind(); dump_thread_backtrace(unwinder, thread); } static void dump_main_thread(Tombstone* tombstone, unwindstack::Unwinder* unwinder, const ThreadInfo& thread_info) { dump_thread(tombstone, unwinder, thread_info, true); auto& threads = *tombstone->mutable_threads(); threads[thread_info.tid] = thread; } static void dump_mappings(Tombstone* tombstone, unwindstack::Unwinder* unwinder) { Loading Loading @@ -663,7 +686,8 @@ void engrave_tombstone_proto(Tombstone* tombstone, unwindstack::Unwinder* unwind dump_abort_message(&result, unwinder, process_info); dump_main_thread(&result, unwinder, main_thread); // Dump the main thread, but save the memory around the registers. dump_thread(&result, unwinder, main_thread, /* memory_dump */ true); for (const auto& [tid, thread_info] : threads) { if (tid != target_thread) { Loading debuggerd/seccomp_policy/crash_dump.arm64.policy +1 −1 Original line number Diff line number Diff line Loading @@ -25,7 +25,7 @@ tgkill: 1 rt_sigprocmask: 1 rt_sigaction: 1 rt_tgsigqueueinfo: 1 prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == 0x53564d41 || arg0 == PR_PAC_RESET_KEYS prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == 0x53564d41 || arg0 == PR_PAC_RESET_KEYS || arg0 == PR_GET_TAGGED_ADDR_CTRL || arg0 == PR_PAC_GET_ENABLED_KEYS madvise: 1 mprotect: arg2 in 0x1|0x2 munmap: 1 Loading Loading
debuggerd/debuggerd_test.cpp +17 −10 Original line number Diff line number Diff line Loading @@ -1409,6 +1409,16 @@ __attribute__((noinline)) extern "C" bool raise_debugger_signal(DebuggerdDumpTyp return true; } extern "C" void foo() { LOG(INFO) << "foo"; std::this_thread::sleep_for(1s); } extern "C" void bar() { LOG(INFO) << "bar"; std::this_thread::sleep_for(1s); } TEST_F(CrasherTest, seccomp_tombstone) { int intercept_result; unique_fd output_fd; Loading @@ -1416,6 +1426,11 @@ TEST_F(CrasherTest, seccomp_tombstone) { static const auto dump_type = kDebuggerdTombstone; StartProcess( []() { std::thread a(foo); std::thread b(bar); std::this_thread::sleep_for(100ms); raise_debugger_signal(dump_type); _exit(0); }, Loading @@ -1430,16 +1445,8 @@ TEST_F(CrasherTest, seccomp_tombstone) { std::string result; ConsumeFd(std::move(output_fd), &result); ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal"); } extern "C" void foo() { LOG(INFO) << "foo"; std::this_thread::sleep_for(1s); } extern "C" void bar() { LOG(INFO) << "bar"; std::this_thread::sleep_for(1s); ASSERT_BACKTRACE_FRAME(result, "foo"); ASSERT_BACKTRACE_FRAME(result, "bar"); } TEST_F(CrasherTest, seccomp_backtrace) { Loading
debuggerd/handler/debuggerd_fallback.cpp +17 −44 Original line number Diff line number Diff line Loading @@ -98,32 +98,6 @@ static void debuggerd_fallback_tombstone(int output_fd, int proto_fd, ucontext_t __linker_disable_fallback_allocator(); } static void iterate_siblings(bool (*callback)(pid_t, int), int output_fd) { pid_t current_tid = gettid(); char buf[BUFSIZ]; snprintf(buf, sizeof(buf), "/proc/%d/task", current_tid); DIR* dir = opendir(buf); if (!dir) { async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to open %s: %s", buf, strerror(errno)); return; } struct dirent* ent; while ((ent = readdir(dir))) { char* end; long tid = strtol(ent->d_name, &end, 10); if (end == ent->d_name || *end != '\0') { continue; } if (tid != current_tid) { callback(tid, output_fd); } } closedir(dir); } static bool forward_output(int src_fd, int dst_fd, pid_t expected_tid) { // Make sure the thread actually got the signal. struct pollfd pfd = { Loading Loading @@ -216,21 +190,21 @@ static void trace_handler(siginfo_t* info, ucontext_t* ucontext) { } // Only allow one thread to perform a trace at a time. static pthread_mutex_t trace_mutex = PTHREAD_MUTEX_INITIALIZER; int ret = pthread_mutex_trylock(&trace_mutex); if (ret != 0) { async_safe_format_log(ANDROID_LOG_INFO, "libc", "pthread_mutex_try_lock failed: %s", strerror(ret)); static std::mutex trace_mutex; if (!trace_mutex.try_lock()) { async_safe_format_log(ANDROID_LOG_INFO, "libc", "trace lock failed"); return; } std::lock_guard<std::mutex> scoped_lock(trace_mutex, std::adopt_lock); // Fetch output fd from tombstoned. unique_fd tombstone_socket, output_fd; if (!tombstoned_connect(getpid(), &tombstone_socket, &output_fd, nullptr, kDebuggerdNativeBacktrace)) { async_safe_format_log(ANDROID_LOG_ERROR, "libc", "missing crash_dump_fallback() in selinux policy?"); goto exit; return; } dump_backtrace_header(output_fd.get()); Loading @@ -239,15 +213,15 @@ static void trace_handler(siginfo_t* info, ucontext_t* ucontext) { debuggerd_fallback_trace(output_fd.get(), ucontext); // Send a signal to all of our siblings, asking them to dump their stack. iterate_siblings( [](pid_t tid, int output_fd) { pid_t current_tid = gettid(); if (!iterate_tids(current_tid, [&output_fd](pid_t tid) { // Use a pipe, to be able to detect situations where the thread gracefully exits before // receiving our signal. unique_fd pipe_read, pipe_write; if (!Pipe(&pipe_read, &pipe_write)) { async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to create pipe: %s", strerror(errno)); return false; return; } uint64_t expected = pack_thread_fd(-1, -1); Loading @@ -257,7 +231,7 @@ static void trace_handler(siginfo_t* info, ucontext_t* ucontext) { async_safe_format_log(ANDROID_LOG_ERROR, "libc", "thread %d is already outputting to fd %d?", tid, fd); close(sent_fd); return false; return; } siginfo_t siginfo = {}; Loading @@ -269,10 +243,10 @@ static void trace_handler(siginfo_t* info, ucontext_t* ucontext) { if (syscall(__NR_rt_tgsigqueueinfo, getpid(), tid, BIONIC_SIGNAL_DEBUGGER, &siginfo) != 0) { async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to send trace signal to %d: %s", tid, strerror(errno)); return false; return; } bool success = forward_output(pipe_read.get(), output_fd, tid); bool success = forward_output(pipe_read.get(), output_fd.get(), tid); if (!success) { async_safe_format_log(ANDROID_LOG_ERROR, "libc", "timeout expired while waiting for thread %d to dump", tid); Loading @@ -288,15 +262,14 @@ static void trace_handler(siginfo_t* info, ucontext_t* ucontext) { } } return true; }, output_fd.get()); return; })) { async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to open /proc/%d/task: %s", current_tid, strerror(errno)); } dump_backtrace_footer(output_fd.get()); tombstoned_notify_completion(tombstone_socket.get()); exit: pthread_mutex_unlock(&trace_mutex); } static void crash_handler(siginfo_t* info, ucontext_t* ucontext, void* abort_message) { Loading
debuggerd/libdebuggerd/tombstone.cpp +28 −9 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ #include <stddef.h> #include <stdio.h> #include <stdlib.h> #include <sys/prctl.h> #include <sys/types.h> #include <unistd.h> Loading Loading @@ -73,22 +74,40 @@ void engrave_tombstone_ucontext(int tombstone_fd, int proto_fd, uint64_t abort_m std::map<pid_t, ThreadInfo> threads; threads[tid] = ThreadInfo{ .registers = std::move(regs), .uid = uid, .tid = tid, .thread_name = std::move(thread_name), .pid = pid, .command_line = std::move(command_line), .selinux_label = std::move(selinux_label), .registers = std::move(regs), .uid = uid, .tid = tid, .thread_name = std::move(thread_name), .pid = pid, .command_line = std::move(command_line), .selinux_label = std::move(selinux_label), .siginfo = siginfo, #if defined(__aarch64__) // Only supported on aarch64 for now. .tagged_addr_ctrl = prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0), .pac_enabled_keys = prctl(PR_PAC_GET_ENABLED_KEYS, 0, 0, 0, 0), #endif }; if (pid == tid) { const ThreadInfo& thread = threads[pid]; if (!iterate_tids(pid, [&threads, &thread](pid_t tid) { threads[tid] = ThreadInfo{ .uid = thread.uid, .tid = tid, .pid = thread.pid, .command_line = thread.command_line, .thread_name = get_thread_name(tid), .tagged_addr_ctrl = thread.tagged_addr_ctrl, .pac_enabled_keys = thread.pac_enabled_keys, }; })) { async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, "failed to open /proc/%d/task: %s", pid, strerror(errno)); } } unwindstack::UnwinderFromPid unwinder(kMaxFrames, pid, unwindstack::Regs::CurrentArch()); auto process_memory = unwindstack::Memory::CreateProcessMemoryCached(getpid()); unwinder.SetProcessMemory(process_memory); if (!unwinder.Init()) { async_safe_fatal("failed to init unwinder object"); async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, "failed to init unwinder object"); return; } ProcessInfo process_info; Loading
debuggerd/libdebuggerd/tombstone_proto.cpp +106 −82 Original line number Diff line number Diff line Loading @@ -48,6 +48,7 @@ #include <android/log.h> #include <bionic/macros.h> #include <bionic/reserved_signals.h> #include <log/log.h> #include <log/log_read.h> #include <log/logprint.h> Loading Loading @@ -346,20 +347,17 @@ void fill_in_backtrace_frame(BacktraceFrame* f, const unwindstack::FrameData& fr f->set_build_id(frame.map_info->GetPrintableBuildID()); } static void dump_thread(Tombstone* tombstone, unwindstack::Unwinder* unwinder, const ThreadInfo& thread_info, bool memory_dump = false) { Thread thread; thread.set_id(thread_info.tid); thread.set_name(thread_info.thread_name); thread.set_tagged_addr_ctrl(thread_info.tagged_addr_ctrl); thread.set_pac_enabled_keys(thread_info.pac_enabled_keys); static void dump_registers(unwindstack::Unwinder* unwinder, const std::unique_ptr<unwindstack::Regs>& regs, Thread& thread, bool memory_dump) { if (regs == nullptr) { return; } unwindstack::Maps* maps = unwinder->GetMaps(); unwindstack::Memory* memory = unwinder->GetProcessMemory().get(); thread_info.registers->IterateRegisters( [&thread, memory_dump, maps, memory](const char* name, uint64_t value) { regs->IterateRegisters([&thread, memory_dump, maps, memory](const char* name, uint64_t value) { Register r; r.set_name(name); r.set_u64(value); Loading @@ -378,18 +376,11 @@ static void dump_thread(Tombstone* tombstone, unwindstack::Unwinder* unwinder, constexpr size_t kNumTagsAroundRegister = kNumBytesAroundRegister / kTagGranuleSize; char buf[kNumBytesAroundRegister]; uint8_t tags[kNumTagsAroundRegister]; size_t start_offset = 0; ssize_t bytes = dump_memory(buf, sizeof(buf), tags, sizeof(tags), &value, memory); if (bytes == -1) { return; } dump.set_begin_address(value); if (start_offset + bytes > sizeof(buf)) { async_safe_fatal("dump_memory overflowed? start offset = %zu, bytes read = %zd", start_offset, bytes); } dump.set_memory(buf, bytes); bool has_tags = false; Loading @@ -408,25 +399,31 @@ static void dump_thread(Tombstone* tombstone, unwindstack::Unwinder* unwinder, *thread.add_memory_dump() = std::move(dump); } }); } static void log_unwinder_error(unwindstack::Unwinder* unwinder) { if (unwinder->LastErrorCode() == unwindstack::ERROR_NONE) { return; } std::unique_ptr<unwindstack::Regs> regs_copy(thread_info.registers->Clone()); unwinder->SetRegs(regs_copy.get()); unwinder->Unwind(); if (unwinder->NumFrames() == 0) { async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, "failed to unwind"); if (unwinder->LastErrorCode() != unwindstack::ERROR_NONE) { async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, " error code: %s", unwinder->LastErrorCodeString()); async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, " error address: 0x%" PRIx64, unwinder->LastErrorAddress()); } } else { static void dump_thread_backtrace(unwindstack::Unwinder* unwinder, Thread& thread) { if (unwinder->NumFrames() == 0) { async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, "failed to unwind"); log_unwinder_error(unwinder); return; } if (unwinder->elf_from_memory_not_file()) { auto backtrace_note = thread.mutable_backtrace_note(); *backtrace_note->Add() = "Function names and BuildId information is missing for some frames due"; *backtrace_note->Add() = "to unreadable libraries. For unwinds of apps, only shared libraries"; *backtrace_note->Add() = "to unreadable libraries. For unwinds of apps, only shared libraries"; *backtrace_note->Add() = "found under the lib/ directory are readable."; *backtrace_note->Add() = "On this device, run setenforce 0 to make the libraries readable."; } Loading @@ -437,13 +434,39 @@ static void dump_thread(Tombstone* tombstone, unwindstack::Unwinder* unwinder, } } auto& threads = *tombstone->mutable_threads(); threads[thread_info.tid] = thread; static void dump_thread(Tombstone* tombstone, unwindstack::Unwinder* unwinder, const ThreadInfo& thread_info, bool memory_dump = false) { Thread thread; thread.set_id(thread_info.tid); thread.set_name(thread_info.thread_name); thread.set_tagged_addr_ctrl(thread_info.tagged_addr_ctrl); thread.set_pac_enabled_keys(thread_info.pac_enabled_keys); if (thread_info.pid == getpid() && thread_info.pid != thread_info.tid) { // Fallback path for non-main thread, doing unwind from running process. unwindstack::ThreadUnwinder thread_unwinder(kMaxFrames, unwinder->GetMaps()); if (!thread_unwinder.Init()) { async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, "Unable to initialize ThreadUnwinder object."); log_unwinder_error(&thread_unwinder); return; } std::unique_ptr<unwindstack::Regs> initial_regs; thread_unwinder.UnwindWithSignal(BIONIC_SIGNAL_BACKTRACE, thread_info.tid, &initial_regs); dump_registers(&thread_unwinder, initial_regs, thread, memory_dump); dump_thread_backtrace(&thread_unwinder, thread); } else { dump_registers(unwinder, thread_info.registers, thread, memory_dump); std::unique_ptr<unwindstack::Regs> regs_copy(thread_info.registers->Clone()); unwinder->SetRegs(regs_copy.get()); unwinder->Unwind(); dump_thread_backtrace(unwinder, thread); } static void dump_main_thread(Tombstone* tombstone, unwindstack::Unwinder* unwinder, const ThreadInfo& thread_info) { dump_thread(tombstone, unwinder, thread_info, true); auto& threads = *tombstone->mutable_threads(); threads[thread_info.tid] = thread; } static void dump_mappings(Tombstone* tombstone, unwindstack::Unwinder* unwinder) { Loading Loading @@ -663,7 +686,8 @@ void engrave_tombstone_proto(Tombstone* tombstone, unwindstack::Unwinder* unwind dump_abort_message(&result, unwinder, process_info); dump_main_thread(&result, unwinder, main_thread); // Dump the main thread, but save the memory around the registers. dump_thread(&result, unwinder, main_thread, /* memory_dump */ true); for (const auto& [tid, thread_info] : threads) { if (tid != target_thread) { Loading
debuggerd/seccomp_policy/crash_dump.arm64.policy +1 −1 Original line number Diff line number Diff line Loading @@ -25,7 +25,7 @@ tgkill: 1 rt_sigprocmask: 1 rt_sigaction: 1 rt_tgsigqueueinfo: 1 prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == 0x53564d41 || arg0 == PR_PAC_RESET_KEYS prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == 0x53564d41 || arg0 == PR_PAC_RESET_KEYS || arg0 == PR_GET_TAGGED_ADDR_CTRL || arg0 == PR_PAC_GET_ENABLED_KEYS madvise: 1 mprotect: arg2 in 0x1|0x2 munmap: 1 Loading