summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristopher Ferris2018-07-26 15:01:15 -0500
committerGerrit Code Review2018-07-26 15:01:15 -0500
commitd1a1202eb7435ff36180bcb6ab39f0861f608fd8 (patch)
treeca6c04dd69149c5db42a7dc227c501753847f96c
parentd6f97d67e094e8962f231ab290bd4468363fd8b3 (diff)
parent02d0f7962d17fc05efdebb947e908817d304673d (diff)
downloadplatform-system-core-d1a1202eb7435ff36180bcb6ab39f0861f608fd8.tar.gz
platform-system-core-d1a1202eb7435ff36180bcb6ab39f0861f608fd8.tar.xz
platform-system-core-d1a1202eb7435ff36180bcb6ab39f0861f608fd8.zip
Merge "Create lookup table of DEX symbols."
-rw-r--r--libunwindstack/DexFile.cpp56
-rw-r--r--libunwindstack/DexFile.h8
-rw-r--r--libunwindstack/tests/DexFileTest.cpp39
3 files changed, 88 insertions, 15 deletions
diff --git a/libunwindstack/DexFile.cpp b/libunwindstack/DexFile.cpp
index b18b0ce3d..3d982f6e9 100644
--- a/libunwindstack/DexFile.cpp
+++ b/libunwindstack/DexFile.cpp
@@ -68,17 +68,51 @@ bool DexFile::GetMethodInformation(uint64_t dex_offset, std::string* method_name
68 return false; // The DEX offset is not within the bytecode of this dex file. 68 return false; // The DEX offset is not within the bytecode of this dex file.
69 } 69 }
70 70
71 for (uint32_t i = 0; i < dex_file_->NumClassDefs(); ++i) { 71 if (dex_file_->IsCompactDexFile()) {
72 const art::DexFile::ClassDef& class_def = dex_file_->GetClassDef(i); 72 // The data section of compact dex files might be shared.
73 // Check the subrange unique to this compact dex.
74 const auto& cdex_header = dex_file_->AsCompactDexFile()->GetHeader();
75 uint32_t begin = cdex_header.data_off_ + cdex_header.OwnedDataBegin();
76 uint32_t end = cdex_header.data_off_ + cdex_header.OwnedDataEnd();
77 if (dex_offset < begin || dex_offset >= end) {
78 return false; // The DEX offset is not within the bytecode of this dex file.
79 }
80 }
81
82 // The method data is cached in a std::map indexed by method end offset and
83 // contains the start offset and the method member index.
84 // Only cache the method data as it is searched. Do not read the entire
85 // set of method data into the cache at once.
86 // This is done because many unwinds only find a single frame with dex file
87 // info, so reading the entire method data is wasteful. However, still cache
88 // the data so that anything doing multiple unwinds will have this data
89 // cached for future use.
90
91 // First look in the method cache.
92 auto entry = method_cache_.upper_bound(dex_offset);
93 if (entry != method_cache_.end() && dex_offset >= entry->second.first) {
94 *method_name = dex_file_->PrettyMethod(entry->second.second, false);
95 *method_offset = dex_offset - entry->second.first;
96 return true;
97 }
98
99 // Check the methods we haven't cached.
100 for (; class_def_index_ < dex_file_->NumClassDefs(); class_def_index_++) {
101 const art::DexFile::ClassDef& class_def = dex_file_->GetClassDef(class_def_index_);
73 const uint8_t* class_data = dex_file_->GetClassData(class_def); 102 const uint8_t* class_data = dex_file_->GetClassData(class_def);
74 if (class_data == nullptr) { 103 if (class_data == nullptr) {
75 continue; 104 continue;
76 } 105 }
77 for (art::ClassDataItemIterator it(*dex_file_.get(), class_data); it.HasNext(); it.Next()) { 106
78 if (!it.IsAtMethod()) { 107 if (class_it_.get() == nullptr || !class_it_->HasNext()) {
108 class_it_.reset(new art::ClassDataItemIterator(*dex_file_.get(), class_data));
109 }
110
111 for (; class_it_->HasNext(); class_it_->Next()) {
112 if (!class_it_->IsAtMethod()) {
79 continue; 113 continue;
80 } 114 }
81 const art::DexFile::CodeItem* code_item = it.GetMethodCodeItem(); 115 const art::DexFile::CodeItem* code_item = class_it_->GetMethodCodeItem();
82 if (code_item == nullptr) { 116 if (code_item == nullptr) {
83 continue; 117 continue;
84 } 118 }
@@ -87,11 +121,15 @@ bool DexFile::GetMethodInformation(uint64_t dex_offset, std::string* method_name
87 continue; 121 continue;
88 } 122 }
89 123
90 uint64_t offset = reinterpret_cast<const uint8_t*>(code.Insns()) - dex_file_->Begin(); 124 uint32_t offset = reinterpret_cast<const uint8_t*>(code.Insns()) - dex_file_->Begin();
91 size_t size = code.InsnsSizeInCodeUnits() * sizeof(uint16_t); 125 uint32_t offset_end = offset + code.InsnsSizeInCodeUnits() * sizeof(uint16_t);
92 if (offset <= dex_offset && dex_offset < offset + size) { 126 uint32_t member_index = class_it_->GetMemberIndex();
93 *method_name = dex_file_->PrettyMethod(it.GetMemberIndex(), false); 127 method_cache_[offset_end] = std::make_pair(offset, member_index);
128 if (offset <= dex_offset && dex_offset < offset_end) {
129 *method_name = dex_file_->PrettyMethod(member_index, false);
94 *method_offset = dex_offset - offset; 130 *method_offset = dex_offset - offset;
131 // Move past this element.
132 class_it_->Next();
95 return true; 133 return true;
96 } 134 }
97 } 135 }
diff --git a/libunwindstack/DexFile.h b/libunwindstack/DexFile.h
index 3ce2f1edd..508692d33 100644
--- a/libunwindstack/DexFile.h
+++ b/libunwindstack/DexFile.h
@@ -19,8 +19,10 @@
19 19
20#include <stdint.h> 20#include <stdint.h>
21 21
22#include <map>
22#include <memory> 23#include <memory>
23#include <string> 24#include <string>
25#include <utility>
24#include <vector> 26#include <vector>
25 27
26#include <dex/dex_file-inl.h> 28#include <dex/dex_file-inl.h>
@@ -37,7 +39,13 @@ class DexFile {
37 static DexFile* Create(uint64_t dex_file_offset_in_memory, Memory* memory, MapInfo* info); 39 static DexFile* Create(uint64_t dex_file_offset_in_memory, Memory* memory, MapInfo* info);
38 40
39 protected: 41 protected:
42 void Init();
43
40 std::unique_ptr<const art::DexFile> dex_file_; 44 std::unique_ptr<const art::DexFile> dex_file_;
45 std::map<uint32_t, std::pair<uint64_t, uint32_t>> method_cache_; // dex offset to method index.
46
47 uint32_t class_def_index_ = 0;
48 std::unique_ptr<art::ClassDataItemIterator> class_it_;
41}; 49};
42 50
43class DexFileFromFile : public DexFile { 51class DexFileFromFile : public DexFile {
diff --git a/libunwindstack/tests/DexFileTest.cpp b/libunwindstack/tests/DexFileTest.cpp
index 0b02c5bf1..4dd8cb046 100644
--- a/libunwindstack/tests/DexFileTest.cpp
+++ b/libunwindstack/tests/DexFileTest.cpp
@@ -206,15 +206,42 @@ TEST(DexFileTest, get_method) {
206 206
207 std::string method; 207 std::string method;
208 uint64_t method_offset; 208 uint64_t method_offset;
209 dex_file->GetMethodInformation(0x102, &method, &method_offset); 209 ASSERT_TRUE(dex_file->GetMethodInformation(0x102, &method, &method_offset));
210 EXPECT_EQ("Main.<init>", method); 210 EXPECT_EQ("Main.<init>", method);
211 EXPECT_EQ(2U, method_offset); 211 EXPECT_EQ(2U, method_offset);
212 212
213 method = "not_in_a_method"; 213 ASSERT_TRUE(dex_file->GetMethodInformation(0x118, &method, &method_offset));
214 method_offset = 0x123; 214 EXPECT_EQ("Main.main", method);
215 dex_file->GetMethodInformation(0x100000, &method, &method_offset); 215 EXPECT_EQ(0U, method_offset);
216 EXPECT_EQ("not_in_a_method", method); 216
217 EXPECT_EQ(0x123U, method_offset); 217 // Make sure that any data that is cached is still retrievable.
218 ASSERT_TRUE(dex_file->GetMethodInformation(0x104, &method, &method_offset));
219 EXPECT_EQ("Main.<init>", method);
220 EXPECT_EQ(4U, method_offset);
221
222 ASSERT_TRUE(dex_file->GetMethodInformation(0x119, &method, &method_offset));
223 EXPECT_EQ("Main.main", method);
224 EXPECT_EQ(1U, method_offset);
225}
226
227TEST(DexFileTest, get_method_empty) {
228 MemoryFake memory;
229 memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
230 MapInfo info(0x100, 0x10000, 0x200, 0x5, "");
231 std::unique_ptr<DexFile> dex_file(DexFile::Create(0x4000, &memory, &info));
232 ASSERT_TRUE(dex_file != nullptr);
233
234 std::string method;
235 uint64_t method_offset;
236 EXPECT_FALSE(dex_file->GetMethodInformation(0x100000, &method, &method_offset));
237
238 EXPECT_FALSE(dex_file->GetMethodInformation(0x98, &method, &method_offset));
239
240 // Make sure that once the whole dex file has been cached, no problems occur.
241 EXPECT_FALSE(dex_file->GetMethodInformation(0x98, &method, &method_offset));
242
243 // Choose a value that is in the cached map, but not in a valid method.
244 EXPECT_FALSE(dex_file->GetMethodInformation(0x110, &method, &method_offset));
218} 245}
219 246
220} // namespace unwindstack 247} // namespace unwindstack