summaryrefslogtreecommitdiff
path: root/libunwindstack/Regs.cpp
diff options
context:
space:
mode:
authorChristopher Ferris <cferris@google.com>2017-07-18 16:09:20 -0700
committerChristopher Ferris <cferris@google.com>2017-07-18 17:27:48 -0700
commit38b1069d9a90f77ef014c3c7e19bb29ef6d20ea3 (patch)
tree1131a7fa391b8315374624d9a02654e4bd705f66 /libunwindstack/Regs.cpp
parent81e61fa6964dfa45301b555ea1ae000bb97df07b (diff)
downloadunwinding-38b1069d9a90f77ef014c3c7e19bb29ef6d20ea3.tar.gz
Add signal handling to the register object.
- Add the StepIfSignalHandler function to the Regs object that checks if the code is in a signal handler. - Add tests for new code, also add a test that unwinds through a signal handler. - Slight modification to Elf to fail if a bad machine type is encountered. Add tests for this. Bug: 23762183 Test: Ran unit tests. Change-Id: Idafa1105d00b91a9343d7464ac9ed1cb95830963
Diffstat (limited to 'libunwindstack/Regs.cpp')
-rw-r--r--libunwindstack/Regs.cpp240
1 files changed, 208 insertions, 32 deletions
diff --git a/libunwindstack/Regs.cpp b/libunwindstack/Regs.cpp
index aa59e31..33319b1 100644
--- a/libunwindstack/Regs.cpp
+++ b/libunwindstack/Regs.cpp
@@ -258,49 +258,51 @@ static Regs* CreateFromArm64Ucontext(void* ucontext) {
return regs;
}
+void RegsX86::SetFromUcontext(x86_ucontext_t* ucontext) {
+ // Put the registers in the expected order.
+ regs_[X86_REG_EDI] = ucontext->uc_mcontext.edi;
+ regs_[X86_REG_ESI] = ucontext->uc_mcontext.esi;
+ regs_[X86_REG_EBP] = ucontext->uc_mcontext.ebp;
+ regs_[X86_REG_ESP] = ucontext->uc_mcontext.esp;
+ regs_[X86_REG_EBX] = ucontext->uc_mcontext.ebx;
+ regs_[X86_REG_EDX] = ucontext->uc_mcontext.edx;
+ regs_[X86_REG_ECX] = ucontext->uc_mcontext.ecx;
+ regs_[X86_REG_EAX] = ucontext->uc_mcontext.eax;
+ regs_[X86_REG_EIP] = ucontext->uc_mcontext.eip;
+ SetFromRaw();
+}
+
static Regs* CreateFromX86Ucontext(void* ucontext) {
x86_ucontext_t* x86_ucontext = reinterpret_cast<x86_ucontext_t*>(ucontext);
RegsX86* regs = new RegsX86();
- // Put the registers in the expected order.
- (*regs)[X86_REG_GS] = x86_ucontext->uc_mcontext.gs;
- (*regs)[X86_REG_FS] = x86_ucontext->uc_mcontext.fs;
- (*regs)[X86_REG_ES] = x86_ucontext->uc_mcontext.es;
- (*regs)[X86_REG_DS] = x86_ucontext->uc_mcontext.ds;
- (*regs)[X86_REG_EDI] = x86_ucontext->uc_mcontext.edi;
- (*regs)[X86_REG_ESI] = x86_ucontext->uc_mcontext.esi;
- (*regs)[X86_REG_EBP] = x86_ucontext->uc_mcontext.ebp;
- (*regs)[X86_REG_ESP] = x86_ucontext->uc_mcontext.esp;
- (*regs)[X86_REG_EBX] = x86_ucontext->uc_mcontext.ebx;
- (*regs)[X86_REG_EDX] = x86_ucontext->uc_mcontext.edx;
- (*regs)[X86_REG_ECX] = x86_ucontext->uc_mcontext.ecx;
- (*regs)[X86_REG_EAX] = x86_ucontext->uc_mcontext.eax;
- (*regs)[X86_REG_EIP] = x86_ucontext->uc_mcontext.eip;
- regs->SetFromRaw();
+ regs->SetFromUcontext(x86_ucontext);
return regs;
}
-static Regs* CreateFromX86_64Ucontext(void* ucontext) {
- x86_64_ucontext_t* x86_64_ucontext = reinterpret_cast<x86_64_ucontext_t*>(ucontext);
-
- RegsX86_64* regs = new RegsX86_64();
- // Put the registers in the expected order.
-
+void RegsX86_64::SetFromUcontext(x86_64_ucontext_t* ucontext) {
// R8-R15
- memcpy(&(*regs)[X86_64_REG_R8], &x86_64_ucontext->uc_mcontext.r8, 8 * sizeof(uint64_t));
+ memcpy(&regs_[X86_64_REG_R8], &ucontext->uc_mcontext.r8, 8 * sizeof(uint64_t));
// Rest of the registers.
- (*regs)[X86_64_REG_RDI] = x86_64_ucontext->uc_mcontext.rdi;
- (*regs)[X86_64_REG_RSI] = x86_64_ucontext->uc_mcontext.rsi;
- (*regs)[X86_64_REG_RBP] = x86_64_ucontext->uc_mcontext.rbp;
- (*regs)[X86_64_REG_RBX] = x86_64_ucontext->uc_mcontext.rbx;
- (*regs)[X86_64_REG_RDX] = x86_64_ucontext->uc_mcontext.rdx;
- (*regs)[X86_64_REG_RAX] = x86_64_ucontext->uc_mcontext.rax;
- (*regs)[X86_64_REG_RCX] = x86_64_ucontext->uc_mcontext.rcx;
- (*regs)[X86_64_REG_RSP] = x86_64_ucontext->uc_mcontext.rsp;
- (*regs)[X86_64_REG_RIP] = x86_64_ucontext->uc_mcontext.rip;
+ regs_[X86_64_REG_RDI] = ucontext->uc_mcontext.rdi;
+ regs_[X86_64_REG_RSI] = ucontext->uc_mcontext.rsi;
+ regs_[X86_64_REG_RBP] = ucontext->uc_mcontext.rbp;
+ regs_[X86_64_REG_RBX] = ucontext->uc_mcontext.rbx;
+ regs_[X86_64_REG_RDX] = ucontext->uc_mcontext.rdx;
+ regs_[X86_64_REG_RAX] = ucontext->uc_mcontext.rax;
+ regs_[X86_64_REG_RCX] = ucontext->uc_mcontext.rcx;
+ regs_[X86_64_REG_RSP] = ucontext->uc_mcontext.rsp;
+ regs_[X86_64_REG_RIP] = ucontext->uc_mcontext.rip;
+
+ SetFromRaw();
+}
- regs->SetFromRaw();
+static Regs* CreateFromX86_64Ucontext(void* ucontext) {
+ x86_64_ucontext_t* x86_64_ucontext = reinterpret_cast<x86_64_ucontext_t*>(ucontext);
+
+ RegsX86_64* regs = new RegsX86_64();
+ regs->SetFromUcontext(x86_64_ucontext);
return regs;
}
@@ -348,4 +350,178 @@ Regs* Regs::CreateFromLocal() {
return regs;
}
+bool RegsArm::StepIfSignalHandler(Memory* memory) {
+ uint32_t data;
+ if (!memory->Read(pc(), &data, sizeof(data))) {
+ return false;
+ }
+
+ uint64_t offset = 0;
+ if (data == 0xe3a07077 || data == 0xef900077 || data == 0xdf002777) {
+ // non-RT sigreturn call.
+ // __restore:
+ //
+ // Form 1 (arm):
+ // 0x77 0x70 mov r7, #0x77
+ // 0xa0 0xe3 svc 0x00000000
+ //
+ // Form 2 (arm):
+ // 0x77 0x00 0x90 0xef svc 0x00900077
+ //
+ // Form 3 (thumb):
+ // 0x77 0x27 movs r7, #77
+ // 0x00 0xdf svc 0
+ if (!memory->Read(sp(), &data, sizeof(data))) {
+ return false;
+ }
+ if (data == 0x5ac3c35a) {
+ // SP + uc_mcontext offset + r0 offset.
+ offset = sp() + 0x14 + 0xc;
+ } else {
+ // SP + r0 offset
+ offset = sp() + 0xc;
+ }
+ } else if (data == 0xe3a070ad || data == 0xef9000ad || data == 0xdf0027ad) {
+ // RT sigreturn call.
+ // __restore_rt:
+ //
+ // Form 1 (arm):
+ // 0xad 0x70 mov r7, #0xad
+ // 0xa0 0xe3 svc 0x00000000
+ //
+ // Form 2 (arm):
+ // 0xad 0x00 0x90 0xef svc 0x009000ad
+ //
+ // Form 3 (thumb):
+ // 0xad 0x27 movs r7, #ad
+ // 0x00 0xdf svc 0
+ if (!memory->Read(sp(), &data, sizeof(data))) {
+ return false;
+ }
+ if (data == sp() + 8) {
+ // SP + 8 + sizeof(siginfo_t) + uc_mcontext_offset + r0 offset
+ offset = sp() + 8 + 0x80 + 0x14 + 0xc;
+ } else {
+ // SP + sizeof(siginfo_t) + uc_mcontext_offset + r0 offset
+ offset = sp() + 0x80 + 0x14 + 0xc;
+ }
+ }
+ if (offset == 0) {
+ return false;
+ }
+
+ if (!memory->Read(offset, regs_.data(), sizeof(uint32_t) * ARM_REG_LAST)) {
+ return false;
+ }
+ SetFromRaw();
+ return true;
+}
+
+bool RegsArm64::StepIfSignalHandler(Memory* memory) {
+ uint64_t data;
+ if (!memory->Read(pc(), &data, sizeof(data))) {
+ return false;
+ }
+
+ // Look for the kernel sigreturn function.
+ // __kernel_rt_sigreturn:
+ // 0xd2801168 mov x8, #0x8b
+ // 0xd4000001 svc #0x0
+ if (data != 0xd4000001d2801168ULL) {
+ return false;
+ }
+
+ // SP + sizeof(siginfo_t) + uc_mcontext offset + X0 offset.
+ if (!memory->Read(sp() + 0x80 + 0xb0 + 0x08, regs_.data(), sizeof(uint64_t) * ARM64_REG_LAST)) {
+ return false;
+ }
+
+ SetFromRaw();
+ return true;
+}
+
+bool RegsX86::StepIfSignalHandler(Memory* memory) {
+ uint64_t data;
+ if (!memory->Read(pc(), &data, sizeof(data))) {
+ return false;
+ }
+
+ if (data == 0x80cd00000077b858ULL) {
+ // Without SA_SIGINFO set, the return sequence is:
+ //
+ // __restore:
+ // 0x58 pop %eax
+ // 0xb8 0x77 0x00 0x00 0x00 movl 0x77,%eax
+ // 0xcd 0x80 int 0x80
+ //
+ // SP points at arguments:
+ // int signum
+ // struct sigcontext (same format as mcontext)
+ struct x86_mcontext_t context;
+ if (!memory->Read(sp() + 4, &context, sizeof(context))) {
+ return false;
+ }
+ regs_[X86_REG_EBP] = context.ebp;
+ regs_[X86_REG_ESP] = context.esp;
+ regs_[X86_REG_EBX] = context.ebx;
+ regs_[X86_REG_EDX] = context.edx;
+ regs_[X86_REG_ECX] = context.ecx;
+ regs_[X86_REG_EAX] = context.eax;
+ regs_[X86_REG_EIP] = context.eip;
+ SetFromRaw();
+ return true;
+ } else if ((data & 0x00ffffffffffffffULL) == 0x0080cd000000adb8ULL) {
+ // With SA_SIGINFO set, the return sequence is:
+ //
+ // __restore_rt:
+ // 0xb8 0xad 0x00 0x00 0x00 movl 0xad,%eax
+ // 0xcd 0x80 int 0x80
+ //
+ // SP points at arguments:
+ // int signum
+ // siginfo*
+ // ucontext*
+
+ // Get the location of the sigcontext data.
+ uint32_t ptr;
+ if (!memory->Read(sp() + 8, &ptr, sizeof(ptr))) {
+ return false;
+ }
+ // Only read the portion of the data structure we care about.
+ x86_ucontext_t x86_ucontext;
+ if (!memory->Read(ptr + 0x14, &x86_ucontext.uc_mcontext, sizeof(x86_mcontext_t))) {
+ return false;
+ }
+ SetFromUcontext(&x86_ucontext);
+ return true;
+ }
+ return false;
+}
+
+bool RegsX86_64::StepIfSignalHandler(Memory* memory) {
+ uint64_t data;
+ if (!memory->Read(pc(), &data, sizeof(data)) || data != 0x0f0000000fc0c748) {
+ return false;
+ }
+
+ uint16_t data2;
+ if (!memory->Read(pc() + 8, &data2, sizeof(data2)) || data2 != 0x0f05) {
+ return false;
+ }
+
+ // __restore_rt:
+ // 0x48 0xc7 0xc0 0x0f 0x00 0x00 0x00 mov $0xf,%rax
+ // 0x0f 0x05 syscall
+ // 0x0f nopl 0x0($rax)
+
+ // Read the mcontext data from the stack.
+ // sp points to the ucontext data structure, read only the mcontext part.
+ x86_64_ucontext_t x86_64_ucontext;
+ if (!memory->Read(sp() + 0x28, &x86_64_ucontext.uc_mcontext, sizeof(x86_64_mcontext_t))) {
+ return false;
+ }
+ SetFromUcontext(&x86_64_ucontext);
+ return true;
+}
+
} // namespace unwindstack