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