summaryrefslogtreecommitdiffstats
path: root/libunwindstack/tools/unwind.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libunwindstack/tools/unwind.cpp')
-rw-r--r--libunwindstack/tools/unwind.cpp133
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());
}
}