Add indicator that an elf is memory backed.
Modify the unwinder library to indicate that at least one of the stack
frames contains an elf file that is unreadable.
Modify debuggerd to display a note about the unreadable frame and a possible
way to fix it.
Bug: 129769339
Test: New unit tests pass.
Test: Ran an app that crashes and has an unreadable file and verified the
Test: message is displayed. Then setenforce 0 and verify the message is
Test: not displayed.
Change-Id: Ibc4fe1d117e9b5840290454e90914ddc698d3cc2
Merged-In: Ibc4fe1d117e9b5840290454e90914ddc698d3cc2
(cherry picked from commit 4ae266ccbddbd0a6529248ecd1b324feab261c0d)
diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp
index 28373b2..03658b4 100644
--- a/libunwindstack/MapInfo.cpp
+++ b/libunwindstack/MapInfo.cpp
@@ -161,6 +161,7 @@
// 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 @@
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 @@
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();
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index f3d2b5e..26626b5 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -141,6 +141,7 @@
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 @@
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.
diff --git a/libunwindstack/include/unwindstack/MapInfo.h b/libunwindstack/include/unwindstack/MapInfo.h
index e938986..025fd98 100644
--- a/libunwindstack/include/unwindstack/MapInfo.h
+++ b/libunwindstack/include/unwindstack/MapInfo.h
@@ -75,6 +75,9 @@
// 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);
diff --git a/libunwindstack/include/unwindstack/Unwinder.h b/libunwindstack/include/unwindstack/Unwinder.h
index 75be209..52b3578 100644
--- a/libunwindstack/include/unwindstack/Unwinder.h
+++ b/libunwindstack/include/unwindstack/Unwinder.h
@@ -111,6 +111,8 @@
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 @@
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_;
};
diff --git a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
index 2ddadef..6be8bdc 100644
--- a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
+++ b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
@@ -108,6 +108,7 @@
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 @@
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 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
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);
diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp
index 48e038e..f635021 100644
--- a/libunwindstack/tests/UnwinderTest.cpp
+++ b/libunwindstack/tests/UnwinderTest.cpp
@@ -108,6 +108,24 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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);