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 ASSERT_TRUE(maps_->Parse());
73
74 // Global variable in a section that is not readable.
75 MapInfo* map_info = maps_->Get(kMapGlobalNonReadable).get();
76 ASSERT_TRUE(map_info != nullptr);
77 CreateFakeElf(map_info, 0x2800, 0x2000, 0x2000, 0x3000);
78
79 // Global variable not set by default.
80 map_info = maps_->Get(kMapGlobalSetToZero).get();
81 ASSERT_TRUE(map_info != nullptr);
82 CreateFakeElf(map_info, 0x2800, 0x2000, 0x2000, 0x3000);
83
84 // Global variable set in this map.
85 map_info = maps_->Get(kMapGlobal).get();
86 ASSERT_TRUE(map_info != nullptr);
87 CreateFakeElf(map_info, 0xf1800, 0xf1000, 0xf1000, 0x10000);
88
89 // Global variable set in this map, but there is an empty map before rw map.
90 map_info = maps_->Get(kMapGlobalAfterEmpty).get();
91 ASSERT_TRUE(map_info != nullptr);
92 CreateFakeElf(map_info, 0x3800, 0x3000, 0x3000, 0xd000);
93 }
94
SetUp()95 void SetUp() override {
96 memory_ = new MemoryFake;
97 process_memory_.reset(memory_);
98
99 Init(ARCH_ARM);
100 }
101
102 void WriteDescriptor32(uint64_t addr, uint32_t head);
103 void WriteDescriptor64(uint64_t addr, uint64_t head);
104 void WriteEntry32(uint64_t entry_addr, uint32_t next, uint32_t prev, uint32_t dex_file,
105 uint64_t dex_size);
106 void WriteEntry64(uint64_t entry_addr, uint64_t next, uint64_t prev, uint64_t dex_file,
107 uint64_t dex_size);
108 void WriteDex(uint64_t dex_file);
109
110 static constexpr size_t kMapGlobalNonReadable = 2;
111 static constexpr size_t kMapGlobalSetToZero = 3;
112 static constexpr size_t kMapGlobal = 5;
113 static constexpr size_t kMapGlobalRw = 6;
114 static constexpr size_t kMapDexFileEntries = 7;
115 static constexpr size_t kMapDexFiles = 8;
116 static constexpr size_t kMapGlobalAfterEmpty = 9;
117 static constexpr size_t kMapDexFilesAfterEmpty = 12;
118
119 std::shared_ptr<Memory> process_memory_;
120 MemoryFake* memory_;
121 std::unique_ptr<DexFiles> dex_files_;
122 std::unique_ptr<BufferMaps> maps_;
123 };
124
WriteDescriptor32(uint64_t addr,uint32_t entry)125 void DexFilesTest::WriteDescriptor32(uint64_t addr, uint32_t entry) {
126 // uint32_t version
127 memory_->SetData32(addr, 1);
128 // uint32_t action_flag
129 memory_->SetData32(addr + 4, 0);
130 // uint32_t relevant_entry
131 memory_->SetData32(addr + 8, 0);
132 // uint32_t first_entry
133 memory_->SetData32(addr + 12, entry);
134 }
135
WriteDescriptor64(uint64_t addr,uint64_t entry)136 void DexFilesTest::WriteDescriptor64(uint64_t addr, uint64_t entry) {
137 // uint32_t version
138 memory_->SetData32(addr, 1);
139 // uint32_t action_flag
140 memory_->SetData32(addr + 4, 0);
141 // uint64_t relevant_entry
142 memory_->SetData64(addr + 8, 0);
143 // uint64_t first_entry
144 memory_->SetData64(addr + 16, entry);
145 }
146
WriteEntry32(uint64_t entry_addr,uint32_t next,uint32_t prev,uint32_t dex_file,uint64_t dex_size)147 void DexFilesTest::WriteEntry32(uint64_t entry_addr, uint32_t next, uint32_t prev,
148 uint32_t dex_file, uint64_t dex_size) {
149 // Format of the 32 bit DEXFileEntry structure:
150 // uint32_t next
151 memory_->SetData32(entry_addr, next);
152 // uint32_t prev
153 memory_->SetData32(entry_addr + 4, prev);
154 // uint32_t dex_file
155 memory_->SetData32(entry_addr + 8, dex_file);
156 // uint32_t dex_size (present in the struct, but we ignore it)
157 memory_->SetData32(entry_addr + 12, 0); // Align.
158 memory_->SetData64(entry_addr + 16, dex_size);
159 }
160
WriteEntry64(uint64_t entry_addr,uint64_t next,uint64_t prev,uint64_t dex_file,uint64_t dex_size)161 void DexFilesTest::WriteEntry64(uint64_t entry_addr, uint64_t next, uint64_t prev,
162 uint64_t dex_file, uint64_t dex_size) {
163 // Format of the 64 bit DEXFileEntry structure:
164 // uint64_t next
165 memory_->SetData64(entry_addr, next);
166 // uint64_t prev
167 memory_->SetData64(entry_addr + 8, prev);
168 // uint64_t dex_file
169 memory_->SetData64(entry_addr + 16, dex_file);
170 // uint32_t dex_size (present in the struct, but we ignore it)
171 memory_->SetData64(entry_addr + 24, dex_size);
172 }
173
WriteDex(uint64_t dex_file)174 void DexFilesTest::WriteDex(uint64_t dex_file) {
175 memory_->SetMemory(dex_file, kDexData, sizeof(kDexData));
176 }
177
TEST_F(DexFilesTest,get_method_information_invalid)178 TEST_F(DexFilesTest, get_method_information_invalid) {
179 SharedString method_name = "nothing";
180 uint64_t method_offset = 0x124;
181
182 dex_files_->GetFunctionName(maps_.get(), 0, &method_name, &method_offset);
183 EXPECT_EQ("nothing", method_name);
184 EXPECT_EQ(0x124U, method_offset);
185 }
186
TEST_F(DexFilesTest,get_method_information_32)187 TEST_F(DexFilesTest, get_method_information_32) {
188 SharedString method_name = "nothing";
189 uint64_t method_offset = 0x124;
190
191 WriteDescriptor32(0x100800, 0x200000);
192 WriteEntry32(0x200000, 0, 0, 0x300000, sizeof(kDexData));
193 WriteDex(0x300000);
194
195 dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset);
196 EXPECT_EQ("Main.<init>", method_name);
197 EXPECT_EQ(0U, method_offset);
198 }
199
TEST_F(DexFilesTest,get_method_information_64)200 TEST_F(DexFilesTest, get_method_information_64) {
201 Init(ARCH_ARM64);
202
203 SharedString method_name = "nothing";
204 uint64_t method_offset = 0x124;
205
206 WriteDescriptor64(0x100800, 0x200000);
207 WriteEntry64(0x200000, 0, 0, 0x301000, sizeof(kDexData));
208 WriteDex(0x301000);
209
210 dex_files_->GetFunctionName(maps_.get(), 0x301102, &method_name, &method_offset);
211 EXPECT_EQ("Main.<init>", method_name);
212 EXPECT_EQ(2U, method_offset);
213 }
214
TEST_F(DexFilesTest,get_method_information_not_first_entry_32)215 TEST_F(DexFilesTest, get_method_information_not_first_entry_32) {
216 SharedString method_name = "nothing";
217 uint64_t method_offset = 0x124;
218
219 WriteDescriptor32(0x100800, 0x200000);
220 WriteEntry32(0x200000, 0x200100, 0, 0x100000, sizeof(kDexData));
221 WriteEntry32(0x200100, 0, 0x200000, 0x300000, sizeof(kDexData));
222 WriteDex(0x300000);
223
224 dex_files_->GetFunctionName(maps_.get(), 0x300104, &method_name, &method_offset);
225 EXPECT_EQ("Main.<init>", method_name);
226 EXPECT_EQ(4U, method_offset);
227 }
228
TEST_F(DexFilesTest,get_method_information_not_first_entry_64)229 TEST_F(DexFilesTest, get_method_information_not_first_entry_64) {
230 Init(ARCH_ARM64);
231
232 SharedString method_name = "nothing";
233 uint64_t method_offset = 0x124;
234
235 WriteDescriptor64(0x100800, 0x200000);
236 WriteEntry64(0x200000, 0x200100, 0, 0x100000, sizeof(kDexData));
237 WriteEntry64(0x200100, 0, 0x200000, 0x300000, sizeof(kDexData));
238 WriteDex(0x300000);
239
240 dex_files_->GetFunctionName(maps_.get(), 0x300106, &method_name, &method_offset);
241 EXPECT_EQ("Main.<init>", method_name);
242 EXPECT_EQ(6U, method_offset);
243 }
244
TEST_F(DexFilesTest,get_method_information_cached)245 TEST_F(DexFilesTest, get_method_information_cached) {
246 SharedString method_name = "nothing";
247 uint64_t method_offset = 0x124;
248
249 WriteDescriptor32(0x100800, 0x200000);
250 WriteEntry32(0x200000, 0, 0, 0x300000, sizeof(kDexData));
251 WriteDex(0x300000);
252
253 dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset);
254 EXPECT_EQ("Main.<init>", method_name);
255 EXPECT_EQ(0U, method_offset);
256
257 // Clear all memory and make sure that data is acquired from the cache.
258 memory_->Clear();
259 dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset);
260 EXPECT_EQ("Main.<init>", method_name);
261 EXPECT_EQ(0U, method_offset);
262 }
263
TEST_F(DexFilesTest,get_method_information_search_libs)264 TEST_F(DexFilesTest, get_method_information_search_libs) {
265 SharedString method_name = "nothing";
266 uint64_t method_offset = 0x124;
267
268 WriteDescriptor32(0x100800, 0x200000);
269 WriteEntry32(0x200000, 0x200100, 0, 0x100000, sizeof(kDexData));
270 WriteEntry32(0x200100, 0, 0x200000, 0x300000, sizeof(kDexData));
271 WriteDex(0x300000);
272
273 // Only search a given named list of libs.
274 std::vector<std::string> libs{"libart.so"};
275 dex_files_ = CreateDexFiles(ARCH_ARM, process_memory_, libs);
276
277 dex_files_->GetFunctionName(maps_.get(), 0x300104, &method_name, &method_offset);
278 EXPECT_EQ("nothing", method_name);
279 EXPECT_EQ(0x124U, method_offset);
280
281 auto map_info = maps_->Get(kMapGlobal);
282 map_info->set_name("/system/lib/libart.so");
283 dex_files_ = CreateDexFiles(ARCH_ARM, process_memory_, libs);
284 // Set the rw map to the same name or this will not scan this entry.
285 map_info = maps_->Get(kMapGlobalRw);
286 map_info->set_name("/system/lib/libart.so");
287 // Make sure that clearing out copy of the libs doesn't affect the
288 // DexFiles object.
289 libs.clear();
290
291 dex_files_->GetFunctionName(maps_.get(), 0x300104, &method_name, &method_offset);
292 EXPECT_EQ("Main.<init>", method_name);
293 EXPECT_EQ(4U, method_offset);
294 }
295
TEST_F(DexFilesTest,get_method_information_global_skip_zero_32)296 TEST_F(DexFilesTest, get_method_information_global_skip_zero_32) {
297 SharedString method_name = "nothing";
298 uint64_t method_offset = 0x124;
299
300 // First global variable found, but value is zero.
301 WriteDescriptor32(0xc800, 0);
302
303 WriteDescriptor32(0x100800, 0x200000);
304 WriteEntry32(0x200000, 0, 0, 0x300000, sizeof(kDexData));
305 WriteDex(0x300000);
306
307 dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset);
308 EXPECT_EQ("Main.<init>", method_name);
309 EXPECT_EQ(0U, method_offset);
310
311 // Verify that second is ignored when first is set to non-zero
312 dex_files_ = CreateDexFiles(ARCH_ARM, process_memory_);
313 method_name = "fail";
314 method_offset = 0x123;
315 WriteDescriptor32(0xc800, 0x100000);
316 dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset);
317 EXPECT_EQ("fail", method_name);
318 EXPECT_EQ(0x123U, method_offset);
319 }
320
TEST_F(DexFilesTest,get_method_information_global_skip_zero_64)321 TEST_F(DexFilesTest, get_method_information_global_skip_zero_64) {
322 Init(ARCH_ARM64);
323
324 SharedString method_name = "nothing";
325 uint64_t method_offset = 0x124;
326
327 // First global variable found, but value is zero.
328 WriteDescriptor64(0xc800, 0);
329
330 WriteDescriptor64(0x100800, 0x200000);
331 WriteEntry64(0x200000, 0, 0, 0x300000, sizeof(kDexData));
332 WriteDex(0x300000);
333
334 dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset);
335 EXPECT_EQ("Main.<init>", method_name);
336 EXPECT_EQ(0U, method_offset);
337
338 // Verify that second is ignored when first is set to non-zero
339 dex_files_ = CreateDexFiles(ARCH_ARM64, process_memory_);
340 method_name = "fail";
341 method_offset = 0x123;
342 WriteDescriptor64(0xc800, 0x100000);
343 dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset);
344 EXPECT_EQ("fail", method_name);
345 EXPECT_EQ(0x123U, method_offset);
346 }
347
TEST_F(DexFilesTest,get_method_information_with_empty_map)348 TEST_F(DexFilesTest, get_method_information_with_empty_map) {
349 SharedString method_name = "nothing";
350 uint64_t method_offset = 0x124;
351
352 WriteDescriptor32(0x503800, 0x506000);
353 WriteEntry32(0x506000, 0, 0, 0x510000, sizeof(kDexData));
354 WriteDex(0x510000);
355
356 dex_files_->GetFunctionName(maps_.get(), 0x510100, &method_name, &method_offset);
357 EXPECT_EQ("Main.<init>", method_name);
358 EXPECT_EQ(0U, method_offset);
359 }
360
TEST_F(DexFilesTest,get_method_information_tagged_descriptor_entry_addr_arm64)361 TEST_F(DexFilesTest, get_method_information_tagged_descriptor_entry_addr_arm64) {
362 Init(ARCH_ARM64);
363
364 SharedString method_name = "nothing";
365 uint64_t method_offset = 0x124;
366
367 // Descriptor-stored adddress (first_entry) with a tag in the top byte, which
368 // should be masked out.
369 WriteDescriptor64(0x100800, 0xb400'0000'0020'0000ull);
370 WriteEntry64(0x200000, 0, 0, 0x301000, sizeof(kDexData));
371 WriteDex(0x301000);
372
373 dex_files_->GetFunctionName(maps_.get(), 0x301102, &method_name, &method_offset);
374 EXPECT_EQ("Main.<init>", method_name);
375 EXPECT_EQ(2U, method_offset);
376 }
377
378 } // namespace unwindstack
379