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

Commit 1d6969cc authored by Martin Stjernholm's avatar Martin Stjernholm Committed by Gerrit Code Review
Browse files

Merge "Use libdexfile external API in libunwindstack."

parents 42c9e7e3 444e23d2
Loading
Loading
Loading
Loading
+21 −2
Original line number Diff line number Diff line
@@ -116,14 +116,21 @@ cc_library_static {
        "libdebuggerd",
        "libbacktrace",
        "libunwindstack",
        "libdexfile",
        "libdexfile",  // libunwindstack dependency
        "libdexfile_external",  // libunwindstack dependency
        "libdexfile_support",  // libunwindstack dependency
        "liblzma",
        "libcutils",
    ],
    target: {
        recovery: {
            cflags: ["-DNO_LIBDEXFILE_SUPPORT"],
            exclude_static_libs: ["libdexfile"],
            exclude_static_libs: [
                "libartbase",
                "libdexfile",
                "libdexfile_external",
                "libdexfile_support",
            ],
        },
    },

@@ -170,12 +177,22 @@ cc_library_static {

    static_libs: [
        "libbacktrace",
        "libdexfile_external",  // libunwindstack dependency
        "libdexfile_support",  // libunwindstack dependency
        "libunwindstack",
        "liblzma",
        "libbase",
        "libcutils",
        "liblog",
    ],
    target: {
        recovery: {
            exclude_static_libs: [
                "libdexfile_external",
                "libdexfile_support",
            ],
        },
    },
}

cc_test {
@@ -216,6 +233,8 @@ cc_test {

    static_libs: [
        "libdebuggerd",
        "libdexfile_external",  // libunwindstack dependency
        "libdexfile_support",  // libunwindstack dependency
        "libunwindstack",
    ],

+11 −3
Original line number Diff line number Diff line
@@ -94,7 +94,10 @@ cc_library {
                "DexFile.cpp",
                "DexFiles.cpp",
            ],
            exclude_shared_libs: ["libdexfile"],
            exclude_shared_libs: [
                "libdexfile_external",
                "libdexfile_support",
            ],
        },
        recovery: {
            cflags: ["-DNO_LIBDEXFILE_SUPPORT"],
@@ -102,7 +105,10 @@ cc_library {
                "DexFile.cpp",
                "DexFiles.cpp",
            ],
            exclude_shared_libs: ["libdexfile"],
            exclude_shared_libs: [
                "libdexfile_external",
                "libdexfile_support",
            ],
        },
    },

