diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp index 73bfdec1e..4c0c1a831 100644 --- a/libbacktrace/UnwindStack.cpp +++ b/libbacktrace/UnwindStack.cpp @@ -43,30 +43,8 @@ #include "UnwindStack.h" #include "UnwindStackMap.h" -static std::string GetFunctionName(BacktraceMap* back_map, uintptr_t pc, uintptr_t* offset) { - *offset = 0; - unwindstack::Maps* maps = reinterpret_cast(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(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* frames, size_t num_ignore_frames) { +bool Backtrace::Unwind(unwindstack::Regs* regs, BacktraceMap* back_map, + std::vector* frames, size_t num_ignore_frames) { static std::set skip_names{"libunwindstack.so", "libbacktrace.so"}; UnwindStackMap* stack_map = reinterpret_cast(back_map); 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) {} 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) { @@ -126,14 +104,14 @@ bool UnwindStackCurrent::UnwindFromContext(size_t num_ignore_frames, ucontext_t* } 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) : BacktracePtrace(pid, tid, map) {} 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) { @@ -146,5 +124,5 @@ bool UnwindStackPtrace::Unwind(size_t num_ignore_frames, ucontext_t* context) { } error_ = BACKTRACE_UNWIND_NO_ERROR; - return ::Unwind(regs.get(), GetMap(), &frames_, num_ignore_frames); + return Backtrace::Unwind(regs.get(), GetMap(), &frames_, num_ignore_frames); } diff --git a/libbacktrace/UnwindStackMap.cpp b/libbacktrace/UnwindStackMap.cpp index d4a2444dc..e7e5e4c43 100644 --- a/libbacktrace/UnwindStackMap.cpp +++ b/libbacktrace/UnwindStackMap.cpp @@ -75,6 +75,31 @@ void UnwindStackMap::FillIn(uintptr_t addr, backtrace_map_t* map) { 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 UnwindStackMap::GetProcessMemory() { + return process_memory_; +} + //------------------------------------------------------------------------- // BacktraceMap create function. //------------------------------------------------------------------------- diff --git a/libbacktrace/UnwindStackMap.h b/libbacktrace/UnwindStackMap.h index b93b3403c..bc432e745 100644 --- a/libbacktrace/UnwindStackMap.h +++ b/libbacktrace/UnwindStackMap.h @@ -34,6 +34,9 @@ class UnwindStackMap : public BacktraceMap { 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 GetProcessMemory() override final; + unwindstack::Maps* stack_maps() { return stack_maps_.get(); } const std::shared_ptr& process_memory() { return process_memory_; } diff --git a/libbacktrace/include/backtrace/Backtrace.h b/libbacktrace/include/backtrace/Backtrace.h index 289fd0cef..274c64bb6 100644 --- a/libbacktrace/include/backtrace/Backtrace.h +++ b/libbacktrace/include/backtrace/Backtrace.h @@ -77,6 +77,10 @@ struct backtrace_stackinfo_t { const uint8_t* data; }; +namespace unwindstack { +class Regs; +} + class Backtrace { public: // 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. virtual bool Unwind(size_t num_ignore_frames, ucontext_t* context = NULL) = 0; + static bool Unwind(unwindstack::Regs* regs, BacktraceMap* back_map, + std::vector* frames, size_t num_ignore_frames); + // Get the function name and offset into the function given the pc. // If the string is empty, then no valid function name was found, // or the pc is not in any valid map. diff --git a/libbacktrace/include/backtrace/BacktraceMap.h b/libbacktrace/include/backtrace/BacktraceMap.h index 6cf8b3fca..e176c783b 100644 --- a/libbacktrace/include/backtrace/BacktraceMap.h +++ b/libbacktrace/include/backtrace/BacktraceMap.h @@ -46,6 +46,10 @@ struct backtrace_map_t { std::string name; }; +namespace unwindstack { +class Memory; +} + class BacktraceMap { public: // 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. 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 GetProcessMemory() { return nullptr; } + // The flags returned are the same flags as used by the mmap call. // The values are PROT_*. int GetFlags(uintptr_t pc) { diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp index f40086e5d..e687a6895 100644 --- a/libunwindstack/Android.bp +++ b/libunwindstack/Android.bp @@ -122,6 +122,7 @@ cc_test { "tests/MemoryRangeTest.cpp", "tests/MemoryRemoteTest.cpp", "tests/MemoryTest.cpp", + "tests/RegsIterateTest.cpp", "tests/RegsStepIfSignalHandlerTest.cpp", "tests/RegsTest.cpp", "tests/SymbolsTest.cpp", diff --git a/libunwindstack/Regs.cpp b/libunwindstack/Regs.cpp index cf71e3922..36b8e25f5 100644 --- a/libunwindstack/Regs.cpp +++ b/libunwindstack/Regs.cpp @@ -80,6 +80,25 @@ bool RegsArm::SetPcFromReturnAddress(Memory*) { return true; } +void RegsArm::IterateRegisters(std::function fn) { + fn("r0", regs_[ARM_REG_R0]); + fn("r1", regs_[ARM_REG_R1]); + fn("r2", regs_[ARM_REG_R2]); + fn("r3", regs_[ARM_REG_R3]); + fn("r4", regs_[ARM_REG_R4]); + fn("r5", regs_[ARM_REG_R5]); + fn("r6", regs_[ARM_REG_R6]); + fn("r7", regs_[ARM_REG_R7]); + fn("r8", regs_[ARM_REG_R8]); + fn("r9", regs_[ARM_REG_R9]); + fn("r10", regs_[ARM_REG_R10]); + fn("r11", regs_[ARM_REG_R11]); + fn("ip", regs_[ARM_REG_R12]); + fn("sp", regs_[ARM_REG_SP]); + fn("lr", regs_[ARM_REG_LR]); + fn("pc", regs_[ARM_REG_PC]); +} + RegsArm64::RegsArm64() : RegsImpl(ARM64_REG_LAST, ARM64_REG_SP, Location(LOCATION_REGISTER, ARM64_REG_LR)) {} @@ -112,6 +131,42 @@ bool RegsArm64::SetPcFromReturnAddress(Memory*) { return true; } +void RegsArm64::IterateRegisters(std::function fn) { + fn("x0", regs_[ARM64_REG_R0]); + fn("x1", regs_[ARM64_REG_R1]); + fn("x2", regs_[ARM64_REG_R2]); + fn("x3", regs_[ARM64_REG_R3]); + fn("x4", regs_[ARM64_REG_R4]); + fn("x5", regs_[ARM64_REG_R5]); + fn("x6", regs_[ARM64_REG_R6]); + fn("x7", regs_[ARM64_REG_R7]); + fn("x8", regs_[ARM64_REG_R8]); + fn("x9", regs_[ARM64_REG_R9]); + fn("x10", regs_[ARM64_REG_R10]); + fn("x11", regs_[ARM64_REG_R11]); + fn("x12", regs_[ARM64_REG_R12]); + fn("x13", regs_[ARM64_REG_R13]); + fn("x14", regs_[ARM64_REG_R14]); + fn("x15", regs_[ARM64_REG_R15]); + fn("x16", regs_[ARM64_REG_R16]); + fn("x17", regs_[ARM64_REG_R17]); + fn("x18", regs_[ARM64_REG_R18]); + fn("x19", regs_[ARM64_REG_R19]); + fn("x20", regs_[ARM64_REG_R20]); + fn("x21", regs_[ARM64_REG_R21]); + fn("x22", regs_[ARM64_REG_R22]); + fn("x23", regs_[ARM64_REG_R23]); + fn("x24", regs_[ARM64_REG_R24]); + fn("x25", regs_[ARM64_REG_R25]); + fn("x26", regs_[ARM64_REG_R26]); + fn("x27", regs_[ARM64_REG_R27]); + fn("x28", regs_[ARM64_REG_R28]); + fn("x29", regs_[ARM64_REG_R29]); + fn("sp", regs_[ARM64_REG_SP]); + fn("lr", regs_[ARM64_REG_LR]); + fn("pc", regs_[ARM64_REG_PC]); +} + RegsX86::RegsX86() : RegsImpl(X86_REG_LAST, X86_REG_SP, Location(LOCATION_SP_OFFSET, -4)) {} @@ -146,6 +201,18 @@ bool RegsX86::SetPcFromReturnAddress(Memory* process_memory) { return true; } +void RegsX86::IterateRegisters(std::function fn) { + fn("eax", regs_[X86_REG_EAX]); + fn("ebx", regs_[X86_REG_EBX]); + fn("ecx", regs_[X86_REG_ECX]); + fn("edx", regs_[X86_REG_EDX]); + fn("ebp", regs_[X86_REG_EBP]); + fn("edi", regs_[X86_REG_EDI]); + fn("esi", regs_[X86_REG_ESI]); + fn("esp", regs_[X86_REG_ESP]); + fn("eip", regs_[X86_REG_EIP]); +} + RegsX86_64::RegsX86_64() : RegsImpl(X86_64_REG_LAST, X86_64_REG_SP, Location(LOCATION_SP_OFFSET, -8)) {} @@ -181,6 +248,26 @@ bool RegsX86_64::SetPcFromReturnAddress(Memory* process_memory) { return true; } +void RegsX86_64::IterateRegisters(std::function fn) { + fn("rax", regs_[X86_64_REG_RAX]); + fn("rbx", regs_[X86_64_REG_RBX]); + fn("rcx", regs_[X86_64_REG_RCX]); + fn("rdx", regs_[X86_64_REG_RDX]); + fn("r8", regs_[X86_64_REG_R8]); + fn("r9", regs_[X86_64_REG_R9]); + fn("r10", regs_[X86_64_REG_R10]); + fn("r11", regs_[X86_64_REG_R11]); + fn("r12", regs_[X86_64_REG_R12]); + fn("r13", regs_[X86_64_REG_R13]); + fn("r14", regs_[X86_64_REG_R14]); + fn("r15", regs_[X86_64_REG_R15]); + fn("rdi", regs_[X86_64_REG_RDI]); + fn("rsi", regs_[X86_64_REG_RSI]); + fn("rbp", regs_[X86_64_REG_RBP]); + fn("rsp", regs_[X86_64_REG_RSP]); + fn("rip", regs_[X86_64_REG_RIP]); +} + static Regs* ReadArm(void* remote_data) { arm_user_regs* user = reinterpret_cast(remote_data); diff --git a/libunwindstack/include/unwindstack/Regs.h b/libunwindstack/include/unwindstack/Regs.h index 9d3150bf6..6576e4c91 100644 --- a/libunwindstack/include/unwindstack/Regs.h +++ b/libunwindstack/include/unwindstack/Regs.h @@ -19,6 +19,8 @@ #include +#include +#include #include namespace unwindstack { @@ -63,6 +65,8 @@ class Regs { virtual bool SetPcFromReturnAddress(Memory* process_memory) = 0; + virtual void IterateRegisters(std::function) = 0; + uint16_t sp_reg() { return sp_reg_; } uint16_t total_regs() { return total_regs_; } @@ -94,6 +98,12 @@ class RegsImpl : public Regs { void* RawData() override { return regs_.data(); } + virtual void IterateRegisters(std::function fn) override { + for (size_t i = 0; i < regs_.size(); ++i) { + fn(std::to_string(i).c_str(), regs_[i]); + } + } + protected: AddressType pc_; AddressType sp_; @@ -114,6 +124,8 @@ class RegsArm : public RegsImpl { bool SetPcFromReturnAddress(Memory* process_memory) override; bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override; + + virtual void IterateRegisters(std::function) override final; }; class RegsArm64 : public RegsImpl { @@ -130,6 +142,8 @@ class RegsArm64 : public RegsImpl { bool SetPcFromReturnAddress(Memory* process_memory) override; bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override; + + virtual void IterateRegisters(std::function) override final; }; class RegsX86 : public RegsImpl { @@ -148,6 +162,8 @@ class RegsX86 : public RegsImpl { bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override; void SetFromUcontext(x86_ucontext_t* ucontext); + + virtual void IterateRegisters(std::function) override final; }; class RegsX86_64 : public RegsImpl { @@ -166,6 +182,8 @@ class RegsX86_64 : public RegsImpl { bool StepIfSignalHandler(uint64_t rel_pc, Elf* elf, Memory* process_memory) override; void SetFromUcontext(x86_64_ucontext_t* ucontext); + + virtual void IterateRegisters(std::function) override final; }; } // namespace unwindstack diff --git a/libunwindstack/tests/RegsFake.h b/libunwindstack/tests/RegsFake.h index efcd029ab..fedaf8734 100644 --- a/libunwindstack/tests/RegsFake.h +++ b/libunwindstack/tests/RegsFake.h @@ -42,6 +42,8 @@ class RegsFake : public Regs { return true; } + void IterateRegisters(std::function) override {} + uint64_t GetAdjustedPc(uint64_t rel_pc, Elf*) override { return rel_pc - 2; } bool StepIfSignalHandler(uint64_t, Elf*, Memory*) override { return false; } diff --git a/libunwindstack/tests/RegsIterateTest.cpp b/libunwindstack/tests/RegsIterateTest.cpp new file mode 100644 index 000000000..c8d1d98bd --- /dev/null +++ b/libunwindstack/tests/RegsIterateTest.cpp @@ -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 + +#include +#include +#include + +#include + +#include +#include +#include +#include + +#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 +class RegsIterateTest : public ::testing::Test { +}; + +template +std::vector ExpectedRegisters(); + +template<> +std::vector ExpectedRegisters() { + std::vector 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 ExpectedRegisters() { + std::vector 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 ExpectedRegisters() { + std::vector 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 ExpectedRegisters() { + std::vector 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; +TYPED_TEST_CASE(RegsIterateTest, RegTypes); + +TYPED_TEST(RegsIterateTest, iterate) { + std::vector expected = ExpectedRegisters(); + TypeParam regs; + for (const auto& reg : expected) { + regs[reg.offset] = reg.offset; + } + + std::vector actual; + regs.IterateRegisters([&actual](const char* name, uint64_t value) { + actual.push_back({name, value}); + }); + + ASSERT_EQ(expected, actual); +} + +} // namespace unwindstack