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 "DexFileData.h"
32 #include "ElfFake.h"
33 #include "MemoryFake.h"
34
35 namespace unwindstack {
36
37 class DexFilesTest : public ::testing::Test {
38 protected:
CreateFakeElf(MapInfo * map_info,uint64_t global_offset,uint64_t data_offset,uint64_t data_vaddr,uint64_t data_size)39 void CreateFakeElf(MapInfo* map_info, uint64_t global_offset, uint64_t data_offset,
40 uint64_t data_vaddr, uint64_t data_size) {
41 MemoryFake* memory = new MemoryFake;
42 ElfFake* elf = new ElfFake(memory);
43 elf->FakeSetValid(true);
44 ElfInterfaceFake* interface = new ElfInterfaceFake(memory);
45 elf->FakeSetInterface(interface);
46
47 interface->FakeSetGlobalVariable("__dex_debug_descriptor", global_offset);
48 interface->FakeSetDataOffset(data_offset);
49 interface->FakeSetDataVaddrStart(data_vaddr);
50 interface->FakeSetDataVaddrEnd(data_vaddr + data_size);
51 map_info->elf.reset(elf);
52 }
53
Init(ArchEnum arch)54 void Init(ArchEnum arch) {
55 dex_files_.reset(new DexFiles(process_memory_));
56 dex_files_->SetArch(arch);
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);
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);
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);
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);
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 void WriteEntry64(uint64_t entry_addr, uint64_t next, uint64_t prev, uint64_t dex_file);
106 void WriteDex(uint64_t dex_file);
107
108 static constexpr size_t kMapGlobalNonReadable = 2;
109 static constexpr size_t kMapGlobalSetToZero = 3;
110 static constexpr size_t kMapGlobal = 5;
111 static constexpr size_t kMapGlobalRw = 6;
112 static constexpr size_t kMapDexFileEntries = 7;
113 static constexpr size_t kMapDexFiles = 8;
114 static constexpr size_t kMapGlobalAfterEmpty = 9;
115 static constexpr size_t kMapDexFilesAfterEmpty = 12;
116
117 std::shared_ptr<Memory> process_memory_;
118 MemoryFake* memory_;
119 std::unique_ptr<DexFiles> dex_files_;
120 std::unique_ptr<BufferMaps> maps_;
121 };
122
WriteDescriptor32(uint64_t addr,uint32_t head)123 void DexFilesTest::WriteDescriptor32(uint64_t addr, uint32_t head) {
124 // void* first_entry_
125 memory_->SetData32(addr + 12, head);
126 }
127
WriteDescriptor64(uint64_t addr,uint64_t head)128 void DexFilesTest::WriteDescriptor64(uint64_t addr, uint64_t head) {
129 // void* first_entry_
130 memory_->SetData64(addr + 16, head);
131 }
132
WriteEntry32(uint64_t entry_addr,uint32_t next,uint32_t prev,uint32_t dex_file)133 void DexFilesTest::WriteEntry32(uint64_t entry_addr, uint32_t next, uint32_t prev,
134 uint32_t dex_file) {
135 // Format of the 32 bit DEXFileEntry structure:
136 // uint32_t next
137 memory_->SetData32(entry_addr, next);
138 // uint32_t prev
139 memory_->SetData32(entry_addr + 4, prev);
140 // uint32_t dex_file
141 memory_->SetData32(entry_addr + 8, dex_file);
142 }
143
WriteEntry64(uint64_t entry_addr,uint64_t next,uint64_t prev,uint64_t dex_file)144 void DexFilesTest::WriteEntry64(uint64_t entry_addr, uint64_t next, uint64_t prev,
145 uint64_t dex_file) {
146 // Format of the 64 bit DEXFileEntry structure:
147 // uint64_t next
148 memory_->SetData64(entry_addr, next);
149 // uint64_t prev
150 memory_->SetData64(entry_addr + 8, prev);
151 // uint64_t dex_file
152 memory_->SetData64(entry_addr + 16, dex_file);
153 }
154
WriteDex(uint64_t dex_file)155 void DexFilesTest::WriteDex(uint64_t dex_file) {
156 memory_->SetMemory(dex_file, kDexData, sizeof(kDexData) * sizeof(uint32_t));
157 }
158
TEST_F(DexFilesTest,get_method_information_invalid)159 TEST_F(DexFilesTest, get_method_information_invalid) {
160 std::string method_name = "nothing";
161 uint64_t method_offset = 0x124;
162 MapInfo* info = maps_->Get(kMapDexFileEntries);
163
164 dex_files_->GetMethodInformation(maps_.get(), info, 0, &method_name, &method_offset);
165 EXPECT_EQ("nothing", method_name);
166 EXPECT_EQ(0x124U, method_offset);
167 }
168
TEST_F(DexFilesTest,get_method_information_32)169 TEST_F(DexFilesTest, get_method_information_32) {
170 std::string method_name = "nothing";
171 uint64_t method_offset = 0x124;
172 MapInfo* info = maps_->Get(kMapDexFiles);
173
174 WriteDescriptor32(0x100800, 0x200000);
175 WriteEntry32(0x200000, 0, 0, 0x300000);
176 WriteDex(0x300000);
177
178 dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
179 EXPECT_EQ("Main.<init>", method_name);
180 EXPECT_EQ(0U, method_offset);
181 }
182
TEST_F(DexFilesTest,get_method_information_64)183 TEST_F(DexFilesTest, get_method_information_64) {
184 Init(ARCH_ARM64);
185
186 std::string method_name = "nothing";
187 uint64_t method_offset = 0x124;
188 MapInfo* info = maps_->Get(kMapDexFiles);
189
190 WriteDescriptor64(0x100800, 0x200000);
191 WriteEntry64(0x200000, 0, 0, 0x301000);
192 WriteDex(0x301000);
193
194 dex_files_->GetMethodInformation(maps_.get(), info, 0x301102, &method_name, &method_offset);
195 EXPECT_EQ("Main.<init>", method_name);
196 EXPECT_EQ(2U, method_offset);
197 }
198
TEST_F(DexFilesTest,get_method_information_not_first_entry_32)199 TEST_F(DexFilesTest, get_method_information_not_first_entry_32) {
200 std::string method_name = "nothing";
201 uint64_t method_offset = 0x124;
202 MapInfo* info = maps_->Get(kMapDexFiles);
203
204 WriteDescriptor32(0x100800, 0x200000);
205 WriteEntry32(0x200000, 0x200100, 0, 0x100000);
206 WriteEntry32(0x200100, 0, 0x200000, 0x300000);
207 WriteDex(0x300000);
208
209 dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset);
210 EXPECT_EQ("Main.<init>", method_name);
211 EXPECT_EQ(4U, method_offset);
212 }
213
TEST_F(DexFilesTest,get_method_information_not_first_entry_64)214 TEST_F(DexFilesTest, get_method_information_not_first_entry_64) {
215 Init(ARCH_ARM64);
216
217 std::string method_name = "nothing";
218 uint64_t method_offset = 0x124;
219 MapInfo* info = maps_->Get(kMapDexFiles);
220
221 WriteDescriptor64(0x100800, 0x200000);
222 WriteEntry64(0x200000, 0x200100, 0, 0x100000);
223 WriteEntry64(0x200100, 0, 0x200000, 0x300000);
224 WriteDex(0x300000);
225
226 dex_files_->GetMethodInformation(maps_.get(), info, 0x300106, &method_name, &method_offset);
227 EXPECT_EQ("Main.<init>", method_name);
228 EXPECT_EQ(6U, method_offset);
229 }
230
TEST_F(DexFilesTest,get_method_information_cached)231 TEST_F(DexFilesTest, get_method_information_cached) {
232 std::string method_name = "nothing";
233 uint64_t method_offset = 0x124;
234 MapInfo* info = maps_->Get(kMapDexFiles);
235
236 WriteDescriptor32(0x100800, 0x200000);
237 WriteEntry32(0x200000, 0, 0, 0x300000);
238 WriteDex(0x300000);
239
240 dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
241 EXPECT_EQ("Main.<init>", method_name);
242 EXPECT_EQ(0U, method_offset);
243
244 // Clear all memory and make sure that data is acquired from the cache.
245 memory_->Clear();
246 dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
247 EXPECT_EQ("Main.<init>", method_name);
248 EXPECT_EQ(0U, method_offset);
249 }
250
TEST_F(DexFilesTest,get_method_information_search_libs)251 TEST_F(DexFilesTest, get_method_information_search_libs) {
252 std::string method_name = "nothing";
253 uint64_t method_offset = 0x124;
254 MapInfo* info = maps_->Get(kMapDexFiles);
255
256 WriteDescriptor32(0x100800, 0x200000);
257 WriteEntry32(0x200000, 0x200100, 0, 0x100000);
258 WriteEntry32(0x200100, 0, 0x200000, 0x300000);
259 WriteDex(0x300000);
260
261 // Only search a given named list of libs.
262 std::vector<std::string> libs{"libart.so"};
263 dex_files_.reset(new DexFiles(process_memory_, libs));
264 dex_files_->SetArch(ARCH_ARM);
265
266 dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset);
267 EXPECT_EQ("nothing", method_name);
268 EXPECT_EQ(0x124U, method_offset);
269
270 MapInfo* map_info = maps_->Get(kMapGlobal);
271 map_info->name = "/system/lib/libart.so";
272 dex_files_.reset(new DexFiles(process_memory_, libs));
273 dex_files_->SetArch(ARCH_ARM);
274 // Set the rw map to the same name or this will not scan this entry.
275 map_info = maps_->Get(kMapGlobalRw);
276 map_info->name = "/system/lib/libart.so";
277 // Make sure that clearing out copy of the libs doesn't affect the
278 // DexFiles object.
279 libs.clear();
280
281 dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset);
282 EXPECT_EQ("Main.<init>", method_name);
283 EXPECT_EQ(4U, method_offset);
284 }
285
TEST_F(DexFilesTest,get_method_information_global_skip_zero_32)286 TEST_F(DexFilesTest, get_method_information_global_skip_zero_32) {
287 std::string method_name = "nothing";
288 uint64_t method_offset = 0x124;
289 MapInfo* info = maps_->Get(kMapDexFiles);
290
291 // First global variable found, but value is zero.
292 WriteDescriptor32(0xc800, 0);
293
294 WriteDescriptor32(0x100800, 0x200000);
295 WriteEntry32(0x200000, 0, 0, 0x300000);
296 WriteDex(0x300000);
297
298 dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
299 EXPECT_EQ("Main.<init>", method_name);
300 EXPECT_EQ(0U, method_offset);
301
302 // Verify that second is ignored when first is set to non-zero
303 dex_files_.reset(new DexFiles(process_memory_));
304 dex_files_->SetArch(ARCH_ARM);
305 method_name = "fail";
306 method_offset = 0x123;
307 WriteDescriptor32(0xc800, 0x100000);
308 dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
309 EXPECT_EQ("fail", method_name);
310 EXPECT_EQ(0x123U, method_offset);
311 }
312
TEST_F(DexFilesTest,get_method_information_global_skip_zero_64)313 TEST_F(DexFilesTest, get_method_information_global_skip_zero_64) {
314 Init(ARCH_ARM64);
315
316 std::string method_name = "nothing";
317 uint64_t method_offset = 0x124;
318 MapInfo* info = maps_->Get(kMapDexFiles);
319
320 // First global variable found, but value is zero.
321 WriteDescriptor64(0xc800, 0);
322
323 WriteDescriptor64(0x100800, 0x200000);
324 WriteEntry64(0x200000, 0, 0, 0x300000);
325 WriteDex(0x300000);
326
327 dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
328 EXPECT_EQ("Main.<init>", method_name);
329 EXPECT_EQ(0U, method_offset);
330
331 // Verify that second is ignored when first is set to non-zero
332 dex_files_.reset(new DexFiles(process_memory_));
333 dex_files_->SetArch(ARCH_ARM64);
334 method_name = "fail";
335 method_offset = 0x123;
336 WriteDescriptor64(0xc800, 0x100000);
337 dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
338 EXPECT_EQ("fail", method_name);
339 EXPECT_EQ(0x123U, method_offset);
340 }
341
TEST_F(DexFilesTest,get_method_information_with_empty_map)342 TEST_F(DexFilesTest, get_method_information_with_empty_map) {
343 std::string method_name = "nothing";
344 uint64_t method_offset = 0x124;
345 MapInfo* info = maps_->Get(kMapDexFilesAfterEmpty);
346
347 WriteDescriptor32(0x503800, 0x506000);
348 WriteEntry32(0x506000, 0, 0, 0x510000);
349 WriteDex(0x510000);
350
351 dex_files_->GetMethodInformation(maps_.get(), info, 0x510100, &method_name, &method_offset);
352 EXPECT_EQ("Main.<init>", method_name);
353 EXPECT_EQ(0U, method_offset);
354 }
355
356 } // namespace unwindstack
357