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());