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
This commit is contained in:
Christopher Ferris 2018-12-13 16:08:50 -08:00
parent 8fd4435d53
commit a09c4a6ff2
14 changed files with 361 additions and 245 deletions

View file

@ -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;
}

View file

@ -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<Memory>& 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;

View file

@ -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));
});
}

View file

@ -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 += " <unknown>";
@ -302,6 +300,11 @@ std::string Unwinder::FormatFrame(const FrameData& frame, bool is32bit) {
} else {
data += android::base::StringPrintf(" <anonymous:%" PRIx64 ">", 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) {

View file

@ -25,38 +25,31 @@
#include <string>
#include <unwindstack/Elf.h>
#include <unwindstack/Memory.h>
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<uint64_t>(-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<uint64_t>(-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> 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;

View file

@ -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;

View file

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

View file

@ -118,6 +118,7 @@ TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_full_file) {
std::unique_ptr<Memory> 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<uint8_t> 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> 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<uint8_t> buffer(0x100);
@ -162,6 +202,7 @@ TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file_whole_e
std::unique_ptr<Memory> 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> 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<uint8_t> 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<uint8_t> buffer(0x4000);
@ -333,6 +377,7 @@ TEST_F(MapInfoCreateMemoryTest, rosegment_from_file) {
std::vector<uint8_t> 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);

View file

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

View file

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

View file

@ -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 <unknown>\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);

View file

@ -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<uint64_t>(-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> maps_;
static RegsFake regs_;
static std::shared_ptr<Memory> process_memory_;
};
MapsFake UnwinderTest::maps_;
std::unique_ptr<Maps> UnwinderTest::maps_;
RegsFake UnwinderTest::regs_(5);
std::shared_ptr<Memory> 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_, &regs_, process_memory_);
Unwinder unwinder(64, maps_.get(), &regs_, 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_, &regs_, process_memory_);
Unwinder unwinder(64, maps_.get(), &regs_, 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_, &regs_, process_memory_);
Unwinder unwinder(64, maps_.get(), &regs_, 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_, &regs_, process_memory_);
Unwinder unwinder(64, maps_.get(), &regs_, 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_, &regs_, process_memory_);
Unwinder unwinder(64, maps_.get(), &regs_, 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_, &regs_, process_memory_);
Unwinder unwinder(64, maps_.get(), &regs_, 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_, &regs_, process_memory_);
Unwinder unwinder(20, maps_.get(), &regs_, 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_, &regs_, process_memory_);
Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
std::vector<std::string> 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_, &regs_, process_memory_);
Unwinder unwinder(64, maps_.get(), &regs_, 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_, &regs_, process_memory_);
Unwinder unwinder(64, maps_.get(), &regs_, 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_, &regs_, process_memory_);
Unwinder unwinder(64, maps_.get(), &regs_, 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_, &regs_, process_memory_);
Unwinder unwinder(64, maps_.get(), &regs_, 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_, &regs_, process_memory_);
Unwinder unwinder(64, maps_.get(), &regs_, 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_, &regs_, process_memory_);
Unwinder unwinder(64, maps_.get(), &regs_, 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_, &regs_, process_memory_);
Unwinder unwinder(64, maps_.get(), &regs_, 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_, &regs_, process_memory_);
Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
std::vector<std::string> 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_, &regs_, process_memory_);
Unwinder unwinder(64, maps_.get(), &regs_, 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_, &regs_, process_memory_);
Unwinder unwinder(64, maps_.get(), &regs_, 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_, &regs_, process_memory_);
Unwinder unwinder(64, maps_.get(), &regs_, 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_, &regs_, process_memory_);
Unwinder unwinder(64, maps_.get(), &regs_, 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_, &regs_, process_memory_);
Unwinder unwinder(1, maps_.get(), &regs_, 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());

View file

@ -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

View file

@ -22,6 +22,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <unistd.h>
@ -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<unwindstack::Memory>& 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<FILE, decltype(&fclose)> 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<FILE, decltype(&fclose)> 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<uint64_t, map_info_t>& 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<unwindstack::Memory>& 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());