summaryrefslogtreecommitdiffstats
path: root/debuggerd
diff options
context:
space:
mode:
authorChristopher Ferris <cferris@google.com>2015-05-22 14:26:13 -0700
committerChristopher Ferris <cferris@google.com>2015-05-28 11:45:34 -0700
commit0c3f1ae66b693ef0f37066b697cc10a07ef56acc (patch)
tree2696c72439d9b049b43476cb4d96d96f9518e95e /debuggerd
parentb37c45e90aa311b4d32a5b21dad5fce93c9761a7 (diff)
downloadsystem_core-0c3f1ae66b693ef0f37066b697cc10a07ef56acc.zip
system_core-0c3f1ae66b693ef0f37066b697cc10a07ef56acc.tar.gz
system_core-0c3f1ae66b693ef0f37066b697cc10a07ef56acc.tar.bz2
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 (cherry picked from commit e8bc77eb845ab5557a4c98fe0da604d4a3740bef) Change-Id: I49ec237e30076a232f084da1072bf9aba15dc0cd
Diffstat (limited to 'debuggerd')
-rw-r--r--debuggerd/Android.mk60
-rw-r--r--debuggerd/arm/machine.cpp42
-rw-r--r--debuggerd/arm64/machine.cpp67
-rw-r--r--debuggerd/machine.h4
-rw-r--r--debuggerd/mips/machine.cpp73
-rw-r--r--debuggerd/mips64/machine.cpp73
-rw-r--r--debuggerd/test/BacktraceMock.h97
-rw-r--r--debuggerd/test/dump_memory_test.cpp504
-rw-r--r--debuggerd/test/log_fake.cpp59
-rw-r--r--debuggerd/test/log_fake.h26
-rw-r--r--debuggerd/tombstone.cpp2
-rw-r--r--debuggerd/utility.cpp142
-rw-r--r--debuggerd/utility.h4
-rw-r--r--debuggerd/x86/machine.cpp30
-rw-r--r--[-rwxr-xr-x]debuggerd/x86_64/machine.cpp65
15 files changed, 1000 insertions, 248 deletions
diff --git a/debuggerd/Android.mk b/debuggerd/Android.mk
index dd53296..1a5f05e 100644
--- a/debuggerd/Android.mk
+++ b/debuggerd/Android.mk
@@ -1,4 +1,12 @@
-LOCAL_PATH:= $(call my-dir)
+LOCAL_PATH := $(call my-dir)
+
+common_cppflags := \
+ -std=gnu++11 \
+ -W \
+ -Wall \
+ -Wextra \
+ -Wunused \
+ -Werror \
include $(CLEAR_VARS)
@@ -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)
diff --git a/debuggerd/arm/machine.cpp b/debuggerd/arm/machine.cpp
index 50e78c5..b7d6997 100644
--- a/debuggerd/arm/machine.cpp
+++ b/debuggerd/arm/machine.cpp
@@ -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;
}
diff --git a/debuggerd/arm64/machine.cpp b/debuggerd/arm64/machine.cpp
index 8b17d53..2e097da 100644
--- a/debuggerd/arm64/machine.cpp
+++ b/debuggerd/arm64/machine.cpp
@@ -17,50 +17,37 @@
#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"
-
-void dump_memory_and_code(log_t* log, pid_t tid) {
- 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",
- __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);
- }
-
- _LOG(log, logtype::MEMORY, "\ncode around pc:\n");
- dump_memory(log, tid, (uintptr_t)regs.pc);
-
- if (regs.pc != regs.sp) {
- _LOG(log, logtype::MEMORY, "\ncode around sp:\n");
- dump_memory(log, tid, (uintptr_t)regs.sp);
- }
+#include <backtrace/Backtrace.h>
+
+#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, 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++) {
+ dump_memory(log, backtrace, regs.regs[reg], "memory near x%d:", reg);
+ }
+
+ dump_memory(log, backtrace, static_cast<uintptr_t>(regs.pc), "code around pc:");
+
+ if (regs.pc != regs.sp) {
+ dump_memory(log, backtrace, static_cast<uintptr_t>(regs.sp), "code around sp:");
+ }
}
void dump_registers(log_t* log, pid_t tid) {
diff --git a/debuggerd/machine.h b/debuggerd/machine.h
index fca9fbe..e65b147 100644
--- a/debuggerd/machine.h
+++ b/debuggerd/machine.h
@@ -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
diff --git a/debuggerd/mips/machine.cpp b/debuggerd/mips/machine.cpp
index 1145963..f7b8a86 100644
--- a/debuggerd/mips/machine.cpp
+++ b/debuggerd/mips/machine.cpp
@@ -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));
}
diff --git a/debuggerd/mips64/machine.cpp b/debuggerd/mips64/machine.cpp
index ef9092f..293dcf6 100644
--- a/debuggerd/mips64/machine.cpp
+++ b/debuggerd/mips64/machine.cpp
@@ -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 long>(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[] = "$0atv0v1a0a1a2a3a4a5a6a7t0t1t2t3s0s1s2s3s4s5s6s7t8t9k0k1gpsps8ra";
+ static const char reg_names[] = "$0atv0v1a0a1a2a3a4a5a6a7t0t1t2t3s0s1s2s3s4s5s6s7t8t9k0k1gpsps8ra";
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 >= 0x4000000000000000) {
- 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 long pc = R(r.cp0_epc);
- unsigned long 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 %016lx at %016lx v0 %016lx v1 %016lx\n",
+ _LOG(log, logtype::REGISTERS, " zr %016" PRIxPTR " at %016" PRIxPTR
+ " v0 %016" PRIxPTR " v1 %016" PRIxPTR "\n",
R(r.regs[0]), R(r.regs[1]), R(r.regs[2]), R(r.regs[3]));
- _LOG(log, logtype::REGISTERS, " a0 %016lx a1 %016lx a2 %016lx a3 %016lx\n",
+ _LOG(log, logtype::REGISTERS, " a0 %016" PRIxPTR " a1 %016" PRIxPTR
+ " a2 %016" PRIxPTR " a3 %016" PRIxPTR "\n",
R(r.regs[4]), R(r.regs[5]), R(r.regs[6]), R(r.regs[7]));
- _LOG(log, logtype::REGISTERS, " a4 %016lx a5 %016lx a6 %016lx a7 %016lx\n",
+ _LOG(log, logtype::REGISTERS, " a4 %016" PRIxPTR " a5 %016" PRIxPTR
+ " a6 %016" PRIxPTR " a7 %016" PRIxPTR "\n",
R(r.regs[8]), R(r.regs[9]), R(r.regs[10]), R(r.regs[11]));
- _LOG(log, logtype::REGISTERS, " t0 %016lx t1 %016lx t2 %016lx t3 %016lx\n",
+ _LOG(log, logtype::REGISTERS, " t0 %016" PRIxPTR " t1 %016" PRIxPTR
+ " t2 %016" PRIxPTR " t3 %016" PRIxPTR "\n",
R(r.regs[12]), R(r.regs[13]), R(r.regs[14]), R(r.regs[15]));
- _LOG(log, logtype::REGISTERS, " s0 %016lx s1 %016lx s2 %016lx s3 %016lx\n",
+ _LOG(log, logtype::REGISTERS, " s0 %016" PRIxPTR " s1 %016" PRIxPTR
+ " s2 %016" PRIxPTR " s3 %016" PRIxPTR "\n",
R(r.regs[16]), R(r.regs[17]), R(r.regs[18]), R(r.regs[19]));
- _LOG(log, logtype::REGISTERS, " s4 %016lx s5 %016lx s6 %016lx s7 %016lx\n",
+ _LOG(log, logtype::REGISTERS, " s4 %016" PRIxPTR " s5 %016" PRIxPTR
+ " s6 %016" PRIxPTR " s7 %016" PRIxPTR "\n",
R(r.regs[20]), R(r.regs[21]), R(r.regs[22]), R(r.regs[23]));
- _LOG(log, logtype::REGISTERS, " t8 %016lx t9 %016lx k0 %016lx k1 %016lx\n",
+ _LOG(log, logtype::REGISTERS, " t8 %016" PRIxPTR " t9 %016" PRIxPTR
+ " k0 %016" PRIxPTR " k1 %016" PRIxPTR "\n",
R(r.regs[24]), R(r.regs[25]), R(r.regs[26]), R(r.regs[27]));
- _LOG(log, logtype::REGISTERS, " gp %016lx sp %016lx s8 %016lx ra %016lx\n",
+ _LOG(log, logtype::REGISTERS, " gp %016" PRIxPTR " sp %016" PRIxPTR
+ " s8 %016" PRIxPTR " ra %016" PRIxPTR "\n",
R(r.regs[28]), R(r.regs[29]), R(r.regs[30]), R(r.regs[31]));
- _LOG(log, logtype::REGISTERS, " hi %016lx lo %016lx bva %016lx epc %016lx\n",
+ _LOG(log, logtype::REGISTERS, " hi %016" PRIxPTR " lo %016" PRIxPTR
+ " bva %016" PRIxPTR " epc %016" PRIxPTR "\n",
R(r.hi), R(r.lo), R(r.cp0_badvaddr), R(r.cp0_epc));
}
diff --git a/debuggerd/test/BacktraceMock.h b/debuggerd/test/BacktraceMock.h
new file mode 100644
index 0000000..05ad12b
--- /dev/null
+++ b/debuggerd/test/BacktraceMock.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _DEBUGGERD_TEST_BACKTRACE_MOCK_H
+#define _DEBUGGERD_TEST_BACKTRACE_MOCK_H
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ucontext.h>
+
+#include <string>
+#include <vector>
+
+#include <backtrace/Backtrace.h>
+#include <backtrace/BacktraceMap.h>
+
+class BacktraceMapMock : public BacktraceMap {
+ public:
+ BacktraceMapMock() : BacktraceMap(0) {}
+ virtual ~BacktraceMapMock() {}
+};
+
+
+class BacktraceMock : public Backtrace {
+ public:
+ BacktraceMock(BacktraceMapMock* map) : Backtrace(0, 0, map) {
+ if (map_ == nullptr) {
+ abort();
+ }
+ }
+ virtual ~BacktraceMock() {}
+
+ virtual bool Unwind(size_t, ucontext_t*) { return false; }
+ virtual bool ReadWord(uintptr_t, word_t*) { return false;}
+
+ virtual std::string GetFunctionNameRaw(uintptr_t, uintptr_t*) { return ""; }
+
+ virtual size_t Read(uintptr_t addr, uint8_t* buffer, size_t bytes) {
+ size_t offset = 0;
+ if (last_read_addr_ > 0) {
+ offset = addr - last_read_addr_;
+ }
+ size_t bytes_available = buffer_.size() - offset;
+
+ if (bytes_partial_read_ > 0) {
+ // Do a partial read.
+ if (bytes > bytes_partial_read_) {
+ bytes = bytes_partial_read_;
+ }
+ bytes_partial_read_ -= bytes;
+ } else if (bytes > bytes_available) {
+ bytes = bytes_available;
+ }
+
+ if (bytes > 0) {
+ memcpy(buffer, buffer_.data() + offset, bytes);
+ }
+
+ last_read_addr_ = addr;
+ return bytes;
+ }
+
+ void SetReadData(uint8_t* buffer, size_t bytes) {
+ buffer_.resize(bytes);
+ memcpy(buffer_.data(), buffer, bytes);
+ bytes_partial_read_ = 0;
+ last_read_addr_ = 0;
+ }
+
+ void SetPartialReadAmount(size_t bytes) {
+ if (bytes > buffer_.size()) {
+ abort();
+ }
+ bytes_partial_read_ = bytes;
+ }
+
+ private:
+ std::vector<uint8_t> buffer_;
+ size_t bytes_partial_read_ = 0;
+ uintptr_t last_read_addr_ = 0;
+};
+
+#endif // _DEBUGGERD_TEST_BACKTRACE_MOCK_H
diff --git a/debuggerd/test/dump_memory_test.cpp b/debuggerd/test/dump_memory_test.cpp
new file mode 100644
index 0000000..fcb0108
--- /dev/null
+++ b/debuggerd/test/dump_memory_test.cpp
@@ -0,0 +1,504 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+
+#include <memory>
+#include <string>
+
+#include <gtest/gtest.h>
+#include <base/file.h>
+
+#include "BacktraceMock.h"
+#include "log_fake.h"
+#include "utility.h"
+
+const char g_expected_full_dump[] =
+"\nmemory near r1:\n"
+#if defined(__LP64__)
+" 0000000012345658 0706050403020100 0f0e0d0c0b0a0908 ................\n"
+" 0000000012345668 1716151413121110 1f1e1d1c1b1a1918 ................\n"
+" 0000000012345678 2726252423222120 2f2e2d2c2b2a2928 !\"#$%&'()*+,-./\n"
+" 0000000012345688 3736353433323130 3f3e3d3c3b3a3938 0123456789:;<=>?\n"
+" 0000000012345698 4746454443424140 4f4e4d4c4b4a4948 @ABCDEFGHIJKLMNO\n"
+" 00000000123456a8 5756555453525150 5f5e5d5c5b5a5958 PQRSTUVWXYZ[\\]^_\n"
+" 00000000123456b8 6766656463626160 6f6e6d6c6b6a6968 `abcdefghijklmno\n"
+" 00000000123456c8 7776757473727170 7f7e7d7c7b7a7978 pqrstuvwxyz{|}~.\n"
+" 00000000123456d8 8786858483828180 8f8e8d8c8b8a8988 ................\n"
+" 00000000123456e8 9796959493929190 9f9e9d9c9b9a9998 ................\n"
+" 00000000123456f8 a7a6a5a4a3a2a1a0 afaeadacabaaa9a8 ................\n"
+" 0000000012345708 b7b6b5b4b3b2b1b0 bfbebdbcbbbab9b8 ................\n"
+" 0000000012345718 c7c6c5c4c3c2c1c0 cfcecdcccbcac9c8 ................\n"
+" 0000000012345728 d7d6d5d4d3d2d1d0 dfdedddcdbdad9d8 ................\n"
+" 0000000012345738 e7e6e5e4e3e2e1e0 efeeedecebeae9e8 ................\n"
+" 0000000012345748 f7f6f5f4f3f2f1f0 fffefdfcfbfaf9f8 ................\n";
+#else
+" 12345658 03020100 07060504 0b0a0908 0f0e0d0c ................\n"
+" 12345668 13121110 17161514 1b1a1918 1f1e1d1c ................\n"
+" 12345678 23222120 27262524 2b2a2928 2f2e2d2c !\"#$%&'()*+,-./\n"
+" 12345688 33323130 37363534 3b3a3938 3f3e3d3c 0123456789:;<=>?\n"
+" 12345698 43424140 47464544 4b4a4948 4f4e4d4c @ABCDEFGHIJKLMNO\n"
+" 123456a8 53525150 57565554 5b5a5958 5f5e5d5c PQRSTUVWXYZ[\\]^_\n"
+" 123456b8 63626160 67666564 6b6a6968 6f6e6d6c `abcdefghijklmno\n"
+" 123456c8 73727170 77767574 7b7a7978 7f7e7d7c pqrstuvwxyz{|}~.\n"
+" 123456d8 83828180 87868584 8b8a8988 8f8e8d8c ................\n"
+" 123456e8 93929190 97969594 9b9a9998 9f9e9d9c ................\n"
+" 123456f8 a3a2a1a0 a7a6a5a4 abaaa9a8 afaeadac ................\n"
+" 12345708 b3b2b1b0 b7b6b5b4 bbbab9b8 bfbebdbc ................\n"
+" 12345718 c3c2c1c0 c7c6c5c4 cbcac9c8 cfcecdcc ................\n"
+" 12345728 d3d2d1d0 d7d6d5d4 dbdad9d8 dfdedddc ................\n"
+" 12345738 e3e2e1e0 e7e6e5e4 ebeae9e8 efeeedec ................\n"
+" 12345748 f3f2f1f0 f7f6f5f4 fbfaf9f8 fffefdfc ................\n";
+#endif
+
+const char g_expected_partial_dump[] = \
+"\nmemory near pc:\n"
+#if defined(__LP64__)
+" 00000000123455e0 0706050403020100 0f0e0d0c0b0a0908 ................\n"
+" 00000000123455f0 1716151413121110 1f1e1d1c1b1a1918 ................\n"
+" 0000000012345600 2726252423222120 2f2e2d2c2b2a2928 !\"#$%&'()*+,-./\n"
+" 0000000012345610 3736353433323130 3f3e3d3c3b3a3938 0123456789:;<=>?\n"
+" 0000000012345620 4746454443424140 4f4e4d4c4b4a4948 @ABCDEFGHIJKLMNO\n"
+" 0000000012345630 5756555453525150 5f5e5d5c5b5a5958 PQRSTUVWXYZ[\\]^_\n"
+" 0000000012345640 6766656463626160 ---------------- `abcdefg........\n"
+" 0000000012345650 ---------------- ---------------- ................\n"
+" 0000000012345660 ---------------- ---------------- ................\n"
+" 0000000012345670 ---------------- ---------------- ................\n"
+" 0000000012345680 ---------------- ---------------- ................\n"
+" 0000000012345690 ---------------- ---------------- ................\n"
+" 00000000123456a0 ---------------- ---------------- ................\n"
+" 00000000123456b0 ---------------- ---------------- ................\n"
+" 00000000123456c0 ---------------- ---------------- ................\n"
+" 00000000123456d0 ---------------- ---------------- ................\n";
+#else
+" 123455e0 03020100 07060504 0b0a0908 0f0e0d0c ................\n"
+" 123455f0 13121110 17161514 1b1a1918 1f1e1d1c ................\n"
+" 12345600 23222120 27262524 2b2a2928 2f2e2d2c !\"#$%&'()*+,-./\n"
+" 12345610 33323130 37363534 3b3a3938 3f3e3d3c 0123456789:;<=>?\n"
+" 12345620 43424140 47464544 4b4a4948 4f4e4d4c @ABCDEFGHIJKLMNO\n"
+" 12345630 53525150 57565554 5b5a5958 5f5e5d5c PQRSTUVWXYZ[\\]^_\n"
+" 12345640 63626160 67666564 -------- -------- `abcdefg........\n"
+" 12345650 -------- -------- -------- -------- ................\n"
+" 12345660 -------- -------- -------- -------- ................\n"
+" 12345670 -------- -------- -------- -------- ................\n"
+" 12345680 -------- -------- -------- -------- ................\n"
+" 12345690 -------- -------- -------- -------- ................\n"
+" 123456a0 -------- -------- -------- -------- ................\n"
+" 123456b0 -------- -------- -------- -------- ................\n"
+" 123456c0 -------- -------- -------- -------- ................\n"
+" 123456d0 -------- -------- -------- -------- ................\n";
+#endif
+
+class DumpMemoryTest : public ::testing::Test {
+ protected:
+ virtual void SetUp() {
+ map_mock_.reset(new BacktraceMapMock());
+ backtrace_mock_.reset(new BacktraceMock(map_mock_.get()));
+
+ char tmp_file[256];
+ const char data_template[] = "/data/local/tmp/debuggerd_memory_testXXXXXX";
+ memcpy(tmp_file, data_template, sizeof(data_template));
+ int tombstone_fd = mkstemp(tmp_file);
+ if (tombstone_fd == -1) {
+ const char tmp_template[] = "/tmp/debuggerd_memory_testXXXXXX";
+ memcpy(tmp_file, tmp_template, sizeof(tmp_template));
+ tombstone_fd = mkstemp(tmp_file);
+ if (tombstone_fd == -1) {
+ abort();
+ }
+ }
+ if (unlink(tmp_file) == -1) {
+ abort();
+ }
+
+ log_.tfd = tombstone_fd;
+ log_.amfd = -1;
+ log_.crashed_tid = 12;
+ log_.current_tid = 12;
+ log_.should_retrieve_logcat = false;
+
+ resetLogs();
+ }
+
+ virtual void TearDown() {
+ if (log_.tfd >= 0) {
+ close(log_.tfd);
+ }
+ }
+
+ std::unique_ptr<BacktraceMapMock> map_mock_;
+ std::unique_ptr<BacktraceMock> backtrace_mock_;
+
+ log_t log_;
+};
+
+TEST_F(DumpMemoryTest, aligned_addr) {
+ uint8_t buffer[256];
+ for (size_t i = 0; i < sizeof(buffer); i++) {
+ buffer[i] = i;
+ }
+ backtrace_mock_->SetReadData(buffer, sizeof(buffer));
+
+ dump_memory(&log_, backtrace_mock_.get(), 0x12345678, "memory near %.2s:", "r1");
+
+ std::string tombstone_contents;
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+ ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+ ASSERT_STREQ(g_expected_full_dump, tombstone_contents.c_str());
+
+ // Verify that the log buf is empty, and no error messages.
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(DumpMemoryTest, partial_read) {
+ uint8_t buffer[256];
+ for (size_t i = 0; i < sizeof(buffer); i++) {
+ buffer[i] = i;
+ }
+ backtrace_mock_->SetReadData(buffer, sizeof(buffer));
+ backtrace_mock_->SetPartialReadAmount(96);
+
+ dump_memory(&log_, backtrace_mock_.get(), 0x12345679, "memory near %.2s:", "r1");
+
+ std::string tombstone_contents;
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+ ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+ ASSERT_STREQ(g_expected_full_dump, tombstone_contents.c_str());
+
+ // Verify that the log buf is empty, and no error messages.
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(DumpMemoryTest, unaligned_addr) {
+ uint8_t buffer[256];
+ for (size_t i = 0; i < sizeof(buffer); i++) {
+ buffer[i] = i;
+ }
+ backtrace_mock_->SetReadData(buffer, sizeof(buffer));
+
+ dump_memory(&log_, backtrace_mock_.get(), 0x12345679, "memory near %.2s:", "r1");
+
+ std::string tombstone_contents;
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+ ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+ ASSERT_STREQ(g_expected_full_dump, tombstone_contents.c_str());
+
+ // Verify that the log buf is empty, and no error messages.
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(DumpMemoryTest, memory_unreadable) {
+ dump_memory(&log_, backtrace_mock_.get(), 0xa2345678, "memory near pc:");
+
+ std::string tombstone_contents;
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+ ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+ const char* expected_dump = \
+"\nmemory near pc:\n"
+#if defined(__LP64__)
+" 00000000a2345658 ---------------- ---------------- ................\n"
+" 00000000a2345668 ---------------- ---------------- ................\n"
+" 00000000a2345678 ---------------- ---------------- ................\n"
+" 00000000a2345688 ---------------- ---------------- ................\n"
+" 00000000a2345698 ---------------- ---------------- ................\n"
+" 00000000a23456a8 ---------------- ---------------- ................\n"
+" 00000000a23456b8 ---------------- ---------------- ................\n"
+" 00000000a23456c8 ---------------- ---------------- ................\n"
+" 00000000a23456d8 ---------------- ---------------- ................\n"
+" 00000000a23456e8 ---------------- ---------------- ................\n"
+" 00000000a23456f8 ---------------- ---------------- ................\n"
+" 00000000a2345708 ---------------- ---------------- ................\n"
+" 00000000a2345718 ---------------- ---------------- ................\n"
+" 00000000a2345728 ---------------- ---------------- ................\n"
+" 00000000a2345738 ---------------- ---------------- ................\n"
+" 00000000a2345748 ---------------- ---------------- ................\n";
+#else
+" a2345658 -------- -------- -------- -------- ................\n"
+" a2345668 -------- -------- -------- -------- ................\n"
+" a2345678 -------- -------- -------- -------- ................\n"
+" a2345688 -------- -------- -------- -------- ................\n"
+" a2345698 -------- -------- -------- -------- ................\n"
+" a23456a8 -------- -------- -------- -------- ................\n"
+" a23456b8 -------- -------- -------- -------- ................\n"
+" a23456c8 -------- -------- -------- -------- ................\n"
+" a23456d8 -------- -------- -------- -------- ................\n"
+" a23456e8 -------- -------- -------- -------- ................\n"
+" a23456f8 -------- -------- -------- -------- ................\n"
+" a2345708 -------- -------- -------- -------- ................\n"
+" a2345718 -------- -------- -------- -------- ................\n"
+" a2345728 -------- -------- -------- -------- ................\n"
+" a2345738 -------- -------- -------- -------- ................\n"
+" a2345748 -------- -------- -------- -------- ................\n";
+#endif
+ ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+
+ // Verify that the log buf is empty, and no error messages.
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(DumpMemoryTest, memory_partially_unreadable) {
+ uint8_t buffer[104];
+ for (size_t i = 0; i < sizeof(buffer); i++) {
+ buffer[i] = i;
+ }
+ backtrace_mock_->SetReadData(buffer, sizeof(buffer));
+
+ dump_memory(&log_, backtrace_mock_.get(), 0x12345600, "memory near pc:");
+
+ std::string tombstone_contents;
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+ ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+ ASSERT_STREQ(g_expected_partial_dump, tombstone_contents.c_str());
+
+ // Verify that the log buf is empty, and no error messages.
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(DumpMemoryTest, memory_partially_unreadable_unaligned_return) {
+ uint8_t buffer[104];
+ for (size_t i = 0; i < sizeof(buffer); i++) {
+ buffer[i] = i;
+ }
+ backtrace_mock_->SetReadData(buffer, sizeof(buffer));
+ backtrace_mock_->SetPartialReadAmount(102);
+
+ dump_memory(&log_, backtrace_mock_.get(), 0x12345600, "memory near pc:");
+
+ std::string tombstone_contents;
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+ ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+ ASSERT_STREQ(g_expected_partial_dump, tombstone_contents.c_str());
+
+#if defined(__LP64__)
+ ASSERT_STREQ("DEBUG Bytes read 102, is not a multiple of 8\n", getFakeLogPrint().c_str());
+#else
+ ASSERT_STREQ("DEBUG Bytes read 102, is not a multiple of 4\n", getFakeLogPrint().c_str());
+#endif
+
+ // Verify that the log buf is empty, and no error messages.
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+}
+
+TEST_F(DumpMemoryTest, memory_partially_unreadable_two_unaligned_reads) {
+ uint8_t buffer[106];
+ for (size_t i = 0; i < sizeof(buffer); i++) {
+ buffer[i] = i;
+ }
+ backtrace_mock_->SetReadData(buffer, sizeof(buffer));
+ backtrace_mock_->SetPartialReadAmount(45);
+
+ dump_memory(&log_, backtrace_mock_.get(), 0x12345600, "memory near pc:");
+
+ std::string tombstone_contents;
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+ ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+ ASSERT_STREQ(g_expected_partial_dump, tombstone_contents.c_str());
+
+#if defined(__LP64__)
+ ASSERT_STREQ("DEBUG Bytes read 45, is not a multiple of 8\n"
+ "DEBUG Bytes after second read 106, is not a multiple of 8\n",
+ getFakeLogPrint().c_str());
+#else
+ ASSERT_STREQ("DEBUG Bytes read 45, is not a multiple of 4\n"
+ "DEBUG Bytes after second read 106, is not a multiple of 4\n",
+ getFakeLogPrint().c_str());
+#endif
+
+ // Verify that the log buf is empty, and no error messages.
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+}
+
+TEST_F(DumpMemoryTest, address_low_fence) {
+ uint8_t buffer[256];
+ memset(buffer, 0, sizeof(buffer));
+ backtrace_mock_->SetReadData(buffer, sizeof(buffer));
+
+ dump_memory(&log_, backtrace_mock_.get(), 0x1000, "memory near %.2s:", "r1");
+
+ std::string tombstone_contents;
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+ ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+ const char* expected_dump = \
+"\nmemory near r1:\n"
+#if defined(__LP64__)
+" 0000000000001000 0000000000000000 0000000000000000 ................\n"
+" 0000000000001010 0000000000000000 0000000000000000 ................\n"
+" 0000000000001020 0000000000000000 0000000000000000 ................\n"
+" 0000000000001030 0000000000000000 0000000000000000 ................\n"
+" 0000000000001040 0000000000000000 0000000000000000 ................\n"
+" 0000000000001050 0000000000000000 0000000000000000 ................\n"
+" 0000000000001060 0000000000000000 0000000000000000 ................\n"
+" 0000000000001070 0000000000000000 0000000000000000 ................\n"
+" 0000000000001080 0000000000000000 0000000000000000 ................\n"
+" 0000000000001090 0000000000000000 0000000000000000 ................\n"
+" 00000000000010a0 0000000000000000 0000000000000000 ................\n"
+" 00000000000010b0 0000000000000000 0000000000000000 ................\n"
+" 00000000000010c0 0000000000000000 0000000000000000 ................\n"
+" 00000000000010d0 0000000000000000 0000000000000000 ................\n"
+" 00000000000010e0 0000000000000000 0000000000000000 ................\n"
+" 00000000000010f0 0000000000000000 0000000000000000 ................\n";
+#else
+" 00001000 00000000 00000000 00000000 00000000 ................\n"
+" 00001010 00000000 00000000 00000000 00000000 ................\n"
+" 00001020 00000000 00000000 00000000 00000000 ................\n"
+" 00001030 00000000 00000000 00000000 00000000 ................\n"
+" 00001040 00000000 00000000 00000000 00000000 ................\n"
+" 00001050 00000000 00000000 00000000 00000000 ................\n"
+" 00001060 00000000 00000000 00000000 00000000 ................\n"
+" 00001070 00000000 00000000 00000000 00000000 ................\n"
+" 00001080 00000000 00000000 00000000 00000000 ................\n"
+" 00001090 00000000 00000000 00000000 00000000 ................\n"
+" 000010a0 00000000 00000000 00000000 00000000 ................\n"
+" 000010b0 00000000 00000000 00000000 00000000 ................\n"
+" 000010c0 00000000 00000000 00000000 00000000 ................\n"
+" 000010d0 00000000 00000000 00000000 00000000 ................\n"
+" 000010e0 00000000 00000000 00000000 00000000 ................\n"
+" 000010f0 00000000 00000000 00000000 00000000 ................\n";
+#endif
+ ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+
+ // Verify that the log buf is empty, and no error messages.
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(DumpMemoryTest, memory_address_too_low) {
+ uint8_t buffer[256];
+ memset(buffer, 0, sizeof(buffer));
+ backtrace_mock_->SetReadData(buffer, sizeof(buffer));
+
+ dump_memory(&log_, backtrace_mock_.get(), 0, "memory near %.2s:", "r1");
+
+ std::string tombstone_contents;
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+ ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+ ASSERT_STREQ("", tombstone_contents.c_str());
+
+ // Verify that the log buf is empty, and no error messages.
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(DumpMemoryTest, memory_address_too_high) {
+ uint8_t buffer[256];
+ memset(buffer, 0, sizeof(buffer));
+ backtrace_mock_->SetReadData(buffer, sizeof(buffer));
+
+#if defined(__LP64__)
+ dump_memory(&log_, backtrace_mock_.get(), 0x4000000000000000UL, "memory near %.2s:", "r1");
+ dump_memory(&log_, backtrace_mock_.get(), 0x4000000000000000UL - 32, "memory near %.2s:", "r1");
+ dump_memory(&log_, backtrace_mock_.get(), 0x4000000000000000UL - 216, "memory near %.2s:", "r1");
+#else
+ dump_memory(&log_, backtrace_mock_.get(), 0xffff0000, "memory near %.2s:", "r1");
+ dump_memory(&log_, backtrace_mock_.get(), 0xffff0000 - 32, "memory near %.2s:", "r1");
+ dump_memory(&log_, backtrace_mock_.get(), 0xffff0000 - 220, "memory near %.2s:", "r1");
+#endif
+
+ std::string tombstone_contents;
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+ ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+ ASSERT_STREQ("", tombstone_contents.c_str());
+
+ // Verify that the log buf is empty, and no error messages.
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(DumpMemoryTest, memory_address_would_overflow) {
+ uint8_t buffer[256];
+ memset(buffer, 0, sizeof(buffer));
+ backtrace_mock_->SetReadData(buffer, sizeof(buffer));
+
+#if defined(__LP64__)
+ dump_memory(&log_, backtrace_mock_.get(), 0xfffffffffffffff0, "memory near %.2s:", "r1");
+#else
+ dump_memory(&log_, backtrace_mock_.get(), 0xfffffff0, "memory near %.2s:", "r1");
+#endif
+
+ std::string tombstone_contents;
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+ ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+ ASSERT_STREQ("", tombstone_contents.c_str());
+
+ // Verify that the log buf is empty, and no error messages.
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(DumpMemoryTest, memory_address_nearly_too_high) {
+ uint8_t buffer[256];
+ for (size_t i = 0; i < sizeof(buffer); i++) {
+ buffer[i] = i;
+ }
+ backtrace_mock_->SetReadData(buffer, sizeof(buffer));
+
+#if defined(__LP64__)
+ dump_memory(&log_, backtrace_mock_.get(), 0x4000000000000000UL - 224, "memory near %.2s:", "r4");
+#else
+ dump_memory(&log_, backtrace_mock_.get(), 0xffff0000 - 224, "memory near %.2s:", "r4");
+#endif
+
+ std::string tombstone_contents;
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+ ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+ const char* expected_dump = \
+"\nmemory near r4:\n"
+#if defined(__LP64__)
+" 3fffffffffffff00 0706050403020100 0f0e0d0c0b0a0908 ................\n"
+" 3fffffffffffff10 1716151413121110 1f1e1d1c1b1a1918 ................\n"
+" 3fffffffffffff20 2726252423222120 2f2e2d2c2b2a2928 !\"#$%&'()*+,-./\n"
+" 3fffffffffffff30 3736353433323130 3f3e3d3c3b3a3938 0123456789:;<=>?\n"
+" 3fffffffffffff40 4746454443424140 4f4e4d4c4b4a4948 @ABCDEFGHIJKLMNO\n"
+" 3fffffffffffff50 5756555453525150 5f5e5d5c5b5a5958 PQRSTUVWXYZ[\\]^_\n"
+" 3fffffffffffff60 6766656463626160 6f6e6d6c6b6a6968 `abcdefghijklmno\n"
+" 3fffffffffffff70 7776757473727170 7f7e7d7c7b7a7978 pqrstuvwxyz{|}~.\n"
+" 3fffffffffffff80 8786858483828180 8f8e8d8c8b8a8988 ................\n"
+" 3fffffffffffff90 9796959493929190 9f9e9d9c9b9a9998 ................\n"
+" 3fffffffffffffa0 a7a6a5a4a3a2a1a0 afaeadacabaaa9a8 ................\n"
+" 3fffffffffffffb0 b7b6b5b4b3b2b1b0 bfbebdbcbbbab9b8 ................\n"
+" 3fffffffffffffc0 c7c6c5c4c3c2c1c0 cfcecdcccbcac9c8 ................\n"
+" 3fffffffffffffd0 d7d6d5d4d3d2d1d0 dfdedddcdbdad9d8 ................\n"
+" 3fffffffffffffe0 e7e6e5e4e3e2e1e0 efeeedecebeae9e8 ................\n"
+" 3ffffffffffffff0 f7f6f5f4f3f2f1f0 fffefdfcfbfaf9f8 ................\n";
+#else
+" fffeff00 03020100 07060504 0b0a0908 0f0e0d0c ................\n"
+" fffeff10 13121110 17161514 1b1a1918 1f1e1d1c ................\n"
+" fffeff20 23222120 27262524 2b2a2928 2f2e2d2c !\"#$%&'()*+,-./\n"
+" fffeff30 33323130 37363534 3b3a3938 3f3e3d3c 0123456789:;<=>?\n"
+" fffeff40 43424140 47464544 4b4a4948 4f4e4d4c @ABCDEFGHIJKLMNO\n"
+" fffeff50 53525150 57565554 5b5a5958 5f5e5d5c PQRSTUVWXYZ[\\]^_\n"
+" fffeff60 63626160 67666564 6b6a6968 6f6e6d6c `abcdefghijklmno\n"
+" fffeff70 73727170 77767574 7b7a7978 7f7e7d7c pqrstuvwxyz{|}~.\n"
+" fffeff80 83828180 87868584 8b8a8988 8f8e8d8c ................\n"
+" fffeff90 93929190 97969594 9b9a9998 9f9e9d9c ................\n"
+" fffeffa0 a3a2a1a0 a7a6a5a4 abaaa9a8 afaeadac ................\n"
+" fffeffb0 b3b2b1b0 b7b6b5b4 bbbab9b8 bfbebdbc ................\n"
+" fffeffc0 c3c2c1c0 c7c6c5c4 cbcac9c8 cfcecdcc ................\n"
+" fffeffd0 d3d2d1d0 d7d6d5d4 dbdad9d8 dfdedddc ................\n"
+" fffeffe0 e3e2e1e0 e7e6e5e4 ebeae9e8 efeeedec ................\n"
+" fffefff0 f3f2f1f0 f7f6f5f4 fbfaf9f8 fffefdfc ................\n";
+#endif
+ ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+
+ // Verify that the log buf is empty, and no error messages.
+ ASSERT_STREQ("", getFakeLogBuf().c_str());
+ ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
diff --git a/debuggerd/test/log_fake.cpp b/debuggerd/test/log_fake.cpp
new file mode 100644
index 0000000..1161afe
--- /dev/null
+++ b/debuggerd/test/log_fake.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdarg.h>
+
+#include <string>
+
+#include <base/stringprintf.h>
+
+std::string g_fake_log_buf;
+
+std::string g_fake_log_print;
+
+void resetLogs() {
+ g_fake_log_buf = "";
+ g_fake_log_print = "";
+}
+
+extern "C" int __android_log_buf_write(int, int, const char* tag, const char* msg) {
+ g_fake_log_buf += tag;
+ g_fake_log_buf += ' ';
+ g_fake_log_buf += msg;
+ return 1;
+}
+
+std::string getFakeLogBuf() {
+ return g_fake_log_buf;
+}
+
+extern "C" int __android_log_print(int, const char* tag, const char* fmt, ...) {
+ g_fake_log_print += tag;
+ g_fake_log_print += ' ';
+
+ va_list ap;
+ va_start(ap, fmt);
+ android::base::StringAppendV(&g_fake_log_print, fmt, ap);
+ va_end(ap);
+
+ g_fake_log_print += '\n';
+
+ return 1;
+}
+
+std::string getFakeLogPrint() {
+ return g_fake_log_print;
+}
diff --git a/debuggerd/test/log_fake.h b/debuggerd/test/log_fake.h
new file mode 100644
index 0000000..5418fce
--- /dev/null
+++ b/debuggerd/test/log_fake.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _DEBUGGERD_TEST_LOG_FAKE_H
+#define _DEBUGGERD_TEST_LOG_FAKE_H
+
+#include <string>
+
+void resetLogs();
+std::string getFakeLogBuf();
+std::string getFakeLogPrint();
+
+#endif // _DEBUGGERD_TEST_LOG_FAKE_H
diff --git a/debuggerd/tombstone.cpp b/debuggerd/tombstone.cpp
index ccdfe85..614edb6 100644
--- a/debuggerd/tombstone.cpp
+++ b/debuggerd/tombstone.cpp
@@ -654,7 +654,7 @@ static bool dump_crash(log_t* log, pid_t pid, pid_t tid, int signal, int si_code
} else {
ALOGE("Unwind failed: pid = %d, tid = %d", pid, tid);
}
- dump_memory_and_code(log, tid);
+ dump_memory_and_code(log, backtrace.get());
if (map.get() != nullptr) {
dump_all_maps(backtrace.get(), map.get(), log, tid);
}
diff --git a/debuggerd/utility.cpp b/debuggerd/utility.cpp
index e722f82..9f340a8 100644
--- a/debuggerd/utility.cpp
+++ b/debuggerd/utility.cpp
@@ -27,6 +27,7 @@
#include <backtrace/Backtrace.h>
#include <base/file.h>
+#include <base/stringprintf.h>
#include <log/log.h>
const int SLEEP_TIME_USEC = 50000; // 0.05 seconds
@@ -118,68 +119,91 @@ int wait_for_sigstop(pid_t tid, int* total_sleep_time_usec, bool* detach_failed)
return -1;
}
-void dump_memory(log_t* log, pid_t tid, uintptr_t addr) {
- char code_buffer[64];
- char ascii_buffer[32];
- uintptr_t p, end;
-
- p = addr & ~(sizeof(long) - 1);
- /* Dump 32 bytes before addr */
- p -= 32;
- if (p > addr) {
- /* catch underflow */
- p = 0;
- }
- /* Dump 256 bytes */
- end = p + 256;
- /* catch overflow; 'end - p' has to be multiples of 16 */
- while (end < p) {
- end -= 16;
- }
+#define MEMORY_BYTES_TO_DUMP 256
+#define MEMORY_BYTES_PER_LINE 16
+
+void dump_memory(log_t* log, Backtrace* backtrace, uintptr_t addr, const char* fmt, ...) {
+ std::string log_msg;
+ va_list ap;
+ va_start(ap, fmt);
+ android::base::StringAppendV(&log_msg, fmt, ap);
+ va_end(ap);
+
+ // Align the address to sizeof(long) and start 32 bytes before the address.
+ addr &= ~(sizeof(long) - 1);
+ if (addr >= 4128) {
+ addr -= 32;
+ }
- /* Dump the code around PC as:
- * addr contents ascii
- * 0000000000008d34 ef000000e8bd0090 e1b00000512fff1e ............../Q
- * 0000000000008d44 ea00b1f9e92d0090 e3a070fcef000000 ......-..p......
- * On 32-bit machines, there are still 16 bytes per line but addresses and
- * words are of course presented differently.
- */
- while (p < end) {
- char* asc_out = ascii_buffer;
-
- int len = snprintf(code_buffer, sizeof(code_buffer), "%" PRIPTR " ", p);
-
- for (size_t i = 0; i < 16/sizeof(long); i++) {
- long data = ptrace(PTRACE_PEEKTEXT, tid, (void*)p, NULL);
- if (data == -1 && errno != 0) {
- // ptrace failed, probably because we're dumping memory in an
- // unmapped or inaccessible page.
-#ifdef __LP64__
- len += sprintf(code_buffer + len, "---------------- ");
+ // Don't bother if the address looks too low, or looks too high.
+ if (addr < 4096 ||
+#if defined(__LP64__)
+ addr > 0x4000000000000000UL - MEMORY_BYTES_TO_DUMP) {
#else
- len += sprintf(code_buffer + len, "-------- ");
+ addr > 0xffff0000 - MEMORY_BYTES_TO_DUMP) {
#endif
- } else {
- len += sprintf(code_buffer + len, "%" PRIPTR " ",
- static_cast<uintptr_t>(data));
- }
-
- for (size_t j = 0; j < sizeof(long); j++) {
- /*
- * Our isprint() allows high-ASCII characters that display
- * differently (often badly) in different viewers, so we
- * just use a simpler test.
- */
- char val = (data >> (j*8)) & 0xff;
- if (val >= 0x20 && val < 0x7f) {
- *asc_out++ = val;
- } else {
- *asc_out++ = '.';
- }
- }
- p += sizeof(long);
+ return;
+ }
+
+ _LOG(log, logtype::MEMORY, "\n%s\n", log_msg.c_str());
+
+ // Dump 256 bytes
+ uintptr_t data[MEMORY_BYTES_TO_DUMP/sizeof(uintptr_t)];
+ memset(data, 0, MEMORY_BYTES_TO_DUMP);
+ size_t bytes = backtrace->Read(addr, reinterpret_cast<uint8_t*>(data), sizeof(data));
+ if (bytes % sizeof(uintptr_t) != 0) {
+ // This should never happen, but just in case.
+ ALOGE("Bytes read %zu, is not a multiple of %zu", bytes, sizeof(uintptr_t));
+ bytes &= ~(sizeof(uintptr_t) - 1);
+ }
+
+ if (bytes < MEMORY_BYTES_TO_DUMP && bytes > 0) {
+ // Try to do one more read. This could happen if a read crosses a map, but
+ // the maps do not have any break between them. Only requires one extra
+ // read because a map has to contain at least one page, and the total
+ // number of bytes to dump is smaller than a page.
+ size_t bytes2 = backtrace->Read(addr + bytes, reinterpret_cast<uint8_t*>(data) + bytes,
+ sizeof(data) - bytes);
+ bytes += bytes2;
+ if (bytes2 > 0 && bytes % sizeof(uintptr_t) != 0) {
+ // This should never happen, but we'll try and continue any way.
+ ALOGE("Bytes after second read %zu, is not a multiple of %zu", bytes, sizeof(uintptr_t));
+ bytes &= ~(sizeof(uintptr_t) - 1);
+ }
+ }
+
+ // Dump the code around memory as:
+ // addr contents ascii
+ // 0000000000008d34 ef000000e8bd0090 e1b00000512fff1e ............../Q
+ // 0000000000008d44 ea00b1f9e92d0090 e3a070fcef000000 ......-..p......
+ // On 32-bit machines, there are still 16 bytes per line but addresses and
+ // words are of course presented differently.
+ uintptr_t* data_ptr = data;
+ for (size_t line = 0; line < MEMORY_BYTES_TO_DUMP / MEMORY_BYTES_PER_LINE; line++) {
+ std::string logline;
+ android::base::StringAppendF(&logline, " %" PRIPTR, addr);
+
+ addr += MEMORY_BYTES_PER_LINE;
+ std::string ascii;
+ for (size_t i = 0; i < MEMORY_BYTES_PER_LINE / sizeof(uintptr_t); i++, data_ptr++) {
+ if (bytes >= sizeof(uintptr_t)) {
+ bytes -= sizeof(uintptr_t);
+ android::base::StringAppendF(&logline, " %" PRIPTR, *data_ptr);
+
+ // Fill out the ascii string from the data.
+ uint8_t* ptr = reinterpret_cast<uint8_t*>(data_ptr);
+ for (size_t val = 0; val < sizeof(uintptr_t); val++, ptr++) {
+ if (*ptr >= 0x20 && *ptr < 0x7f) {
+ ascii += *ptr;
+ } else {
+ ascii += '.';
+ }
}
- *asc_out = '\0';
- _LOG(log, logtype::MEMORY, " %s %s\n", code_buffer, ascii_buffer);
+ } else {
+ logline += ' ' + std::string(sizeof(uintptr_t) * 2, '-');
+ ascii += std::string(sizeof(uintptr_t), '.');
+ }
}
+ _LOG(log, logtype::MEMORY, "%s %s\n", logline.c_str(), ascii.c_str());
+ }
}
diff --git a/debuggerd/utility.h b/debuggerd/utility.h
index 49b46e8..263374d 100644
--- a/debuggerd/utility.h
+++ b/debuggerd/utility.h
@@ -21,6 +21,8 @@
#include <stdbool.h>
#include <sys/types.h>
+#include <backtrace/Backtrace.h>
+
// Figure out the abi based on defined macros.
#if defined(__arm__)
#define ABI_STRING "arm"
@@ -75,6 +77,6 @@ void _LOG(log_t* log, logtype ltype, const char *fmt, ...)
int wait_for_sigstop(pid_t, int*, bool*);
-void dump_memory(log_t* log, pid_t tid, uintptr_t addr);
+void dump_memory(log_t* log, Backtrace* backtrace, uintptr_t addr, const char* fmt, ...);
#endif // _DEBUGGERD_UTILITY_H
diff --git a/debuggerd/x86/machine.cpp b/debuggerd/x86/machine.cpp
index 57330c1..c5f9259 100644
--- a/debuggerd/x86/machine.cpp
+++ b/debuggerd/x86/machine.cpp
@@ -14,18 +14,31 @@
* limitations under the License.
*/
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
#include <errno.h>
-#include <sys/types.h>
+#include <stdint.h>
+#include <string.h>
#include <sys/ptrace.h>
-#include "../utility.h"
-#include "../machine.h"
+#include <backtrace/Backtrace.h>
+
+#include "machine.h"
+#include "utility.h"
+
+void dump_memory_and_code(log_t* log, Backtrace* backtrace) {
+ struct pt_regs r;
+ if (ptrace(PTRACE_GETREGS, backtrace->Tid(), 0, &r) == -1) {
+ _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
+ return;
+ }
+
+ dump_memory(log, backtrace, static_cast<uintptr_t>(r.eax), "memory near eax:");
+ dump_memory(log, backtrace, static_cast<uintptr_t>(r.ebx), "memory near ebx:");
+ dump_memory(log, backtrace, static_cast<uintptr_t>(r.ecx), "memory near ecx:");
+ dump_memory(log, backtrace, static_cast<uintptr_t>(r.edx), "memory near edx:");
+ dump_memory(log, backtrace, static_cast<uintptr_t>(r.esi), "memory near esi:");
+ dump_memory(log, backtrace, static_cast<uintptr_t>(r.edi), "memory near edi:");
-void dump_memory_and_code(log_t*, pid_t) {
+ dump_memory(log, backtrace, static_cast<uintptr_t>(r.eip), "code around eip:");
}
void dump_registers(log_t* log, pid_t tid) {
@@ -34,6 +47,7 @@ void dump_registers(log_t* log, pid_t tid) {
_LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
return;
}
+
_LOG(log, logtype::REGISTERS, " eax %08lx ebx %08lx ecx %08lx edx %08lx\n",
r.eax, r.ebx, r.ecx, r.edx);
_LOG(log, logtype::REGISTERS, " esi %08lx edi %08lx\n",
diff --git a/debuggerd/x86_64/machine.cpp b/debuggerd/x86_64/machine.cpp
index af4f35a..4f09a5d 100755..100644
--- a/debuggerd/x86_64/machine.cpp
+++ b/debuggerd/x86_64/machine.cpp
@@ -14,38 +14,51 @@
** limitations under the License.
*/
-#include <stddef.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
#include <errno.h>
-#include <sys/types.h>
+#include <stdint.h>
#include <sys/ptrace.h>
+#include <string.h>
#include <sys/user.h>
-#include "../utility.h"
-#include "../machine.h"
+#include <backtrace/Backtrace.h>
+
+#include "machine.h"
+#include "utility.h"
-void dump_memory_and_code(log_t*, pid_t) {
+void dump_memory_and_code(log_t* log, Backtrace* backtrace) {
+ struct user_regs_struct r;
+ if (ptrace(PTRACE_GETREGS, backtrace->Tid(), 0, &r) == -1) {
+ _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
+ return;
+ }
+
+ dump_memory(log, backtrace, static_cast<uintptr_t>(r.rax), "memory near rax:");
+ dump_memory(log, backtrace, static_cast<uintptr_t>(r.rbx), "memory near rbx:");
+ dump_memory(log, backtrace, static_cast<uintptr_t>(r.rcx), "memory near rcx:");
+ dump_memory(log, backtrace, static_cast<uintptr_t>(r.rdx), "memory near rdx:");
+ dump_memory(log, backtrace, static_cast<uintptr_t>(r.rsi), "memory near rsi:");
+ dump_memory(log, backtrace, static_cast<uintptr_t>(r.rdi), "memory near rdi:");
+
+ dump_memory(log, backtrace, static_cast<uintptr_t>(r.rip), "code around rip:");
}
void dump_registers(log_t* log, pid_t tid) {
- struct user_regs_struct r;
- if (ptrace(PTRACE_GETREGS, tid, 0, &r) == -1) {
- _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
- return;
- }
- _LOG(log, logtype::REGISTERS, " rax %016lx rbx %016lx rcx %016lx rdx %016lx\n",
- r.rax, r.rbx, r.rcx, r.rdx);
- _LOG(log, logtype::REGISTERS, " rsi %016lx rdi %016lx\n",
- r.rsi, r.rdi);
- _LOG(log, logtype::REGISTERS, " r8 %016lx r9 %016lx r10 %016lx r11 %016lx\n",
- r.r8, r.r9, r.r10, r.r11);
- _LOG(log, logtype::REGISTERS, " r12 %016lx r13 %016lx r14 %016lx r15 %016lx\n",
- r.r12, r.r13, r.r14, r.r15);
- _LOG(log, logtype::REGISTERS, " cs %016lx ss %016lx\n",
- r.cs, r.ss);
- _LOG(log, logtype::REGISTERS, " rip %016lx rbp %016lx rsp %016lx eflags %016lx\n",
- r.rip, r.rbp, r.rsp, r.eflags);
+ struct user_regs_struct r;
+ if (ptrace(PTRACE_GETREGS, tid, 0, &r) == -1) {
+ _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
+ return;
+ }
+
+ _LOG(log, logtype::REGISTERS, " rax %016lx rbx %016lx rcx %016lx rdx %016lx\n",
+ r.rax, r.rbx, r.rcx, r.rdx);
+ _LOG(log, logtype::REGISTERS, " rsi %016lx rdi %016lx\n",
+ r.rsi, r.rdi);
+ _LOG(log, logtype::REGISTERS, " r8 %016lx r9 %016lx r10 %016lx r11 %016lx\n",
+ r.r8, r.r9, r.r10, r.r11);
+ _LOG(log, logtype::REGISTERS, " r12 %016lx r13 %016lx r14 %016lx r15 %016lx\n",
+ r.r12, r.r13, r.r14, r.r15);
+ _LOG(log, logtype::REGISTERS, " cs %016lx ss %016lx\n",
+ r.cs, r.ss);
+ _LOG(log, logtype::REGISTERS, " rip %016lx rbp %016lx rsp %016lx eflags %016lx\n",
+ r.rip, r.rbp, r.rsp, r.eflags);
}