blob: 3ac3ca61b5a6100338cd31955b25b7dc836a6eef [file] [log] [blame]
Christopher Ferris7747b602018-01-31 19:05:19 -08001/*
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
35namespace unwindstack {
36
37class DexFilesTest : public ::testing::Test {
38 protected:
39 void SetUp() override {
40 memory_ = new MemoryFake;
41 process_memory_.reset(memory_);
42
43 dex_files_.reset(new DexFiles(process_memory_));
44 dex_files_->SetArch(ARCH_ARM);
45
46 maps_.reset(
Christopher Ferris56d0e072018-10-17 10:57:53 -070047 new BufferMaps("1000-4000 ---s 00000000 00:00 0 /fake/elf\n"
48 "4000-6000 r--s 00000000 00:00 0 /fake/elf\n"
49 "6000-8000 -wxs 00000000 00:00 0 /fake/elf\n"
50 "a000-c000 r--p 00000000 00:00 0 /fake/elf2\n"
51 "c000-f000 rw-p 00001000 00:00 0 /fake/elf2\n"
52 "f000-11000 r--p 00000000 00:00 0 /fake/elf3\n"
53 "100000-110000 rw-p 0001000 00:00 0 /fake/elf3\n"
54 "200000-210000 rw-p 0002000 00:00 0 /fake/elf3\n"
55 "300000-400000 rw-p 0003000 00:00 0 /fake/elf3\n"));
Christopher Ferris7747b602018-01-31 19:05:19 -080056 ASSERT_TRUE(maps_->Parse());
57
Christopher Ferris1f34c0e2018-10-08 17:39:39 -070058 // Global variable in a section that is not readable.
59 MapInfo* map_info = maps_->Get(kMapGlobalNonReadable);
Christopher Ferris7747b602018-01-31 19:05:19 -080060 ASSERT_TRUE(map_info != nullptr);
61 MemoryFake* memory = new MemoryFake;
62 ElfFake* elf = new ElfFake(memory);
63 elf->FakeSetValid(true);
64 ElfInterfaceFake* interface = new ElfInterfaceFake(memory);
65 elf->FakeSetInterface(interface);
David Srbecky4015ef42018-02-15 17:57:16 +000066 interface->FakeSetGlobalVariable("__dex_debug_descriptor", 0x800);
Christopher Ferris7747b602018-01-31 19:05:19 -080067 map_info->elf.reset(elf);
68
69 // Global variable not set by default.
70 map_info = maps_->Get(kMapGlobalSetToZero);
71 ASSERT_TRUE(map_info != nullptr);
72 memory = new MemoryFake;
73 elf = new ElfFake(memory);
74 elf->FakeSetValid(true);
75 interface = new ElfInterfaceFake(memory);
76 elf->FakeSetInterface(interface);
David Srbecky4015ef42018-02-15 17:57:16 +000077 interface->FakeSetGlobalVariable("__dex_debug_descriptor", 0x800);
Christopher Ferris7747b602018-01-31 19:05:19 -080078 map_info->elf.reset(elf);
79
80 // Global variable set in this map.
81 map_info = maps_->Get(kMapGlobal);
82 ASSERT_TRUE(map_info != nullptr);
83 memory = new MemoryFake;
84 elf = new ElfFake(memory);
85 elf->FakeSetValid(true);
86 interface = new ElfInterfaceFake(memory);
87 elf->FakeSetInterface(interface);
David Srbecky4015ef42018-02-15 17:57:16 +000088 interface->FakeSetGlobalVariable("__dex_debug_descriptor", 0x800);
Christopher Ferris7747b602018-01-31 19:05:19 -080089 map_info->elf.reset(elf);
90 }
91
David Srbecky4015ef42018-02-15 17:57:16 +000092 void WriteDescriptor32(uint64_t addr, uint32_t head);
93 void WriteDescriptor64(uint64_t addr, uint64_t head);
Christopher Ferris7747b602018-01-31 19:05:19 -080094 void WriteEntry32(uint64_t entry_addr, uint32_t next, uint32_t prev, uint32_t dex_file);
95 void WriteEntry64(uint64_t entry_addr, uint64_t next, uint64_t prev, uint64_t dex_file);
96 void WriteDex(uint64_t dex_file);
97
Christopher Ferris1f34c0e2018-10-08 17:39:39 -070098 static constexpr size_t kMapGlobalNonReadable = 2;
Christopher Ferris56d0e072018-10-17 10:57:53 -070099 static constexpr size_t kMapGlobalSetToZero = 3;
Christopher Ferris7747b602018-01-31 19:05:19 -0800100 static constexpr size_t kMapGlobal = 5;
Christopher Ferris56d0e072018-10-17 10:57:53 -0700101 static constexpr size_t kMapGlobalRw = 6;
Christopher Ferris7747b602018-01-31 19:05:19 -0800102 static constexpr size_t kMapDexFileEntries = 7;
103 static constexpr size_t kMapDexFiles = 8;
104
105 std::shared_ptr<Memory> process_memory_;
106 MemoryFake* memory_;
107 std::unique_ptr<DexFiles> dex_files_;
108 std::unique_ptr<BufferMaps> maps_;
109};
110
David Srbecky4015ef42018-02-15 17:57:16 +0000111void DexFilesTest::WriteDescriptor32(uint64_t addr, uint32_t head) {
112 // void* first_entry_
113 memory_->SetData32(addr + 12, head);
114}
115
116void DexFilesTest::WriteDescriptor64(uint64_t addr, uint64_t head) {
117 // void* first_entry_
118 memory_->SetData64(addr + 16, head);
119}
120
Christopher Ferris7747b602018-01-31 19:05:19 -0800121void DexFilesTest::WriteEntry32(uint64_t entry_addr, uint32_t next, uint32_t prev,
122 uint32_t dex_file) {
123 // Format of the 32 bit DEXFileEntry structure:
124 // uint32_t next
125 memory_->SetData32(entry_addr, next);
126 // uint32_t prev
127 memory_->SetData32(entry_addr + 4, prev);
128 // uint32_t dex_file
129 memory_->SetData32(entry_addr + 8, dex_file);
130}
131
132void DexFilesTest::WriteEntry64(uint64_t entry_addr, uint64_t next, uint64_t prev,
133 uint64_t dex_file) {
134 // Format of the 64 bit DEXFileEntry structure:
135 // uint64_t next
136 memory_->SetData64(entry_addr, next);
137 // uint64_t prev
138 memory_->SetData64(entry_addr + 8, prev);
139 // uint64_t dex_file
140 memory_->SetData64(entry_addr + 16, dex_file);
141}
142
143void DexFilesTest::WriteDex(uint64_t dex_file) {
144 memory_->SetMemory(dex_file, kDexData, sizeof(kDexData) * sizeof(uint32_t));
145}
146
147TEST_F(DexFilesTest, get_method_information_invalid) {
148 std::string method_name = "nothing";
149 uint64_t method_offset = 0x124;
150 MapInfo* info = maps_->Get(kMapDexFileEntries);
151
152 dex_files_->GetMethodInformation(maps_.get(), info, 0, &method_name, &method_offset);
153 EXPECT_EQ("nothing", method_name);
154 EXPECT_EQ(0x124U, method_offset);
155}
156
157TEST_F(DexFilesTest, get_method_information_32) {
158 std::string method_name = "nothing";
159 uint64_t method_offset = 0x124;
160 MapInfo* info = maps_->Get(kMapDexFiles);
161
David Srbecky4015ef42018-02-15 17:57:16 +0000162 WriteDescriptor32(0xf800, 0x200000);
Christopher Ferris7747b602018-01-31 19:05:19 -0800163 WriteEntry32(0x200000, 0, 0, 0x300000);
164 WriteDex(0x300000);
165
166 dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
167 EXPECT_EQ("Main.<init>", method_name);
168 EXPECT_EQ(0U, method_offset);
169}
170
171TEST_F(DexFilesTest, get_method_information_64) {
172 std::string method_name = "nothing";
173 uint64_t method_offset = 0x124;
174 MapInfo* info = maps_->Get(kMapDexFiles);
175
176 dex_files_->SetArch(ARCH_ARM64);
David Srbecky4015ef42018-02-15 17:57:16 +0000177 WriteDescriptor64(0xf800, 0x200000);
Christopher Ferris7747b602018-01-31 19:05:19 -0800178 WriteEntry64(0x200000, 0, 0, 0x301000);
179 WriteDex(0x301000);
180
181 dex_files_->GetMethodInformation(maps_.get(), info, 0x301102, &method_name, &method_offset);
182 EXPECT_EQ("Main.<init>", method_name);
183 EXPECT_EQ(2U, method_offset);
184}
185
186TEST_F(DexFilesTest, get_method_information_not_first_entry_32) {
187 std::string method_name = "nothing";
188 uint64_t method_offset = 0x124;
189 MapInfo* info = maps_->Get(kMapDexFiles);
190
David Srbecky4015ef42018-02-15 17:57:16 +0000191 WriteDescriptor32(0xf800, 0x200000);
Christopher Ferris7747b602018-01-31 19:05:19 -0800192 WriteEntry32(0x200000, 0x200100, 0, 0x100000);
193 WriteEntry32(0x200100, 0, 0x200000, 0x300000);
194 WriteDex(0x300000);
195
196 dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset);
197 EXPECT_EQ("Main.<init>", method_name);
198 EXPECT_EQ(4U, method_offset);
199}
200
201TEST_F(DexFilesTest, get_method_information_not_first_entry_64) {
202 std::string method_name = "nothing";
203 uint64_t method_offset = 0x124;
204 MapInfo* info = maps_->Get(kMapDexFiles);
205
206 dex_files_->SetArch(ARCH_ARM64);
David Srbecky4015ef42018-02-15 17:57:16 +0000207 WriteDescriptor64(0xf800, 0x200000);
Christopher Ferris7747b602018-01-31 19:05:19 -0800208 WriteEntry64(0x200000, 0x200100, 0, 0x100000);
209 WriteEntry64(0x200100, 0, 0x200000, 0x300000);
210 WriteDex(0x300000);
211
212 dex_files_->GetMethodInformation(maps_.get(), info, 0x300106, &method_name, &method_offset);
213 EXPECT_EQ("Main.<init>", method_name);
214 EXPECT_EQ(6U, method_offset);
215}
216
217TEST_F(DexFilesTest, get_method_information_cached) {
218 std::string method_name = "nothing";
219 uint64_t method_offset = 0x124;
220 MapInfo* info = maps_->Get(kMapDexFiles);
221
David Srbecky4015ef42018-02-15 17:57:16 +0000222 WriteDescriptor32(0xf800, 0x200000);
Christopher Ferris7747b602018-01-31 19:05:19 -0800223 WriteEntry32(0x200000, 0, 0, 0x300000);
224 WriteDex(0x300000);
225
226 dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
227 EXPECT_EQ("Main.<init>", method_name);
228 EXPECT_EQ(0U, method_offset);
229
230 // Clear all memory and make sure that data is acquired from the cache.
231 memory_->Clear();
232 dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
233 EXPECT_EQ("Main.<init>", method_name);
234 EXPECT_EQ(0U, method_offset);
235}
236
237TEST_F(DexFilesTest, get_method_information_search_libs) {
238 std::string method_name = "nothing";
239 uint64_t method_offset = 0x124;
240 MapInfo* info = maps_->Get(kMapDexFiles);
241
David Srbecky4015ef42018-02-15 17:57:16 +0000242 WriteDescriptor32(0xf800, 0x200000);
Christopher Ferris7747b602018-01-31 19:05:19 -0800243 WriteEntry32(0x200000, 0x200100, 0, 0x100000);
244 WriteEntry32(0x200100, 0, 0x200000, 0x300000);
245 WriteDex(0x300000);
246
247 // Only search a given named list of libs.
248 std::vector<std::string> libs{"libart.so"};
249 dex_files_.reset(new DexFiles(process_memory_, libs));
250 dex_files_->SetArch(ARCH_ARM);
251
252 dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset);
253 EXPECT_EQ("nothing", method_name);
254 EXPECT_EQ(0x124U, method_offset);
255
256 MapInfo* map_info = maps_->Get(kMapGlobal);
257 map_info->name = "/system/lib/libart.so";
258 dex_files_.reset(new DexFiles(process_memory_, libs));
259 dex_files_->SetArch(ARCH_ARM);
Christopher Ferris56d0e072018-10-17 10:57:53 -0700260 // Set the rw map to the same name or this will not scan this entry.
261 map_info = maps_->Get(kMapGlobalRw);
262 map_info->name = "/system/lib/libart.so";
Christopher Ferris7747b602018-01-31 19:05:19 -0800263 // Make sure that clearing out copy of the libs doesn't affect the
264 // DexFiles object.
265 libs.clear();
266
267 dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset);
268 EXPECT_EQ("Main.<init>", method_name);
269 EXPECT_EQ(4U, method_offset);
270}
271
272TEST_F(DexFilesTest, get_method_information_global_skip_zero_32) {
273 std::string method_name = "nothing";
274 uint64_t method_offset = 0x124;
275 MapInfo* info = maps_->Get(kMapDexFiles);
276
277 // First global variable found, but value is zero.
Christopher Ferris56d0e072018-10-17 10:57:53 -0700278 WriteDescriptor32(0xa800, 0);
Christopher Ferris7747b602018-01-31 19:05:19 -0800279
David Srbecky4015ef42018-02-15 17:57:16 +0000280 WriteDescriptor32(0xf800, 0x200000);
Christopher Ferris7747b602018-01-31 19:05:19 -0800281 WriteEntry32(0x200000, 0, 0, 0x300000);
282 WriteDex(0x300000);
283
284 dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
285 EXPECT_EQ("Main.<init>", method_name);
286 EXPECT_EQ(0U, method_offset);
287
288 // Verify that second is ignored when first is set to non-zero
289 dex_files_.reset(new DexFiles(process_memory_));
290 dex_files_->SetArch(ARCH_ARM);
291 method_name = "fail";
292 method_offset = 0x123;
Christopher Ferris56d0e072018-10-17 10:57:53 -0700293 WriteDescriptor32(0xa800, 0x100000);
Christopher Ferris7747b602018-01-31 19:05:19 -0800294 dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
295 EXPECT_EQ("fail", method_name);
296 EXPECT_EQ(0x123U, method_offset);
297}
298
299TEST_F(DexFilesTest, get_method_information_global_skip_zero_64) {
300 std::string method_name = "nothing";
301 uint64_t method_offset = 0x124;
302 MapInfo* info = maps_->Get(kMapDexFiles);
303
304 // First global variable found, but value is zero.
Christopher Ferris56d0e072018-10-17 10:57:53 -0700305 WriteDescriptor64(0xa800, 0);
Christopher Ferris7747b602018-01-31 19:05:19 -0800306
David Srbecky4015ef42018-02-15 17:57:16 +0000307 WriteDescriptor64(0xf800, 0x200000);
Christopher Ferris7747b602018-01-31 19:05:19 -0800308 WriteEntry64(0x200000, 0, 0, 0x300000);
309 WriteDex(0x300000);
310
311 dex_files_->SetArch(ARCH_ARM64);
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;
Christopher Ferris56d0e072018-10-17 10:57:53 -0700321 WriteDescriptor64(0xa800, 0x100000);
Christopher Ferris7747b602018-01-31 19:05:19 -0800322 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