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)39 void CreateFakeElf(MapInfo* map_info) {
40 MemoryFake* memory = new MemoryFake;
41 ElfFake* elf = new ElfFake(memory);
42 elf->FakeSetValid(true);
43 ElfInterfaceFake* interface = new ElfInterfaceFake(memory);
44 elf->FakeSetInterface(interface);
45
46 interface->FakeSetGlobalVariable("__dex_debug_descriptor", 0x800);
47 map_info->elf.reset(elf);
48 }
49
Init(ArchEnum arch)50 void Init(ArchEnum arch) {
51 dex_files_.reset(new DexFiles(process_memory_));
52 dex_files_->SetArch(arch);
53
54 maps_.reset(
55 new BufferMaps("1000-4000 ---s 00000000 00:00 0 /fake/elf\n"
56 "4000-6000 r--s 00000000 00:00 0 /fake/elf\n"
57 "6000-8000 -wxs 00000000 00:00 0 /fake/elf\n"
58 "a000-c000 r--p 00000000 00:00 0 /fake/elf2\n"
59 "c000-f000 rw-p 00001000 00:00 0 /fake/elf2\n"
60 "f000-11000 r--p 00000000 00:00 0 /fake/elf3\n"
61 "100000-110000 rw-p 0001000 00:00 0 /fake/elf3\n"
62 "200000-210000 rw-p 0002000 00:00 0 /fake/elf3\n"
63 "300000-400000 rw-p 0003000 00:00 0 /fake/elf3\n"));
64 ASSERT_TRUE(maps_->Parse());
65
66 // Global variable in a section that is not readable.
67 MapInfo* map_info = maps_->Get(kMapGlobalNonReadable);
68 ASSERT_TRUE(map_info != nullptr);
69 CreateFakeElf(map_info);
70
71 // Global variable not set by default.
72 map_info = maps_->Get(kMapGlobalSetToZero);
73 ASSERT_TRUE(map_info != nullptr);
74 CreateFakeElf(map_info);
75
76 // Global variable set in this map.
77 map_info = maps_->Get(kMapGlobal);
78 ASSERT_TRUE(map_info != nullptr);
79 CreateFakeElf(map_info);
80 }
81
SetUp()82 void SetUp() override {
83 memory_ = new MemoryFake;
84 process_memory_.reset(memory_);
85
86 Init(ARCH_ARM);
87 }
88
89 void WriteDescriptor32(uint64_t addr, uint32_t head);
90 void WriteDescriptor64(uint64_t addr, uint64_t head);
91 void WriteEntry32(uint64_t entry_addr, uint32_t next, uint32_t prev, uint32_t dex_file);
92 void WriteEntry64(uint64_t entry_addr, uint64_t next, uint64_t prev, uint64_t dex_file);
93 void WriteDex(uint64_t dex_file);
94
95 static constexpr size_t kMapGlobalNonReadable = 2;
96 static constexpr size_t kMapGlobalSetToZero = 3;
97 static constexpr size_t kMapGlobal = 5;
98 static constexpr size_t kMapGlobalRw = 6;
99 static constexpr size_t kMapDexFileEntries = 7;
100 static constexpr size_t kMapDexFiles = 8;
101
102 std::shared_ptr<Memory> process_memory_;
103 MemoryFake* memory_;
104 std::unique_ptr<DexFiles> dex_files_;
105 std::unique_ptr<BufferMaps> maps_;
106 };
107
WriteDescriptor32(uint64_t addr,uint32_t head)108 void DexFilesTest::WriteDescriptor32(uint64_t addr, uint32_t head) {
109 // void* first_entry_
110 memory_->SetData32(addr + 12, head);
111 }
112
WriteDescriptor64(uint64_t addr,uint64_t head)113 void DexFilesTest::WriteDescriptor64(uint64_t addr, uint64_t head) {
114 // void* first_entry_
115 memory_->SetData64(addr + 16, head);
116 }
117
WriteEntry32(uint64_t entry_addr,uint32_t next,uint32_t prev,uint32_t dex_file)118 void DexFilesTest::WriteEntry32(uint64_t entry_addr, uint32_t next, uint32_t prev,
119 uint32_t dex_file) {
120 // Format of the 32 bit DEXFileEntry structure:
121 // uint32_t next
122 memory_->SetData32(entry_addr, next);
123 // uint32_t prev
124 memory_->SetData32(entry_addr + 4, prev);
125 // uint32_t dex_file
126 memory_->SetData32(entry_addr + 8, dex_file);
127 }
128
WriteEntry64(uint64_t entry_addr,uint64_t next,uint64_t prev,uint64_t dex_file)129 void DexFilesTest::WriteEntry64(uint64_t entry_addr, uint64_t next, uint64_t prev,
130 uint64_t dex_file) {
131 // Format of the 64 bit DEXFileEntry structure:
132 // uint64_t next
133 memory_->SetData64(entry_addr, next);
134 // uint64_t prev
135 memory_->SetData64(entry_addr + 8, prev);
136 // uint64_t dex_file
137 memory_->SetData64(entry_addr + 16, dex_file);
138 }
139
WriteDex(uint64_t dex_file)140 void DexFilesTest::WriteDex(uint64_t dex_file) {
141 memory_->SetMemory(dex_file, kDexData, sizeof(kDexData) * sizeof(uint32_t));
142 }
143
TEST_F(DexFilesTest,get_method_information_invalid)144 TEST_F(DexFilesTest, get_method_information_invalid) {
145 std::string method_name = "nothing";
146 uint64_t method_offset = 0x124;
147 MapInfo* info = maps_->Get(kMapDexFileEntries);
148
149 dex_files_->GetMethodInformation(maps_.get(), info, 0, &method_name, &method_offset);
150 EXPECT_EQ("nothing", method_name);
151 EXPECT_EQ(0x124U, method_offset);
152 }
153
TEST_F(DexFilesTest,get_method_information_32)154 TEST_F(DexFilesTest, get_method_information_32) {
155 std::string method_name = "nothing";
156 uint64_t method_offset = 0x124;
157 MapInfo* info = maps_->Get(kMapDexFiles);
158
159 WriteDescriptor32(0xf800, 0x200000);
160 WriteEntry32(0x200000, 0, 0, 0x300000);
161 WriteDex(0x300000);
162
163 dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
164 EXPECT_EQ("Main.<init>", method_name);
165 EXPECT_EQ(0U, method_offset);
166 }
167
TEST_F(DexFilesTest,get_method_information_64)168 TEST_F(DexFilesTest, get_method_information_64) {
169 Init(ARCH_ARM64);
170
171 std::string method_name = "nothing";
172 uint64_t method_offset = 0x124;
173 MapInfo* info = maps_->Get(kMapDexFiles);
174
175 WriteDescriptor64(0xf800, 0x200000);
176 WriteEntry64(0x200000, 0, 0, 0x301000);
177 WriteDex(0x301000);
178
179 dex_files_->GetMethodInformation(maps_.get(), info, 0x301102, &method_name, &method_offset);
180 EXPECT_EQ("Main.<init>", method_name);
181 EXPECT_EQ(2U, method_offset);
182 }
183
TEST_F(DexFilesTest,get_method_information_not_first_entry_32)184 TEST_F(DexFilesTest, get_method_information_not_first_entry_32) {
185 std::string method_name = "nothing";
186 uint64_t method_offset = 0x124;
187 MapInfo* info = maps_->Get(kMapDexFiles);
188
189 WriteDescriptor32(0xf800, 0x200000);
190 WriteEntry32(0x200000, 0x200100, 0, 0x100000);
191 WriteEntry32(0x200100, 0, 0x200000, 0x300000);
192 WriteDex(0x300000);
193
194 dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset);
195 EXPECT_EQ("Main.<init>", method_name);
196 EXPECT_EQ(4U, method_offset);
197 }
198
TEST_F(DexFilesTest,get_method_information_not_first_entry_64)199 TEST_F(DexFilesTest, get_method_information_not_first_entry_64) {
200 Init(ARCH_ARM64);
201
202 std::string method_name = "nothing";
203 uint64_t method_offset = 0x124;
204 MapInfo* info = maps_->Get(kMapDexFiles);
205
206 WriteDescriptor64(0xf800, 0x200000);
207 WriteEntry64(0x200000, 0x200100, 0, 0x100000);
208 WriteEntry64(0x200100, 0, 0x200000, 0x300000);
209 WriteDex(0x300000);
210
211 dex_files_->GetMethodInformation(maps_.get(), info, 0x300106, &method_name, &method_offset);
212 EXPECT_EQ("Main.<init>", method_name);
213 EXPECT_EQ(6U, method_offset);
214 }
215
TEST_F(DexFilesTest,get_method_information_cached)216 TEST_F(DexFilesTest, get_method_information_cached) {
217 std::string method_name = "nothing";
218 uint64_t method_offset = 0x124;
219 MapInfo* info = maps_->Get(kMapDexFiles);
220
221 WriteDescriptor32(0xf800, 0x200000);
222 WriteEntry32(0x200000, 0, 0, 0x300000);
223 WriteDex(0x300000);
224
225 dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
226 EXPECT_EQ("Main.<init>", method_name);
227 EXPECT_EQ(0U, method_offset);
228
229 // Clear all memory and make sure that data is acquired from the cache.
230 memory_->Clear();
231 dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
232 EXPECT_EQ("Main.<init>", method_name);
233 EXPECT_EQ(0U, method_offset);
234 }
235
TEST_F(DexFilesTest,get_method_information_search_libs)236 TEST_F(DexFilesTest, get_method_information_search_libs) {
237 std::string method_name = "nothing";
238 uint64_t method_offset = 0x124;
239 MapInfo* info = maps_->Get(kMapDexFiles);
240
241 WriteDescriptor32(0xf800, 0x200000);
242 WriteEntry32(0x200000, 0x200100, 0, 0x100000);
243 WriteEntry32(0x200100, 0, 0x200000, 0x300000);
244 WriteDex(0x300000);
245
246 // Only search a given named list of libs.
247 std::vector<std::string> libs{"libart.so"};
248 dex_files_.reset(new DexFiles(process_memory_, libs));
249 dex_files_->SetArch(ARCH_ARM);
250
251 dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset);
252 EXPECT_EQ("nothing", method_name);
253 EXPECT_EQ(0x124U, method_offset);
254
255 MapInfo* map_info = maps_->Get(kMapGlobal);
256 map_info->name = "/system/lib/libart.so";
257 dex_files_.reset(new DexFiles(process_memory_, libs));
258 dex_files_->SetArch(ARCH_ARM);
259 // Set the rw map to the same name or this will not scan this entry.
260 map_info = maps_->Get(kMapGlobalRw);
261 map_info->name = "/system/lib/libart.so";
262 // Make sure that clearing out copy of the libs doesn't affect the
263 // DexFiles object.
264 libs.clear();
265
266 dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset);
267 EXPECT_EQ("Main.<init>", method_name);
268 EXPECT_EQ(4U, method_offset);
269 }
270
TEST_F(DexFilesTest,get_method_information_global_skip_zero_32)271 TEST_F(DexFilesTest, get_method_information_global_skip_zero_32) {
272 std::string method_name = "nothing";
273 uint64_t method_offset = 0x124;
274 MapInfo* info = maps_->Get(kMapDexFiles);
275
276 // First global variable found, but value is zero.
277 WriteDescriptor32(0xa800, 0);
278
279 WriteDescriptor32(0xf800, 0x200000);
280 WriteEntry32(0x200000, 0, 0, 0x300000);
281 WriteDex(0x300000);
282
283 dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
284 EXPECT_EQ("Main.<init>", method_name);
285 EXPECT_EQ(0U, method_offset);
286
287 // Verify that second is ignored when first is set to non-zero
288 dex_files_.reset(new DexFiles(process_memory_));
289 dex_files_->SetArch(ARCH_ARM);
290 method_name = "fail";
291 method_offset = 0x123;
292 WriteDescriptor32(0xa800, 0x100000);
293 dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
294 EXPECT_EQ("fail", method_name);
295 EXPECT_EQ(0x123U, method_offset);
296 }
297
TEST_F(DexFilesTest,get_method_information_global_skip_zero_64)298 TEST_F(DexFilesTest, get_method_information_global_skip_zero_64) {
299 Init(ARCH_ARM64);
300
301 std::string method_name = "nothing";
302 uint64_t method_offset = 0x124;
303 MapInfo* info = maps_->Get(kMapDexFiles);
304
305 // First global variable found, but value is zero.
306 WriteDescriptor64(0xa800, 0);
307
308 WriteDescriptor64(0xf800, 0x200000);
309 WriteEntry64(0x200000, 0, 0, 0x300000);
310 WriteDex(0x300000);
311
312 dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
313 EXPECT_EQ("Main.<init>", method_name);
314 EXPECT_EQ(0U, method_offset);
315
316 // Verify that second is ignored when first is set to non-zero
317 dex_files_.reset(new DexFiles(process_memory_));
318 dex_files_->SetArch(ARCH_ARM64);
319 method_name = "fail";
320 method_offset = 0x123;
321 WriteDescriptor64(0xa800, 0x100000);
322 dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
323 EXPECT_EQ("fail", method_name);
324 EXPECT_EQ(0x123U, method_offset);
325 }
326
327 } // namespace unwindstack
328