From ef1c70d26b7e84a6f47c0c6a868b769935b2b008 Mon Sep 17 00:00:00 2001 From: Dmitry Chestnykh Date: Wed, 24 Jul 2024 09:52:51 +0300 Subject: [PATCH] [compiler-rt] Implement `DumpAllRegisters` for arm-linux and aarch64-linux (#99613) Examples of the output: ARM: ``` # ./a.out AddressSanitizer:DEADLYSIGNAL ================================================================= ==122==ERROR: AddressSanitizer: SEGV on unknown address 0x0000007a (pc 0x76e13ac0 bp 0x7eb7fd00 sp 0x7eb7fcc8 T0) ==122==The signal is caused by a READ memory access. ==122==Hint: address points to the zero page. #0 0x76e13ac0 (/lib/libc.so.6+0x7cac0) #1 0x76dce680 in gsignal (/lib/libc.so.6+0x37680) #2 0x005c2250 (/root/a.out+0x145250) #3 0x76db982c (/lib/libc.so.6+0x2282c) #4 0x76db9918 in __libc_start_main (/lib/libc.so.6+0x22918) ==122==Register values: r0 = 0x00000000 r1 = 0x0000007a r2 = 0x0000000b r3 = 0x76d95020 r4 = 0x0000007a r5 = 0x00000001 r6 = 0x005dcc5c r7 = 0x0000010c r8 = 0x0000000b r9 = 0x76f9ece0 r10 = 0x00000000 r11 = 0x7eb7fd00 r12 = 0x76dce670 sp = 0x7eb7fcc8 lr = 0x76e13ab4 pc = 0x76e13ac0 AddressSanitizer can not provide additional info. SUMMARY: AddressSanitizer: SEGV (/lib/libc.so.6+0x7cac0) ==122==ABORTING ``` AArch64: ``` # ./a.out UndefinedBehaviorSanitizer:DEADLYSIGNAL ==99==ERROR: UndefinedBehaviorSanitizer: SEGV on unknown address 0x000000000063 (pc 0x007fbbbc5860 bp 0x007fcfdcb700 sp 0x007fcfdcb700 T99) ==99==The signal is caused by a UNKNOWN memory access. ==99==Hint: address points to the zero page. #0 0x007fbbbc5860 (/lib64/libc.so.6+0x82860) #1 0x007fbbb81578 (/lib64/libc.so.6+0x3e578) #2 0x00556051152c (/root/a.out+0x3152c) #3 0x007fbbb6e268 (/lib64/libc.so.6+0x2b268) #4 0x007fbbb6e344 (/lib64/libc.so.6+0x2b344) #5 0x0055604e45ec (/root/a.out+0x45ec) ==99==Register values: x0 = 0x0000000000000000 x1 = 0x0000000000000063 x2 = 0x000000000000000b x3 = 0x0000007fbbb41440 x4 = 0x0000007fbbb41580 x5 = 0x3669288942d44cce x6 = 0x0000000000000000 x7 = 0x00000055605110b0 x8 = 0x0000000000000083 x9 = 0x0000000000000000 x10 = 0x0000000000000000 x11 = 0x0000000000000000 x12 = 0x0000007fbbdb3360 x13 = 0x0000000000010000 x14 = 0x0000000000000039 x15 = 0x00000000004113a0 x16 = 0x0000007fbbb81560 x17 = 0x0000005560540138 x18 = 0x000000006474e552 x19 = 0x0000000000000063 x20 = 0x0000000000000001 x21 = 0x000000000000000b x22 = 0x0000005560511510 x23 = 0x0000007fcfdcb918 x24 = 0x0000007fbbdb1b50 x25 = 0x0000000000000000 x26 = 0x0000007fbbdb2000 x27 = 0x000000556053f858 x28 = 0x0000000000000000 fp = 0x0000007fcfdcb700 lr = 0x0000007fbbbc584c sp = 0x0000007fcfdcb700 UndefinedBehaviorSanitizer can not provide additional info. SUMMARY: UndefinedBehaviorSanitizer: SEGV (/lib64/libc.so.6+0x82860) ==99==ABORTING ``` --- .../lib/sanitizer_common/sanitizer_linux.cpp | 142 +++++++++++++++++- .../Linux/dump_registers_aarch64.cpp | 23 +++ .../TestCases/Linux/dump_registers_arm.cpp | 19 +++ 3 files changed, 182 insertions(+), 2 deletions(-) create mode 100644 compiler-rt/test/sanitizer_common/TestCases/Linux/dump_registers_aarch64.cpp create mode 100644 compiler-rt/test/sanitizer_common/TestCases/Linux/dump_registers_arm.cpp diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp index 483a1042a62383..bc2cb247f2a8a8 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp @@ -2172,15 +2172,118 @@ static const char *RegNumToRegName(int reg) { return "ebp"; case REG_ESP: return "esp"; +# elif defined(__arm__) +# define REG_STR(reg) #reg +# define MAKE_CASE(N) \ + case REG_R##N: \ + return REG_STR(r##N) + MAKE_CASE(0); + MAKE_CASE(1); + MAKE_CASE(2); + MAKE_CASE(3); + MAKE_CASE(4); + MAKE_CASE(5); + MAKE_CASE(6); + MAKE_CASE(7); + MAKE_CASE(8); + MAKE_CASE(9); + MAKE_CASE(10); + MAKE_CASE(11); + MAKE_CASE(12); + case REG_R13: + return "sp"; + case REG_R14: + return "lr"; + case REG_R15: + return "pc"; +# elif defined(__aarch64__) +# define REG_STR(reg) #reg +# define MAKE_CASE(N) \ + case N: \ + return REG_STR(x##N) + MAKE_CASE(0); + MAKE_CASE(1); + MAKE_CASE(2); + MAKE_CASE(3); + MAKE_CASE(4); + MAKE_CASE(5); + MAKE_CASE(6); + MAKE_CASE(7); + MAKE_CASE(8); + MAKE_CASE(9); + MAKE_CASE(10); + MAKE_CASE(11); + MAKE_CASE(12); + MAKE_CASE(13); + MAKE_CASE(14); + MAKE_CASE(15); + MAKE_CASE(16); + MAKE_CASE(17); + MAKE_CASE(18); + MAKE_CASE(19); + MAKE_CASE(20); + MAKE_CASE(21); + MAKE_CASE(22); + MAKE_CASE(23); + MAKE_CASE(24); + MAKE_CASE(25); + MAKE_CASE(26); + MAKE_CASE(27); + MAKE_CASE(28); + case 29: + return "fp"; + case 30: + return "lr"; + case 31: + return "sp"; # endif -# endif default: return NULL; } return NULL; } -# if SANITIZER_LINUX +# if SANITIZER_LINUX && (defined(__arm__) || defined(__aarch64__)) +static uptr GetArmRegister(ucontext_t *ctx, int RegNum) { + switch (RegNum) { +# if defined(__arm__) +# define MAKE_CASE(N) \ + case REG_R##N: \ + return ctx->uc_mcontext.arm_r##N + MAKE_CASE(0); + MAKE_CASE(1); + MAKE_CASE(2); + MAKE_CASE(3); + MAKE_CASE(4); + MAKE_CASE(5); + MAKE_CASE(6); + MAKE_CASE(7); + MAKE_CASE(8); + MAKE_CASE(9); + MAKE_CASE(10); + case REG_R11: + return ctx->uc_mcontext.arm_fp; + case REG_R12: + return ctx->uc_mcontext.arm_ip; + case REG_R13: + return ctx->uc_mcontext.arm_sp; + case REG_R14: + return ctx->uc_mcontext.arm_lr; + case REG_R15: + return ctx->uc_mcontext.arm_pc; +# elif defined(__aarch64__) + case 0 ... 30: + return ctx->uc_mcontext.regs[RegNum]; + case 31: + return ctx->uc_mcontext.sp; +# endif + default: + return 0; + } + return 0; +} +# endif // SANITIZER_LINUX && (defined(__arm__) || defined(__aarch64__)) + UNUSED static void DumpSingleReg(ucontext_t *ctx, int RegNum) { const char *RegName = RegNumToRegName(RegNum); @@ -2189,6 +2292,12 @@ static void DumpSingleReg(ucontext_t *ctx, int RegNum) { RegName, ctx->uc_mcontext.gregs[RegNum]); # elif defined(__i386__) Printf("%s = 0x%08x ", RegName, ctx->uc_mcontext.gregs[RegNum]); +# elif defined(__arm__) + Printf("%s%s = 0x%08zx ", internal_strlen(RegName) == 2 ? " " : "", RegName, + GetArmRegister(ctx, RegNum)); +# elif defined(__aarch64__) + Printf("%s%s = 0x%016zx ", internal_strlen(RegName) == 2 ? " " : "", RegName, + GetArmRegister(ctx, RegNum)); # else (void)RegName; # endif @@ -2236,6 +2345,35 @@ void SignalContext::DumpAllRegisters(void *context) { DumpSingleReg(ucontext, REG_EBP); DumpSingleReg(ucontext, REG_ESP); Printf("\n"); +# elif defined(__arm__) + Report("Register values:\n"); + DumpSingleReg(ucontext, REG_R0); + DumpSingleReg(ucontext, REG_R1); + DumpSingleReg(ucontext, REG_R2); + DumpSingleReg(ucontext, REG_R3); + Printf("\n"); + DumpSingleReg(ucontext, REG_R4); + DumpSingleReg(ucontext, REG_R5); + DumpSingleReg(ucontext, REG_R6); + DumpSingleReg(ucontext, REG_R7); + 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(__aarch64__) + Report("Register values:\n"); + for (int i = 0; i <= 31; ++i) { + DumpSingleReg(ucontext, i); + if (i % 4 == 3) + Printf("\n"); + } # else (void)ucontext; # endif diff --git a/compiler-rt/test/sanitizer_common/TestCases/Linux/dump_registers_aarch64.cpp b/compiler-rt/test/sanitizer_common/TestCases/Linux/dump_registers_aarch64.cpp new file mode 100644 index 00000000000000..e01b826c86b8ac --- /dev/null +++ b/compiler-rt/test/sanitizer_common/TestCases/Linux/dump_registers_aarch64.cpp @@ -0,0 +1,23 @@ +// 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 --strict-whitespace --check-prefix=CHECK-DUMP +// +// REQUIRES: aarch64-target-arch + +#include + +int main() { + raise(SIGSEGV); + // CHECK-DUMP: Register values + // CHECK-DUMP-NEXT: x0 = {{0x[0-9a-f]+}} x1 = {{0x[0-9a-f]+}} x2 = {{0x[0-9a-f]+}} x3 = {{0x[0-9a-f]+}} + // CHECK-DUMP-NEXT: x4 = {{0x[0-9a-f]+}} x5 = {{0x[0-9a-f]+}} x6 = {{0x[0-9a-f]+}} x7 = {{0x[0-9a-f]+}} + // CHECK-DUMP-NEXT: x8 = {{0x[0-9a-f]+}} x9 = {{0x[0-9a-f]+}} x10 = {{0x[0-9a-f]+}} x11 = {{0x[0-9a-f]+}} + // CHECK-DUMP-NEXT:x12 = {{0x[0-9a-f]+}} x13 = {{0x[0-9a-f]+}} x14 = {{0x[0-9a-f]+}} x15 = {{0x[0-9a-f]+}} + // CHECK-DUMP-NEXT:x16 = {{0x[0-9a-f]+}} x17 = {{0x[0-9a-f]+}} x18 = {{0x[0-9a-f]+}} x19 = {{0x[0-9a-f]+}} + // CHECK-DUMP-NEXT:x20 = {{0x[0-9a-f]+}} x21 = {{0x[0-9a-f]+}} x22 = {{0x[0-9a-f]+}} x23 = {{0x[0-9a-f]+}} + // CHECK-DUMP-NEXT:x24 = {{0x[0-9a-f]+}} x25 = {{0x[0-9a-f]+}} x26 = {{0x[0-9a-f]+}} x27 = {{0x[0-9a-f]+}} + // CHECK-DUMP-NEXT:x28 = {{0x[0-9a-f]+}} fp = {{0x[0-9a-f]+}} lr = {{0x[0-9a-f]+}} sp = {{0x[0-9a-f]+}} + // CHECK-NODUMP-NOT: Register values + return 0; +} diff --git a/compiler-rt/test/sanitizer_common/TestCases/Linux/dump_registers_arm.cpp b/compiler-rt/test/sanitizer_common/TestCases/Linux/dump_registers_arm.cpp new file mode 100644 index 00000000000000..e17dbf196227b6 --- /dev/null +++ b/compiler-rt/test/sanitizer_common/TestCases/Linux/dump_registers_arm.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 --strict-whitespace --check-prefix=CHECK-DUMP +// +// REQUIRES: arm-target-arch + +#include + +int main() { + raise(SIGSEGV); + // CHECK-DUMP: Register values + // CHECK-DUMP-NEXT: r0 = {{0x[0-9a-f]+}} r1 = {{0x[0-9a-f]+}} r2 = {{0x[0-9a-f]+}} r3 = {{0x[0-9a-f]+}} + // CHECK-DUMP-NEXT: r4 = {{0x[0-9a-f]+}} r5 = {{0x[0-9a-f]+}} r6 = {{0x[0-9a-f]+}} r7 = {{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]+}} sp = {{0x[0-9a-f]+}} lr = {{0x[0-9a-f]+}} pc = {{0x[0-9a-f]+}} + // CHECK-NODUMP-NOT: Register values + return 0; +}