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

Commit e8bc77eb authored by Christopher Ferris's avatar Christopher Ferris
Browse files

Refactor dump_memory function.

- Add dumping memory around registers for x86/x86_64.
- Add unit tests for new dump_memory function.
- Cleanup all of the machine.cpp files.
- Increase the high address check for 32 bit, and decrease the high
  address allowed for 64 bit slightly to match mips64.

Bug: 21206576
Change-Id: I6f75141f3282db48b10f7c695a1cf2eb75a08351
parent 7c789575
Loading
Loading
Loading
Loading
+54 −6
Original line number Diff line number Diff line
LOCAL_PATH := $(call my-dir)

common_cppflags := \
    -std=gnu++11 \
    -W \
    -Wall \
    -Wextra \
    -Wunused \
    -Werror \

include $(CLEAR_VARS)

LOCAL_SRC_FILES:= \
@@ -17,11 +25,7 @@ LOCAL_SRC_FILES_mips64 := mips64/machine.cpp
LOCAL_SRC_FILES_x86    := x86/machine.cpp
LOCAL_SRC_FILES_x86_64 := x86_64/machine.cpp

LOCAL_CPPFLAGS := \
    -std=gnu++11 \
    -W -Wall -Wextra \
    -Wunused \
    -Werror \
LOCAL_CPPFLAGS := $(common_cppflags)

ifeq ($(TARGET_IS_64_BIT),true)
LOCAL_CPPFLAGS += -DTARGET_IS_64_BIT
@@ -70,3 +74,47 @@ LOCAL_MODULE_STEM_64 := crasher64
LOCAL_MULTILIB := both

include $(BUILD_EXECUTABLE)

include $(CLEAR_VARS)

LOCAL_SRC_FILES := \
    utility.cpp \
    test/dump_memory_test.cpp \
    test/log_fake.cpp \

LOCAL_MODULE := debuggerd_test

LOCAL_SHARED_LIBRARIES := \
    libbacktrace \
    libbase \

LOCAL_C_INCLUDES += $(LOCAL_PATH)/test
LOCAL_CPPFLAGS := $(common_cppflags)

LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
LOCAL_MULTILIB := both

include $(BUILD_HOST_NATIVE_TEST)

include $(CLEAR_VARS)

LOCAL_SRC_FILES := \
    utility.cpp \
    test/dump_memory_test.cpp \
    test/log_fake.cpp \

LOCAL_MODULE := debuggerd_test

LOCAL_SHARED_LIBRARIES := \
    libbacktrace \
    libbase \

LOCAL_C_INCLUDES += $(LOCAL_PATH)/test
LOCAL_CPPFLAGS := $(common_cppflags)

LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
LOCAL_MULTILIB := both

include $(BUILD_NATIVE_TEST)
+14 −28
Original line number Diff line number Diff line
@@ -16,53 +16,39 @@
 */

#include <errno.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/user.h>

#include "../utility.h"
#include "../machine.h"
#include <backtrace/Backtrace.h>

