blob: dca560549b6fa5b0746d52359f90991f5a4b623d [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(
47 new BufferMaps("1000-4000 ---s 00000000 00:00 0\n"
48 "4000-6000 r--s 00000000 00:00 0\n"
49 "6000-8000 -w-s 00000000 00:00 0\n"
50 "a000-c000 r-xp 00000000 00:00 0\n"
51 "c000-f000 rwxp 00000000 00:00 0\n"
52 "f000-11000 r-xp 00000000 00:00 0\n"
53 "100000-110000 rw-p 0000000 00:00 0\n"
54 "200000-210000 rw-p 0000000 00:00 0\n"
55 "300000-400000 rw-p 0000000 00:00 0\n"));
56 ASSERT_TRUE(maps_->Parse());
57
58 // Global variable in a section that is not readable/executable.
59 MapInfo* map_info = maps_->Get(kMapGlobalNonReadableExectable);
60 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);
66 interface->FakeSetGlobalVariable("__art_debug_dexfiles", 0x800);
67 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);
77 interface->FakeSetGlobalVariable("__art_debug_dexfiles", 0x800);
78 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);
88 interface->FakeSetGlobalVariable("__art_debug_dexfiles", 0x800);
89 map_info->elf.reset(elf);
90 }
91
92 void WriteEntry32(uint64_t entry_addr, uint32_t next, uint32_t prev, uint32_t dex_file);
93 void WriteEntry64(uint64_t entry_addr, uint64_t next, uint64_t prev, uint64_t dex_file);
94 void WriteDex(uint64_t dex_file);
95
96 static constexpr size_t kMapGlobalNonReadableExectable = 3;
97 static constexpr size_t kMapGlobalSetToZero = 4;
98 static constexpr size_t kMapGlobal = 5;
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
108void DexFilesTest::WriteEntry32(uint64_t entry_addr, uint32_t next, uint32_t prev,
109 uint32_t dex_file) {
110 // Format of the 32 bit DEXFileEntry structure:
111 // uint32_t next
112 memory_->SetData32(entry_addr, next);
113 // uint32_t prev
114 memory_->SetData32(entry_addr + 4, prev);
115 // uint32_t dex_file
116 memory_->SetData32(entry_addr + 8, dex_file);
117}
118
119void DexFilesTest::WriteEntry64(uint64_t entry_addr, uint64_t next, uint64_t prev,
120 uint64_t dex_file) {
121 // Format of the 64 bit DEXFileEntry structure:
122 // uint64_t next
123 memory_->SetData64(entry_addr, next);
124 // uint64_t prev
125 memory_->SetData64(entry_addr + 8, prev);
126 // uint64_t dex_file
127 memory_->SetData64(entry_addr + 16, dex_file);
128}
129
130void DexFilesTest::WriteDex(uint64_t dex_file) {
131 memory_->SetMemory(dex_file, kDexData, sizeof(kDexData) * sizeof(uint32_t));
132}
133
134TEST_F(DexFilesTest, get_method_information_invalid) {
135 std::string method_name = "nothing";
136 uint64_t method_offset = 0x124;
137 MapInfo* info = maps_->Get(kMapDexFileEntries);
138
139 dex_files_->GetMethodInformation(maps_.get(), info, 0, &method_name, &method_offset);
140 EXPECT_EQ("nothing", method_name);
141 EXPECT_EQ(0x124U, method_offset);
142}
143
144TEST_F(DexFilesTest, get_method_information_32) {
145 std::string method_name = "nothing";
146 uint64_t method_offset = 0x124;
147 MapInfo* info = maps_->Get(kMapDexFiles);
148
149 memory_->SetData32(0xf800, 0x200000);
150 WriteEntry32(0x200000, 0, 0, 0x300000);
151 WriteDex(0x300000);
152
153 dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
154 EXPECT_EQ("Main.<init>", method_name);
155 EXPECT_EQ(0U, method_offset);
156}
157
158TEST_F(DexFilesTest, get_method_information_64) {
159 std::string method_name = "nothing";
160 uint64_t method_offset = 0x124;
161 MapInfo* info = maps_->Get(kMapDexFiles);
162
163 dex_files_->SetArch(ARCH_ARM64);
164 memory_->SetData64(0xf800, 0x200000);
165 WriteEntry64(0x200000, 0, 0, 0x301000);
166 WriteDex(0x301000);
167
168 dex_files_->GetMethodInformation(maps_.get(), info, 0x301102, &method_name, &method_offset);
169 EXPECT_EQ("Main.<init>", method_name);
170 EXPECT_EQ(2U, method_offset);
171}
172
173TEST_F(DexFilesTest, get_method_information_not_first_entry_32) {
174 std::string method_name = "nothing";
175 uint64_t method_offset = 0x124;
176 MapInfo* info = maps_->Get(kMapDexFiles);
177
178 memory_->SetData32(0xf800, 0x200000);
179 WriteEntry32(0x200000, 0x200100, 0, 0x100000);
180 WriteEntry32(0x200100, 0, 0x200000, 0x300000);
181 WriteDex(0x300000);
182
183 dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset);
184 EXPECT_EQ("Main.<init>", method_name);
185 EXPECT_EQ(4U, method_offset);
186}
187
188TEST_F(DexFilesTest, get_method_information_not_first_entry_64) {
189 std::string method_name = "nothing";
190 uint64_t method_offset = 0x124;
191 MapInfo* info = maps_->Get(kMapDexFiles);
192
193 dex_files_->SetArch(ARCH_ARM64);
194 memory_->SetData64(0xf800, 0x200000);
195 WriteEntry64(0x200000, 0x200100, 0, 0x100000);
196 WriteEntry64(0x200100, 0, 0x200000, 0x300000);
197 WriteDex(0x300000);
198
199 dex_files_->GetMethodInformation(maps_.get(), info, 0x300106, &method_name, &method_offset);
200 EXPECT_EQ("Main.<init>", method_name);
201 EXPECT_EQ(6U, method_offset);
202}
203
204TEST_F(DexFilesTest, get_method_information_cached) {
205 std::string method_name = "nothing";
206 uint64_t method_offset = 0x124;
207 MapInfo* info = maps_->Get(kMapDexFiles);
208
209 memory_->SetData32(0xf800, 0x200000);
210 WriteEntry32(0x200000, 0, 0, 0x300000);
211 WriteDex(0x300000);
212
213 dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
214 EXPECT_EQ("Main.<init>", method_name);
215 EXPECT_EQ(0U, method_offset);
216
217 // Clear all memory and make sure that data is acquired from the cache.
218 memory_->Clear();
219 dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
220 EXPECT_EQ("Main.<init>", method_name);
221 EXPECT_EQ(0U, method_offset);
222}
223
224TEST_F(DexFilesTest, get_method_information_search_libs) {
225 std::string method_name = "nothing";
226 uint64_t method_offset = 0x124;
227 MapInfo* info = maps_->Get(kMapDexFiles);
228
229 memory_->SetData32(0xf800, 0x200000);
230 WriteEntry32(0x200000, 0x200100, 0, 0x100000);
231 WriteEntry32(0x200100, 0, 0x200000, 0x300000);
232 WriteDex(0x300000);
233
234 // Only search a given named list of libs.
235 std::vector<std::string> libs{"libart.so"};
236 dex_files_.reset(new DexFiles(process_memory_, libs));
237 dex_files_->SetArch(ARCH_ARM);
238
239 dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset);
240 EXPECT_EQ("nothing", method_name);
241 EXPECT_EQ(0x124U, method_offset);
242
243 MapInfo* map_info = maps_->Get(kMapGlobal);
244 map_info->name = "/system/lib/libart.so";
245 dex_files_.reset(new DexFiles(process_memory_, libs));
246 dex_files_->SetArch(ARCH_ARM);
247 // Make sure that clearing out copy of the libs doesn't affect the
248 // DexFiles object.
249 libs.clear();
250
251 dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset);
252 EXPECT_EQ("Main.<init>", method_name);
253 EXPECT_EQ(4U, method_offset);
254}
255
256TEST_F(DexFilesTest, get_method_information_global_skip_zero_32) {
257 std::string method_name = "nothing";
258 uint64_t method_offset = 0x124;
259 MapInfo* info = maps_->Get(kMapDexFiles);
260
261 // First global variable found, but value is zero.
262 memory_->SetData32(0xc800, 0);
263
264 memory_->SetData32(0xf800, 0x200000);
265 WriteEntry32(0x200000, 0, 0, 0x300000);
266 WriteDex(0x300000);
267
268 dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
269 EXPECT_EQ("Main.<init>", method_name);
270 EXPECT_EQ(0U, method_offset);
271
272 // Verify that second is ignored when first is set to non-zero
273 dex_files_.reset(new DexFiles(process_memory_));
274 dex_files_->SetArch(ARCH_ARM);
275 method_name = "fail";
276 method_offset = 0x123;
277 memory_->SetData32(0xc800, 0x100000);
278 dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
279 EXPECT_EQ("fail", method_name);
280 EXPECT_EQ(0x123U, method_offset);
281}
282
283TEST_F(DexFilesTest, get_method_information_global_skip_zero_64) {
284 std::string method_name = "nothing";
285 uint64_t method_offset = 0x124;
286 MapInfo* info = maps_->Get(kMapDexFiles);
287
288 // First global variable found, but value is zero.
289 memory_->SetData64(0xc800, 0);
290
291 memory_->SetData64(0xf800, 0x200000);
292 WriteEntry64(0x200000, 0, 0, 0x300000);
293 WriteDex(0x300000);
294
295 dex_files_->SetArch(ARCH_ARM64);
296 dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
297 EXPECT_EQ("Main.<init>", method_name);
298 EXPECT_EQ(0U, method_offset);
299
300 // Verify that second is ignored when first is set to non-zero
301 dex_files_.reset(new DexFiles(process_memory_));
302 dex_files_->SetArch(ARCH_ARM64);
303 method_name = "fail";
304 method_offset = 0x123;
305 memory_->SetData32(0xc800, 0x100000);
306 dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
307 EXPECT_EQ("fail", method_name);
308 EXPECT_EQ(0x123U, method_offset);
309}
310
311} // namespace unwindstack