Merge "Add indicator that an elf is memory backed."

This commit is contained in:
Christopher Ferris 2019-04-19 02:50:43 +00:00 committed by Gerrit Code Review
commit 7908ff90d0
11 changed files with 199 additions and 12 deletions

View file

@ -183,6 +183,12 @@ cc_library_static {
],
},
},
product_variables: {
debuggable: {
cflags: ["-DROOT_POSSIBLE"],
},
},
}
cc_test {

View file

@ -74,10 +74,7 @@ void dump_backtrace_thread(int output_fd, unwindstack::Unwinder* unwinder,
return;
}
unwinder->SetDisplayBuildID(true);
for (size_t i = 0; i < unwinder->NumFrames(); i++) {
_LOG(&log, logtype::BACKTRACE, " %s\n", unwinder->FormatFrame(i).c_str());
}
log_backtrace(&log, unwinder, " ");
}
void dump_backtrace(android::base::unique_fd output_fd, unwindstack::Unwinder* unwinder,

View file

@ -73,9 +73,12 @@ typedef uint32_t word_t;
void _LOG(log_t* log, logtype ltype, const char* fmt, ...) __attribute__((format(printf, 3, 4)));
namespace unwindstack {
class Unwinder;
class Memory;
}
void log_backtrace(log_t* log, unwindstack::Unwinder* unwinder, const char* prefix);
void dump_memory(log_t* log, unwindstack::Memory* backtrace, uint64_t addr, const std::string&);
void read_with_default(const char* path, char* buf, size_t len, const char* default_value);

View file

@ -371,13 +371,6 @@ static void dump_all_maps(log_t* log, unwindstack::Unwinder* unwinder, uint64_t
}
}
void dump_backtrace(log_t* log, unwindstack::Unwinder* unwinder, const char* prefix) {
unwinder->SetDisplayBuildID(true);
for (size_t i = 0; i < unwinder->NumFrames(); i++) {
_LOG(log, logtype::BACKTRACE, "%s%s\n", prefix, unwinder->FormatFrame(i).c_str());
}
}
static void print_register_row(log_t* log,
const std::vector<std::pair<std::string, uint64_t>>& registers) {
std::string output;
@ -470,7 +463,7 @@ static bool dump_thread(log_t* log, unwindstack::Unwinder* unwinder, const Threa
_LOG(log, logtype::THREAD, "Failed to unwind");
} else {
_LOG(log, logtype::BACKTRACE, "\nbacktrace:\n");
dump_backtrace(log, unwinder, " ");
log_backtrace(log, unwinder, " ");
_LOG(log, logtype::STACK, "\nstack:\n");
dump_stack(log, unwinder->frames(), unwinder->GetMaps(), unwinder->GetProcessMemory().get());

View file

@ -38,6 +38,7 @@
#include <debuggerd/handler.h>
#include <log/log.h>
#include <unwindstack/Memory.h>
#include <unwindstack/Unwinder.h>
using android::base::unique_fd;
@ -422,3 +423,22 @@ const char* get_sigcode(const siginfo_t* si) {
// Then give up...
return "?";
}
void log_backtrace(log_t* log, unwindstack::Unwinder* unwinder, const char* prefix) {
if (unwinder->elf_from_memory_not_file()) {
_LOG(log, logtype::BACKTRACE,
"%sNOTE: Function names and BuildId information is missing for some frames due\n", prefix);
_LOG(log, logtype::BACKTRACE,
"%sNOTE: to unreadable libraries. For unwinds of apps, only shared libraries\n", prefix);
_LOG(log, logtype::BACKTRACE, "%sNOTE: found under the lib/ directory are readable.\n", prefix);
#if defined(ROOT_POSSIBLE)
_LOG(log, logtype::BACKTRACE,
"%sNOTE: On this device, run setenforce 0 to make the libraries readable.\n", prefix);
#endif
}
unwinder->SetDisplayBuildID(true);
for (size_t i = 0; i < unwinder->NumFrames(); i++) {
_LOG(log, logtype::BACKTRACE, "%s%s\n", prefix, unwinder->FormatFrame(i).c_str());
}
}

View file

@ -161,6 +161,7 @@ Memory* MapInfo::CreateMemory(const std::shared_ptr<Memory>& process_memory) {
// option is used.
std::unique_ptr<MemoryRange> memory(new MemoryRange(process_memory, start, end - start, 0));
if (Elf::IsValidElf(memory.get())) {
memory_backed_elf = true;
return memory.release();
}
@ -184,6 +185,7 @@ Memory* MapInfo::CreateMemory(const std::shared_ptr<Memory>& process_memory) {
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));
memory_backed_elf = true;
return ranges;
}
@ -237,6 +239,7 @@ Elf* MapInfo::GetElf(const std::shared_ptr<Memory>& process_memory, ArchEnum exp
std::lock_guard<std::mutex> guard(prev_map->mutex_);
if (prev_map->elf.get() == nullptr) {
prev_map->elf = elf;
prev_map->memory_backed_elf = memory_backed_elf;
}
}
return elf.get();

View file

@ -141,6 +141,7 @@ void Unwinder::Unwind(const std::vector<std::string>* initial_map_names_to_skip,
frames_.clear();
last_error_.code = ERROR_NONE;
last_error_.address = 0;
elf_from_memory_not_file_ = false;
ArchEnum arch = regs_->Arch();
@ -164,6 +165,12 @@ void Unwinder::Unwind(const std::vector<std::string>* initial_map_names_to_skip,
break;
}
elf = map_info->GetElf(process_memory_, arch);
// If this elf is memory backed, and there is a valid file, then set
// an indicator that we couldn't open the file.
if (!elf_from_memory_not_file_ && map_info->memory_backed_elf && !map_info->name.empty() &&
map_info->name[0] != '[') {
elf_from_memory_not_file_ = true;
}
step_pc = regs_->pc();
rel_pc = elf->GetRelPc(step_pc, map_info);
// Everyone except elf data in gdb jit debug maps uses the relative pc.

View file

@ -75,6 +75,9 @@ struct MapInfo {
// make it easier to move to a fine grained lock in the future.
std::atomic_uintptr_t build_id;
// Set to true if the elf file data is coming from memory.
bool memory_backed_elf = false;
// This function guarantees it will never return nullptr.
Elf* GetElf(const std::shared_ptr<Memory>& process_memory, ArchEnum expected_arch);

View file

@ -111,6 +111,8 @@ class Unwinder {
void SetDexFiles(DexFiles* dex_files, ArchEnum arch);
#endif
bool elf_from_memory_not_file() { return elf_from_memory_not_file_; }
ErrorCode LastErrorCode() { return last_error_.code; }
uint64_t LastErrorAddress() { return last_error_.address; }
@ -132,6 +134,9 @@ class Unwinder {
bool resolve_names_ = true;
bool embedded_soname_ = true;
bool display_build_id_ = false;
// True if at least one elf file is coming from memory and not the related
// file. This is only true if there is an actual file backing up the elf.
bool elf_from_memory_not_file_ = false;
ErrorData last_error_;
};

View file

@ -108,6 +108,7 @@ TEST_F(MapInfoCreateMemoryTest, end_le_start) {
info.end = 0x101;
memory.reset(info.CreateMemory(process_memory_));
ASSERT_TRUE(memory.get() != nullptr);
EXPECT_FALSE(info.memory_backed_elf);
}
// Verify that if the offset is non-zero but there is no elf at the offset,
@ -117,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);
EXPECT_FALSE(info.memory_backed_elf);
ASSERT_EQ(0x100U, info.elf_offset);
EXPECT_EQ(0x100U, info.elf_start_offset);
@ -140,32 +142,40 @@ TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_full_file) {
// offset to zero.
info.elf_offset = 0;
info.elf_start_offset = 0;
info.memory_backed_elf = false;
memory.reset(info.CreateMemory(process_memory_));
ASSERT_TRUE(memory.get() != nullptr);
EXPECT_FALSE(info.memory_backed_elf);
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;
info.memory_backed_elf = false;
memory.reset(info.CreateMemory(process_memory_));
ASSERT_TRUE(memory.get() != nullptr);
EXPECT_FALSE(info.memory_backed_elf);
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;
info.memory_backed_elf = false;
memory.reset(info.CreateMemory(process_memory_));
ASSERT_TRUE(memory.get() != nullptr);
EXPECT_FALSE(info.memory_backed_elf);
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;
info.memory_backed_elf = false;
memory.reset(info.CreateMemory(process_memory_));
ASSERT_TRUE(memory.get() != nullptr);
EXPECT_FALSE(info.memory_backed_elf);
ASSERT_EQ(0x100U, info.elf_offset);
EXPECT_EQ(0U, info.elf_start_offset);
}
@ -177,6 +187,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);
EXPECT_FALSE(info.memory_backed_elf);
ASSERT_EQ(0U, info.elf_offset);
EXPECT_EQ(0x1000U, info.elf_start_offset);
@ -201,6 +212,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);
EXPECT_FALSE(info.memory_backed_elf);
ASSERT_EQ(0U, info.elf_offset);
EXPECT_EQ(0x1000U, info.elf_start_offset);
@ -218,6 +230,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);
EXPECT_FALSE(info.memory_backed_elf);
ASSERT_EQ(0U, info.elf_offset);
EXPECT_EQ(0x2000U, info.elf_start_offset);
@ -259,6 +272,7 @@ TEST_F(MapInfoCreateMemoryTest, process_memory) {
std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
ASSERT_TRUE(memory.get() != nullptr);
EXPECT_TRUE(info.memory_backed_elf);
memset(buffer.data(), 0, buffer.size());
ASSERT_TRUE(memory->ReadFully(0, buffer.data(), buffer.size()));
@ -290,6 +304,7 @@ TEST_F(MapInfoCreateMemoryTest, valid_rosegment_zero_offset) {
std::unique_ptr<Memory> mem(map_info->CreateMemory(process_memory_));
ASSERT_TRUE(mem.get() != nullptr);
EXPECT_TRUE(map_info->memory_backed_elf);
EXPECT_EQ(0x4000UL, map_info->elf_offset);
EXPECT_EQ(0x4000UL, map_info->offset);
EXPECT_EQ(0U, map_info->elf_start_offset);
@ -336,6 +351,7 @@ TEST_F(MapInfoCreateMemoryTest, valid_rosegment_non_zero_offset) {
std::unique_ptr<Memory> mem(map_info->CreateMemory(process_memory_));
ASSERT_TRUE(mem.get() != nullptr);
EXPECT_TRUE(map_info->memory_backed_elf);
EXPECT_EQ(0x1000UL, map_info->elf_offset);
EXPECT_EQ(0xb000UL, map_info->offset);
EXPECT_EQ(0xa000UL, map_info->elf_start_offset);
@ -374,6 +390,7 @@ TEST_F(MapInfoCreateMemoryTest, rosegment_from_file) {
// extend over the executable segment.
std::unique_ptr<Memory> memory(map_info->CreateMemory(process_memory_));
ASSERT_TRUE(memory.get() != nullptr);
EXPECT_FALSE(map_info->memory_backed_elf);
std::vector<uint8_t> buffer(0x100);
EXPECT_EQ(0x2000U, map_info->offset);
EXPECT_EQ(0U, map_info->elf_offset);
@ -388,7 +405,9 @@ TEST_F(MapInfoCreateMemoryTest, rosegment_from_file) {
ASSERT_EQ(0x1000, lseek(elf_at_1000_.fd, 0x1000, SEEK_SET));
ASSERT_TRUE(android::base::WriteFully(elf_at_1000_.fd, &ehdr, sizeof(ehdr)));
map_info->memory_backed_elf = false;
memory.reset(map_info->CreateMemory(process_memory_));
EXPECT_FALSE(map_info->memory_backed_elf);
EXPECT_EQ(0x2000U, map_info->offset);
EXPECT_EQ(0x1000U, map_info->elf_offset);
EXPECT_EQ(0x1000U, map_info->elf_start_offset);

View file

@ -108,6 +108,24 @@ class UnwinderTest : public ::testing::Test {
const auto& info2 = *--maps_->end();
info2->elf_offset = 0x8000;
elf = new ElfFake(new MemoryFake);
elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
AddMapInfo(0xc0000, 0xc1000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/unreadable.so", elf);
const auto& info3 = *--maps_->end();
info3->memory_backed_elf = true;
elf = new ElfFake(new MemoryFake);
elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
AddMapInfo(0xc1000, 0xc2000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "[vdso]", elf);
const auto& info4 = *--maps_->end();
info4->memory_backed_elf = true;
elf = new ElfFake(new MemoryFake);
elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
AddMapInfo(0xc2000, 0xc3000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "", elf);
const auto& info5 = *--maps_->end();
info5->memory_backed_elf = true;
process_memory_.reset(new MemoryFake);
}
@ -140,6 +158,7 @@ TEST_F(UnwinderTest, multiple_frames) {
Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(3U, unwinder.NumFrames());
@ -204,6 +223,7 @@ TEST_F(UnwinderTest, multiple_frames_dont_resolve_names) {
unwinder.SetResolveNames(false);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(3U, unwinder.NumFrames());
@ -263,6 +283,7 @@ TEST_F(UnwinderTest, non_zero_load_bias) {
Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(1U, unwinder.NumFrames());
@ -292,6 +313,7 @@ TEST_F(UnwinderTest, non_zero_elf_offset) {
Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(1U, unwinder.NumFrames());
@ -321,6 +343,7 @@ TEST_F(UnwinderTest, non_zero_map_offset) {
Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(1U, unwinder.NumFrames());
@ -351,6 +374,7 @@ TEST_F(UnwinderTest, disable_embedded_soname) {
unwinder.SetEmbeddedSoname(false);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(1U, unwinder.NumFrames());
@ -387,6 +411,7 @@ TEST_F(UnwinderTest, no_frames_after_finished) {
Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(1U, unwinder.NumFrames());
@ -419,6 +444,7 @@ TEST_F(UnwinderTest, max_frames) {
Unwinder unwinder(20, maps_.get(), &regs_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_MAX_FRAMES_EXCEEDED, unwinder.LastErrorCode());
EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(20U, unwinder.NumFrames());
@ -461,6 +487,7 @@ TEST_F(UnwinderTest, verify_frames_skipped) {
std::vector<std::string> skip_libs{"libunwind.so", "libanother.so"};
unwinder.Unwind(&skip_libs);
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(3U, unwinder.NumFrames());
@ -522,6 +549,7 @@ TEST_F(UnwinderTest, sp_not_in_map) {
Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(2U, unwinder.NumFrames());
@ -569,6 +597,7 @@ TEST_F(UnwinderTest, pc_in_device_stops_unwind) {
Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(1U, unwinder.NumFrames());
}
@ -588,6 +617,7 @@ TEST_F(UnwinderTest, sp_in_device_stops_unwind) {
Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(1U, unwinder.NumFrames());
}
@ -602,6 +632,7 @@ TEST_F(UnwinderTest, pc_without_map) {
Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_INVALID_MAP, unwinder.LastErrorCode());
EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(1U, unwinder.NumFrames());
@ -638,6 +669,7 @@ TEST_F(UnwinderTest, speculative_frame) {
Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(3U, unwinder.NumFrames());
@ -703,6 +735,7 @@ TEST_F(UnwinderTest, speculative_frame_removed) {
Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_INVALID_MAP, unwinder.LastErrorCode());
EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(2U, unwinder.NumFrames());
@ -752,6 +785,7 @@ TEST_F(UnwinderTest, speculative_frame_not_removed_pc_bad) {
Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(2U, unwinder.NumFrames());
@ -799,6 +833,7 @@ TEST_F(UnwinderTest, speculative_frame_check_with_no_frames) {
std::vector<std::string> skip_names{"libanother.so"};
unwinder.Unwind(&skip_names);
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(0U, unwinder.NumFrames());
}
@ -821,6 +856,7 @@ TEST_F(UnwinderTest, map_ignore_suffixes) {
std::vector<std::string> suffixes{"oat"};
unwinder.Unwind(nullptr, &suffixes);
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(2U, unwinder.NumFrames());
// Make sure the elf was not initialized.
@ -879,6 +915,7 @@ TEST_F(UnwinderTest, sp_pc_do_not_change) {
Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_REPEATED_FRAME, unwinder.LastErrorCode());
EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(3U, unwinder.NumFrames());
@ -937,6 +974,7 @@ TEST_F(UnwinderTest, dex_pc_in_map) {
Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(2U, unwinder.NumFrames());
@ -980,6 +1018,7 @@ TEST_F(UnwinderTest, dex_pc_not_in_map) {
Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(2U, unwinder.NumFrames());
@ -1026,6 +1065,7 @@ TEST_F(UnwinderTest, dex_pc_multiple_frames) {
Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(3U, unwinder.NumFrames());
@ -1084,6 +1124,7 @@ TEST_F(UnwinderTest, dex_pc_max_frames) {
Unwinder unwinder(1, maps_.get(), &regs_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_MAX_FRAMES_EXCEEDED, unwinder.LastErrorCode());
EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(1U, unwinder.NumFrames());
@ -1103,6 +1144,96 @@ TEST_F(UnwinderTest, dex_pc_max_frames) {
EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags);
}
TEST_F(UnwinderTest, elf_from_memory_not_file) {
ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
regs_.set_pc(0xc0050);
regs_.set_sp(0x10000);
ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
EXPECT_TRUE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(1U, unwinder.NumFrames());
auto* frame = &unwinder.frames()[0];
EXPECT_EQ(0U, frame->num);
EXPECT_EQ(0x50U, frame->rel_pc);
EXPECT_EQ(0xc0050U, frame->pc);
EXPECT_EQ(0x10000U, frame->sp);
EXPECT_EQ("Frame0", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
EXPECT_EQ("/fake/unreadable.so", frame->map_name);
EXPECT_EQ(0U, frame->map_elf_start_offset);
EXPECT_EQ(0U, frame->map_exact_offset);
EXPECT_EQ(0xc0000U, frame->map_start);
EXPECT_EQ(0xc1000U, frame->map_end);
EXPECT_EQ(0U, frame->map_load_bias);
EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags);
}
TEST_F(UnwinderTest, elf_from_memory_but_no_valid_file_with_bracket) {
ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
regs_.set_pc(0xc1050);
regs_.set_sp(0x10000);
ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(1U, unwinder.NumFrames());
auto* frame = &unwinder.frames()[0];
EXPECT_EQ(0U, frame->num);
EXPECT_EQ(0x50U, frame->rel_pc);
EXPECT_EQ(0xc1050U, frame->pc);
EXPECT_EQ(0x10000U, frame->sp);
EXPECT_EQ("Frame0", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
EXPECT_EQ("[vdso]", frame->map_name);
EXPECT_EQ(0U, frame->map_elf_start_offset);
EXPECT_EQ(0U, frame->map_exact_offset);
EXPECT_EQ(0xc1000U, frame->map_start);
EXPECT_EQ(0xc2000U, frame->map_end);
EXPECT_EQ(0U, frame->map_load_bias);
EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags);
}
TEST_F(UnwinderTest, elf_from_memory_but_empty_filename) {
ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
regs_.set_pc(0xc2050);
regs_.set_sp(0x10000);
ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(1U, unwinder.NumFrames());
auto* frame = &unwinder.frames()[0];
EXPECT_EQ(0U, frame->num);
EXPECT_EQ(0x50U, frame->rel_pc);
EXPECT_EQ(0xc2050U, frame->pc);
EXPECT_EQ(0x10000U, frame->sp);
EXPECT_EQ("Frame0", frame->function_name);
EXPECT_EQ(0U, frame->function_offset);
EXPECT_EQ("", frame->map_name);
EXPECT_EQ(0U, frame->map_elf_start_offset);
EXPECT_EQ(0U, frame->map_exact_offset);
EXPECT_EQ(0xc2000U, frame->map_start);
EXPECT_EQ(0xc3000U, frame->map_end);
EXPECT_EQ(0U, frame->map_load_bias);
EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags);
}
// Verify format frame code.
TEST_F(UnwinderTest, format_frame) {
RegsFake regs_arm(10);