1 /*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <elf.h>
18 #include <string.h>
19
20 #include <memory>
21 #include <vector>
22
23 #include <gtest/gtest.h>
24
25 #include <unwindstack/DexFiles.h>
26 #include <unwindstack/Elf.h>
27 #include <unwindstack/MapInfo.h>
28 #include <unwindstack/Maps.h>
29 #include <unwindstack/Memory.h>
30
31 #include "DexFile.h"
32 #include "DexFileData.h"
33 #include "ElfFake.h"
34 #include "utils/MemoryFake.h"
35
36 namespace unwindstack {
37
38 class DexFilesTest : public ::testing::Test {
39 protected:
CreateFakeElf(MapInfo * map_info,uint64_t global_offset,uint64_t data_offset,uint64_t data_vaddr,uint64_t data_size)40 void CreateFakeElf(MapInfo* map_info, uint64_t global_offset, uint64_t data_offset,
41 uint64_t data_vaddr, uint64_t data_size) {
42 std::shared_ptr<Memory> fake_memory(new MemoryFake);
43 ElfFake* elf = new ElfFake(fake_memory);
44 elf->FakeSetValid(true);
45 ElfInterfaceFake* interface = new ElfInterfaceFake(fake_memory);
46 elf->FakeSetInterface(interface);
47
48 interface->FakeSetGlobalVariable("__dex_debug_descriptor", global_offset);
49 interface->FakeSetDataOffset(data_offset);
50 interface->FakeSetDataVaddrStart(data_vaddr);
51 interface->FakeSetDataVaddrEnd(data_vaddr + data_size);
52 map_info->set_elf(elf);
53 }
54
Init(ArchEnum arch)55 void Init(ArchEnum arch) {
56 dex_files_ = CreateDexFiles(arch, process_memory_);
57
58 maps_.reset(
59 new BufferMaps("1000-4000 ---s 00000000 00:00 0 /fake/elf\n"
60 "4000-6000 r--s 00000000 00:00 0 /fake/elf\n"
61 "6000-8000 -wxs 00002000 00:00 0 /fake/elf\n"
62 "a000-c000 r--p 00000000 00:00 0 /fake/elf2\n"
63 "c000-f000 rw-p 00002000 00:00 0 /fake/elf2\n"
64 "f000-11000 r--p 00000000 00:00 0 /fake/elf3\n"
65 "100000-110000 rw-p 00f1000 00:00 0 /fake/elf3\n"
66 "200000-210000 rw-p 0002000 00:00 0 /fake/elf3\n"
67 "300000-400000 rw-p 0003000 00:00 0 /fake/elf3\n"
68 "500000-501000 r--p 0000000 00:00 0 /fake/elf4\n"
69 "501000-502000 ---p 0000000 00:00 0\n"
70 "503000-510000 rw-p 0003000 00:00 0 /fake/elf4\n"
71 "510000-520000 rw-p 0010000 00:00 0 /fake/elf4\n"
72 "600000-601000 r--p 0000000 00:00 0 /fake/elf5\n"
73 "601000-602000 ---p 0000000 00:00 0 [page size compat]\n"
74 "603000-610000 rw-p 0003000 00:00 0 /fake/elf5\n"));
75 ASSERT_TRUE(maps_->Parse());
76
77 // Global variable in a section that is not readable.
78 MapInfo* map_info = maps_->Get(kMapGlobalNonReadable).get();
79 ASSERT_TRUE(map_info != nullptr);
80 CreateFakeElf(map_info, 0x2800, 0x2000, 0x2000, 0x3000);
81
82 // Global variable not set by default.
83 map_info = maps_->Get(kMapGlobalSetToZero).get();
84 ASSERT_TRUE(map_info != nullptr);
85 CreateFakeElf(map_info, 0x2800, 0x2000, 0x2000, 0x3000);
86
87 // Global variable set in this map.
88 map_info = maps_->Get(kMapGlobal).get();
89 ASSERT_TRUE(map_info != nullptr);
90 CreateFakeElf(map_info, 0xf1800, 0xf1000, 0xf1000, 0x10000);
91
92 // Global variable set in this map, but there is an empty map before rw map.
93 map_info = maps_->Get(kMapGlobalAfterEmpty).get();
94 ASSERT_TRUE(map_info != nullptr);
95 CreateFakeElf(map_info, 0x3800, 0x3000, 0x3000, 0xd000);
96
97 // Global variable set in this map, but there is a page size compat map before rw map.
98 map_info = maps_->Get(kMapGlobalAfterPageSizeCompat).get();
99 ASSERT_TRUE(map_info != nullptr);
100 CreateFakeElf(map_info, 0x3800, 0x3000, 0x3000, 0xd000);
101 }
102
SetUp()103 void SetUp() override {
104 memory_ = new MemoryFake;
105 process_memory_.reset(memory_);
106
107 Init(ARCH_ARM);
108 }
109
110 void WriteDescriptor32(uint64_t addr, uint32_t head);
111 void WriteDescriptor64(uint64_t addr, uint64_t head);
112 void WriteEntry32(uint64_t entry_addr, uint32_t next, uint32_t prev, uint32_t dex_file,
113 uint64_t dex_size);
114 void WriteEntry64(uint64_t entry_addr, uint64_t next, uint64_t prev, uint64_t dex_file,
115 uint64_t dex_size);
116 void WriteDex(uint64_t dex_file);
117
118 static constexpr size_t kMapGlobalNonReadable = 2;
119 static constexpr size_t kMapGlobalSetToZero = 3;
120 static constexpr size_t kMapGlobal = 5;
121 static constexpr size_t kMapGlobalRw = 6;
122 static constexpr size_t kMapDexFileEntries = 7;
123 static constexpr size_t kMapDexFiles = 8;
124 static constexpr size_t kMapGlobalAfterEmpty = 9;
125 static constexpr size_t kMapDexFilesAfterEmpty = 12;
126 static constexpr size_t kMapGlobalAfterPageSizeCompat = 13;
127
128 std::shared_ptr<Memory> process_memory_;
129 MemoryFake* memory_;
130 std::unique_ptr<DexFiles> dex_files_;
131 std::unique_ptr<BufferMaps> maps_;
132 };
133
WriteDescriptor32(uint64_t addr,uint32_t entry)134 void DexFilesTest::WriteDescriptor32(uint64_t addr, uint32_t entry) {
135 // uint32_t version
136 memory_->SetData32(addr, 1);
137 // uint32_t action_flag
138 memory_->SetData32(addr + 4, 0);
139 // uint32_t relevant_entry
140 memory_->SetData32(addr + 8, 0);
141 // uint32_t first_entry
142 memory_->SetData32(addr + 12, entry);
143 }
144
WriteDescriptor64(uint64_t addr,uint64_t entry)145 void DexFilesTest::WriteDescriptor64(uint64_t addr, uint64_t entry) {
146 // uint32_t version
147 memory_->SetData32(addr, 1);
148 // uint32_t action_flag
149 memory_->SetData32(addr + 4, 0);
150 // uint64_t relevant_entry
151 memory_->SetData64(addr + 8, 0);
152 // uint64_t first_entry
153 memory_->SetData64(addr + 16, entry);
154 }
155
WriteEntry32(uint64_t entry_addr,uint32_t next,uint32_t prev,uint32_t dex_file,uint64_t dex_size)156 void DexFilesTest::WriteEntry32(uint64_t entry_addr, uint32_t next, uint32_t prev,
157 uint32_t dex_file, uint64_t dex_size) {
158 // Format of the 32 bit DEXFileEntry structure:
159 // uint32_t next
160 memory_->SetData32(entry_addr, next);
161 // uint32_t prev
162 memory_->SetData32(entry_addr + 4, prev);
163 // uint32_t dex_file
164 memory_->SetData32(entry_addr + 8, dex_file);
165 // uint32_t dex_size (present in the struct, but we ignore it)
166 memory_->SetData32(entry_addr + 12, 0); // Align.
167 memory_->SetData64(entry_addr + 16, dex_size);
168 }
169
WriteEntry64(uint64_t entry_addr,uint64_t next,uint64_t prev,uint64_t dex_file,uint64_t dex_size)170 void DexFilesTest::WriteEntry64(uint64_t entry_addr, uint64_t next, uint64_t prev,
171 uint64_t dex_file, uint64_t dex_size) {
172 // Format of the 64 bit DEXFileEntry structure:
173 // uint64_t next
174 memory_->SetData64(entry_addr, next);
175 // uint64_t prev
176 memory_->SetData64(entry_addr + 8, prev);
177 // uint64_t dex_file
178 memory_->SetData64(entry_addr + 16, dex_file);
179 // uint32_t dex_size (present in the struct, but we ignore it)
180 memory_->SetData64(entry_addr + 24, dex_size);
181 }
182
WriteDex(uint64_t dex_file)183 void DexFilesTest::WriteDex(uint64_t dex_file) {
184 memory_->SetMemory(dex_file, kDexData, sizeof(kDexData));
185 }
186
TEST_F(DexFilesTest,get_method_information_invalid)187 TEST_F(DexFilesTest, get_method_information_invalid) {
188 SharedString method_name = "nothing";
189 uint64_t method_offset = 0x124;
190
191 dex_files_->GetFunctionName(maps_.get(), 0, &method_name, &method_offset);
192 EXPECT_EQ("nothing", method_name);
193 EXPECT_EQ(0x124U, method_offset);
194 }
195
TEST_F(DexFilesTest,get_method_information_32)196 TEST_F(DexFilesTest, get_method_information_32) {
197 SharedString method_name = "nothing";
198 uint64_t method_offset = 0x124;
199
200 WriteDescriptor32(0x100800, 0x200000);
201 WriteEntry32(0x200000, 0, 0, 0x300000, sizeof(kDexData));
202 WriteDex(0x300000);
203
204 dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset);
205 EXPECT_EQ("Main.<init>", method_name);
206 EXPECT_EQ(0U, method_offset);
207 }
208
TEST_F(DexFilesTest,get_method_information_64)209 TEST_F(DexFilesTest, get_method_information_64) {
210 Init(ARCH_ARM64);
211
212 SharedString method_name = "nothing";
213 uint64_t method_offset = 0x124;
214
215 WriteDescriptor64(0x100800, 0x200000);
216 WriteEntry64(0x200000, 0, 0, 0x301000, sizeof(kDexData));
217 WriteDex(0x301000);
218
219 dex_files_->GetFunctionName(maps_.get(), 0x301102, &method_name, &method_offset);
220 EXPECT_EQ("Main.<init>", method_name);
221 EXPECT_EQ(2U, method_offset);
222 }
223
TEST_F(DexFilesTest,get_method_information_not_first_entry_32)224 TEST_F(DexFilesTest, get_method_information_not_first_entry_32) {
225 SharedString method_name = "nothing";
226 uint64_t method_offset = 0x124;
227
228 WriteDescriptor32(0x100800, 0x200000);
229 WriteEntry32(0x200000, 0x200100, 0, 0x100000, sizeof(kDexData));
230 WriteEntry32(0x200100, 0, 0x200000, 0x300000, sizeof(kDexData));
231 WriteDex(0x300000);
232
233 dex_files_->GetFunctionName(maps_.get(), 0x300104, &method_name, &method_offset);
234 EXPECT_EQ("Main.<init>", method_name);
235 EXPECT_EQ(4U, method_offset);
236 }
237
TEST_F(DexFilesTest,get_method_information_not_first_entry_64)238 TEST_F(DexFilesTest, get_method_information_not_first_entry_64) {
239 Init(ARCH_ARM64);
240
241 SharedString method_name = "nothing";
242 uint64_t method_offset = 0x124;
243
244 WriteDescriptor64(0x100800, 0x200000);
245 WriteEntry64(0x200000, 0x200100, 0, 0x100000, sizeof(kDexData));
246 WriteEntry64(0x200100, 0, 0x200000, 0x300000, sizeof(kDexData));
247 WriteDex(0x300000);
248
249 dex_files_->GetFunctionName(maps_.get(), 0x300106, &method_name, &method_offset);
250 EXPECT_EQ("Main.<init>", method_name);
251 EXPECT_EQ(6U, method_offset);
252 }
253
TEST_F(DexFilesTest,get_method_information_cached)254 TEST_F(DexFilesTest, get_method_information_cached) {
255 SharedString method_name = "nothing";
256 uint64_t method_offset = 0x124;
257
258 WriteDescriptor32(0x100800, 0x200000);
259 WriteEntry32(0x200000, 0, 0, 0x300000, sizeof(kDexData));
260 WriteDex(0x300000);
261
262 dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset);
263 EXPECT_EQ("Main.<init>", method_name);
264 EXPECT_EQ(0U, method_offset);
265
266 // Clear all memory and make sure that data is acquired from the cache.
267 memory_->Clear();
268 dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset);
269 EXPECT_EQ("Main.<init>", method_name);
270 EXPECT_EQ(0U, method_offset);
271 }
272
TEST_F(DexFilesTest,get_method_information_search_libs)273 TEST_F(DexFilesTest, get_method_information_search_libs) {
274 SharedString method_name = "nothing";
275 uint64_t method_offset = 0x124;
276
277 WriteDescriptor32(0x100800, 0x200000);
278 WriteEntry32(0x200000, 0x200100, 0, 0x100000, sizeof(kDexData));
279 WriteEntry32(0x200100, 0, 0x200000, 0x300000, sizeof(kDexData));
280 WriteDex(0x300000);
281
282 // Only search a given named list of libs.
283 std::vector<std::string> libs{"libart.so"};
284 dex_files_ = CreateDexFiles(ARCH_ARM, process_memory_, libs);
285
286 dex_files_->GetFunctionName(maps_.get(), 0x300104, &method_name, &method_offset);
287 EXPECT_EQ("nothing", method_name);
288 EXPECT_EQ(0x124U, method_offset);
289
290 auto map_info = maps_->Get(kMapGlobal);
291 map_info->set_name("/system/lib/libart.so");
292 dex_files_ = CreateDexFiles(ARCH_ARM, process_memory_, libs);
293 // Set the rw map to the same name or this will not scan this entry.
294 map_info = maps_->Get(kMapGlobalRw);
295 map_info->set_name("/system/lib/libart.so");
296 // Make sure that clearing out copy of the libs doesn't affect the
297 // DexFiles object.
298 libs.clear();
299
300 dex_files_->GetFunctionName(maps_.get(), 0x300104, &method_name, &method_offset);
301 EXPECT_EQ("Main.<init>", method_name);
302 EXPECT_EQ(4U, method_offset);
303 }
304
TEST_F(DexFilesTest,get_method_information_global_skip_zero_32)305 TEST_F(DexFilesTest, get_method_information_global_skip_zero_32) {
306 SharedString method_name = "nothing";
307 uint64_t method_offset = 0x124;
308
309 // First global variable found, but value is zero.
310 WriteDescriptor32(0xc800, 0);
311
312 WriteDescriptor32(0x100800, 0x200000);
313 WriteEntry32(0x200000, 0, 0, 0x300000, sizeof(kDexData));
314 WriteDex(0x300000);
315
316 dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset);
317 EXPECT_EQ("Main.<init>", method_name);
318 EXPECT_EQ(0U, method_offset);
319
320 // Verify that second is ignored when first is set to non-zero
321 dex_files_ = CreateDexFiles(ARCH_ARM, process_memory_);
322 method_name = "fail";
323 method_offset = 0x123;
324 WriteDescriptor32(0xc800, 0x100000);
325 dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset);
326 EXPECT_EQ("fail", method_name);
327 EXPECT_EQ(0x123U, method_offset);
328 }
329
TEST_F(DexFilesTest,get_method_information_global_skip_zero_64)330 TEST_F(DexFilesTest, get_method_information_global_skip_zero_64) {
331 Init(ARCH_ARM64);
332
333 SharedString method_name = "nothing";
334 uint64_t method_offset = 0x124;
335
336 // First global variable found, but value is zero.
337 WriteDescriptor64(0xc800, 0);
338
339 WriteDescriptor64(0x100800, 0x200000);
340 WriteEntry64(0x200000, 0, 0, 0x300000, sizeof(kDexData));
341 WriteDex(0x300000);
342
343 dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset);
344 EXPECT_EQ("Main.<init>", method_name);
345 EXPECT_EQ(0U, method_offset);
346
347 // Verify that second is ignored when first is set to non-zero
348 dex_files_ = CreateDexFiles(ARCH_ARM64, process_memory_);
349 method_name = "fail";
350 method_offset = 0x123;
351 WriteDescriptor64(0xc800, 0x100000);
352 dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset);
353 EXPECT_EQ("fail", method_name);
354 EXPECT_EQ(0x123U, method_offset);
355 }
356
TEST_F(DexFilesTest,get_method_information_with_empty_map)357 TEST_F(DexFilesTest, get_method_information_with_empty_map) {
358 SharedString method_name = "nothing";
359 uint64_t method_offset = 0x124;
360
361 WriteDescriptor32(0x503800, 0x506000);
362 WriteEntry32(0x506000, 0, 0, 0x510000, sizeof(kDexData));
363 WriteDex(0x510000);
364
365 dex_files_->GetFunctionName(maps_.get(), 0x510100, &method_name, &method_offset);
366 EXPECT_EQ("Main.<init>", method_name);
367 EXPECT_EQ(0U, method_offset);
368 }
369
TEST_F(DexFilesTest,get_method_information_with_page_size_compat_map)370 TEST_F(DexFilesTest, get_method_information_with_page_size_compat_map) {
371 SharedString method_name = "nothing";
372 uint64_t method_offset = 0x124;
373
374 WriteDescriptor32(0x603800, 0x606000);
375 WriteEntry32(0x606000, 0, 0, 0x610000, sizeof(kDexData));
376 WriteDex(0x610000);
377
378 dex_files_->GetFunctionName(maps_.get(), 0x610100, &method_name, &method_offset);
379 EXPECT_EQ("Main.<init>", method_name);
380 EXPECT_EQ(0U, method_offset);
381 }
382
TEST_F(DexFilesTest,get_method_information_tagged_descriptor_entry_addr_arm64)383 TEST_F(DexFilesTest, get_method_information_tagged_descriptor_entry_addr_arm64) {
384 Init(ARCH_ARM64);
385
386 SharedString method_name = "nothing";
387 uint64_t method_offset = 0x124;
388
389 // Descriptor-stored adddress (first_entry) with a tag in the top byte, which
390 // should be masked out.
391 WriteDescriptor64(0x100800, 0xb400'0000'0020'0000ull);
392 WriteEntry64(0x200000, 0, 0, 0x301000, sizeof(kDexData));
393 WriteDex(0x301000);
394
395 dex_files_->GetFunctionName(maps_.get(), 0x301102, &method_name, &method_offset);
396 EXPECT_EQ("Main.<init>", method_name);
397 EXPECT_EQ(2U, method_offset);
398 }
399
400 } // namespace unwindstack
401