Merge "Fix offsets when shared lib split across maps."
This commit is contained in:
commit
1baa19b1a6
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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_, ®s_, process_memory_);
|
||||
Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
|
||||
unwinder.Unwind();
|
||||
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
|
||||
|
||||
|
@ -164,7 +144,8 @@ TEST_F(UnwinderTest, multiple_frames) {
|
|||
EXPECT_EQ("Frame0", frame->function_name);
|
||||
EXPECT_EQ(0U, frame->function_offset);
|
||||
EXPECT_EQ("/system/fake/libc.so", frame->map_name);
|
||||
EXPECT_EQ(0U, frame->map_offset);
|
||||
EXPECT_EQ(0U, frame->map_elf_start_offset);
|
||||
EXPECT_EQ(0U, frame->map_exact_offset);
|
||||
EXPECT_EQ(0x1000U, frame->map_start);
|
||||
EXPECT_EQ(0x8000U, frame->map_end);
|
||||
EXPECT_EQ(0U, frame->map_load_bias);
|
||||
|
@ -178,7 +159,8 @@ TEST_F(UnwinderTest, multiple_frames) {
|
|||
EXPECT_EQ("Frame1", frame->function_name);
|
||||
EXPECT_EQ(1U, frame->function_offset);
|
||||
EXPECT_EQ("/system/fake/libc.so", frame->map_name);
|
||||
EXPECT_EQ(0U, frame->map_offset);
|
||||
EXPECT_EQ(0U, frame->map_elf_start_offset);
|
||||
EXPECT_EQ(0U, frame->map_exact_offset);
|
||||
EXPECT_EQ(0x1000U, frame->map_start);
|
||||
EXPECT_EQ(0x8000U, frame->map_end);
|
||||
EXPECT_EQ(0U, frame->map_load_bias);
|
||||
|
@ -192,7 +174,8 @@ TEST_F(UnwinderTest, multiple_frames) {
|
|||
EXPECT_EQ("Frame2", frame->function_name);
|
||||
EXPECT_EQ(2U, frame->function_offset);
|
||||
EXPECT_EQ("/system/fake/libc.so", frame->map_name);
|
||||
EXPECT_EQ(0U, frame->map_offset);
|
||||
EXPECT_EQ(0U, frame->map_elf_start_offset);
|
||||
EXPECT_EQ(0U, frame->map_exact_offset);
|
||||
EXPECT_EQ(0x1000U, frame->map_start);
|
||||
EXPECT_EQ(0x8000U, frame->map_end);
|
||||
EXPECT_EQ(0U, frame->map_load_bias);
|
||||
|
@ -210,7 +193,7 @@ TEST_F(UnwinderTest, multiple_frames_dont_resolve_names) {
|
|||
ElfInterfaceFake::FakePushStepData(StepData(0x1202, 0x10020, false));
|
||||
ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
|
||||
|
||||
Unwinder unwinder(64, &maps_, ®s_, process_memory_);
|
||||
Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
|
||||
unwinder.SetResolveNames(false);
|
||||
unwinder.Unwind();
|
||||
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
|
||||
|
@ -225,7 +208,8 @@ TEST_F(UnwinderTest, multiple_frames_dont_resolve_names) {
|
|||
EXPECT_EQ("", frame->function_name);
|
||||
EXPECT_EQ(0U, frame->function_offset);
|
||||
EXPECT_EQ("", frame->map_name);
|
||||
EXPECT_EQ(0U, frame->map_offset);
|
||||
EXPECT_EQ(0U, frame->map_elf_start_offset);
|
||||
EXPECT_EQ(0U, frame->map_exact_offset);
|
||||
EXPECT_EQ(0x1000U, frame->map_start);
|
||||
EXPECT_EQ(0x8000U, frame->map_end);
|
||||
EXPECT_EQ(0U, frame->map_load_bias);
|
||||
|
@ -239,7 +223,8 @@ TEST_F(UnwinderTest, multiple_frames_dont_resolve_names) {
|
|||
EXPECT_EQ("", frame->function_name);
|
||||
EXPECT_EQ(0U, frame->function_offset);
|
||||
EXPECT_EQ("", frame->map_name);
|
||||
EXPECT_EQ(0U, frame->map_offset);
|
||||
EXPECT_EQ(0U, frame->map_elf_start_offset);
|
||||
EXPECT_EQ(0U, frame->map_exact_offset);
|
||||
EXPECT_EQ(0x1000U, frame->map_start);
|
||||
EXPECT_EQ(0x8000U, frame->map_end);
|
||||
EXPECT_EQ(0U, frame->map_load_bias);
|
||||
|
@ -253,7 +238,8 @@ TEST_F(UnwinderTest, multiple_frames_dont_resolve_names) {
|
|||
EXPECT_EQ("", frame->function_name);
|
||||
EXPECT_EQ(0U, frame->function_offset);
|
||||
EXPECT_EQ("", frame->map_name);
|
||||
EXPECT_EQ(0U, frame->map_offset);
|
||||
EXPECT_EQ(0U, frame->map_elf_start_offset);
|
||||
EXPECT_EQ(0U, frame->map_exact_offset);
|
||||
EXPECT_EQ(0x1000U, frame->map_start);
|
||||
EXPECT_EQ(0x8000U, frame->map_end);
|
||||
EXPECT_EQ(0U, frame->map_load_bias);
|
||||
|
@ -267,7 +253,7 @@ TEST_F(UnwinderTest, non_zero_load_bias) {
|
|||
regs_.set_sp(0x10000);
|
||||
ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
|
||||
|
||||
Unwinder unwinder(64, &maps_, ®s_, process_memory_);
|
||||
Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
|
||||
unwinder.Unwind();
|
||||
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
|
||||
|
||||
|
@ -281,7 +267,8 @@ TEST_F(UnwinderTest, non_zero_load_bias) {
|
|||
EXPECT_EQ("Frame0", frame->function_name);
|
||||
EXPECT_EQ(0U, frame->function_offset);
|
||||
EXPECT_EQ("/fake/fake_load_bias.so", frame->map_name);
|
||||
EXPECT_EQ(0U, frame->map_offset);
|
||||
EXPECT_EQ(0U, frame->map_elf_start_offset);
|
||||
EXPECT_EQ(0U, frame->map_exact_offset);
|
||||
EXPECT_EQ(0xa5000U, frame->map_start);
|
||||
EXPECT_EQ(0xa6000U, frame->map_end);
|
||||
EXPECT_EQ(0x5000U, frame->map_load_bias);
|
||||
|
@ -295,7 +282,7 @@ TEST_F(UnwinderTest, non_zero_elf_offset) {
|
|||
regs_.set_sp(0x10000);
|
||||
ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
|
||||
|
||||
Unwinder unwinder(64, &maps_, ®s_, process_memory_);
|
||||
Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
|
||||
unwinder.Unwind();
|
||||
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
|
||||
|
||||
|
@ -309,7 +296,8 @@ TEST_F(UnwinderTest, non_zero_elf_offset) {
|
|||
EXPECT_EQ("Frame0", frame->function_name);
|
||||
EXPECT_EQ(0U, frame->function_offset);
|
||||
EXPECT_EQ("/fake/fake_offset.oat", frame->map_name);
|
||||
EXPECT_EQ(0U, frame->map_offset);
|
||||
EXPECT_EQ(0U, frame->map_elf_start_offset);
|
||||
EXPECT_EQ(0U, frame->map_exact_offset);
|
||||
EXPECT_EQ(0xa7000U, frame->map_start);
|
||||
EXPECT_EQ(0xa8000U, frame->map_end);
|
||||
EXPECT_EQ(0U, frame->map_load_bias);
|
||||
|
@ -323,7 +311,7 @@ TEST_F(UnwinderTest, non_zero_map_offset) {
|
|||
regs_.set_sp(0x10000);
|
||||
ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
|
||||
|
||||
Unwinder unwinder(64, &maps_, ®s_, process_memory_);
|
||||
Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
|
||||
unwinder.Unwind();
|
||||
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
|
||||
|
||||
|
@ -337,7 +325,8 @@ TEST_F(UnwinderTest, non_zero_map_offset) {
|
|||
EXPECT_EQ("Frame0", frame->function_name);
|
||||
EXPECT_EQ(0U, frame->function_offset);
|
||||
EXPECT_EQ("/fake/fake.apk", frame->map_name);
|
||||
EXPECT_EQ(0x1d000U, frame->map_offset);
|
||||
EXPECT_EQ(0U, frame->map_elf_start_offset);
|
||||
EXPECT_EQ(0x1d000U, frame->map_exact_offset);
|
||||
EXPECT_EQ(0x43000U, frame->map_start);
|
||||
EXPECT_EQ(0x44000U, frame->map_end);
|
||||
EXPECT_EQ(0U, frame->map_load_bias);
|
||||
|
@ -358,7 +347,7 @@ TEST_F(UnwinderTest, no_frames_after_finished) {
|
|||
ElfInterfaceFake::FakePushStepData(StepData(0x1102, 0x10010, false));
|
||||
ElfInterfaceFake::FakePushStepData(StepData(0x1202, 0x10020, false));
|
||||
|
||||
Unwinder unwinder(64, &maps_, ®s_, process_memory_);
|
||||
Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
|
||||
unwinder.Unwind();
|
||||
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
|
||||
|
||||
|
@ -372,7 +361,8 @@ TEST_F(UnwinderTest, no_frames_after_finished) {
|
|||
EXPECT_EQ("Frame0", frame->function_name);
|
||||
EXPECT_EQ(0U, frame->function_offset);
|
||||
EXPECT_EQ("/system/fake/libc.so", frame->map_name);
|
||||
EXPECT_EQ(0U, frame->map_offset);
|
||||
EXPECT_EQ(0U, frame->map_elf_start_offset);
|
||||
EXPECT_EQ(0U, frame->map_exact_offset);
|
||||
EXPECT_EQ(0x1000U, frame->map_start);
|
||||
EXPECT_EQ(0x8000U, frame->map_end);
|
||||
EXPECT_EQ(0U, frame->map_load_bias);
|
||||
|
@ -389,7 +379,7 @@ TEST_F(UnwinderTest, max_frames) {
|
|||
regs_.set_pc(0x1000);
|
||||
regs_.set_sp(0x10000);
|
||||
|
||||
Unwinder unwinder(20, &maps_, ®s_, process_memory_);
|
||||
Unwinder unwinder(20, maps_.get(), ®s_, process_memory_);
|
||||
unwinder.Unwind();
|
||||
EXPECT_EQ(ERROR_MAX_FRAMES_EXCEEDED, unwinder.LastErrorCode());
|
||||
|
||||
|
@ -404,7 +394,8 @@ TEST_F(UnwinderTest, max_frames) {
|
|||
EXPECT_EQ("Frame" + std::to_string(i), frame->function_name) << "Failed at frame " << i;
|
||||
EXPECT_EQ(i, frame->function_offset) << "Failed at frame " << i;
|
||||
EXPECT_EQ("/system/fake/libc.so", frame->map_name) << "Failed at frame " << i;
|
||||
EXPECT_EQ(0U, frame->map_offset) << "Failed at frame " << i;
|
||||
EXPECT_EQ(0U, frame->map_elf_start_offset) << "Failed at frame " << i;
|
||||
EXPECT_EQ(0U, frame->map_exact_offset) << "Failed at frame " << i;
|
||||
EXPECT_EQ(0x1000U, frame->map_start) << "Failed at frame " << i;
|
||||
EXPECT_EQ(0x8000U, frame->map_end) << "Failed at frame " << i;
|
||||
EXPECT_EQ(0U, frame->map_load_bias) << "Failed at frame " << i;
|
||||
|
@ -429,7 +420,7 @@ TEST_F(UnwinderTest, verify_frames_skipped) {
|
|||
ElfInterfaceFake::FakePushStepData(StepData(0x23002, 0x10070, false));
|
||||
ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
|
||||
|
||||
Unwinder unwinder(64, &maps_, ®s_, process_memory_);
|
||||
Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
|
||||
std::vector<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_, ®s_, process_memory_);
|
||||
Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
|
||||
unwinder.Unwind();
|
||||
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
|
||||
|
||||
|
@ -503,7 +496,7 @@ TEST_F(UnwinderTest, sp_not_in_map) {
|
|||
EXPECT_EQ("Frame0", frame->function_name);
|
||||
EXPECT_EQ(0U, frame->function_offset);
|
||||
EXPECT_EQ("/system/fake/libc.so", frame->map_name);
|
||||
EXPECT_EQ(0U, frame->map_offset);
|
||||
EXPECT_EQ(0U, frame->map_exact_offset);
|
||||
EXPECT_EQ(0x1000U, frame->map_start);
|
||||
EXPECT_EQ(0x8000U, frame->map_end);
|
||||
EXPECT_EQ(0U, frame->map_load_bias);
|
||||
|
@ -517,7 +510,7 @@ TEST_F(UnwinderTest, sp_not_in_map) {
|
|||
EXPECT_EQ("Frame1", frame->function_name);
|
||||
EXPECT_EQ(1U, frame->function_offset);
|
||||
EXPECT_EQ("/system/fake/libunwind.so", frame->map_name);
|
||||
EXPECT_EQ(0U, frame->map_offset);
|
||||
EXPECT_EQ(0U, frame->map_exact_offset);
|
||||
EXPECT_EQ(0x20000U, frame->map_start);
|
||||
EXPECT_EQ(0x22000U, frame->map_end);
|
||||
EXPECT_EQ(0U, frame->map_load_bias);
|
||||
|
@ -536,7 +529,7 @@ TEST_F(UnwinderTest, pc_in_device_stops_unwind) {
|
|||
ElfInterfaceFake::FakePushStepData(StepData(0x23102, 0x10020, false));
|
||||
ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
|
||||
|
||||
Unwinder unwinder(64, &maps_, ®s_, process_memory_);
|
||||
Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
|
||||
unwinder.Unwind();
|
||||
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
|
||||
|
||||
|
@ -555,7 +548,7 @@ TEST_F(UnwinderTest, sp_in_device_stops_unwind) {
|
|||
ElfInterfaceFake::FakePushStepData(StepData(0x23102, 0x10020, false));
|
||||
ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
|
||||
|
||||
Unwinder unwinder(64, &maps_, ®s_, process_memory_);
|
||||
Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
|
||||
unwinder.Unwind();
|
||||
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
|
||||
|
||||
|
@ -569,7 +562,7 @@ TEST_F(UnwinderTest, pc_without_map) {
|
|||
regs_.set_pc(0x41000);
|
||||
regs_.set_sp(0x13000);
|
||||
|
||||
Unwinder unwinder(64, &maps_, ®s_, process_memory_);
|
||||
Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
|
||||
unwinder.Unwind();
|
||||
EXPECT_EQ(ERROR_INVALID_MAP, unwinder.LastErrorCode());
|
||||
|
||||
|
@ -583,7 +576,8 @@ TEST_F(UnwinderTest, pc_without_map) {
|
|||
EXPECT_EQ("", frame->function_name);
|
||||
EXPECT_EQ(0U, frame->function_offset);
|
||||
EXPECT_EQ("", frame->map_name);
|
||||
EXPECT_EQ(0U, frame->map_offset);
|
||||
EXPECT_EQ(0U, frame->map_elf_start_offset);
|
||||
EXPECT_EQ(0U, frame->map_exact_offset);
|
||||
EXPECT_EQ(0U, frame->map_start);
|
||||
EXPECT_EQ(0U, frame->map_end);
|
||||
EXPECT_EQ(0U, frame->map_load_bias);
|
||||
|
@ -604,7 +598,7 @@ TEST_F(UnwinderTest, speculative_frame) {
|
|||
ElfInterfaceFake::FakePushStepData(StepData(0x23102, 0x10020, false));
|
||||
ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
|
||||
|
||||
Unwinder unwinder(64, &maps_, ®s_, process_memory_);
|
||||
Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
|
||||
unwinder.Unwind();
|
||||
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
|
||||
|
||||
|
@ -618,7 +612,8 @@ TEST_F(UnwinderTest, speculative_frame) {
|
|||
EXPECT_EQ("", frame->function_name);
|
||||
EXPECT_EQ(0U, frame->function_offset);
|
||||
EXPECT_EQ("", frame->map_name);
|
||||
EXPECT_EQ(0U, frame->map_offset);
|
||||
EXPECT_EQ(0U, frame->map_elf_start_offset);
|
||||
EXPECT_EQ(0U, frame->map_exact_offset);
|
||||
EXPECT_EQ(0U, frame->map_start);
|
||||
EXPECT_EQ(0U, frame->map_end);
|
||||
EXPECT_EQ(0U, frame->map_load_bias);
|
||||
|
@ -632,7 +627,8 @@ TEST_F(UnwinderTest, speculative_frame) {
|
|||
EXPECT_EQ("Frame0", frame->function_name);
|
||||
EXPECT_EQ(0U, frame->function_offset);
|
||||
EXPECT_EQ("/system/fake/libc.so", frame->map_name);
|
||||
EXPECT_EQ(0U, frame->map_offset);
|
||||
EXPECT_EQ(0U, frame->map_elf_start_offset);
|
||||
EXPECT_EQ(0U, frame->map_exact_offset);
|
||||
EXPECT_EQ(0x1000U, frame->map_start);
|
||||
EXPECT_EQ(0x8000U, frame->map_end);
|
||||
EXPECT_EQ(0U, frame->map_load_bias);
|
||||
|
@ -646,7 +642,8 @@ TEST_F(UnwinderTest, speculative_frame) {
|
|||
EXPECT_EQ("Frame1", frame->function_name);
|
||||
EXPECT_EQ(1U, frame->function_offset);
|
||||
EXPECT_EQ("/fake/libanother.so", frame->map_name);
|
||||
EXPECT_EQ(0U, frame->map_offset);
|
||||
EXPECT_EQ(0U, frame->map_elf_start_offset);
|
||||
EXPECT_EQ(0U, frame->map_exact_offset);
|
||||
EXPECT_EQ(0x23000U, frame->map_start);
|
||||
EXPECT_EQ(0x24000U, frame->map_end);
|
||||
EXPECT_EQ(0U, frame->map_load_bias);
|
||||
|
@ -666,7 +663,7 @@ TEST_F(UnwinderTest, speculative_frame_removed) {
|
|||
regs_.FakeSetReturnAddress(0x12);
|
||||
regs_.FakeSetReturnAddressValid(true);
|
||||
|
||||
Unwinder unwinder(64, &maps_, ®s_, process_memory_);
|
||||
Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
|
||||
unwinder.Unwind();
|
||||
EXPECT_EQ(ERROR_INVALID_MAP, unwinder.LastErrorCode());
|
||||
|
||||
|
@ -680,7 +677,8 @@ TEST_F(UnwinderTest, speculative_frame_removed) {
|
|||
EXPECT_EQ("Frame0", frame->function_name);
|
||||
EXPECT_EQ(0U, frame->function_offset);
|
||||
EXPECT_EQ("/system/fake/libunwind.so", frame->map_name);
|
||||
EXPECT_EQ(0U, frame->map_offset);
|
||||
EXPECT_EQ(0U, frame->map_elf_start_offset);
|
||||
EXPECT_EQ(0U, frame->map_exact_offset);
|
||||
EXPECT_EQ(0x20000U, frame->map_start);
|
||||
EXPECT_EQ(0x22000U, frame->map_end);
|
||||
EXPECT_EQ(0U, frame->map_load_bias);
|
||||
|
@ -694,7 +692,8 @@ TEST_F(UnwinderTest, speculative_frame_removed) {
|
|||
EXPECT_EQ("", frame->function_name);
|
||||
EXPECT_EQ(0U, frame->function_offset);
|
||||
EXPECT_EQ("", frame->map_name);
|
||||
EXPECT_EQ(0U, frame->map_offset);
|
||||
EXPECT_EQ(0U, frame->map_elf_start_offset);
|
||||
EXPECT_EQ(0U, frame->map_exact_offset);
|
||||
EXPECT_EQ(0U, frame->map_start);
|
||||
EXPECT_EQ(0U, frame->map_end);
|
||||
EXPECT_EQ(0U, frame->map_load_bias);
|
||||
|
@ -713,7 +712,7 @@ TEST_F(UnwinderTest, speculative_frame_not_removed_pc_bad) {
|
|||
regs_.FakeSetReturnAddress(0x1202);
|
||||
regs_.FakeSetReturnAddressValid(true);
|
||||
|
||||
Unwinder unwinder(64, &maps_, ®s_, process_memory_);
|
||||
Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
|
||||
unwinder.Unwind();
|
||||
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
|
||||
|
||||
|
@ -727,7 +726,8 @@ TEST_F(UnwinderTest, speculative_frame_not_removed_pc_bad) {
|
|||
EXPECT_EQ("", frame->function_name);
|
||||
EXPECT_EQ(0U, frame->function_offset);
|
||||
EXPECT_EQ("", frame->map_name);
|
||||
EXPECT_EQ(0U, frame->map_offset);
|
||||
EXPECT_EQ(0U, frame->map_elf_start_offset);
|
||||
EXPECT_EQ(0U, frame->map_exact_offset);
|
||||
EXPECT_EQ(0U, frame->map_start);
|
||||
EXPECT_EQ(0U, frame->map_end);
|
||||
EXPECT_EQ(0U, frame->map_load_bias);
|
||||
|
@ -741,7 +741,8 @@ TEST_F(UnwinderTest, speculative_frame_not_removed_pc_bad) {
|
|||
EXPECT_EQ("Frame0", frame->function_name);
|
||||
EXPECT_EQ(0U, frame->function_offset);
|
||||
EXPECT_EQ("/system/fake/libc.so", frame->map_name);
|
||||
EXPECT_EQ(0U, frame->map_offset);
|
||||
EXPECT_EQ(0U, frame->map_elf_start_offset);
|
||||
EXPECT_EQ(0U, frame->map_exact_offset);
|
||||
EXPECT_EQ(0x1000U, frame->map_start);
|
||||
EXPECT_EQ(0x8000U, frame->map_end);
|
||||
EXPECT_EQ(0U, frame->map_load_bias);
|
||||
|
@ -762,14 +763,14 @@ TEST_F(UnwinderTest, map_ignore_suffixes) {
|
|||
ElfInterfaceFake::FakePushStepData(StepData(0x53502, 0x10020, false));
|
||||
ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
|
||||
|
||||
Unwinder unwinder(64, &maps_, ®s_, process_memory_);
|
||||
Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
|
||||
std::vector<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_, ®s_, process_memory_);
|
||||
Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
|
||||
unwinder.Unwind();
|
||||
EXPECT_EQ(ERROR_REPEATED_FRAME, unwinder.LastErrorCode());
|
||||
|
||||
|
@ -833,7 +836,8 @@ TEST_F(UnwinderTest, sp_pc_do_not_change) {
|
|||
EXPECT_EQ("Frame0", frame->function_name);
|
||||
EXPECT_EQ(0U, frame->function_offset);
|
||||
EXPECT_EQ("/system/fake/libc.so", frame->map_name);
|
||||
EXPECT_EQ(0U, frame->map_offset);
|
||||
EXPECT_EQ(0U, frame->map_elf_start_offset);
|
||||
EXPECT_EQ(0U, frame->map_exact_offset);
|
||||
EXPECT_EQ(0x1000U, frame->map_start);
|
||||
EXPECT_EQ(0x8000U, frame->map_end);
|
||||
EXPECT_EQ(0U, frame->map_load_bias);
|
||||
|
@ -847,7 +851,8 @@ TEST_F(UnwinderTest, sp_pc_do_not_change) {
|
|||
EXPECT_EQ("Frame1", frame->function_name);
|
||||
EXPECT_EQ(1U, frame->function_offset);
|
||||
EXPECT_EQ("/fake/compressed.so", frame->map_name);
|
||||
EXPECT_EQ(0U, frame->map_offset);
|
||||
EXPECT_EQ(0U, frame->map_elf_start_offset);
|
||||
EXPECT_EQ(0U, frame->map_exact_offset);
|
||||
EXPECT_EQ(0x33000U, frame->map_start);
|
||||
EXPECT_EQ(0x34000U, frame->map_end);
|
||||
EXPECT_EQ(0U, frame->map_load_bias);
|
||||
|
@ -861,7 +866,8 @@ TEST_F(UnwinderTest, sp_pc_do_not_change) {
|
|||
EXPECT_EQ("Frame2", frame->function_name);
|
||||
EXPECT_EQ(2U, frame->function_offset);
|
||||
EXPECT_EQ("/fake/compressed.so", frame->map_name);
|
||||
EXPECT_EQ(0U, frame->map_offset);
|
||||
EXPECT_EQ(0U, frame->map_elf_start_offset);
|
||||
EXPECT_EQ(0U, frame->map_exact_offset);
|
||||
EXPECT_EQ(0x33000U, frame->map_start);
|
||||
EXPECT_EQ(0x34000U, frame->map_end);
|
||||
EXPECT_EQ(0U, frame->map_load_bias);
|
||||
|
@ -874,7 +880,7 @@ TEST_F(UnwinderTest, dex_pc_in_map) {
|
|||
regs_.set_sp(0x10000);
|
||||
regs_.FakeSetDexPc(0xa3400);
|
||||
|
||||
Unwinder unwinder(64, &maps_, ®s_, process_memory_);
|
||||
Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
|
||||
unwinder.Unwind();
|
||||
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
|
||||
|
||||
|
@ -888,7 +894,8 @@ TEST_F(UnwinderTest, dex_pc_in_map) {
|
|||
EXPECT_EQ("", frame->function_name);
|
||||
EXPECT_EQ(0U, frame->function_offset);
|
||||
EXPECT_EQ("/fake/fake.vdex", frame->map_name);
|
||||
EXPECT_EQ(0U, frame->map_offset);
|
||||
EXPECT_EQ(0U, frame->map_elf_start_offset);
|
||||
EXPECT_EQ(0U, frame->map_exact_offset);
|
||||
EXPECT_EQ(0xa3000U, frame->map_start);
|
||||
EXPECT_EQ(0xa4000U, frame->map_end);
|
||||
EXPECT_EQ(0U, frame->map_load_bias);
|
||||
|
@ -902,7 +909,8 @@ TEST_F(UnwinderTest, dex_pc_in_map) {
|
|||
EXPECT_EQ("Frame0", frame->function_name);
|
||||
EXPECT_EQ(0U, frame->function_offset);
|
||||
EXPECT_EQ("/system/fake/libc.so", frame->map_name);
|
||||
EXPECT_EQ(0U, frame->map_offset);
|
||||
EXPECT_EQ(0U, frame->map_elf_start_offset);
|
||||
EXPECT_EQ(0U, frame->map_exact_offset);
|
||||
EXPECT_EQ(0x1000U, frame->map_start);
|
||||
EXPECT_EQ(0x8000U, frame->map_end);
|
||||
EXPECT_EQ(0U, frame->map_load_bias);
|
||||
|
@ -915,7 +923,7 @@ TEST_F(UnwinderTest, dex_pc_not_in_map) {
|
|||
regs_.set_sp(0x10000);
|
||||
regs_.FakeSetDexPc(0x50000);
|
||||
|
||||
Unwinder unwinder(64, &maps_, ®s_, process_memory_);
|
||||
Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
|
||||
unwinder.Unwind();
|
||||
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
|
||||
|
||||
|
@ -929,7 +937,8 @@ TEST_F(UnwinderTest, dex_pc_not_in_map) {
|
|||
EXPECT_EQ("", frame->function_name);
|
||||
EXPECT_EQ(0U, frame->function_offset);
|
||||
EXPECT_EQ("", frame->map_name);
|
||||
EXPECT_EQ(0U, frame->map_offset);
|
||||
EXPECT_EQ(0U, frame->map_elf_start_offset);
|
||||
EXPECT_EQ(0U, frame->map_exact_offset);
|
||||
EXPECT_EQ(0U, frame->map_start);
|
||||
EXPECT_EQ(0U, frame->map_end);
|
||||
EXPECT_EQ(0U, frame->map_load_bias);
|
||||
|
@ -943,7 +952,8 @@ TEST_F(UnwinderTest, dex_pc_not_in_map) {
|
|||
EXPECT_EQ("Frame0", frame->function_name);
|
||||
EXPECT_EQ(0U, frame->function_offset);
|
||||
EXPECT_EQ("/system/fake/libc.so", frame->map_name);
|
||||
EXPECT_EQ(0U, frame->map_offset);
|
||||
EXPECT_EQ(0U, frame->map_elf_start_offset);
|
||||
EXPECT_EQ(0U, frame->map_exact_offset);
|
||||
EXPECT_EQ(0x1000U, frame->map_start);
|
||||
EXPECT_EQ(0x8000U, frame->map_end);
|
||||
EXPECT_EQ(0U, frame->map_load_bias);
|
||||
|
@ -959,7 +969,7 @@ TEST_F(UnwinderTest, dex_pc_multiple_frames) {
|
|||
ElfInterfaceFake::FakePushStepData(StepData(0x33402, 0x10010, false));
|
||||
ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
|
||||
|
||||
Unwinder unwinder(64, &maps_, ®s_, process_memory_);
|
||||
Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
|
||||
unwinder.Unwind();
|
||||
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
|
||||
|
||||
|
@ -973,7 +983,8 @@ TEST_F(UnwinderTest, dex_pc_multiple_frames) {
|
|||
EXPECT_EQ("", frame->function_name);
|
||||
EXPECT_EQ(0U, frame->function_offset);
|
||||
EXPECT_EQ("/fake/fake.vdex", frame->map_name);
|
||||
EXPECT_EQ(0U, frame->map_offset);
|
||||
EXPECT_EQ(0U, frame->map_elf_start_offset);
|
||||
EXPECT_EQ(0U, frame->map_exact_offset);
|
||||
EXPECT_EQ(0xa3000U, frame->map_start);
|
||||
EXPECT_EQ(0xa4000U, frame->map_end);
|
||||
EXPECT_EQ(0U, frame->map_load_bias);
|
||||
|
@ -987,7 +998,8 @@ TEST_F(UnwinderTest, dex_pc_multiple_frames) {
|
|||
EXPECT_EQ("Frame0", frame->function_name);
|
||||
EXPECT_EQ(0U, frame->function_offset);
|
||||
EXPECT_EQ("/system/fake/libc.so", frame->map_name);
|
||||
EXPECT_EQ(0U, frame->map_offset);
|
||||
EXPECT_EQ(0U, frame->map_elf_start_offset);
|
||||
EXPECT_EQ(0U, frame->map_exact_offset);
|
||||
EXPECT_EQ(0x1000U, frame->map_start);
|
||||
EXPECT_EQ(0x8000U, frame->map_end);
|
||||
EXPECT_EQ(0U, frame->map_load_bias);
|
||||
|
@ -1001,7 +1013,8 @@ TEST_F(UnwinderTest, dex_pc_multiple_frames) {
|
|||
EXPECT_EQ("Frame1", frame->function_name);
|
||||
EXPECT_EQ(1U, frame->function_offset);
|
||||
EXPECT_EQ("/fake/compressed.so", frame->map_name);
|
||||
EXPECT_EQ(0U, frame->map_offset);
|
||||
EXPECT_EQ(0U, frame->map_elf_start_offset);
|
||||
EXPECT_EQ(0U, frame->map_exact_offset);
|
||||
EXPECT_EQ(0x33000U, frame->map_start);
|
||||
EXPECT_EQ(0x34000U, frame->map_end);
|
||||
EXPECT_EQ(0U, frame->map_load_bias);
|
||||
|
@ -1014,7 +1027,7 @@ TEST_F(UnwinderTest, dex_pc_max_frames) {
|
|||
regs_.set_sp(0x10000);
|
||||
regs_.FakeSetDexPc(0xa3400);
|
||||
|
||||
Unwinder unwinder(1, &maps_, ®s_, process_memory_);
|
||||
Unwinder unwinder(1, maps_.get(), ®s_, process_memory_);
|
||||
unwinder.Unwind();
|
||||
EXPECT_EQ(ERROR_MAX_FRAMES_EXCEEDED, unwinder.LastErrorCode());
|
||||
|
||||
|
@ -1028,7 +1041,8 @@ TEST_F(UnwinderTest, dex_pc_max_frames) {
|
|||
EXPECT_EQ("", frame->function_name);
|
||||
EXPECT_EQ(0U, frame->function_offset);
|
||||
EXPECT_EQ("/fake/fake.vdex", frame->map_name);
|
||||
EXPECT_EQ(0U, frame->map_offset);
|
||||
EXPECT_EQ(0U, frame->map_elf_start_offset);
|
||||
EXPECT_EQ(0U, frame->map_exact_offset);
|
||||
EXPECT_EQ(0xa3000U, frame->map_start);
|
||||
EXPECT_EQ(0xa4000U, frame->map_end);
|
||||
EXPECT_EQ(0U, frame->map_load_bias);
|
||||
|
@ -1045,17 +1059,17 @@ TEST_F(UnwinderTest, format_frame_static) {
|
|||
frame.function_name = "function";
|
||||
frame.function_offset = 100;
|
||||
frame.map_name = "/fake/libfake.so";
|
||||
frame.map_offset = 0x2000;
|
||||
frame.map_elf_start_offset = 0x2000;
|
||||
frame.map_start = 0x3000;
|
||||
frame.map_end = 0x6000;
|
||||
frame.map_flags = PROT_READ;
|
||||
|
||||
EXPECT_EQ(" #01 pc 0000000000001000 (offset 0x2000) /fake/libfake.so (function+100)",
|
||||
EXPECT_EQ(" #01 pc 0000000000001000 /fake/libfake.so (offset 0x2000) (function+100)",
|
||||
Unwinder::FormatFrame(frame, false));
|
||||
EXPECT_EQ(" #01 pc 00001000 (offset 0x2000) /fake/libfake.so (function+100)",
|
||||
EXPECT_EQ(" #01 pc 00001000 /fake/libfake.so (offset 0x2000) (function+100)",
|
||||
Unwinder::FormatFrame(frame, true));
|
||||
|
||||
frame.map_offset = 0;
|
||||
frame.map_elf_start_offset = 0;
|
||||
EXPECT_EQ(" #01 pc 0000000000001000 /fake/libfake.so (function+100)",
|
||||
Unwinder::FormatFrame(frame, false));
|
||||
EXPECT_EQ(" #01 pc 00001000 /fake/libfake.so (function+100)",
|
||||
|
@ -1130,7 +1144,7 @@ TEST_F(UnwinderTest, format_frame) {
|
|||
for (auto regs : reg_list) {
|
||||
ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 10));
|
||||
|
||||
Unwinder unwinder(64, &maps_, regs, process_memory_);
|
||||
Unwinder unwinder(64, maps_.get(), regs, process_memory_);
|
||||
unwinder.Unwind();
|
||||
|
||||
ASSERT_EQ(1U, unwinder.NumFrames());
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
|
|
Loading…
Reference in New Issue