Loading libunwindstack/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -235,6 +235,8 @@ cc_test { "tests/files/offline/jit_map_arm/*", "tests/files/offline/gnu_debugdata_arm/*", "tests/files/offline/offset_arm/*", "tests/files/offline/shared_lib_in_apk_arm64/*", "tests/files/offline/shared_lib_in_apk_memory_only_arm64/*", "tests/files/offline/straddle_arm/*", "tests/files/offline/straddle_arm64/*", ], Loading libunwindstack/MapInfo.cpp +82 −34 Original line number Diff line number Diff line Loading @@ -29,6 +29,38 @@ namespace unwindstack { bool MapInfo::InitFileMemoryFromPreviousReadOnlyMap(MemoryFileAtOffset* memory) { // One last attempt, see if the previous map is read-only with the // same name and stretches across this map. for (auto iter = maps_->begin(); iter != maps_->end(); ++iter) { if (*iter == this) { if (iter == maps_->begin()) { return false; } --iter; MapInfo* prev_map = *iter; // Make sure this is a read-only map. if (prev_map->flags != PROT_READ) { return false; } uint64_t map_size = end - prev_map->end; if (!memory->Init(name, prev_map->offset, map_size)) { return false; } uint64_t max_size; if (!Elf::GetInfo(memory, &max_size) || max_size < map_size) { return false; } if (!memory->Init(name, prev_map->offset, max_size)) { return false; } elf_offset = offset - prev_map->offset; return true; } } return false; } Memory* MapInfo::GetFileMemory() { std::unique_ptr<MemoryFileAtOffset> memory(new MemoryFileAtOffset); if (offset == 0) { Loading @@ -38,8 +70,12 @@ Memory* MapInfo::GetFileMemory() { return nullptr; } // There are two possibilities when the offset is non-zero. // - There is an elf file embedded in a file. // These are the possibilities when the offset is non-zero. // - There is an elf file embedded in a file, and the offset is the // the start of the elf in the file. // - There is an elf file embedded in a file, and the offset is the // the start of the executable part of the file. The actual start // of the elf is in the read-only segment preceeding this map. // - The whole file is an elf file, and the offset needs to be saved. // // Map in just the part of the file for the map. If this is not Loading @@ -53,28 +89,42 @@ Memory* MapInfo::GetFileMemory() { return nullptr; } uint64_t max_size; if (!Elf::GetInfo(memory.get(), &max_size)) { // Init as if the whole file is an elf. if (memory->Init(name, 0)) { elf_offset = offset; // Check if the start of this map is an embedded elf. uint64_t max_size = 0; uint64_t file_offset = offset; if (Elf::GetInfo(memory.get(), &max_size)) { if (max_size > map_size) { if (memory->Init(name, file_offset, max_size)) { return memory.release(); } // Try to reinit using the default map_size. if (memory->Init(name, file_offset, map_size)) { return memory.release(); } return nullptr; } return memory.release(); } if (max_size > map_size) { if (memory->Init(name, offset, max_size)) { // No elf at offset, try to init as if the whole file is an elf. if (memory->Init(name, 0) && Elf::IsValidElf(memory.get())) { elf_offset = offset; return memory.release(); } // Try to reinit using the default map_size. // See if the map previous to this one contains a read-only map // that represents the real start of the elf data. if (InitFileMemoryFromPreviousReadOnlyMap(memory.get())) { return memory.release(); } // Failed to find elf at start of file or at read-only map, return // file object from the current map. if (memory->Init(name, offset, map_size)) { return memory.release(); } return nullptr; } return memory.release(); } Memory* MapInfo::CreateMemory(const std::shared_ptr<Memory>& process_memory) { if (end <= start) { Loading Loading @@ -110,29 +160,27 @@ Memory* MapInfo::CreateMemory(const std::shared_ptr<Memory>& process_memory) { return nullptr; } // Find the read-only map that has the same name and has an offset closest // to the current offset but less than the offset of the current map. // For shared libraries, there should be a r-x map that has a non-zero // offset and then a r-- map that has a zero offset. // For shared libraries loaded from an apk, there should be a r-x map that // has a non-zero offset and then a r-- map that has a non-zero offset less // than the offset from the r-x map. uint64_t closest_offset = 0; // Find the read-only map by looking at the previous map. The linker // doesn't guarantee that this invariant will always be true. However, // if that changes, there is likely something else that will change and // break something. MapInfo* ro_map_info = nullptr; for (auto map_info : *maps_) { if (map_info->flags == PROT_READ && map_info->name == name && map_info->offset < offset && map_info->offset >= closest_offset) { ro_map_info = map_info; closest_offset = ro_map_info->offset; for (auto iter = maps_->begin(); iter != maps_->end(); ++iter) { if (*iter == this) { if (iter != maps_->begin()) { --iter; ro_map_info = *iter; } break; } } if (ro_map_info == nullptr) { if (ro_map_info == nullptr || ro_map_info->name != name || ro_map_info->offset >= offset) { return nullptr; } // Make sure that relative pc values are corrected properly. elf_offset = offset - closest_offset; elf_offset = offset - ro_map_info->offset; MemoryRanges* ranges = new MemoryRanges; ranges->Insert(new MemoryRange(process_memory, ro_map_info->start, Loading libunwindstack/include/unwindstack/MapInfo.h +1 −0 Original line number Diff line number Diff line Loading @@ -83,6 +83,7 @@ struct MapInfo { void operator=(const MapInfo&) = delete; Memory* GetFileMemory(); bool InitFileMemoryFromPreviousReadOnlyMap(MemoryFileAtOffset* memory); // Protect the creation of the elf object. std::mutex mutex_; Loading libunwindstack/tests/MapInfoCreateMemoryTest.cpp +48 −9 Original line number Diff line number Diff line Loading @@ -59,16 +59,16 @@ class MapInfoCreateMemoryTest : public ::testing::Test { } static void SetUpTestCase() { std::vector<uint8_t> buffer(1024); memset(buffer.data(), 0, buffer.size()); std::vector<uint8_t> buffer(12288, 0); memcpy(buffer.data(), ELFMAG, SELFMAG); buffer[EI_CLASS] = ELFCLASS32; ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size())); ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), 1024)); memset(buffer.data(), 0, buffer.size()); memcpy(&buffer[0x100], ELFMAG, SELFMAG); buffer[0x100 + EI_CLASS] = ELFCLASS64; ASSERT_TRUE(android::base::WriteFully(elf_at_100_.fd, buffer.data(), buffer.size())); memcpy(&buffer[0x1000], ELFMAG, SELFMAG); buffer[0x1000 + EI_CLASS] = ELFCLASS64; buffer[0x2000] = 0xff; ASSERT_TRUE(android::base::WriteFully(elf_at_1000_.fd, buffer.data(), buffer.size())); InitElf<Elf32_Ehdr, Elf32_Shdr>(elf32_at_map_.fd, 0x1000, 0x2000, ELFCLASS32); InitElf<Elf64_Ehdr, Elf64_Shdr>(elf64_at_map_.fd, 0x2000, 0x3000, ELFCLASS64); Loading @@ -84,13 +84,13 @@ class MapInfoCreateMemoryTest : public ::testing::Test { static TemporaryFile elf_; static TemporaryFile elf_at_100_; static TemporaryFile elf_at_1000_; static TemporaryFile elf32_at_map_; static TemporaryFile elf64_at_map_; }; TemporaryFile MapInfoCreateMemoryTest::elf_; TemporaryFile MapInfoCreateMemoryTest::elf_at_100_; TemporaryFile MapInfoCreateMemoryTest::elf_at_1000_; TemporaryFile MapInfoCreateMemoryTest::elf32_at_map_; TemporaryFile MapInfoCreateMemoryTest::elf64_at_map_; Loading Loading @@ -134,7 +134,7 @@ TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_full_file) { // Verify that if the offset is non-zero and there is an elf at that // offset, that only part of the file is used. TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file) { MapInfo info(nullptr, 0x100, 0x200, 0x100, 0, elf_at_100_.path); MapInfo info(nullptr, 0x100, 0x200, 0x1000, 0, elf_at_1000_.path); std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_)); ASSERT_TRUE(memory.get() != nullptr); Loading Loading @@ -312,4 +312,43 @@ TEST_F(MapInfoCreateMemoryTest, valid_rosegment_non_zero_offset) { } } TEST_F(MapInfoCreateMemoryTest, rosegment_from_file) { Maps maps; maps.Add(0x500, 0x600, 0, PROT_READ, "something_else", 0); maps.Add(0x1000, 0x2000, 0x1000, PROT_READ, elf_at_1000_.path, 0); maps.Add(0x2000, 0x3000, 0x2000, PROT_READ | PROT_EXEC, elf_at_1000_.path, 0); MapInfo* map_info = maps.Find(0x2000); ASSERT_TRUE(map_info != nullptr); // Set up the size Elf64_Ehdr ehdr; ASSERT_EQ(0x1000, lseek(elf_at_1000_.fd, 0x1000, SEEK_SET)); ASSERT_TRUE(android::base::ReadFully(elf_at_1000_.fd, &ehdr, sizeof(ehdr))); // Will not give the elf memory, because the read-only entry does not // extend over the executable segment. std::unique_ptr<Memory> memory(map_info->CreateMemory(process_memory_)); ASSERT_TRUE(memory.get() != nullptr); std::vector<uint8_t> buffer(0x100); EXPECT_EQ(0x2000U, map_info->offset); EXPECT_EQ(0U, map_info->elf_offset); ASSERT_TRUE(memory->ReadFully(0, buffer.data(), 0x100)); EXPECT_EQ(0xffU, buffer[0]); // Now init the elf data enough so that the file memory object will be used. ehdr.e_shoff = 0x4000; ehdr.e_shnum = 1; ehdr.e_shentsize = 0x100; ASSERT_EQ(0x1000, lseek(elf_at_1000_.fd, 0x1000, SEEK_SET)); ASSERT_TRUE(android::base::WriteFully(elf_at_1000_.fd, &ehdr, sizeof(ehdr))); memory.reset(map_info->CreateMemory(process_memory_)); EXPECT_EQ(0x2000U, map_info->offset); EXPECT_EQ(0x1000U, map_info->elf_offset); Elf64_Ehdr ehdr_mem; ASSERT_TRUE(memory->ReadFully(0, &ehdr_mem, sizeof(ehdr_mem))); EXPECT_TRUE(memcmp(&ehdr, &ehdr_mem, sizeof(ehdr)) == 0); } } // namespace unwindstack libunwindstack/tests/UnwindOfflineTest.cpp +75 −0 Original line number Diff line number Diff line Loading @@ -1239,4 +1239,79 @@ TEST_F(UnwindOfflineTest, debug_frame_load_bias_arm) { EXPECT_EQ(0xffd4a718U, unwinder.frames()[7].sp); } TEST_F(UnwindOfflineTest, shared_lib_in_apk_arm64) { ASSERT_NO_FATAL_FAILURE(Init("shared_lib_in_apk_arm64/", ARCH_ARM64)); Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_); unwinder.Unwind(); std::string frame_info(DumpFrames(unwinder)); ASSERT_EQ(7U, unwinder.NumFrames()) << "Unwind:\n" << frame_info; EXPECT_EQ( " #00 pc 000000000014ccbc (offset 0x39000) linker64 (__dl_syscall+28)\n" " #01 pc 000000000005426c (offset 0x39000) linker64 " "(__dl__ZL24debuggerd_signal_handleriP7siginfoPv+1128)\n" " #02 pc 00000000000008bc vdso.so\n" " #03 pc 00000000000846f4 (offset 0x40000) libc.so (abort+172)\n" " #04 pc 0000000000084ad4 (offset 0x40000) libc.so (__assert2+36)\n" " #05 pc 000000000003d5b4 (offset 0x40000) ANGLEPrebuilt.apk (ANGLEGetUtilityAPI+56)\n" " #06 pc 000000000007fe68 (offset 0x40000) libc.so (__libc_init)\n", frame_info); EXPECT_EQ(0x7e82c4fcbcULL, unwinder.frames()[0].pc); EXPECT_EQ(0x7df8ca3bf0ULL, unwinder.frames()[0].sp); EXPECT_EQ(0x7e82b5726cULL, unwinder.frames()[1].pc); EXPECT_EQ(0x7df8ca3bf0ULL, unwinder.frames()[1].sp); EXPECT_EQ(0x7e82b018bcULL, unwinder.frames()[2].pc); EXPECT_EQ(0x7df8ca3da0ULL, unwinder.frames()[2].sp); EXPECT_EQ(0x7e7eecc6f4ULL, unwinder.frames()[3].pc); EXPECT_EQ(0x7dabf3db60ULL, unwinder.frames()[3].sp); EXPECT_EQ(0x7e7eeccad4ULL, unwinder.frames()[4].pc); EXPECT_EQ(0x7dabf3dc40ULL, unwinder.frames()[4].sp); EXPECT_EQ(0x7dabc405b4ULL, unwinder.frames()[5].pc); EXPECT_EQ(0x7dabf3dc50ULL, unwinder.frames()[5].sp); EXPECT_EQ(0x7e7eec7e68ULL, unwinder.frames()[6].pc); EXPECT_EQ(0x7dabf3dc70ULL, unwinder.frames()[6].sp); // Ignore top frame since the test code was modified to end in __libc_init. } TEST_F(UnwindOfflineTest, shared_lib_in_apk_memory_only_arm64) { ASSERT_NO_FATAL_FAILURE(Init("shared_lib_in_apk_memory_only_arm64/", ARCH_ARM64)); // Add the memory that represents the shared library. MemoryOfflineParts* memory = reinterpret_cast<MemoryOfflineParts*>(process_memory_.get()); AddMemory(dir_ + "lib_mem.data", memory); Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_); unwinder.Unwind(); std::string frame_info(DumpFrames(unwinder)); ASSERT_EQ(7U, unwinder.NumFrames()) << "Unwind:\n" << frame_info; EXPECT_EQ( " #00 pc 000000000014ccbc (offset 0x39000) linker64 (__dl_syscall+28)\n" " #01 pc 000000000005426c (offset 0x39000) linker64 " "(__dl__ZL24debuggerd_signal_handleriP7siginfoPv+1128)\n" " #02 pc 00000000000008bc vdso.so\n" " #03 pc 00000000000846f4 (offset 0x40000) libc.so (abort+172)\n" " #04 pc 0000000000084ad4 (offset 0x40000) libc.so (__assert2+36)\n" " #05 pc 000000000003d5b4 (offset 0x2211000) ANGLEPrebuilt.apk\n" " #06 pc 000000000007fe68 (offset 0x40000) libc.so (__libc_init)\n", frame_info); EXPECT_EQ(0x7e82c4fcbcULL, unwinder.frames()[0].pc); EXPECT_EQ(0x7df8ca3bf0ULL, unwinder.frames()[0].sp); EXPECT_EQ(0x7e82b5726cULL, unwinder.frames()[1].pc); EXPECT_EQ(0x7df8ca3bf0ULL, unwinder.frames()[1].sp); EXPECT_EQ(0x7e82b018bcULL, unwinder.frames()[2].pc); EXPECT_EQ(0x7df8ca3da0ULL, unwinder.frames()[2].sp); EXPECT_EQ(0x7e7eecc6f4ULL, unwinder.frames()[3].pc); EXPECT_EQ(0x7dabf3db60ULL, unwinder.frames()[3].sp); EXPECT_EQ(0x7e7eeccad4ULL, unwinder.frames()[4].pc); EXPECT_EQ(0x7dabf3dc40ULL, unwinder.frames()[4].sp); EXPECT_EQ(0x7dabc405b4ULL, unwinder.frames()[5].pc); EXPECT_EQ(0x7dabf3dc50ULL, unwinder.frames()[5].sp); EXPECT_EQ(0x7e7eec7e68ULL, unwinder.frames()[6].pc); EXPECT_EQ(0x7dabf3dc70ULL, unwinder.frames()[6].sp); // Ignore top frame since the test code was modified to end in __libc_init. } } // namespace unwindstack Loading
libunwindstack/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -235,6 +235,8 @@ cc_test { "tests/files/offline/jit_map_arm/*", "tests/files/offline/gnu_debugdata_arm/*", "tests/files/offline/offset_arm/*", "tests/files/offline/shared_lib_in_apk_arm64/*", "tests/files/offline/shared_lib_in_apk_memory_only_arm64/*", "tests/files/offline/straddle_arm/*", "tests/files/offline/straddle_arm64/*", ], Loading
libunwindstack/MapInfo.cpp +82 −34 Original line number Diff line number Diff line Loading @@ -29,6 +29,38 @@ namespace unwindstack { bool MapInfo::InitFileMemoryFromPreviousReadOnlyMap(MemoryFileAtOffset* memory) { // One last attempt, see if the previous map is read-only with the // same name and stretches across this map. for (auto iter = maps_->begin(); iter != maps_->end(); ++iter) { if (*iter == this) { if (iter == maps_->begin()) { return false; } --iter; MapInfo* prev_map = *iter; // Make sure this is a read-only map. if (prev_map->flags != PROT_READ) { return false; } uint64_t map_size = end - prev_map->end; if (!memory->Init(name, prev_map->offset, map_size)) { return false; } uint64_t max_size; if (!Elf::GetInfo(memory, &max_size) || max_size < map_size) { return false; } if (!memory->Init(name, prev_map->offset, max_size)) { return false; } elf_offset = offset - prev_map->offset; return true; } } return false; } Memory* MapInfo::GetFileMemory() { std::unique_ptr<MemoryFileAtOffset> memory(new MemoryFileAtOffset); if (offset == 0) { Loading @@ -38,8 +70,12 @@ Memory* MapInfo::GetFileMemory() { return nullptr; } // There are two possibilities when the offset is non-zero. // - There is an elf file embedded in a file. // These are the possibilities when the offset is non-zero. // - There is an elf file embedded in a file, and the offset is the // the start of the elf in the file. // - There is an elf file embedded in a file, and the offset is the // the start of the executable part of the file. The actual start // of the elf is in the read-only segment preceeding this map. // - The whole file is an elf file, and the offset needs to be saved. // // Map in just the part of the file for the map. If this is not Loading @@ -53,28 +89,42 @@ Memory* MapInfo::GetFileMemory() { return nullptr; } uint64_t max_size; if (!Elf::GetInfo(memory.get(), &max_size)) { // Init as if the whole file is an elf. if (memory->Init(name, 0)) { elf_offset = offset; // Check if the start of this map is an embedded elf. uint64_t max_size = 0; uint64_t file_offset = offset; if (Elf::GetInfo(memory.get(), &max_size)) { if (max_size > map_size) { if (memory->Init(name, file_offset, max_size)) { return memory.release(); } // Try to reinit using the default map_size. if (memory->Init(name, file_offset, map_size)) { return memory.release(); } return nullptr; } return memory.release(); } if (max_size > map_size) { if (memory->Init(name, offset, max_size)) { // No elf at offset, try to init as if the whole file is an elf. if (memory->Init(name, 0) && Elf::IsValidElf(memory.get())) { elf_offset = offset; return memory.release(); } // Try to reinit using the default map_size. // See if the map previous to this one contains a read-only map // that represents the real start of the elf data. if (InitFileMemoryFromPreviousReadOnlyMap(memory.get())) { return memory.release(); } // Failed to find elf at start of file or at read-only map, return // file object from the current map. if (memory->Init(name, offset, map_size)) { return memory.release(); } return nullptr; } return memory.release(); } Memory* MapInfo::CreateMemory(const std::shared_ptr<Memory>& process_memory) { if (end <= start) { Loading Loading @@ -110,29 +160,27 @@ Memory* MapInfo::CreateMemory(const std::shared_ptr<Memory>& process_memory) { return nullptr; } // Find the read-only map that has the same name and has an offset closest // to the current offset but less than the offset of the current map. // For shared libraries, there should be a r-x map that has a non-zero // offset and then a r-- map that has a zero offset. // For shared libraries loaded from an apk, there should be a r-x map that // has a non-zero offset and then a r-- map that has a non-zero offset less // than the offset from the r-x map. uint64_t closest_offset = 0; // Find the read-only map by looking at the previous map. The linker // doesn't guarantee that this invariant will always be true. However, // if that changes, there is likely something else that will change and // break something. MapInfo* ro_map_info = nullptr; for (auto map_info : *maps_) { if (map_info->flags == PROT_READ && map_info->name == name && map_info->offset < offset && map_info->offset >= closest_offset) { ro_map_info = map_info; closest_offset = ro_map_info->offset; for (auto iter = maps_->begin(); iter != maps_->end(); ++iter) { if (*iter == this) { if (iter != maps_->begin()) { --iter; ro_map_info = *iter; } break; } } if (ro_map_info == nullptr) { if (ro_map_info == nullptr || ro_map_info->name != name || ro_map_info->offset >= offset) { return nullptr; } // Make sure that relative pc values are corrected properly. elf_offset = offset - closest_offset; elf_offset = offset - ro_map_info->offset; MemoryRanges* ranges = new MemoryRanges; ranges->Insert(new MemoryRange(process_memory, ro_map_info->start, Loading
libunwindstack/include/unwindstack/MapInfo.h +1 −0 Original line number Diff line number Diff line Loading @@ -83,6 +83,7 @@ struct MapInfo { void operator=(const MapInfo&) = delete; Memory* GetFileMemory(); bool InitFileMemoryFromPreviousReadOnlyMap(MemoryFileAtOffset* memory); // Protect the creation of the elf object. std::mutex mutex_; Loading
libunwindstack/tests/MapInfoCreateMemoryTest.cpp +48 −9 Original line number Diff line number Diff line Loading @@ -59,16 +59,16 @@ class MapInfoCreateMemoryTest : public ::testing::Test { } static void SetUpTestCase() { std::vector<uint8_t> buffer(1024); memset(buffer.data(), 0, buffer.size()); std::vector<uint8_t> buffer(12288, 0); memcpy(buffer.data(), ELFMAG, SELFMAG); buffer[EI_CLASS] = ELFCLASS32; ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size())); ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), 1024)); memset(buffer.data(), 0, buffer.size()); memcpy(&buffer[0x100], ELFMAG, SELFMAG); buffer[0x100 + EI_CLASS] = ELFCLASS64; ASSERT_TRUE(android::base::WriteFully(elf_at_100_.fd, buffer.data(), buffer.size())); memcpy(&buffer[0x1000], ELFMAG, SELFMAG); buffer[0x1000 + EI_CLASS] = ELFCLASS64; buffer[0x2000] = 0xff; ASSERT_TRUE(android::base::WriteFully(elf_at_1000_.fd, buffer.data(), buffer.size())); InitElf<Elf32_Ehdr, Elf32_Shdr>(elf32_at_map_.fd, 0x1000, 0x2000, ELFCLASS32); InitElf<Elf64_Ehdr, Elf64_Shdr>(elf64_at_map_.fd, 0x2000, 0x3000, ELFCLASS64); Loading @@ -84,13 +84,13 @@ class MapInfoCreateMemoryTest : public ::testing::Test { static TemporaryFile elf_; static TemporaryFile elf_at_100_; static TemporaryFile elf_at_1000_; static TemporaryFile elf32_at_map_; static TemporaryFile elf64_at_map_; }; TemporaryFile MapInfoCreateMemoryTest::elf_; TemporaryFile MapInfoCreateMemoryTest::elf_at_100_; TemporaryFile MapInfoCreateMemoryTest::elf_at_1000_; TemporaryFile MapInfoCreateMemoryTest::elf32_at_map_; TemporaryFile MapInfoCreateMemoryTest::elf64_at_map_; Loading Loading @@ -134,7 +134,7 @@ TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_full_file) { // Verify that if the offset is non-zero and there is an elf at that // offset, that only part of the file is used. TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file) { MapInfo info(nullptr, 0x100, 0x200, 0x100, 0, elf_at_100_.path); MapInfo info(nullptr, 0x100, 0x200, 0x1000, 0, elf_at_1000_.path); std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_)); ASSERT_TRUE(memory.get() != nullptr); Loading Loading @@ -312,4 +312,43 @@ TEST_F(MapInfoCreateMemoryTest, valid_rosegment_non_zero_offset) { } } TEST_F(MapInfoCreateMemoryTest, rosegment_from_file) { Maps maps; maps.Add(0x500, 0x600, 0, PROT_READ, "something_else", 0); maps.Add(0x1000, 0x2000, 0x1000, PROT_READ, elf_at_1000_.path, 0); maps.Add(0x2000, 0x3000, 0x2000, PROT_READ | PROT_EXEC, elf_at_1000_.path, 0); MapInfo* map_info = maps.Find(0x2000); ASSERT_TRUE(map_info != nullptr); // Set up the size Elf64_Ehdr ehdr; ASSERT_EQ(0x1000, lseek(elf_at_1000_.fd, 0x1000, SEEK_SET)); ASSERT_TRUE(android::base::ReadFully(elf_at_1000_.fd, &ehdr, sizeof(ehdr))); // Will not give the elf memory, because the read-only entry does not // extend over the executable segment. std::unique_ptr<Memory> memory(map_info->CreateMemory(process_memory_)); ASSERT_TRUE(memory.get() != nullptr); std::vector<uint8_t> buffer(0x100); EXPECT_EQ(0x2000U, map_info->offset); EXPECT_EQ(0U, map_info->elf_offset); ASSERT_TRUE(memory->ReadFully(0, buffer.data(), 0x100)); EXPECT_EQ(0xffU, buffer[0]); // Now init the elf data enough so that the file memory object will be used. ehdr.e_shoff = 0x4000; ehdr.e_shnum = 1; ehdr.e_shentsize = 0x100; ASSERT_EQ(0x1000, lseek(elf_at_1000_.fd, 0x1000, SEEK_SET)); ASSERT_TRUE(android::base::WriteFully(elf_at_1000_.fd, &ehdr, sizeof(ehdr))); memory.reset(map_info->CreateMemory(process_memory_)); EXPECT_EQ(0x2000U, map_info->offset); EXPECT_EQ(0x1000U, map_info->elf_offset); Elf64_Ehdr ehdr_mem; ASSERT_TRUE(memory->ReadFully(0, &ehdr_mem, sizeof(ehdr_mem))); EXPECT_TRUE(memcmp(&ehdr, &ehdr_mem, sizeof(ehdr)) == 0); } } // namespace unwindstack
libunwindstack/tests/UnwindOfflineTest.cpp +75 −0 Original line number Diff line number Diff line Loading @@ -1239,4 +1239,79 @@ TEST_F(UnwindOfflineTest, debug_frame_load_bias_arm) { EXPECT_EQ(0xffd4a718U, unwinder.frames()[7].sp); } TEST_F(UnwindOfflineTest, shared_lib_in_apk_arm64) { ASSERT_NO_FATAL_FAILURE(Init("shared_lib_in_apk_arm64/", ARCH_ARM64)); Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_); unwinder.Unwind(); std::string frame_info(DumpFrames(unwinder)); ASSERT_EQ(7U, unwinder.NumFrames()) << "Unwind:\n" << frame_info; EXPECT_EQ( " #00 pc 000000000014ccbc (offset 0x39000) linker64 (__dl_syscall+28)\n" " #01 pc 000000000005426c (offset 0x39000) linker64 " "(__dl__ZL24debuggerd_signal_handleriP7siginfoPv+1128)\n" " #02 pc 00000000000008bc vdso.so\n" " #03 pc 00000000000846f4 (offset 0x40000) libc.so (abort+172)\n" " #04 pc 0000000000084ad4 (offset 0x40000) libc.so (__assert2+36)\n" " #05 pc 000000000003d5b4 (offset 0x40000) ANGLEPrebuilt.apk (ANGLEGetUtilityAPI+56)\n" " #06 pc 000000000007fe68 (offset 0x40000) libc.so (__libc_init)\n", frame_info); EXPECT_EQ(0x7e82c4fcbcULL, unwinder.frames()[0].pc); EXPECT_EQ(0x7df8ca3bf0ULL, unwinder.frames()[0].sp); EXPECT_EQ(0x7e82b5726cULL, unwinder.frames()[1].pc); EXPECT_EQ(0x7df8ca3bf0ULL, unwinder.frames()[1].sp); EXPECT_EQ(0x7e82b018bcULL, unwinder.frames()[2].pc); EXPECT_EQ(0x7df8ca3da0ULL, unwinder.frames()[2].sp); EXPECT_EQ(0x7e7eecc6f4ULL, unwinder.frames()[3].pc); EXPECT_EQ(0x7dabf3db60ULL, unwinder.frames()[3].sp); EXPECT_EQ(0x7e7eeccad4ULL, unwinder.frames()[4].pc); EXPECT_EQ(0x7dabf3dc40ULL, unwinder.frames()[4].sp); EXPECT_EQ(0x7dabc405b4ULL, unwinder.frames()[5].pc); EXPECT_EQ(0x7dabf3dc50ULL, unwinder.frames()[5].sp); EXPECT_EQ(0x7e7eec7e68ULL, unwinder.frames()[6].pc); EXPECT_EQ(0x7dabf3dc70ULL, unwinder.frames()[6].sp); // Ignore top frame since the test code was modified to end in __libc_init. } TEST_F(UnwindOfflineTest, shared_lib_in_apk_memory_only_arm64) { ASSERT_NO_FATAL_FAILURE(Init("shared_lib_in_apk_memory_only_arm64/", ARCH_ARM64)); // Add the memory that represents the shared library. MemoryOfflineParts* memory = reinterpret_cast<MemoryOfflineParts*>(process_memory_.get()); AddMemory(dir_ + "lib_mem.data", memory); Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_); unwinder.Unwind(); std::string frame_info(DumpFrames(unwinder)); ASSERT_EQ(7U, unwinder.NumFrames()) << "Unwind:\n" << frame_info; EXPECT_EQ( " #00 pc 000000000014ccbc (offset 0x39000) linker64 (__dl_syscall+28)\n" " #01 pc 000000000005426c (offset 0x39000) linker64 " "(__dl__ZL24debuggerd_signal_handleriP7siginfoPv+1128)\n" " #02 pc 00000000000008bc vdso.so\n" " #03 pc 00000000000846f4 (offset 0x40000) libc.so (abort+172)\n" " #04 pc 0000000000084ad4 (offset 0x40000) libc.so (__assert2+36)\n" " #05 pc 000000000003d5b4 (offset 0x2211000) ANGLEPrebuilt.apk\n" " #06 pc 000000000007fe68 (offset 0x40000) libc.so (__libc_init)\n", frame_info); EXPECT_EQ(0x7e82c4fcbcULL, unwinder.frames()[0].pc); EXPECT_EQ(0x7df8ca3bf0ULL, unwinder.frames()[0].sp); EXPECT_EQ(0x7e82b5726cULL, unwinder.frames()[1].pc); EXPECT_EQ(0x7df8ca3bf0ULL, unwinder.frames()[1].sp); EXPECT_EQ(0x7e82b018bcULL, unwinder.frames()[2].pc); EXPECT_EQ(0x7df8ca3da0ULL, unwinder.frames()[2].sp); EXPECT_EQ(0x7e7eecc6f4ULL, unwinder.frames()[3].pc); EXPECT_EQ(0x7dabf3db60ULL, unwinder.frames()[3].sp); EXPECT_EQ(0x7e7eeccad4ULL, unwinder.frames()[4].pc); EXPECT_EQ(0x7dabf3dc40ULL, unwinder.frames()[4].sp); EXPECT_EQ(0x7dabc405b4ULL, unwinder.frames()[5].pc); EXPECT_EQ(0x7dabf3dc50ULL, unwinder.frames()[5].sp); EXPECT_EQ(0x7e7eec7e68ULL, unwinder.frames()[6].pc); EXPECT_EQ(0x7dabf3dc70ULL, unwinder.frames()[6].sp); // Ignore top frame since the test code was modified to end in __libc_init. } } // namespace unwindstack