diff options
author | Christopher Ferris <cferris@google.com> | 2020-01-22 12:17:06 -0800 |
---|---|---|
committer | Christopher Ferris <cferris@google.com> | 2020-01-22 18:30:12 -0800 |
commit | 22363d327fc53841c7e7725469db6809872ba2f0 (patch) | |
tree | 46d0fa327289a8eb44158632059bc2105723b243 /libunwindstack/tests | |
parent | 5f65745c00d62e69e2c0cda7dbcf3ae56399ec9e (diff) | |
download | unwinding-22363d327fc53841c7e7725469db6809872ba2f0.tar.gz |
Properly handle empty map after read-only map.
Recently, the maps for an elf in memory might show up looking like:
f0000-f1000 0 r-- /system/lib/libc.so
f1000-f2000 0 ---
f2000-f3000 1000 r-x /system/lib/libc.so
f3000-f4000 2000 rw- /system/lib/libc.so
The problem is that there is logic in the code that assumed that the
map before the execute map must be the read-only map. In the case
above, this is not true. Add a new prev_real_map that will point
to the previous map that is not one of these empty maps.
This will fix the backtraces that look like this:
#00 pc 0000000000050d58 /apex/com.android.runtime/lib64/bionic/libc.so!libc.so (offset 0x50000) (syscall+24) (BuildId: 5252408bf30e395d49ee270b54c77ca4)
To get rid of the !libc.so and the offset value, which is not correct.
Added new unit tests to verify this.
Added new offline test which an empty map between read-only and execute
map. Before this change, the backtraces had lines like
libc.so!libc.so (offset XXX) would be present.
Bug: 148075852
Test: Ran unit tests.
Change-Id: Ie04bfc96b8f91ed885cb1e655cf1e346efe48a45
Diffstat (limited to 'libunwindstack/tests')
17 files changed, 170 insertions, 69 deletions
diff --git a/libunwindstack/tests/DexFileTest.cpp b/libunwindstack/tests/DexFileTest.cpp index 0149a42..1b54da6 100644 --- a/libunwindstack/tests/DexFileTest.cpp +++ b/libunwindstack/tests/DexFileTest.cpp @@ -105,7 +105,7 @@ TEST(DexFileTest, create_using_file) { static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData))))); MemoryFake memory; - MapInfo info(nullptr, 0, 0x10000, 0, 0x5, tf.path); + MapInfo info(nullptr, nullptr, 0, 0x10000, 0, 0x5, tf.path); EXPECT_TRUE(DexFile::Create(0x500, &memory, &info) != nullptr); } @@ -118,7 +118,7 @@ TEST(DexFileTest, create_using_file_non_zero_start) { static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData))))); MemoryFake memory; - MapInfo info(nullptr, 0x100, 0x10000, 0, 0x5, tf.path); + MapInfo info(nullptr, nullptr, 0x100, 0x10000, 0, 0x5, tf.path); EXPECT_TRUE(DexFile::Create(0x600, &memory, &info) != nullptr); } @@ -131,21 +131,21 @@ TEST(DexFileTest, create_using_file_non_zero_offset) { static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData))))); MemoryFake memory; - MapInfo info(nullptr, 0x100, 0x10000, 0x200, 0x5, tf.path); + MapInfo info(nullptr, nullptr, 0x100, 0x10000, 0x200, 0x5, tf.path); EXPECT_TRUE(DexFile::Create(0x400, &memory, &info) != nullptr); } TEST(DexFileTest, create_using_memory_empty_file) { MemoryFake memory; memory.SetMemory(0x4000, kDexData, sizeof(kDexData)); - MapInfo info(nullptr, 0x100, 0x10000, 0x200, 0x5, ""); + MapInfo info(nullptr, nullptr, 0x100, 0x10000, 0x200, 0x5, ""); EXPECT_TRUE(DexFile::Create(0x4000, &memory, &info) != nullptr); } TEST(DexFileTest, create_using_memory_file_does_not_exist) { MemoryFake memory; memory.SetMemory(0x4000, kDexData, sizeof(kDexData)); - MapInfo info(nullptr, 0x100, 0x10000, 0x200, 0x5, "/does/not/exist"); + MapInfo info(nullptr, nullptr, 0x100, 0x10000, 0x200, 0x5, "/does/not/exist"); EXPECT_TRUE(DexFile::Create(0x4000, &memory, &info) != nullptr); } @@ -158,7 +158,7 @@ TEST(DexFileTest, create_using_memory_file_is_malformed) { MemoryFake memory; memory.SetMemory(0x4000, kDexData, sizeof(kDexData)); - MapInfo info(nullptr, 0x4000, 0x10000, 0x200, 0x5, "/does/not/exist"); + MapInfo info(nullptr, nullptr, 0x4000, 0x10000, 0x200, 0x5, "/does/not/exist"); std::unique_ptr<DexFile> dex_file = DexFile::Create(0x4000, &memory, &info); ASSERT_TRUE(dex_file != nullptr); @@ -171,7 +171,7 @@ TEST(DexFileTest, create_using_memory_file_is_malformed) { TEST(DexFileTest, get_method) { MemoryFake memory; memory.SetMemory(0x4000, kDexData, sizeof(kDexData)); - MapInfo info(nullptr, 0x100, 0x10000, 0x200, 0x5, ""); + MapInfo info(nullptr, nullptr, 0x100, 0x10000, 0x200, 0x5, ""); std::unique_ptr<DexFile> dex_file(DexFile::Create(0x4000, &memory, &info)); ASSERT_TRUE(dex_file != nullptr); @@ -189,7 +189,7 @@ TEST(DexFileTest, get_method) { TEST(DexFileTest, get_method_empty) { MemoryFake memory; memory.SetMemory(0x4000, kDexData, sizeof(kDexData)); - MapInfo info(nullptr, 0x100, 0x10000, 0x200, 0x5, ""); + MapInfo info(nullptr, nullptr, 0x100, 0x10000, 0x200, 0x5, ""); std::unique_ptr<DexFile> dex_file(DexFile::Create(0x4000, &memory, &info)); ASSERT_TRUE(dex_file != nullptr); diff --git a/libunwindstack/tests/ElfCacheTest.cpp b/libunwindstack/tests/ElfCacheTest.cpp index 5735858..5f13546 100644 --- a/libunwindstack/tests/ElfCacheTest.cpp +++ b/libunwindstack/tests/ElfCacheTest.cpp @@ -78,8 +78,8 @@ void ElfCacheTest::VerifySameMap(bool cache_enabled) { uint64_t start = 0x1000; uint64_t end = 0x20000; - MapInfo info1(nullptr, start, end, 0, 0x5, tf.path); - MapInfo info2(nullptr, start, end, 0, 0x5, tf.path); + MapInfo info1(nullptr, nullptr, start, end, 0, 0x5, tf.path); + MapInfo info2(nullptr, nullptr, start, end, 0, 0x5, tf.path); Elf* elf1 = info1.GetElf(memory_, ARCH_ARM); ASSERT_TRUE(elf1->valid()); @@ -119,17 +119,17 @@ void ElfCacheTest::VerifyWithinSameMap(bool cache_enabled) { uint64_t start = 0x1000; uint64_t end = 0x20000; // Will have an elf at offset 0 in file. - MapInfo info0_1(nullptr, start, end, 0, 0x5, tf.path); - MapInfo info0_2(nullptr, start, end, 0, 0x5, tf.path); + MapInfo info0_1(nullptr, nullptr, start, end, 0, 0x5, tf.path); + MapInfo info0_2(nullptr, nullptr, start, end, 0, 0x5, tf.path); // Will have an elf at offset 0x100 in file. - MapInfo info100_1(nullptr, start, end, 0x100, 0x5, tf.path); - MapInfo info100_2(nullptr, start, end, 0x100, 0x5, tf.path); + MapInfo info100_1(nullptr, nullptr, start, end, 0x100, 0x5, tf.path); + MapInfo info100_2(nullptr, nullptr, start, end, 0x100, 0x5, tf.path); // Will have an elf at offset 0x200 in file. - MapInfo info200_1(nullptr, start, end, 0x200, 0x5, tf.path); - MapInfo info200_2(nullptr, start, end, 0x200, 0x5, tf.path); + MapInfo info200_1(nullptr, nullptr, start, end, 0x200, 0x5, tf.path); + MapInfo info200_2(nullptr, nullptr, start, end, 0x200, 0x5, tf.path); // Will have an elf at offset 0 in file. - MapInfo info300_1(nullptr, start, end, 0x300, 0x5, tf.path); - MapInfo info300_2(nullptr, start, end, 0x300, 0x5, tf.path); + MapInfo info300_1(nullptr, nullptr, start, end, 0x300, 0x5, tf.path); + MapInfo info300_2(nullptr, nullptr, start, end, 0x300, 0x5, tf.path); Elf* elf0_1 = info0_1.GetElf(memory_, ARCH_ARM); ASSERT_TRUE(elf0_1->valid()); @@ -216,10 +216,10 @@ void ElfCacheTest::VerifyWithinSameMapNeverReadAtZero(bool cache_enabled) { uint64_t start = 0x1000; uint64_t end = 0x20000; // Multiple info sections at different offsets will have non-zero elf offsets. - MapInfo info300_1(nullptr, start, end, 0x300, 0x5, tf.path); - MapInfo info300_2(nullptr, start, end, 0x300, 0x5, tf.path); - MapInfo info400_1(nullptr, start, end, 0x400, 0x5, tf.path); - MapInfo info400_2(nullptr, start, end, 0x400, 0x5, tf.path); + MapInfo info300_1(nullptr, nullptr, start, end, 0x300, 0x5, tf.path); + MapInfo info300_2(nullptr, nullptr, start, end, 0x300, 0x5, tf.path); + MapInfo info400_1(nullptr, nullptr, start, end, 0x400, 0x5, tf.path); + MapInfo info400_2(nullptr, nullptr, start, end, 0x400, 0x5, tf.path); Elf* elf300_1 = info300_1.GetElf(memory_, ARCH_ARM); ASSERT_TRUE(elf300_1->valid()); diff --git a/libunwindstack/tests/ElfTest.cpp b/libunwindstack/tests/ElfTest.cpp index 4866345..1f3ed81 100644 --- a/libunwindstack/tests/ElfTest.cpp +++ b/libunwindstack/tests/ElfTest.cpp @@ -275,7 +275,7 @@ TEST_F(ElfTest, rel_pc) { elf.FakeSetInterface(interface); elf.FakeSetValid(true); - MapInfo map_info(nullptr, 0x1000, 0x2000, 0, 0, ""); + MapInfo map_info(nullptr, nullptr, 0x1000, 0x2000, 0, 0, ""); ASSERT_EQ(0x101U, elf.GetRelPc(0x1101, &map_info)); diff --git a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp index 6c1cfa2..6d8d58e 100644 --- a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp +++ b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp @@ -89,7 +89,7 @@ class MapInfoCreateMemoryTest : public ::testing::Test { }; TEST_F(MapInfoCreateMemoryTest, end_le_start) { - MapInfo info(nullptr, 0x100, 0x100, 0, 0, elf_.path); + MapInfo info(nullptr, nullptr, 0x100, 0x100, 0, 0, elf_.path); std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_)); ASSERT_TRUE(memory.get() == nullptr); @@ -108,7 +108,7 @@ TEST_F(MapInfoCreateMemoryTest, end_le_start) { // Verify that if the offset is non-zero but there is no elf at the offset, // that the full file is used. TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_full_file) { - MapInfo info(nullptr, 0x100, 0x200, 0x100, 0, elf_.path); + MapInfo info(nullptr, nullptr, 0x100, 0x200, 0x100, 0, elf_.path); std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_)); ASSERT_TRUE(memory.get() != nullptr); @@ -129,8 +129,9 @@ TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_full_file) { // Now verify the elf start offset is set correctly based on the previous // info. - MapInfo prev_info(nullptr, 0, 0x100, 0x10, 0, ""); + MapInfo prev_info(nullptr, nullptr, 0, 0x100, 0x10, 0, ""); info.prev_map = &prev_info; + info.prev_real_map = &prev_info; // No preconditions met, change each one until it should set the elf start // offset to zero. @@ -177,7 +178,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, 0x1000, 0, elf_at_1000_.path); + MapInfo info(nullptr, nullptr, 0x100, 0x200, 0x1000, 0, elf_at_1000_.path); std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_)); ASSERT_TRUE(memory.get() != nullptr); @@ -202,7 +203,7 @@ TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file) { // embedded elf is bigger than the initial map, the new object is larger // than the original map size. Do this for a 32 bit elf and a 64 bit elf. TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file_whole_elf32) { - MapInfo info(nullptr, 0x5000, 0x6000, 0x1000, 0, elf32_at_map_.path); + MapInfo info(nullptr, nullptr, 0x5000, 0x6000, 0x1000, 0, elf32_at_map_.path); std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_)); ASSERT_TRUE(memory.get() != nullptr); @@ -220,7 +221,7 @@ TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file_whole_e } TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file_whole_elf64) { - MapInfo info(nullptr, 0x7000, 0x8000, 0x2000, 0, elf64_at_map_.path); + MapInfo info(nullptr, nullptr, 0x7000, 0x8000, 0x2000, 0, elf64_at_map_.path); std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_)); ASSERT_TRUE(memory.get() != nullptr); @@ -243,14 +244,14 @@ TEST_F(MapInfoCreateMemoryTest, check_device_maps) { // be returned if the file mapping fails, but the device check is incorrect. std::vector<uint8_t> buffer(1024); uint64_t start = reinterpret_cast<uint64_t>(buffer.data()); - MapInfo info(nullptr, start, start + buffer.size(), 0, 0x8000, "/dev/something"); + MapInfo info(nullptr, nullptr, start, start + buffer.size(), 0, 0x8000, "/dev/something"); std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_)); ASSERT_TRUE(memory.get() == nullptr); } TEST_F(MapInfoCreateMemoryTest, process_memory) { - MapInfo info(nullptr, 0x2000, 0x3000, 0, PROT_READ, ""); + MapInfo info(nullptr, nullptr, 0x2000, 0x3000, 0, PROT_READ, ""); Elf32_Ehdr ehdr = {}; TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM); diff --git a/libunwindstack/tests/MapInfoGetBuildIDTest.cpp b/libunwindstack/tests/MapInfoGetBuildIDTest.cpp index 16451d1..6953e26 100644 --- a/libunwindstack/tests/MapInfoGetBuildIDTest.cpp +++ b/libunwindstack/tests/MapInfoGetBuildIDTest.cpp @@ -50,7 +50,8 @@ class MapInfoGetBuildIDTest : public ::testing::Test { elf_interface_ = new ElfInterfaceFake(memory_); elf_->FakeSetInterface(elf_interface_); elf_container_.reset(elf_); - map_info_.reset(new MapInfo(nullptr, 0x1000, 0x20000, 0, PROT_READ | PROT_WRITE, tf_->path)); + map_info_.reset( + new MapInfo(nullptr, nullptr, 0x1000, 0x20000, 0, PROT_READ | PROT_WRITE, tf_->path)); } void MultipleThreadTest(std::string expected_build_id); @@ -64,7 +65,7 @@ class MapInfoGetBuildIDTest : public ::testing::Test { }; TEST_F(MapInfoGetBuildIDTest, no_elf_and_no_valid_elf_in_memory) { - MapInfo info(nullptr, 0x1000, 0x2000, 0, PROT_READ, ""); + MapInfo info(nullptr, nullptr, 0x1000, 0x2000, 0, PROT_READ, ""); EXPECT_EQ("", info.GetBuildID()); EXPECT_EQ("", info.GetPrintableBuildID()); diff --git a/libunwindstack/tests/MapInfoGetElfTest.cpp b/libunwindstack/tests/MapInfoGetElfTest.cpp index d60b8b1..7f97814 100644 --- a/libunwindstack/tests/MapInfoGetElfTest.cpp +++ b/libunwindstack/tests/MapInfoGetElfTest.cpp @@ -68,7 +68,7 @@ class MapInfoGetElfTest : public ::testing::Test { }; TEST_F(MapInfoGetElfTest, invalid) { - MapInfo info(nullptr, 0x1000, 0x2000, 0, PROT_READ, ""); + MapInfo info(nullptr, nullptr, 0x1000, 0x2000, 0, PROT_READ, ""); // The map is empty, but this should still create an invalid elf object. Elf* elf = info.GetElf(process_memory_, ARCH_ARM); @@ -77,7 +77,7 @@ TEST_F(MapInfoGetElfTest, invalid) { } TEST_F(MapInfoGetElfTest, valid32) { - MapInfo info(nullptr, 0x3000, 0x4000, 0, PROT_READ, ""); + MapInfo info(nullptr, nullptr, 0x3000, 0x4000, 0, PROT_READ, ""); Elf32_Ehdr ehdr; TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM); @@ -97,7 +97,7 @@ TEST_F(MapInfoGetElfTest, valid32) { } TEST_F(MapInfoGetElfTest, valid64) { - MapInfo info(nullptr, 0x8000, 0x9000, 0, PROT_READ, ""); + MapInfo info(nullptr, nullptr, 0x8000, 0x9000, 0, PROT_READ, ""); Elf64_Ehdr ehdr; TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_AARCH64); @@ -111,7 +111,7 @@ TEST_F(MapInfoGetElfTest, valid64) { } TEST_F(MapInfoGetElfTest, invalid_arch_mismatch) { - MapInfo info(nullptr, 0x3000, 0x4000, 0, PROT_READ, ""); + MapInfo info(nullptr, nullptr, 0x3000, 0x4000, 0, PROT_READ, ""); Elf32_Ehdr ehdr; TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM); @@ -123,7 +123,7 @@ TEST_F(MapInfoGetElfTest, invalid_arch_mismatch) { } TEST_F(MapInfoGetElfTest, gnu_debugdata_init32) { - MapInfo info(nullptr, 0x2000, 0x3000, 0, PROT_READ, ""); + MapInfo info(nullptr, nullptr, 0x2000, 0x3000, 0, PROT_READ, ""); TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(ELFCLASS32, EM_ARM, true, [&](uint64_t offset, const void* ptr, size_t size) { @@ -139,7 +139,7 @@ TEST_F(MapInfoGetElfTest, gnu_debugdata_init32) { } TEST_F(MapInfoGetElfTest, gnu_debugdata_init64) { - MapInfo info(nullptr, 0x5000, 0x8000, 0, PROT_READ, ""); + MapInfo info(nullptr, nullptr, 0x5000, 0x8000, 0, PROT_READ, ""); TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(ELFCLASS64, EM_AARCH64, true, [&](uint64_t offset, const void* ptr, size_t size) { @@ -155,7 +155,7 @@ TEST_F(MapInfoGetElfTest, gnu_debugdata_init64) { } TEST_F(MapInfoGetElfTest, end_le_start) { - MapInfo info(nullptr, 0x1000, 0x1000, 0, PROT_READ, elf_.path); + MapInfo info(nullptr, nullptr, 0x1000, 0x1000, 0, PROT_READ, elf_.path); Elf32_Ehdr ehdr; TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM); @@ -182,7 +182,7 @@ TEST_F(MapInfoGetElfTest, end_le_start) { // Verify that if the offset is non-zero but there is no elf at the offset, // that the full file is used. TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_full_file) { - MapInfo info(nullptr, 0x1000, 0x2000, 0x100, PROT_READ, elf_.path); + MapInfo info(nullptr, nullptr, 0x1000, 0x2000, 0x100, PROT_READ, elf_.path); std::vector<uint8_t> buffer(0x1000); memset(buffer.data(), 0, buffer.size()); @@ -211,7 +211,7 @@ TEST_F(MapInfoGetElfTest, 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(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file) { - MapInfo info(nullptr, 0x1000, 0x2000, 0x2000, PROT_READ, elf_.path); + MapInfo info(nullptr, nullptr, 0x1000, 0x2000, 0x2000, PROT_READ, elf_.path); std::vector<uint8_t> buffer(0x4000); memset(buffer.data(), 0, buffer.size()); @@ -241,7 +241,7 @@ TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file) { // embedded elf is bigger than the initial map, the new object is larger // than the original map size. Do this for a 32 bit elf and a 64 bit elf. TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file_whole_elf32) { - MapInfo info(nullptr, 0x5000, 0x6000, 0x1000, PROT_READ, elf_.path); + MapInfo info(nullptr, nullptr, 0x5000, 0x6000, 0x1000, PROT_READ, elf_.path); std::vector<uint8_t> buffer(0x4000); memset(buffer.data(), 0, buffer.size()); @@ -269,7 +269,7 @@ TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file_whole_elf32) } TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file_whole_elf64) { - MapInfo info(nullptr, 0x7000, 0x8000, 0x1000, PROT_READ, elf_.path); + MapInfo info(nullptr, nullptr, 0x7000, 0x8000, 0x1000, PROT_READ, elf_.path); std::vector<uint8_t> buffer(0x4000); memset(buffer.data(), 0, buffer.size()); @@ -297,7 +297,7 @@ TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file_whole_elf64) } TEST_F(MapInfoGetElfTest, check_device_maps) { - MapInfo info(nullptr, 0x7000, 0x8000, 0x1000, PROT_READ | MAPS_FLAGS_DEVICE_MAP, + MapInfo info(nullptr, nullptr, 0x7000, 0x8000, 0x1000, PROT_READ | MAPS_FLAGS_DEVICE_MAP, "/dev/something"); // Create valid elf data in process memory for this to verify that only @@ -343,7 +343,7 @@ TEST_F(MapInfoGetElfTest, multiple_thread_get_elf) { wait = true; // Create all of the threads and have them do the GetElf at the same time // to make it likely that a race will occur. - MapInfo info(nullptr, 0x7000, 0x8000, 0x1000, PROT_READ, ""); + MapInfo info(nullptr, nullptr, 0x7000, 0x8000, 0x1000, PROT_READ, ""); for (size_t i = 0; i < kNumConcurrentThreads; i++) { std::thread* thread = new std::thread([i, this, &wait, &info, &elf_in_threads]() { while (wait) @@ -373,8 +373,8 @@ TEST_F(MapInfoGetElfTest, multiple_thread_get_elf) { // Verify that previous maps don't automatically get the same elf object. TEST_F(MapInfoGetElfTest, prev_map_elf_not_set) { - MapInfo info1(nullptr, 0x1000, 0x2000, 0, PROT_READ, "/not/present"); - MapInfo info2(&info1, 0x2000, 0x3000, 0, PROT_READ, elf_.path); + MapInfo info1(nullptr, nullptr, 0x1000, 0x2000, 0, PROT_READ, "/not/present"); + MapInfo info2(&info1, &info1, 0x2000, 0x3000, 0, PROT_READ, elf_.path); Elf32_Ehdr ehdr; TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM); @@ -389,8 +389,25 @@ TEST_F(MapInfoGetElfTest, prev_map_elf_not_set) { // Verify that a read-only map followed by a read-execute map will result // in the same elf object in both maps. TEST_F(MapInfoGetElfTest, read_only_followed_by_read_exec_share_elf) { - MapInfo r_info(nullptr, 0x1000, 0x2000, 0, PROT_READ, elf_.path); - MapInfo rw_info(&r_info, 0x2000, 0x3000, 0x1000, PROT_READ | PROT_EXEC, elf_.path); + MapInfo r_info(nullptr, nullptr, 0x1000, 0x2000, 0, PROT_READ, elf_.path); + MapInfo rw_info(&r_info, &r_info, 0x2000, 0x3000, 0x1000, PROT_READ | PROT_EXEC, elf_.path); + + Elf32_Ehdr ehdr; + TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM); + memory_->SetMemory(0x1000, &ehdr, sizeof(ehdr)); + Elf* elf = rw_info.GetElf(process_memory_, ARCH_ARM); + ASSERT_TRUE(elf != nullptr); + ASSERT_TRUE(elf->valid()); + + ASSERT_EQ(elf, r_info.GetElf(process_memory_, ARCH_ARM)); +} + +// Verify that a read-only map followed by an empty map, then followed by +// a read-execute map will result in the same elf object in both maps. +TEST_F(MapInfoGetElfTest, read_only_followed_by_empty_then_read_exec_share_elf) { + MapInfo r_info(nullptr, nullptr, 0x1000, 0x2000, 0, PROT_READ, elf_.path); + MapInfo empty(&r_info, &r_info, 0x2000, 0x3000, 0, 0, ""); + MapInfo rw_info(&empty, &r_info, 0x3000, 0x4000, 0x2000, PROT_READ | PROT_EXEC, elf_.path); Elf32_Ehdr ehdr; TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM); diff --git a/libunwindstack/tests/MapInfoGetLoadBiasTest.cpp b/libunwindstack/tests/MapInfoGetLoadBiasTest.cpp index da3dbf2..971d452 100644 --- a/libunwindstack/tests/MapInfoGetLoadBiasTest.cpp +++ b/libunwindstack/tests/MapInfoGetLoadBiasTest.cpp @@ -50,7 +50,7 @@ class MapInfoGetLoadBiasTest : public ::testing::Test { process_memory_.reset(memory_); elf_ = new ElfFake(new MemoryFake); elf_container_.reset(elf_); - map_info_.reset(new MapInfo(nullptr, 0x1000, 0x20000, 0, PROT_READ | PROT_WRITE, "")); + map_info_.reset(new MapInfo(nullptr, nullptr, 0x1000, 0x20000, 0, PROT_READ | PROT_WRITE, "")); } void MultipleThreadTest(uint64_t expected_load_bias); @@ -63,7 +63,7 @@ class MapInfoGetLoadBiasTest : public ::testing::Test { }; TEST_F(MapInfoGetLoadBiasTest, no_elf_and_no_valid_elf_in_memory) { - MapInfo info(nullptr, 0x1000, 0x2000, 0, PROT_READ, ""); + MapInfo info(nullptr, nullptr, 0x1000, 0x2000, 0, PROT_READ, ""); EXPECT_EQ(0U, info.GetLoadBias(process_memory_)); } diff --git a/libunwindstack/tests/MapInfoTest.cpp b/libunwindstack/tests/MapInfoTest.cpp index ef76b1b..98edc0e 100644 --- a/libunwindstack/tests/MapInfoTest.cpp +++ b/libunwindstack/tests/MapInfoTest.cpp @@ -26,8 +26,8 @@ namespace unwindstack { TEST(MapInfoTest, maps_constructor_const_char) { - MapInfo prev_map(nullptr, 0, 0, 0, 0, ""); - MapInfo map_info(&prev_map, 1, 2, 3, 4, "map"); + MapInfo prev_map(nullptr, nullptr, 0, 0, 0, 0, ""); + MapInfo map_info(&prev_map, &prev_map, 1, 2, 3, 4, "map"); EXPECT_EQ(&prev_map, map_info.prev_map); EXPECT_EQ(1UL, map_info.start); @@ -42,8 +42,8 @@ TEST(MapInfoTest, maps_constructor_const_char) { TEST(MapInfoTest, maps_constructor_string) { std::string name("string_map"); - MapInfo prev_map(nullptr, 0, 0, 0, 0, ""); - MapInfo map_info(&prev_map, 1, 2, 3, 4, name); + MapInfo prev_map(nullptr, nullptr, 0, 0, 0, 0, ""); + MapInfo map_info(&prev_map, &prev_map, 1, 2, 3, 4, name); EXPECT_EQ(&prev_map, map_info.prev_map); EXPECT_EQ(1UL, map_info.start); @@ -62,7 +62,7 @@ TEST(MapInfoTest, get_function_name) { elf->FakeSetInterface(interface); interface->FakePushFunctionData(FunctionData("function", 1000)); - MapInfo map_info(nullptr, 1, 2, 3, 4, ""); + MapInfo map_info(nullptr, nullptr, 1, 2, 3, 4, ""); map_info.elf.reset(elf); std::string name; diff --git a/libunwindstack/tests/MapsTest.cpp b/libunwindstack/tests/MapsTest.cpp index 9e7a6ab..724eeb5 100644 --- a/libunwindstack/tests/MapsTest.cpp +++ b/libunwindstack/tests/MapsTest.cpp @@ -82,7 +82,7 @@ TEST(MapsTest, map_move) { } TEST(MapsTest, verify_parse_line) { - MapInfo info(nullptr, 0, 0, 0, 0, ""); + MapInfo info(nullptr, nullptr, 0, 0, 0, 0, ""); VerifyLine("01-02 rwxp 03 04:05 06\n", &info); EXPECT_EQ(1U, info.start); @@ -155,7 +155,7 @@ TEST(MapsTest, verify_parse_line) { } TEST(MapsTest, verify_large_values) { - MapInfo info(nullptr, 0, 0, 0, 0, ""); + MapInfo info(nullptr, nullptr, 0, 0, 0, 0, ""); #if defined(__LP64__) VerifyLine("fabcdef012345678-f12345678abcdef8 rwxp f0b0d0f010305070 00:00 0\n", &info); EXPECT_EQ(0xfabcdef012345678UL, info.start); diff --git a/libunwindstack/tests/RegsTest.cpp b/libunwindstack/tests/RegsTest.cpp index 472d1cf..0a33e2f 100644 --- a/libunwindstack/tests/RegsTest.cpp +++ b/libunwindstack/tests/RegsTest.cpp @@ -182,7 +182,7 @@ TEST_F(RegsTest, elf_invalid) { RegsX86_64 regs_x86_64; RegsMips regs_mips; RegsMips64 regs_mips64; - MapInfo map_info(nullptr, 0x1000, 0x2000, 0, 0, ""); + MapInfo map_info(nullptr, nullptr, 0x1000, 0x2000, 0, 0, ""); Elf* invalid_elf = new Elf(nullptr); map_info.elf.reset(invalid_elf); diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp index 364101a..c2bd836 100644 --- a/libunwindstack/tests/UnwindOfflineTest.cpp +++ b/libunwindstack/tests/UnwindOfflineTest.cpp @@ -169,15 +169,18 @@ std::unordered_map<std::string, uint32_t> UnwindOfflineTest::arm_regs_ = { }; std::unordered_map<std::string, uint32_t> UnwindOfflineTest::arm64_regs_ = { - {"x0", ARM64_REG_R0}, {"x1", ARM64_REG_R1}, {"x2", ARM64_REG_R2}, {"x3", ARM64_REG_R3}, - {"x4", ARM64_REG_R4}, {"x5", ARM64_REG_R5}, {"x6", ARM64_REG_R6}, {"x7", ARM64_REG_R7}, - {"x8", ARM64_REG_R8}, {"x9", ARM64_REG_R9}, {"x10", ARM64_REG_R10}, {"x11", ARM64_REG_R11}, - {"x12", ARM64_REG_R12}, {"x13", ARM64_REG_R13}, {"x14", ARM64_REG_R14}, {"x15", ARM64_REG_R15}, - {"x16", ARM64_REG_R16}, {"x17", ARM64_REG_R17}, {"x18", ARM64_REG_R18}, {"x19", ARM64_REG_R19}, - {"x20", ARM64_REG_R20}, {"x21", ARM64_REG_R21}, {"x22", ARM64_REG_R22}, {"x23", ARM64_REG_R23}, - {"x24", ARM64_REG_R24}, {"x25", ARM64_REG_R25}, {"x26", ARM64_REG_R26}, {"x27", ARM64_REG_R27}, - {"x28", ARM64_REG_R28}, {"x29", ARM64_REG_R29}, {"sp", ARM64_REG_SP}, {"lr", ARM64_REG_LR}, - {"pc", ARM64_REG_PC}, + {"x0", ARM64_REG_R0}, {"x1", ARM64_REG_R1}, {"x2", ARM64_REG_R2}, + {"x3", ARM64_REG_R3}, {"x4", ARM64_REG_R4}, {"x5", ARM64_REG_R5}, + {"x6", ARM64_REG_R6}, {"x7", ARM64_REG_R7}, {"x8", ARM64_REG_R8}, + {"x9", ARM64_REG_R9}, {"x10", ARM64_REG_R10}, {"x11", ARM64_REG_R11}, + {"x12", ARM64_REG_R12}, {"x13", ARM64_REG_R13}, {"x14", ARM64_REG_R14}, + {"x15", ARM64_REG_R15}, {"x16", ARM64_REG_R16}, {"x17", ARM64_REG_R17}, + {"x18", ARM64_REG_R18}, {"x19", ARM64_REG_R19}, {"x20", ARM64_REG_R20}, + {"x21", ARM64_REG_R21}, {"x22", ARM64_REG_R22}, {"x23", ARM64_REG_R23}, + {"x24", ARM64_REG_R24}, {"x25", ARM64_REG_R25}, {"x26", ARM64_REG_R26}, + {"x27", ARM64_REG_R27}, {"x28", ARM64_REG_R28}, {"x29", ARM64_REG_R29}, + {"sp", ARM64_REG_SP}, {"lr", ARM64_REG_LR}, {"pc", ARM64_REG_PC}, + {"pst", ARM64_REG_PSTATE}, }; std::unordered_map<std::string, uint32_t> UnwindOfflineTest::x86_regs_ = { @@ -1697,4 +1700,40 @@ TEST_F(UnwindOfflineTest, signal_load_bias_arm) { EXPECT_EQ(0xffe67d10ULL, unwinder.frames()[16].sp); } +TEST_F(UnwindOfflineTest, empty_arm64) { + ASSERT_NO_FATAL_FAILURE(Init("empty_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 00000000000963a4 libc.so (__ioctl+4)\n" + " #01 pc 000000000005344c libc.so (ioctl+140)\n" + " #02 pc 0000000000050ce4 libbinder.so " + "(android::IPCThreadState::talkWithDriver(bool)+308)\n" + " #03 pc 0000000000050e98 libbinder.so " + "(android::IPCThreadState::getAndExecuteCommand()+24)\n" + " #04 pc 00000000000516ac libbinder.so (android::IPCThreadState::joinThreadPool(bool)+60)\n" + " #05 pc 00000000000443b0 netd (main+1056)\n" + " #06 pc 0000000000045594 libc.so (__libc_init+108)\n", + frame_info); + + EXPECT_EQ(0x72a02203a4U, unwinder.frames()[0].pc); + EXPECT_EQ(0x7ffb6c0b50U, unwinder.frames()[0].sp); + EXPECT_EQ(0x72a01dd44cU, unwinder.frames()[1].pc); + EXPECT_EQ(0x7ffb6c0b50U, unwinder.frames()[1].sp); + EXPECT_EQ(0x729f759ce4U, unwinder.frames()[2].pc); + EXPECT_EQ(0x7ffb6c0c50U, unwinder.frames()[2].sp); + EXPECT_EQ(0x729f759e98U, unwinder.frames()[3].pc); + EXPECT_EQ(0x7ffb6c0ce0U, unwinder.frames()[3].sp); + EXPECT_EQ(0x729f75a6acU, unwinder.frames()[4].pc); + EXPECT_EQ(0x7ffb6c0d10U, unwinder.frames()[4].sp); + EXPECT_EQ(0x5d478af3b0U, unwinder.frames()[5].pc); + EXPECT_EQ(0x7ffb6c0d40U, unwinder.frames()[5].sp); + EXPECT_EQ(0x72a01cf594U, unwinder.frames()[6].pc); + EXPECT_EQ(0x7ffb6c0f30U, unwinder.frames()[6].sp); +} + } // namespace unwindstack diff --git a/libunwindstack/tests/files/offline/empty_arm64/libbinder.so b/libunwindstack/tests/files/offline/empty_arm64/libbinder.so Binary files differnew file mode 100644 index 0000000..f30384c --- /dev/null +++ b/libunwindstack/tests/files/offline/empty_arm64/libbinder.so diff --git a/libunwindstack/tests/files/offline/empty_arm64/libc.so b/libunwindstack/tests/files/offline/empty_arm64/libc.so Binary files differnew file mode 100644 index 0000000..b05dcaf --- /dev/null +++ b/libunwindstack/tests/files/offline/empty_arm64/libc.so diff --git a/libunwindstack/tests/files/offline/empty_arm64/maps.txt b/libunwindstack/tests/files/offline/empty_arm64/maps.txt new file mode 100644 index 0000000..edb83c6 --- /dev/null +++ b/libunwindstack/tests/files/offline/empty_arm64/maps.txt @@ -0,0 +1,9 @@ +5d4786b000-5d47893000 r--p 0 00:00 0 netd +5d47893000-5d47894000 ---p 0 00:00 0 +5d47894000-5d47901000 --xp 29000 00:00 0 netd +729f709000-729f750000 r--p 0 00:00 0 libbinder.so +729f750000-729f751000 ---p 0 00:00 0 +729f751000-729f794000 --xp 48000 00:00 0 libbinder.so +72a018a000-72a01c2000 r--p 0 00:00 0 libc.so +72a01c2000-72a01c3000 ---p 0 00:00 0 +72a01c3000-72a023b000 --xp 39000 00:00 0 libc.so diff --git a/libunwindstack/tests/files/offline/empty_arm64/netd b/libunwindstack/tests/files/offline/empty_arm64/netd Binary files differnew file mode 100644 index 0000000..8a72e94 --- /dev/null +++ b/libunwindstack/tests/files/offline/empty_arm64/netd diff --git a/libunwindstack/tests/files/offline/empty_arm64/regs.txt b/libunwindstack/tests/files/offline/empty_arm64/regs.txt new file mode 100644 index 0000000..3d4279f --- /dev/null +++ b/libunwindstack/tests/files/offline/empty_arm64/regs.txt @@ -0,0 +1,34 @@ +x0: 1d +x1: c0306201 +x2: 7ffb6c0c50 +x3: 0 +x4: 0 +x5: 0 +x6: 0 +x7: 0 +x8: 1d +x9: 7ffb6c0c00 +x10: 7ffb6c0c50 +x11: 7ffb6c0bd0 +x12: ffffff80ffffffd0 +x13: 0 +x14: 72a0240ce2 +x15: 20 +x16: 729f7a54e8 +x17: 72a01dd3c0 +x18: 72a0ac2000 +x19: 72a0666000 +x20: 719769b610 +x21: 719769b730 +x22: c0306201 +x23: fffffff7 +x24: 72a0666000 +x25: 0 +x26: 0 +x27: 0 +x28: 0 +x29: 7ffb6c0c30 +sp: 7ffb6c0b50 +lr: 72a01dd450 +pc: 72a02203a4 +pst: a0000000 diff --git a/libunwindstack/tests/files/offline/empty_arm64/stack.data b/libunwindstack/tests/files/offline/empty_arm64/stack.data Binary files differnew file mode 100644 index 0000000..6d6108c --- /dev/null +++ b/libunwindstack/tests/files/offline/empty_arm64/stack.data |