blob: 1ea9e5c03a84f9b2ba8cf52e8704c8f3b5da86f0 [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 Ferris4568f4b2018-10-23 17:42:41 -070039 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);
Christopher Ferris7747b602018-01-31 19:05:19 -080045
Christopher Ferris4568f4b2018-10-23 17:42:41 -070046 interface->FakeSetGlobalVariable("__dex_debug_descriptor", 0x800);
47 map_info->elf.reset(elf);
48 }
49
50 void Init(ArchEnum arch) {
David Srbeckyb9cc4fb2019-04-05 18:23:32 +000051 dex_files_.reset(new DexFiles(process_memory_));
52 dex_files_->SetArch(arch);
Christopher Ferris7747b602018-01-31 19:05:19 -080053
54 maps_.reset(
Christopher Ferris56d0e072018-10-17 10:57:53 -070055 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"));
Christopher Ferris7747b602018-01-31 19:05:19 -080064 ASSERT_TRUE(maps_->Parse());
65
Christopher Ferris1f34c0e2018-10-08 17:39:39 -070066 // Global variable in a section that is not readable.
67 MapInfo* map_info = maps_->Get(kMapGlobalNonReadable);
Christopher Ferris7747b602018-01-31 19:05:19 -080068 ASSERT_TRUE(map_info != nullptr);
Christopher Ferris4568f4b2018-10-23 17:42:41 -070069 CreateFakeElf(map_info);
Christopher Ferris7747b602018-01-31 19:05:19 -080070
71 // Global variable not set by default.
72 map_info = maps_->Get(kMapGlobalSetToZero);
73 ASSERT_TRUE(map_info != nullptr);
Christopher Ferris4568f4b2018-10-23 17:42:41 -070074 CreateFakeElf(map_info);
Christopher Ferris7747b602018-01-31 19:05:19 -080075
76 // Global variable set in this map.
77 map_info = maps_->Get(kMapGlobal);
78 ASSERT_TRUE(map_info != nullptr);
Christopher Ferris4568f4b2018-10-23 17:42:41 -070079 CreateFakeElf(map_info);
80 }
81
82 void SetUp() override {
83 memory_ = new MemoryFake;
84 process_memory_.reset(memory_);
85
86 Init(ARCH_ARM);
Christopher Ferris7747b602018-01-31 19:05:19 -080087 }
88
David Srbeckyb9cc4fb2019-04-05 18:23:32 +000089 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);
Christopher Ferris7747b602018-01-31 19:05:19 -080093 void WriteDex(uint64_t dex_file);
94
Christopher Ferris1f34c0e2018-10-08 17:39:39 -070095 static constexpr size_t kMapGlobalNonReadable = 2;
Christopher Ferris56d0e072018-10-17 10:57:53 -070096 static constexpr size_t kMapGlobalSetToZero = 3;
Christopher Ferris7747b602018-01-31 19:05:19 -080097 static constexpr size_t kMapGlobal = 5;
Christopher Ferris56d0e072018-10-17 10:57:53 -070098 static constexpr size_t kMapGlobalRw = 6;
Christopher Ferris7747b602018-01-31 19:05:19 -080099 static constexpr size_t kMapDexFileEntries = 7;
100 static constexpr size_t kMapDexFiles = 8;
101
102 std::shared_ptr<Memory> process_memory_;
103 MemoryFake* memory_;
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000104 std::unique_ptr<DexFiles> dex_files_;
Christopher Ferris7747b602018-01-31 19:05:19 -0800105 std::unique_ptr<BufferMaps> maps_;
106};
107
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000108void DexFilesTest::WriteDescriptor32(uint64_t addr, uint32_t head) {
109 // void* first_entry_
110 memory_->SetData32(addr + 12, head);
David Srbecky4015ef42018-02-15 17:57:16 +0000111}
112
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000113void DexFilesTest::WriteDescriptor64(uint64_t addr, uint64_t head) {
114 // void* first_entry_
115 memory_->SetData64(addr + 16, head);
David Srbecky4015ef42018-02-15 17:57:16 +0000116}
117
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000118void 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:
Christopher Ferris7747b602018-01-31 19:05:19 -0800121 // uint32_t next
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000122 memory_->SetData32(entry_addr, next);
Christopher Ferris7747b602018-01-31 19:05:19 -0800123 // uint32_t prev
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000124 memory_->SetData32(entry_addr + 4, prev);
125 // uint32_t dex_file
126 memory_->SetData32(entry_addr + 8, dex_file);
Christopher Ferris7747b602018-01-31 19:05:19 -0800127}
128
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000129void 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:
Christopher Ferris7747b602018-01-31 19:05:19 -0800132 // uint64_t next
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000133 memory_->SetData64(entry_addr, next);
Christopher Ferris7747b602018-01-31 19:05:19 -0800134 // uint64_t prev
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000135 memory_->SetData64(entry_addr + 8, prev);
136 // uint64_t dex_file
137 memory_->SetData64(entry_addr + 16, dex_file);
Christopher Ferris7747b602018-01-31 19:05:19 -0800138}
139
140void DexFilesTest::WriteDex(uint64_t dex_file) {
141 memory_->SetMemory(dex_file, kDexData, sizeof(kDexData) * sizeof(uint32_t));
142}
143
144TEST_F(DexFilesTest, get_method_information_invalid) {
145 std::string method_name = "nothing";
146 uint64_t method_offset = 0x124;
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000147 MapInfo* info = maps_->Get(kMapDexFileEntries);
Christopher Ferris7747b602018-01-31 19:05:19 -0800148
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000149 dex_files_->GetMethodInformation(maps_.get(), info, 0, &method_name, &method_offset);
Christopher Ferris7747b602018-01-31 19:05:19 -0800150 EXPECT_EQ("nothing", method_name);
151 EXPECT_EQ(0x124U, method_offset);
152}
153
154TEST_F(DexFilesTest, get_method_information_32) {
155 std::string method_name = "nothing";
156 uint64_t method_offset = 0x124;
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000157 MapInfo* info = maps_->Get(kMapDexFiles);
Christopher Ferris7747b602018-01-31 19:05:19 -0800158
David Srbecky4015ef42018-02-15 17:57:16 +0000159 WriteDescriptor32(0xf800, 0x200000);
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000160 WriteEntry32(0x200000, 0, 0, 0x300000);
Christopher Ferris7747b602018-01-31 19:05:19 -0800161 WriteDex(0x300000);
162
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000163 dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
Christopher Ferris7747b602018-01-31 19:05:19 -0800164 EXPECT_EQ("Main.<init>", method_name);
165 EXPECT_EQ(0U, method_offset);
166}
167
168TEST_F(DexFilesTest, get_method_information_64) {
Christopher Ferris4568f4b2018-10-23 17:42:41 -0700169 Init(ARCH_ARM64);
170
Christopher Ferris7747b602018-01-31 19:05:19 -0800171 std::string method_name = "nothing";
172 uint64_t method_offset = 0x124;
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000173 MapInfo* info = maps_->Get(kMapDexFiles);
Christopher Ferris7747b602018-01-31 19:05:19 -0800174
David Srbecky4015ef42018-02-15 17:57:16 +0000175 WriteDescriptor64(0xf800, 0x200000);
Christopher Ferris7747b602018-01-31 19:05:19 -0800176 WriteEntry64(0x200000, 0, 0, 0x301000);
177 WriteDex(0x301000);
178
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000179 dex_files_->GetMethodInformation(maps_.get(), info, 0x301102, &method_name, &method_offset);
Christopher Ferris7747b602018-01-31 19:05:19 -0800180 EXPECT_EQ("Main.<init>", method_name);
181 EXPECT_EQ(2U, method_offset);
182}
183
184TEST_F(DexFilesTest, get_method_information_not_first_entry_32) {
185 std::string method_name = "nothing";
186 uint64_t method_offset = 0x124;
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000187 MapInfo* info = maps_->Get(kMapDexFiles);
Christopher Ferris7747b602018-01-31 19:05:19 -0800188
David Srbecky4015ef42018-02-15 17:57:16 +0000189 WriteDescriptor32(0xf800, 0x200000);
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000190 WriteEntry32(0x200000, 0x200100, 0, 0x100000);
191 WriteEntry32(0x200100, 0, 0x200000, 0x300000);
Christopher Ferris7747b602018-01-31 19:05:19 -0800192 WriteDex(0x300000);
193
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000194 dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset);
Christopher Ferris7747b602018-01-31 19:05:19 -0800195 EXPECT_EQ("Main.<init>", method_name);
196 EXPECT_EQ(4U, method_offset);
197}
198
199TEST_F(DexFilesTest, get_method_information_not_first_entry_64) {
Christopher Ferris4568f4b2018-10-23 17:42:41 -0700200 Init(ARCH_ARM64);
201
Christopher Ferris7747b602018-01-31 19:05:19 -0800202 std::string method_name = "nothing";
203 uint64_t method_offset = 0x124;
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000204 MapInfo* info = maps_->Get(kMapDexFiles);
Christopher Ferris7747b602018-01-31 19:05:19 -0800205
David Srbecky4015ef42018-02-15 17:57:16 +0000206 WriteDescriptor64(0xf800, 0x200000);
Christopher Ferris7747b602018-01-31 19:05:19 -0800207 WriteEntry64(0x200000, 0x200100, 0, 0x100000);
208 WriteEntry64(0x200100, 0, 0x200000, 0x300000);
209 WriteDex(0x300000);
210
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000211 dex_files_->GetMethodInformation(maps_.get(), info, 0x300106, &method_name, &method_offset);
Christopher Ferris7747b602018-01-31 19:05:19 -0800212 EXPECT_EQ("Main.<init>", method_name);
213 EXPECT_EQ(6U, method_offset);
214}
215
216TEST_F(DexFilesTest, get_method_information_cached) {
217 std::string method_name = "nothing";
218 uint64_t method_offset = 0x124;
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000219 MapInfo* info = maps_->Get(kMapDexFiles);
Christopher Ferris7747b602018-01-31 19:05:19 -0800220
David Srbecky4015ef42018-02-15 17:57:16 +0000221 WriteDescriptor32(0xf800, 0x200000);
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000222 WriteEntry32(0x200000, 0, 0, 0x300000);
Christopher Ferris7747b602018-01-31 19:05:19 -0800223 WriteDex(0x300000);
224
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000225 dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
Christopher Ferris7747b602018-01-31 19:05:19 -0800226 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();
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000231 dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
Christopher Ferris7747b602018-01-31 19:05:19 -0800232 EXPECT_EQ("Main.<init>", method_name);
233 EXPECT_EQ(0U, method_offset);
234}
235
236TEST_F(DexFilesTest, get_method_information_search_libs) {
237 std::string method_name = "nothing";
238 uint64_t method_offset = 0x124;
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000239 MapInfo* info = maps_->Get(kMapDexFiles);
Christopher Ferris7747b602018-01-31 19:05:19 -0800240
David Srbecky4015ef42018-02-15 17:57:16 +0000241 WriteDescriptor32(0xf800, 0x200000);
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000242 WriteEntry32(0x200000, 0x200100, 0, 0x100000);
243 WriteEntry32(0x200100, 0, 0x200000, 0x300000);
Christopher Ferris7747b602018-01-31 19:05:19 -0800244 WriteDex(0x300000);
245
246 // Only search a given named list of libs.
247 std::vector<std::string> libs{"libart.so"};
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000248 dex_files_.reset(new DexFiles(process_memory_, libs));
249 dex_files_->SetArch(ARCH_ARM);
Christopher Ferris7747b602018-01-31 19:05:19 -0800250
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000251 dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset);
Christopher Ferris7747b602018-01-31 19:05:19 -0800252 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";
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000257 dex_files_.reset(new DexFiles(process_memory_, libs));
258 dex_files_->SetArch(ARCH_ARM);
Christopher Ferris56d0e072018-10-17 10:57:53 -0700259 // 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";
Christopher Ferris7747b602018-01-31 19:05:19 -0800262 // Make sure that clearing out copy of the libs doesn't affect the
263 // DexFiles object.
264 libs.clear();
265
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000266 dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset);
Christopher Ferris7747b602018-01-31 19:05:19 -0800267 EXPECT_EQ("Main.<init>", method_name);
268 EXPECT_EQ(4U, method_offset);
269}
270
271TEST_F(DexFilesTest, get_method_information_global_skip_zero_32) {
272 std::string method_name = "nothing";
273 uint64_t method_offset = 0x124;
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000274 MapInfo* info = maps_->Get(kMapDexFiles);
Christopher Ferris7747b602018-01-31 19:05:19 -0800275
276 // First global variable found, but value is zero.
Christopher Ferris56d0e072018-10-17 10:57:53 -0700277 WriteDescriptor32(0xa800, 0);
Christopher Ferris7747b602018-01-31 19:05:19 -0800278
David Srbecky4015ef42018-02-15 17:57:16 +0000279 WriteDescriptor32(0xf800, 0x200000);
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000280 WriteEntry32(0x200000, 0, 0, 0x300000);
Christopher Ferris7747b602018-01-31 19:05:19 -0800281 WriteDex(0x300000);
282
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000283 dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
Christopher Ferris7747b602018-01-31 19:05:19 -0800284 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
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000288 dex_files_.reset(new DexFiles(process_memory_));
289 dex_files_->SetArch(ARCH_ARM);
Christopher Ferris7747b602018-01-31 19:05:19 -0800290 method_name = "fail";
291 method_offset = 0x123;
Christopher Ferris56d0e072018-10-17 10:57:53 -0700292 WriteDescriptor32(0xa800, 0x100000);
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000293 dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
Christopher Ferris7747b602018-01-31 19:05:19 -0800294 EXPECT_EQ("fail", method_name);
295 EXPECT_EQ(0x123U, method_offset);
296}
297
298TEST_F(DexFilesTest, get_method_information_global_skip_zero_64) {
Christopher Ferris4568f4b2018-10-23 17:42:41 -0700299 Init(ARCH_ARM64);
300
Christopher Ferris7747b602018-01-31 19:05:19 -0800301 std::string method_name = "nothing";
302 uint64_t method_offset = 0x124;
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000303 MapInfo* info = maps_->Get(kMapDexFiles);
Christopher Ferris7747b602018-01-31 19:05:19 -0800304
305 // First global variable found, but value is zero.
Christopher Ferris56d0e072018-10-17 10:57:53 -0700306 WriteDescriptor64(0xa800, 0);
Christopher Ferris7747b602018-01-31 19:05:19 -0800307
David Srbecky4015ef42018-02-15 17:57:16 +0000308 WriteDescriptor64(0xf800, 0x200000);
Christopher Ferris7747b602018-01-31 19:05:19 -0800309 WriteEntry64(0x200000, 0, 0, 0x300000);
310 WriteDex(0x300000);
311
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000312 dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
Christopher Ferris7747b602018-01-31 19:05:19 -0800313 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
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000317 dex_files_.reset(new DexFiles(process_memory_));
318 dex_files_->SetArch(ARCH_ARM64);
Christopher Ferris7747b602018-01-31 19:05:19 -0800319 method_name = "fail";
320 method_offset = 0x123;
Christopher Ferris56d0e072018-10-17 10:57:53 -0700321 WriteDescriptor64(0xa800, 0x100000);
David Srbeckyb9cc4fb2019-04-05 18:23:32 +0000322 dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
Christopher Ferris7747b602018-01-31 19:05:19 -0800323 EXPECT_EQ("fail", method_name);
324 EXPECT_EQ(0x123U, method_offset);
325}
326
327} // namespace unwindstack