diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp index 3a882ea8f..0c5543ed9 100644 --- a/debuggerd/Android.bp +++ b/debuggerd/Android.bp @@ -452,6 +452,7 @@ cc_binary { header_libs: [ "bionic_libc_platform_headers", + "libnative_bridge_support_accessor_headers", ], static_libs: [ @@ -461,6 +462,8 @@ cc_binary { "libtombstone_proto", "libprotobuf-cpp-lite", + + "libnative_bridge_guest_state_accessor", ], shared_libs: [ @@ -476,6 +479,15 @@ cc_binary { // Required for tests. required: ["crash_dump.policy"], + + target: { + android: { + header_libs: [ + "libnative_bridge_support_accessor_headers", // For dlext_namespaces.h + ], + shared_libs: ["libdl_android"], // For android_get_exported_namespace implementation + }, + }, } cc_binary { diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp index 203b4855b..6706650b9 100644 --- a/debuggerd/crash_dump.cpp +++ b/debuggerd/crash_dump.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -42,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -52,7 +54,18 @@ #include #include +#include +#include +#include #include +#include +#include +#include +#include +#include +#include + +#include #include "libdebuggerd/backtrace.h" #include "libdebuggerd/tombstone.h" @@ -403,6 +416,103 @@ static void InstallSigPipeHandler() { sigaction(SIGPIPE, &action, nullptr); } +static bool PtracePeek(int request, pid_t tid, uintptr_t addr, void* data, std::string_view err_msg, + uintptr_t* result) { + errno = 0; + *result = ptrace(request, tid, addr, data); + if (errno != 0) { + PLOG(ERROR) << err_msg; + return false; + } + return true; +} + +static bool GetGuestRegistersFromCrashedProcess([[maybe_unused]] pid_t tid, + NativeBridgeGuestRegs* guest_regs) { + auto process_memory = unwindstack::Memory::CreateProcessMemoryCached(tid); + + uintptr_t header_ptr = 0; + uintptr_t base = 0; +#if defined(__x86_64__) + if (!PtracePeek(PTRACE_PEEKUSER, tid, offsetof(user_regs_struct, fs_base), nullptr, + "failed to read thread register for thread " + std::to_string(tid), &base)) { + return false; + } +#elif defined(__aarch64__) + // base is implicitly casted to uint64_t. + struct iovec pt_iov { + .iov_base = &base, .iov_len = sizeof(base), + }; + + if (ptrace(PTRACE_GETREGSET, tid, NT_ARM_TLS, &pt_iov) != 0) { + PLOG(ERROR) << "failed to read thread register for thread " << tid; + } +#else + // TODO(b/339287219): Add case for Riscv host. + return false; +#endif + auto ptr_to_guest_slot = base + TLS_SLOT_NATIVE_BRIDGE_GUEST_STATE * sizeof(uintptr_t); + if (!process_memory->ReadFully(ptr_to_guest_slot, &header_ptr, sizeof(uintptr_t))) { + PLOG(ERROR) << "failed to get guest state TLS slot content for thread " << tid; + return false; + } + + NativeBridgeGuestStateHeader header; + if (!process_memory->ReadFully(header_ptr, &header, sizeof(NativeBridgeGuestStateHeader))) { + PLOG(ERROR) << "failed to get the guest state header for thread " << tid; + return false; + } + if (header.signature != NATIVE_BRIDGE_GUEST_STATE_SIGNATURE) { + // Return when ptr points to unmapped memory or no valid guest state. + return false; + } + auto guest_state_data_copy = std::make_unique(header.guest_state_data_size); + if (!process_memory->ReadFully(reinterpret_cast(header.guest_state_data), + guest_state_data_copy.get(), header.guest_state_data_size)) { + PLOG(ERROR) << "failed to read the guest state data for thread " << tid; + return false; + } + + LoadGuestStateRegisters(guest_state_data_copy.get(), header.guest_state_data_size, guest_regs); + return true; +} + +static void ReadGuestRegisters([[maybe_unused]] std::unique_ptr* regs, + pid_t tid) { + // TODO: remove [[maybe_unused]], when the ARM32 case is removed from the native bridge support. + NativeBridgeGuestRegs guest_regs; + if (!GetGuestRegistersFromCrashedProcess(tid, &guest_regs)) { + return; + } + + switch (guest_regs.guest_arch) { +#if defined(__LP64__) + case NATIVE_BRIDGE_ARCH_ARM64: { + unwindstack::arm64_user_regs arm64_user_regs = {}; + for (size_t i = 0; i < unwindstack::ARM64_REG_R31; i++) { + arm64_user_regs.regs[i] = guest_regs.regs_arm64.x[i]; + } + arm64_user_regs.sp = guest_regs.regs_arm64.sp; + arm64_user_regs.pc = guest_regs.regs_arm64.ip; + regs->reset(unwindstack::RegsArm64::Read(&arm64_user_regs)); + break; + } + case NATIVE_BRIDGE_ARCH_RISCV64: { + unwindstack::riscv64_user_regs riscv64_user_regs = {}; + // RISCV64_REG_PC is at the first position. + riscv64_user_regs.regs[0] = guest_regs.regs_riscv64.ip; + for (size_t i = 1; i < unwindstack::RISCV64_REG_REAL_COUNT; i++) { + riscv64_user_regs.regs[i] = guest_regs.regs_riscv64.x[i]; + } + regs->reset(unwindstack::RegsRiscv64::Read(&riscv64_user_regs, tid)); + break; + } +#endif + default: + break; + } +} + int main(int argc, char** argv) { DefuseSignalHandlers(); InstallSigPipeHandler(); @@ -551,6 +661,7 @@ int main(int argc, char** argv) { continue; } } + ReadGuestRegisters(&info.guest_registers, thread); thread_info[thread] = std::move(info); } diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/types.h b/debuggerd/libdebuggerd/include/libdebuggerd/types.h index 4d69658e2..c799f2448 100644 --- a/debuggerd/libdebuggerd/include/libdebuggerd/types.h +++ b/debuggerd/libdebuggerd/include/libdebuggerd/types.h @@ -39,6 +39,8 @@ struct ThreadInfo { int signo = 0; siginfo_t* siginfo = nullptr; + + std::unique_ptr guest_registers; }; // This struct is written into a pipe from inside the crashing process.