Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3ff250f6 authored by Sijie Chen's avatar Sijie Chen
Browse files

[Berberis][CrashReporting] Extend ThreadInfo to have guest registers

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: Iff44ac5c2b202e44f3fb4e6909fbea141e54ae6b
parent 3e29843f
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -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 {
+115 −0
Original line number Diff line number Diff line
@@ -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,107 @@ static void InstallSigPipeHandler() {
  sigaction(SIGPIPE, &action, nullptr);
}

static bool PtracePeek(int request, pid_t tid, uintptr_t addr, void* data, std::string 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(std::unique_ptr<unwindstack::Regs>* regs, pid_t tid) {
  NativeBridgeGuestRegs guest_regs;
  if (!GetGuestRegistersFromCrashedProcess(tid, &guest_regs)) {
    return;
  }

  switch (guest_regs.guest_arch) {
    case NATIVE_BRIDGE_ARCH_ARM: {
      unwindstack::arm_user_regs arm_user_regs = {};
      for (size_t i = 0; i < unwindstack::ARM_REG_LAST; i++) {
        arm_user_regs.regs[i] = guest_regs.regs_arm.r[i];
      }
      regs->reset(unwindstack::RegsArm::Read(&arm_user_regs));
      break;
    }
#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
  }
}

int main(int argc, char** argv) {
  DefuseSignalHandlers();
  InstallSigPipeHandler();
@@ -537,6 +651,7 @@ int main(int argc, char** argv) {
      }

      if (thread == g_target_thread) {
        ReadGuestRegisters(&info.guest_registers, thread);
        // Read the thread's registers along with the rest of the crash info out of the pipe.
        ReadCrashInfo(input_pipe, &siginfo, &info.registers, &process_info, &recoverable_crash);
        info.siginfo = &siginfo;
+2 −0
Original line number Diff line number Diff line
@@ -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.