summaryrefslogtreecommitdiff
path: root/libunwindstack
diff options
context:
space:
mode:
Diffstat (limited to 'libunwindstack')
-rw-r--r--libunwindstack/DwarfSection.cpp24
-rw-r--r--libunwindstack/RegsX86_64.cpp5
-rw-r--r--libunwindstack/Unwinder.cpp28
-rw-r--r--libunwindstack/include/unwindstack/Error.h7
-rw-r--r--libunwindstack/include/unwindstack/Unwinder.h4
-rw-r--r--libunwindstack/tests/DwarfSectionImplTest.cpp35
-rw-r--r--libunwindstack/tests/RegsFake.h18
-rw-r--r--libunwindstack/tests/UnwinderTest.cpp345
-rw-r--r--libunwindstack/tests/fuzz/UnwinderComponentCreator.cpp33
9 files changed, 437 insertions, 62 deletions
diff --git a/libunwindstack/DwarfSection.cpp b/libunwindstack/DwarfSection.cpp
index 9e2a3cda7..bf86e6e66 100644
--- a/libunwindstack/DwarfSection.cpp
+++ b/libunwindstack/DwarfSection.cpp
@@ -465,13 +465,9 @@ bool DwarfSectionImpl<AddressType>::EvalRegister(const DwarfLocation* loc, uint3
eval_info->return_address_undefined = true;
}
break;
- case DWARF_LOCATION_PSEUDO_REGISTER: {
- if (!eval_info->regs_info.regs->SetPseudoRegister(reg, loc->values[0])) {
- last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
- return false;
- }
- break;
- }
+ case DWARF_LOCATION_PSEUDO_REGISTER:
+ last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
+ return false;
default:
break;
}
@@ -543,11 +539,15 @@ bool DwarfSectionImpl<AddressType>::Eval(const DwarfCie* cie, Memory* regular_me
// Skip this unknown register.
continue;
}
- }
-
- reg_ptr = eval_info.regs_info.Save(reg);
- if (!EvalRegister(&entry.second, reg, reg_ptr, &eval_info)) {
- return false;
+ if (!eval_info.regs_info.regs->SetPseudoRegister(reg, entry.second.values[0])) {
+ last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
+ return false;
+ }
+ } else {
+ reg_ptr = eval_info.regs_info.Save(reg);
+ if (!EvalRegister(&entry.second, reg, reg_ptr, &eval_info)) {
+ return false;
+ }
}
}
diff --git a/libunwindstack/RegsX86_64.cpp b/libunwindstack/RegsX86_64.cpp
index c9e245d2f..26d9f6578 100644
--- a/libunwindstack/RegsX86_64.cpp
+++ b/libunwindstack/RegsX86_64.cpp
@@ -141,15 +141,14 @@ bool RegsX86_64::StepIfSignalHandler(uint64_t elf_offset, Elf* elf, Memory* proc
return false;
}
- uint16_t data2;
- if (!elf_memory->ReadFully(elf_offset + 8, &data2, sizeof(data2)) || data2 != 0x0f05) {
+ uint8_t data2;
+ if (!elf_memory->ReadFully(elf_offset + 8, &data2, sizeof(data2)) || data2 != 0x05) {
return false;
}
// __restore_rt:
// 0x48 0xc7 0xc0 0x0f 0x00 0x00 0x00 mov $0xf,%rax
// 0x0f 0x05 syscall
- // 0x0f nopl 0x0($rax)
// Read the mcontext data from the stack.
// sp points to the ucontext data structure, read only the mcontext part.
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index 2d867cd5e..57806c157 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -75,6 +75,7 @@ void Unwinder::FillInDexFrame() {
frame->rel_pc = dex_pc - info->start;
} else {
frame->rel_pc = dex_pc;
+ warnings_ |= WARNING_DEX_PC_NOT_IN_MAP;
return;
}
@@ -142,6 +143,7 @@ static bool ShouldStop(const std::vector<std::string>* map_suffixes_to_ignore,
void Unwinder::Unwind(const std::vector<std::string>* initial_map_names_to_skip,
const std::vector<std::string>* map_suffixes_to_ignore) {
frames_.clear();
+ warnings_ = WARNING_NONE;
last_error_.code = ERROR_NONE;
last_error_.address = 0;
elf_from_memory_not_file_ = false;
@@ -395,18 +397,20 @@ bool UnwinderFromPid::Init(ArchEnum arch) {
return true;
}
-FrameData Unwinder::BuildFrameFromPcOnly(uint64_t pc) {
+FrameData Unwinder::BuildFrameFromPcOnly(uint64_t pc, ArchEnum arch, Maps* maps,
+ JitDebug* jit_debug,
+ std::shared_ptr<Memory> process_memory,
+ bool resolve_names) {
FrameData frame;
- Maps* maps = GetMaps();
MapInfo* map_info = maps->Find(pc);
- if (!map_info) {
+ if (map_info == nullptr || arch == ARCH_UNKNOWN) {
+ frame.pc = pc;
frame.rel_pc = pc;
return frame;
}
- ArchEnum arch = Regs::CurrentArch();
- Elf* elf = map_info->GetElf(GetProcessMemory(), arch);
+ Elf* elf = map_info->GetElf(process_memory, arch);
uint64_t relative_pc = elf->GetRelPc(pc, map_info);
@@ -416,10 +420,9 @@ FrameData Unwinder::BuildFrameFromPcOnly(uint64_t pc) {
uint64_t debug_pc = relative_pc;
// If we don't have a valid ELF file, check the JIT.
- if (!elf->valid()) {
- JitDebug jit_debug(GetProcessMemory());
+ if (!elf->valid() && jit_debug != nullptr) {
uint64_t jit_pc = pc - pc_adjustment;
- Elf* jit_elf = jit_debug.GetElf(maps, jit_pc);
+ Elf* jit_elf = jit_debug->GetElf(maps, jit_pc);
if (jit_elf != nullptr) {
debug_pc = jit_pc;
elf = jit_elf;
@@ -437,12 +440,17 @@ FrameData Unwinder::BuildFrameFromPcOnly(uint64_t pc) {
frame.map_flags = map_info->flags;
frame.map_load_bias = elf->GetLoadBias();
- if (!resolve_names_ ||
- !elf->GetFunctionName(relative_pc, &frame.function_name, &frame.function_offset)) {
+ if (!resolve_names ||
+ !elf->GetFunctionName(debug_pc, &frame.function_name, &frame.function_offset)) {
frame.function_name = "";
frame.function_offset = 0;
}
return frame;
}
+FrameData Unwinder::BuildFrameFromPcOnly(uint64_t pc) {
+ return BuildFrameFromPcOnly(pc, regs_ ? regs_->Arch() : ARCH_UNKNOWN, maps_, jit_debug_,
+ process_memory_, resolve_names_);
+}
+
} // namespace unwindstack
diff --git a/libunwindstack/include/unwindstack/Error.h b/libunwindstack/include/unwindstack/Error.h
index 72ec4547f..66fefe76d 100644
--- a/libunwindstack/include/unwindstack/Error.h
+++ b/libunwindstack/include/unwindstack/Error.h
@@ -21,6 +21,13 @@
namespace unwindstack {
+// A bit map of warnings, multiple warnings can be set at the same time.
+enum WarningCode : uint64_t {
+ WARNING_NONE = 0,
+ WARNING_DEX_PC_NOT_IN_MAP = 0x1, // A dex pc was found, but it doesn't exist
+ // in any valid map.
+};
+
enum ErrorCode : uint8_t {
ERROR_NONE, // No error.
ERROR_MEMORY_INVALID, // Memory read failed.
diff --git a/libunwindstack/include/unwindstack/Unwinder.h b/libunwindstack/include/unwindstack/Unwinder.h
index 4d49f236a..3df8aadfd 100644
--- a/libunwindstack/include/unwindstack/Unwinder.h
+++ b/libunwindstack/include/unwindstack/Unwinder.h
@@ -113,12 +113,15 @@ class Unwinder {
ErrorCode LastErrorCode() { return last_error_.code; }
uint64_t LastErrorAddress() { return last_error_.address; }
+ uint64_t warnings() { return warnings_; }
// Builds a frame for symbolization using the maps from this unwinder. The
// constructed frame contains just enough information to be used to symbolize
// frames collected by frame-pointer unwinding that's done outside of
// libunwindstack. This is used by tombstoned to symbolize frame pointer-based
// stack traces that are collected by tools such as GWP-ASan and MTE.
+ static FrameData BuildFrameFromPcOnly(uint64_t pc, ArchEnum arch, Maps* maps, JitDebug* jit_debug,
+ std::shared_ptr<Memory> process_memory, bool resolve_names);
FrameData BuildFrameFromPcOnly(uint64_t pc);
protected:
@@ -141,6 +144,7 @@ class Unwinder {
// 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_;
+ uint64_t warnings_;
};
class UnwinderFromPid : public Unwinder {
diff --git a/libunwindstack/tests/DwarfSectionImplTest.cpp b/libunwindstack/tests/DwarfSectionImplTest.cpp
index d57cd339d..a08a8d070 100644
--- a/libunwindstack/tests/DwarfSectionImplTest.cpp
+++ b/libunwindstack/tests/DwarfSectionImplTest.cpp
@@ -492,6 +492,40 @@ TYPED_TEST_P(DwarfSectionImplTest, Eval_reg_val_expr) {
EXPECT_EQ(0x80000000U, regs.pc());
}
+TYPED_TEST_P(DwarfSectionImplTest, Eval_pseudo_register_invalid) {
+ DwarfCie cie{.return_address_register = 5};
+ RegsImplFake<TypeParam> regs(10);
+ regs.set_pseudo_reg(11);
+ dwarf_loc_regs_t loc_regs;
+
+ loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}};
+ loc_regs[1] = DwarfLocation{DWARF_LOCATION_PSEUDO_REGISTER, {20, 0}};
+ bool finished;
+ ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, &regs, &finished));
+ EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->LastErrorCode());
+
+ loc_regs.clear();
+ loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}};
+ loc_regs[12] = DwarfLocation{DWARF_LOCATION_PSEUDO_REGISTER, {20, 0}};
+ ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, &regs, &finished));
+ EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->LastErrorCode());
+}
+
+TYPED_TEST_P(DwarfSectionImplTest, Eval_pseudo_register) {
+ DwarfCie cie{.return_address_register = 5};
+ RegsImplFake<TypeParam> regs(10);
+ regs.set_pseudo_reg(11);
+ dwarf_loc_regs_t loc_regs;
+
+ loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}};
+ loc_regs[11] = DwarfLocation{DWARF_LOCATION_PSEUDO_REGISTER, {20, 0}};
+ bool finished;
+ ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, &regs, &finished));
+ uint64_t pseudo_value = 0;
+ ASSERT_TRUE(regs.GetPseudoRegister(11, &pseudo_value));
+ EXPECT_EQ(20U, pseudo_value);
+}
+
TYPED_TEST_P(DwarfSectionImplTest, GetCfaLocationInfo_cie_not_cached) {
DwarfCie cie{};
cie.cfa_instructions_offset = 0x3000;
@@ -581,6 +615,7 @@ REGISTER_TYPED_TEST_SUITE_P(DwarfSectionImplTest, GetCieFromOffset_fail_should_n
Eval_invalid_register, Eval_different_reg_locations,
Eval_return_address_undefined, Eval_pc_zero, Eval_return_address,
Eval_ignore_large_reg_loc, Eval_reg_expr, Eval_reg_val_expr,
+ Eval_pseudo_register_invalid, Eval_pseudo_register,
GetCfaLocationInfo_cie_not_cached, GetCfaLocationInfo_cie_cached, Log);
typedef ::testing::Types<uint32_t, uint64_t> DwarfSectionImplTestTypes;
diff --git a/libunwindstack/tests/RegsFake.h b/libunwindstack/tests/RegsFake.h
index 75fc9d02d..f67d7dc61 100644
--- a/libunwindstack/tests/RegsFake.h
+++ b/libunwindstack/tests/RegsFake.h
@@ -83,15 +83,33 @@ class RegsImplFake : public RegsImpl<TypeParam> {
uint64_t sp() override { return fake_sp_; }
void set_pc(uint64_t pc) override { fake_pc_ = pc; }
void set_sp(uint64_t sp) override { fake_sp_ = sp; }
+ void set_pseudo_reg(uint64_t reg) { fake_pseudo_reg_ = reg; }
bool SetPcFromReturnAddress(Memory*) override { return false; }
bool StepIfSignalHandler(uint64_t, Elf*, Memory*) override { return false; }
+ bool SetPseudoRegister(uint16_t reg, uint64_t value) override {
+ if (fake_pseudo_reg_ != reg) {
+ return false;
+ }
+ fake_pseudo_reg_value_ = value;
+ return true;
+ }
+ bool GetPseudoRegister(uint16_t reg, uint64_t* value) override {
+ if (fake_pseudo_reg_ != reg) {
+ return false;
+ }
+ *value = fake_pseudo_reg_value_;
+ return true;
+ }
+
Regs* Clone() override { return nullptr; }
private:
uint64_t fake_pc_ = 0;
uint64_t fake_sp_ = 0;
+ uint16_t fake_pseudo_reg_ = 0;
+ uint64_t fake_pseudo_reg_value_ = 0;
};
} // namespace unwindstack
diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp
index dd33aa9d7..915f24884 100644
--- a/libunwindstack/tests/UnwinderTest.cpp
+++ b/libunwindstack/tests/UnwinderTest.cpp
@@ -37,6 +37,7 @@
#include <unwindstack/Unwinder.h>
#include "ElfFake.h"
+#include "ElfTestUtils.h"
#include "MemoryFake.h"
#include "RegsFake.h"
@@ -44,23 +45,31 @@ namespace unwindstack {
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) {
+ static MapInfo* 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));
+ MapInfo* map_info = maps_->Find(start);
if (elf != nullptr) {
- const auto& map_info = *--maps_->end();
map_info->elf.reset(elf);
}
+ return map_info;
}
static void SetUpTestSuite() {
maps_.reset(new Maps);
- ElfFake* elf = new ElfFake(new MemoryFake);
- ElfInterfaceFake* interface_fake = new ElfInterfaceFake(nullptr);
- interface_fake->FakeSetBuildID("FAKE");
- elf->FakeSetInterface(interface_fake);
+ memory_ = new MemoryFake;
+ process_memory_.reset(memory_);
+
+ ElfFake* elf;
+ ElfInterfaceFake* interface;
+ MapInfo* map_info;
+
+ elf = new ElfFake(new MemoryFake);
+ interface = new ElfInterfaceFake(nullptr);
+ interface->FakeSetBuildID("FAKE");
+ elf->FakeSetInterface(interface);
AddMapInfo(0x1000, 0x8000, 0, PROT_READ | PROT_WRITE, "/system/fake/libc.so", elf);
AddMapInfo(0x10000, 0x12000, 0, PROT_READ | PROT_WRITE, "[stack]");
@@ -81,19 +90,17 @@ class UnwinderTest : public ::testing::Test {
AddMapInfo(0x33000, 0x34000, 0, PROT_READ | PROT_WRITE, "/fake/compressed.so", elf);
elf = new ElfFake(new MemoryFake);
- ElfInterfaceFake* interface = new ElfInterfaceFake(nullptr);
+ interface = new ElfInterfaceFake(nullptr);
interface->FakeSetSoname("lib_fake.so");
elf->FakeSetInterface(interface);
- AddMapInfo(0x43000, 0x44000, 0x1d000, PROT_READ | PROT_WRITE, "/fake/fake.apk", elf);
- MapInfo* map_info = maps_->Find(0x43000);
- ASSERT_TRUE(map_info != nullptr);
+ map_info = AddMapInfo(0x43000, 0x44000, 0x1d000, PROT_READ | PROT_WRITE, "/fake/fake.apk", elf);
map_info->elf_start_offset = 0x1d000;
AddMapInfo(0x53000, 0x54000, 0, PROT_READ | PROT_WRITE, "/fake/fake.oat");
- AddMapInfo(0xa3000, 0xa4000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/fake.vdex");
- const auto& info = *--maps_->end();
- info->load_bias = 0;
+ map_info =
+ AddMapInfo(0xa3000, 0xa4000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/fake.vdex");
+ map_info->load_bias = 0;
elf = new ElfFake(new MemoryFake);
elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
@@ -103,40 +110,76 @@ class UnwinderTest : public ::testing::Test {
elf = new ElfFake(new MemoryFake);
elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
- AddMapInfo(0xa7000, 0xa8000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/fake_offset.oat",
- elf);
- const auto& info2 = *--maps_->end();
- info2->elf_offset = 0x8000;
+ map_info = AddMapInfo(0xa7000, 0xa8000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
+ "/fake/fake_offset.oat", elf);
+ map_info->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;
+ map_info = AddMapInfo(0xc0000, 0xc1000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
+ "/fake/unreadable.so", elf);
+ map_info->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;
+ map_info = AddMapInfo(0xc1000, 0xc2000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "[vdso]", elf);
+ map_info->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;
+ map_info = AddMapInfo(0xc2000, 0xc3000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "", elf);
+ map_info->memory_backed_elf = true;
elf = new ElfFake(new MemoryFake);
elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
- AddMapInfo(0xc3000, 0xc4000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "/memfd:/jit-cache", elf);
- const auto& info6 = *--maps_->end();
- info6->memory_backed_elf = true;
+ map_info = AddMapInfo(0xc3000, 0xc4000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
+ "/memfd:/jit-cache", elf);
+ map_info->memory_backed_elf = true;
- AddMapInfo(0xd0000, 0xd1000, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/fake.apk");
- const auto& info7 = *--maps_->end();
- info7->load_bias = 0;
+ map_info =
+ AddMapInfo(0xd0000, 0xd1000, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/fake.apk");
+ map_info->load_bias = 0;
- process_memory_.reset(new MemoryFake);
+ elf = new ElfFake(new MemoryFake);
+ interface = new ElfInterfaceFake(nullptr);
+ elf->FakeSetInterface(interface);
+ interface->FakeSetGlobalVariable("__dex_debug_descriptor", 0x1800);
+ interface->FakeSetGlobalVariable("__jit_debug_descriptor", 0x1900);
+ interface->FakeSetDataOffset(0x1000);
+ interface->FakeSetDataVaddrStart(0x1000);
+ interface->FakeSetDataVaddrEnd(0x8000);
+ AddMapInfo(0xf0000, 0xf1000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/global.so", elf);
+ AddMapInfo(0xf1000, 0xf9000, 0x1000, PROT_READ | PROT_WRITE, "/fake/global.so");
+ // dex debug data
+ memory_->SetData32(0xf180c, 0xf3000);
+ memory_->SetData32(0xf3000, 0xf4000);
+ memory_->SetData32(0xf3004, 0xf4000);
+ memory_->SetData32(0xf3008, 0xf5000);
+ // jit debug data
+ memory_->SetData32(0xf1900, 1);
+ memory_->SetData32(0xf1904, 0);
+ memory_->SetData32(0xf1908, 0xf6000);
+ memory_->SetData32(0xf190c, 0xf6000);
+ memory_->SetData32(0xf6000, 0);
+ memory_->SetData32(0xf6004, 0);
+ memory_->SetData32(0xf6008, 0xf7000);
+ memory_->SetData32(0xf600c, 0);
+ memory_->SetData64(0xf6010, 0x1000);
+
+ elf = new ElfFake(new MemoryFake);
+ elf->FakeSetValid(false);
+ elf->FakeSetLoadBias(0x300);
+ map_info = AddMapInfo(0x100000, 0x101000, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC,
+ "/fake/jit.so", elf);
+ map_info->elf_start_offset = 0x100;
+ map_info->offset = 0x200;
+
+#if 0
+ elf = new ElfFake(new MemoryFake);
+ interface = new ElfInterfaceFake(nullptr);
+ interface->FakePushFunctionData(FunctionData("Fake0", 10));
+ AddMapInfo(0x110000, 0x111000, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/elf.so", elf);
+#endif
}
void SetUp() override {
@@ -147,11 +190,13 @@ class UnwinderTest : public ::testing::Test {
static std::unique_ptr<Maps> maps_;
static RegsFake regs_;
+ static MemoryFake* memory_;
static std::shared_ptr<Memory> process_memory_;
};
std::unique_ptr<Maps> UnwinderTest::maps_;
RegsFake UnwinderTest::regs_(5);
+MemoryFake* UnwinderTest::memory_;
std::shared_ptr<Memory> UnwinderTest::process_memory_(nullptr);
TEST_F(UnwinderTest, multiple_frames) {
@@ -168,6 +213,7 @@ TEST_F(UnwinderTest, multiple_frames) {
Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+ EXPECT_EQ(WARNING_NONE, unwinder.warnings());
EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(3U, unwinder.NumFrames());
@@ -233,6 +279,7 @@ TEST_F(UnwinderTest, multiple_frames_dont_resolve_names) {
unwinder.SetResolveNames(false);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+ EXPECT_EQ(WARNING_NONE, unwinder.warnings());
EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(3U, unwinder.NumFrames());
@@ -293,6 +340,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_EQ(WARNING_NONE, unwinder.warnings());
EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(1U, unwinder.NumFrames());
@@ -323,6 +371,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_EQ(WARNING_NONE, unwinder.warnings());
EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(1U, unwinder.NumFrames());
@@ -353,6 +402,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_EQ(WARNING_NONE, unwinder.warnings());
EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(1U, unwinder.NumFrames());
@@ -384,6 +434,7 @@ TEST_F(UnwinderTest, disable_embedded_soname) {
unwinder.SetEmbeddedSoname(false);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+ EXPECT_EQ(WARNING_NONE, unwinder.warnings());
EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(1U, unwinder.NumFrames());
@@ -421,6 +472,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_EQ(WARNING_NONE, unwinder.warnings());
EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(1U, unwinder.NumFrames());
@@ -454,6 +506,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_EQ(WARNING_NONE, unwinder.warnings());
EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(20U, unwinder.NumFrames());
@@ -497,6 +550,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_EQ(WARNING_NONE, unwinder.warnings());
EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(3U, unwinder.NumFrames());
@@ -559,6 +613,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_EQ(WARNING_NONE, unwinder.warnings());
EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(2U, unwinder.NumFrames());
@@ -607,6 +662,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_EQ(WARNING_NONE, unwinder.warnings());
EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(1U, unwinder.NumFrames());
@@ -627,6 +683,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_EQ(WARNING_NONE, unwinder.warnings());
EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(1U, unwinder.NumFrames());
@@ -642,6 +699,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_EQ(WARNING_NONE, unwinder.warnings());
EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(1U, unwinder.NumFrames());
@@ -679,6 +737,7 @@ TEST_F(UnwinderTest, speculative_frame) {
Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+ EXPECT_EQ(WARNING_NONE, unwinder.warnings());
EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(3U, unwinder.NumFrames());
@@ -745,6 +804,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_EQ(WARNING_NONE, unwinder.warnings());
EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(2U, unwinder.NumFrames());
@@ -795,6 +855,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_EQ(WARNING_NONE, unwinder.warnings());
EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(2U, unwinder.NumFrames());
@@ -843,6 +904,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_EQ(WARNING_NONE, unwinder.warnings());
EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(0U, unwinder.NumFrames());
@@ -866,6 +928,7 @@ TEST_F(UnwinderTest, map_ignore_suffixes) {
std::vector<std::string> suffixes{"oat"};
unwinder.Unwind(nullptr, &suffixes);
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+ EXPECT_EQ(WARNING_NONE, unwinder.warnings());
EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(2U, unwinder.NumFrames());
@@ -925,6 +988,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_EQ(WARNING_NONE, unwinder.warnings());
EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(3U, unwinder.NumFrames());
@@ -984,6 +1048,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_EQ(WARNING_NONE, unwinder.warnings());
EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(2U, unwinder.NumFrames());
@@ -1028,6 +1093,7 @@ TEST_F(UnwinderTest, dex_pc_in_map_non_zero_offset) {
Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+ EXPECT_EQ(WARNING_NONE, unwinder.warnings());
EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(2U, unwinder.NumFrames());
@@ -1072,6 +1138,54 @@ 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_EQ(WARNING_DEX_PC_NOT_IN_MAP, unwinder.warnings());
+ EXPECT_FALSE(unwinder.elf_from_memory_not_file());
+
+ ASSERT_EQ(2U, unwinder.NumFrames());
+
+ auto* frame = &unwinder.frames()[0];
+ EXPECT_EQ(0U, frame->num);
+ EXPECT_EQ(0x50000U, frame->rel_pc);
+ EXPECT_EQ(0x50000U, frame->pc);
+ EXPECT_EQ(0x10000U, frame->sp);
+ EXPECT_EQ("", 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(0U, frame->map_start);
+ EXPECT_EQ(0U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(0, frame->map_flags);
+
+ frame = &unwinder.frames()[1];
+ EXPECT_EQ(1U, frame->num);
+ EXPECT_EQ(0U, frame->rel_pc);
+ EXPECT_EQ(0x1000U, frame->pc);
+ EXPECT_EQ(0x10000U, frame->sp);
+ 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_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);
+ EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
+}
+
+TEST_F(UnwinderTest, dex_pc_not_in_map_valid_dex_files) {
+ ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
+ regs_.set_pc(0x1000);
+ regs_.set_sp(0x10000);
+ regs_.FakeSetDexPc(0x50000);
+
+ DexFiles dex_files(process_memory_);
+ Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
+ unwinder.SetDexFiles(&dex_files, ARCH_ARM);
+ unwinder.Unwind();
+ EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+ EXPECT_EQ(WARNING_DEX_PC_NOT_IN_MAP, unwinder.warnings());
EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(2U, unwinder.NumFrames());
@@ -1119,6 +1233,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_EQ(WARNING_NONE, unwinder.warnings());
EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(3U, unwinder.NumFrames());
@@ -1178,6 +1293,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_EQ(WARNING_NONE, unwinder.warnings());
EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(1U, unwinder.NumFrames());
@@ -1208,6 +1324,7 @@ TEST_F(UnwinderTest, elf_from_memory_not_file) {
Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+ EXPECT_EQ(WARNING_NONE, unwinder.warnings());
EXPECT_TRUE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(1U, unwinder.NumFrames());
@@ -1238,6 +1355,7 @@ TEST_F(UnwinderTest, elf_from_memory_but_no_valid_file_with_bracket) {
Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+ EXPECT_EQ(WARNING_NONE, unwinder.warnings());
EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(1U, unwinder.NumFrames());
@@ -1268,6 +1386,7 @@ TEST_F(UnwinderTest, elf_from_memory_but_empty_filename) {
Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+ EXPECT_EQ(WARNING_NONE, unwinder.warnings());
EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(1U, unwinder.NumFrames());
@@ -1298,6 +1417,7 @@ TEST_F(UnwinderTest, elf_from_memory_but_from_memfd) {
Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+ EXPECT_EQ(WARNING_NONE, unwinder.warnings());
EXPECT_FALSE(unwinder.elf_from_memory_not_file());
ASSERT_EQ(1U, unwinder.NumFrames());
@@ -1474,4 +1594,161 @@ TEST_F(UnwinderTest, format_frame_by_arch) {
}
}
+TEST_F(UnwinderTest, build_frame_pc_only_errors) {
+ RegsFake regs(10);
+ regs.FakeSetArch(ARCH_ARM);
+ Unwinder unwinder(10, maps_.get(), &regs, process_memory_);
+
+ FrameData frame;
+
+ // Pc not in map
+ frame = unwinder.BuildFrameFromPcOnly(0x10);
+ EXPECT_EQ(0x10U, frame.pc);
+ EXPECT_EQ(0x10U, frame.rel_pc);
+
+ // No regs set
+ unwinder.SetRegs(nullptr);
+ frame = unwinder.BuildFrameFromPcOnly(0x100310);
+ EXPECT_EQ(0x100310U, frame.pc);
+ EXPECT_EQ(0x100310U, frame.rel_pc);
+ unwinder.SetRegs(&regs);
+
+ // Invalid elf
+ frame = unwinder.BuildFrameFromPcOnly(0x100310);
+ EXPECT_EQ(0x10030eU, frame.pc);
+ EXPECT_EQ(0x60eU, frame.rel_pc);
+ EXPECT_EQ("/fake/jit.so", frame.map_name);
+ EXPECT_EQ(0x100U, frame.map_elf_start_offset);
+ EXPECT_EQ(0x200U, frame.map_exact_offset);
+ EXPECT_EQ(0x100000U, frame.map_start);
+ EXPECT_EQ(0x101000U, frame.map_end);
+ EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame.map_flags);
+ EXPECT_EQ(0x300U, frame.map_load_bias);
+ EXPECT_EQ("", frame.function_name);
+ EXPECT_EQ(0U, frame.function_offset);
+}
+
+TEST_F(UnwinderTest, build_frame_pc_valid_elf) {
+ RegsFake regs(10);
+ regs.FakeSetArch(ARCH_ARM);
+ Unwinder unwinder(10, maps_.get(), &regs, process_memory_);
+
+ FrameData frame;
+
+ // Valid elf, no function data.
+ frame = unwinder.BuildFrameFromPcOnly(0x1010);
+ EXPECT_EQ(0x100cU, frame.pc);
+ EXPECT_EQ(0xcU, frame.rel_pc);
+ EXPECT_EQ("/system/fake/libc.so", frame.map_name);
+ 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(PROT_READ | PROT_WRITE, frame.map_flags);
+ EXPECT_EQ(0U, frame.map_load_bias);
+ EXPECT_EQ("", frame.function_name);
+ EXPECT_EQ(0U, frame.function_offset);
+
+ // Valid elf, function data present, but do not resolve.
+ ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 10));
+ unwinder.SetResolveNames(false);
+
+ frame = unwinder.BuildFrameFromPcOnly(0x1010);
+ EXPECT_EQ(0x100cU, frame.pc);
+ EXPECT_EQ(0xcU, frame.rel_pc);
+ EXPECT_EQ("/system/fake/libc.so", frame.map_name);
+ 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(PROT_READ | PROT_WRITE, frame.map_flags);
+ EXPECT_EQ(0U, frame.map_load_bias);
+ EXPECT_EQ("", frame.function_name);
+ EXPECT_EQ(0U, frame.function_offset);
+
+ // Valid elf, function data present.
+ unwinder.SetResolveNames(true);
+
+ frame = unwinder.BuildFrameFromPcOnly(0x1010);
+ EXPECT_EQ(0x100cU, frame.pc);
+ EXPECT_EQ(0xcU, frame.rel_pc);
+ EXPECT_EQ("/system/fake/libc.so", frame.map_name);
+ 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(PROT_READ | PROT_WRITE, frame.map_flags);
+ EXPECT_EQ(0U, frame.map_load_bias);
+ EXPECT_EQ("Frame0", frame.function_name);
+ EXPECT_EQ(10U, frame.function_offset);
+}
+
+TEST_F(UnwinderTest, build_frame_pc_in_jit) {
+ // Create the elf data for the jit debug information.
+ Elf32_Ehdr ehdr = {};
+ TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
+ ehdr.e_phoff = 0x50;
+ ehdr.e_phnum = 1;
+ ehdr.e_phentsize = sizeof(Elf32_Phdr);
+ ehdr.e_shoff = 0x100;
+ ehdr.e_shstrndx = 1;
+ ehdr.e_shentsize = sizeof(Elf32_Shdr);
+ ehdr.e_shnum = 3;
+ memory_->SetMemory(0xf7000, &ehdr, sizeof(ehdr));
+
+ Elf32_Phdr phdr = {};
+ phdr.p_flags = PF_X;
+ phdr.p_type = PT_LOAD;
+ phdr.p_offset = 0x100000;
+ phdr.p_vaddr = 0x100000;
+ phdr.p_memsz = 0x1000;
+ memory_->SetMemory(0xf7050, &phdr, sizeof(phdr));
+
+ Elf32_Shdr shdr = {};
+ shdr.sh_type = SHT_NULL;
+ memory_->SetMemory(0xf7100, &shdr, sizeof(shdr));
+
+ shdr.sh_type = SHT_SYMTAB;
+ shdr.sh_link = 2;
+ shdr.sh_addr = 0x300;
+ shdr.sh_offset = 0x300;
+ shdr.sh_entsize = sizeof(Elf32_Sym);
+ shdr.sh_size = shdr.sh_entsize;
+ memory_->SetMemory(0xf7100 + sizeof(shdr), &shdr, sizeof(shdr));
+
+ memset(&shdr, 0, sizeof(shdr));
+ shdr.sh_type = SHT_STRTAB;
+ shdr.sh_name = 0x500;
+ shdr.sh_offset = 0x400;
+ shdr.sh_size = 0x100;
+ memory_->SetMemory(0xf7100 + 2 * sizeof(shdr), &shdr, sizeof(shdr));
+
+ Elf32_Sym sym = {};
+ sym.st_shndx = 2;
+ sym.st_info = STT_FUNC;
+ sym.st_value = 0x100300;
+ sym.st_size = 0x100;
+ memory_->SetMemory(0xf7300, &sym, sizeof(sym));
+ memory_->SetMemory(0xf7400, "FakeJitFunction");
+
+ RegsFake regs(10);
+ regs.FakeSetArch(ARCH_ARM);
+ JitDebug jit_debug(process_memory_);
+ Unwinder unwinder(10, maps_.get(), &regs, process_memory_);
+ unwinder.SetJitDebug(&jit_debug, ARCH_ARM);
+
+ FrameData frame = unwinder.BuildFrameFromPcOnly(0x100310);
+ EXPECT_EQ(0x10030eU, frame.pc);
+ EXPECT_EQ(0x60eU, frame.rel_pc);
+ EXPECT_EQ("/fake/jit.so", frame.map_name);
+ EXPECT_EQ(0x100U, frame.map_elf_start_offset);
+ EXPECT_EQ(0x200U, frame.map_exact_offset);
+ EXPECT_EQ(0x100000U, frame.map_start);
+ EXPECT_EQ(0x101000U, frame.map_end);
+ EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame.map_flags);
+ EXPECT_EQ(0U, frame.map_load_bias);
+ EXPECT_EQ("FakeJitFunction", frame.function_name);
+ EXPECT_EQ(0xeU, frame.function_offset);
+}
+
} // namespace unwindstack
diff --git a/libunwindstack/tests/fuzz/UnwinderComponentCreator.cpp b/libunwindstack/tests/fuzz/UnwinderComponentCreator.cpp
index 94f5a73cd..9c5374a5b 100644
--- a/libunwindstack/tests/fuzz/UnwinderComponentCreator.cpp
+++ b/libunwindstack/tests/fuzz/UnwinderComponentCreator.cpp
@@ -16,6 +16,11 @@
#include "UnwinderComponentCreator.h"
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
std::unique_ptr<Regs> GetRegisters(ArchEnum arch) {
switch (arch) {
case unwindstack::ARCH_ARM: {
@@ -109,13 +114,35 @@ ElfFake* PopulateElfFake(FuzzedDataProvider* data_provider) {
return elf;
}
+static constexpr size_t kPageSize = 4096;
+
+static constexpr uint64_t AlignToPage(uint64_t address) {
+ return (address + kPageSize - 1) & ~(kPageSize - 1);
+}
+
std::unique_ptr<Maps> GetMaps(FuzzedDataProvider* data_provider) {
std::unique_ptr<Maps> maps = std::make_unique<Maps>();
+ std::map<uint64_t, uint64_t> map_ends;
uint8_t entry_count = data_provider->ConsumeIntegralInRange<uint8_t>(0, kMaxMapEntryCount);
for (uint8_t i = 0; i < entry_count; i++) {
- uint64_t start = data_provider->ConsumeIntegral<uint64_t>();
- uint64_t end = data_provider->ConsumeIntegralInRange<uint64_t>(start, UINT64_MAX);
- uint64_t offset = data_provider->ConsumeIntegral<uint64_t>();
+ uint64_t start = AlignToPage(data_provider->ConsumeIntegral<uint64_t>());
+ uint64_t end = AlignToPage(data_provider->ConsumeIntegralInRange<uint64_t>(start, UINT64_MAX));
+ if (start == end) {
+ // It's impossible to see start == end in the real world, so
+ // make sure the map contains at least one page of data.
+ if (__builtin_add_overflow(end, 0x1000, &end)) {
+ continue;
+ }
+ }
+ // Make sure not to add overlapping maps, that is not something that can
+ // happen in the real world.
+ auto entry = map_ends.upper_bound(start);
+ if (entry != map_ends.end() && end > entry->second) {
+ continue;
+ }
+ map_ends[end] = start;
+
+ uint64_t offset = AlignToPage(data_provider->ConsumeIntegral<uint64_t>());
std::string map_info_name = data_provider->ConsumeRandomLengthString(kMaxMapInfoNameLen);
uint8_t flags = PROT_READ | PROT_WRITE;