From a09c4a6ff2806644c8baf0b93415078fa252b0e9 Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Thu, 13 Dec 2018 16:08:50 -0800 Subject: [PATCH] Fix offsets when shared lib split across maps. The linker was modified so that a shared library has a read-only map, then a read-execute map to represent the whole shared library. When backtraces are created, then the offsets are set incorrectly for backtraces. For example, all backtraces wind up with an offset now, and a shared library loaded out of an apk shows the wrong offset. Changes: - Fix the FormatFrame function which was putting the offset before the map name. - Refactor the Maps and MapInfo classes to keep track of the previous map instead of all maps. This was the only map that was ever needed. - Modify the unwind_for_offline tool to capture both the read-only and read-execute map when using the read-only segment option. Bug: 120981155 Test: Updated unit tests pass. Test: Unwinds on device don't show the offsets everywhere any more. Change-Id: I75b3727221be9c20316dfdcd7a1c6d242d7ce948 --- libbacktrace/UnwindStack.cpp | 2 +- libunwindstack/MapInfo.cpp | 85 +++--- libunwindstack/Maps.cpp | 16 +- libunwindstack/Unwinder.cpp | 15 +- libunwindstack/include/unwindstack/MapInfo.h | 31 +-- libunwindstack/include/unwindstack/Unwinder.h | 8 +- libunwindstack/tests/ElfTest.cpp | 2 +- .../tests/MapInfoCreateMemoryTest.cpp | 46 ++++ libunwindstack/tests/MapsTest.cpp | 4 +- libunwindstack/tests/RegsTest.cpp | 2 +- libunwindstack/tests/UnwindOfflineTest.cpp | 64 ++--- libunwindstack/tests/UnwinderTest.cpp | 242 +++++++++--------- .../tests/files/offline/offset_arm/maps.txt | 2 + libunwindstack/tools/unwind_for_offline.cpp | 87 +++++-- 14 files changed, 361 insertions(+), 245 deletions(-) diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp index fe28eba41..f5f9b2ada 100644 --- a/libbacktrace/UnwindStack.cpp +++ b/libbacktrace/UnwindStack.cpp @@ -117,7 +117,7 @@ bool Backtrace::Unwind(unwindstack::Regs* regs, BacktraceMap* back_map, back_frame->map.name = frame->map_name; back_frame->map.start = frame->map_start; back_frame->map.end = frame->map_end; - back_frame->map.offset = frame->map_offset; + back_frame->map.offset = frame->map_elf_start_offset; back_frame->map.load_bias = frame->map_load_bias; back_frame->map.flags = frame->map_flags; } diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp index 44ec5c1d2..39a09cf41 100644 --- a/libunwindstack/MapInfo.cpp +++ b/libunwindstack/MapInfo.cpp @@ -32,33 +32,27 @@ 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; - } + if (prev_map == nullptr || prev_map->flags != PROT_READ) { + return false; } - 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; + elf_start_offset = prev_map->offset; + return true; } Memory* MapInfo::GetFileMemory() { @@ -91,14 +85,13 @@ Memory* MapInfo::GetFileMemory() { // 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)) { + if (memory->Init(name, offset, max_size)) { return memory.release(); } // Try to reinit using the default map_size. - if (memory->Init(name, file_offset, map_size)) { + if (memory->Init(name, offset, map_size)) { return memory.release(); } return nullptr; @@ -109,6 +102,13 @@ Memory* MapInfo::GetFileMemory() { // 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; + // Need to check how to set the elf start offset. If this map is not + // the r-x map of a r-- map, then use the real offset value. Otherwise, + // use 0. + if (prev_map == nullptr || prev_map->offset != 0 || prev_map->flags != PROT_READ || + prev_map->name != name) { + elf_start_offset = offset; + } return memory.release(); } @@ -156,35 +156,24 @@ Memory* MapInfo::CreateMemory(const std::shared_ptr& process_memory) { return memory.release(); } - if (name.empty() || maps_ == nullptr) { - return nullptr; - } - // 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 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 || ro_map_info->name != name || ro_map_info->offset >= offset) { + if (offset == 0 || name.empty() || prev_map == nullptr || prev_map->name != name || + prev_map->offset >= offset) { return nullptr; } // Make sure that relative pc values are corrected properly. - elf_offset = offset - ro_map_info->offset; + elf_offset = offset - prev_map->offset; + // Use this as the elf start offset, otherwise, you always get offsets into + // the r-x section, which is not quite the right information. + elf_start_offset = prev_map->offset; MemoryRanges* ranges = new MemoryRanges; - ranges->Insert(new MemoryRange(process_memory, ro_map_info->start, - ro_map_info->end - ro_map_info->start, 0)); + ranges->Insert( + new MemoryRange(process_memory, prev_map->start, prev_map->end - prev_map->start, 0)); ranges->Insert(new MemoryRange(process_memory, start, end - start, elf_offset)); return ranges; diff --git a/libunwindstack/Maps.cpp b/libunwindstack/Maps.cpp index a9fb859eb..c90e38309 100644 --- a/libunwindstack/Maps.cpp +++ b/libunwindstack/Maps.cpp @@ -67,13 +67,15 @@ bool Maps::Parse() { if (strncmp(name, "/dev/", 5) == 0 && strncmp(name + 5, "ashmem/", 7) != 0) { flags |= unwindstack::MAPS_FLAGS_DEVICE_MAP; } - maps_.push_back(new MapInfo(this, start, end, pgoff, flags, name)); + maps_.push_back( + new MapInfo(maps_.empty() ? nullptr : maps_.back(), start, end, pgoff, flags, name)); }); } void Maps::Add(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags, const std::string& name, uint64_t load_bias) { - MapInfo* map_info = new MapInfo(this, start, end, offset, flags, name); + MapInfo* map_info = + new MapInfo(maps_.empty() ? nullptr : maps_.back(), start, end, offset, flags, name); map_info->load_bias = load_bias; maps_.push_back(map_info); } @@ -81,6 +83,13 @@ void Maps::Add(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags, void Maps::Sort() { std::sort(maps_.begin(), maps_.end(), [](const MapInfo* a, const MapInfo* b) { return a->start < b->start; }); + + // Set the prev_map values on the info objects. + MapInfo* prev_map = nullptr; + for (MapInfo* map_info : maps_) { + map_info->prev_map = prev_map; + prev_map = map_info; + } } Maps::~Maps() { @@ -98,7 +107,8 @@ bool BufferMaps::Parse() { if (strncmp(name, "/dev/", 5) == 0 && strncmp(name + 5, "ashmem/", 7) != 0) { flags |= unwindstack::MAPS_FLAGS_DEVICE_MAP; } - maps_.push_back(new MapInfo(this, start, end, pgoff, flags, name)); + maps_.push_back( + new MapInfo(maps_.empty() ? nullptr : maps_.back(), start, end, pgoff, flags, name)); }); } diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp index 792cd0b70..813363905 100644 --- a/libunwindstack/Unwinder.cpp +++ b/libunwindstack/Unwinder.cpp @@ -59,7 +59,8 @@ void Unwinder::FillInDexFrame() { if (info != nullptr) { frame->map_start = info->start; frame->map_end = info->end; - frame->map_offset = info->offset; + frame->map_elf_start_offset = info->elf_start_offset; + frame->map_exact_offset = info->offset; frame->map_load_bias = info->load_bias; frame->map_flags = info->flags; if (resolve_names_) { @@ -102,7 +103,8 @@ void Unwinder::FillInFrame(MapInfo* map_info, Elf* elf, uint64_t rel_pc, uint64_ if (resolve_names_) { frame->map_name = map_info->name; } - frame->map_offset = map_info->offset; + frame->map_elf_start_offset = map_info->elf_start_offset; + frame->map_exact_offset = map_info->offset; frame->map_start = map_info->start; frame->map_end = map_info->end; frame->map_flags = map_info->flags; @@ -290,10 +292,6 @@ std::string Unwinder::FormatFrame(const FrameData& frame, bool is32bit) { data += android::base::StringPrintf(" #%02zu pc %016" PRIx64, frame.num, frame.rel_pc); } - if (frame.map_offset != 0) { - data += android::base::StringPrintf(" (offset 0x%" PRIx64 ")", frame.map_offset); - } - if (frame.map_start == frame.map_end) { // No valid map associated with this frame. data += " "; @@ -302,6 +300,11 @@ std::string Unwinder::FormatFrame(const FrameData& frame, bool is32bit) { } else { data += android::base::StringPrintf(" ", frame.map_start); } + + if (frame.map_elf_start_offset != 0) { + data += android::base::StringPrintf(" (offset 0x%" PRIx64 ")", frame.map_elf_start_offset); + } + if (!frame.function_name.empty()) { data += " (" + frame.function_name; if (frame.function_offset != 0) { diff --git a/libunwindstack/include/unwindstack/MapInfo.h b/libunwindstack/include/unwindstack/MapInfo.h index cfdefd0bb..5e3d6f607 100644 --- a/libunwindstack/include/unwindstack/MapInfo.h +++ b/libunwindstack/include/unwindstack/MapInfo.h @@ -25,38 +25,31 @@ #include #include +#include namespace unwindstack { -// Forward declarations. -class Maps; -class Memory; - struct MapInfo { - MapInfo(Maps* maps) : maps_(maps) {} - MapInfo(Maps* maps, uint64_t start, uint64_t end) : maps_(maps), start(start), end(end) {} - MapInfo(Maps* maps, uint64_t start, uint64_t end, uint64_t offset, uint64_t flags, + MapInfo(MapInfo* map_info, uint64_t start, uint64_t end, uint64_t offset, uint64_t flags, const char* name) - : maps_(maps), - start(start), + : start(start), end(end), offset(offset), flags(flags), name(name), + prev_map(map_info), load_bias(static_cast(-1)) {} - MapInfo(Maps* maps, uint64_t start, uint64_t end, uint64_t offset, uint64_t flags, + MapInfo(MapInfo* map_info, uint64_t start, uint64_t end, uint64_t offset, uint64_t flags, const std::string& name) - : maps_(maps), - start(start), + : start(start), end(end), offset(offset), flags(flags), name(name), + prev_map(map_info), load_bias(static_cast(-1)) {} ~MapInfo() = default; - Maps* maps_ = nullptr; - uint64_t start = 0; uint64_t end = 0; uint64_t offset = 0; @@ -64,10 +57,14 @@ struct MapInfo { std::string name; std::shared_ptr elf; // This value is only non-zero if the offset is non-zero but there is - // no elf signature found at that offset. This indicates that the - // entire file is represented by the Memory object returned by CreateMemory, - // instead of a portion of the file. + // no elf signature found at that offset. uint64_t elf_offset = 0; + // This value is the offset from the map in memory that is the start + // of the elf. This is not equal to offset when the linker splits + // shared libraries into a read-only and read-execute map. + uint64_t elf_start_offset = 0; + + MapInfo* prev_map = nullptr; std::atomic_uint64_t load_bias; diff --git a/libunwindstack/include/unwindstack/Unwinder.h b/libunwindstack/include/unwindstack/Unwinder.h index 56b058156..d7bbd9d3d 100644 --- a/libunwindstack/include/unwindstack/Unwinder.h +++ b/libunwindstack/include/unwindstack/Unwinder.h @@ -48,7 +48,13 @@ struct FrameData { uint64_t function_offset = 0; std::string map_name; - uint64_t map_offset = 0; + // The offset from the first map representing the frame. When there are + // two maps (read-only and read-execute) this will be the offset from + // the read-only map. When there is only one map, this will be the + // same as the actual offset of the map and match map_exact_offset. + uint64_t map_elf_start_offset = 0; + // The actual offset from the map where the pc lies. + uint64_t map_exact_offset = 0; uint64_t map_start = 0; uint64_t map_end = 0; uint64_t map_load_bias = 0; diff --git a/libunwindstack/tests/ElfTest.cpp b/libunwindstack/tests/ElfTest.cpp index 7766218b1..f7689ceb7 100644 --- a/libunwindstack/tests/ElfTest.cpp +++ b/libunwindstack/tests/ElfTest.cpp @@ -269,7 +269,7 @@ TEST_F(ElfTest, rel_pc) { elf.FakeSetInterface(interface); elf.FakeSetValid(true); - MapInfo map_info(nullptr, 0x1000, 0x2000); + MapInfo map_info(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 943b3c9dc..a66685a26 100644 --- a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp +++ b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp @@ -118,6 +118,7 @@ TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_full_file) { std::unique_ptr memory(info.CreateMemory(process_memory_)); ASSERT_TRUE(memory.get() != nullptr); ASSERT_EQ(0x100U, info.elf_offset); + EXPECT_EQ(0x100U, info.elf_start_offset); // Read the entire file. std::vector buffer(1024); @@ -129,6 +130,44 @@ TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_full_file) { } ASSERT_FALSE(memory->ReadFully(1024, buffer.data(), 1)); + + // Now verify the elf start offset is set correctly based on the previous + // info. + MapInfo prev_info(nullptr, 0, 0x100, 0x10, 0, ""); + info.prev_map = &prev_info; + + // No preconditions met, change each one until it should set the elf start + // offset to zero. + info.elf_offset = 0; + info.elf_start_offset = 0; + memory.reset(info.CreateMemory(process_memory_)); + ASSERT_TRUE(memory.get() != nullptr); + ASSERT_EQ(0x100U, info.elf_offset); + EXPECT_EQ(0x100U, info.elf_start_offset); + + prev_info.offset = 0; + info.elf_offset = 0; + info.elf_start_offset = 0; + memory.reset(info.CreateMemory(process_memory_)); + ASSERT_TRUE(memory.get() != nullptr); + ASSERT_EQ(0x100U, info.elf_offset); + EXPECT_EQ(0x100U, info.elf_start_offset); + + prev_info.flags = PROT_READ; + info.elf_offset = 0; + info.elf_start_offset = 0; + memory.reset(info.CreateMemory(process_memory_)); + ASSERT_TRUE(memory.get() != nullptr); + ASSERT_EQ(0x100U, info.elf_offset); + EXPECT_EQ(0x100U, info.elf_start_offset); + + prev_info.name = info.name; + info.elf_offset = 0; + info.elf_start_offset = 0; + memory.reset(info.CreateMemory(process_memory_)); + ASSERT_TRUE(memory.get() != nullptr); + ASSERT_EQ(0x100U, info.elf_offset); + EXPECT_EQ(0U, info.elf_start_offset); } // Verify that if the offset is non-zero and there is an elf at that @@ -139,6 +178,7 @@ TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file) { std::unique_ptr memory(info.CreateMemory(process_memory_)); ASSERT_TRUE(memory.get() != nullptr); ASSERT_EQ(0U, info.elf_offset); + EXPECT_EQ(0U, info.elf_start_offset); // Read the valid part of the file. std::vector buffer(0x100); @@ -162,6 +202,7 @@ TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file_whole_e std::unique_ptr memory(info.CreateMemory(process_memory_)); ASSERT_TRUE(memory.get() != nullptr); ASSERT_EQ(0U, info.elf_offset); + EXPECT_EQ(0U, info.elf_start_offset); // Verify the memory is a valid elf. uint8_t e_ident[SELFMAG + 1]; @@ -178,6 +219,7 @@ TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file_whole_e std::unique_ptr memory(info.CreateMemory(process_memory_)); ASSERT_TRUE(memory.get() != nullptr); ASSERT_EQ(0U, info.elf_offset); + EXPECT_EQ(0U, info.elf_start_offset); // Verify the memory is a valid elf. uint8_t e_ident[SELFMAG + 1]; @@ -250,6 +292,7 @@ TEST_F(MapInfoCreateMemoryTest, valid_rosegment_zero_offset) { ASSERT_TRUE(mem.get() != nullptr); EXPECT_EQ(0x4000UL, map_info->elf_offset); EXPECT_EQ(0x4000UL, map_info->offset); + EXPECT_EQ(0U, map_info->elf_start_offset); // Verify that reading values from this memory works properly. std::vector buffer(0x4000); @@ -295,6 +338,7 @@ TEST_F(MapInfoCreateMemoryTest, valid_rosegment_non_zero_offset) { ASSERT_TRUE(mem.get() != nullptr); EXPECT_EQ(0x1000UL, map_info->elf_offset); EXPECT_EQ(0xb000UL, map_info->offset); + EXPECT_EQ(0xa000UL, map_info->elf_start_offset); // Verify that reading values from this memory works properly. std::vector buffer(0x4000); @@ -333,6 +377,7 @@ TEST_F(MapInfoCreateMemoryTest, rosegment_from_file) { std::vector buffer(0x100); EXPECT_EQ(0x2000U, map_info->offset); EXPECT_EQ(0U, map_info->elf_offset); + EXPECT_EQ(0U, map_info->elf_start_offset); ASSERT_TRUE(memory->ReadFully(0, buffer.data(), 0x100)); EXPECT_EQ(0xffU, buffer[0]); @@ -346,6 +391,7 @@ TEST_F(MapInfoCreateMemoryTest, rosegment_from_file) { memory.reset(map_info->CreateMemory(process_memory_)); EXPECT_EQ(0x2000U, map_info->offset); EXPECT_EQ(0x1000U, map_info->elf_offset); + EXPECT_EQ(0x1000U, map_info->elf_start_offset); Elf64_Ehdr ehdr_mem; ASSERT_TRUE(memory->ReadFully(0, &ehdr_mem, sizeof(ehdr_mem))); EXPECT_TRUE(memcmp(&ehdr, &ehdr_mem, sizeof(ehdr)) == 0); diff --git a/libunwindstack/tests/MapsTest.cpp b/libunwindstack/tests/MapsTest.cpp index 80e292a63..b4197f2a1 100644 --- a/libunwindstack/tests/MapsTest.cpp +++ b/libunwindstack/tests/MapsTest.cpp @@ -62,7 +62,7 @@ TEST(MapsTest, map_add) { } TEST(MapsTest, verify_parse_line) { - MapInfo info(nullptr); + MapInfo info(nullptr, 0, 0, 0, 0, ""); VerifyLine("01-02 rwxp 03 04:05 06\n", &info); EXPECT_EQ(1U, info.start); @@ -135,7 +135,7 @@ TEST(MapsTest, verify_parse_line) { } TEST(MapsTest, verify_large_values) { - MapInfo info(nullptr); + MapInfo info(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 00264c2c5..472d1cfa4 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); + MapInfo map_info(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 dc015b4b6..aab9ec20d 100644 --- a/libunwindstack/tests/UnwindOfflineTest.cpp +++ b/libunwindstack/tests/UnwindOfflineTest.cpp @@ -298,7 +298,7 @@ TEST_F(UnwindOfflineTest, jit_debug_x86) { EXPECT_EQ( " #00 pc 00068fb8 libarttestd.so (_ZN3artL13CauseSegfaultEv+72)\n" " #01 pc 00067f00 libarttestd.so (Java_Main_unwindInProcess+10032)\n" - " #02 pc 000021a8 (offset 0x2000) 137-cfi.odex (boolean Main.unwindInProcess(boolean, int, " + " #02 pc 000021a8 137-cfi.odex (offset 0x2000) (boolean Main.unwindInProcess(boolean, int, " "boolean)+136)\n" " #03 pc 0000fe80 anonymous:ee74c000 (boolean Main.bar(boolean)+64)\n" " #04 pc 006ad4d2 libartd.so (art_quick_invoke_stub+338)\n" @@ -591,7 +591,7 @@ TEST_F(UnwindOfflineTest, jit_debug_arm) { ASSERT_EQ(76U, unwinder.NumFrames()) << "Unwind:\n" << frame_info; EXPECT_EQ( " #00 pc 00018a5e libarttestd.so (Java_Main_unwindInProcess+866)\n" - " #01 pc 0000212d (offset 0x2000) 137-cfi.odex (boolean Main.unwindInProcess(boolean, int, " + " #01 pc 0000212d 137-cfi.odex (offset 0x2000) (boolean Main.unwindInProcess(boolean, int, " "boolean)+92)\n" " #02 pc 00011cb1 anonymous:e2796000 (boolean Main.bar(boolean)+72)\n" " #03 pc 00462175 libartd.so (art_quick_invoke_stub_internal+68)\n" @@ -1135,29 +1135,29 @@ TEST_F(UnwindOfflineTest, offset_arm) { std::string frame_info(DumpFrames(unwinder)); ASSERT_EQ(19U, unwinder.NumFrames()) << "Unwind:\n" << frame_info; EXPECT_EQ( - " #00 pc 0032bfa0 (offset 0x42000) libunwindstack_test (SignalInnerFunction+40)\n" - " #01 pc 0032bfeb (offset 0x42000) libunwindstack_test (SignalMiddleFunction+2)\n" - " #02 pc 0032bff3 (offset 0x42000) libunwindstack_test (SignalOuterFunction+2)\n" - " #03 pc 0032fed3 (offset 0x42000) libunwindstack_test " + " #00 pc 0032bfa0 libunwindstack_test (SignalInnerFunction+40)\n" + " #01 pc 0032bfeb libunwindstack_test (SignalMiddleFunction+2)\n" + " #02 pc 0032bff3 libunwindstack_test (SignalOuterFunction+2)\n" + " #03 pc 0032fed3 libunwindstack_test " "(_ZN11unwindstackL19SignalCallerHandlerEiP7siginfoPv+26)\n" - " #04 pc 00026528 (offset 0x25000) libc.so\n" + " #04 pc 00026528 libc.so\n" " #05 pc 00000000 \n" - " #06 pc 0032c2d9 (offset 0x42000) libunwindstack_test (InnerFunction+736)\n" - " #07 pc 0032cc4f (offset 0x42000) libunwindstack_test (MiddleFunction+42)\n" - " #08 pc 0032cc81 (offset 0x42000) libunwindstack_test (OuterFunction+42)\n" - " #09 pc 0032e547 (offset 0x42000) libunwindstack_test " + " #06 pc 0032c2d9 libunwindstack_test (InnerFunction+736)\n" + " #07 pc 0032cc4f libunwindstack_test (MiddleFunction+42)\n" + " #08 pc 0032cc81 libunwindstack_test (OuterFunction+42)\n" + " #09 pc 0032e547 libunwindstack_test " "(_ZN11unwindstackL19RemoteThroughSignalEij+270)\n" - " #10 pc 0032ed99 (offset 0x42000) libunwindstack_test " + " #10 pc 0032ed99 libunwindstack_test " "(_ZN11unwindstack55UnwindTest_remote_through_signal_with_invalid_func_Test8TestBodyEv+16)\n" - " #11 pc 00354453 (offset 0x42000) libunwindstack_test (_ZN7testing4Test3RunEv+154)\n" - " #12 pc 00354de7 (offset 0x42000) libunwindstack_test (_ZN7testing8TestInfo3RunEv+194)\n" - " #13 pc 00355105 (offset 0x42000) libunwindstack_test (_ZN7testing8TestCase3RunEv+180)\n" - " #14 pc 0035a215 (offset 0x42000) libunwindstack_test " + " #11 pc 00354453 libunwindstack_test (_ZN7testing4Test3RunEv+154)\n" + " #12 pc 00354de7 libunwindstack_test (_ZN7testing8TestInfo3RunEv+194)\n" + " #13 pc 00355105 libunwindstack_test (_ZN7testing8TestCase3RunEv+180)\n" + " #14 pc 0035a215 libunwindstack_test " "(_ZN7testing8internal12UnitTestImpl11RunAllTestsEv+664)\n" - " #15 pc 00359f4f (offset 0x42000) libunwindstack_test (_ZN7testing8UnitTest3RunEv+110)\n" - " #16 pc 0034d3db (offset 0x42000) libunwindstack_test (main+38)\n" - " #17 pc 00092c0d (offset 0x25000) libc.so (__libc_init+48)\n" - " #18 pc 0004202f (offset 0x42000) libunwindstack_test (_start_main+38)\n", + " #15 pc 00359f4f libunwindstack_test (_ZN7testing8UnitTest3RunEv+110)\n" + " #16 pc 0034d3db libunwindstack_test (main+38)\n" + " #17 pc 00092c0d libc.so (__libc_init+48)\n" + " #18 pc 0004202f libunwindstack_test (_start_main+38)\n", frame_info); EXPECT_EQ(0x2e55fa0U, unwinder.frames()[0].pc); @@ -1248,14 +1248,14 @@ TEST_F(UnwindOfflineTest, shared_lib_in_apk_arm64) { 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 " + " #00 pc 000000000014ccbc linker64 (__dl_syscall+28)\n" + " #01 pc 000000000005426c 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", + " #03 pc 00000000000846f4 libc.so (abort+172)\n" + " #04 pc 0000000000084ad4 libc.so (__assert2+36)\n" + " #05 pc 000000000003d5b4 ANGLEPrebuilt.apk (offset 0x4000) (ANGLEGetUtilityAPI+56)\n" + " #06 pc 000000000007fe68 libc.so (__libc_init)\n", frame_info); EXPECT_EQ(0x7e82c4fcbcULL, unwinder.frames()[0].pc); @@ -1287,14 +1287,14 @@ TEST_F(UnwindOfflineTest, shared_lib_in_apk_memory_only_arm64) { 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 " + " #00 pc 000000000014ccbc linker64 (__dl_syscall+28)\n" + " #01 pc 000000000005426c 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", + " #03 pc 00000000000846f4 libc.so (abort+172)\n" + " #04 pc 0000000000084ad4 libc.so (__assert2+36)\n" + " #05 pc 000000000003d5b4 ANGLEPrebuilt.apk (offset 0x21d5000)\n" + " #06 pc 000000000007fe68 libc.so (__libc_init)\n", frame_info); EXPECT_EQ(0x7e82c4fcbcULL, unwinder.frames()[0].pc); diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp index c4b87631c..1fdeee566 100644 --- a/libunwindstack/tests/UnwinderTest.cpp +++ b/libunwindstack/tests/UnwinderTest.cpp @@ -42,84 +42,64 @@ namespace unwindstack { -class MapsFake : public Maps { - public: - MapsFake() = default; - virtual ~MapsFake() = default; - - bool Parse() { return true; } - - void FakeClear() { maps_.clear(); } - - void FakeAddMapInfo(MapInfo* map_info) { maps_.push_back(map_info); } -}; - class UnwinderTest : public ::testing::Test { protected: + static void AddMapInfo(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags, + const char* name, Elf* elf = nullptr) { + std::string str_name(name); + maps_->Add(start, end, offset, flags, name, static_cast(-1)); + if (elf != nullptr) { + MapInfo* map_info = *--maps_->end(); + map_info->elf.reset(elf); + } + } + static void SetUpTestCase() { - maps_.FakeClear(); - MapInfo* info = - new MapInfo(&maps_, 0x1000, 0x8000, 0, PROT_READ | PROT_WRITE, "/system/fake/libc.so"); + maps_.reset(new Maps); + ElfFake* elf = new ElfFake(new MemoryFake); - info->elf.reset(elf); elf->FakeSetInterface(new ElfInterfaceFake(nullptr)); - maps_.FakeAddMapInfo(info); + AddMapInfo(0x1000, 0x8000, 0, PROT_READ | PROT_WRITE, "/system/fake/libc.so", elf); - info = new MapInfo(&maps_, 0x10000, 0x12000, 0, PROT_READ | PROT_WRITE, "[stack]"); - maps_.FakeAddMapInfo(info); + AddMapInfo(0x10000, 0x12000, 0, PROT_READ | PROT_WRITE, "[stack]"); - info = new MapInfo(&maps_, 0x13000, 0x15000, 0, PROT_READ | PROT_WRITE | MAPS_FLAGS_DEVICE_MAP, - "/dev/fake_device"); - maps_.FakeAddMapInfo(info); + AddMapInfo(0x13000, 0x15000, 0, PROT_READ | PROT_WRITE | MAPS_FLAGS_DEVICE_MAP, + "/dev/fake_device"); - info = new MapInfo(&maps_, 0x20000, 0x22000, 0, PROT_READ | PROT_WRITE, - "/system/fake/libunwind.so"); elf = new ElfFake(new MemoryFake); - info->elf.reset(elf); elf->FakeSetInterface(new ElfInterfaceFake(nullptr)); - maps_.FakeAddMapInfo(info); + AddMapInfo(0x20000, 0x22000, 0, PROT_READ | PROT_WRITE, "/system/fake/libunwind.so", elf); - info = new MapInfo(&maps_, 0x23000, 0x24000, 0, PROT_READ | PROT_WRITE, "/fake/libanother.so"); elf = new ElfFake(new MemoryFake); - info->elf.reset(elf); elf->FakeSetInterface(new ElfInterfaceFake(nullptr)); - maps_.FakeAddMapInfo(info); + AddMapInfo(0x23000, 0x24000, 0, PROT_READ | PROT_WRITE, "/fake/libanother.so", elf); - info = new MapInfo(&maps_, 0x33000, 0x34000, 0, PROT_READ | PROT_WRITE, "/fake/compressed.so"); elf = new ElfFake(new MemoryFake); - info->elf.reset(elf); elf->FakeSetInterface(new ElfInterfaceFake(nullptr)); - maps_.FakeAddMapInfo(info); + AddMapInfo(0x33000, 0x34000, 0, PROT_READ | PROT_WRITE, "/fake/compressed.so", elf); - info = new MapInfo(&maps_, 0x43000, 0x44000, 0x1d000, PROT_READ | PROT_WRITE, "/fake/fake.apk"); elf = new ElfFake(new MemoryFake); - info->elf.reset(elf); elf->FakeSetInterface(new ElfInterfaceFake(nullptr)); - maps_.FakeAddMapInfo(info); + AddMapInfo(0x43000, 0x44000, 0x1d000, PROT_READ | PROT_WRITE, "/fake/fake.apk", elf); - info = new MapInfo(&maps_, 0x53000, 0x54000, 0, PROT_READ | PROT_WRITE, "/fake/fake.oat"); - maps_.FakeAddMapInfo(info); + AddMapInfo(0x53000, 0x54000, 0, PROT_READ | PROT_WRITE, "/fake/fake.oat"); - info = new MapInfo(&maps_, 0xa3000, 0xa4000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, - "/fake/fake.vdex"); + AddMapInfo(0xa3000, 0xa4000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/fake.vdex"); + MapInfo* info = *--maps_->end(); info->load_bias = 0; - maps_.FakeAddMapInfo(info); - info = new MapInfo(&maps_, 0xa5000, 0xa6000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, - "/fake/fake_load_bias.so"); elf = new ElfFake(new MemoryFake); - info->elf.reset(elf); elf->FakeSetInterface(new ElfInterfaceFake(nullptr)); elf->FakeSetLoadBias(0x5000); - maps_.FakeAddMapInfo(info); + AddMapInfo(0xa5000, 0xa6000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/fake_load_bias.so", + elf); - info = new MapInfo(&maps_, 0xa7000, 0xa8000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, - "/fake/fake_offset.oat"); elf = new ElfFake(new MemoryFake); - info->elf.reset(elf); elf->FakeSetInterface(new ElfInterfaceFake(nullptr)); + AddMapInfo(0xa7000, 0xa8000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/fake_offset.oat", + elf); + info = *--maps_->end(); info->elf_offset = 0x8000; - maps_.FakeAddMapInfo(info); process_memory_.reset(new MemoryFake); } @@ -130,12 +110,12 @@ class UnwinderTest : public ::testing::Test { regs_.FakeSetReturnAddressValid(false); } - static MapsFake maps_; + static std::unique_ptr maps_; static RegsFake regs_; static std::shared_ptr process_memory_; }; -MapsFake UnwinderTest::maps_; +std::unique_ptr UnwinderTest::maps_; RegsFake UnwinderTest::regs_(5); std::shared_ptr UnwinderTest::process_memory_(nullptr); @@ -150,7 +130,7 @@ TEST_F(UnwinderTest, multiple_frames) { ElfInterfaceFake::FakePushStepData(StepData(0x1202, 0x10020, false)); ElfInterfaceFake::FakePushStepData(StepData(0, 0, true)); - Unwinder unwinder(64, &maps_, ®s_, process_memory_); + Unwinder unwinder(64, maps_.get(), ®s_, process_memory_); unwinder.Unwind(); EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode()); @@ -164,7 +144,8 @@ TEST_F(UnwinderTest, multiple_frames) { EXPECT_EQ("Frame0", frame->function_name); EXPECT_EQ(0U, frame->function_offset); EXPECT_EQ("/system/fake/libc.so", frame->map_name); - EXPECT_EQ(0U, frame->map_offset); + EXPECT_EQ(0U, frame->map_elf_start_offset); + EXPECT_EQ(0U, frame->map_exact_offset); EXPECT_EQ(0x1000U, frame->map_start); EXPECT_EQ(0x8000U, frame->map_end); EXPECT_EQ(0U, frame->map_load_bias); @@ -178,7 +159,8 @@ TEST_F(UnwinderTest, multiple_frames) { EXPECT_EQ("Frame1", frame->function_name); EXPECT_EQ(1U, frame->function_offset); EXPECT_EQ("/system/fake/libc.so", frame->map_name); - EXPECT_EQ(0U, frame->map_offset); + EXPECT_EQ(0U, frame->map_elf_start_offset); + EXPECT_EQ(0U, frame->map_exact_offset); EXPECT_EQ(0x1000U, frame->map_start); EXPECT_EQ(0x8000U, frame->map_end); EXPECT_EQ(0U, frame->map_load_bias); @@ -192,7 +174,8 @@ TEST_F(UnwinderTest, multiple_frames) { EXPECT_EQ("Frame2", frame->function_name); EXPECT_EQ(2U, frame->function_offset); EXPECT_EQ("/system/fake/libc.so", frame->map_name); - EXPECT_EQ(0U, frame->map_offset); + EXPECT_EQ(0U, frame->map_elf_start_offset); + EXPECT_EQ(0U, frame->map_exact_offset); EXPECT_EQ(0x1000U, frame->map_start); EXPECT_EQ(0x8000U, frame->map_end); EXPECT_EQ(0U, frame->map_load_bias); @@ -210,7 +193,7 @@ TEST_F(UnwinderTest, multiple_frames_dont_resolve_names) { ElfInterfaceFake::FakePushStepData(StepData(0x1202, 0x10020, false)); ElfInterfaceFake::FakePushStepData(StepData(0, 0, true)); - Unwinder unwinder(64, &maps_, ®s_, process_memory_); + Unwinder unwinder(64, maps_.get(), ®s_, process_memory_); unwinder.SetResolveNames(false); unwinder.Unwind(); EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode()); @@ -225,7 +208,8 @@ TEST_F(UnwinderTest, multiple_frames_dont_resolve_names) { EXPECT_EQ("", frame->function_name); EXPECT_EQ(0U, frame->function_offset); EXPECT_EQ("", frame->map_name); - EXPECT_EQ(0U, frame->map_offset); + EXPECT_EQ(0U, frame->map_elf_start_offset); + EXPECT_EQ(0U, frame->map_exact_offset); EXPECT_EQ(0x1000U, frame->map_start); EXPECT_EQ(0x8000U, frame->map_end); EXPECT_EQ(0U, frame->map_load_bias); @@ -239,7 +223,8 @@ TEST_F(UnwinderTest, multiple_frames_dont_resolve_names) { EXPECT_EQ("", frame->function_name); EXPECT_EQ(0U, frame->function_offset); EXPECT_EQ("", frame->map_name); - EXPECT_EQ(0U, frame->map_offset); + EXPECT_EQ(0U, frame->map_elf_start_offset); + EXPECT_EQ(0U, frame->map_exact_offset); EXPECT_EQ(0x1000U, frame->map_start); EXPECT_EQ(0x8000U, frame->map_end); EXPECT_EQ(0U, frame->map_load_bias); @@ -253,7 +238,8 @@ TEST_F(UnwinderTest, multiple_frames_dont_resolve_names) { EXPECT_EQ("", frame->function_name); EXPECT_EQ(0U, frame->function_offset); EXPECT_EQ("", frame->map_name); - EXPECT_EQ(0U, frame->map_offset); + EXPECT_EQ(0U, frame->map_elf_start_offset); + EXPECT_EQ(0U, frame->map_exact_offset); EXPECT_EQ(0x1000U, frame->map_start); EXPECT_EQ(0x8000U, frame->map_end); EXPECT_EQ(0U, frame->map_load_bias); @@ -267,7 +253,7 @@ TEST_F(UnwinderTest, non_zero_load_bias) { regs_.set_sp(0x10000); ElfInterfaceFake::FakePushStepData(StepData(0, 0, true)); - Unwinder unwinder(64, &maps_, ®s_, process_memory_); + Unwinder unwinder(64, maps_.get(), ®s_, process_memory_); unwinder.Unwind(); EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode()); @@ -281,7 +267,8 @@ TEST_F(UnwinderTest, non_zero_load_bias) { EXPECT_EQ("Frame0", frame->function_name); EXPECT_EQ(0U, frame->function_offset); EXPECT_EQ("/fake/fake_load_bias.so", frame->map_name); - EXPECT_EQ(0U, frame->map_offset); + EXPECT_EQ(0U, frame->map_elf_start_offset); + EXPECT_EQ(0U, frame->map_exact_offset); EXPECT_EQ(0xa5000U, frame->map_start); EXPECT_EQ(0xa6000U, frame->map_end); EXPECT_EQ(0x5000U, frame->map_load_bias); @@ -295,7 +282,7 @@ TEST_F(UnwinderTest, non_zero_elf_offset) { regs_.set_sp(0x10000); ElfInterfaceFake::FakePushStepData(StepData(0, 0, true)); - Unwinder unwinder(64, &maps_, ®s_, process_memory_); + Unwinder unwinder(64, maps_.get(), ®s_, process_memory_); unwinder.Unwind(); EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode()); @@ -309,7 +296,8 @@ TEST_F(UnwinderTest, non_zero_elf_offset) { EXPECT_EQ("Frame0", frame->function_name); EXPECT_EQ(0U, frame->function_offset); EXPECT_EQ("/fake/fake_offset.oat", frame->map_name); - EXPECT_EQ(0U, frame->map_offset); + EXPECT_EQ(0U, frame->map_elf_start_offset); + EXPECT_EQ(0U, frame->map_exact_offset); EXPECT_EQ(0xa7000U, frame->map_start); EXPECT_EQ(0xa8000U, frame->map_end); EXPECT_EQ(0U, frame->map_load_bias); @@ -323,7 +311,7 @@ TEST_F(UnwinderTest, non_zero_map_offset) { regs_.set_sp(0x10000); ElfInterfaceFake::FakePushStepData(StepData(0, 0, true)); - Unwinder unwinder(64, &maps_, ®s_, process_memory_); + Unwinder unwinder(64, maps_.get(), ®s_, process_memory_); unwinder.Unwind(); EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode()); @@ -337,7 +325,8 @@ TEST_F(UnwinderTest, non_zero_map_offset) { EXPECT_EQ("Frame0", frame->function_name); EXPECT_EQ(0U, frame->function_offset); EXPECT_EQ("/fake/fake.apk", frame->map_name); - EXPECT_EQ(0x1d000U, frame->map_offset); + EXPECT_EQ(0U, frame->map_elf_start_offset); + EXPECT_EQ(0x1d000U, frame->map_exact_offset); EXPECT_EQ(0x43000U, frame->map_start); EXPECT_EQ(0x44000U, frame->map_end); EXPECT_EQ(0U, frame->map_load_bias); @@ -358,7 +347,7 @@ TEST_F(UnwinderTest, no_frames_after_finished) { ElfInterfaceFake::FakePushStepData(StepData(0x1102, 0x10010, false)); ElfInterfaceFake::FakePushStepData(StepData(0x1202, 0x10020, false)); - Unwinder unwinder(64, &maps_, ®s_, process_memory_); + Unwinder unwinder(64, maps_.get(), ®s_, process_memory_); unwinder.Unwind(); EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode()); @@ -372,7 +361,8 @@ TEST_F(UnwinderTest, no_frames_after_finished) { EXPECT_EQ("Frame0", frame->function_name); EXPECT_EQ(0U, frame->function_offset); EXPECT_EQ("/system/fake/libc.so", frame->map_name); - EXPECT_EQ(0U, frame->map_offset); + EXPECT_EQ(0U, frame->map_elf_start_offset); + EXPECT_EQ(0U, frame->map_exact_offset); EXPECT_EQ(0x1000U, frame->map_start); EXPECT_EQ(0x8000U, frame->map_end); EXPECT_EQ(0U, frame->map_load_bias); @@ -389,7 +379,7 @@ TEST_F(UnwinderTest, max_frames) { regs_.set_pc(0x1000); regs_.set_sp(0x10000); - Unwinder unwinder(20, &maps_, ®s_, process_memory_); + Unwinder unwinder(20, maps_.get(), ®s_, process_memory_); unwinder.Unwind(); EXPECT_EQ(ERROR_MAX_FRAMES_EXCEEDED, unwinder.LastErrorCode()); @@ -404,7 +394,8 @@ TEST_F(UnwinderTest, max_frames) { EXPECT_EQ("Frame" + std::to_string(i), frame->function_name) << "Failed at frame " << i; EXPECT_EQ(i, frame->function_offset) << "Failed at frame " << i; EXPECT_EQ("/system/fake/libc.so", frame->map_name) << "Failed at frame " << i; - EXPECT_EQ(0U, frame->map_offset) << "Failed at frame " << i; + EXPECT_EQ(0U, frame->map_elf_start_offset) << "Failed at frame " << i; + EXPECT_EQ(0U, frame->map_exact_offset) << "Failed at frame " << i; EXPECT_EQ(0x1000U, frame->map_start) << "Failed at frame " << i; EXPECT_EQ(0x8000U, frame->map_end) << "Failed at frame " << i; EXPECT_EQ(0U, frame->map_load_bias) << "Failed at frame " << i; @@ -429,7 +420,7 @@ TEST_F(UnwinderTest, verify_frames_skipped) { ElfInterfaceFake::FakePushStepData(StepData(0x23002, 0x10070, false)); ElfInterfaceFake::FakePushStepData(StepData(0, 0, true)); - Unwinder unwinder(64, &maps_, ®s_, process_memory_); + Unwinder unwinder(64, maps_.get(), ®s_, process_memory_); std::vector skip_libs{"libunwind.so", "libanother.so"}; unwinder.Unwind(&skip_libs); EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode()); @@ -444,7 +435,8 @@ TEST_F(UnwinderTest, verify_frames_skipped) { EXPECT_EQ("Frame0", frame->function_name); EXPECT_EQ(0U, frame->function_offset); EXPECT_EQ("/system/fake/libc.so", frame->map_name); - EXPECT_EQ(0U, frame->map_offset); + EXPECT_EQ(0U, frame->map_elf_start_offset); + EXPECT_EQ(0U, frame->map_exact_offset); EXPECT_EQ(0x1000U, frame->map_start); EXPECT_EQ(0x8000U, frame->map_end); EXPECT_EQ(0U, frame->map_load_bias); @@ -458,7 +450,8 @@ TEST_F(UnwinderTest, verify_frames_skipped) { EXPECT_EQ("Frame1", frame->function_name); EXPECT_EQ(1U, frame->function_offset); EXPECT_EQ("/system/fake/libunwind.so", frame->map_name); - EXPECT_EQ(0U, frame->map_offset); + EXPECT_EQ(0U, frame->map_elf_start_offset); + EXPECT_EQ(0U, frame->map_exact_offset); EXPECT_EQ(0x20000U, frame->map_start); EXPECT_EQ(0x22000U, frame->map_end); EXPECT_EQ(0U, frame->map_load_bias); @@ -472,7 +465,7 @@ TEST_F(UnwinderTest, verify_frames_skipped) { EXPECT_EQ("Frame2", frame->function_name); EXPECT_EQ(2U, frame->function_offset); EXPECT_EQ("/fake/libanother.so", frame->map_name); - EXPECT_EQ(0U, frame->map_offset); + EXPECT_EQ(0U, frame->map_exact_offset); EXPECT_EQ(0x23000U, frame->map_start); EXPECT_EQ(0x24000U, frame->map_end); EXPECT_EQ(0U, frame->map_load_bias); @@ -489,7 +482,7 @@ TEST_F(UnwinderTest, sp_not_in_map) { ElfInterfaceFake::FakePushStepData(StepData(0x21002, 0x50020, false)); ElfInterfaceFake::FakePushStepData(StepData(0, 0, true)); - Unwinder unwinder(64, &maps_, ®s_, process_memory_); + Unwinder unwinder(64, maps_.get(), ®s_, process_memory_); unwinder.Unwind(); EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode()); @@ -503,7 +496,7 @@ TEST_F(UnwinderTest, sp_not_in_map) { EXPECT_EQ("Frame0", frame->function_name); EXPECT_EQ(0U, frame->function_offset); EXPECT_EQ("/system/fake/libc.so", frame->map_name); - EXPECT_EQ(0U, frame->map_offset); + EXPECT_EQ(0U, frame->map_exact_offset); EXPECT_EQ(0x1000U, frame->map_start); EXPECT_EQ(0x8000U, frame->map_end); EXPECT_EQ(0U, frame->map_load_bias); @@ -517,7 +510,7 @@ TEST_F(UnwinderTest, sp_not_in_map) { EXPECT_EQ("Frame1", frame->function_name); EXPECT_EQ(1U, frame->function_offset); EXPECT_EQ("/system/fake/libunwind.so", frame->map_name); - EXPECT_EQ(0U, frame->map_offset); + EXPECT_EQ(0U, frame->map_exact_offset); EXPECT_EQ(0x20000U, frame->map_start); EXPECT_EQ(0x22000U, frame->map_end); EXPECT_EQ(0U, frame->map_load_bias); @@ -536,7 +529,7 @@ TEST_F(UnwinderTest, pc_in_device_stops_unwind) { ElfInterfaceFake::FakePushStepData(StepData(0x23102, 0x10020, false)); ElfInterfaceFake::FakePushStepData(StepData(0, 0, true)); - Unwinder unwinder(64, &maps_, ®s_, process_memory_); + Unwinder unwinder(64, maps_.get(), ®s_, process_memory_); unwinder.Unwind(); EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode()); @@ -555,7 +548,7 @@ TEST_F(UnwinderTest, sp_in_device_stops_unwind) { ElfInterfaceFake::FakePushStepData(StepData(0x23102, 0x10020, false)); ElfInterfaceFake::FakePushStepData(StepData(0, 0, true)); - Unwinder unwinder(64, &maps_, ®s_, process_memory_); + Unwinder unwinder(64, maps_.get(), ®s_, process_memory_); unwinder.Unwind(); EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode()); @@ -569,7 +562,7 @@ TEST_F(UnwinderTest, pc_without_map) { regs_.set_pc(0x41000); regs_.set_sp(0x13000); - Unwinder unwinder(64, &maps_, ®s_, process_memory_); + Unwinder unwinder(64, maps_.get(), ®s_, process_memory_); unwinder.Unwind(); EXPECT_EQ(ERROR_INVALID_MAP, unwinder.LastErrorCode()); @@ -583,7 +576,8 @@ TEST_F(UnwinderTest, pc_without_map) { EXPECT_EQ("", frame->function_name); EXPECT_EQ(0U, frame->function_offset); EXPECT_EQ("", frame->map_name); - EXPECT_EQ(0U, frame->map_offset); + EXPECT_EQ(0U, frame->map_elf_start_offset); + EXPECT_EQ(0U, frame->map_exact_offset); EXPECT_EQ(0U, frame->map_start); EXPECT_EQ(0U, frame->map_end); EXPECT_EQ(0U, frame->map_load_bias); @@ -604,7 +598,7 @@ TEST_F(UnwinderTest, speculative_frame) { ElfInterfaceFake::FakePushStepData(StepData(0x23102, 0x10020, false)); ElfInterfaceFake::FakePushStepData(StepData(0, 0, true)); - Unwinder unwinder(64, &maps_, ®s_, process_memory_); + Unwinder unwinder(64, maps_.get(), ®s_, process_memory_); unwinder.Unwind(); EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode()); @@ -618,7 +612,8 @@ TEST_F(UnwinderTest, speculative_frame) { EXPECT_EQ("", frame->function_name); EXPECT_EQ(0U, frame->function_offset); EXPECT_EQ("", frame->map_name); - EXPECT_EQ(0U, frame->map_offset); + EXPECT_EQ(0U, frame->map_elf_start_offset); + EXPECT_EQ(0U, frame->map_exact_offset); EXPECT_EQ(0U, frame->map_start); EXPECT_EQ(0U, frame->map_end); EXPECT_EQ(0U, frame->map_load_bias); @@ -632,7 +627,8 @@ TEST_F(UnwinderTest, speculative_frame) { EXPECT_EQ("Frame0", frame->function_name); EXPECT_EQ(0U, frame->function_offset); EXPECT_EQ("/system/fake/libc.so", frame->map_name); - EXPECT_EQ(0U, frame->map_offset); + EXPECT_EQ(0U, frame->map_elf_start_offset); + EXPECT_EQ(0U, frame->map_exact_offset); EXPECT_EQ(0x1000U, frame->map_start); EXPECT_EQ(0x8000U, frame->map_end); EXPECT_EQ(0U, frame->map_load_bias); @@ -646,7 +642,8 @@ TEST_F(UnwinderTest, speculative_frame) { EXPECT_EQ("Frame1", frame->function_name); EXPECT_EQ(1U, frame->function_offset); EXPECT_EQ("/fake/libanother.so", frame->map_name); - EXPECT_EQ(0U, frame->map_offset); + EXPECT_EQ(0U, frame->map_elf_start_offset); + EXPECT_EQ(0U, frame->map_exact_offset); EXPECT_EQ(0x23000U, frame->map_start); EXPECT_EQ(0x24000U, frame->map_end); EXPECT_EQ(0U, frame->map_load_bias); @@ -666,7 +663,7 @@ TEST_F(UnwinderTest, speculative_frame_removed) { regs_.FakeSetReturnAddress(0x12); regs_.FakeSetReturnAddressValid(true); - Unwinder unwinder(64, &maps_, ®s_, process_memory_); + Unwinder unwinder(64, maps_.get(), ®s_, process_memory_); unwinder.Unwind(); EXPECT_EQ(ERROR_INVALID_MAP, unwinder.LastErrorCode()); @@ -680,7 +677,8 @@ TEST_F(UnwinderTest, speculative_frame_removed) { EXPECT_EQ("Frame0", frame->function_name); EXPECT_EQ(0U, frame->function_offset); EXPECT_EQ("/system/fake/libunwind.so", frame->map_name); - EXPECT_EQ(0U, frame->map_offset); + EXPECT_EQ(0U, frame->map_elf_start_offset); + EXPECT_EQ(0U, frame->map_exact_offset); EXPECT_EQ(0x20000U, frame->map_start); EXPECT_EQ(0x22000U, frame->map_end); EXPECT_EQ(0U, frame->map_load_bias); @@ -694,7 +692,8 @@ TEST_F(UnwinderTest, speculative_frame_removed) { EXPECT_EQ("", frame->function_name); EXPECT_EQ(0U, frame->function_offset); EXPECT_EQ("", frame->map_name); - EXPECT_EQ(0U, frame->map_offset); + EXPECT_EQ(0U, frame->map_elf_start_offset); + EXPECT_EQ(0U, frame->map_exact_offset); EXPECT_EQ(0U, frame->map_start); EXPECT_EQ(0U, frame->map_end); EXPECT_EQ(0U, frame->map_load_bias); @@ -713,7 +712,7 @@ TEST_F(UnwinderTest, speculative_frame_not_removed_pc_bad) { regs_.FakeSetReturnAddress(0x1202); regs_.FakeSetReturnAddressValid(true); - Unwinder unwinder(64, &maps_, ®s_, process_memory_); + Unwinder unwinder(64, maps_.get(), ®s_, process_memory_); unwinder.Unwind(); EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode()); @@ -727,7 +726,8 @@ TEST_F(UnwinderTest, speculative_frame_not_removed_pc_bad) { EXPECT_EQ("", frame->function_name); EXPECT_EQ(0U, frame->function_offset); EXPECT_EQ("", frame->map_name); - EXPECT_EQ(0U, frame->map_offset); + EXPECT_EQ(0U, frame->map_elf_start_offset); + EXPECT_EQ(0U, frame->map_exact_offset); EXPECT_EQ(0U, frame->map_start); EXPECT_EQ(0U, frame->map_end); EXPECT_EQ(0U, frame->map_load_bias); @@ -741,7 +741,8 @@ TEST_F(UnwinderTest, speculative_frame_not_removed_pc_bad) { EXPECT_EQ("Frame0", frame->function_name); EXPECT_EQ(0U, frame->function_offset); EXPECT_EQ("/system/fake/libc.so", frame->map_name); - EXPECT_EQ(0U, frame->map_offset); + EXPECT_EQ(0U, frame->map_elf_start_offset); + EXPECT_EQ(0U, frame->map_exact_offset); EXPECT_EQ(0x1000U, frame->map_start); EXPECT_EQ(0x8000U, frame->map_end); EXPECT_EQ(0U, frame->map_load_bias); @@ -762,14 +763,14 @@ TEST_F(UnwinderTest, map_ignore_suffixes) { ElfInterfaceFake::FakePushStepData(StepData(0x53502, 0x10020, false)); ElfInterfaceFake::FakePushStepData(StepData(0, 0, true)); - Unwinder unwinder(64, &maps_, ®s_, process_memory_); + Unwinder unwinder(64, maps_.get(), ®s_, process_memory_); std::vector suffixes{"oat"}; unwinder.Unwind(nullptr, &suffixes); EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode()); ASSERT_EQ(2U, unwinder.NumFrames()); // Make sure the elf was not initialized. - MapInfo* map_info = maps_.Find(0x53000); + MapInfo* map_info = maps_->Find(0x53000); ASSERT_TRUE(map_info != nullptr); EXPECT_TRUE(map_info->elf == nullptr); @@ -781,7 +782,8 @@ TEST_F(UnwinderTest, map_ignore_suffixes) { EXPECT_EQ("Frame0", frame->function_name); EXPECT_EQ(0U, frame->function_offset); EXPECT_EQ("/system/fake/libc.so", frame->map_name); - EXPECT_EQ(0U, frame->map_offset); + EXPECT_EQ(0U, frame->map_elf_start_offset); + EXPECT_EQ(0U, frame->map_exact_offset); EXPECT_EQ(0x1000U, frame->map_start); EXPECT_EQ(0x8000U, frame->map_end); EXPECT_EQ(0U, frame->map_load_bias); @@ -795,7 +797,8 @@ TEST_F(UnwinderTest, map_ignore_suffixes) { EXPECT_EQ("Frame1", frame->function_name); EXPECT_EQ(1U, frame->function_offset); EXPECT_EQ("/fake/fake.apk", frame->map_name); - EXPECT_EQ(0x1d000U, frame->map_offset); + EXPECT_EQ(0U, frame->map_elf_start_offset); + EXPECT_EQ(0x1d000U, frame->map_exact_offset); EXPECT_EQ(0x43000U, frame->map_start); EXPECT_EQ(0x44000U, frame->map_end); EXPECT_EQ(0U, frame->map_load_bias); @@ -819,7 +822,7 @@ TEST_F(UnwinderTest, sp_pc_do_not_change) { ElfInterfaceFake::FakePushStepData(StepData(0x33502, 0x10020, false)); ElfInterfaceFake::FakePushStepData(StepData(0, 0, true)); - Unwinder unwinder(64, &maps_, ®s_, process_memory_); + Unwinder unwinder(64, maps_.get(), ®s_, process_memory_); unwinder.Unwind(); EXPECT_EQ(ERROR_REPEATED_FRAME, unwinder.LastErrorCode()); @@ -833,7 +836,8 @@ TEST_F(UnwinderTest, sp_pc_do_not_change) { EXPECT_EQ("Frame0", frame->function_name); EXPECT_EQ(0U, frame->function_offset); EXPECT_EQ("/system/fake/libc.so", frame->map_name); - EXPECT_EQ(0U, frame->map_offset); + EXPECT_EQ(0U, frame->map_elf_start_offset); + EXPECT_EQ(0U, frame->map_exact_offset); EXPECT_EQ(0x1000U, frame->map_start); EXPECT_EQ(0x8000U, frame->map_end); EXPECT_EQ(0U, frame->map_load_bias); @@ -847,7 +851,8 @@ TEST_F(UnwinderTest, sp_pc_do_not_change) { EXPECT_EQ("Frame1", frame->function_name); EXPECT_EQ(1U, frame->function_offset); EXPECT_EQ("/fake/compressed.so", frame->map_name); - EXPECT_EQ(0U, frame->map_offset); + EXPECT_EQ(0U, frame->map_elf_start_offset); + EXPECT_EQ(0U, frame->map_exact_offset); EXPECT_EQ(0x33000U, frame->map_start); EXPECT_EQ(0x34000U, frame->map_end); EXPECT_EQ(0U, frame->map_load_bias); @@ -861,7 +866,8 @@ TEST_F(UnwinderTest, sp_pc_do_not_change) { EXPECT_EQ("Frame2", frame->function_name); EXPECT_EQ(2U, frame->function_offset); EXPECT_EQ("/fake/compressed.so", frame->map_name); - EXPECT_EQ(0U, frame->map_offset); + EXPECT_EQ(0U, frame->map_elf_start_offset); + EXPECT_EQ(0U, frame->map_exact_offset); EXPECT_EQ(0x33000U, frame->map_start); EXPECT_EQ(0x34000U, frame->map_end); EXPECT_EQ(0U, frame->map_load_bias); @@ -874,7 +880,7 @@ TEST_F(UnwinderTest, dex_pc_in_map) { regs_.set_sp(0x10000); regs_.FakeSetDexPc(0xa3400); - Unwinder unwinder(64, &maps_, ®s_, process_memory_); + Unwinder unwinder(64, maps_.get(), ®s_, process_memory_); unwinder.Unwind(); EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode()); @@ -888,7 +894,8 @@ TEST_F(UnwinderTest, dex_pc_in_map) { EXPECT_EQ("", frame->function_name); EXPECT_EQ(0U, frame->function_offset); EXPECT_EQ("/fake/fake.vdex", frame->map_name); - EXPECT_EQ(0U, frame->map_offset); + EXPECT_EQ(0U, frame->map_elf_start_offset); + EXPECT_EQ(0U, frame->map_exact_offset); EXPECT_EQ(0xa3000U, frame->map_start); EXPECT_EQ(0xa4000U, frame->map_end); EXPECT_EQ(0U, frame->map_load_bias); @@ -902,7 +909,8 @@ TEST_F(UnwinderTest, dex_pc_in_map) { EXPECT_EQ("Frame0", frame->function_name); EXPECT_EQ(0U, frame->function_offset); EXPECT_EQ("/system/fake/libc.so", frame->map_name); - EXPECT_EQ(0U, frame->map_offset); + EXPECT_EQ(0U, frame->map_elf_start_offset); + EXPECT_EQ(0U, frame->map_exact_offset); EXPECT_EQ(0x1000U, frame->map_start); EXPECT_EQ(0x8000U, frame->map_end); EXPECT_EQ(0U, frame->map_load_bias); @@ -915,7 +923,7 @@ TEST_F(UnwinderTest, dex_pc_not_in_map) { regs_.set_sp(0x10000); regs_.FakeSetDexPc(0x50000); - Unwinder unwinder(64, &maps_, ®s_, process_memory_); + Unwinder unwinder(64, maps_.get(), ®s_, process_memory_); unwinder.Unwind(); EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode()); @@ -929,7 +937,8 @@ TEST_F(UnwinderTest, dex_pc_not_in_map) { EXPECT_EQ("", frame->function_name); EXPECT_EQ(0U, frame->function_offset); EXPECT_EQ("", frame->map_name); - EXPECT_EQ(0U, frame->map_offset); + EXPECT_EQ(0U, frame->map_elf_start_offset); + EXPECT_EQ(0U, frame->map_exact_offset); EXPECT_EQ(0U, frame->map_start); EXPECT_EQ(0U, frame->map_end); EXPECT_EQ(0U, frame->map_load_bias); @@ -943,7 +952,8 @@ TEST_F(UnwinderTest, dex_pc_not_in_map) { EXPECT_EQ("Frame0", frame->function_name); EXPECT_EQ(0U, frame->function_offset); EXPECT_EQ("/system/fake/libc.so", frame->map_name); - EXPECT_EQ(0U, frame->map_offset); + EXPECT_EQ(0U, frame->map_elf_start_offset); + EXPECT_EQ(0U, frame->map_exact_offset); EXPECT_EQ(0x1000U, frame->map_start); EXPECT_EQ(0x8000U, frame->map_end); EXPECT_EQ(0U, frame->map_load_bias); @@ -959,7 +969,7 @@ TEST_F(UnwinderTest, dex_pc_multiple_frames) { ElfInterfaceFake::FakePushStepData(StepData(0x33402, 0x10010, false)); ElfInterfaceFake::FakePushStepData(StepData(0, 0, true)); - Unwinder unwinder(64, &maps_, ®s_, process_memory_); + Unwinder unwinder(64, maps_.get(), ®s_, process_memory_); unwinder.Unwind(); EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode()); @@ -973,7 +983,8 @@ TEST_F(UnwinderTest, dex_pc_multiple_frames) { EXPECT_EQ("", frame->function_name); EXPECT_EQ(0U, frame->function_offset); EXPECT_EQ("/fake/fake.vdex", frame->map_name); - EXPECT_EQ(0U, frame->map_offset); + EXPECT_EQ(0U, frame->map_elf_start_offset); + EXPECT_EQ(0U, frame->map_exact_offset); EXPECT_EQ(0xa3000U, frame->map_start); EXPECT_EQ(0xa4000U, frame->map_end); EXPECT_EQ(0U, frame->map_load_bias); @@ -987,7 +998,8 @@ TEST_F(UnwinderTest, dex_pc_multiple_frames) { EXPECT_EQ("Frame0", frame->function_name); EXPECT_EQ(0U, frame->function_offset); EXPECT_EQ("/system/fake/libc.so", frame->map_name); - EXPECT_EQ(0U, frame->map_offset); + EXPECT_EQ(0U, frame->map_elf_start_offset); + EXPECT_EQ(0U, frame->map_exact_offset); EXPECT_EQ(0x1000U, frame->map_start); EXPECT_EQ(0x8000U, frame->map_end); EXPECT_EQ(0U, frame->map_load_bias); @@ -1001,7 +1013,8 @@ TEST_F(UnwinderTest, dex_pc_multiple_frames) { EXPECT_EQ("Frame1", frame->function_name); EXPECT_EQ(1U, frame->function_offset); EXPECT_EQ("/fake/compressed.so", frame->map_name); - EXPECT_EQ(0U, frame->map_offset); + EXPECT_EQ(0U, frame->map_elf_start_offset); + EXPECT_EQ(0U, frame->map_exact_offset); EXPECT_EQ(0x33000U, frame->map_start); EXPECT_EQ(0x34000U, frame->map_end); EXPECT_EQ(0U, frame->map_load_bias); @@ -1014,7 +1027,7 @@ TEST_F(UnwinderTest, dex_pc_max_frames) { regs_.set_sp(0x10000); regs_.FakeSetDexPc(0xa3400); - Unwinder unwinder(1, &maps_, ®s_, process_memory_); + Unwinder unwinder(1, maps_.get(), ®s_, process_memory_); unwinder.Unwind(); EXPECT_EQ(ERROR_MAX_FRAMES_EXCEEDED, unwinder.LastErrorCode()); @@ -1028,7 +1041,8 @@ TEST_F(UnwinderTest, dex_pc_max_frames) { EXPECT_EQ("", frame->function_name); EXPECT_EQ(0U, frame->function_offset); EXPECT_EQ("/fake/fake.vdex", frame->map_name); - EXPECT_EQ(0U, frame->map_offset); + EXPECT_EQ(0U, frame->map_elf_start_offset); + EXPECT_EQ(0U, frame->map_exact_offset); EXPECT_EQ(0xa3000U, frame->map_start); EXPECT_EQ(0xa4000U, frame->map_end); EXPECT_EQ(0U, frame->map_load_bias); @@ -1045,17 +1059,17 @@ TEST_F(UnwinderTest, format_frame_static) { frame.function_name = "function"; frame.function_offset = 100; frame.map_name = "/fake/libfake.so"; - frame.map_offset = 0x2000; + frame.map_elf_start_offset = 0x2000; frame.map_start = 0x3000; frame.map_end = 0x6000; frame.map_flags = PROT_READ; - EXPECT_EQ(" #01 pc 0000000000001000 (offset 0x2000) /fake/libfake.so (function+100)", + EXPECT_EQ(" #01 pc 0000000000001000 /fake/libfake.so (offset 0x2000) (function+100)", Unwinder::FormatFrame(frame, false)); - EXPECT_EQ(" #01 pc 00001000 (offset 0x2000) /fake/libfake.so (function+100)", + EXPECT_EQ(" #01 pc 00001000 /fake/libfake.so (offset 0x2000) (function+100)", Unwinder::FormatFrame(frame, true)); - frame.map_offset = 0; + frame.map_elf_start_offset = 0; EXPECT_EQ(" #01 pc 0000000000001000 /fake/libfake.so (function+100)", Unwinder::FormatFrame(frame, false)); EXPECT_EQ(" #01 pc 00001000 /fake/libfake.so (function+100)", @@ -1130,7 +1144,7 @@ TEST_F(UnwinderTest, format_frame) { for (auto regs : reg_list) { ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 10)); - Unwinder unwinder(64, &maps_, regs, process_memory_); + Unwinder unwinder(64, maps_.get(), regs, process_memory_); unwinder.Unwind(); ASSERT_EQ(1U, unwinder.NumFrames()); diff --git a/libunwindstack/tests/files/offline/offset_arm/maps.txt b/libunwindstack/tests/files/offline/offset_arm/maps.txt index 62244645e..768dd9f8d 100644 --- a/libunwindstack/tests/files/offline/offset_arm/maps.txt +++ b/libunwindstack/tests/files/offline/offset_arm/maps.txt @@ -1,2 +1,4 @@ +2b2a000-2b6c000 r--p 0 00:00 0 libunwindstack_test 2b6c000-2e92000 r-xp 42000 00:00 0 libunwindstack_test +f4110000-f4135000 r--p 0 00:00 0 libc.so f4135000-f41a9000 r-xp 25000 00:00 0 libc.so diff --git a/libunwindstack/tools/unwind_for_offline.cpp b/libunwindstack/tools/unwind_for_offline.cpp index 652dbd1d3..5ae887458 100644 --- a/libunwindstack/tools/unwind_for_offline.cpp +++ b/libunwindstack/tools/unwind_for_offline.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -46,6 +47,7 @@ struct map_info_t { uint64_t start; uint64_t end; uint64_t offset; + uint64_t flags; std::string name; }; @@ -163,14 +165,19 @@ bool CreateElfFromMemory(std::shared_ptr& memory, map_info_ return true; } -bool CopyElfFromFile(map_info_t* info) { +bool CopyElfFromFile(map_info_t* info, bool* file_copied) { + std::string cur_name = basename(info->name.c_str()); + if (*file_copied) { + info->name = cur_name; + return true; + } + std::unique_ptr fp(fopen(info->name.c_str(), "r"), &fclose); if (fp == nullptr) { perror((std::string("Cannot open ") + info->name).c_str()); return false; } - std::string cur_name = basename(info->name.c_str()); std::unique_ptr output(fopen(cur_name.c_str(), "w+"), &fclose); if (output == nullptr) { perror((std::string("Cannot create file " + cur_name)).c_str()); @@ -193,6 +200,39 @@ bool CopyElfFromFile(map_info_t* info) { return true; } +map_info_t* FillInAndGetMapInfo(std::unordered_map& maps_by_start, + unwindstack::MapInfo* map_info) { + auto info = &maps_by_start[map_info->start]; + info->start = map_info->start; + info->end = map_info->end; + info->offset = map_info->offset; + info->name = map_info->name; + info->flags = map_info->flags; + + return info; +} + +void SaveMapInformation(std::shared_ptr& process_memory, map_info_t* info, + bool* file_copied) { + if (CopyElfFromFile(info, file_copied)) { + return; + } + *file_copied = false; + + // Try to create the elf from memory, this will handle cases where + // the data only exists in memory such as vdso data on x86. + if (CreateElfFromMemory(process_memory, info)) { + return; + } + + printf("Cannot save memory or file for map "); + if (!info->name.empty()) { + printf("%s\n", info->name.c_str()); + } else { + printf("anonymous:%" PRIx64 "\n", info->start); + } +} + int SaveData(pid_t pid) { unwindstack::Regs* regs = unwindstack::Regs::RemoteGet(pid); if (regs == nullptr) { @@ -237,22 +277,21 @@ int SaveData(pid_t pid) { } if (maps_by_start.count(frame.map_start) == 0) { - auto info = &maps_by_start[frame.map_start]; - info->start = frame.map_start; - info->end = frame.map_end; - info->offset = frame.map_offset; - info->name = frame.map_name; - if (!CopyElfFromFile(info)) { - // Try to create the elf from memory, this will handle cases where - // the data only exists in memory such as vdso data on x86. - if (!CreateElfFromMemory(process_memory, info)) { - printf("Ignoring map "); - if (!info->name.empty()) { - printf("%s\n", info->name.c_str()); - } else { - printf("anonymous:%" PRIx64 "\n", info->start); - } - } + map_info = maps.Find(frame.map_start); + + auto info = FillInAndGetMapInfo(maps_by_start, map_info); + bool file_copied = false; + SaveMapInformation(process_memory, info, &file_copied); + + // If you are using a a linker that creates two maps (one read-only, one + // read-executable), it's necessary to capture the previous map + // information if needed. + unwindstack::MapInfo* prev_map = map_info->prev_map; + if (prev_map != nullptr && map_info->offset != 0 && prev_map->offset == 0 && + prev_map->flags == PROT_READ && map_info->name == prev_map->name && + maps_by_start.count(prev_map->start) == 0) { + info = FillInAndGetMapInfo(maps_by_start, prev_map); + SaveMapInformation(process_memory, info, &file_copied); } } } @@ -277,8 +316,18 @@ int SaveData(pid_t pid) { } for (auto& element : sorted_maps) { + char perms[5] = {"---p"}; map_info_t& map = element.second; - fprintf(fp.get(), "%" PRIx64 "-%" PRIx64 " r-xp %" PRIx64 " 00:00 0", map.start, map.end, + if (map.flags & PROT_READ) { + perms[0] = 'r'; + } + if (map.flags & PROT_WRITE) { + perms[1] = 'w'; + } + if (map.flags & PROT_EXEC) { + perms[2] = 'x'; + } + fprintf(fp.get(), "%" PRIx64 "-%" PRIx64 " %s %" PRIx64 " 00:00 0", map.start, map.end, perms, map.offset); if (!map.name.empty()) { fprintf(fp.get(), " %s", map.name.c_str());