Loading debuggerd/crash_dump.cpp +7 −0 Original line number Diff line number Diff line Loading @@ -295,6 +295,13 @@ static void ReadCrashInfo(unique_fd& fd, siginfo_t* siginfo, case 3: process_info->abort_msg_address = crash_info->data.s.abort_msg_address; *siginfo = crash_info->data.s.siginfo; if (signal_has_si_addr(siginfo)) { // Make a copy of the ucontext field because otherwise it is not aligned enough (due to // being in a packed struct) and clang complains about that. ucontext_t ucontext = crash_info->data.s.ucontext; process_info->has_fault_address = true; process_info->fault_address = get_fault_address(siginfo, &ucontext); } regs->reset(unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(), &crash_info->data.s.ucontext)); break; Loading debuggerd/debuggerd_test.cpp +26 −0 Original line number Diff line number Diff line Loading @@ -305,6 +305,32 @@ TEST_F(CrasherTest, smoke) { ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0xdead)"); } TEST_F(CrasherTest, tagged_fault_addr) { #if !defined(__aarch64__) GTEST_SKIP() << "Requires aarch64"; #endif int intercept_result; unique_fd output_fd; StartProcess([]() { *reinterpret_cast<volatile char*>(0x100000000000dead) = '1'; }); StartIntercept(&output_fd); FinishCrasher(); AssertDeath(SIGSEGV); FinishIntercept(&intercept_result); ASSERT_EQ(1, intercept_result) << "tombstoned reported failure"; std::string result; ConsumeFd(std::move(output_fd), &result); // The address can either be tagged (new kernels) or untagged (old kernels). ASSERT_MATCH( result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr (0x100000000000dead|0xdead))"); } TEST_F(CrasherTest, LD_PRELOAD) { int intercept_result; unique_fd output_fd; Loading debuggerd/handler/debuggerd_handler.cpp +7 −4 Original line number Diff line number Diff line Loading @@ -167,7 +167,7 @@ static bool get_main_thread_name(char* buf, size_t len) { * mutex is being held, so we don't want to use any libc functions that * could allocate memory or hold a lock. */ static void log_signal_summary(const siginfo_t* info) { static void log_signal_summary(const siginfo_t* info, const ucontext_t* ucontext) { char thread_name[MAX_TASK_NAME_LEN + 1]; // one more for termination if (prctl(PR_GET_NAME, reinterpret_cast<unsigned long>(thread_name), 0, 0, 0) != 0) { strcpy(thread_name, "<name unknown>"); Loading @@ -186,7 +186,8 @@ static void log_signal_summary(const siginfo_t* info) { // Many signals don't have an address or sender. char addr_desc[32] = ""; // ", fault addr 0x1234" if (signal_has_si_addr(info)) { async_safe_format_buffer(addr_desc, sizeof(addr_desc), ", fault addr %p", info->si_addr); async_safe_format_buffer(addr_desc, sizeof(addr_desc), ", fault addr %p", reinterpret_cast<void*>(get_fault_address(info, ucontext))); } pid_t self_pid = __getpid(); char sender_desc[32] = {}; // " from pid 1234, uid 666" Loading Loading @@ -476,6 +477,8 @@ static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void* c // making a syscall and checking errno. ErrnoRestorer restorer; auto *ucontext = static_cast<ucontext_t*>(context); // It's possible somebody cleared the SA_SIGINFO flag, which would mean // our "info" arg holds an undefined value. if (!have_siginfo(signal_number)) { Loading Loading @@ -522,7 +525,7 @@ static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void* c // This check might be racy if another thread sets NO_NEW_PRIVS, but this should be unlikely, // you can only set NO_NEW_PRIVS to 1, and the effect should be at worst a single missing // ANR trace. debuggerd_fallback_handler(info, static_cast<ucontext_t*>(context), process_info.abort_msg); debuggerd_fallback_handler(info, ucontext, process_info.abort_msg); resend_signal(info); return; } Loading @@ -534,7 +537,7 @@ static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void* c return; } log_signal_summary(info); log_signal_summary(info, ucontext); debugger_thread_info thread_info = { .crashing_tid = __gettid(), Loading debuggerd/libdebuggerd/include/libdebuggerd/types.h +3 −0 Original line number Diff line number Diff line Loading @@ -41,4 +41,7 @@ struct ProcessInfo { uintptr_t fdsan_table_address = 0; uintptr_t gwp_asan_state = 0; uintptr_t gwp_asan_metadata = 0; bool has_fault_address = false; uintptr_t fault_address = 0; }; debuggerd/libdebuggerd/include/libdebuggerd/utility.h +2 −0 Original line number Diff line number Diff line Loading @@ -93,4 +93,6 @@ void get_signal_sender(char* buf, size_t n, const siginfo_t*); const char* get_signame(const siginfo_t*); const char* get_sigcode(const siginfo_t*); uintptr_t get_fault_address(const siginfo_t* siginfo, const ucontext_t* ucontext); #endif // _DEBUGGERD_UTILITY_H Loading
debuggerd/crash_dump.cpp +7 −0 Original line number Diff line number Diff line Loading @@ -295,6 +295,13 @@ static void ReadCrashInfo(unique_fd& fd, siginfo_t* siginfo, case 3: process_info->abort_msg_address = crash_info->data.s.abort_msg_address; *siginfo = crash_info->data.s.siginfo; if (signal_has_si_addr(siginfo)) { // Make a copy of the ucontext field because otherwise it is not aligned enough (due to // being in a packed struct) and clang complains about that. ucontext_t ucontext = crash_info->data.s.ucontext; process_info->has_fault_address = true; process_info->fault_address = get_fault_address(siginfo, &ucontext); } regs->reset(unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(), &crash_info->data.s.ucontext)); break; Loading
debuggerd/debuggerd_test.cpp +26 −0 Original line number Diff line number Diff line Loading @@ -305,6 +305,32 @@ TEST_F(CrasherTest, smoke) { ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0xdead)"); } TEST_F(CrasherTest, tagged_fault_addr) { #if !defined(__aarch64__) GTEST_SKIP() << "Requires aarch64"; #endif int intercept_result; unique_fd output_fd; StartProcess([]() { *reinterpret_cast<volatile char*>(0x100000000000dead) = '1'; }); StartIntercept(&output_fd); FinishCrasher(); AssertDeath(SIGSEGV); FinishIntercept(&intercept_result); ASSERT_EQ(1, intercept_result) << "tombstoned reported failure"; std::string result; ConsumeFd(std::move(output_fd), &result); // The address can either be tagged (new kernels) or untagged (old kernels). ASSERT_MATCH( result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr (0x100000000000dead|0xdead))"); } TEST_F(CrasherTest, LD_PRELOAD) { int intercept_result; unique_fd output_fd; Loading
debuggerd/handler/debuggerd_handler.cpp +7 −4 Original line number Diff line number Diff line Loading @@ -167,7 +167,7 @@ static bool get_main_thread_name(char* buf, size_t len) { * mutex is being held, so we don't want to use any libc functions that * could allocate memory or hold a lock. */ static void log_signal_summary(const siginfo_t* info) { static void log_signal_summary(const siginfo_t* info, const ucontext_t* ucontext) { char thread_name[MAX_TASK_NAME_LEN + 1]; // one more for termination if (prctl(PR_GET_NAME, reinterpret_cast<unsigned long>(thread_name), 0, 0, 0) != 0) { strcpy(thread_name, "<name unknown>"); Loading @@ -186,7 +186,8 @@ static void log_signal_summary(const siginfo_t* info) { // Many signals don't have an address or sender. char addr_desc[32] = ""; // ", fault addr 0x1234" if (signal_has_si_addr(info)) { async_safe_format_buffer(addr_desc, sizeof(addr_desc), ", fault addr %p", info->si_addr); async_safe_format_buffer(addr_desc, sizeof(addr_desc), ", fault addr %p", reinterpret_cast<void*>(get_fault_address(info, ucontext))); } pid_t self_pid = __getpid(); char sender_desc[32] = {}; // " from pid 1234, uid 666" Loading Loading @@ -476,6 +477,8 @@ static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void* c // making a syscall and checking errno. ErrnoRestorer restorer; auto *ucontext = static_cast<ucontext_t*>(context); // It's possible somebody cleared the SA_SIGINFO flag, which would mean // our "info" arg holds an undefined value. if (!have_siginfo(signal_number)) { Loading Loading @@ -522,7 +525,7 @@ static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void* c // This check might be racy if another thread sets NO_NEW_PRIVS, but this should be unlikely, // you can only set NO_NEW_PRIVS to 1, and the effect should be at worst a single missing // ANR trace. debuggerd_fallback_handler(info, static_cast<ucontext_t*>(context), process_info.abort_msg); debuggerd_fallback_handler(info, ucontext, process_info.abort_msg); resend_signal(info); return; } Loading @@ -534,7 +537,7 @@ static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void* c return; } log_signal_summary(info); log_signal_summary(info, ucontext); debugger_thread_info thread_info = { .crashing_tid = __gettid(), Loading
debuggerd/libdebuggerd/include/libdebuggerd/types.h +3 −0 Original line number Diff line number Diff line Loading @@ -41,4 +41,7 @@ struct ProcessInfo { uintptr_t fdsan_table_address = 0; uintptr_t gwp_asan_state = 0; uintptr_t gwp_asan_metadata = 0; bool has_fault_address = false; uintptr_t fault_address = 0; };
debuggerd/libdebuggerd/include/libdebuggerd/utility.h +2 −0 Original line number Diff line number Diff line Loading @@ -93,4 +93,6 @@ void get_signal_sender(char* buf, size_t n, const siginfo_t*); const char* get_signame(const siginfo_t*); const char* get_sigcode(const siginfo_t*); uintptr_t get_fault_address(const siginfo_t* siginfo, const ucontext_t* ucontext); #endif // _DEBUGGERD_UTILITY_H