• 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)39   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);
45 
46     interface->FakeSetGlobalVariable("__dex_debug_descriptor", 0x800);
47     map_info->elf.reset(elf);
48   }
49 
Init(ArchEnum arch)50   void Init(ArchEnum arch) {
51     dex_files_.reset(new DexFiles(process_memory_));
52     dex_files_->SetArch(arch);
53 
54     maps_.reset(
55         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"));
64     ASSERT_TRUE(maps_->Parse());
65 
66     // Global variable in a section that is not readable.
67     MapInfo* map_info = maps_->Get(kMapGlobalNonReadable);
68     ASSERT_TRUE(map_info != nullptr);
69     CreateFakeElf(map_info);
70 
71     // Global variable not set by default.
72     map_info = maps_->Get(kMapGlobalSetToZero);
73     ASSERT_TRUE(map_info != nullptr);
74     CreateFakeElf(map_info);
75 
76     // Global variable set in this map.
77     map_info = maps_->Get(kMapGlobal);
78     ASSERT_TRUE(map_info != nullptr);
79     CreateFakeElf(map_info);
80   }
81 
SetUp()82   void SetUp() override {
83     memory_ = new MemoryFake;
84     process_memory_.reset(memory_);
85 
86     Init(ARCH_ARM);
87   }
88 
89   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);
93   void WriteDex(uint64_t dex_file);
94 
95   static constexpr size_t kMapGlobalNonReadable = 2;
96   static constexpr size_t kMapGlobalSetToZero = 3;
97   static constexpr size_t kMapGlobal = 5;
98   static constexpr size_t kMapGlobalRw = 6;
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 
WriteDescriptor32(uint64_t addr,uint32_t head)108 void DexFilesTest::WriteDescriptor32(uint64_t addr, uint32_t head) {
109   //   void* first_entry_
110   memory_->SetData32(addr + 12, head);
111 }
112 
WriteDescriptor64(uint64_t addr,uint64_t head)113 void DexFilesTest::WriteDescriptor64(uint64_t addr, uint64_t head) {
114   //   void* first_entry_
115   memory_->SetData64(addr + 16, head);
116 }
117 
WriteEntry32(uint64_t entry_addr,uint32_t next,uint32_t prev,uint32_t dex_file)118 void 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:
121   //   uint32_t next
122   memory_->SetData32(entry_addr, next);
123   //   uint32_t prev
124   memory_->SetData32(entry_addr + 4, prev);
125   //   uint32_t dex_file
126   memory_->SetData32(entry_addr + 8, dex_file);
127 }
128 
WriteEntry64(uint64_t entry_addr,uint64_t next,uint64_t prev,uint64_t dex_file)129 void 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:
132   //   uint64_t next
133   memory_->SetData64(entry_addr, next);
134   //   uint64_t prev
135   memory_->SetData64(entry_addr + 8, prev);
136   //   uint64_t dex_file
137   memory_->SetData64(entry_addr + 16, dex_file);
138 }
139 
WriteDex(uint64_t dex_file)140 void DexFilesTest::WriteDex(uint64_t dex_file) {
141   memory_->SetMemory(dex_file, kDexData, sizeof(kDexData) * sizeof(uint32_t));
142 }
143 
TEST_F(DexFilesTest,get_method_information_invalid)144 TEST_F(DexFilesTest, get_method_information_invalid) {
145   std::string method_name = "nothing";
146   uint64_t method_offset = 0x124;
147   MapInfo* info = maps_->Get(kMapDexFileEntries);
148 
149   dex_files_->GetMethodInformation(maps_.get(), info, 0, &method_name, &method_offset);
150   EXPECT_EQ("nothing", method_name);
151   EXPECT_EQ(0x124U, method_offset);
152 }
153 
TEST_F(DexFilesTest,get_method_information_32)154 TEST_F(DexFilesTest, get_method_information_32) {
155   std::string method_name = "nothing";
156   uint64_t method_offset = 0x124;
157   MapInfo* info = maps_->Get(kMapDexFiles);
158 
159   WriteDescriptor32(0xf800, 0x200000);
160   WriteEntry32(0x200000, 0, 0, 0x300000);
161   WriteDex(0x300000);
162 
163   dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
164   EXPECT_EQ("Main.<init>", method_name);
165   EXPECT_EQ(0U, method_offset);
166 }
167 
TEST_F(DexFilesTest,get_method_information_64)168 TEST_F(DexFilesTest, get_method_information_64) {
169   Init(ARCH_ARM64);
170 
171   std::string method_name = "nothing";
172   uint64_t method_offset = 0x124;
173   MapInfo* info = maps_->Get(kMapDexFiles);
174 
175   WriteDescriptor64(0xf800, 0x200000);
176   WriteEntry64(0x200000, 0, 0, 0x301000);
177   WriteDex(0x301000);
178 
179   dex_files_->GetMethodInformation(maps_.get(), info, 0x301102, &method_name, &method_offset);
180   EXPECT_EQ("Main.<init>", method_name);
181   EXPECT_EQ(2U, method_offset);
182 }
183 
TEST_F(DexFilesTest,get_method_information_not_first_entry_32)184 TEST_F(DexFilesTest, get_method_information_not_first_entry_32) {
185   std::string method_name = "nothing";
186   uint64_t method_offset = 0x124;
187   MapInfo* info = maps_->Get(kMapDexFiles);
188 
189   WriteDescriptor32(0xf800, 0x200000);
190   WriteEntry32(0x200000, 0x200100, 0, 0x100000);
191   WriteEntry32(0x200100, 0, 0x200000, 0x300000);
192   WriteDex(0x300000);
193 
194   dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset);
195   EXPECT_EQ("Main.<init>", method_name);
196   EXPECT_EQ(4U, method_offset);
197 }
198 
TEST_F(DexFilesTest,get_method_information_not_first_entry_64)199 TEST_F(DexFilesTest, get_method_information_not_first_entry_64) {
200   Init(ARCH_ARM64);
201 
202   std::string method_name = "nothing";
203   uint64_t method_offset = 0x124;
204   MapInfo* info = maps_->Get(kMapDexFiles);
205 
206   WriteDescriptor64(0xf800, 0x200000);
207   WriteEntry64(0x200000, 0x200100, 0, 0x100000);
208   WriteEntry64(0x200100, 0, 0x200000, 0x300000);
209   WriteDex(0x300000);
210 
211   dex_files_->GetMethodInformation(maps_.get(), info, 0x300106, &method_name, &method_offset);
212   EXPECT_EQ("Main.<init>", method_name);
213   EXPECT_EQ(6U, method_offset);
214 }
215 
TEST_F(DexFilesTest,get_method_information_cached)216 TEST_F(DexFilesTest, get_method_information_cached) {
217   std::string method_name = "nothing";
218   uint64_t method_offset = 0x124;
219   MapInfo* info = maps_->Get(kMapDexFiles);
220 
221   WriteDescriptor32(0xf800, 0x200000);
222   WriteEntry32(0x200000, 0, 0, 0x300000);
223   WriteDex(0x300000);
224 
225   dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
226   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();
231   dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
232   EXPECT_EQ("Main.<init>", method_name);
233   EXPECT_EQ(0U, method_offset);
234 }
235 
TEST_F(DexFilesTest,get_method_information_search_libs)236 TEST_F(DexFilesTest, get_method_information_search_libs) {
237   std::string method_name = "nothing";
238   uint64_t method_offset = 0x124;
239   MapInfo* info = maps_->Get(kMapDexFiles);
240 
241   WriteDescriptor32(0xf800, 0x200000);
242   WriteEntry32(0x200000, 0x200100, 0, 0x100000);
243   WriteEntry32(0x200100, 0, 0x200000, 0x300000);
244   WriteDex(0x300000);
245 
246   // Only search a given named list of libs.
247   std::vector<std::string> libs{"libart.so"};
248   dex_files_.reset(new DexFiles(process_memory_, libs));
249   dex_files_->SetArch(ARCH_ARM);
250 
251   dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset);
252   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";
257   dex_files_.reset(new DexFiles(process_memory_, libs));
258   dex_files_->SetArch(ARCH_ARM);
259   // 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";
262   // Make sure that clearing out copy of the libs doesn't affect the
263   // DexFiles object.
264   libs.clear();
265 
266   dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset);
267   EXPECT_EQ("Main.<init>", method_name);
268   EXPECT_EQ(4U, method_offset);
269 }
270 
TEST_F(DexFilesTest,get_method_information_global_skip_zero_32)271 TEST_F(DexFilesTest, get_method_information_global_skip_zero_32) {
272   std::string method_name = "nothing";
273   uint64_t method_offset = 0x124;
274   MapInfo* info = maps_->Get(kMapDexFiles);
275 
276   // First global variable found, but value is zero.
277   WriteDescriptor32(0xa800, 0);
278 
279   WriteDescriptor32(0xf800, 0x200000);
280   WriteEntry32(0x200000, 0, 0, 0x300000);
281   WriteDex(0x300000);
282 
283   dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
284   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
288   dex_files_.reset(new DexFiles(process_memory_));
289   dex_files_->SetArch(ARCH_ARM);
290   method_name = "fail";
291   method_offset = 0x123;
292   WriteDescriptor32(0xa800, 0x100000);
293   dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
294   EXPECT_EQ("fail", method_name);
295   EXPECT_EQ(0x123U, method_offset);
296 }
297 
TEST_F(DexFilesTest,get_method_information_global_skip_zero_64)298 TEST_F(DexFilesTest, get_method_information_global_skip_zero_64) {
299   Init(ARCH_ARM64);
300 
301   std::string method_name = "nothing";
302   uint64_t method_offset = 0x124;
303   MapInfo* info = maps_->Get(kMapDexFiles);
304 
305   // First global variable found, but value is zero.
306   WriteDescriptor64(0xa800, 0);
307 
308   WriteDescriptor64(0xf800, 0x200000);
309   WriteEntry64(0x200000, 0, 0, 0x300000);
310   WriteDex(0x300000);
311 
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;
321   WriteDescriptor64(0xa800, 0x100000);
322   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
328