Split arch data into separate files.
Add an ArchEnum to express the arch of the Elf objects and Reg objects. Split out the regs code into per arch pieces and generic parts. Also, split out the header files for each arch. Do not break out the test code yet, there isn't enough and it doesn't help to maintain the tests. Test: libunwindstack/libbacktrace/debuggerd unit tests pass. Test: Running debuggerd -b <PIDS> yields valid data on bullhead. Change-Id: If61f6c730c9ff2249f986b41de8c4d62f7158325
This commit is contained in:
parent
1ae6d14f93
commit
d06001d6e0
|
@ -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;
|
||||
|
|
|
@ -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",
|
||||
],
|
||||
|
|
|
@ -23,11 +23,11 @@
|
|||
|
||||
#include <unwindstack/Log.h>
|
||||
#include <unwindstack/Memory.h>
|
||||
#include <unwindstack/Regs.h>
|
||||
#include <unwindstack/RegsArm.h>
|
||||
|
||||
#include "ArmExidx.h"
|
||||
#include "Check.h"
|
||||
#include "Machine.h"
|
||||
#include "MachineArm.h"
|
||||
|
||||
namespace unwindstack {
|
||||
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
#include <unwindstack/Regs.h>
|
||||
|
||||
#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));
|
||||
}
|
||||
|
||||
|
|
|
@ -18,11 +18,11 @@
|
|||
#include <stdint.h>
|
||||
|
||||
#include <unwindstack/Memory.h>
|
||||
#include <unwindstack/Regs.h>
|
||||
#include <unwindstack/RegsArm.h>
|
||||
|
||||
#include "ArmExidx.h"
|
||||
#include "ElfInterfaceArm.h"
|
||||
#include "Machine.h"
|
||||
#include "MachineArm.h"
|
||||
|
||||
namespace unwindstack {
|
||||
|
||||
|
|
|
@ -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 <stdint.h>
|
||||
|
||||
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
|
|
@ -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 <stdint.h>
|
||||
|
||||
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
|
|
@ -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 <stdint.h>
|
||||
|
||||
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
|
|
@ -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 <stdint.h>
|
||||
|
||||
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
|
|
@ -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 <stdint.h>
|
||||
|
||||
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
|
|
@ -14,7 +14,6 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <elf.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/uio.h>
|
||||
|
@ -23,315 +22,21 @@
|
|||
|
||||
#include <unwindstack/Elf.h>
|
||||
#include <unwindstack/MapInfo.h>
|
||||
#include <unwindstack/Memory.h>
|
||||
#include <unwindstack/Regs.h>
|
||||
#include <unwindstack/RegsArm.h>
|
||||
#include <unwindstack/RegsArm64.h>
|
||||
#include <unwindstack/RegsX86.h>
|
||||
#include <unwindstack/RegsX86_64.h>
|
||||
|
||||
#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<uint32_t>(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<void(const char*, uint64_t)> 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<uint64_t>(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<void(const char*, uint64_t)> 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<uint32_t>(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<void(const char*, uint64_t)> 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<uint64_t>(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<void(const char*, uint64_t)> 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<arm_user_regs*>(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<arm64_user_regs*>(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<uint64_t*>(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<x86_user_regs*>(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<x86_64_user_regs*>(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<arm_ucontext_t*>(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<arm64_ucontext_t*>(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<x86_ucontext_t*>(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<x86_64_ucontext_t*>(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
|
||||
|
|
|
@ -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 <stdint.h>
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include <unwindstack/Elf.h>
|
||||
#include <unwindstack/MapInfo.h>
|
||||
#include <unwindstack/Memory.h>
|
||||
#include <unwindstack/RegsArm.h>
|
||||
|
||||
#include "MachineArm.h"
|
||||
#include "UcontextArm.h"
|
||||
#include "UserArm.h"
|
||||
|
||||
namespace unwindstack {
|
||||
|
||||
RegsArm::RegsArm()
|
||||
: RegsImpl<uint32_t>(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<void(const char*, uint64_t)> 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<arm_user_regs*>(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<arm_ucontext_t*>(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
|
|
@ -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 <stdint.h>
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include <unwindstack/Elf.h>
|
||||
#include <unwindstack/MapInfo.h>
|
||||
#include <unwindstack/Memory.h>
|
||||
#include <unwindstack/RegsArm64.h>
|
||||
|
||||
#include "MachineArm64.h"
|
||||
#include "UcontextArm64.h"
|
||||
#include "UserArm64.h"
|
||||
|
||||
namespace unwindstack {
|
||||
|
||||
RegsArm64::RegsArm64()
|
||||
: RegsImpl<uint64_t>(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<void(const char*, uint64_t)> 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<arm64_user_regs*>(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<uint64_t*>(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<arm64_ucontext_t*>(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
|
|
@ -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 <stdint.h>
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include <unwindstack/Elf.h>
|
||||
#include <unwindstack/MapInfo.h>
|
||||
#include <unwindstack/Memory.h>
|
||||
#include <unwindstack/RegsX86.h>
|
||||
|
||||
#include "MachineX86.h"
|
||||
#include "UcontextX86.h"
|
||||
#include "UserX86.h"
|
||||
|
||||
namespace unwindstack {
|
||||
|
||||
RegsX86::RegsX86()
|
||||
: RegsImpl<uint32_t>(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<void(const char*, uint64_t)> 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<x86_user_regs*>(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<x86_ucontext_t*>(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
|
|
@ -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 <stdint.h>
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include <unwindstack/Elf.h>
|
||||
#include <unwindstack/MapInfo.h>
|
||||
#include <unwindstack/Memory.h>
|
||||
#include <unwindstack/RegsX86_64.h>
|
||||
|
||||
#include "MachineX86_64.h"
|
||||
#include "UcontextX86_64.h"
|
||||
#include "UserX86_64.h"
|
||||
|
||||
namespace unwindstack {
|
||||
|
||||
RegsX86_64::RegsX86_64()
|
||||
: RegsImpl<uint64_t>(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<void(const char*, uint64_t)> 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<x86_64_user_regs*>(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<x86_64_ucontext_t*>(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
|
|
@ -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 <stdint.h>
|
||||
|
||||
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
|
|
@ -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 <stdint.h>
|
||||
|
||||
#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
|
|
@ -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 <stdint.h>
|
||||
|
||||
#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
|
|
@ -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 <stdint.h>
|
||||
|
||||
#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
|
|
@ -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 <stdint.h>
|
||||
|
||||
#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
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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> 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_;
|
||||
|
||||
|
|
|
@ -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<AddressType> regs_;
|
||||
};
|
||||
|
||||
class RegsArm : public RegsImpl<uint32_t> {
|
||||
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<void(const char*, uint64_t)>) override final;
|
||||
};
|
||||
|
||||
class RegsArm64 : public RegsImpl<uint64_t> {
|
||||
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<void(const char*, uint64_t)>) override final;
|
||||
};
|
||||
|
||||
class RegsX86 : public RegsImpl<uint32_t> {
|
||||
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<void(const char*, uint64_t)>) override final;
|
||||
};
|
||||
|
||||
class RegsX86_64 : public RegsImpl<uint64_t> {
|
||||
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<void(const char*, uint64_t)>) override final;
|
||||
};
|
||||
|
||||
} // namespace unwindstack
|
||||
|
||||
#endif // _LIBUNWINDSTACK_REGS_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 <stdint.h>
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include <unwindstack/Elf.h>
|
||||
#include <unwindstack/Regs.h>
|
||||
|
||||
namespace unwindstack {
|
||||
|
||||
// Forward declarations.
|
||||
class Memory;
|
||||
|
||||
class RegsArm : public RegsImpl<uint32_t> {
|
||||
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<void(const char*, uint64_t)>) override final;
|
||||
|
||||
static Regs* Read(void* data);
|
||||
|
||||
static Regs* CreateFromUcontext(void* ucontext);
|
||||
};
|
||||
|
||||
} // namespace unwindstack
|
||||
|
||||
#endif // _LIBUNWINDSTACK_REGS_ARM_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 <stdint.h>
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include <unwindstack/Elf.h>
|
||||
#include <unwindstack/Regs.h>
|
||||
|
||||
namespace unwindstack {
|
||||
|
||||
// Forward declarations.
|
||||
class Memory;
|
||||
|
||||
class RegsArm64 : public RegsImpl<uint64_t> {
|
||||
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<void(const char*, uint64_t)>) override final;
|
||||
|
||||
static Regs* Read(void* data);
|
||||
|
||||
static Regs* CreateFromUcontext(void* ucontext);
|
||||
};
|
||||
|
||||
} // namespace unwindstack
|
||||
|
||||
#endif // _LIBUNWINDSTACK_REGS_ARM64_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 <stdint.h>
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include <unwindstack/Elf.h>
|
||||
#include <unwindstack/Regs.h>
|
||||
|
||||
namespace unwindstack {
|
||||
|
||||
// Forward declarations.
|
||||
class Memory;
|
||||
struct x86_ucontext_t;
|
||||
|
||||
class RegsX86 : public RegsImpl<uint32_t> {
|
||||
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<void(const char*, uint64_t)>) override final;
|
||||
|
||||
static Regs* Read(void* data);
|
||||
|
||||
static Regs* CreateFromUcontext(void* ucontext);
|
||||
};
|
||||
|
||||
} // namespace unwindstack
|
||||
|
||||
#endif // _LIBUNWINDSTACK_REGS_X86_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 <stdint.h>
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include <unwindstack/Elf.h>
|
||||
#include <unwindstack/Regs.h>
|
||||
|
||||
namespace unwindstack {
|
||||
|
||||
// Forward declarations.
|
||||
class Memory;
|
||||
struct x86_64_ucontext_t;
|
||||
|
||||
class RegsX86_64 : public RegsImpl<uint64_t> {
|
||||
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<void(const char*, uint64_t)>) override final;
|
||||
|
||||
static Regs* Read(void* data);
|
||||
|
||||
static Regs* CreateFromUcontext(void* ucontext);
|
||||
};
|
||||
|
||||
} // namespace unwindstack
|
||||
|
||||
#endif // _LIBUNWINDSTACK_REGS_X86_64_H
|
|
@ -24,7 +24,7 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include <unwindstack/Log.h>
|
||||
#include <unwindstack/Regs.h>
|
||||
#include <unwindstack/RegsArm.h>
|
||||
|
||||
#include "ArmExidx.h"
|
||||
|
||||
|
|
|
@ -20,10 +20,10 @@
|
|||
|
||||
#include <vector>
|
||||
|
||||
#include <unwindstack/Regs.h>
|
||||
#include <unwindstack/RegsArm.h>
|
||||
|
||||
#include "ElfInterfaceArm.h"
|
||||
#include "Machine.h"
|
||||
#include "MachineArm.h"
|
||||
|
||||
#include "ElfFake.h"
|
||||
#include "MemoryFake.h"
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#include <unwindstack/Elf.h>
|
||||
#include <unwindstack/MapInfo.h>
|
||||
#include <unwindstack/RegsArm.h>
|
||||
|
||||
#include "ElfFake.h"
|
||||
#include "ElfTestUtils.h"
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <unwindstack/Elf.h>
|
||||
#include <unwindstack/Memory.h>
|
||||
#include <unwindstack/Regs.h>
|
||||
|
||||
|
@ -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<TypeParam> {
|
|||
: RegsImpl<TypeParam>(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 {}
|
||||
|
|
|
@ -25,9 +25,15 @@
|
|||
#include <unwindstack/Elf.h>
|
||||
#include <unwindstack/ElfInterface.h>
|
||||
#include <unwindstack/MapInfo.h>
|
||||
#include <unwindstack/Regs.h>
|
||||
#include <unwindstack/RegsArm.h>
|
||||
#include <unwindstack/RegsArm64.h>
|
||||
#include <unwindstack/RegsX86.h>
|
||||
#include <unwindstack/RegsX86_64.h>
|
||||
|
||||
#include "Machine.h"
|
||||
#include "MachineArm.h"
|
||||
#include "MachineArm64.h"
|
||||
#include "MachineX86.h"
|
||||
#include "MachineX86_64.h"
|
||||
|
||||
namespace unwindstack {
|
||||
|
||||
|
|
|
@ -19,9 +19,15 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include <unwindstack/Elf.h>
|
||||
#include <unwindstack/Regs.h>
|
||||
#include <unwindstack/RegsArm.h>
|
||||
#include <unwindstack/RegsArm64.h>
|
||||
#include <unwindstack/RegsX86.h>
|
||||
#include <unwindstack/RegsX86_64.h>
|
||||
|
||||
#include "Machine.h"
|
||||
#include "MachineArm.h"
|
||||
#include "MachineArm64.h"
|
||||
#include "MachineX86.h"
|
||||
#include "MachineX86_64.h"
|
||||
|
||||
#include "MemoryFake.h"
|
||||
|
||||
|
|
|
@ -21,7 +21,10 @@
|
|||
#include <unwindstack/Elf.h>
|
||||
#include <unwindstack/ElfInterface.h>
|
||||
#include <unwindstack/MapInfo.h>
|
||||
#include <unwindstack/Regs.h>
|
||||
#include <unwindstack/RegsArm.h>
|
||||
#include <unwindstack/RegsArm64.h>
|
||||
#include <unwindstack/RegsX86.h>
|
||||
#include <unwindstack/RegsX86_64.h>
|
||||
|
||||
#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
|
||||
|
|
|
@ -27,10 +27,12 @@
|
|||
|
||||
#include <unwindstack/Maps.h>
|
||||
#include <unwindstack/Memory.h>
|
||||
#include <unwindstack/Regs.h>
|
||||
#include <unwindstack/RegsArm.h>
|
||||
#include <unwindstack/RegsArm64.h>
|
||||
#include <unwindstack/Unwinder.h>
|
||||
|
||||
#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<uint32_t>(EM_ARM), regs.MachineType());
|
||||
ASSERT_EQ(ARCH_ARM, regs.Arch());
|
||||
|
||||
std::shared_ptr<Memory> process_memory(memory);
|
||||
|
||||
|
@ -125,7 +127,7 @@ TEST(UnwindOfflineTest, pc_straddle_arm64) {
|
|||
BufferMaps maps(buffer.data());
|
||||
ASSERT_TRUE(maps.Parse());
|
||||
|
||||
ASSERT_EQ(static_cast<uint32_t>(EM_AARCH64), regs.MachineType());
|
||||
ASSERT_EQ(ARCH_ARM64, regs.Arch());
|
||||
|
||||
std::shared_ptr<Memory> process_memory(memory);
|
||||
|
||||
|
|
|
@ -250,7 +250,7 @@ TEST_F(UnwindTest, from_context) {
|
|||
|
||||
LocalMaps maps;
|
||||
ASSERT_TRUE(maps.Parse());
|
||||
std::unique_ptr<Regs> regs(Regs::CreateFromUcontext(Regs::CurrentMachineType(), ucontext));
|
||||
std::unique_ptr<Regs> regs(Regs::CreateFromUcontext(Regs::CurrentArch(), ucontext));
|
||||
|
||||
VerifyUnwind(getpid(), &maps, regs.get(), kFunctionOrder);
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in New Issue