diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp index 794e3e7b2fb6c9..aa74a4c581dd0f 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp @@ -2118,8 +2118,122 @@ bool SignalContext::IsTrueFaultingAddress() const { return si->si_signo == SIGSEGV && si->si_code != 128; } +UNUSED +static const char *RegNumToRegName(int reg) { + switch (reg) { +# if defined(__x86_64__) + case REG_RAX: + return "rax"; + case REG_RBX: + return "rbx"; + case REG_RCX: + return "rcx"; + case REG_RDX: + return "rdx"; + case REG_RDI: + return "rdi"; + case REG_RSI: + return "rsi"; + case REG_RBP: + return "rbp"; + case REG_RSP: + return "rsp"; + case REG_R8: + return "r8"; + case REG_R9: + return "r9"; + case REG_R10: + return "r10"; + case REG_R11: + return "r11"; + case REG_R12: + return "r12"; + case REG_R13: + return "r13"; + case REG_R14: + return "r14"; + case REG_R15: + return "r15"; +# elif defined(__i386__) + case REG_EAX: + return "eax"; + case REG_EBX: + return "ebx"; + case REG_ECX: + return "ecx"; + case REG_EDX: + return "edx"; + case REG_EDI: + return "edi"; + case REG_ESI: + return "esi"; + case REG_EBP: + return "ebp"; + case REG_ESP: + return "esp"; +# endif + default: + return NULL; + } + return NULL; +} + +UNUSED +static void DumpSingleReg(ucontext_t *ctx, int RegNum) { + const char *RegName = RegNumToRegName(RegNum); +# if defined(__x86_64__) + Printf("%s%s = 0x%016llx ", internal_strlen(RegName) == 2 ? " " : "", + RegName, ctx->uc_mcontext.gregs[RegNum]); +# elif defined(__i386__) + Printf("%s = 0x%08x ", RegName, ctx->uc_mcontext.gregs[RegNum]); +# endif +} + void SignalContext::DumpAllRegisters(void *context) { - // FIXME: Implement this. +# if SANITIZER_LINUX + ucontext_t *ucontext = (ucontext_t *)context; +# if defined(__x86_64__) + Report("Register values:\n"); + DumpSingleReg(ucontext, REG_RAX); + DumpSingleReg(ucontext, REG_RBX); + DumpSingleReg(ucontext, REG_RCX); + DumpSingleReg(ucontext, REG_RDX); + Printf("\n"); + DumpSingleReg(ucontext, REG_RDI); + DumpSingleReg(ucontext, REG_RSI); + DumpSingleReg(ucontext, REG_RBP); + DumpSingleReg(ucontext, REG_RSP); + Printf("\n"); + DumpSingleReg(ucontext, REG_R8); + DumpSingleReg(ucontext, REG_R9); + DumpSingleReg(ucontext, REG_R10); + DumpSingleReg(ucontext, REG_R11); + Printf("\n"); + DumpSingleReg(ucontext, REG_R12); + DumpSingleReg(ucontext, REG_R13); + DumpSingleReg(ucontext, REG_R14); + DumpSingleReg(ucontext, REG_R15); + Printf("\n"); +# elif defined(__i386__) + // Duplication of this report print is caused by partial support + // of register values dumping. In case of unsupported yet architecture let's + // avoid printing 'Register values:' without actual values in the following + // output. + Report("Register values:\n"); + DumpSingleReg(ucontext, REG_EAX); + DumpSingleReg(ucontext, REG_EBX); + DumpSingleReg(ucontext, REG_ECX); + DumpSingleReg(ucontext, REG_EDX); + Printf("\n"); + DumpSingleReg(ucontext, REG_EDI); + DumpSingleReg(ucontext, REG_ESI); + DumpSingleReg(ucontext, REG_EBP); + DumpSingleReg(ucontext, REG_ESP); + Printf("\n"); +# endif + (void)ucontext; +# endif + // FIXME: Implement this for other OSes and architectures. } static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { diff --git a/compiler-rt/test/sanitizer_common/TestCases/Linux/dump_registers_i386.cpp b/compiler-rt/test/sanitizer_common/TestCases/Linux/dump_registers_i386.cpp new file mode 100644 index 00000000000000..0a6c3e361732c6 --- /dev/null +++ b/compiler-rt/test/sanitizer_common/TestCases/Linux/dump_registers_i386.cpp @@ -0,0 +1,17 @@ +// Check that sanitizer prints registers dump_registers on dump_registers=1 +// RUN: %clangxx %s -o %t +// RUN: %env_tool_opts=dump_registers=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-NODUMP +// RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-DUMP +// +// REQUIRES: i386-target-arch + +#include + +int main() { + raise(SIGSEGV); + // CHECK-DUMP: Register values + // CHECK-DUMP-NEXT: eax = {{0x[0-9a-f]+}} ebx = {{0x[0-9a-f]+}} ecx = {{0x[0-9a-f]+}} edx = {{0x[0-9a-f]+}} + // CHECK-DUMP-NEXT: edi = {{0x[0-9a-f]+}} esi = {{0x[0-9a-f]+}} ebp = {{0x[0-9a-f]+}} esp = {{0x[0-9a-f]+}} + // CHECK-NODUMP-NOT: Register values + return 0; +} diff --git a/compiler-rt/test/sanitizer_common/TestCases/Linux/dump_registers_x86_64.cpp b/compiler-rt/test/sanitizer_common/TestCases/Linux/dump_registers_x86_64.cpp new file mode 100644 index 00000000000000..1805343c230637 --- /dev/null +++ b/compiler-rt/test/sanitizer_common/TestCases/Linux/dump_registers_x86_64.cpp @@ -0,0 +1,19 @@ +// Check that sanitizer prints registers dump_registers on dump_registers=1 +// RUN: %clangxx %s -o %t +// RUN: %env_tool_opts=dump_registers=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-NODUMP +// RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-DUMP +// +// REQUIRES: x86_64-target-arch + +#include + +int main() { + raise(SIGSEGV); + // CHECK-DUMP: Register values + // CHECK-DUMP-NEXT: rax = {{0x[0-9a-f]+}} rbx = {{0x[0-9a-f]+}} rcx = {{0x[0-9a-f]+}} rdx = {{0x[0-9a-f]+}} + // CHECK-DUMP-NEXT: rdi = {{0x[0-9a-f]+}} rsi = {{0x[0-9a-f]+}} rbp = {{0x[0-9a-f]+}} rsp = {{0x[0-9a-f]+}} + // CHECK-DUMP-NEXT: r8 = {{0x[0-9a-f]+}} r9 = {{0x[0-9a-f]+}} r10 = {{0x[0-9a-f]+}} r11 = {{0x[0-9a-f]+}} + // CHECK-DUMP-NEXT: r12 = {{0x[0-9a-f]+}} r13 = {{0x[0-9a-f]+}} r14 = {{0x[0-9a-f]+}} r15 = {{0x[0-9a-f]+}} + // CHECK-NODUMP-NOT: Register values + return 0; +}