Merge changes I8f33830f,Icd2b891b,I8736ff5c,Iae6e342a am: 1c65e77e6d
am: cada8d74d0
Change-Id: I547cd2c462d8636d3bb375292863ec5f8d5b81e6
This commit is contained in:
commit
7445e8dc84
10 changed files with 324 additions and 28 deletions
|
|
@ -43,30 +43,8 @@
|
||||||
#include "UnwindStack.h"
|
#include "UnwindStack.h"
|
||||||
#include "UnwindStackMap.h"
|
#include "UnwindStackMap.h"
|
||||||
|
|
||||||
static std::string GetFunctionName(BacktraceMap* back_map, uintptr_t pc, uintptr_t* offset) {
|
bool Backtrace::Unwind(unwindstack::Regs* regs, BacktraceMap* back_map,
|
||||||
*offset = 0;
|
std::vector<backtrace_frame_data_t>* frames, size_t num_ignore_frames) {
|
||||||
unwindstack::Maps* maps = reinterpret_cast<UnwindStackMap*>(back_map)->stack_maps();
|
|
||||||
|
|
||||||
// Get the map for this
|
|
||||||
unwindstack::MapInfo* map_info = maps->Find(pc);
|
|
||||||
if (map_info == nullptr || map_info->flags & PROT_DEVICE_MAP) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
UnwindStackMap* stack_map = reinterpret_cast<UnwindStackMap*>(back_map);
|
|
||||||
unwindstack::Elf* elf = map_info->GetElf(stack_map->process_memory(), true);
|
|
||||||
|
|
||||||
std::string name;
|
|
||||||
uint64_t func_offset;
|
|
||||||
if (!elf->GetFunctionName(elf->GetRelPc(pc, map_info), &name, &func_offset)) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
*offset = func_offset;
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool Unwind(unwindstack::Regs* regs, BacktraceMap* back_map,
|
|
||||||
std::vector<backtrace_frame_data_t>* frames, size_t num_ignore_frames) {
|
|
||||||
static std::set<std::string> skip_names{"libunwindstack.so", "libbacktrace.so"};
|
static std::set<std::string> skip_names{"libunwindstack.so", "libbacktrace.so"};
|
||||||
UnwindStackMap* stack_map = reinterpret_cast<UnwindStackMap*>(back_map);
|
UnwindStackMap* stack_map = reinterpret_cast<UnwindStackMap*>(back_map);
|
||||||
auto process_memory = stack_map->process_memory();
|
auto process_memory = stack_map->process_memory();
|
||||||
|
|
@ -110,7 +88,7 @@ UnwindStackCurrent::UnwindStackCurrent(pid_t pid, pid_t tid, BacktraceMap* map)
|
||||||
: BacktraceCurrent(pid, tid, map) {}
|
: BacktraceCurrent(pid, tid, map) {}
|
||||||
|
|
||||||
std::string UnwindStackCurrent::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
|
std::string UnwindStackCurrent::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
|
||||||
return ::GetFunctionName(GetMap(), pc, offset);
|
return GetMap()->GetFunctionName(pc, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UnwindStackCurrent::UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) {
|
bool UnwindStackCurrent::UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) {
|
||||||
|
|
@ -126,14 +104,14 @@ bool UnwindStackCurrent::UnwindFromContext(size_t num_ignore_frames, ucontext_t*
|
||||||
}
|
}
|
||||||
|
|
||||||
error_ = BACKTRACE_UNWIND_NO_ERROR;
|
error_ = BACKTRACE_UNWIND_NO_ERROR;
|
||||||
return ::Unwind(regs.get(), GetMap(), &frames_, num_ignore_frames);
|
return Backtrace::Unwind(regs.get(), GetMap(), &frames_, num_ignore_frames);
|
||||||
}
|
}
|
||||||
|
|
||||||
UnwindStackPtrace::UnwindStackPtrace(pid_t pid, pid_t tid, BacktraceMap* map)
|
UnwindStackPtrace::UnwindStackPtrace(pid_t pid, pid_t tid, BacktraceMap* map)
|
||||||
: BacktracePtrace(pid, tid, map) {}
|
: BacktracePtrace(pid, tid, map) {}
|
||||||
|
|
||||||
std::string UnwindStackPtrace::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
|
std::string UnwindStackPtrace::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
|
||||||
return ::GetFunctionName(GetMap(), pc, offset);
|
return GetMap()->GetFunctionName(pc, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UnwindStackPtrace::Unwind(size_t num_ignore_frames, ucontext_t* context) {
|
bool UnwindStackPtrace::Unwind(size_t num_ignore_frames, ucontext_t* context) {
|
||||||
|
|
@ -146,5 +124,5 @@ bool UnwindStackPtrace::Unwind(size_t num_ignore_frames, ucontext_t* context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
error_ = BACKTRACE_UNWIND_NO_ERROR;
|
error_ = BACKTRACE_UNWIND_NO_ERROR;
|
||||||
return ::Unwind(regs.get(), GetMap(), &frames_, num_ignore_frames);
|
return Backtrace::Unwind(regs.get(), GetMap(), &frames_, num_ignore_frames);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,31 @@ void UnwindStackMap::FillIn(uintptr_t addr, backtrace_map_t* map) {
|
||||||
map->load_bias = elf->GetLoadBias();
|
map->load_bias = elf->GetLoadBias();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string UnwindStackMap::GetFunctionName(uintptr_t pc, uintptr_t* offset) {
|
||||||
|
*offset = 0;
|
||||||
|
unwindstack::Maps* maps = stack_maps();
|
||||||
|
|
||||||
|
// Get the map for this
|
||||||
|
unwindstack::MapInfo* map_info = maps->Find(pc);
|
||||||
|
if (map_info == nullptr || map_info->flags & PROT_DEVICE_MAP) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
unwindstack::Elf* elf = map_info->GetElf(process_memory(), true);
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
uint64_t func_offset;
|
||||||
|
if (!elf->GetFunctionName(elf->GetRelPc(pc, map_info), &name, &func_offset)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
*offset = func_offset;
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<unwindstack::Memory> UnwindStackMap::GetProcessMemory() {
|
||||||
|
return process_memory_;
|
||||||
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
// BacktraceMap create function.
|
// BacktraceMap create function.
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,9 @@ class UnwindStackMap : public BacktraceMap {
|
||||||
|
|
||||||
void FillIn(uintptr_t addr, backtrace_map_t* map) override;
|
void FillIn(uintptr_t addr, backtrace_map_t* map) override;
|
||||||
|
|
||||||
|
virtual std::string GetFunctionName(uintptr_t pc, uintptr_t* offset) override;
|
||||||
|
virtual std::shared_ptr<unwindstack::Memory> GetProcessMemory() override final;
|
||||||
|
|
||||||
unwindstack::Maps* stack_maps() { return stack_maps_.get(); }
|
unwindstack::Maps* stack_maps() { return stack_maps_.get(); }
|
||||||
|
|
||||||
const std::shared_ptr<unwindstack::Memory>& process_memory() { return process_memory_; }
|
const std::shared_ptr<unwindstack::Memory>& process_memory() { return process_memory_; }
|
||||||
|
|
|
||||||
|
|
@ -77,6 +77,10 @@ struct backtrace_stackinfo_t {
|
||||||
const uint8_t* data;
|
const uint8_t* data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace unwindstack {
|
||||||
|
class Regs;
|
||||||
|
}
|
||||||
|
|
||||||
class Backtrace {
|
class Backtrace {
|
||||||
public:
|
public:
|
||||||
// Create the correct Backtrace object based on what is to be unwound.
|
// Create the correct Backtrace object based on what is to be unwound.
|
||||||
|
|
@ -106,6 +110,9 @@ public:
|
||||||
// Get the current stack trace and store in the backtrace_ structure.
|
// Get the current stack trace and store in the backtrace_ structure.
|
||||||
virtual bool Unwind(size_t num_ignore_frames, ucontext_t* context = NULL) = 0;
|
virtual bool Unwind(size_t num_ignore_frames, ucontext_t* context = NULL) = 0;
|
||||||
|
|
||||||
|
static bool Unwind(unwindstack::Regs* regs, BacktraceMap* back_map,
|
||||||
|
std::vector<backtrace_frame_data_t>* frames, size_t num_ignore_frames);
|
||||||
|
|
||||||
// Get the function name and offset into the function given the pc.
|
// Get the function name and offset into the function given the pc.
|
||||||
// If the string is empty, then no valid function name was found,
|
// If the string is empty, then no valid function name was found,
|
||||||
// or the pc is not in any valid map.
|
// or the pc is not in any valid map.
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,10 @@ struct backtrace_map_t {
|
||||||
std::string name;
|
std::string name;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace unwindstack {
|
||||||
|
class Memory;
|
||||||
|
}
|
||||||
|
|
||||||
class BacktraceMap {
|
class BacktraceMap {
|
||||||
public:
|
public:
|
||||||
// If uncached is true, then parse the current process map as of the call.
|
// If uncached is true, then parse the current process map as of the call.
|
||||||
|
|
@ -62,6 +66,10 @@ public:
|
||||||
// Fill in the map data structure for the given address.
|
// Fill in the map data structure for the given address.
|
||||||
virtual void FillIn(uintptr_t addr, backtrace_map_t* map);
|
virtual void FillIn(uintptr_t addr, backtrace_map_t* map);
|
||||||
|
|
||||||
|
// Only supported with the new unwinder.
|
||||||
|
virtual std::string GetFunctionName(uintptr_t /*pc*/, uintptr_t* /*offset*/) { return ""; }
|
||||||
|
virtual std::shared_ptr<unwindstack::Memory> GetProcessMemory() { return nullptr; }
|
||||||
|
|
||||||
// The flags returned are the same flags as used by the mmap call.
|
// The flags returned are the same flags as used by the mmap call.
|
||||||
// The values are PROT_*.
|
// The values are PROT_*.
|
||||||
int GetFlags(uintptr_t pc) {
|
int GetFlags(uintptr_t pc) {
|
||||||
|
|
|
||||||
|
|
@ -122,6 +122,7 @@ cc_test {
|
||||||
"tests/MemoryRangeTest.cpp",
|
"tests/MemoryRangeTest.cpp",
|
||||||
"tests/MemoryRemoteTest.cpp",
|
"tests/MemoryRemoteTest.cpp",
|
||||||
"tests/MemoryTest.cpp",
|
"tests/MemoryTest.cpp",
|
||||||
|
"tests/RegsIterateTest.cpp",
|
||||||
"tests/RegsStepIfSignalHandlerTest.cpp",
|
"tests/RegsStepIfSignalHandlerTest.cpp",
|
||||||
"tests/RegsTest.cpp",
|
"tests/RegsTest.cpp",
|
||||||
"tests/SymbolsTest.cpp",
|
"tests/SymbolsTest.cpp",
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,25 @@ bool RegsArm::SetPcFromReturnAddress(Memory*) {
|
||||||
return true;
|
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()
|
RegsArm64::RegsArm64()
|
||||||
: RegsImpl<uint64_t>(ARM64_REG_LAST, ARM64_REG_SP, Location(LOCATION_REGISTER, ARM64_REG_LR)) {}
|
: RegsImpl<uint64_t>(ARM64_REG_LAST, ARM64_REG_SP, Location(LOCATION_REGISTER, ARM64_REG_LR)) {}
|
||||||
|
|
||||||
|
|
@ -112,6 +131,42 @@ bool RegsArm64::SetPcFromReturnAddress(Memory*) {
|
||||||
return true;
|
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()
|
RegsX86::RegsX86()
|
||||||
: RegsImpl<uint32_t>(X86_REG_LAST, X86_REG_SP, Location(LOCATION_SP_OFFSET, -4)) {}
|
: RegsImpl<uint32_t>(X86_REG_LAST, X86_REG_SP, Location(LOCATION_SP_OFFSET, -4)) {}
|
||||||
|
|
||||||
|
|
@ -146,6 +201,18 @@ bool RegsX86::SetPcFromReturnAddress(Memory* process_memory) {
|
||||||
return true;
|
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()
|
RegsX86_64::RegsX86_64()
|
||||||
: RegsImpl<uint64_t>(X86_64_REG_LAST, X86_64_REG_SP, Location(LOCATION_SP_OFFSET, -8)) {}
|
: RegsImpl<uint64_t>(X86_64_REG_LAST, X86_64_REG_SP, Location(LOCATION_SP_OFFSET, -8)) {}
|
||||||
|
|
||||||
|
|
@ -181,6 +248,26 @@ bool RegsX86_64::SetPcFromReturnAddress(Memory* process_memory) {
|
||||||
return true;
|
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) {
|
static Regs* ReadArm(void* remote_data) {
|
||||||
arm_user_regs* user = reinterpret_cast<arm_user_regs*>(remote_data);
|
arm_user_regs* user = reinterpret_cast<arm_user_regs*>(remote_data);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,8 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace unwindstack {
|
namespace unwindstack {
|
||||||
|
|
@ -63,6 +65,8 @@ class Regs {
|
||||||
|
|
||||||
virtual bool SetPcFromReturnAddress(Memory* process_memory) = 0;
|
virtual bool SetPcFromReturnAddress(Memory* process_memory) = 0;
|
||||||
|
|
||||||
|
virtual void IterateRegisters(std::function<void(const char*, uint64_t)>) = 0;
|
||||||
|
|
||||||
uint16_t sp_reg() { return sp_reg_; }
|
uint16_t sp_reg() { return sp_reg_; }
|
||||||
uint16_t total_regs() { return total_regs_; }
|
uint16_t total_regs() { return total_regs_; }
|
||||||
|
|
||||||
|
|
@ -94,6 +98,12 @@ class RegsImpl : public Regs {
|
||||||
|
|
||||||
void* RawData() override { return regs_.data(); }
|
void* RawData() override { return regs_.data(); }
|
||||||
|
|
||||||
|
virtual void IterateRegisters(std::function<void(const char*, uint64_t)> fn) override {
|
||||||
|
for (size_t i = 0; i < regs_.size(); ++i) {
|
||||||
|
fn(std::to_string(i).c_str(), regs_[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
AddressType pc_;
|
AddressType pc_;
|
||||||
AddressType sp_;
|
AddressType sp_;
|
||||||
|
|
@ -114,6 +124,8 @@ class RegsArm : public RegsImpl<uint32_t> {
|
||||||
bool SetPcFromReturnAddress(Memory* process_memory) override;
|
bool SetPcFromReturnAddress(Memory* process_memory) override;
|
||||||
|
|
||||||
bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, 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> {
|
class RegsArm64 : public RegsImpl<uint64_t> {
|
||||||
|
|
@ -130,6 +142,8 @@ class RegsArm64 : public RegsImpl<uint64_t> {
|
||||||
bool SetPcFromReturnAddress(Memory* process_memory) override;
|
bool SetPcFromReturnAddress(Memory* process_memory) override;
|
||||||
|
|
||||||
bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, 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> {
|
class RegsX86 : public RegsImpl<uint32_t> {
|
||||||
|
|
@ -148,6 +162,8 @@ class RegsX86 : public RegsImpl<uint32_t> {
|
||||||
bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override;
|
bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override;
|
||||||
|
|
||||||
void SetFromUcontext(x86_ucontext_t* ucontext);
|
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> {
|
class RegsX86_64 : public RegsImpl<uint64_t> {
|
||||||
|
|
@ -166,6 +182,8 @@ class RegsX86_64 : public RegsImpl<uint64_t> {
|
||||||
bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override;
|
bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override;
|
||||||
|
|
||||||
void SetFromUcontext(x86_64_ucontext_t* ucontext);
|
void SetFromUcontext(x86_64_ucontext_t* ucontext);
|
||||||
|
|
||||||
|
virtual void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace unwindstack
|
} // namespace unwindstack
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,8 @@ class RegsFake : public Regs {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IterateRegisters(std::function<void(const char*, uint64_t)>) override {}
|
||||||
|
|
||||||
uint64_t GetAdjustedPc(uint64_t rel_pc, Elf*) override { return rel_pc - 2; }
|
uint64_t GetAdjustedPc(uint64_t rel_pc, Elf*) override { return rel_pc - 2; }
|
||||||
|
|
||||||
bool StepIfSignalHandler(uint64_t, Elf*, Memory*) override { return false; }
|
bool StepIfSignalHandler(uint64_t, Elf*, Memory*) override { return false; }
|
||||||
|
|
|
||||||
167
libunwindstack/tests/RegsIterateTest.cpp
Normal file
167
libunwindstack/tests/RegsIterateTest.cpp
Normal file
|
|
@ -0,0 +1,167 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include <unwindstack/Elf.h>
|
||||||
|
#include <unwindstack/ElfInterface.h>
|
||||||
|
#include <unwindstack/MapInfo.h>
|
||||||
|
#include <unwindstack/Regs.h>
|
||||||
|
|
||||||
|
#include "Machine.h"
|
||||||
|
|
||||||
|
namespace unwindstack {
|
||||||
|
|
||||||
|
struct Register {
|
||||||
|
std::string expected_name;
|
||||||
|
uint64_t offset;
|
||||||
|
|
||||||
|
bool operator==(const Register& rhs) const {
|
||||||
|
return std::tie(expected_name, offset) == std::tie(rhs.expected_name, rhs.offset);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class RegsIterateTest : public ::testing::Test {
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename RegsType>
|
||||||
|
std::vector<Register> ExpectedRegisters();
|
||||||
|
|
||||||
|
template<>
|
||||||
|
std::vector<Register> ExpectedRegisters<RegsArm>() {
|
||||||
|
std::vector<Register> result;
|
||||||
|
result.push_back({"r0", ARM_REG_R0});
|
||||||
|
result.push_back({"r1", ARM_REG_R1});
|
||||||
|
result.push_back({"r2", ARM_REG_R2});
|
||||||
|
result.push_back({"r3", ARM_REG_R3});
|
||||||
|
result.push_back({"r4", ARM_REG_R4});
|
||||||
|
result.push_back({"r5", ARM_REG_R5});
|
||||||
|
result.push_back({"r6", ARM_REG_R6});
|
||||||
|
result.push_back({"r7", ARM_REG_R7});
|
||||||
|
result.push_back({"r8", ARM_REG_R8});
|
||||||
|
result.push_back({"r9", ARM_REG_R9});
|
||||||
|
result.push_back({"r10", ARM_REG_R10});
|
||||||
|
result.push_back({"r11", ARM_REG_R11});
|
||||||
|
result.push_back({"ip", ARM_REG_R12});
|
||||||
|
result.push_back({"sp", ARM_REG_SP});
|
||||||
|
result.push_back({"lr", ARM_REG_LR});
|
||||||
|
result.push_back({"pc", ARM_REG_PC});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
std::vector<Register> ExpectedRegisters<RegsArm64>() {
|
||||||
|
std::vector<Register> result;
|
||||||
|
result.push_back({"x0", ARM64_REG_R0});
|
||||||
|
result.push_back({"x1", ARM64_REG_R1});
|
||||||
|
result.push_back({"x2", ARM64_REG_R2});
|
||||||
|
result.push_back({"x3", ARM64_REG_R3});
|
||||||
|
result.push_back({"x4", ARM64_REG_R4});
|
||||||
|
result.push_back({"x5", ARM64_REG_R5});
|
||||||
|
result.push_back({"x6", ARM64_REG_R6});
|
||||||
|
result.push_back({"x7", ARM64_REG_R7});
|
||||||
|
result.push_back({"x8", ARM64_REG_R8});
|
||||||
|
result.push_back({"x9", ARM64_REG_R9});
|
||||||
|
result.push_back({"x10", ARM64_REG_R10});
|
||||||
|
result.push_back({"x11", ARM64_REG_R11});
|
||||||
|
result.push_back({"x12", ARM64_REG_R12});
|
||||||
|
result.push_back({"x13", ARM64_REG_R13});
|
||||||
|
result.push_back({"x14", ARM64_REG_R14});
|
||||||
|
result.push_back({"x15", ARM64_REG_R15});
|
||||||
|
result.push_back({"x16", ARM64_REG_R16});
|
||||||
|
result.push_back({"x17", ARM64_REG_R17});
|
||||||
|
result.push_back({"x18", ARM64_REG_R18});
|
||||||
|
result.push_back({"x19", ARM64_REG_R19});
|
||||||
|
result.push_back({"x20", ARM64_REG_R20});
|
||||||
|
result.push_back({"x21", ARM64_REG_R21});
|
||||||
|
result.push_back({"x22", ARM64_REG_R22});
|
||||||
|
result.push_back({"x23", ARM64_REG_R23});
|
||||||
|
result.push_back({"x24", ARM64_REG_R24});
|
||||||
|
result.push_back({"x25", ARM64_REG_R25});
|
||||||
|
result.push_back({"x26", ARM64_REG_R26});
|
||||||
|
result.push_back({"x27", ARM64_REG_R27});
|
||||||
|
result.push_back({"x28", ARM64_REG_R28});
|
||||||
|
result.push_back({"x29", ARM64_REG_R29});
|
||||||
|
result.push_back({"sp", ARM64_REG_SP});
|
||||||
|
result.push_back({"lr", ARM64_REG_LR});
|
||||||
|
result.push_back({"pc", ARM64_REG_PC});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
std::vector<Register> ExpectedRegisters<RegsX86>() {
|
||||||
|
std::vector<Register> result;
|
||||||
|
result.push_back({"eax", X86_REG_EAX});
|
||||||
|
result.push_back({"ebx", X86_REG_EBX});
|
||||||
|
result.push_back({"ecx", X86_REG_ECX});
|
||||||
|
result.push_back({"edx", X86_REG_EDX});
|
||||||
|
result.push_back({"ebp", X86_REG_EBP});
|
||||||
|
result.push_back({"edi", X86_REG_EDI});
|
||||||
|
result.push_back({"esi", X86_REG_ESI});
|
||||||
|
result.push_back({"esp", X86_REG_ESP});
|
||||||
|
result.push_back({"eip", X86_REG_EIP});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
std::vector<Register> ExpectedRegisters<RegsX86_64>() {
|
||||||
|
std::vector<Register> result;
|
||||||
|
result.push_back({"rax", X86_64_REG_RAX});
|
||||||
|
result.push_back({"rbx", X86_64_REG_RBX});
|
||||||
|
result.push_back({"rcx", X86_64_REG_RCX});
|
||||||
|
result.push_back({"rdx", X86_64_REG_RDX});
|
||||||
|
result.push_back({"r8", X86_64_REG_R8});
|
||||||
|
result.push_back({"r9", X86_64_REG_R9});
|
||||||
|
result.push_back({"r10", X86_64_REG_R10});
|
||||||
|
result.push_back({"r11", X86_64_REG_R11});
|
||||||
|
result.push_back({"r12", X86_64_REG_R12});
|
||||||
|
result.push_back({"r13", X86_64_REG_R13});
|
||||||
|
result.push_back({"r14", X86_64_REG_R14});
|
||||||
|
result.push_back({"r15", X86_64_REG_R15});
|
||||||
|
result.push_back({"rdi", X86_64_REG_RDI});
|
||||||
|
result.push_back({"rsi", X86_64_REG_RSI});
|
||||||
|
result.push_back({"rbp", X86_64_REG_RBP});
|
||||||
|
result.push_back({"rsp", X86_64_REG_RSP});
|
||||||
|
result.push_back({"rip", X86_64_REG_RIP});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
using RegTypes = ::testing::Types<RegsArm, RegsArm64, RegsX86, RegsX86_64>;
|
||||||
|
TYPED_TEST_CASE(RegsIterateTest, RegTypes);
|
||||||
|
|
||||||
|
TYPED_TEST(RegsIterateTest, iterate) {
|
||||||
|
std::vector<Register> expected = ExpectedRegisters<TypeParam>();
|
||||||
|
TypeParam regs;
|
||||||
|
for (const auto& reg : expected) {
|
||||||
|
regs[reg.offset] = reg.offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Register> actual;
|
||||||
|
regs.IterateRegisters([&actual](const char* name, uint64_t value) {
|
||||||
|
actual.push_back({name, value});
|
||||||
|
});
|
||||||
|
|
||||||
|
ASSERT_EQ(expected, actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace unwindstack
|
||||||
Loading…
Add table
Reference in a new issue