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

Commit 5cb792d6 authored by Christopher Ferris's avatar Christopher Ferris Committed by android-build-merger
Browse files

Merge "Create lookup table of DEX symbols."

am: d1a1202e

Change-Id: I585af2d897292c4c6aa9dfc86acc0dbb060b890e
parents c6e9a94e d1a1202e
Loading
Loading
Loading
Loading
+47 −9
Original line number Diff line number Diff line
@@ -68,17 +68,51 @@ bool DexFile::GetMethodInformation(uint64_t dex_offset, std::string* method_name
    return false;  // The DEX offset is not within the bytecode of this dex file.
  }

  for (uint32_t i = 0; i < dex_file_->NumClassDefs(); ++i) {
    const art::DexFile::ClassDef& class_def = dex_file_->GetClassDef(i);
  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_++) {
    const art::DexFile::ClassDef& class_def = dex_file_->GetClassDef(class_def_index_);
    const uint8_t* class_data = dex_file_->GetClassData(class_def);
    if (class_data == nullptr) {
      continue;
    }
    for (art::ClassDataItemIterator it(*dex_file_.get(), class_data); it.HasNext(); it.Next()) {
      if (!it.IsAtMethod()) {

    if (class_it_.get() == nullptr || !class_it_->HasNext()) {
      class_it_.reset(new art::ClassDataItemIterator(*dex_file_.get(), class_data));
    }

    for (; class_it_->HasNext(); class_it_->Next()) {
      if (!class_it_->IsAtMethod()) {
        continue;
      }
      const art::DexFile::CodeItem* code_item = it.GetMethodCodeItem();
      const art::DexFile::CodeItem* code_item = class_it_->GetMethodCodeItem();
      if (code_item == nullptr) {
        continue;
      }
@@ -87,11 +121,15 @@ bool DexFile::GetMethodInformation(uint64_t dex_offset, std::string* method_name
        continue;
      }

      uint64_t offset = reinterpret_cast<const uint8_t*>(code.Insns()) - dex_file_->Begin();
      size_t size = code.InsnsSizeInCodeUnits() * sizeof(uint16_t);
      if (offset <= dex_offset && dex_offset < offset + size) {
        *method_name = dex_file_->PrettyMethod(it.GetMemberIndex(), false);
      uint32_t offset = reinterpret_cast<const uint8_t*>(code.Insns()) - dex_file_->Begin();
      uint32_t offset_end = offset + code.InsnsSizeInCodeUnits() * sizeof(uint16_t);
      uint32_t member_index = class_it_->GetMemberIndex();
      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;
        // Move past this element.
        class_it_->Next();
        return true;
      }
    }
+8 −0
Original line number Diff line number Diff line
@@ -19,8 +19,10 @@

#include <stdint.h>

#include <map>
#include <memory>
#include <string>
#include <utility>
#include <vector>

#include <dex/dex_file-inl.h>
@@ -37,7 +39,13 @@ class DexFile {
  static 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;
  std::unique_ptr<art::ClassDataItemIterator> class_it_;
};

class DexFileFromFile : public DexFile {
+33 −6
Original line number Diff line number Diff line
@@ -206,15 +206,42 @@ TEST(DexFileTest, get_method) {

  std::string method;
  uint64_t method_offset;
  dex_file->GetMethodInformation(0x102, &method, &method_offset);
  ASSERT_TRUE(dex_file->GetMethodInformation(0x102, &method, &method_offset));
  EXPECT_EQ("Main.<init>", method);
  EXPECT_EQ(2U, method_offset);

  method = "not_in_a_method";
  method_offset = 0x123;
  dex_file->GetMethodInformation(0x100000, &method, &method_offset);
  EXPECT_EQ("not_in_a_method", method);
  EXPECT_EQ(0x123U, method_offset);
  ASSERT_TRUE(dex_file->GetMethodInformation(0x118, &method, &method_offset));
  EXPECT_EQ("Main.main", method);
  EXPECT_EQ(0U, method_offset);

  // Make sure that any data that is cached is still retrievable.
  ASSERT_TRUE(dex_file->GetMethodInformation(0x104, &method, &method_offset));
  EXPECT_EQ("Main.<init>", method);
  EXPECT_EQ(4U, method_offset);

  ASSERT_TRUE(dex_file->GetMethodInformation(0x119, &method, &method_offset));
  EXPECT_EQ("Main.main", method);
  EXPECT_EQ(1U, method_offset);
}

TEST(DexFileTest, get_method_empty) {
  MemoryFake memory;
  memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
  MapInfo info(0x100, 0x10000, 0x200, 0x5, "");
  std::unique_ptr<DexFile> dex_file(DexFile::Create(0x4000, &memory, &info));
  ASSERT_TRUE(dex_file != nullptr);

  std::string method;
  uint64_t method_offset;
  EXPECT_FALSE(dex_file->GetMethodInformation(0x100000, &method, &method_offset));

  EXPECT_FALSE(dex_file->GetMethodInformation(0x98, &method, &method_offset));

  // Make sure that once the whole dex file has been cached, no problems occur.
  EXPECT_FALSE(dex_file->GetMethodInformation(0x98, &method, &method_offset));

  // Choose a value that is in the cached map, but not in a valid method.
  EXPECT_FALSE(dex_file->GetMethodInformation(0x110, &method, &method_offset));
}

}  // namespace unwindstack