Merge "Add indicator that an elf is memory backed."
This commit is contained in:
commit
7908ff90d0
11 changed files with 199 additions and 12 deletions
|
|
@ -183,6 +183,12 @@ cc_library_static {
|
|||
],
|
||||
},
|
||||
},
|
||||
|
||||
product_variables: {
|
||||
debuggable: {
|
||||
cflags: ["-DROOT_POSSIBLE"],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
cc_test {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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(), ®s_, 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(), ®s_, 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(), ®s_, 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(), ®s_, 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(), ®s_, 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(), ®s_, 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(), ®s_, 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(), ®s_, 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(), ®s_, 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(), ®s_, 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(), ®s_, 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(), ®s_, 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(), ®s_, 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(), ®s_, 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(), ®s_, 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(), ®s_, 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(), ®s_, 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(), ®s_, 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(), ®s_, 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(), ®s_, 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(), ®s_, 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);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue