blob: 0dd3af60b1d21b4676357fa6aa11439b45175d3b [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
David Srbeckyb9cc4fb2019-04-05 18:23:32 +000025#include <unwindstack/DexFiles.h>
Christopher Ferris7747b602018-01-31 19:05:19 -080026#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:
Christopher Ferrisdf683b72019-12-03 17:13:49 -080039 void CreateFakeElf(MapInfo* map_info, uint64_t global_offset, uint64_t data_offset,
40 uint64_t data_vaddr, uint64_t data_size) {
Christopher Ferris4568f4b2018-10-23 17:42:41 -070041 MemoryFake* memory = new MemoryFake;
42 ElfFake* elf = new ElfFake(memory);
43 elf->FakeSetValid(true);
44 ElfInterfaceFake* interface = new ElfInterfaceFake(memory);
45 elf->FakeSetInterface(interface);
Christopher Ferris7747b602018-01-31 19:05:19 -080046
Christopher Ferrisdf683b72019-12-03 17:13:49 -080047 interface->FakeSetGlobalVariable("__dex_debug_descriptor", global_offset);
48 interface->FakeSetDataOffset(data_offset);
49 interface->FakeSetDataVaddrStart(data_vaddr);
50 interface->FakeSetDataVaddrEnd(data_vaddr + data_size);
Christopher Ferris4568f4b2018-10-23 17:42:41 -070051 map_info->elf.reset(elf);
52 }
53
54 void Init(ArchEnum arch) {
David Srbeckyb9cc4fb2019-04-05 18:23:32 +000055 dex_files_.reset(new DexFiles(process_memory_));
56 dex_files_->SetArch(arch);
Christopher Ferris7747b602018-01-31 19:05:19 -080057
58 maps_.reset(
Christopher Ferris56d0e072018-10-17 10:57:53 -070059 new BufferMaps("1000-4000 ---s 00000000 00:00 0 /fake/elf\n"
60 "4000-6000 r--s 00000000 00:00 0 /fake/elf\n"
Christopher Ferrisdf683b72019-12-03 17:13:49 -080061 "6000-8000 -wxs 00002000 00:00 0 /fake/elf\n"
Christopher Ferris56d0e072018-10-17 10:57:53 -070062 "a000-c000 r--p 00000000 00:00 0 /fake/elf2\n"
Christopher Ferrisdf683b72019-12-03 17:13:49 -080063 "c000-f000 rw-p 00002000 00:00 0 /fake/elf2\n"
Christopher Ferris56d0e072018-10-17 10:57:53 -070064 "f000-11000 r--p 00000000 00:00 0 /fake/elf3\n"
Christopher Ferrisdf683b72019-12-03 17:13:49 -080065 "100000-110000 rw-p 00f1000 00:00 0 /fake/elf3\n"
Christopher Ferris56d0e072018-10-17 10:57:53 -070066 "200000-210000 rw-p 0002000 00:00 0 /fake/elf3\n"
67 "300000-400000 rw-p 0003000 00:00 0 /fake/elf3\n"));
Christopher Ferris7747b602018-01-31 19:05:19 -080068 ASSERT_TRUE(maps_->Parse());
69
Christopher Ferris1f34c0e2018-10-08 17:39:39 -070070 // Global variable in a section that is not readable.
71 MapInfo* map_info = maps_->Get(kMapGlobalNonReadable);
Christopher Ferris7747b602018-01-31 19:05:19 -080072 ASSERT_TRUE(map_info != nullptr);
Christopher Ferrisdf683b72019-12-03 17:13:49 -080073 CreateFakeElf(map_info, 0x2800, 0x2000, 0x2000, 0x3000);
Christopher Ferris7747b602018-01-31 19:05:19 -080074
75 // Global variable not set by default.
76 map_info = maps_->Get(kMapGlobalSetToZero);
77 ASSERT_TRUE(map_info != nullptr);
Christopher Ferrisdf683b72019-12-03 17:13:49 -080078 CreateFakeElf(map_info, 0x2800, 0x2000, 0x2000, 0x3000);
Christopher Ferris7747b602018-01-31 19:05:19 -080079
80 // Global variable set in this map.
81 map_info = maps_->Get(kMapGlobal);
82 ASSERT_TRUE(map_info != nullptr);
Christopher Ferrisdf683b72019-12-03 17:13:49 -080083 CreateFakeElf(map_info, 0xf1800, 0xf1000, 0xf1000, 0x10000);
Christopher Ferris4568f4b2018-10-23 17:42:41 -070084 }
85
86 void SetUp() override {
87 memory_ = new MemoryFake;
88 process_memory_.reset(memory_);
89
90 Init(ARCH_ARM);
Christopher Ferris7747b602018-01-31 19:05:19 -080091 }
92
David Srbeckyb9cc4fb2019-04-05 18:23:32 +000093 void WriteDescriptor32(uint64_t addr, uint32_t head);
94 void WriteDescriptor64(uint64_t addr, uint64_t head);
95 void WriteEntry32(uint64_t entry_addr, uint32_t next, uint32_t prev, uint32_t dex_file);
96 void WriteEntry64(uint64_t entry_addr, uint64_t next, uint64_t prev, uint64_t dex_file);
Christopher Ferris7747b602018-01-31 19:05:19 -080097 void WriteDex(uint64_t dex_file);
98
Christopher Ferris1f34c0e2018-10-08 17:39:39 -070099 static constexpr size_t kMapGlobalNonReadable = 2;
Christopher Ferris56d0e072018-10-17 10:57:53 -0700100 static constexpr size_t kMapGlobalSetToZero = 3;
Christopher Ferris7747b602018-01-31 19:05:19 -0800101 static constexpr size_t kMapGlobal = 5;
Christopher Ferris56d0e072018-10-17 10:57:53 -0700102 static constexpr size_t kMapGlobalRw = 6;
Christopher Ferris7747b602018-01-31 19:05:19 -0800103 static constexpr size_t kMapDexFileEntries = 7;
104 static constexpr size_t kMapDexFiles = 8;
105
106 std::shared_ptr<Memory> process_memory_;
107 MemoryFake* memory_;
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000108 std::unique_ptr<DexFiles> dex_files_;
Christopher Ferris7747b602018-01-31 19:05:19 -0800109 std::unique_ptr<BufferMaps> maps_;
110};
111
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000112void DexFilesTest::WriteDescriptor32(uint64_t addr, uint32_t head) {
113 // void* first_entry_
114 memory_->SetData32(addr + 12, head);
David Srbecky4015ef42018-02-15 17:57:16 +0000115}
116
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000117void DexFilesTest::WriteDescriptor64(uint64_t addr, uint64_t head) {
118 // void* first_entry_
119 memory_->SetData64(addr + 16, head);
David Srbecky4015ef42018-02-15 17:57:16 +0000120}
121
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000122void DexFilesTest::WriteEntry32(uint64_t entry_addr, uint32_t next, uint32_t prev,
123 uint32_t dex_file) {
124 // Format of the 32 bit DEXFileEntry structure:
Christopher Ferris7747b602018-01-31 19:05:19 -0800125 // uint32_t next
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000126 memory_->SetData32(entry_addr, next);
Christopher Ferris7747b602018-01-31 19:05:19 -0800127 // uint32_t prev
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000128 memory_->SetData32(entry_addr + 4, prev);
129 // uint32_t dex_file
130 memory_->SetData32(entry_addr + 8, dex_file);
Christopher Ferris7747b602018-01-31 19:05:19 -0800131}
132
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000133void DexFilesTest::WriteEntry64(uint64_t entry_addr, uint64_t next, uint64_t prev,
134 uint64_t dex_file) {
135 // Format of the 64 bit DEXFileEntry structure:
Christopher Ferris7747b602018-01-31 19:05:19 -0800136 // uint64_t next
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000137 memory_->SetData64(entry_addr, next);
Christopher Ferris7747b602018-01-31 19:05:19 -0800138 // uint64_t prev
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000139 memory_->SetData64(entry_addr + 8, prev);
140 // uint64_t dex_file
141 memory_->SetData64(entry_addr + 16, dex_file);
Christopher Ferris7747b602018-01-31 19:05:19 -0800142}
143
144void DexFilesTest::WriteDex(uint64_t dex_file) {
145 memory_->SetMemory(dex_file, kDexData, sizeof(kDexData) * sizeof(uint32_t));
146}
147
148TEST_F(DexFilesTest, get_method_information_invalid) {
149 std::string method_name = "nothing";
150 uint64_t method_offset = 0x124;
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000151 MapInfo* info = maps_->Get(kMapDexFileEntries);
Christopher Ferris7747b602018-01-31 19:05:19 -0800152
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000153 dex_files_->GetMethodInformation(maps_.get(), info, 0, &method_name, &method_offset);
Christopher Ferris7747b602018-01-31 19:05:19 -0800154 EXPECT_EQ("nothing", method_name);
155 EXPECT_EQ(0x124U, method_offset);
156}
157
158TEST_F(DexFilesTest, get_method_information_32) {
159 std::string method_name = "nothing";
160 uint64_t method_offset = 0x124;
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000161 MapInfo* info = maps_->Get(kMapDexFiles);
Christopher Ferris7747b602018-01-31 19:05:19 -0800162
Christopher Ferrisdf683b72019-12-03 17:13:49 -0800163 WriteDescriptor32(0x100800, 0x200000);
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000164 WriteEntry32(0x200000, 0, 0, 0x300000);
Christopher Ferris7747b602018-01-31 19:05:19 -0800165 WriteDex(0x300000);
166
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000167 dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
Christopher Ferris7747b602018-01-31 19:05:19 -0800168 EXPECT_EQ("Main.<init>", method_name);
169 EXPECT_EQ(0U, method_offset);
170}
171
172TEST_F(DexFilesTest, get_method_information_64) {
Christopher Ferris4568f4b2018-10-23 17:42:41 -0700173 Init(ARCH_ARM64);
174
Christopher Ferris7747b602018-01-31 19:05:19 -0800175 std::string method_name = "nothing";
176 uint64_t method_offset = 0x124;
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000177 MapInfo* info = maps_->Get(kMapDexFiles);
Christopher Ferris7747b602018-01-31 19:05:19 -0800178
Christopher Ferrisdf683b72019-12-03 17:13:49 -0800179 WriteDescriptor64(0x100800, 0x200000);
Christopher Ferris7747b602018-01-31 19:05:19 -0800180 WriteEntry64(0x200000, 0, 0, 0x301000);
181 WriteDex(0x301000);
182
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000183 dex_files_->GetMethodInformation(maps_.get(), info, 0x301102, &method_name, &method_offset);
Christopher Ferris7747b602018-01-31 19:05:19 -0800184 EXPECT_EQ("Main.<init>", method_name);
185 EXPECT_EQ(2U, method_offset);
186}
187
188TEST_F(DexFilesTest, get_method_information_not_first_entry_32) {
189 std::string method_name = "nothing";
190 uint64_t method_offset = 0x124;
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000191 MapInfo* info = maps_->Get(kMapDexFiles);
Christopher Ferris7747b602018-01-31 19:05:19 -0800192
Christopher Ferrisdf683b72019-12-03 17:13:49 -0800193 WriteDescriptor32(0x100800, 0x200000);
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000194 WriteEntry32(0x200000, 0x200100, 0, 0x100000);
195 WriteEntry32(0x200100, 0, 0x200000, 0x300000);
Christopher Ferris7747b602018-01-31 19:05:19 -0800196 WriteDex(0x300000);
197
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000198 dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset);
Christopher Ferris7747b602018-01-31 19:05:19 -0800199 EXPECT_EQ("Main.<init>", method_name);
200 EXPECT_EQ(4U, method_offset);
201}
202
203TEST_F(DexFilesTest, get_method_information_not_first_entry_64) {
Christopher Ferris4568f4b2018-10-23 17:42:41 -0700204 Init(ARCH_ARM64);
205
Christopher Ferris7747b602018-01-31 19:05:19 -0800206 std::string method_name = "nothing";
207 uint64_t method_offset = 0x124;
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000208 MapInfo* info = maps_->Get(kMapDexFiles);
Christopher Ferris7747b602018-01-31 19:05:19 -0800209
Christopher Ferrisdf683b72019-12-03 17:13:49 -0800210 WriteDescriptor64(0x100800, 0x200000);
Christopher Ferris7747b602018-01-31 19:05:19 -0800211 WriteEntry64(0x200000, 0x200100, 0, 0x100000);
212 WriteEntry64(0x200100, 0, 0x200000, 0x300000);
213 WriteDex(0x300000);
214
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000215 dex_files_->GetMethodInformation(maps_.get(), info, 0x300106, &method_name, &method_offset);
Christopher Ferris7747b602018-01-31 19:05:19 -0800216 EXPECT_EQ("Main.<init>", method_name);
217 EXPECT_EQ(6U, method_offset);
218}
219
220TEST_F(DexFilesTest, get_method_information_cached) {
221 std::string method_name = "nothing";
222 uint64_t method_offset = 0x124;
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000223 MapInfo* info = maps_->Get(kMapDexFiles);
Christopher Ferris7747b602018-01-31 19:05:19 -0800224
Christopher Ferrisdf683b72019-12-03 17:13:49 -0800225 WriteDescriptor32(0x100800, 0x200000);
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000226 WriteEntry32(0x200000, 0, 0, 0x300000);
Christopher Ferris7747b602018-01-31 19:05:19 -0800227 WriteDex(0x300000);
228
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000229 dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
Christopher Ferris7747b602018-01-31 19:05:19 -0800230 EXPECT_EQ("Main.<init>", method_name);
231 EXPECT_EQ(0U, method_offset);
232
233 // Clear all memory and make sure that data is acquired from the cache.
234 memory_->Clear();
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000235 dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
Christopher Ferris7747b602018-01-31 19:05:19 -0800236 EXPECT_EQ("Main.<init>", method_name);
237 EXPECT_EQ(0U, method_offset);
238}
239
240TEST_F(DexFilesTest, get_method_information_search_libs) {
241 std::string method_name = "nothing";
242 uint64_t method_offset = 0x124;
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000243 MapInfo* info = maps_->Get(kMapDexFiles);
Christopher Ferris7747b602018-01-31 19:05:19 -0800244
Christopher Ferrisdf683b72019-12-03 17:13:49 -0800245 WriteDescriptor32(0x100800, 0x200000);
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000246 WriteEntry32(0x200000, 0x200100, 0, 0x100000);
247 WriteEntry32(0x200100, 0, 0x200000, 0x300000);
Christopher Ferris7747b602018-01-31 19:05:19 -0800248 WriteDex(0x300000);
249
250 // Only search a given named list of libs.
251 std::vector<std::string> libs{"libart.so"};
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000252 dex_files_.reset(new DexFiles(process_memory_, libs));
253 dex_files_->SetArch(ARCH_ARM);
Christopher Ferris7747b602018-01-31 19:05:19 -0800254
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000255 dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset);
Christopher Ferris7747b602018-01-31 19:05:19 -0800256 EXPECT_EQ("nothing", method_name);
257 EXPECT_EQ(0x124U, method_offset);
258
259 MapInfo* map_info = maps_->Get(kMapGlobal);
260 map_info->name = "/system/lib/libart.so";
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000261 dex_files_.reset(new DexFiles(process_memory_, libs));
262 dex_files_->SetArch(ARCH_ARM);
Christopher Ferris56d0e072018-10-17 10:57:53 -0700263 // Set the rw map to the same name or this will not scan this entry.
264 map_info = maps_->Get(kMapGlobalRw);
265 map_info->name = "/system/lib/libart.so";
Christopher Ferris7747b602018-01-31 19:05:19 -0800266 // Make sure that clearing out copy of the libs doesn't affect the
267 // DexFiles object.
268 libs.clear();
269
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000270 dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset);
Christopher Ferris7747b602018-01-31 19:05:19 -0800271 EXPECT_EQ("Main.<init>", method_name);
272 EXPECT_EQ(4U, method_offset);
273}
274
275TEST_F(DexFilesTest, get_method_information_global_skip_zero_32) {
276 std::string method_name = "nothing";
277 uint64_t method_offset = 0x124;
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000278 MapInfo* info = maps_->Get(kMapDexFiles);
Christopher Ferris7747b602018-01-31 19:05:19 -0800279
280 // First global variable found, but value is zero.
Christopher Ferrisdf683b72019-12-03 17:13:49 -0800281 WriteDescriptor32(0xc800, 0);
Christopher Ferris7747b602018-01-31 19:05:19 -0800282
Christopher Ferrisdf683b72019-12-03 17:13:49 -0800283 WriteDescriptor32(0x100800, 0x200000);
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000284 WriteEntry32(0x200000, 0, 0, 0x300000);
Christopher Ferris7747b602018-01-31 19:05:19 -0800285 WriteDex(0x300000);
286
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000287 dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
Christopher Ferris7747b602018-01-31 19:05:19 -0800288 EXPECT_EQ("Main.<init>", method_name);
289 EXPECT_EQ(0U, method_offset);
290
291 // Verify that second is ignored when first is set to non-zero
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000292 dex_files_.reset(new DexFiles(process_memory_));
293 dex_files_->SetArch(ARCH_ARM);
Christopher Ferris7747b602018-01-31 19:05:19 -0800294 method_name = "fail";
295 method_offset = 0x123;
Christopher Ferrisdf683b72019-12-03 17:13:49 -0800296 WriteDescriptor32(0xc800, 0x100000);
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000297 dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
Christopher Ferris7747b602018-01-31 19:05:19 -0800298 EXPECT_EQ("fail", method_name);
299 EXPECT_EQ(0x123U, method_offset);
300}
301
302TEST_F(DexFilesTest, get_method_information_global_skip_zero_64) {
Christopher Ferris4568f4b2018-10-23 17:42:41 -0700303 Init(ARCH_ARM64);
304
Christopher Ferris7747b602018-01-31 19:05:19 -0800305 std::string method_name = "nothing";
306 uint64_t method_offset = 0x124;
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000307 MapInfo* info = maps_->Get(kMapDexFiles);
Christopher Ferris7747b602018-01-31 19:05:19 -0800308
309 // First global variable found, but value is zero.
Christopher Ferrisdf683b72019-12-03 17:13:49 -0800310 WriteDescriptor64(0xc800, 0);
Christopher Ferris7747b602018-01-31 19:05:19 -0800311
Christopher Ferrisdf683b72019-12-03 17:13:49 -0800312 WriteDescriptor64(0x100800, 0x200000);
Christopher Ferris7747b602018-01-31 19:05:19 -0800313 WriteEntry64(0x200000, 0, 0, 0x300000);
314 WriteDex(0x300000);
315
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000316 dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
Christopher Ferris7747b602018-01-31 19:05:19 -0800317 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
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000321 dex_files_.reset(new DexFiles(process_memory_));
322 dex_files_->SetArch(ARCH_ARM64);
Christopher Ferris7747b602018-01-31 19:05:19 -0800323 method_name = "fail";
324 method_offset = 0x123;
Christopher Ferrisdf683b72019-12-03 17:13:49 -0800325 WriteDescriptor64(0xc800, 0x100000);
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000326 dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
Christopher Ferris7747b602018-01-31 19:05:19 -0800327 EXPECT_EQ("fail", method_name);
328 EXPECT_EQ(0x123U, method_offset);
329}
330
331} // namespace unwindstack