Merge "Fix offsets when shared lib split across maps."
am: 1baa19b1a6
Change-Id: I05884b4b1dbd604c4c2bdec961bf51c376ef6ba1
diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp
index fe28eba..f5f9b2a 100644
--- a/libbacktrace/UnwindStack.cpp
+++ b/libbacktrace/UnwindStack.cpp
@@ -117,7 +117,7 @@
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 44ec5c1..39a09cf 100644
--- a/libunwindstack/MapInfo.cpp
+++ b/libunwindstack/MapInfo.cpp
@@ -32,33 +32,27 @@
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 @@
// 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 @@
// 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 @@
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 a9fb859..c90e383 100644
--- a/libunwindstack/Maps.cpp
+++ b/libunwindstack/Maps.cpp
@@ -67,13 +67,15 @@
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::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 @@
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 792cd0b..8133639 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -59,7 +59,8 @@
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 @@
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 @@
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 @@
} 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) {
diff --git a/libunwindstack/include/unwindstack/MapInfo.h b/libunwindstack/include/unwindstack/MapInfo.h
index cfdefd0..5e3d6f6 100644
--- a/libunwindstack/include/unwindstack/MapInfo.h
+++ b/libunwindstack/include/unwindstack/MapInfo.h
@@ -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 @@
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;
diff --git a/libunwindstack/include/unwindstack/Unwinder.h b/libunwindstack/include/unwindstack/Unwinder.h
index 56b0581..d7bbd9d 100644
--- a/libunwindstack/include/unwindstack/Unwinder.h
+++ b/libunwindstack/include/unwindstack/Unwinder.h
@@ -48,7 +48,13 @@
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 7766218..f7689ce 100644
--- a/libunwindstack/tests/ElfTest.cpp
+++ b/libunwindstack/tests/ElfTest.cpp
@@ -269,7 +269,7 @@
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 943b3c9..a66685a 100644
--- a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
+++ b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
@@ -118,6 +118,7 @@
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 @@
}
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 80e292a..b4197f2 100644
--- a/libunwindstack/tests/MapsTest.cpp
+++ b/libunwindstack/tests/MapsTest.cpp
@@ -62,7 +62,7 @@
}
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_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 00264c2..472d1cf 100644
--- a/libunwindstack/tests/RegsTest.cpp
+++ b/libunwindstack/tests/RegsTest.cpp
@@ -182,7 +182,7 @@
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 dc015b4..aab9ec2 100644
--- a/libunwindstack/tests/UnwindOfflineTest.cpp
+++ b/libunwindstack/tests/UnwindOfflineTest.cpp
@@ -298,7 +298,7 @@
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 @@
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 @@
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 @@
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 @@
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 c4b8763..1fdeee5 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<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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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<std::string> skip_libs{"libunwind.so", "libanother.so"};
unwinder.Unwind(&skip_libs);
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
@@ -444,7 +435,8 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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<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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 6224464..768dd9f 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 652dbd1..5ae8874 100644
--- a/libunwindstack/tools/unwind_for_offline.cpp
+++ b/libunwindstack/tools/unwind_for_offline.cpp
@@ -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 @@
uint64_t start;
uint64_t end;
uint64_t offset;
+ uint64_t flags;
std::string name;
};
@@ -163,14 +165,19 @@
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 @@
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 @@
}
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 @@
}
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());