diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp index 3a3883902..d61384ef1 100644 --- a/libbacktrace/UnwindStack.cpp +++ b/libbacktrace/UnwindStack.cpp @@ -99,8 +99,7 @@ bool UnwindStackCurrent::UnwindFromContext(size_t num_ignore_frames, ucontext_t* // one extra function call appearing in the unwind. unwindstack::RegsGetLocal(regs.get()); } else { - regs.reset( - unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentMachineType(), ucontext)); + regs.reset(unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(), ucontext)); } error_ = BACKTRACE_UNWIND_NO_ERROR; @@ -120,8 +119,7 @@ bool UnwindStackPtrace::Unwind(size_t num_ignore_frames, ucontext_t* context) { if (context == nullptr) { regs.reset(unwindstack::Regs::RemoteGet(Tid())); } else { - regs.reset( - unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentMachineType(), context)); + regs.reset(unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(), context)); } error_ = BACKTRACE_UNWIND_NO_ERROR; diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp index 74930d6eb..4125b1204 100644 --- a/libunwindstack/Android.bp +++ b/libunwindstack/Android.bp @@ -60,6 +60,10 @@ cc_library { "Maps.cpp", "Memory.cpp", "Regs.cpp", + "RegsArm.cpp", + "RegsArm64.cpp", + "RegsX86.cpp", + "RegsX86_64.cpp", "Unwinder.cpp", "Symbols.cpp", ], diff --git a/libunwindstack/ArmExidx.cpp b/libunwindstack/ArmExidx.cpp index fed3e0e0f..6b0646fbc 100644 --- a/libunwindstack/ArmExidx.cpp +++ b/libunwindstack/ArmExidx.cpp @@ -23,11 +23,11 @@ #include #include -#include +#include #include "ArmExidx.h" #include "Check.h" -#include "Machine.h" +#include "MachineArm.h" namespace unwindstack { diff --git a/libunwindstack/Elf.cpp b/libunwindstack/Elf.cpp index 5f307ed9e..025429f52 100644 --- a/libunwindstack/Elf.cpp +++ b/libunwindstack/Elf.cpp @@ -31,7 +31,6 @@ #include #include "ElfInterfaceArm.h" -#include "Machine.h" #include "Symbols.h" namespace unwindstack { @@ -183,18 +182,15 @@ ElfInterface* Elf::CreateInterfaceFromMemory(Memory* memory) { return nullptr; } - if (e_machine != EM_ARM && e_machine != EM_386) { - // Unsupported. - ALOGI("32 bit elf that is neither arm nor x86: e_machine = %d\n", e_machine); - return nullptr; - } - machine_type_ = e_machine; if (e_machine == EM_ARM) { + arch_ = ARCH_ARM; interface.reset(new ElfInterfaceArm(memory)); } else if (e_machine == EM_386) { + arch_ = ARCH_X86; interface.reset(new ElfInterface32(memory)); } else { + // Unsupported. ALOGI("32 bit elf that is neither arm nor x86: e_machine = %d\n", e_machine); return nullptr; } @@ -203,12 +199,17 @@ ElfInterface* Elf::CreateInterfaceFromMemory(Memory* memory) { if (!memory->ReadFully(EI_NIDENT + sizeof(Elf64_Half), &e_machine, sizeof(e_machine))) { return nullptr; } - if (e_machine != EM_AARCH64 && e_machine != EM_X86_64) { + + machine_type_ = e_machine; + if (e_machine == EM_AARCH64) { + arch_ = ARCH_ARM64; + } else if (e_machine == EM_X86_64) { + arch_ = ARCH_X86_64; + } else { // Unsupported. ALOGI("64 bit elf that is neither aarch64 nor x86_64: e_machine = %d\n", e_machine); return nullptr; } - machine_type_ = e_machine; interface.reset(new ElfInterface64(memory)); } diff --git a/libunwindstack/ElfInterfaceArm.cpp b/libunwindstack/ElfInterfaceArm.cpp index 170a5cdf7..9841e2474 100644 --- a/libunwindstack/ElfInterfaceArm.cpp +++ b/libunwindstack/ElfInterfaceArm.cpp @@ -18,11 +18,11 @@ #include #include -#include +#include #include "ArmExidx.h" #include "ElfInterfaceArm.h" -#include "Machine.h" +#include "MachineArm.h" namespace unwindstack { diff --git a/libunwindstack/Machine.h b/libunwindstack/Machine.h deleted file mode 100644 index 1fb930905..000000000 --- a/libunwindstack/Machine.h +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (C) 2016 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 _LIBUNWINDSTACK_MACHINE_H -#define _LIBUNWINDSTACK_MACHINE_H - -#include - -namespace unwindstack { - -enum ArmReg : uint16_t { - ARM_REG_R0 = 0, - ARM_REG_R1, - ARM_REG_R2, - ARM_REG_R3, - ARM_REG_R4, - ARM_REG_R5, - ARM_REG_R6, - ARM_REG_R7, - ARM_REG_R8, - ARM_REG_R9, - ARM_REG_R10, - ARM_REG_R11, - ARM_REG_R12, - ARM_REG_R13, - ARM_REG_R14, - ARM_REG_R15, - ARM_REG_LAST, - - ARM_REG_SP = ARM_REG_R13, - ARM_REG_LR = ARM_REG_R14, - ARM_REG_PC = ARM_REG_R15, -}; - -enum Arm64Reg : uint16_t { - ARM64_REG_R0 = 0, - ARM64_REG_R1, - ARM64_REG_R2, - ARM64_REG_R3, - ARM64_REG_R4, - ARM64_REG_R5, - ARM64_REG_R6, - ARM64_REG_R7, - ARM64_REG_R8, - ARM64_REG_R9, - ARM64_REG_R10, - ARM64_REG_R11, - ARM64_REG_R12, - ARM64_REG_R13, - ARM64_REG_R14, - ARM64_REG_R15, - ARM64_REG_R16, - ARM64_REG_R17, - ARM64_REG_R18, - ARM64_REG_R19, - ARM64_REG_R20, - ARM64_REG_R21, - ARM64_REG_R22, - ARM64_REG_R23, - ARM64_REG_R24, - ARM64_REG_R25, - ARM64_REG_R26, - ARM64_REG_R27, - ARM64_REG_R28, - ARM64_REG_R29, - ARM64_REG_R30, - ARM64_REG_R31, - ARM64_REG_PC, - ARM64_REG_LAST, - - ARM64_REG_SP = ARM64_REG_R31, - ARM64_REG_LR = ARM64_REG_R30, -}; - -// Matches the numbers for the registers as generated by compilers. -// If this is changed, then unwinding will fail. -enum X86Reg : uint16_t { - X86_REG_EAX = 0, - X86_REG_ECX = 1, - X86_REG_EDX = 2, - X86_REG_EBX = 3, - X86_REG_ESP = 4, - X86_REG_EBP = 5, - X86_REG_ESI = 6, - X86_REG_EDI = 7, - X86_REG_EIP = 8, - X86_REG_EFL = 9, - X86_REG_CS = 10, - X86_REG_SS = 11, - X86_REG_DS = 12, - X86_REG_ES = 13, - X86_REG_FS = 14, - X86_REG_GS = 15, - X86_REG_LAST, - - X86_REG_SP = X86_REG_ESP, - X86_REG_PC = X86_REG_EIP, -}; - -// Matches the numbers for the registers as generated by compilers. -// If this is changed, then unwinding will fail. -enum X86_64Reg : uint16_t { - X86_64_REG_RAX = 0, - X86_64_REG_RDX = 1, - X86_64_REG_RCX = 2, - X86_64_REG_RBX = 3, - X86_64_REG_RSI = 4, - X86_64_REG_RDI = 5, - X86_64_REG_RBP = 6, - X86_64_REG_RSP = 7, - X86_64_REG_R8 = 8, - X86_64_REG_R9 = 9, - X86_64_REG_R10 = 10, - X86_64_REG_R11 = 11, - X86_64_REG_R12 = 12, - X86_64_REG_R13 = 13, - X86_64_REG_R14 = 14, - X86_64_REG_R15 = 15, - X86_64_REG_RIP = 16, - X86_64_REG_LAST, - - X86_64_REG_SP = X86_64_REG_RSP, - X86_64_REG_PC = X86_64_REG_RIP, -}; - -} // namespace unwindstack - -#endif // _LIBUNWINDSTACK_MACHINE_H diff --git a/libunwindstack/MachineArm.h b/libunwindstack/MachineArm.h new file mode 100644 index 000000000..3f902b194 --- /dev/null +++ b/libunwindstack/MachineArm.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2017 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 _LIBUNWINDSTACK_MACHINE_ARM_H +#define _LIBUNWINDSTACK_MACHINE_ARM_H + +#include + +namespace unwindstack { + +enum ArmReg : uint16_t { + ARM_REG_R0 = 0, + ARM_REG_R1, + ARM_REG_R2, + ARM_REG_R3, + ARM_REG_R4, + ARM_REG_R5, + ARM_REG_R6, + ARM_REG_R7, + ARM_REG_R8, + ARM_REG_R9, + ARM_REG_R10, + ARM_REG_R11, + ARM_REG_R12, + ARM_REG_R13, + ARM_REG_R14, + ARM_REG_R15, + ARM_REG_LAST, + + ARM_REG_SP = ARM_REG_R13, + ARM_REG_LR = ARM_REG_R14, + ARM_REG_PC = ARM_REG_R15, +}; + +} // namespace unwindstack + +#endif // _LIBUNWINDSTACK_MACHINE_ARM_H diff --git a/libunwindstack/MachineArm64.h b/libunwindstack/MachineArm64.h new file mode 100644 index 000000000..e8b778b13 --- /dev/null +++ b/libunwindstack/MachineArm64.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2017 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 _LIBUNWINDSTACK_MACHINE_ARM64_H +#define _LIBUNWINDSTACK_MACHINE_ARM64_H + +#include + +namespace unwindstack { + +enum Arm64Reg : uint16_t { + ARM64_REG_R0 = 0, + ARM64_REG_R1, + ARM64_REG_R2, + ARM64_REG_R3, + ARM64_REG_R4, + ARM64_REG_R5, + ARM64_REG_R6, + ARM64_REG_R7, + ARM64_REG_R8, + ARM64_REG_R9, + ARM64_REG_R10, + ARM64_REG_R11, + ARM64_REG_R12, + ARM64_REG_R13, + ARM64_REG_R14, + ARM64_REG_R15, + ARM64_REG_R16, + ARM64_REG_R17, + ARM64_REG_R18, + ARM64_REG_R19, + ARM64_REG_R20, + ARM64_REG_R21, + ARM64_REG_R22, + ARM64_REG_R23, + ARM64_REG_R24, + ARM64_REG_R25, + ARM64_REG_R26, + ARM64_REG_R27, + ARM64_REG_R28, + ARM64_REG_R29, + ARM64_REG_R30, + ARM64_REG_R31, + ARM64_REG_PC, + ARM64_REG_LAST, + + ARM64_REG_SP = ARM64_REG_R31, + ARM64_REG_LR = ARM64_REG_R30, +}; + +} // namespace unwindstack + +#endif // _LIBUNWINDSTACK_MACHINE_ARM64_H diff --git a/libunwindstack/MachineX86.h b/libunwindstack/MachineX86.h new file mode 100644 index 000000000..02adb98c3 --- /dev/null +++ b/libunwindstack/MachineX86.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2017 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 _LIBUNWINDSTACK_MACHINE_X86_H +#define _LIBUNWINDSTACK_MACHINE_X86_H + +#include + +namespace unwindstack { + +// Matches the numbers for the registers as generated by compilers. +// If this is changed, then unwinding will fail. +enum X86Reg : uint16_t { + X86_REG_EAX = 0, + X86_REG_ECX = 1, + X86_REG_EDX = 2, + X86_REG_EBX = 3, + X86_REG_ESP = 4, + X86_REG_EBP = 5, + X86_REG_ESI = 6, + X86_REG_EDI = 7, + X86_REG_EIP = 8, + X86_REG_EFL = 9, + X86_REG_CS = 10, + X86_REG_SS = 11, + X86_REG_DS = 12, + X86_REG_ES = 13, + X86_REG_FS = 14, + X86_REG_GS = 15, + X86_REG_LAST, + + X86_REG_SP = X86_REG_ESP, + X86_REG_PC = X86_REG_EIP, +}; + +} // namespace unwindstack + +#endif // _LIBUNWINDSTACK_MACHINE_X86_H diff --git a/libunwindstack/MachineX86_64.h b/libunwindstack/MachineX86_64.h new file mode 100644 index 000000000..af33fea80 --- /dev/null +++ b/libunwindstack/MachineX86_64.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2017 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 _LIBUNWINDSTACK_MACHINE_X86_64_H +#define _LIBUNWINDSTACK_MACHINE_X86_64_H + +#include + +namespace unwindstack { + +// Matches the numbers for the registers as generated by compilers. +// If this is changed, then unwinding will fail. +enum X86_64Reg : uint16_t { + X86_64_REG_RAX = 0, + X86_64_REG_RDX = 1, + X86_64_REG_RCX = 2, + X86_64_REG_RBX = 3, + X86_64_REG_RSI = 4, + X86_64_REG_RDI = 5, + X86_64_REG_RBP = 6, + X86_64_REG_RSP = 7, + X86_64_REG_R8 = 8, + X86_64_REG_R9 = 9, + X86_64_REG_R10 = 10, + X86_64_REG_R11 = 11, + X86_64_REG_R12 = 12, + X86_64_REG_R13 = 13, + X86_64_REG_R14 = 14, + X86_64_REG_R15 = 15, + X86_64_REG_RIP = 16, + X86_64_REG_LAST, + + X86_64_REG_SP = X86_64_REG_RSP, + X86_64_REG_PC = X86_64_REG_RIP, +}; + +} // namespace unwindstack + +#endif // _LIBUNWINDSTACK_MACHINE_X86_64_H diff --git a/libunwindstack/Regs.cpp b/libunwindstack/Regs.cpp index 28a77dc16..29dbf9d15 100644 --- a/libunwindstack/Regs.cpp +++ b/libunwindstack/Regs.cpp @@ -14,7 +14,6 @@ * limitations under the License. */ -#include #include #include #include @@ -23,315 +22,21 @@ #include #include -#include #include +#include +#include +#include +#include -#include "Check.h" -#include "Machine.h" -#include "Ucontext.h" -#include "User.h" +#include "UserArm.h" +#include "UserArm64.h" +#include "UserX86.h" +#include "UserX86_64.h" namespace unwindstack { -RegsArm::RegsArm() - : RegsImpl(ARM_REG_LAST, ARM_REG_SP, Location(LOCATION_REGISTER, ARM_REG_LR)) {} - -uint32_t RegsArm::MachineType() { - return EM_ARM; -} - -uint64_t RegsArm::GetAdjustedPc(uint64_t rel_pc, Elf* elf) { - if (!elf->valid()) { - return rel_pc; - } - - uint64_t load_bias = elf->GetLoadBias(); - if (rel_pc < load_bias) { - return rel_pc; - } - uint64_t adjusted_rel_pc = rel_pc - load_bias; - - if (adjusted_rel_pc < 5) { - return rel_pc; - } - - if (adjusted_rel_pc & 1) { - // This is a thumb instruction, it could be 2 or 4 bytes. - uint32_t value; - if (rel_pc < 5 || !elf->memory()->ReadFully(adjusted_rel_pc - 5, &value, sizeof(value)) || - (value & 0xe000f000) != 0xe000f000) { - return rel_pc - 2; - } - } - return rel_pc - 4; -} - -void RegsArm::SetFromRaw() { - set_pc(regs_[ARM_REG_PC]); - set_sp(regs_[ARM_REG_SP]); -} - -bool RegsArm::SetPcFromReturnAddress(Memory*) { - if (pc() == regs_[ARM_REG_LR]) { - return false; - } - - set_pc(regs_[ARM_REG_LR]); - return true; -} - -void RegsArm::IterateRegisters(std::function fn) { - fn("r0", regs_[ARM_REG_R0]); - fn("r1", regs_[ARM_REG_R1]); - fn("r2", regs_[ARM_REG_R2]); - fn("r3", regs_[ARM_REG_R3]); - fn("r4", regs_[ARM_REG_R4]); - fn("r5", regs_[ARM_REG_R5]); - fn("r6", regs_[ARM_REG_R6]); - fn("r7", regs_[ARM_REG_R7]); - fn("r8", regs_[ARM_REG_R8]); - fn("r9", regs_[ARM_REG_R9]); - fn("r10", regs_[ARM_REG_R10]); - fn("r11", regs_[ARM_REG_R11]); - fn("ip", regs_[ARM_REG_R12]); - fn("sp", regs_[ARM_REG_SP]); - fn("lr", regs_[ARM_REG_LR]); - fn("pc", regs_[ARM_REG_PC]); -} - -RegsArm64::RegsArm64() - : RegsImpl(ARM64_REG_LAST, ARM64_REG_SP, Location(LOCATION_REGISTER, ARM64_REG_LR)) {} - -uint32_t RegsArm64::MachineType() { - return EM_AARCH64; -} - -uint64_t RegsArm64::GetAdjustedPc(uint64_t rel_pc, Elf* elf) { - if (!elf->valid()) { - return rel_pc; - } - - if (rel_pc < 4) { - return rel_pc; - } - return rel_pc - 4; -} - -void RegsArm64::SetFromRaw() { - set_pc(regs_[ARM64_REG_PC]); - set_sp(regs_[ARM64_REG_SP]); -} - -bool RegsArm64::SetPcFromReturnAddress(Memory*) { - if (pc() == regs_[ARM64_REG_LR]) { - return false; - } - - set_pc(regs_[ARM64_REG_LR]); - return true; -} - -void RegsArm64::IterateRegisters(std::function fn) { - fn("x0", regs_[ARM64_REG_R0]); - fn("x1", regs_[ARM64_REG_R1]); - fn("x2", regs_[ARM64_REG_R2]); - fn("x3", regs_[ARM64_REG_R3]); - fn("x4", regs_[ARM64_REG_R4]); - fn("x5", regs_[ARM64_REG_R5]); - fn("x6", regs_[ARM64_REG_R6]); - fn("x7", regs_[ARM64_REG_R7]); - fn("x8", regs_[ARM64_REG_R8]); - fn("x9", regs_[ARM64_REG_R9]); - fn("x10", regs_[ARM64_REG_R10]); - fn("x11", regs_[ARM64_REG_R11]); - fn("x12", regs_[ARM64_REG_R12]); - fn("x13", regs_[ARM64_REG_R13]); - fn("x14", regs_[ARM64_REG_R14]); - fn("x15", regs_[ARM64_REG_R15]); - fn("x16", regs_[ARM64_REG_R16]); - fn("x17", regs_[ARM64_REG_R17]); - fn("x18", regs_[ARM64_REG_R18]); - fn("x19", regs_[ARM64_REG_R19]); - fn("x20", regs_[ARM64_REG_R20]); - fn("x21", regs_[ARM64_REG_R21]); - fn("x22", regs_[ARM64_REG_R22]); - fn("x23", regs_[ARM64_REG_R23]); - fn("x24", regs_[ARM64_REG_R24]); - fn("x25", regs_[ARM64_REG_R25]); - fn("x26", regs_[ARM64_REG_R26]); - fn("x27", regs_[ARM64_REG_R27]); - fn("x28", regs_[ARM64_REG_R28]); - fn("x29", regs_[ARM64_REG_R29]); - fn("sp", regs_[ARM64_REG_SP]); - fn("lr", regs_[ARM64_REG_LR]); - fn("pc", regs_[ARM64_REG_PC]); -} - -RegsX86::RegsX86() - : RegsImpl(X86_REG_LAST, X86_REG_SP, Location(LOCATION_SP_OFFSET, -4)) {} - -uint32_t RegsX86::MachineType() { - return EM_386; -} - -uint64_t RegsX86::GetAdjustedPc(uint64_t rel_pc, Elf* elf) { - if (!elf->valid()) { - return rel_pc; - } - - if (rel_pc == 0) { - return 0; - } - return rel_pc - 1; -} - -void RegsX86::SetFromRaw() { - set_pc(regs_[X86_REG_PC]); - set_sp(regs_[X86_REG_SP]); -} - -bool RegsX86::SetPcFromReturnAddress(Memory* process_memory) { - // Attempt to get the return address from the top of the stack. - uint32_t new_pc; - if (!process_memory->ReadFully(sp_, &new_pc, sizeof(new_pc)) || new_pc == pc()) { - return false; - } - - set_pc(new_pc); - return true; -} - -void RegsX86::IterateRegisters(std::function fn) { - fn("eax", regs_[X86_REG_EAX]); - fn("ebx", regs_[X86_REG_EBX]); - fn("ecx", regs_[X86_REG_ECX]); - fn("edx", regs_[X86_REG_EDX]); - fn("ebp", regs_[X86_REG_EBP]); - fn("edi", regs_[X86_REG_EDI]); - fn("esi", regs_[X86_REG_ESI]); - fn("esp", regs_[X86_REG_ESP]); - fn("eip", regs_[X86_REG_EIP]); -} - -RegsX86_64::RegsX86_64() - : RegsImpl(X86_64_REG_LAST, X86_64_REG_SP, Location(LOCATION_SP_OFFSET, -8)) {} - -uint32_t RegsX86_64::MachineType() { - return EM_X86_64; -} - -uint64_t RegsX86_64::GetAdjustedPc(uint64_t rel_pc, Elf* elf) { - if (!elf->valid()) { - return rel_pc; - } - - if (rel_pc == 0) { - return 0; - } - - return rel_pc - 1; -} - -void RegsX86_64::SetFromRaw() { - set_pc(regs_[X86_64_REG_PC]); - set_sp(regs_[X86_64_REG_SP]); -} - -bool RegsX86_64::SetPcFromReturnAddress(Memory* process_memory) { - // Attempt to get the return address from the top of the stack. - uint64_t new_pc; - if (!process_memory->ReadFully(sp_, &new_pc, sizeof(new_pc)) || new_pc == pc()) { - return false; - } - - set_pc(new_pc); - return true; -} - -void RegsX86_64::IterateRegisters(std::function fn) { - fn("rax", regs_[X86_64_REG_RAX]); - fn("rbx", regs_[X86_64_REG_RBX]); - fn("rcx", regs_[X86_64_REG_RCX]); - fn("rdx", regs_[X86_64_REG_RDX]); - fn("r8", regs_[X86_64_REG_R8]); - fn("r9", regs_[X86_64_REG_R9]); - fn("r10", regs_[X86_64_REG_R10]); - fn("r11", regs_[X86_64_REG_R11]); - fn("r12", regs_[X86_64_REG_R12]); - fn("r13", regs_[X86_64_REG_R13]); - fn("r14", regs_[X86_64_REG_R14]); - fn("r15", regs_[X86_64_REG_R15]); - fn("rdi", regs_[X86_64_REG_RDI]); - fn("rsi", regs_[X86_64_REG_RSI]); - fn("rbp", regs_[X86_64_REG_RBP]); - fn("rsp", regs_[X86_64_REG_RSP]); - fn("rip", regs_[X86_64_REG_RIP]); -} - -static Regs* ReadArm(void* remote_data) { - arm_user_regs* user = reinterpret_cast(remote_data); - - RegsArm* regs = new RegsArm(); - memcpy(regs->RawData(), &user->regs[0], ARM_REG_LAST * sizeof(uint32_t)); - regs->SetFromRaw(); - return regs; -} - -static Regs* ReadArm64(void* remote_data) { - arm64_user_regs* user = reinterpret_cast(remote_data); - - RegsArm64* regs = new RegsArm64(); - memcpy(regs->RawData(), &user->regs[0], (ARM64_REG_R31 + 1) * sizeof(uint64_t)); - uint64_t* reg_data = reinterpret_cast(regs->RawData()); - reg_data[ARM64_REG_PC] = user->pc; - reg_data[ARM64_REG_SP] = user->sp; - regs->SetFromRaw(); - return regs; -} - -static Regs* ReadX86(void* remote_data) { - x86_user_regs* user = reinterpret_cast(remote_data); - - RegsX86* regs = new RegsX86(); - (*regs)[X86_REG_EAX] = user->eax; - (*regs)[X86_REG_EBX] = user->ebx; - (*regs)[X86_REG_ECX] = user->ecx; - (*regs)[X86_REG_EDX] = user->edx; - (*regs)[X86_REG_EBP] = user->ebp; - (*regs)[X86_REG_EDI] = user->edi; - (*regs)[X86_REG_ESI] = user->esi; - (*regs)[X86_REG_ESP] = user->esp; - (*regs)[X86_REG_EIP] = user->eip; - - regs->SetFromRaw(); - return regs; -} - -static Regs* ReadX86_64(void* remote_data) { - x86_64_user_regs* user = reinterpret_cast(remote_data); - - RegsX86_64* regs = new RegsX86_64(); - (*regs)[X86_64_REG_RAX] = user->rax; - (*regs)[X86_64_REG_RBX] = user->rbx; - (*regs)[X86_64_REG_RCX] = user->rcx; - (*regs)[X86_64_REG_RDX] = user->rdx; - (*regs)[X86_64_REG_R8] = user->r8; - (*regs)[X86_64_REG_R9] = user->r9; - (*regs)[X86_64_REG_R10] = user->r10; - (*regs)[X86_64_REG_R11] = user->r11; - (*regs)[X86_64_REG_R12] = user->r12; - (*regs)[X86_64_REG_R13] = user->r13; - (*regs)[X86_64_REG_R14] = user->r14; - (*regs)[X86_64_REG_R15] = user->r15; - (*regs)[X86_64_REG_RDI] = user->rdi; - (*regs)[X86_64_REG_RSI] = user->rsi; - (*regs)[X86_64_REG_RBP] = user->rbp; - (*regs)[X86_64_REG_RSP] = user->rsp; - (*regs)[X86_64_REG_RIP] = user->rip; - - regs->SetFromRaw(); - return regs; -} +// The largest user structure. +constexpr size_t MAX_USER_REGS_SIZE = sizeof(arm64_user_regs) + 10; // This function assumes that reg_data is already aligned to a 64 bit value. // If not this could crash with an unaligned access. @@ -348,106 +53,42 @@ Regs* Regs::RemoteGet(pid_t pid) { switch (io.iov_len) { case sizeof(x86_user_regs): - return ReadX86(buffer.data()); + return RegsX86::Read(buffer.data()); case sizeof(x86_64_user_regs): - return ReadX86_64(buffer.data()); + return RegsX86_64::Read(buffer.data()); case sizeof(arm_user_regs): - return ReadArm(buffer.data()); + return RegsArm::Read(buffer.data()); case sizeof(arm64_user_regs): - return ReadArm64(buffer.data()); + return RegsArm64::Read(buffer.data()); } return nullptr; } -static Regs* CreateFromArmUcontext(void* ucontext) { - arm_ucontext_t* arm_ucontext = reinterpret_cast(ucontext); - - RegsArm* regs = new RegsArm(); - memcpy(regs->RawData(), &arm_ucontext->uc_mcontext.regs[0], ARM_REG_LAST * sizeof(uint32_t)); - regs->SetFromRaw(); - return regs; -} - -static Regs* CreateFromArm64Ucontext(void* ucontext) { - arm64_ucontext_t* arm64_ucontext = reinterpret_cast(ucontext); - - RegsArm64* regs = new RegsArm64(); - memcpy(regs->RawData(), &arm64_ucontext->uc_mcontext.regs[0], ARM64_REG_LAST * sizeof(uint64_t)); - regs->SetFromRaw(); - 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(ucontext); - - RegsX86* regs = new RegsX86(); - regs->SetFromUcontext(x86_ucontext); - return regs; -} - -void RegsX86_64::SetFromUcontext(x86_64_ucontext_t* ucontext) { - // R8-R15 - memcpy(®s_[X86_64_REG_R8], &ucontext->uc_mcontext.r8, 8 * sizeof(uint64_t)); - - // Rest of the registers. - 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(); -} - -static Regs* CreateFromX86_64Ucontext(void* ucontext) { - x86_64_ucontext_t* x86_64_ucontext = reinterpret_cast(ucontext); - - RegsX86_64* regs = new RegsX86_64(); - regs->SetFromUcontext(x86_64_ucontext); - return regs; -} - -Regs* Regs::CreateFromUcontext(uint32_t machine_type, void* ucontext) { - switch (machine_type) { - case EM_386: - return CreateFromX86Ucontext(ucontext); - case EM_X86_64: - return CreateFromX86_64Ucontext(ucontext); - case EM_ARM: - return CreateFromArmUcontext(ucontext); - case EM_AARCH64: - return CreateFromArm64Ucontext(ucontext); +Regs* Regs::CreateFromUcontext(ArchEnum arch, void* ucontext) { + switch (arch) { + case ARCH_X86: + return RegsX86::CreateFromUcontext(ucontext); + case ARCH_X86_64: + return RegsX86_64::CreateFromUcontext(ucontext); + case ARCH_ARM: + return RegsArm::CreateFromUcontext(ucontext); + case ARCH_ARM64: + return RegsArm64::CreateFromUcontext(ucontext); + case ARCH_UNKNOWN: + default: + return nullptr; } - return nullptr; } -uint32_t Regs::CurrentMachineType() { +ArchEnum Regs::CurrentArch() { #if defined(__arm__) - return EM_ARM; + return ARCH_ARM; #elif defined(__aarch64__) - return EM_AARCH64; + return ARCH_ARM64; #elif defined(__i386__) - return EM_386; + return ARCH_X86; #elif defined(__x86_64__) - return EM_X86_64; + return ARCH_X86_64; #else abort(); #endif @@ -469,192 +110,4 @@ Regs* Regs::CreateFromLocal() { return regs; } -bool RegsArm::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) { - uint32_t data; - Memory* elf_memory = elf->memory(); - // Read from elf memory since it is usually more expensive to read from - // process memory. - if (!elf_memory->ReadFully(rel_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 (!process_memory->ReadFully(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 (!process_memory->ReadFully(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 (!process_memory->ReadFully(offset, regs_.data(), sizeof(uint32_t) * ARM_REG_LAST)) { - return false; - } - SetFromRaw(); - return true; -} - -bool RegsArm64::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) { - uint64_t data; - Memory* elf_memory = elf->memory(); - // Read from elf memory since it is usually more expensive to read from - // process memory. - if (!elf_memory->ReadFully(rel_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 (!process_memory->ReadFully(sp() + 0x80 + 0xb0 + 0x08, regs_.data(), - sizeof(uint64_t) * ARM64_REG_LAST)) { - return false; - } - - SetFromRaw(); - return true; -} - -bool RegsX86::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) { - uint64_t data; - Memory* elf_memory = elf->memory(); - // Read from elf memory since it is usually more expensive to read from - // process memory. - if (!elf_memory->ReadFully(rel_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 (!process_memory->ReadFully(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 (!process_memory->ReadFully(sp() + 8, &ptr, sizeof(ptr))) { - return false; - } - // Only read the portion of the data structure we care about. - x86_ucontext_t x86_ucontext; - if (!process_memory->ReadFully(ptr + 0x14, &x86_ucontext.uc_mcontext, sizeof(x86_mcontext_t))) { - return false; - } - SetFromUcontext(&x86_ucontext); - return true; - } - return false; -} - -bool RegsX86_64::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) { - uint64_t data; - Memory* elf_memory = elf->memory(); - // Read from elf memory since it is usually more expensive to read from - // process memory. - if (!elf_memory->ReadFully(rel_pc, &data, sizeof(data)) || data != 0x0f0000000fc0c748) { - return false; - } - - uint16_t data2; - if (!elf_memory->ReadFully(rel_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 (!process_memory->ReadFully(sp() + 0x28, &x86_64_ucontext.uc_mcontext, - sizeof(x86_64_mcontext_t))) { - return false; - } - SetFromUcontext(&x86_64_ucontext); - return true; -} - } // namespace unwindstack diff --git a/libunwindstack/RegsArm.cpp b/libunwindstack/RegsArm.cpp new file mode 100644 index 000000000..34f29bd95 --- /dev/null +++ b/libunwindstack/RegsArm.cpp @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2016 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 + +#include + +#include +#include +#include +#include + +#include "MachineArm.h" +#include "UcontextArm.h" +#include "UserArm.h" + +namespace unwindstack { + +RegsArm::RegsArm() + : RegsImpl(ARM_REG_LAST, ARM_REG_SP, Location(LOCATION_REGISTER, ARM_REG_LR)) {} + +ArchEnum RegsArm::Arch() { + return ARCH_ARM; +} + +uint64_t RegsArm::GetAdjustedPc(uint64_t rel_pc, Elf* elf) { + if (!elf->valid()) { + return rel_pc; + } + + uint64_t load_bias = elf->GetLoadBias(); + if (rel_pc < load_bias) { + return rel_pc; + } + uint64_t adjusted_rel_pc = rel_pc - load_bias; + + if (adjusted_rel_pc < 5) { + return rel_pc; + } + + if (adjusted_rel_pc & 1) { + // This is a thumb instruction, it could be 2 or 4 bytes. + uint32_t value; + if (rel_pc < 5 || !elf->memory()->ReadFully(adjusted_rel_pc - 5, &value, sizeof(value)) || + (value & 0xe000f000) != 0xe000f000) { + return rel_pc - 2; + } + } + return rel_pc - 4; +} + +void RegsArm::SetFromRaw() { + set_pc(regs_[ARM_REG_PC]); + set_sp(regs_[ARM_REG_SP]); +} + +bool RegsArm::SetPcFromReturnAddress(Memory*) { + if (pc() == regs_[ARM_REG_LR]) { + return false; + } + + set_pc(regs_[ARM_REG_LR]); + return true; +} + +void RegsArm::IterateRegisters(std::function fn) { + fn("r0", regs_[ARM_REG_R0]); + fn("r1", regs_[ARM_REG_R1]); + fn("r2", regs_[ARM_REG_R2]); + fn("r3", regs_[ARM_REG_R3]); + fn("r4", regs_[ARM_REG_R4]); + fn("r5", regs_[ARM_REG_R5]); + fn("r6", regs_[ARM_REG_R6]); + fn("r7", regs_[ARM_REG_R7]); + fn("r8", regs_[ARM_REG_R8]); + fn("r9", regs_[ARM_REG_R9]); + fn("r10", regs_[ARM_REG_R10]); + fn("r11", regs_[ARM_REG_R11]); + fn("ip", regs_[ARM_REG_R12]); + fn("sp", regs_[ARM_REG_SP]); + fn("lr", regs_[ARM_REG_LR]); + fn("pc", regs_[ARM_REG_PC]); +} + +Regs* RegsArm::Read(void* remote_data) { + arm_user_regs* user = reinterpret_cast(remote_data); + + RegsArm* regs = new RegsArm(); + memcpy(regs->RawData(), &user->regs[0], ARM_REG_LAST * sizeof(uint32_t)); + regs->SetFromRaw(); + return regs; +} + +Regs* RegsArm::CreateFromUcontext(void* ucontext) { + arm_ucontext_t* arm_ucontext = reinterpret_cast(ucontext); + + RegsArm* regs = new RegsArm(); + memcpy(regs->RawData(), &arm_ucontext->uc_mcontext.regs[0], ARM_REG_LAST * sizeof(uint32_t)); + regs->SetFromRaw(); + return regs; +} + +bool RegsArm::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) { + uint32_t data; + Memory* elf_memory = elf->memory(); + // Read from elf memory since it is usually more expensive to read from + // process memory. + if (!elf_memory->ReadFully(rel_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 (!process_memory->ReadFully(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 (!process_memory->ReadFully(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 (!process_memory->ReadFully(offset, regs_.data(), sizeof(uint32_t) * ARM_REG_LAST)) { + return false; + } + SetFromRaw(); + return true; +} + +} // namespace unwindstack diff --git a/libunwindstack/RegsArm64.cpp b/libunwindstack/RegsArm64.cpp new file mode 100644 index 000000000..2077bc5ff --- /dev/null +++ b/libunwindstack/RegsArm64.cpp @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2016 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 + +#include + +#include +#include +#include +#include + +#include "MachineArm64.h" +#include "UcontextArm64.h" +#include "UserArm64.h" + +namespace unwindstack { + +RegsArm64::RegsArm64() + : RegsImpl(ARM64_REG_LAST, ARM64_REG_SP, Location(LOCATION_REGISTER, ARM64_REG_LR)) {} + +ArchEnum RegsArm64::Arch() { + return ARCH_ARM64; +} + +uint64_t RegsArm64::GetAdjustedPc(uint64_t rel_pc, Elf* elf) { + if (!elf->valid()) { + return rel_pc; + } + + if (rel_pc < 4) { + return rel_pc; + } + return rel_pc - 4; +} + +void RegsArm64::SetFromRaw() { + set_pc(regs_[ARM64_REG_PC]); + set_sp(regs_[ARM64_REG_SP]); +} + +bool RegsArm64::SetPcFromReturnAddress(Memory*) { + if (pc() == regs_[ARM64_REG_LR]) { + return false; + } + + set_pc(regs_[ARM64_REG_LR]); + return true; +} + +void RegsArm64::IterateRegisters(std::function fn) { + fn("x0", regs_[ARM64_REG_R0]); + fn("x1", regs_[ARM64_REG_R1]); + fn("x2", regs_[ARM64_REG_R2]); + fn("x3", regs_[ARM64_REG_R3]); + fn("x4", regs_[ARM64_REG_R4]); + fn("x5", regs_[ARM64_REG_R5]); + fn("x6", regs_[ARM64_REG_R6]); + fn("x7", regs_[ARM64_REG_R7]); + fn("x8", regs_[ARM64_REG_R8]); + fn("x9", regs_[ARM64_REG_R9]); + fn("x10", regs_[ARM64_REG_R10]); + fn("x11", regs_[ARM64_REG_R11]); + fn("x12", regs_[ARM64_REG_R12]); + fn("x13", regs_[ARM64_REG_R13]); + fn("x14", regs_[ARM64_REG_R14]); + fn("x15", regs_[ARM64_REG_R15]); + fn("x16", regs_[ARM64_REG_R16]); + fn("x17", regs_[ARM64_REG_R17]); + fn("x18", regs_[ARM64_REG_R18]); + fn("x19", regs_[ARM64_REG_R19]); + fn("x20", regs_[ARM64_REG_R20]); + fn("x21", regs_[ARM64_REG_R21]); + fn("x22", regs_[ARM64_REG_R22]); + fn("x23", regs_[ARM64_REG_R23]); + fn("x24", regs_[ARM64_REG_R24]); + fn("x25", regs_[ARM64_REG_R25]); + fn("x26", regs_[ARM64_REG_R26]); + fn("x27", regs_[ARM64_REG_R27]); + fn("x28", regs_[ARM64_REG_R28]); + fn("x29", regs_[ARM64_REG_R29]); + fn("sp", regs_[ARM64_REG_SP]); + fn("lr", regs_[ARM64_REG_LR]); + fn("pc", regs_[ARM64_REG_PC]); +} + +Regs* RegsArm64::Read(void* remote_data) { + arm64_user_regs* user = reinterpret_cast(remote_data); + + RegsArm64* regs = new RegsArm64(); + memcpy(regs->RawData(), &user->regs[0], (ARM64_REG_R31 + 1) * sizeof(uint64_t)); + uint64_t* reg_data = reinterpret_cast(regs->RawData()); + reg_data[ARM64_REG_PC] = user->pc; + reg_data[ARM64_REG_SP] = user->sp; + regs->SetFromRaw(); + return regs; +} + +Regs* RegsArm64::CreateFromUcontext(void* ucontext) { + arm64_ucontext_t* arm64_ucontext = reinterpret_cast(ucontext); + + RegsArm64* regs = new RegsArm64(); + memcpy(regs->RawData(), &arm64_ucontext->uc_mcontext.regs[0], ARM64_REG_LAST * sizeof(uint64_t)); + regs->SetFromRaw(); + return regs; +} + +bool RegsArm64::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) { + uint64_t data; + Memory* elf_memory = elf->memory(); + // Read from elf memory since it is usually more expensive to read from + // process memory. + if (!elf_memory->ReadFully(rel_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 (!process_memory->ReadFully(sp() + 0x80 + 0xb0 + 0x08, regs_.data(), + sizeof(uint64_t) * ARM64_REG_LAST)) { + return false; + } + + SetFromRaw(); + return true; +} + +} // namespace unwindstack diff --git a/libunwindstack/RegsX86.cpp b/libunwindstack/RegsX86.cpp new file mode 100644 index 000000000..ef2f3decc --- /dev/null +++ b/libunwindstack/RegsX86.cpp @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2016 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 + +#include + +#include +#include +#include +#include + +#include "MachineX86.h" +#include "UcontextX86.h" +#include "UserX86.h" + +namespace unwindstack { + +RegsX86::RegsX86() + : RegsImpl(X86_REG_LAST, X86_REG_SP, Location(LOCATION_SP_OFFSET, -4)) {} + +ArchEnum RegsX86::Arch() { + return ARCH_X86; +} + +uint64_t RegsX86::GetAdjustedPc(uint64_t rel_pc, Elf* elf) { + if (!elf->valid()) { + return rel_pc; + } + + if (rel_pc == 0) { + return 0; + } + return rel_pc - 1; +} + +void RegsX86::SetFromRaw() { + set_pc(regs_[X86_REG_PC]); + set_sp(regs_[X86_REG_SP]); +} + +bool RegsX86::SetPcFromReturnAddress(Memory* process_memory) { + // Attempt to get the return address from the top of the stack. + uint32_t new_pc; + if (!process_memory->ReadFully(sp_, &new_pc, sizeof(new_pc)) || new_pc == pc()) { + return false; + } + + set_pc(new_pc); + return true; +} + +void RegsX86::IterateRegisters(std::function fn) { + fn("eax", regs_[X86_REG_EAX]); + fn("ebx", regs_[X86_REG_EBX]); + fn("ecx", regs_[X86_REG_ECX]); + fn("edx", regs_[X86_REG_EDX]); + fn("ebp", regs_[X86_REG_EBP]); + fn("edi", regs_[X86_REG_EDI]); + fn("esi", regs_[X86_REG_ESI]); + fn("esp", regs_[X86_REG_ESP]); + fn("eip", regs_[X86_REG_EIP]); +} + +Regs* RegsX86::Read(void* user_data) { + x86_user_regs* user = reinterpret_cast(user_data); + + RegsX86* regs = new RegsX86(); + (*regs)[X86_REG_EAX] = user->eax; + (*regs)[X86_REG_EBX] = user->ebx; + (*regs)[X86_REG_ECX] = user->ecx; + (*regs)[X86_REG_EDX] = user->edx; + (*regs)[X86_REG_EBP] = user->ebp; + (*regs)[X86_REG_EDI] = user->edi; + (*regs)[X86_REG_ESI] = user->esi; + (*regs)[X86_REG_ESP] = user->esp; + (*regs)[X86_REG_EIP] = user->eip; + + regs->SetFromRaw(); + 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(); +} + +Regs* RegsX86::CreateFromUcontext(void* ucontext) { + x86_ucontext_t* x86_ucontext = reinterpret_cast(ucontext); + + RegsX86* regs = new RegsX86(); + regs->SetFromUcontext(x86_ucontext); + return regs; +} + +bool RegsX86::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) { + uint64_t data; + Memory* elf_memory = elf->memory(); + // Read from elf memory since it is usually more expensive to read from + // process memory. + if (!elf_memory->ReadFully(rel_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 (!process_memory->ReadFully(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 (!process_memory->ReadFully(sp() + 8, &ptr, sizeof(ptr))) { + return false; + } + // Only read the portion of the data structure we care about. + x86_ucontext_t x86_ucontext; + if (!process_memory->ReadFully(ptr + 0x14, &x86_ucontext.uc_mcontext, sizeof(x86_mcontext_t))) { + return false; + } + SetFromUcontext(&x86_ucontext); + return true; + } + return false; +} + +} // namespace unwindstack diff --git a/libunwindstack/RegsX86_64.cpp b/libunwindstack/RegsX86_64.cpp new file mode 100644 index 000000000..70921f8b2 --- /dev/null +++ b/libunwindstack/RegsX86_64.cpp @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2016 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 + +#include + +#include +#include +#include +#include + +#include "MachineX86_64.h" +#include "UcontextX86_64.h" +#include "UserX86_64.h" + +namespace unwindstack { + +RegsX86_64::RegsX86_64() + : RegsImpl(X86_64_REG_LAST, X86_64_REG_SP, Location(LOCATION_SP_OFFSET, -8)) {} + +ArchEnum RegsX86_64::Arch() { + return ARCH_X86_64; +} + +uint64_t RegsX86_64::GetAdjustedPc(uint64_t rel_pc, Elf* elf) { + if (!elf->valid()) { + return rel_pc; + } + + if (rel_pc == 0) { + return 0; + } + + return rel_pc - 1; +} + +void RegsX86_64::SetFromRaw() { + set_pc(regs_[X86_64_REG_PC]); + set_sp(regs_[X86_64_REG_SP]); +} + +bool RegsX86_64::SetPcFromReturnAddress(Memory* process_memory) { + // Attempt to get the return address from the top of the stack. + uint64_t new_pc; + if (!process_memory->ReadFully(sp_, &new_pc, sizeof(new_pc)) || new_pc == pc()) { + return false; + } + + set_pc(new_pc); + return true; +} + +void RegsX86_64::IterateRegisters(std::function fn) { + fn("rax", regs_[X86_64_REG_RAX]); + fn("rbx", regs_[X86_64_REG_RBX]); + fn("rcx", regs_[X86_64_REG_RCX]); + fn("rdx", regs_[X86_64_REG_RDX]); + fn("r8", regs_[X86_64_REG_R8]); + fn("r9", regs_[X86_64_REG_R9]); + fn("r10", regs_[X86_64_REG_R10]); + fn("r11", regs_[X86_64_REG_R11]); + fn("r12", regs_[X86_64_REG_R12]); + fn("r13", regs_[X86_64_REG_R13]); + fn("r14", regs_[X86_64_REG_R14]); + fn("r15", regs_[X86_64_REG_R15]); + fn("rdi", regs_[X86_64_REG_RDI]); + fn("rsi", regs_[X86_64_REG_RSI]); + fn("rbp", regs_[X86_64_REG_RBP]); + fn("rsp", regs_[X86_64_REG_RSP]); + fn("rip", regs_[X86_64_REG_RIP]); +} + +Regs* RegsX86_64::Read(void* remote_data) { + x86_64_user_regs* user = reinterpret_cast(remote_data); + + RegsX86_64* regs = new RegsX86_64(); + (*regs)[X86_64_REG_RAX] = user->rax; + (*regs)[X86_64_REG_RBX] = user->rbx; + (*regs)[X86_64_REG_RCX] = user->rcx; + (*regs)[X86_64_REG_RDX] = user->rdx; + (*regs)[X86_64_REG_R8] = user->r8; + (*regs)[X86_64_REG_R9] = user->r9; + (*regs)[X86_64_REG_R10] = user->r10; + (*regs)[X86_64_REG_R11] = user->r11; + (*regs)[X86_64_REG_R12] = user->r12; + (*regs)[X86_64_REG_R13] = user->r13; + (*regs)[X86_64_REG_R14] = user->r14; + (*regs)[X86_64_REG_R15] = user->r15; + (*regs)[X86_64_REG_RDI] = user->rdi; + (*regs)[X86_64_REG_RSI] = user->rsi; + (*regs)[X86_64_REG_RBP] = user->rbp; + (*regs)[X86_64_REG_RSP] = user->rsp; + (*regs)[X86_64_REG_RIP] = user->rip; + + regs->SetFromRaw(); + return regs; +} + +void RegsX86_64::SetFromUcontext(x86_64_ucontext_t* ucontext) { + // R8-R15 + memcpy(®s_[X86_64_REG_R8], &ucontext->uc_mcontext.r8, 8 * sizeof(uint64_t)); + + // Rest of the registers. + 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* RegsX86_64::CreateFromUcontext(void* ucontext) { + x86_64_ucontext_t* x86_64_ucontext = reinterpret_cast(ucontext); + + RegsX86_64* regs = new RegsX86_64(); + regs->SetFromUcontext(x86_64_ucontext); + return regs; +} + +bool RegsX86_64::StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) { + uint64_t data; + Memory* elf_memory = elf->memory(); + // Read from elf memory since it is usually more expensive to read from + // process memory. + if (!elf_memory->ReadFully(rel_pc, &data, sizeof(data)) || data != 0x0f0000000fc0c748) { + return false; + } + + uint16_t data2; + if (!elf_memory->ReadFully(rel_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 (!process_memory->ReadFully(sp() + 0x28, &x86_64_ucontext.uc_mcontext, + sizeof(x86_64_mcontext_t))) { + return false; + } + SetFromUcontext(&x86_64_ucontext); + return true; +} + +} // namespace unwindstack diff --git a/libunwindstack/Ucontext.h b/libunwindstack/Ucontext.h deleted file mode 100644 index 22f6a8988..000000000 --- a/libunwindstack/Ucontext.h +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef _LIBUNWINDSTACK_UCONTEXT_H -#define _LIBUNWINDSTACK_UCONTEXT_H - -#include - -namespace unwindstack { - -//------------------------------------------------------------------- -// ARM ucontext structures -//------------------------------------------------------------------- -struct arm_stack_t { - uint32_t ss_sp; // void __user* - int32_t ss_flags; // int - uint32_t ss_size; // size_t -}; - -struct arm_mcontext_t { - uint32_t trap_no; // unsigned long - uint32_t error_code; // unsigned long - uint32_t oldmask; // unsigned long - uint32_t regs[ARM_REG_LAST]; // unsigned long - uint32_t cpsr; // unsigned long - uint32_t fault_address; // unsigned long -}; - -struct arm_ucontext_t { - uint32_t uc_flags; // unsigned long - uint32_t uc_link; // struct ucontext* - arm_stack_t uc_stack; - arm_mcontext_t uc_mcontext; - // Nothing else is used, so don't define it. -}; -//------------------------------------------------------------------- - -//------------------------------------------------------------------- -// ARM64 ucontext structures -//------------------------------------------------------------------- -struct arm64_stack_t { - uint64_t ss_sp; // void __user* - int32_t ss_flags; // int - uint64_t ss_size; // size_t -}; - -struct arm64_sigset_t { - uint64_t sig; // unsigned long -}; - -struct arm64_mcontext_t { - uint64_t fault_address; // __u64 - uint64_t regs[ARM64_REG_LAST]; // __u64 - uint64_t pstate; // __u64 - // Nothing else is used, so don't define it. -}; - -struct arm64_ucontext_t { - uint64_t uc_flags; // unsigned long - uint64_t uc_link; // struct ucontext* - arm64_stack_t uc_stack; - arm64_sigset_t uc_sigmask; - // The kernel adds extra padding after uc_sigmask to match glibc sigset_t on ARM64. - char __padding[128 - sizeof(arm64_sigset_t)]; - // The full structure requires 16 byte alignment, but our partial structure - // doesn't, so force the alignment. - arm64_mcontext_t uc_mcontext __attribute__((aligned(16))); -}; -//------------------------------------------------------------------- - -//------------------------------------------------------------------- -// X86 ucontext structures -//------------------------------------------------------------------- -struct x86_stack_t { - uint32_t ss_sp; // void __user* - int32_t ss_flags; // int - uint32_t ss_size; // size_t -}; - -struct x86_mcontext_t { - uint32_t gs; - uint32_t fs; - uint32_t es; - uint32_t ds; - uint32_t edi; - uint32_t esi; - uint32_t ebp; - uint32_t esp; - uint32_t ebx; - uint32_t edx; - uint32_t ecx; - uint32_t eax; - uint32_t trapno; - uint32_t err; - uint32_t eip; - uint32_t cs; - uint32_t efl; - uint32_t uesp; - uint32_t ss; - // Only care about the registers, skip everything else. -}; - -struct x86_ucontext_t { - uint32_t uc_flags; // unsigned long - uint32_t uc_link; // struct ucontext* - x86_stack_t uc_stack; - x86_mcontext_t uc_mcontext; - // Nothing else is used, so don't define it. -}; -//------------------------------------------------------------------- - -//------------------------------------------------------------------- -// X86_64 ucontext structures -//------------------------------------------------------------------- -struct x86_64_stack_t { - uint64_t ss_sp; // void __user* - int32_t ss_flags; // int - uint64_t ss_size; // size_t -}; - -struct x86_64_mcontext_t { - uint64_t r8; - uint64_t r9; - uint64_t r10; - uint64_t r11; - uint64_t r12; - uint64_t r13; - uint64_t r14; - uint64_t r15; - uint64_t rdi; - uint64_t rsi; - uint64_t rbp; - uint64_t rbx; - uint64_t rdx; - uint64_t rax; - uint64_t rcx; - uint64_t rsp; - uint64_t rip; - uint64_t efl; - uint64_t csgsfs; - uint64_t err; - uint64_t trapno; - uint64_t oldmask; - uint64_t cr2; - // Only care about the registers, skip everything else. -}; - -struct x86_64_ucontext_t { - uint64_t uc_flags; // unsigned long - uint64_t uc_link; // struct ucontext* - x86_64_stack_t uc_stack; - x86_64_mcontext_t uc_mcontext; - // Nothing else is used, so don't define it. -}; -//------------------------------------------------------------------- - -} // namespace unwindstack - -#endif // _LIBUNWINDSTACK_UCONTEXT_H diff --git a/libunwindstack/UcontextArm.h b/libunwindstack/UcontextArm.h new file mode 100644 index 000000000..8c94166af --- /dev/null +++ b/libunwindstack/UcontextArm.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _LIBUNWINDSTACK_UCONTEXT_ARM_H +#define _LIBUNWINDSTACK_UCONTEXT_ARM_H + +#include + +#include "MachineArm.h" + +namespace unwindstack { + +struct arm_stack_t { + uint32_t ss_sp; // void __user* + int32_t ss_flags; // int + uint32_t ss_size; // size_t +}; + +struct arm_mcontext_t { + uint32_t trap_no; // unsigned long + uint32_t error_code; // unsigned long + uint32_t oldmask; // unsigned long + uint32_t regs[ARM_REG_LAST]; // unsigned long + uint32_t cpsr; // unsigned long + uint32_t fault_address; // unsigned long +}; + +struct arm_ucontext_t { + uint32_t uc_flags; // unsigned long + uint32_t uc_link; // struct ucontext* + arm_stack_t uc_stack; + arm_mcontext_t uc_mcontext; + // Nothing else is used, so don't define it. +}; + +} // namespace unwindstack + +#endif // _LIBUNWINDSTACK_UCONTEXT_ARM_H diff --git a/libunwindstack/UcontextArm64.h b/libunwindstack/UcontextArm64.h new file mode 100644 index 000000000..655719f83 --- /dev/null +++ b/libunwindstack/UcontextArm64.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _LIBUNWINDSTACK_UCONTEXT_ARM64_H +#define _LIBUNWINDSTACK_UCONTEXT_ARM64_H + +#include + +#include "MachineArm64.h" + +namespace unwindstack { + +struct arm64_stack_t { + uint64_t ss_sp; // void __user* + int32_t ss_flags; // int + uint64_t ss_size; // size_t +}; + +struct arm64_sigset_t { + uint64_t sig; // unsigned long +}; + +struct arm64_mcontext_t { + uint64_t fault_address; // __u64 + uint64_t regs[ARM64_REG_LAST]; // __u64 + uint64_t pstate; // __u64 + // Nothing else is used, so don't define it. +}; + +struct arm64_ucontext_t { + uint64_t uc_flags; // unsigned long + uint64_t uc_link; // struct ucontext* + arm64_stack_t uc_stack; + arm64_sigset_t uc_sigmask; + // The kernel adds extra padding after uc_sigmask to match glibc sigset_t on ARM64. + char __padding[128 - sizeof(arm64_sigset_t)]; + // The full structure requires 16 byte alignment, but our partial structure + // doesn't, so force the alignment. + arm64_mcontext_t uc_mcontext __attribute__((aligned(16))); +}; + +} // namespace unwindstack + +#endif // _LIBUNWINDSTACK_UCONTEXT_ARM64_H diff --git a/libunwindstack/UcontextX86.h b/libunwindstack/UcontextX86.h new file mode 100644 index 000000000..f79d92b3a --- /dev/null +++ b/libunwindstack/UcontextX86.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _LIBUNWINDSTACK_UCONTEXT_X86_H +#define _LIBUNWINDSTACK_UCONTEXT_X86_H + +#include + +#include "MachineX86.h" + +namespace unwindstack { + +struct x86_stack_t { + uint32_t ss_sp; // void __user* + int32_t ss_flags; // int + uint32_t ss_size; // size_t +}; + +struct x86_mcontext_t { + uint32_t gs; + uint32_t fs; + uint32_t es; + uint32_t ds; + uint32_t edi; + uint32_t esi; + uint32_t ebp; + uint32_t esp; + uint32_t ebx; + uint32_t edx; + uint32_t ecx; + uint32_t eax; + uint32_t trapno; + uint32_t err; + uint32_t eip; + uint32_t cs; + uint32_t efl; + uint32_t uesp; + uint32_t ss; + // Only care about the registers, skip everything else. +}; + +struct x86_ucontext_t { + uint32_t uc_flags; // unsigned long + uint32_t uc_link; // struct ucontext* + x86_stack_t uc_stack; + x86_mcontext_t uc_mcontext; + // Nothing else is used, so don't define it. +}; + +} // namespace unwindstack + +#endif // _LIBUNWINDSTACK_UCONTEXT_X86_H diff --git a/libunwindstack/UcontextX86_64.h b/libunwindstack/UcontextX86_64.h new file mode 100644 index 000000000..d689796bf --- /dev/null +++ b/libunwindstack/UcontextX86_64.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _LIBUNWINDSTACK_UCONTEXT_X86_64_H +#define _LIBUNWINDSTACK_UCONTEXT_X86_64_H + +#include + +#include "MachineX86_64.h" + +namespace unwindstack { + +struct x86_64_stack_t { + uint64_t ss_sp; // void __user* + int32_t ss_flags; // int + uint64_t ss_size; // size_t +}; + +struct x86_64_mcontext_t { + uint64_t r8; + uint64_t r9; + uint64_t r10; + uint64_t r11; + uint64_t r12; + uint64_t r13; + uint64_t r14; + uint64_t r15; + uint64_t rdi; + uint64_t rsi; + uint64_t rbp; + uint64_t rbx; + uint64_t rdx; + uint64_t rax; + uint64_t rcx; + uint64_t rsp; + uint64_t rip; + uint64_t efl; + uint64_t csgsfs; + uint64_t err; + uint64_t trapno; + uint64_t oldmask; + uint64_t cr2; + // Only care about the registers, skip everything else. +}; + +struct x86_64_ucontext_t { + uint64_t uc_flags; // unsigned long + uint64_t uc_link; // struct ucontext* + x86_64_stack_t uc_stack; + x86_64_mcontext_t uc_mcontext; + // Nothing else is used, so don't define it. +}; + +} // namespace unwindstack + +#endif // _LIBUNWINDSTACK_UCONTEXT_X86_64_H diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp index 3092a62c2..4ae365d59 100644 --- a/libunwindstack/Unwinder.cpp +++ b/libunwindstack/Unwinder.cpp @@ -174,8 +174,7 @@ std::string Unwinder::FormatFrame(size_t frame_num) { if (frame_num >= frames_.size()) { return ""; } - return FormatFrame(frames_[frame_num], - regs_->MachineType() == EM_ARM || regs_->MachineType() == EM_386); + return FormatFrame(frames_[frame_num], regs_->Arch() == ARCH_ARM || regs_->Arch() == ARCH_X86); } std::string Unwinder::FormatFrame(const FrameData& frame, bool bits32) { diff --git a/libunwindstack/UserArm.h b/libunwindstack/UserArm.h new file mode 100644 index 000000000..7388c03e4 --- /dev/null +++ b/libunwindstack/UserArm.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _LIBUNWINDSTACK_USER_ARM_H +#define _LIBUNWINDSTACK_USER_ARM_H + +namespace unwindstack { + +struct arm_user_regs { + uint32_t regs[18]; +}; + +} // namespace unwindstack + +#endif // _LIBUNWINDSTACK_USER_ARM_H diff --git a/libunwindstack/UserArm64.h b/libunwindstack/UserArm64.h new file mode 100644 index 000000000..d74983fec --- /dev/null +++ b/libunwindstack/UserArm64.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _LIBUNWINDSTACK_USER_ARM64_H +#define _LIBUNWINDSTACK_USER_ARM64_H + +namespace unwindstack { + +struct arm64_user_regs { + uint64_t regs[31]; + uint64_t sp; + uint64_t pc; + uint64_t pstate; +}; + +} // namespace unwindstack + +#endif // _LIBUNWINDSTACK_USER_ARM64_H diff --git a/libunwindstack/UserX86.h b/libunwindstack/UserX86.h new file mode 100644 index 000000000..a040560c7 --- /dev/null +++ b/libunwindstack/UserX86.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _LIBUNWINDSTACK_USER_X86_H +#define _LIBUNWINDSTACK_USER_X86_H + +namespace unwindstack { + +struct x86_user_regs { + uint32_t ebx; + uint32_t ecx; + uint32_t edx; + uint32_t esi; + uint32_t edi; + uint32_t ebp; + uint32_t eax; + uint32_t xds; + uint32_t xes; + uint32_t xfs; + uint32_t xgs; + uint32_t orig_eax; + uint32_t eip; + uint32_t xcs; + uint32_t eflags; + uint32_t esp; + uint32_t xss; +}; + +} // namespace unwindstack + +#endif // _LIBUNWINDSTACK_USER_X86_H diff --git a/libunwindstack/User.h b/libunwindstack/UserX86_64.h similarity index 74% rename from libunwindstack/User.h rename to libunwindstack/UserX86_64.h index 53f7e50fe..b80d201d5 100644 --- a/libunwindstack/User.h +++ b/libunwindstack/UserX86_64.h @@ -26,31 +26,11 @@ * SUCH DAMAGE. */ -#ifndef _LIBUNWINDSTACK_USER_H -#define _LIBUNWINDSTACK_USER_H +#ifndef _LIBUNWINDSTACK_USER_X86_64_H +#define _LIBUNWINDSTACK_USER_X86_64_H namespace unwindstack { -struct x86_user_regs { - uint32_t ebx; - uint32_t ecx; - uint32_t edx; - uint32_t esi; - uint32_t edi; - uint32_t ebp; - uint32_t eax; - uint32_t xds; - uint32_t xes; - uint32_t xfs; - uint32_t xgs; - uint32_t orig_eax; - uint32_t eip; - uint32_t xcs; - uint32_t eflags; - uint32_t esp; - uint32_t xss; -}; - struct x86_64_user_regs { uint64_t r15; uint64_t r14; @@ -81,20 +61,6 @@ struct x86_64_user_regs { uint64_t gs; }; -struct arm_user_regs { - uint32_t regs[18]; -}; - -struct arm64_user_regs { - uint64_t regs[31]; - uint64_t sp; - uint64_t pc; - uint64_t pstate; -}; - -// The largest user structure. -constexpr size_t MAX_USER_REGS_SIZE = sizeof(arm64_user_regs) + 10; - } // namespace unwindstack -#endif // _LIBUNWINDSTACK_USER_H +#endif // _LIBUNWINDSTACK_USER_X86_64_H diff --git a/libunwindstack/include/unwindstack/Elf.h b/libunwindstack/include/unwindstack/Elf.h index d9ea9c49b..d27727b89 100644 --- a/libunwindstack/include/unwindstack/Elf.h +++ b/libunwindstack/include/unwindstack/Elf.h @@ -36,6 +36,14 @@ namespace unwindstack { struct MapInfo; class Regs; +enum ArchEnum : uint8_t { + ARCH_UNKNOWN = 0, + ARCH_ARM, + ARCH_ARM64, + ARCH_X86, + ARCH_X86_64, +}; + class Elf { public: Elf(Memory* memory) : memory_(memory) {} @@ -64,6 +72,8 @@ class Elf { uint8_t class_type() { return class_type_; } + ArchEnum arch() { return arch_; } + Memory* memory() { return memory_.get(); } ElfInterface* interface() { return interface_.get(); } @@ -83,6 +93,7 @@ class Elf { std::unique_ptr memory_; uint32_t machine_type_; uint8_t class_type_; + ArchEnum arch_; // Protect calls that can modify internal state of the interface object. std::mutex lock_; diff --git a/libunwindstack/include/unwindstack/Regs.h b/libunwindstack/include/unwindstack/Regs.h index 6576e4c91..7025fcf12 100644 --- a/libunwindstack/include/unwindstack/Regs.h +++ b/libunwindstack/include/unwindstack/Regs.h @@ -27,10 +27,8 @@ namespace unwindstack { // Forward declarations. class Elf; -struct MapInfo; +enum ArchEnum : uint8_t; class Memory; -struct x86_ucontext_t; -struct x86_64_ucontext_t; class Regs { public: @@ -51,7 +49,7 @@ class Regs { : total_regs_(total_regs), sp_reg_(sp_reg), return_loc_(return_loc) {} virtual ~Regs() = default; - virtual uint32_t MachineType() = 0; + virtual ArchEnum Arch() = 0; virtual void* RawData() = 0; virtual uint64_t pc() = 0; @@ -70,9 +68,9 @@ class Regs { uint16_t sp_reg() { return sp_reg_; } uint16_t total_regs() { return total_regs_; } - static uint32_t CurrentMachineType(); + static ArchEnum CurrentArch(); static Regs* RemoteGet(pid_t pid); - static Regs* CreateFromUcontext(uint32_t machine_type, void* ucontext); + static Regs* CreateFromUcontext(ArchEnum arch, void* ucontext); static Regs* CreateFromLocal(); protected: @@ -110,82 +108,6 @@ class RegsImpl : public Regs { std::vector regs_; }; -class RegsArm : public RegsImpl { - public: - RegsArm(); - virtual ~RegsArm() = default; - - virtual uint32_t MachineType() override final; - - uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override; - - void SetFromRaw() override; - - bool SetPcFromReturnAddress(Memory* process_memory) override; - - bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override; - - virtual void IterateRegisters(std::function) override final; -}; - -class RegsArm64 : public RegsImpl { - public: - RegsArm64(); - virtual ~RegsArm64() = default; - - virtual uint32_t MachineType() override final; - - uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override; - - void SetFromRaw() override; - - bool SetPcFromReturnAddress(Memory* process_memory) override; - - bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override; - - virtual void IterateRegisters(std::function) override final; -}; - -class RegsX86 : public RegsImpl { - public: - RegsX86(); - virtual ~RegsX86() = default; - - virtual uint32_t MachineType() override final; - - uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override; - - void SetFromRaw() override; - - bool SetPcFromReturnAddress(Memory* process_memory) override; - - bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override; - - void SetFromUcontext(x86_ucontext_t* ucontext); - - virtual void IterateRegisters(std::function) override final; -}; - -class RegsX86_64 : public RegsImpl { - public: - RegsX86_64(); - virtual ~RegsX86_64() = default; - - virtual uint32_t MachineType() override final; - - uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override; - - void SetFromRaw() override; - - bool SetPcFromReturnAddress(Memory* process_memory) override; - - bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override; - - void SetFromUcontext(x86_64_ucontext_t* ucontext); - - virtual void IterateRegisters(std::function) override final; -}; - } // namespace unwindstack #endif // _LIBUNWINDSTACK_REGS_H diff --git a/libunwindstack/include/unwindstack/RegsArm.h b/libunwindstack/include/unwindstack/RegsArm.h new file mode 100644 index 000000000..b5d344be6 --- /dev/null +++ b/libunwindstack/include/unwindstack/RegsArm.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2016 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 _LIBUNWINDSTACK_REGS_ARM_H +#define _LIBUNWINDSTACK_REGS_ARM_H + +#include + +#include + +#include +#include + +namespace unwindstack { + +// Forward declarations. +class Memory; + +class RegsArm : public RegsImpl { + public: + RegsArm(); + virtual ~RegsArm() = default; + + virtual ArchEnum Arch() override final; + + uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override; + + void SetFromRaw() override; + + bool SetPcFromReturnAddress(Memory* process_memory) override; + + bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override; + + virtual void IterateRegisters(std::function) override final; + + static Regs* Read(void* data); + + static Regs* CreateFromUcontext(void* ucontext); +}; + +} // namespace unwindstack + +#endif // _LIBUNWINDSTACK_REGS_ARM_H diff --git a/libunwindstack/include/unwindstack/RegsArm64.h b/libunwindstack/include/unwindstack/RegsArm64.h new file mode 100644 index 000000000..30e626ccf --- /dev/null +++ b/libunwindstack/include/unwindstack/RegsArm64.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2016 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 _LIBUNWINDSTACK_REGS_ARM64_H +#define _LIBUNWINDSTACK_REGS_ARM64_H + +#include + +#include + +#include +#include + +namespace unwindstack { + +// Forward declarations. +class Memory; + +class RegsArm64 : public RegsImpl { + public: + RegsArm64(); + virtual ~RegsArm64() = default; + + virtual ArchEnum Arch() override final; + + uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override; + + void SetFromRaw() override; + + bool SetPcFromReturnAddress(Memory* process_memory) override; + + bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override; + + virtual void IterateRegisters(std::function) override final; + + static Regs* Read(void* data); + + static Regs* CreateFromUcontext(void* ucontext); +}; + +} // namespace unwindstack + +#endif // _LIBUNWINDSTACK_REGS_ARM64_H diff --git a/libunwindstack/include/unwindstack/RegsX86.h b/libunwindstack/include/unwindstack/RegsX86.h new file mode 100644 index 000000000..a695bbfbb --- /dev/null +++ b/libunwindstack/include/unwindstack/RegsX86.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2016 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 _LIBUNWINDSTACK_REGS_X86_H +#define _LIBUNWINDSTACK_REGS_X86_H + +#include + +#include + +#include +#include + +namespace unwindstack { + +// Forward declarations. +class Memory; +struct x86_ucontext_t; + +class RegsX86 : public RegsImpl { + public: + RegsX86(); + virtual ~RegsX86() = default; + + virtual ArchEnum Arch() override final; + + uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override; + + void SetFromRaw() override; + + bool SetPcFromReturnAddress(Memory* process_memory) override; + + bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override; + + void SetFromUcontext(x86_ucontext_t* ucontext); + + virtual void IterateRegisters(std::function) override final; + + static Regs* Read(void* data); + + static Regs* CreateFromUcontext(void* ucontext); +}; + +} // namespace unwindstack + +#endif // _LIBUNWINDSTACK_REGS_X86_H diff --git a/libunwindstack/include/unwindstack/RegsX86_64.h b/libunwindstack/include/unwindstack/RegsX86_64.h new file mode 100644 index 000000000..23a3f2077 --- /dev/null +++ b/libunwindstack/include/unwindstack/RegsX86_64.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2016 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 _LIBUNWINDSTACK_REGS_X86_64_H +#define _LIBUNWINDSTACK_REGS_X86_64_H + +#include + +#include + +#include +#include + +namespace unwindstack { + +// Forward declarations. +class Memory; +struct x86_64_ucontext_t; + +class RegsX86_64 : public RegsImpl { + public: + RegsX86_64(); + virtual ~RegsX86_64() = default; + + virtual ArchEnum Arch() override final; + + uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override; + + void SetFromRaw() override; + + bool SetPcFromReturnAddress(Memory* process_memory) override; + + bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override; + + void SetFromUcontext(x86_64_ucontext_t* ucontext); + + virtual void IterateRegisters(std::function) override final; + + static Regs* Read(void* data); + + static Regs* CreateFromUcontext(void* ucontext); +}; + +} // namespace unwindstack + +#endif // _LIBUNWINDSTACK_REGS_X86_64_H diff --git a/libunwindstack/tests/ArmExidxDecodeTest.cpp b/libunwindstack/tests/ArmExidxDecodeTest.cpp index 94cb493d6..8d6d00de9 100644 --- a/libunwindstack/tests/ArmExidxDecodeTest.cpp +++ b/libunwindstack/tests/ArmExidxDecodeTest.cpp @@ -24,7 +24,7 @@ #include #include -#include +#include #include "ArmExidx.h" diff --git a/libunwindstack/tests/ElfInterfaceArmTest.cpp b/libunwindstack/tests/ElfInterfaceArmTest.cpp index 4b621c9be..5f7cf6097 100644 --- a/libunwindstack/tests/ElfInterfaceArmTest.cpp +++ b/libunwindstack/tests/ElfInterfaceArmTest.cpp @@ -20,10 +20,10 @@ #include -#include +#include #include "ElfInterfaceArm.h" -#include "Machine.h" +#include "MachineArm.h" #include "ElfFake.h" #include "MemoryFake.h" diff --git a/libunwindstack/tests/ElfTest.cpp b/libunwindstack/tests/ElfTest.cpp index afd113d0d..00192f1a4 100644 --- a/libunwindstack/tests/ElfTest.cpp +++ b/libunwindstack/tests/ElfTest.cpp @@ -25,6 +25,7 @@ #include #include +#include #include "ElfFake.h" #include "ElfTestUtils.h" diff --git a/libunwindstack/tests/RegsFake.h b/libunwindstack/tests/RegsFake.h index fedaf8734..3c5af4a2b 100644 --- a/libunwindstack/tests/RegsFake.h +++ b/libunwindstack/tests/RegsFake.h @@ -19,6 +19,7 @@ #include +#include #include #include @@ -30,7 +31,7 @@ class RegsFake : public Regs { : Regs(total_regs, sp_reg, Regs::Location(Regs::LOCATION_UNKNOWN, 0)) {} virtual ~RegsFake() = default; - uint32_t MachineType() override { return fake_type_; } + ArchEnum Arch() override { return fake_arch_; } void* RawData() override { return nullptr; } uint64_t pc() override { return fake_pc_; } uint64_t sp() override { return fake_sp_; } @@ -50,14 +51,14 @@ class RegsFake : public Regs { void SetFromRaw() override {} - void FakeSetMachineType(uint32_t type) { fake_type_ = type; } + void FakeSetArch(ArchEnum arch) { fake_arch_ = arch; } void FakeSetPc(uint64_t pc) { fake_pc_ = pc; } void FakeSetSp(uint64_t sp) { fake_sp_ = sp; } void FakeSetReturnAddress(uint64_t return_address) { fake_return_address_ = return_address; } void FakeSetReturnAddressValid(bool valid) { fake_return_address_valid_ = valid; } private: - uint32_t fake_type_ = 0; + ArchEnum fake_arch_ = ARCH_UNKNOWN; uint64_t fake_pc_ = 0; uint64_t fake_sp_ = 0; bool fake_return_address_valid_ = false; @@ -71,7 +72,7 @@ class RegsImplFake : public RegsImpl { : RegsImpl(total_regs, sp_reg, Regs::Location(Regs::LOCATION_UNKNOWN, 0)) {} virtual ~RegsImplFake() = default; - uint32_t MachineType() override { return 0; } + ArchEnum Arch() override { return ARCH_UNKNOWN; } uint64_t GetAdjustedPc(uint64_t, Elf*) override { return 0; } void SetFromRaw() override {} diff --git a/libunwindstack/tests/RegsIterateTest.cpp b/libunwindstack/tests/RegsIterateTest.cpp index c8d1d98bd..0cb70ba27 100644 --- a/libunwindstack/tests/RegsIterateTest.cpp +++ b/libunwindstack/tests/RegsIterateTest.cpp @@ -25,9 +25,15 @@ #include #include #include -#include +#include +#include +#include +#include -#include "Machine.h" +#include "MachineArm.h" +#include "MachineArm64.h" +#include "MachineX86.h" +#include "MachineX86_64.h" namespace unwindstack { diff --git a/libunwindstack/tests/RegsStepIfSignalHandlerTest.cpp b/libunwindstack/tests/RegsStepIfSignalHandlerTest.cpp index 85192d5d8..ae57cafb1 100644 --- a/libunwindstack/tests/RegsStepIfSignalHandlerTest.cpp +++ b/libunwindstack/tests/RegsStepIfSignalHandlerTest.cpp @@ -19,9 +19,15 @@ #include #include -#include +#include +#include +#include +#include -#include "Machine.h" +#include "MachineArm.h" +#include "MachineArm64.h" +#include "MachineX86.h" +#include "MachineX86_64.h" #include "MemoryFake.h" diff --git a/libunwindstack/tests/RegsTest.cpp b/libunwindstack/tests/RegsTest.cpp index 3320f7795..a93297344 100644 --- a/libunwindstack/tests/RegsTest.cpp +++ b/libunwindstack/tests/RegsTest.cpp @@ -21,7 +21,10 @@ #include #include #include -#include +#include +#include +#include +#include #include "ElfFake.h" #include "MemoryFake.h" @@ -212,4 +215,18 @@ TEST_F(RegsTest, x86_64_set_from_raw) { EXPECT_EQ(0x4900000000U, x86_64.pc()); } +TEST_F(RegsTest, machine_type) { + RegsArm arm_regs; + EXPECT_EQ(ARCH_ARM, arm_regs.Arch()); + + RegsArm64 arm64_regs; + EXPECT_EQ(ARCH_ARM64, arm64_regs.Arch()); + + RegsX86 x86_regs; + EXPECT_EQ(ARCH_X86, x86_regs.Arch()); + + RegsX86_64 x86_64_regs; + EXPECT_EQ(ARCH_X86_64, x86_64_regs.Arch()); +} + } // namespace unwindstack diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp index d24abe493..962f74455 100644 --- a/libunwindstack/tests/UnwindOfflineTest.cpp +++ b/libunwindstack/tests/UnwindOfflineTest.cpp @@ -27,10 +27,12 @@ #include #include -#include +#include +#include #include -#include "Machine.h" +#include "MachineArm.h" +#include "MachineArm64.h" #include "ElfTestUtils.h" @@ -73,7 +75,7 @@ TEST(UnwindOfflineTest, pc_straddle_arm32) { BufferMaps maps(buffer.data()); ASSERT_TRUE(maps.Parse()); - ASSERT_EQ(static_cast(EM_ARM), regs.MachineType()); + ASSERT_EQ(ARCH_ARM, regs.Arch()); std::shared_ptr process_memory(memory); @@ -125,7 +127,7 @@ TEST(UnwindOfflineTest, pc_straddle_arm64) { BufferMaps maps(buffer.data()); ASSERT_TRUE(maps.Parse()); - ASSERT_EQ(static_cast(EM_AARCH64), regs.MachineType()); + ASSERT_EQ(ARCH_ARM64, regs.Arch()); std::shared_ptr process_memory(memory); diff --git a/libunwindstack/tests/UnwindTest.cpp b/libunwindstack/tests/UnwindTest.cpp index b372fd0d4..242cc6a6f 100644 --- a/libunwindstack/tests/UnwindTest.cpp +++ b/libunwindstack/tests/UnwindTest.cpp @@ -250,7 +250,7 @@ TEST_F(UnwindTest, from_context) { LocalMaps maps; ASSERT_TRUE(maps.Parse()); - std::unique_ptr regs(Regs::CreateFromUcontext(Regs::CurrentMachineType(), ucontext)); + std::unique_ptr regs(Regs::CreateFromUcontext(Regs::CurrentArch(), ucontext)); VerifyUnwind(getpid(), &maps, regs.get(), kFunctionOrder); diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp index 098459e3e..71103b4fb 100644 --- a/libunwindstack/tests/UnwinderTest.cpp +++ b/libunwindstack/tests/UnwinderTest.cpp @@ -95,7 +95,7 @@ class UnwinderTest : public ::testing::Test { void SetUp() override { ElfInterfaceFake::FakeClear(); - regs_.FakeSetMachineType(EM_ARM); + regs_.FakeSetArch(ARCH_ARM); regs_.FakeSetReturnAddressValid(false); } @@ -702,14 +702,14 @@ TEST_F(UnwinderTest, format_frame) { ASSERT_EQ(1U, unwinder.NumFrames()); - regs_.FakeSetMachineType(EM_ARM); + regs_.FakeSetArch(ARCH_ARM); EXPECT_EQ(" #00 pc 00001300 /system/fake/libc.so (Frame0+10)", unwinder.FormatFrame(0)); - regs_.FakeSetMachineType(EM_386); + regs_.FakeSetArch(ARCH_X86); EXPECT_EQ(" #00 pc 00001300 /system/fake/libc.so (Frame0+10)", unwinder.FormatFrame(0)); - regs_.FakeSetMachineType(EM_AARCH64); + regs_.FakeSetArch(ARCH_ARM64); EXPECT_EQ(" #00 pc 0000000000001300 /system/fake/libc.so (Frame0+10)", unwinder.FormatFrame(0)); - regs_.FakeSetMachineType(EM_X86_64); + regs_.FakeSetArch(ARCH_X86_64); EXPECT_EQ(" #00 pc 0000000000001300 /system/fake/libc.so (Frame0+10)", unwinder.FormatFrame(0)); EXPECT_EQ("", unwinder.FormatFrame(1)); diff --git a/libunwindstack/tools/unwind.cpp b/libunwindstack/tools/unwind.cpp index f2530d767..789627984 100644 --- a/libunwindstack/tools/unwind.cpp +++ b/libunwindstack/tools/unwind.cpp @@ -63,17 +63,17 @@ void DoUnwind(pid_t pid) { } printf("ABI: "); - switch (regs->MachineType()) { - case EM_ARM: + switch (regs->Arch()) { + case unwindstack::ARCH_ARM: printf("arm"); break; - case EM_386: + case unwindstack::ARCH_X86: printf("x86"); break; - case EM_AARCH64: + case unwindstack::ARCH_ARM64: printf("arm64"); break; - case EM_X86_64: + case unwindstack::ARCH_X86_64: printf("x86_64"); break; default: