diff options
Diffstat (limited to 'libunwindstack/tools/unwind.cpp')
| -rw-r--r-- | libunwindstack/tools/unwind.cpp | 133 |
1 files changed, 93 insertions, 40 deletions
diff --git a/libunwindstack/tools/unwind.cpp b/libunwindstack/tools/unwind.cpp index 3614198eb..faac2eff6 100644 --- a/libunwindstack/tools/unwind.cpp +++ b/libunwindstack/tools/unwind.cpp @@ -26,7 +26,11 @@ #include <sys/types.h> #include <unistd.h> +#include <memory> #include <string> +#include <vector> + +#include <android-base/stringprintf.h> #include <unwindstack/Elf.h> #include <unwindstack/MapInfo.h> @@ -55,6 +59,62 @@ static bool Detach(pid_t pid) { return ptrace(PTRACE_DETACH, pid, 0, 0) == 0; } +std::string GetFrameInfo(size_t frame_num, unwindstack::Regs* regs, + const std::shared_ptr<unwindstack::Memory>& process_memory, + unwindstack::MapInfo* map_info, uint64_t* rel_pc) { + bool bits32; + switch (regs->MachineType()) { + case EM_ARM: + case EM_386: + bits32 = true; + break; + + default: + bits32 = false; + } + + if (map_info == nullptr) { + if (bits32) { + return android::base::StringPrintf(" #%02zu pc %08" PRIx64, frame_num, regs->pc()); + } else { + return android::base::StringPrintf(" #%02zu pc %016" PRIx64, frame_num, regs->pc()); + } + } + + unwindstack::Elf* elf = map_info->GetElf(process_memory, true); + *rel_pc = elf->GetRelPc(regs->pc(), map_info); + uint64_t adjusted_rel_pc = *rel_pc; + // Don't need to adjust the first frame pc. + if (frame_num != 0) { + adjusted_rel_pc = regs->GetAdjustedPc(*rel_pc, elf); + } + + std::string line; + if (bits32) { + line = android::base::StringPrintf(" #%02zu pc %08" PRIx64, frame_num, adjusted_rel_pc); + } else { + line = android::base::StringPrintf(" #%02zu pc %016" PRIx64, frame_num, adjusted_rel_pc); + } + if (!map_info->name.empty()) { + line += " " + map_info->name; + if (map_info->elf_offset != 0) { + line += android::base::StringPrintf(" (offset 0x%" PRIx64 ")", map_info->elf_offset); + } + } else { + line += android::base::StringPrintf(" <anonymous:%" PRIx64 ">", map_info->offset); + } + uint64_t func_offset; + std::string func_name; + if (elf->GetFunctionName(adjusted_rel_pc, &func_name, &func_offset)) { + line += " (" + func_name; + if (func_offset != 0) { + line += android::base::StringPrintf("+%" PRId64, func_offset); + } + line += ')'; + } + return line; +} + void DoUnwind(pid_t pid) { unwindstack::RemoteMaps remote_maps(pid); if (!remote_maps.Parse()) { @@ -68,7 +128,6 @@ void DoUnwind(pid_t pid) { return; } - bool bits32 = true; printf("ABI: "); switch (regs->MachineType()) { case EM_ARM: @@ -79,11 +138,9 @@ void DoUnwind(pid_t pid) { break; case EM_AARCH64: printf("arm64"); - bits32 = false; break; case EM_X86_64: printf("x86_64"); - bits32 = false; break; default: printf("unknown\n"); @@ -92,52 +149,48 @@ void DoUnwind(pid_t pid) { printf("\n"); auto process_memory = unwindstack::Memory::CreateProcessMemory(pid); + bool return_address_attempt = false; + std::vector<std::string> frames; for (size_t frame_num = 0; frame_num < 64; frame_num++) { - if (regs->pc() == 0) { - break; - } unwindstack::MapInfo* map_info = remote_maps.Find(regs->pc()); + uint64_t rel_pc; + frames.push_back(GetFrameInfo(frame_num, regs, process_memory, map_info, &rel_pc)); + bool stepped; if (map_info == nullptr) { - printf("Failed to find map data for the pc\n"); - break; - } - - unwindstack::Elf* elf = map_info->GetElf(process_memory, true); - - uint64_t rel_pc = elf->GetRelPc(regs->pc(), map_info); - uint64_t adjusted_rel_pc = rel_pc; - // Don't need to adjust the first frame pc. - if (frame_num != 0) { - adjusted_rel_pc = regs->GetAdjustedPc(rel_pc, elf); - } - - std::string name; - if (bits32) { - printf(" #%02zu pc %08" PRIx64, frame_num, adjusted_rel_pc); + stepped = false; } else { - printf(" #%02zu pc %016" PRIx64, frame_num, adjusted_rel_pc); - } - if (!map_info->name.empty()) { - printf(" %s", map_info->name.c_str()); - if (map_info->elf_offset != 0) { - printf(" (offset 0x%" PRIx64 ")", map_info->elf_offset); + bool finished; + stepped = + map_info->elf->Step(rel_pc + map_info->elf_offset, regs, process_memory.get(), &finished); + if (stepped && finished) { + break; } - } else { - printf(" <anonymous:%" PRIx64 ">", map_info->offset); } - uint64_t func_offset; - if (elf->GetFunctionName(adjusted_rel_pc, &name, &func_offset)) { - printf(" (%s", name.c_str()); - if (func_offset != 0) { - printf("+%" PRId64, func_offset); + if (!stepped) { + if (return_address_attempt) { + // We tried the return address and it didn't work, remove the last + // two frames. If this bad frame is the only frame, only remove + // the last frame. + frames.pop_back(); + if (frame_num != 1) { + frames.pop_back(); + } + break; + } else { + // Steping didn't work, try this secondary method. + if (!regs->SetPcFromReturnAddress(process_memory.get())) { + break; + } + return_address_attempt = true; } - printf(")"); + } else { + return_address_attempt = false; } - printf("\n"); + } - if (!elf->Step(rel_pc + map_info->elf_offset, regs, process_memory.get())) { - break; - } + // Print the frames. + for (auto& frame : frames) { + printf("%s\n", frame.c_str()); } } |
