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

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

Move dex pc frame creation into libunwindstack.

Test: Compiles, all unit tests pass.
Test: Ran 137-cfi art test in interpreter and verified interpreter
Test: frames still show up.

Change-Id: Icea90194986faa733a873e8cf467fc2513eb5573
parent 01ba1157
Loading
Loading
Loading
Loading
+2 −6
Original line number Diff line number Diff line
@@ -50,7 +50,6 @@ libbacktrace_sources = [
    "BacktracePtrace.cpp",
    "thread_utils.c",
    "ThreadEntry.cpp",
    "UnwindDexFile.cpp",
    "UnwindStack.cpp",
    "UnwindStackMap.cpp",
]
@@ -110,10 +109,9 @@ cc_library {
            static_libs: ["libasync_safe"],
        },
        vendor: {
            cflags: ["-DNO_LIBDEXFILE"],
            exclude_srcs: ["UnwindDexFile.cpp"],
            cflags: ["-DNO_LIBDEXFILE_SUPPORT"],
            exclude_shared_libs: ["libdexfile"],
        },
        }
    },
    whole_static_libs: ["libdemangle"],
}
@@ -145,8 +143,6 @@ cc_test {
        "backtrace_test.cpp",
        "GetPss.cpp",
        "thread_utils.c",

        "unwind_dex_test.cpp",
    ],

    cflags: [
+9 −84
Original line number Diff line number Diff line
@@ -36,70 +36,15 @@
#include <unwindstack/Regs.h>
#include <unwindstack/RegsGetLocal.h>

#if !defined(NO_LIBDEXFILE_SUPPORT)
#include <unwindstack/DexFiles.h>
#endif
#include <unwindstack/Unwinder.h>

#include "BacktraceLog.h"
#ifndef NO_LIBDEXFILE
#include "UnwindDexFile.h"
#endif
#include "UnwindStack.h"
#include "UnwindStackMap.h"

static void FillInDexFrame(UnwindStackMap* stack_map, uint64_t dex_pc,
                           backtrace_frame_data_t* frame) {
  // The DEX PC points into the .dex section within an ELF file.
  // However, this is a BBS section manually mmaped to a .vdex file,
  // so we need to get the following map to find the ELF data.
  unwindstack::Maps* maps = stack_map->stack_maps();
  auto it = maps->begin();
  uint64_t rel_dex_pc;
  unwindstack::MapInfo* info;
  for (; it != maps->end(); ++it) {
    auto entry = *it;
    if (dex_pc >= entry->start && dex_pc < entry->end) {
      info = entry;
      rel_dex_pc = dex_pc - entry->start;
      frame->map.start = entry->start;
      frame->map.end = entry->end;
      frame->map.offset = entry->offset;
      frame->map.load_bias = entry->load_bias;
      frame->map.flags = entry->flags;
      frame->map.name = entry->name;
      frame->rel_pc = rel_dex_pc;
      break;
    }
  }
  if (it == maps->end() || ++it == maps->end()) {
    return;
  }

  auto entry = *it;
  auto process_memory = stack_map->process_memory();
  unwindstack::Elf* elf = entry->GetElf(process_memory, true);
  if (!elf->valid()) {
    return;
  }

  // Adjust the relative dex by the offset.
  rel_dex_pc += entry->elf_offset;

  uint64_t dex_offset;
  if (!elf->GetFunctionName(rel_dex_pc, &frame->func_name, &dex_offset)) {
    return;
  }
  frame->func_offset = dex_offset;
  if (frame->func_name != "$dexfile") {
    return;
  }

#ifndef NO_LIBDEXFILE
  UnwindDexFile* dex_file = stack_map->GetDexFile(dex_pc - dex_offset, info);
  if (dex_file != nullptr) {
    dex_file->GetMethodInformation(dex_offset, &frame->func_name, &frame->func_offset);
  }
#endif
}

bool Backtrace::Unwind(unwindstack::Regs* regs, BacktraceMap* back_map,
                       std::vector<backtrace_frame_data_t>* frames, size_t num_ignore_frames,
                       std::vector<std::string>* skip_names, BacktraceUnwindError* error) {
@@ -110,6 +55,11 @@ bool Backtrace::Unwind(unwindstack::Regs* regs, BacktraceMap* back_map,
  if (stack_map->GetJitDebug() != nullptr) {
    unwinder.SetJitDebug(stack_map->GetJitDebug(), regs->Arch());
  }
#if !defined(NO_LIBDEXFILE_SUPPORT)
  if (stack_map->GetDexFiles() != nullptr) {
    unwinder.SetDexFiles(stack_map->GetDexFiles(), regs->Arch());
  }
#endif
  unwinder.Unwind(skip_names, &stack_map->GetSuffixesToIgnore());
  if (error != nullptr) {
    switch (unwinder.LastErrorCode()) {
@@ -150,36 +100,11 @@ bool Backtrace::Unwind(unwindstack::Regs* regs, BacktraceMap* back_map,
  }

  auto unwinder_frames = unwinder.frames();
  // Get the real number of frames we'll need.
  size_t total_frames = 0;
  for (size_t i = num_ignore_frames; i < unwinder.NumFrames(); i++, total_frames++) {
    if (unwinder_frames[i].dex_pc != 0) {
      total_frames++;
    }
  }
  frames->resize(total_frames);
  frames->resize(unwinder.NumFrames() - num_ignore_frames);
  size_t cur_frame = 0;
  for (size_t i = num_ignore_frames; i < unwinder.NumFrames(); i++) {
    auto frame = &unwinder_frames[i];

    // Inject extra 'virtual' frame that represents the dex pc data.
    // The dex pc is magic register defined in the Mterp interpreter,
    // and thus it will be restored/observed in the frame after it.
    // Adding the dex frame first here will create something like:
    //   #7 pc 006b1ba1 libartd.so  ExecuteMterpImpl+14625
    //   #8 pc 0015fa20 core.vdex   java.util.Arrays.binarySearch+8
    //   #9 pc 0039a1ef libartd.so  art::interpreter::Execute+719
    if (frame->dex_pc != 0) {
      backtrace_frame_data_t* dex_frame = &frames->at(cur_frame);
      dex_frame->num = cur_frame++;
      dex_frame->pc = frame->dex_pc;
      dex_frame->rel_pc = frame->dex_pc;
      dex_frame->sp = frame->sp;
      dex_frame->stack_size = 0;
      dex_frame->func_offset = 0;
      FillInDexFrame(stack_map, frame->dex_pc, dex_frame);
    }

    backtrace_frame_data_t* back_frame = &frames->at(cur_frame);

    back_frame->num = cur_frame++;
+3 −29
Original line number Diff line number Diff line
@@ -26,20 +26,11 @@
#include <unwindstack/MapInfo.h>
#include <unwindstack/Maps.h>

#include "UnwindDexFile.h"
#include "UnwindStackMap.h"

//-------------------------------------------------------------------------
UnwindStackMap::UnwindStackMap(pid_t pid) : BacktraceMap(pid) {}

UnwindStackMap::~UnwindStackMap() {
#ifndef NO_LIBDEXFILE
  for (auto& entry : dex_files_) {
    delete entry.second;
  }
#endif
}

bool UnwindStackMap::Build() {
  if (pid_ == 0) {
    pid_ = getpid();
@@ -54,6 +45,9 @@ bool UnwindStackMap::Build() {
  // Create a JitDebug object for getting jit unwind information.
  std::vector<std::string> search_libs_{"libart.so", "libartd.so"};
  jit_debug_.reset(new unwindstack::JitDebug(process_memory_, search_libs_));
#if !defined(NO_LIBDEXFILE_SUPPORT)
  dex_files_.reset(new unwindstack::DexFiles(process_memory_));
#endif

  if (!stack_maps_->Parse()) {
    return false;
@@ -127,26 +121,6 @@ std::shared_ptr<unwindstack::Memory> UnwindStackMap::GetProcessMemory() {
  return process_memory_;
}

#ifdef NO_LIBDEXFILE
UnwindDexFile* UnwindStackMap::GetDexFile(uint64_t, unwindstack::MapInfo*) {
  return nullptr;
}
#else
UnwindDexFile* UnwindStackMap::GetDexFile(uint64_t dex_file_offset, unwindstack::MapInfo* info) {
  // Lock while we get the data.
  std::lock_guard<std::mutex> guard(dex_lock_);
  UnwindDexFile* dex_file;
  auto entry = dex_files_.find(dex_file_offset);
  if (entry == dex_files_.end()) {
    dex_file = UnwindDexFile::Create(dex_file_offset, process_memory_.get(), info);
    dex_files_[dex_file_offset] = dex_file;
  } else {
    dex_file = entry->second;
  }
  return dex_file;
}
#endif

UnwindStackOfflineMap::UnwindStackOfflineMap(pid_t pid) : UnwindStackMap(pid) {}

bool UnwindStackOfflineMap::Build() {
+9 −5
Original line number Diff line number Diff line
@@ -27,6 +27,9 @@

#include <backtrace/Backtrace.h>
#include <backtrace/BacktraceMap.h>
#if !defined(NO_LIBDEXFILE_SUPPORT)
#include <unwindstack/DexFiles.h>
#endif
#include <unwindstack/JitDebug.h>
#include <unwindstack/Maps.h>

@@ -36,7 +39,7 @@ class UnwindDexFile;
class UnwindStackMap : public BacktraceMap {
 public:
  explicit UnwindStackMap(pid_t pid);
  ~UnwindStackMap();
  ~UnwindStackMap() = default;

  bool Build() override;

@@ -51,7 +54,9 @@ class UnwindStackMap : public BacktraceMap {

  unwindstack::JitDebug* GetJitDebug() { return jit_debug_.get(); }

  UnwindDexFile* GetDexFile(uint64_t dex_file_offset, unwindstack::MapInfo* info);
#if !defined(NO_LIBDEXFILE_SUPPORT)
  unwindstack::DexFiles* GetDexFiles() { return dex_files_.get(); }
#endif

 protected:
  uint64_t GetLoadBias(size_t index) override;
@@ -59,9 +64,8 @@ class UnwindStackMap : public BacktraceMap {
  std::unique_ptr<unwindstack::Maps> stack_maps_;
  std::shared_ptr<unwindstack::Memory> process_memory_;
  std::unique_ptr<unwindstack::JitDebug> jit_debug_;
#ifndef NO_LIBDEXFILE
  std::mutex dex_lock_;
  std::unordered_map<uint64_t, UnwindDexFile*> dex_files_;
#if !defined(NO_LIBDEXFILE_SUPPORT)
  std::unique_ptr<unwindstack::DexFiles> dex_files_;
#endif
};

+64 −0
Original line number Diff line number Diff line
@@ -80,7 +80,13 @@ cc_library {
        host: {
            cflags: ["-O0", "-g"],
        },
        vendor: {
            cflags: ["-DNO_LIBDEXFILE_SUPPORT"],
            exclude_static_libs: ["libunwindstack_dex"],
            exclude_shared_libs: ["libdexfile"],
        },
    },
    whole_static_libs: ["libunwindstack_dex"],

    arch: {
        x86: {
@@ -99,14 +105,70 @@ cc_library {

    shared_libs: [
        "libbase",
        "libdexfile",
        "liblog",
        "liblzma",
    ],
}

// Isolate the dex file processing into a separate library. Currently,
// it is necessary to add art include directories directly, which also
// adds the art elf.h file in the include path, overriding the system one.
// Work to isolate libdexfile is b/72216369.
cc_library_static {
    name: "libunwindstack_dex",
    vendor_available: false,
    defaults: ["libunwindstack_flags"],

    cflags: [
        "-Wexit-time-destructors",
    ],

    srcs: [
        "DexFile.cpp",
        "DexFiles.cpp",
    ],

    shared_libs: [
        "libbase",
        "libdexfile",
    ],
    local_include_dirs: ["include"],
    allow_undefined_symbols: true,

    // libdexfile will eventually properly export headers, for now include
    // these directly.
    include_dirs: [
        "art/runtime",
    ],
}

//-------------------------------------------------------------------------
// Unit Tests
//-------------------------------------------------------------------------
cc_test_library {
    name: "libunwindstack_dex_test",
    vendor_available: false,
    defaults: ["libunwindstack_flags"],

    srcs: [
        "tests/DexFileTest.cpp",
    ],
    local_include_dirs: ["include"],
    allow_undefined_symbols: true,

    shared_libs: [
        "libbase",
        "libunwindstack",
    ],

    // libdexfile will eventually properly export headers, for now include
    // these directly.
    include_dirs: [
        "art/runtime",
    ],
}

cc_test {
    name: "libunwindstack_test",
    defaults: ["libunwindstack_flags"],
@@ -168,6 +230,8 @@ cc_test {
        "libgmock",
    ],

    whole_static_libs: ["libunwindstack_dex_test"],

    data: [
        "tests/files/elf32.xz",
        "tests/files/elf64.xz",
Loading