Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ae3b1365 authored by Christopher Ferris's avatar Christopher Ferris
Browse files

Use Unwinder object for unwind tool.

Test: Ran unwind on arm and arm64 processes.
Change-Id: I8a2a3ed31482044fe51d7e0d8c7f5588d5aad81c
parent 9e6c11da
Loading
Loading
Loading
Loading
+6 −108
Original line number Diff line number Diff line
@@ -26,17 +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>
#include <unwindstack/Maps.h>
#include <unwindstack/Memory.h>
#include <unwindstack/Regs.h>
#include <unwindstack/Unwinder.h>

static bool Attach(pid_t pid) {
  if (ptrace(PTRACE_ATTACH, pid, 0, 0) == -1) {
@@ -55,66 +49,6 @@ static bool Attach(pid_t pid) {
  return false;
}

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()) {
@@ -149,48 +83,12 @@ 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++) {
    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) {
      stepped = false;
    } else {
      bool finished;
      stepped =
          map_info->elf->Step(rel_pc + map_info->elf_offset, regs, process_memory.get(), &finished);
      if (stepped && finished) {
        break;
      }
    }
    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;
      }
    } else {
      return_address_attempt = false;
    }
  }
  unwindstack::Unwinder unwinder(128, &remote_maps, regs, process_memory);
  unwinder.Unwind();

  // Print the frames.
  for (auto& frame : frames) {
    printf("%s\n", frame.c_str());
  for (size_t i = 0; i < unwinder.NumFrames(); i++) {
    printf("%s\n", unwinder.FormatFrame(i).c_str());
  }
}

@@ -208,7 +106,7 @@ int main(int argc, char** argv) {

  DoUnwind(pid);

  Detach(pid);
  ptrace(PTRACE_DETACH, pid, 0, 0);

  return 0;
}