@@ -127,7 +133,8 @@ cc_library {

    shared_libs: [
        "libbase",
        "libdexfile",
        "libdexfile_external",
        "libdexfile_support",
        "liblog",
        "liblzma",
    ],
@@ -215,6 +222,7 @@ cc_test {
        "liblzma",
        "libunwindstack",
        "libdexfile",
        "libdexfile_support",
    ],

    static_libs: [
+42 −146
Original line number Diff line number Diff line
@@ -23,13 +23,7 @@
#include <memory>

#include <android-base/unique_fd.h>

#include <dex/class_accessor-inl.h>
#include <dex/code_item_accessors-inl.h>
#include <dex/compact_dex_file.h>
#include <dex/dex_file-inl.h>
#include <dex/dex_file_loader.h>
#include <dex/standard_dex_file.h>
#include <art_api/ext_dex_file.h>

#include <unwindstack/MapInfo.h>
#include <unwindstack/Memory.h>
@@ -38,169 +32,71 @@

namespace unwindstack {

DexFile* DexFile::Create(uint64_t dex_file_offset_in_memory, Memory* memory, MapInfo* info) {
std::unique_ptr<DexFile> DexFile::Create(uint64_t dex_file_offset_in_memory, Memory* memory,
                                         MapInfo* info) {
  if (!info->name.empty()) {
    std::unique_ptr<DexFileFromFile> dex_file(new DexFileFromFile);
    if (dex_file->Open(dex_file_offset_in_memory - info->start + info->offset, info->name)) {
      return dex_file.release();
    }
  }

  std::unique_ptr<DexFileFromMemory> dex_file(new DexFileFromMemory);
  if (dex_file->Open(dex_file_offset_in_memory, memory)) {
    return dex_file.release();
  }
  return nullptr;
    std::unique_ptr<DexFile> dex_file =
        DexFileFromFile::Create(dex_file_offset_in_memory - info->start + info->offset, info->name);
    if (dex_file) {
      return dex_file;
    }

DexFileFromFile::~DexFileFromFile() {
  if (size_ != 0) {
    munmap(mapped_memory_, size_);
  }
  return DexFileFromMemory::Create(dex_file_offset_in_memory, memory, info->name);
}

bool DexFile::GetMethodInformation(uint64_t dex_offset, std::string* method_name,
                                   uint64_t* method_offset) {
  if (dex_file_ == nullptr) {
  art_api::dex::MethodInfo method_info = GetMethodInfoForOffset(dex_offset);
  if (method_info.offset == 0) {
    return false;
  }

  if (!dex_file_->IsInDataSection(dex_file_->Begin() + dex_offset)) {
    return false;  // The DEX offset is not within the bytecode of this dex file.
  }

  if (dex_file_->IsCompactDexFile()) {
    // The data section of compact dex files might be shared.
    // Check the subrange unique to this compact dex.
    const auto& cdex_header = dex_file_->AsCompactDexFile()->GetHeader();
    uint32_t begin = cdex_header.data_off_ + cdex_header.OwnedDataBegin();
    uint32_t end = cdex_header.data_off_ + cdex_header.OwnedDataEnd();
    if (dex_offset < begin || dex_offset >= end) {
      return false;  // The DEX offset is not within the bytecode of this dex file.
    }
  }

  // The method data is cached in a std::map indexed by method end offset and
  // contains the start offset and the method member index.
  // Only cache the method data as it is searched. Do not read the entire
  // set of method data into the cache at once.
  // This is done because many unwinds only find a single frame with dex file
  // info, so reading the entire method data is wasteful. However, still cache
  // the data so that anything doing multiple unwinds will have this data
  // cached for future use.

  // First look in the method cache.
  auto entry = method_cache_.upper_bound(dex_offset);
  if (entry != method_cache_.end() && dex_offset >= entry->second.first) {
    *method_name = dex_file_->PrettyMethod(entry->second.second, false);
    *method_offset = dex_offset - entry->second.first;
    return true;
  }

  // Check the methods we haven't cached.
  for (; class_def_index_ < dex_file_->NumClassDefs(); class_def_index_++) {
    art::ClassAccessor accessor(*dex_file_, dex_file_->GetClassDef(class_def_index_));

    for (const art::ClassAccessor::Method& method : accessor.GetMethods()) {
      art::CodeItemInstructionAccessor code = method.GetInstructions();
      if (!code.HasCodeItem()) {
        continue;
      }
      uint32_t offset = reinterpret_cast<const uint8_t*>(code.Insns()) - dex_file_->Begin();
      uint32_t offset_end = offset + code.InsnsSizeInBytes();
      uint32_t member_index = method.GetIndex();
      method_cache_[offset_end] = std::make_pair(offset, member_index);
      if (offset <= dex_offset && dex_offset < offset_end) {
        *method_name = dex_file_->PrettyMethod(member_index, false);
        *method_offset = dex_offset - offset;
  *method_name = method_info.name;
  *method_offset = dex_offset - method_info.offset;
  return true;
}
    }
  }
  return false;
}

bool DexFileFromFile::Open(uint64_t dex_file_offset_in_file, const std::string& file) {
std::unique_ptr<DexFileFromFile> DexFileFromFile::Create(uint64_t dex_file_offset_in_file,
                                                         const std::string& file) {
  android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(file.c_str(), O_RDONLY | O_CLOEXEC)));
  if (fd == -1) {
    return false;
  }
  struct stat buf;
  if (fstat(fd, &buf) == -1) {
    return false;
  }
  uint64_t length;
  if (buf.st_size < 0 ||
      __builtin_add_overflow(dex_file_offset_in_file, sizeof(art::DexFile::Header), &length) ||
      static_cast<uint64_t>(buf.st_size) < length) {
    return false;
    return nullptr;
  }

  mapped_memory_ = mmap(nullptr, buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
  if (mapped_memory_ == MAP_FAILED) {
    return false;
  std::string error_msg;
  std::unique_ptr<art_api::dex::DexFile> art_dex_file =
      OpenFromFd(fd, dex_file_offset_in_file, file, &error_msg);
  if (art_dex_file == nullptr) {
    return nullptr;
  }
  size_ = buf.st_size;

  uint8_t* memory = reinterpret_cast<uint8_t*>(mapped_memory_);

  art::DexFile::Header* header =
      reinterpret_cast<art::DexFile::Header*>(&memory[dex_file_offset_in_file]);
  if (!art::StandardDexFile::IsMagicValid(header->magic_) &&
      !art::CompactDexFile::IsMagicValid(header->magic_)) {
    return false;
  return std::unique_ptr<DexFileFromFile>(new DexFileFromFile(std::move(*art_dex_file.release())));
}

  if (__builtin_add_overflow(dex_file_offset_in_file, header->file_size_, &length) ||
      static_cast<uint64_t>(buf.st_size) < length) {
    return false;
  }
std::unique_ptr<DexFileFromMemory> DexFileFromMemory::Create(uint64_t dex_file_offset_in_memory,
                                                             Memory* memory,
                                                             const std::string& name) {
  std::vector<uint8_t> backing_memory;

  art::DexFileLoader loader;
  for (size_t size = 0;;) {
    std::string error_msg;
  auto dex = loader.Open(&memory[dex_file_offset_in_file], header->file_size_, "", 0, nullptr,
                         false, false, &error_msg);
  dex_file_.reset(dex.release());
  return dex_file_ != nullptr;
}
    std::unique_ptr<art_api::dex::DexFile> art_dex_file =
        OpenFromMemory(backing_memory.data(), &size, name, &error_msg);

bool DexFileFromMemory::Open(uint64_t dex_file_offset_in_memory, Memory* memory) {
  memory_.resize(sizeof(art::DexFile::Header));
  if (!memory->ReadFully(dex_file_offset_in_memory, memory_.data(), memory_.size())) {
    return false;
    if (art_dex_file != nullptr) {
      return std::unique_ptr<DexFileFromMemory>(
          new DexFileFromMemory(std::move(*art_dex_file.release()), std::move(backing_memory)));
    }

  art::DexFile::Header* header = reinterpret_cast<art::DexFile::Header*>(memory_.data());
  uint32_t file_size = header->file_size_;
  if (art::CompactDexFile::IsMagicValid(header->magic_)) {
    // Compact dex file store data section separately so that it can be shared.
    // Therefore we need to extend the read memory range to include it.
    // TODO: This might be wasteful as we might read data in between as well.
    //       In practice, this should be fine, as such sharing only happens on disk.
    uint32_t computed_file_size;
    if (__builtin_add_overflow(header->data_off_, header->data_size_, &computed_file_size)) {
      return false;
    }
    if (computed_file_size > file_size) {
      file_size = computed_file_size;
    }
  } else if (!art::StandardDexFile::IsMagicValid(header->magic_)) {
    return false;
    if (!error_msg.empty()) {
      return nullptr;
    }

  memory_.resize(file_size);
  if (!memory->ReadFully(dex_file_offset_in_memory, memory_.data(), memory_.size())) {
    return false;
    backing_memory.resize(size);
    if (!memory->ReadFully(dex_file_offset_in_memory, backing_memory.data(),
                           backing_memory.size())) {
      return nullptr;
    }
  }

  header = reinterpret_cast<art::DexFile::Header*>(memory_.data());

  art::DexFileLoader loader;
  std::string error_msg;
  auto dex =
      loader.Open(memory_.data(), header->file_size_, "", 0, nullptr, false, false, &error_msg);
  dex_file_.reset(dex.release());
  return dex_file_ != nullptr;
}

}  // namespace unwindstack
+13 −20
Original line number Diff line number Diff line
@@ -25,48 +25,41 @@
#include <utility>
#include <vector>

#include <dex/dex_file-inl.h>
#include <art_api/ext_dex_file.h>

namespace unwindstack {

class DexFile {
class DexFile : protected art_api::dex::DexFile {
 public:
  DexFile() = default;
  virtual ~DexFile() = default;

  bool GetMethodInformation(uint64_t dex_offset, std::string* method_name, uint64_t* method_offset);

  static DexFile* Create(uint64_t dex_file_offset_in_memory, Memory* memory, MapInfo* info);
  static std::unique_ptr<DexFile> Create(uint64_t dex_file_offset_in_memory, Memory* memory,
                                         MapInfo* info);

 protected:
  void Init();

  std::unique_ptr<const art::DexFile> dex_file_;
  std::map<uint32_t, std::pair<uint64_t, uint32_t>> method_cache_;  // dex offset to method index.

  uint32_t class_def_index_ = 0;
  DexFile(art_api::dex::DexFile&& art_dex_file) : art_api::dex::DexFile(std::move(art_dex_file)) {}
};

class DexFileFromFile : public DexFile {
 public:
  DexFileFromFile() = default;
  virtual ~DexFileFromFile();

  bool Open(uint64_t dex_file_offset_in_file, const std::string& name);
  static std::unique_ptr<DexFileFromFile> Create(uint64_t dex_file_offset_in_file,
                                                 const std::string& file);

 private:
  void* mapped_memory_ = nullptr;
  size_t size_ = 0;
  DexFileFromFile(art_api::dex::DexFile&& art_dex_file) : DexFile(std::move(art_dex_file)) {}
};

class DexFileFromMemory : public DexFile {
 public:
  DexFileFromMemory() = default;
  virtual ~DexFileFromMemory() = default;

  bool Open(uint64_t dex_file_offset_in_memory, Memory* memory);
  static std::unique_ptr<DexFileFromMemory> Create(uint64_t dex_file_offset_in_memory,
                                                   Memory* memory, const std::string& name);

 private:
  DexFileFromMemory(art_api::dex::DexFile&& art_dex_file, std::vector<uint8_t>&& memory)
      : DexFile(std::move(art_dex_file)), memory_(std::move(memory)) {}

  std::vector<uint8_t> memory_;
};

+5 −8
Original line number Diff line number Diff line
@@ -48,11 +48,7 @@ DexFiles::DexFiles(std::shared_ptr<Memory>& memory) : Global(memory) {}
DexFiles::DexFiles(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs)
    : Global(memory, search_libs) {}

DexFiles::~DexFiles() {
  for (auto& entry : files_) {
    delete entry.second;
  }
}
DexFiles::~DexFiles() {}

void DexFiles::ProcessArch() {
  switch (arch()) {
@@ -137,10 +133,11 @@ DexFile* DexFiles::GetDexFile(uint64_t dex_file_offset, MapInfo* info) {
  DexFile* dex_file;
  auto entry = files_.find(dex_file_offset);
  if (entry == files_.end()) {
    dex_file = DexFile::Create(dex_file_offset, memory_.get(), info);
    files_[dex_file_offset] = dex_file;
    std::unique_ptr<DexFile> new_dex_file = DexFile::Create(dex_file_offset, memory_.get(), info);
    dex_file = new_dex_file.get();
    files_[dex_file_offset] = std::move(new_dex_file);
  } else {
    dex_file = entry->second;
    dex_file = entry->second.get();
  }
  return dex_file;
}
Loading