xref: /aosp_15_r20/system/unwinding/libunwindstack/tests/DexFilesTest.cpp (revision eb293b8f56ee8303637c5595cfcdeef8039e85c6)
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 "DexFile.h"
32 #include "DexFileData.h"
33 #include "ElfFake.h"
34 #include "utils/MemoryFake.h"
35 
36 namespace unwindstack {
37 
38 class DexFilesTest : public ::testing::Test {
39  protected:
CreateFakeElf(MapInfo * map_info,uint64_t global_offset,uint64_t data_offset,uint64_t data_vaddr,uint64_t data_size)40   void CreateFakeElf(MapInfo* map_info, uint64_t global_offset, uint64_t data_offset,
41                      uint64_t data_vaddr, uint64_t data_size) {
42     std::shared_ptr<Memory> fake_memory(new MemoryFake);
43     ElfFake* elf = new ElfFake(fake_memory);
44     elf->FakeSetValid(true);
45     ElfInterfaceFake* interface = new ElfInterfaceFake(fake_memory);
46     elf->FakeSetInterface(interface);
47 
48     interface->FakeSetGlobalVariable("__dex_debug_descriptor", global_offset);
49     interface->FakeSetDataOffset(data_offset);
50     interface->FakeSetDataVaddrStart(data_vaddr);
51     interface->FakeSetDataVaddrEnd(data_vaddr + data_size);
52     map_info->set_elf(elf);
53   }
54 
Init(ArchEnum arch)55   void Init(ArchEnum arch) {
56     dex_files_ = CreateDexFiles(arch, process_memory_);
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                        "600000-601000 r--p 0000000 00:00 0 /fake/elf5\n"
73                        "601000-602000 ---p 0000000 00:00 0 [page size compat]\n"
74                        "603000-610000 rw-p 0003000 00:00 0 /fake/elf5\n"));
75     ASSERT_TRUE(maps_->Parse());
76 
77     // Global variable in a section that is not readable.
78     MapInfo* map_info = maps_->Get(kMapGlobalNonReadable).get();
79     ASSERT_TRUE(map_info != nullptr);
80     CreateFakeElf(map_info, 0x2800, 0x2000, 0x2000, 0x3000);
81 
82     // Global variable not set by default.
83     map_info = maps_->Get(kMapGlobalSetToZero).get();
84     ASSERT_TRUE(map_info != nullptr);
85     CreateFakeElf(map_info, 0x2800, 0x2000, 0x2000, 0x3000);
86 
87     // Global variable set in this map.
88     map_info = maps_->Get(kMapGlobal).get();
89     ASSERT_TRUE(map_info != nullptr);
90     CreateFakeElf(map_info, 0xf1800, 0xf1000, 0xf1000, 0x10000);
91 
92     // Global variable set in this map, but there is an empty map before rw map.
93     map_info = maps_->Get(kMapGlobalAfterEmpty).get();
94     ASSERT_TRUE(map_info != nullptr);
95     CreateFakeElf(map_info, 0x3800, 0x3000, 0x3000, 0xd000);
96 
97     // Global variable set in this map, but there is a page size compat map before rw map.
98     map_info = maps_->Get(kMapGlobalAfterPageSizeCompat).get();
99     ASSERT_TRUE(map_info != nullptr);
100     CreateFakeElf(map_info, 0x3800, 0x3000, 0x3000, 0xd000);
101   }
102 
SetUp()103   void SetUp() override {
104     memory_ = new MemoryFake;
105     process_memory_.reset(memory_);
106 
107     Init(ARCH_ARM);
108   }
109 
110   void WriteDescriptor32(uint64_t addr, uint32_t head);
111   void WriteDescriptor64(uint64_t addr, uint64_t head);
112   void WriteEntry32(uint64_t entry_addr, uint32_t next, uint32_t prev, uint32_t dex_file,
113                     uint64_t dex_size);
114   void WriteEntry64(uint64_t entry_addr, uint64_t next, uint64_t prev, uint64_t dex_file,
115                     uint64_t dex_size);
116   void WriteDex(uint64_t dex_file);
117 
118   static constexpr size_t kMapGlobalNonReadable = 2;
119   static constexpr size_t kMapGlobalSetToZero = 3;
120   static constexpr size_t kMapGlobal = 5;
121   static constexpr size_t kMapGlobalRw = 6;
122   static constexpr size_t kMapDexFileEntries = 7;
123   static constexpr size_t kMapDexFiles = 8;
124   static constexpr size_t kMapGlobalAfterEmpty = 9;
125   static constexpr size_t kMapDexFilesAfterEmpty = 12;
126   static constexpr size_t kMapGlobalAfterPageSizeCompat = 13;
127 
128   std::shared_ptr<Memory> process_memory_;
129   MemoryFake* memory_;
130   std::unique_ptr<DexFiles> dex_files_;
131   std::unique_ptr<BufferMaps> maps_;
132 };
133 
WriteDescriptor32(uint64_t addr,uint32_t entry)134 void DexFilesTest::WriteDescriptor32(uint64_t addr, uint32_t entry) {
135   //   uint32_t version
136   memory_->SetData32(addr, 1);
137   //   uint32_t action_flag
138   memory_->SetData32(addr + 4, 0);
139   //   uint32_t relevant_entry
140   memory_->SetData32(addr + 8, 0);
141   //   uint32_t first_entry
142   memory_->SetData32(addr + 12, entry);
143 }
144 
WriteDescriptor64(uint64_t addr,uint64_t entry)145 void DexFilesTest::WriteDescriptor64(uint64_t addr, uint64_t entry) {
146   //   uint32_t version
147   memory_->SetData32(addr, 1);
148   //   uint32_t action_flag
149   memory_->SetData32(addr + 4, 0);
150   //   uint64_t relevant_entry
151   memory_->SetData64(addr + 8, 0);
152   //   uint64_t first_entry
153   memory_->SetData64(addr + 16, entry);
154 }
155 
WriteEntry32(uint64_t entry_addr,uint32_t next,uint32_t prev,uint32_t dex_file,uint64_t dex_size)156 void DexFilesTest::WriteEntry32(uint64_t entry_addr, uint32_t next, uint32_t prev,
157                                 uint32_t dex_file, uint64_t dex_size) {
158   // Format of the 32 bit DEXFileEntry structure:
159   //   uint32_t next
160   memory_->SetData32(entry_addr, next);
161   //   uint32_t prev
162   memory_->SetData32(entry_addr + 4, prev);
163   //   uint32_t dex_file
164   memory_->SetData32(entry_addr + 8, dex_file);
165   //   uint32_t dex_size (present in the struct, but we ignore it)
166   memory_->SetData32(entry_addr + 12, 0);  // Align.
167   memory_->SetData64(entry_addr + 16, dex_size);
168 }
169 
WriteEntry64(uint64_t entry_addr,uint64_t next,uint64_t prev,uint64_t dex_file,uint64_t dex_size)170 void DexFilesTest::WriteEntry64(uint64_t entry_addr, uint64_t next, uint64_t prev,
171                                 uint64_t dex_file, uint64_t dex_size) {
172   // Format of the 64 bit DEXFileEntry structure:
173   //   uint64_t next
174   memory_->SetData64(entry_addr, next);
175   //   uint64_t prev
176   memory_->SetData64(entry_addr + 8, prev);
177   //   uint64_t dex_file
178   memory_->SetData64(entry_addr + 16, dex_file);
179   //   uint32_t dex_size (present in the struct, but we ignore it)
180   memory_->SetData64(entry_addr + 24, dex_size);
181 }
182 
WriteDex(uint64_t dex_file)183 void DexFilesTest::WriteDex(uint64_t dex_file) {
184   memory_->SetMemory(dex_file, kDexData, sizeof(kDexData));
185 }
186 
TEST_F(DexFilesTest,get_method_information_invalid)187 TEST_F(DexFilesTest, get_method_information_invalid) {
188   SharedString method_name = "nothing";
189   uint64_t method_offset = 0x124;
190 
191   dex_files_->GetFunctionName(maps_.get(), 0, &method_name, &method_offset);
192   EXPECT_EQ("nothing", method_name);
193   EXPECT_EQ(0x124U, method_offset);
194 }
195 
TEST_F(DexFilesTest,get_method_information_32)196 TEST_F(DexFilesTest, get_method_information_32) {
197   SharedString method_name = "nothing";
198   uint64_t method_offset = 0x124;
199 
200   WriteDescriptor32(0x100800, 0x200000);
201   WriteEntry32(0x200000, 0, 0, 0x300000, sizeof(kDexData));
202   WriteDex(0x300000);
203 
204   dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset);
205   EXPECT_EQ("Main.<init>", method_name);
206   EXPECT_EQ(0U, method_offset);
207 }
208 
TEST_F(DexFilesTest,get_method_information_64)209 TEST_F(DexFilesTest, get_method_information_64) {
210   Init(ARCH_ARM64);
211 
212   SharedString method_name = "nothing";
213   uint64_t method_offset = 0x124;
214 
215   WriteDescriptor64(0x100800, 0x200000);
216   WriteEntry64(0x200000, 0, 0, 0x301000, sizeof(kDexData));
217   WriteDex(0x301000);
218 
219   dex_files_->GetFunctionName(maps_.get(), 0x301102, &method_name, &method_offset);
220   EXPECT_EQ("Main.<init>", method_name);
221   EXPECT_EQ(2U, method_offset);
222 }
223 
TEST_F(DexFilesTest,get_method_information_not_first_entry_32)224 TEST_F(DexFilesTest, get_method_information_not_first_entry_32) {
225   SharedString method_name = "nothing";
226   uint64_t method_offset = 0x124;
227 
228   WriteDescriptor32(0x100800, 0x200000);
229   WriteEntry32(0x200000, 0x200100, 0, 0x100000, sizeof(kDexData));
230   WriteEntry32(0x200100, 0, 0x200000, 0x300000, sizeof(kDexData));
231   WriteDex(0x300000);
232 
233   dex_files_->GetFunctionName(maps_.get(), 0x300104, &method_name, &method_offset);
234   EXPECT_EQ("Main.<init>", method_name);
235   EXPECT_EQ(4U, method_offset);
236 }
237 
TEST_F(DexFilesTest,get_method_information_not_first_entry_64)238 TEST_F(DexFilesTest, get_method_information_not_first_entry_64) {
239   Init(ARCH_ARM64);
240 
241   SharedString method_name = "nothing";
242   uint64_t method_offset = 0x124;
243 
244   WriteDescriptor64(0x100800, 0x200000);
245   WriteEntry64(0x200000, 0x200100, 0, 0x100000, sizeof(kDexData));
246   WriteEntry64(0x200100, 0, 0x200000, 0x300000, sizeof(kDexData));
247   WriteDex(0x300000);
248 
249   dex_files_->GetFunctionName(maps_.get(), 0x300106, &method_name, &method_offset);
250   EXPECT_EQ("Main.<init>", method_name);
251   EXPECT_EQ(6U, method_offset);
252 }
253 
TEST_F(DexFilesTest,get_method_information_cached)254 TEST_F(DexFilesTest, get_method_information_cached) {
255   SharedString method_name = "nothing";
256   uint64_t method_offset = 0x124;
257 
258   WriteDescriptor32(0x100800, 0x200000);
259   WriteEntry32(0x200000, 0, 0, 0x300000, sizeof(kDexData));
260   WriteDex(0x300000);
261 
262   dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset);
263   EXPECT_EQ("Main.<init>", method_name);
264   EXPECT_EQ(0U, method_offset);
265 
266   // Clear all memory and make sure that data is acquired from the cache.
267   memory_->Clear();
268   dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset);
269   EXPECT_EQ("Main.<init>", method_name);
270   EXPECT_EQ(0U, method_offset);
271 }
272 
TEST_F(DexFilesTest,get_method_information_search_libs)273 TEST_F(DexFilesTest, get_method_information_search_libs) {
274   SharedString method_name = "nothing";
275   uint64_t method_offset = 0x124;
276 
277   WriteDescriptor32(0x100800, 0x200000);
278   WriteEntry32(0x200000, 0x200100, 0, 0x100000, sizeof(kDexData));
279   WriteEntry32(0x200100, 0, 0x200000, 0x300000, sizeof(kDexData));
280   WriteDex(0x300000);
281 
282   // Only search a given named list of libs.
283   std::vector<std::string> libs{"libart.so"};
284   dex_files_ = CreateDexFiles(ARCH_ARM, process_memory_, libs);
285 
286   dex_files_->GetFunctionName(maps_.get(), 0x300104, &method_name, &method_offset);
287   EXPECT_EQ("nothing", method_name);
288   EXPECT_EQ(0x124U, method_offset);
289 
290   auto map_info = maps_->Get(kMapGlobal);
291   map_info->set_name("/system/lib/libart.so");
292   dex_files_ = CreateDexFiles(ARCH_ARM, process_memory_, libs);
293   // Set the rw map to the same name or this will not scan this entry.
294   map_info = maps_->Get(kMapGlobalRw);
295   map_info->set_name("/system/lib/libart.so");
296   // Make sure that clearing out copy of the libs doesn't affect the
297   // DexFiles object.
298   libs.clear();
299 
300   dex_files_->GetFunctionName(maps_.get(), 0x300104, &method_name, &method_offset);
301   EXPECT_EQ("Main.<init>", method_name);
302   EXPECT_EQ(4U, method_offset);
303 }
304 
TEST_F(DexFilesTest,get_method_information_global_skip_zero_32)305 TEST_F(DexFilesTest, get_method_information_global_skip_zero_32) {
306   SharedString method_name = "nothing";
307   uint64_t method_offset = 0x124;
308 
309   // First global variable found, but value is zero.
310   WriteDescriptor32(0xc800, 0);
311 
312   WriteDescriptor32(0x100800, 0x200000);
313   WriteEntry32(0x200000, 0, 0, 0x300000, sizeof(kDexData));
314   WriteDex(0x300000);
315 
316   dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset);
317   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
321   dex_files_ = CreateDexFiles(ARCH_ARM, process_memory_);
322   method_name = "fail";
323   method_offset = 0x123;
324   WriteDescriptor32(0xc800, 0x100000);
325   dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset);
326   EXPECT_EQ("fail", method_name);
327   EXPECT_EQ(0x123U, method_offset);
328 }
329 
TEST_F(DexFilesTest,get_method_information_global_skip_zero_64)330 TEST_F(DexFilesTest, get_method_information_global_skip_zero_64) {
331   Init(ARCH_ARM64);
332 
333   SharedString method_name = "nothing";
334   uint64_t method_offset = 0x124;
335 
336   // First global variable found, but value is zero.
337   WriteDescriptor64(0xc800, 0);
338 
339   WriteDescriptor64(0x100800, 0x200000);
340   WriteEntry64(0x200000, 0, 0, 0x300000, sizeof(kDexData));
341   WriteDex(0x300000);
342 
343   dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset);
344   EXPECT_EQ("Main.<init>", method_name);
345   EXPECT_EQ(0U, method_offset);
346 
347   // Verify that second is ignored when first is set to non-zero
348   dex_files_ = CreateDexFiles(ARCH_ARM64, process_memory_);
349   method_name = "fail";
350   method_offset = 0x123;
351   WriteDescriptor64(0xc800, 0x100000);
352   dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset);
353   EXPECT_EQ("fail", method_name);
354   EXPECT_EQ(0x123U, method_offset);
355 }
356 
TEST_F(DexFilesTest,get_method_information_with_empty_map)357 TEST_F(DexFilesTest, get_method_information_with_empty_map) {
358   SharedString method_name = "nothing";
359   uint64_t method_offset = 0x124;
360 
361   WriteDescriptor32(0x503800, 0x506000);
362   WriteEntry32(0x506000, 0, 0, 0x510000, sizeof(kDexData));
363   WriteDex(0x510000);
364 
365   dex_files_->GetFunctionName(maps_.get(), 0x510100, &method_name, &method_offset);
366   EXPECT_EQ("Main.<init>", method_name);
367   EXPECT_EQ(0U, method_offset);
368 }
369 
TEST_F(DexFilesTest,get_method_information_with_page_size_compat_map)370 TEST_F(DexFilesTest, get_method_information_with_page_size_compat_map) {
371   SharedString method_name = "nothing";
372   uint64_t method_offset = 0x124;
373 
374   WriteDescriptor32(0x603800, 0x606000);
375   WriteEntry32(0x606000, 0, 0, 0x610000, sizeof(kDexData));
376   WriteDex(0x610000);
377 
378   dex_files_->GetFunctionName(maps_.get(), 0x610100, &method_name, &method_offset);
379   EXPECT_EQ("Main.<init>", method_name);
380   EXPECT_EQ(0U, method_offset);
381 }
382 
TEST_F(DexFilesTest,get_method_information_tagged_descriptor_entry_addr_arm64)383 TEST_F(DexFilesTest, get_method_information_tagged_descriptor_entry_addr_arm64) {
384   Init(ARCH_ARM64);
385 
386   SharedString method_name = "nothing";
387   uint64_t method_offset = 0x124;
388 
389   // Descriptor-stored adddress (first_entry) with a tag in the top byte, which
390   // should be masked out.
391   WriteDescriptor64(0x100800, 0xb400'0000'0020'0000ull);
392   WriteEntry64(0x200000, 0, 0, 0x301000, sizeof(kDexData));
393   WriteDex(0x301000);
394 
395   dex_files_->GetFunctionName(maps_.get(), 0x301102, &method_name, &method_offset);
396   EXPECT_EQ("Main.<init>", method_name);
397   EXPECT_EQ(2U, method_offset);
398 }
399 
400 }  // namespace unwindstack
401