void dump_memory_and_code(log_t* log, pid_t tid) {
#include "machine.h"
#include "utility.h"

void dump_memory_and_code(log_t* log, Backtrace* backtrace) {
  pt_regs regs;
  if (ptrace(PTRACE_GETREGS, tid, 0, &regs)) {
  if (ptrace(PTRACE_GETREGS, backtrace->Tid(), 0, &regs)) {
    _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
    return;
  }

  static const char REG_NAMES[] = "r0r1r2r3r4r5r6r7r8r9slfpipsp";
  static const char reg_names[] = "r0r1r2r3r4r5r6r7r8r9slfpipsp";

  for (int reg = 0; reg < 14; reg++) {
    // this may not be a valid way to access, but it'll do for now
    uintptr_t addr = regs.uregs[reg];

    // Don't bother if it looks like a small int or ~= null, or if
    // it's in the kernel area.
    if (addr < 4096 || addr >= 0xc0000000) {
      continue;
    }

    _LOG(log, logtype::MEMORY, "\nmemory near %.2s:\n", &REG_NAMES[reg * 2]);
    dump_memory(log, tid, addr);
    dump_memory(log, backtrace, regs.uregs[reg], "memory near %.2s:", &reg_names[reg * 2]);
  }

  // explicitly allow upload of code dump logging
  _LOG(log, logtype::MEMORY, "\ncode around pc:\n");
  dump_memory(log, tid, static_cast<uintptr_t>(regs.ARM_pc));
  dump_memory(log, backtrace, static_cast<uintptr_t>(regs.ARM_pc), "code around pc:");

  if (regs.ARM_pc != regs.ARM_lr) {
    _LOG(log, logtype::MEMORY, "\ncode around lr:\n");
    dump_memory(log, tid, static_cast<uintptr_t>(regs.ARM_lr));
    dump_memory(log, backtrace, static_cast<uintptr_t>(regs.ARM_lr), "code around lr:");
  }
}

void dump_registers(log_t* log, pid_t tid) {
  pt_regs r;
  if (ptrace(PTRACE_GETREGS, tid, 0, &r)) {
    _LOG(log, logtype::REGISTERS, "cannot get registers: %s\n", strerror(errno));
    _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
    return;
  }

@@ -82,7 +68,7 @@ void dump_registers(log_t* log, pid_t tid) {

  user_vfp vfp_regs;
  if (ptrace(PTRACE_GETVFPREGS, tid, 0, &vfp_regs)) {
    _LOG(log, logtype::FP_REGISTERS, "cannot get FP registers: %s\n", strerror(errno));
    _LOG(log, logtype::ERROR, "cannot get FP registers: %s\n", strerror(errno));
    return;
  }

+27 −40
Original line number Diff line number Diff line
@@ -17,49 +17,36 @@

#include <elf.h>
#include <errno.h>
#include <inttypes.h>
#include <stdint.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ptrace.h>
#include <sys/user.h>
#include <sys/uio.h>

#include "../utility.h"
#include "../machine.h"
#include <backtrace/Backtrace.h>

void dump_memory_and_code(log_t* log, pid_t tid) {
#include "machine.h"
#include "utility.h"

void dump_memory_and_code(log_t* log, Backtrace* backtrace) {
  struct user_pt_regs regs;
  struct iovec io;
  io.iov_base = &regs;
  io.iov_len = sizeof(regs);

    if (ptrace(PTRACE_GETREGSET, tid, (void*)NT_PRSTATUS, &io) == -1) {
        _LOG(log, logtype::ERROR, "%s: ptrace failed to get registers: %s\n",
  if (ptrace(PTRACE_GETREGSET, backtrace->Tid(), reinterpret_cast<void*>(NT_PRSTATUS), &io) == -1) {
    _LOG(log, logtype::ERROR, "%s: ptrace failed to get registers: %s",
         __func__, strerror(errno));
    return;
  }

  for (int reg = 0; reg < 31; reg++) {
        uintptr_t addr = regs.regs[reg];

        /*
         * Don't bother if it looks like a small int or ~= null, or if
         * it's in the kernel area.
         */
        if (addr < 4096 || addr >= (1UL<<63)) {
            continue;
        }

        _LOG(log, logtype::MEMORY, "\nmemory near x%d:\n", reg);
        dump_memory(log, tid, addr);
    dump_memory(log, backtrace, regs.regs[reg], "memory near x%d:", reg);
  }

    _LOG(log, logtype::MEMORY, "\ncode around pc:\n");
    dump_memory(log, tid, (uintptr_t)regs.pc);
  dump_memory(log, backtrace, static_cast<uintptr_t>(regs.pc), "code around pc:");

  if (regs.pc != regs.sp) {
        _LOG(log, logtype::MEMORY, "\ncode around sp:\n");
        dump_memory(log, tid, (uintptr_t)regs.sp);
    dump_memory(log, backtrace, static_cast<uintptr_t>(regs.sp), "code around sp:");
  }
}

+3 −1
Original line number Diff line number Diff line
@@ -19,9 +19,11 @@

#include <sys/types.h>

#include <backtrace/Backtrace.h>

#include "utility.h"

void dump_memory_and_code(log_t* log, pid_t tid);
void dump_memory_and_code(log_t* log, Backtrace* backtrace);
void dump_registers(log_t* log, pid_t tid);

#endif // _DEBUGGERD_MACHINE_H
+34 −39
Original line number Diff line number Diff line
@@ -14,30 +14,29 @@
 * limitations under the License.
 */

#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <inttypes.h>
#include <stdint.h>
#include <string.h>
#include <sys/ptrace.h>

#include <sys/user.h>
#include <backtrace/Backtrace.h>

#include "../utility.h"
#include "../machine.h"
#include "machine.h"
#include "utility.h"

#define R(x) (static_cast<unsigned int>(x))
#define R(x) (static_cast<uintptr_t>(x))

// If configured to do so, dump memory around *all* registers
// for the crashing thread.
void dump_memory_and_code(log_t* log, pid_t tid) {
void dump_memory_and_code(log_t* log, Backtrace* backtrace) {
  pt_regs r;
  if (ptrace(PTRACE_GETREGS, tid, 0, &r)) {
  if (ptrace(PTRACE_GETREGS, backtrace->Tid(), 0, &r)) {
    _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
    return;
  }

  static const char REG_NAMES[] = "$0atv0v1a0a1a2a3t0t1t2t3t4t5t6t7s0s1s2s3s4s5s6s7t8t9k0k1gpsps8ra";
  static const char reg_names[] = "$0atv0v1a0a1a2a3t0t1t2t3t4t5t6t7s0s1s2s3s4s5s6s7t8t9k0k1gpsps8ra";

  for (int reg = 0; reg < 32; reg++) {
    // skip uninteresting registers
@@ -48,27 +47,14 @@ void dump_memory_and_code(log_t* log, pid_t tid) {
       )
      continue;

    uintptr_t addr = R(r.regs[reg]);

    // Don't bother if it looks like a small int or ~= null, or if
    // it's in the kernel area.
    if (addr < 4096 || addr >= 0x80000000) {
      continue;
    }

    _LOG(log, logtype::MEMORY, "\nmemory near %.2s:\n", &REG_NAMES[reg * 2]);
    dump_memory(log, tid, addr);
    dump_memory(log, backtrace, R(r.regs[reg]), "memory near %.2s:", &reg_names[reg * 2]);
  }

  unsigned int pc = R(r.cp0_epc);
  unsigned int ra = R(r.regs[31]);

  _LOG(log, logtype::MEMORY, "\ncode around pc:\n");
  dump_memory(log, tid, (uintptr_t)pc);

  uintptr_t pc = R(r.cp0_epc);
  uintptr_t ra = R(r.regs[31]);
  dump_memory(log, backtrace, pc, "code around pc:");
  if (pc != ra) {
    _LOG(log, logtype::MEMORY, "\ncode around ra:\n");
    dump_memory(log, tid, (uintptr_t)ra);
    dump_memory(log, backtrace, ra, "code around ra:");
  }
}

@@ -79,22 +65,31 @@ void dump_registers(log_t* log, pid_t tid) {
    return;
  }

  _LOG(log, logtype::REGISTERS, " zr %08x  at %08x  v0 %08x  v1 %08x\n",
  _LOG(log, logtype::REGISTERS, " zr %08" PRIxPTR "  at %08" PRIxPTR
       "  v0 %08" PRIxPTR "  v1 %08" PRIxPTR "\n",
       R(r.regs[0]), R(r.regs[1]), R(r.regs[2]), R(r.regs[3]));
  _LOG(log, logtype::REGISTERS, " a0 %08x  a1 %08x  a2 %08x  a3 %08x\n",
  _LOG(log, logtype::REGISTERS, " a0 %08" PRIxPTR "  a1 %08" PRIxPTR
       "  a2 %08" PRIxPTR "  a3 %08" PRIxPTR "\n",
       R(r.regs[4]), R(r.regs[5]), R(r.regs[6]), R(r.regs[7]));
  _LOG(log, logtype::REGISTERS, " t0 %08x  t1 %08x  t2 %08x  t3 %08x\n",
  _LOG(log, logtype::REGISTERS, " t0 %08" PRIxPTR "  t1 %08" PRIxPTR
       "  t2 %08" PRIxPTR "  t3 %08" PRIxPTR "\n",
       R(r.regs[8]), R(r.regs[9]), R(r.regs[10]), R(r.regs[11]));
  _LOG(log, logtype::REGISTERS, " t4 %08x  t5 %08x  t6 %08x  t7 %08x\n",
  _LOG(log, logtype::REGISTERS, " t4 %08" PRIxPTR "  t5 %08" PRIxPTR
       "  t6 %08" PRIxPTR "  t7 %08" PRIxPTR "\n",
       R(r.regs[12]), R(r.regs[13]), R(r.regs[14]), R(r.regs[15]));
  _LOG(log, logtype::REGISTERS, " s0 %08x  s1 %08x  s2 %08x  s3 %08x\n",
  _LOG(log, logtype::REGISTERS, " s0 %08" PRIxPTR "  s1 %08" PRIxPTR
       "  s2 %08" PRIxPTR "  s3 %08" PRIxPTR "\n",
       R(r.regs[16]), R(r.regs[17]), R(r.regs[18]), R(r.regs[19]));
  _LOG(log, logtype::REGISTERS, " s4 %08x  s5 %08x  s6 %08x  s7 %08x\n",
  _LOG(log, logtype::REGISTERS, " s4 %08" PRIxPTR "  s5 %08" PRIxPTR
       "  s6 %08" PRIxPTR "  s7 %08" PRIxPTR "\n",
       R(r.regs[20]), R(r.regs[21]), R(r.regs[22]), R(r.regs[23]));
  _LOG(log, logtype::REGISTERS, " t8 %08x  t9 %08x  k0 %08x  k1 %08x\n",
  _LOG(log, logtype::REGISTERS, " t8 %08" PRIxPTR "  t9 %08" PRIxPTR
       "  k0 %08" PRIxPTR "  k1 %08" PRIxPTR "\n",
       R(r.regs[24]), R(r.regs[25]), R(r.regs[26]), R(r.regs[27]));
  _LOG(log, logtype::REGISTERS, " gp %08x  sp %08x  s8 %08x  ra %08x\n",
  _LOG(log, logtype::REGISTERS, " gp %08" PRIxPTR "  sp %08" PRIxPTR
       "  s8 %08" PRIxPTR "  ra %08" PRIxPTR "\n",
       R(r.regs[28]), R(r.regs[29]), R(r.regs[30]), R(r.regs[31]));
  _LOG(log, logtype::REGISTERS, " hi %08x  lo %08x bva %08x epc %08x\n",
  _LOG(log, logtype::REGISTERS, " hi %08" PRIxPTR "  lo %08" PRIxPTR
       " bva %08" PRIxPTR " epc %08" PRIxPTR "\n",
       R(r.hi), R(r.lo), R(r.cp0_badvaddr), R(r.cp0_epc));
}
Loading