diff options
Diffstat (limited to 'libunwindstack')
-rw-r--r-- | libunwindstack/DwarfSection.cpp | 24 | ||||
-rw-r--r-- | libunwindstack/RegsX86_64.cpp | 5 | ||||
-rw-r--r-- | libunwindstack/Unwinder.cpp | 28 | ||||
-rw-r--r-- | libunwindstack/include/unwindstack/Error.h | 7 | ||||
-rw-r--r-- | libunwindstack/include/unwindstack/Unwinder.h | 4 | ||||
-rw-r--r-- | libunwindstack/tests/DwarfSectionImplTest.cpp | 35 | ||||
-rw-r--r-- | libunwindstack/tests/RegsFake.h | 18 | ||||
-rw-r--r-- | libunwindstack/tests/UnwinderTest.cpp | 345 | ||||
-rw-r--r-- | libunwindstack/tests/fuzz/UnwinderComponentCreator.cpp | 33 |
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, ®s, &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, ®s, &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, ®s, &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(), ®s_, 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(), ®s_, 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(), ®s_, 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(), ®s_, 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(), ®s_, 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(), ®s_, 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(), ®s_, 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(), ®s_, 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(), ®s_, 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(), ®s_, 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(), ®s_, 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(), ®s_, 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(), ®s_, 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(), ®s_, 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(), ®s_, 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(), ®s_, 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(), ®s_, 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(), ®s_, 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(), ®s_, 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(), ®s_, 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(), ®s_, 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(), ®s_, 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(), ®s_, 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(), ®s_, 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(), ®s, 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(®s); + + // 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(), ®s, 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(), ®s, 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; |