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: 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("__dex_debug_descriptor", 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("__dex_debug_descriptor", 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("__dex_debug_descriptor", 0x800); 89 map_info->elf.reset(elf); 90 } 91 92 void WriteDescriptor32(uint64_t addr, uint32_t head); 93 void WriteDescriptor64(uint64_t addr, uint64_t head); 94 void WriteEntry32(uint64_t entry_addr, uint32_t next, uint32_t prev, uint32_t dex_file); 95 void WriteEntry64(uint64_t entry_addr, uint64_t next, uint64_t prev, uint64_t dex_file); 96 void WriteDex(uint64_t dex_file); 97 98 static constexpr size_t kMapGlobalNonReadableExectable = 3; 99 static constexpr size_t kMapGlobalSetToZero = 4; 100 static constexpr size_t kMapGlobal = 5; 101 static constexpr size_t kMapDexFileEntries = 7; 102 static constexpr size_t kMapDexFiles = 8; 103 104 std::shared_ptr<Memory> process_memory_; 105 MemoryFake* memory_; 106 std::unique_ptr<DexFiles> dex_files_; 107 std::unique_ptr<BufferMaps> maps_; 108 }; 109 110 void DexFilesTest::WriteDescriptor32(uint64_t addr, uint32_t head) { 111 // void* first_entry_ 112 memory_->SetData32(addr + 12, head); 113 } 114 115 void DexFilesTest::WriteDescriptor64(uint64_t addr, uint64_t head) { 116 // void* first_entry_ 117 memory_->SetData64(addr + 16, head); 118 } 119 120 void DexFilesTest::WriteEntry32(uint64_t entry_addr, uint32_t next, uint32_t prev, 121 uint32_t dex_file) { 122 // Format of the 32 bit DEXFileEntry structure: 123 // uint32_t next 124 memory_->SetData32(entry_addr, next); 125 // uint32_t prev 126 memory_->SetData32(entry_addr + 4, prev); 127 // uint32_t dex_file 128 memory_->SetData32(entry_addr + 8, dex_file); 129 } 130 131 void DexFilesTest::WriteEntry64(uint64_t entry_addr, uint64_t next, uint64_t prev, 132 uint64_t dex_file) { 133 // Format of the 64 bit DEXFileEntry structure: 134 // uint64_t next 135 memory_->SetData64(entry_addr, next); 136 // uint64_t prev 137 memory_->SetData64(entry_addr + 8, prev); 138 // uint64_t dex_file 139 memory_->SetData64(entry_addr + 16, dex_file); 140 } 141 142 void DexFilesTest::WriteDex(uint64_t dex_file) { 143 memory_->SetMemory(dex_file, kDexData, sizeof(kDexData) * sizeof(uint32_t)); 144 } 145 146 TEST_F(DexFilesTest, get_method_information_invalid) { 147 std::string method_name = "nothing"; 148 uint64_t method_offset = 0x124; 149 MapInfo* info = maps_->Get(kMapDexFileEntries); 150 151 dex_files_->GetMethodInformation(maps_.get(), info, 0, &method_name, &method_offset); 152 EXPECT_EQ("nothing", method_name); 153 EXPECT_EQ(0x124U, method_offset); 154 } 155 156 TEST_F(DexFilesTest, get_method_information_32) { 157 std::string method_name = "nothing"; 158 uint64_t method_offset = 0x124; 159 MapInfo* info = maps_->Get(kMapDexFiles); 160 161 WriteDescriptor32(0xf800, 0x200000); 162 WriteEntry32(0x200000, 0, 0, 0x300000); 163 WriteDex(0x300000); 164 165 dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset); 166 EXPECT_EQ("Main.<init>", method_name); 167 EXPECT_EQ(0U, method_offset); 168 } 169 170 TEST_F(DexFilesTest, get_method_information_64) { 171 std::string method_name = "nothing"; 172 uint64_t method_offset = 0x124; 173 MapInfo* info = maps_->Get(kMapDexFiles); 174 175 dex_files_->SetArch(ARCH_ARM64); 176 WriteDescriptor64(0xf800, 0x200000); 177 WriteEntry64(0x200000, 0, 0, 0x301000); 178 WriteDex(0x301000); 179 180 dex_files_->GetMethodInformation(maps_.get(), info, 0x301102, &method_name, &method_offset); 181 EXPECT_EQ("Main.<init>", method_name); 182 EXPECT_EQ(2U, method_offset); 183 } 184 185 TEST_F(DexFilesTest, get_method_information_not_first_entry_32) { 186 std::string method_name = "nothing"; 187 uint64_t method_offset = 0x124; 188 MapInfo* info = maps_->Get(kMapDexFiles); 189 190 WriteDescriptor32(0xf800, 0x200000); 191 WriteEntry32(0x200000, 0x200100, 0, 0x100000); 192 WriteEntry32(0x200100, 0, 0x200000, 0x300000); 193 WriteDex(0x300000); 194 195 dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset); 196 EXPECT_EQ("Main.<init>", method_name); 197 EXPECT_EQ(4U, method_offset); 198 } 199 200 TEST_F(DexFilesTest, get_method_information_not_first_entry_64) { 201 std::string method_name = "nothing"; 202 uint64_t method_offset = 0x124; 203 MapInfo* info = maps_->Get(kMapDexFiles); 204 205 dex_files_->SetArch(ARCH_ARM64); 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 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 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 // Make sure that clearing out copy of the libs doesn't affect the 260 // DexFiles object. 261 libs.clear(); 262 263 dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset); 264 EXPECT_EQ("Main.<init>", method_name); 265 EXPECT_EQ(4U, method_offset); 266 } 267 268 TEST_F(DexFilesTest, get_method_information_global_skip_zero_32) { 269 std::string method_name = "nothing"; 270 uint64_t method_offset = 0x124; 271 MapInfo* info = maps_->Get(kMapDexFiles); 272 273 // First global variable found, but value is zero. 274 WriteDescriptor32(0xc800, 0); 275 276 WriteDescriptor32(0xf800, 0x200000); 277 WriteEntry32(0x200000, 0, 0, 0x300000); 278 WriteDex(0x300000); 279 280 dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset); 281 EXPECT_EQ("Main.<init>", method_name); 282 EXPECT_EQ(0U, method_offset); 283 284 // Verify that second is ignored when first is set to non-zero 285 dex_files_.reset(new DexFiles(process_memory_)); 286 dex_files_->SetArch(ARCH_ARM); 287 method_name = "fail"; 288 method_offset = 0x123; 289 WriteDescriptor32(0xc800, 0x100000); 290 dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset); 291 EXPECT_EQ("fail", method_name); 292 EXPECT_EQ(0x123U, method_offset); 293 } 294 295 TEST_F(DexFilesTest, get_method_information_global_skip_zero_64) { 296 std::string method_name = "nothing"; 297 uint64_t method_offset = 0x124; 298 MapInfo* info = maps_->Get(kMapDexFiles); 299 300 // First global variable found, but value is zero. 301 WriteDescriptor64(0xc800, 0); 302 303 WriteDescriptor64(0xf800, 0x200000); 304 WriteEntry64(0x200000, 0, 0, 0x300000); 305 WriteDex(0x300000); 306 307 dex_files_->SetArch(ARCH_ARM64); 308 dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset); 309 EXPECT_EQ("Main.<init>", method_name); 310 EXPECT_EQ(0U, method_offset); 311 312 // Verify that second is ignored when first is set to non-zero 313 dex_files_.reset(new DexFiles(process_memory_)); 314 dex_files_->SetArch(ARCH_ARM64); 315 method_name = "fail"; 316 method_offset = 0x123; 317 WriteDescriptor64(0xc800, 0x100000); 318 dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset); 319 EXPECT_EQ("fail", method_name); 320 EXPECT_EQ(0x123U, method_offset); 321 } 322 323 } // namespace unwindstack 324