Reland "[Berberis][CrashReporting] Extend ThreadInfo to ..."
Revert submission 3081452-revert-3062926-CJGHTRPCBP Reason for revert: Will make the change base on the original CLs for a reland. (Original CL commit message) This CL is to get guest registers information. Bug: b/321799516 Test: m Testing for TLS Slot: Manual testing by: 1. crash the jni tests to produce tombstones file 2. get the signature field of guest state header 3. verified it is the same value as NATIVE_BRIDGE_GUEST_STATE_SIGNATURE Manual test the arm64 by: 1. flash build to pixel phone and verify retrieving TLS_SLOT_THREAD_ID's tid field is the same as current thread id. Testing for register values: Test and print out registers values for riscv64, looks make sense that has null zero value slots. Change-Id: Ieebf845bff517380ee07fac77f24b48efeb53521
This commit is contained in:
parent
9fbd7e1026
commit
cb53fe136b
3 changed files with 125 additions and 0 deletions
|
@ -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 {
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
@ -42,6 +43,7 @@
|
|||
#include <android-base/unique_fd.h>
|
||||
#include <bionic/macros.h>
|
||||
#include <bionic/reserved_signals.h>
|
||||
#include <bionic/tls_defines.h>
|
||||
#include <cutils/sockets.h>
|
||||
#include <log/log.h>
|
||||
#include <private/android_filesystem_config.h>
|
||||
|
@ -52,7 +54,18 @@
|
|||
|
||||
#include <unwindstack/AndroidUnwinder.h>
|
||||
#include <unwindstack/Error.h>
|
||||
#include <unwindstack/MachineArm.h>
|
||||
#include <unwindstack/MachineArm64.h>
|
||||
#include <unwindstack/MachineRiscv64.h>
|
||||
#include <unwindstack/Regs.h>
|
||||
#include <unwindstack/RegsArm.h>
|
||||
#include <unwindstack/RegsArm64.h>
|
||||
#include <unwindstack/RegsRiscv64.h>
|
||||
#include <unwindstack/UserArm.h>
|
||||
#include <unwindstack/UserArm64.h>
|
||||
#include <unwindstack/UserRiscv64.h>
|
||||
|
||||
#include <native_bridge_support/guest_state_accessor/accessor.h>
|
||||
|
||||
#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<unsigned char[]>(header.guest_state_data_size);
|
||||
if (!process_memory->ReadFully(reinterpret_cast<uintptr_t>(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<unwindstack::Regs>* 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);
|
||||
}
|
||||
|
|
|
@ -39,6 +39,8 @@ struct ThreadInfo {
|
|||
|
||||
int signo = 0;
|
||||
siginfo_t* siginfo = nullptr;
|
||||
|
||||
std::unique_ptr<unwindstack::Regs> guest_registers;
|
||||
};
|
||||
|
||||
// This struct is written into a pipe from inside the crashing process.
|
||||
|
|
Loading…
Reference in a new issue