TEST(MinidumpFile, getModuleList) { std::vector<uint8_t> OneModule{ // Header 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version 1, 0, 0, 0, // NumberOfStreams, 32, 0, 0, 0, // StreamDirectoryRVA 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp 0, 0, 0, 0, 0, 0, 0, 0, // Flags // Stream Directory 4, 0, 0, 0, 112, 0, 0, 0, // Type, DataSize, 44, 0, 0, 0, // RVA // ModuleList 1, 0, 0, 0, // NumberOfModules 1, 2, 3, 4, 5, 6, 7, 8, // BaseOfImage 9, 0, 1, 2, 3, 4, 5, 6, // SizeOfImage, Checksum 7, 8, 9, 0, 1, 2, 3, 4, // TimeDateStamp, ModuleNameRVA 0, 0, 0, 0, 0, 0, 0, 0, // Signature, StructVersion 0, 0, 0, 0, 0, 0, 0, 0, // FileVersion 0, 0, 0, 0, 0, 0, 0, 0, // ProductVersion 0, 0, 0, 0, 0, 0, 0, 0, // FileFlagsMask, FileFlags 0, 0, 0, 0, // FileOS 0, 0, 0, 0, 0, 0, 0, 0, // FileType, FileSubType 0, 0, 0, 0, 0, 0, 0, 0, // FileDate 1, 2, 3, 4, 5, 6, 7, 8, // CvRecord 9, 0, 1, 2, 3, 4, 5, 6, // MiscRecord 7, 8, 9, 0, 1, 2, 3, 4, // Reserved0 5, 6, 7, 8, 9, 0, 1, 2, // Reserved1 }; // Same as before, but with a padded module list. std::vector<uint8_t> PaddedModule{ // Header 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version 1, 0, 0, 0, // NumberOfStreams, 32, 0, 0, 0, // StreamDirectoryRVA 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp 0, 0, 0, 0, 0, 0, 0, 0, // Flags // Stream Directory 4, 0, 0, 0, 116, 0, 0, 0, // Type, DataSize, 44, 0, 0, 0, // RVA // ModuleList 1, 0, 0, 0, // NumberOfModules 0, 0, 0, 0, // Padding 1, 2, 3, 4, 5, 6, 7, 8, // BaseOfImage 9, 0, 1, 2, 3, 4, 5, 6, // SizeOfImage, Checksum 7, 8, 9, 0, 1, 2, 3, 4, // TimeDateStamp, ModuleNameRVA 0, 0, 0, 0, 0, 0, 0, 0, // Signature, StructVersion 0, 0, 0, 0, 0, 0, 0, 0, // FileVersion 0, 0, 0, 0, 0, 0, 0, 0, // ProductVersion 0, 0, 0, 0, 0, 0, 0, 0, // FileFlagsMask, FileFlags 0, 0, 0, 0, // FileOS 0, 0, 0, 0, 0, 0, 0, 0, // FileType, FileSubType 0, 0, 0, 0, 0, 0, 0, 0, // FileDate 1, 2, 3, 4, 5, 6, 7, 8, // CvRecord 9, 0, 1, 2, 3, 4, 5, 6, // MiscRecord 7, 8, 9, 0, 1, 2, 3, 4, // Reserved0 5, 6, 7, 8, 9, 0, 1, 2, // Reserved1 }; for (const std::vector<uint8_t> &Data : {OneModule, PaddedModule}) { auto ExpectedFile = create(Data); ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded()); const MinidumpFile &File = **ExpectedFile; Expected<ArrayRef<Module>> ExpectedModule = File.getModuleList(); ASSERT_THAT_EXPECTED(ExpectedModule, Succeeded()); ASSERT_EQ(1u, ExpectedModule->size()); const Module &M = ExpectedModule.get()[0]; EXPECT_EQ(0x0807060504030201u, M.BaseOfImage); EXPECT_EQ(0x02010009u, M.SizeOfImage); EXPECT_EQ(0x06050403u, M.Checksum); EXPECT_EQ(0x00090807u, M.TimeDateStamp); EXPECT_EQ(0x04030201u, M.ModuleNameRVA); EXPECT_EQ(0x04030201u, M.CvRecord.DataSize); EXPECT_EQ(0x08070605u, M.CvRecord.RVA); EXPECT_EQ(0x02010009u, M.MiscRecord.DataSize); EXPECT_EQ(0x06050403u, M.MiscRecord.RVA); EXPECT_EQ(0x0403020100090807u, M.Reserved0); EXPECT_EQ(0x0201000908070605u, M.Reserved1); } std::vector<uint8_t> StreamTooShort{ // Header 'M', 'D', 'M', 'P', 0x93, 0xa7, 0, 0, // Signature, Version 1, 0, 0, 0, // NumberOfStreams, 32, 0, 0, 0, // StreamDirectoryRVA 0, 1, 2, 3, 4, 5, 6, 7, // Checksum, TimeDateStamp 0, 0, 0, 0, 0, 0, 0, 0, // Flags // Stream Directory 4, 0, 0, 0, 111, 0, 0, 0, // Type, DataSize, 44, 0, 0, 0, // RVA // ModuleList 1, 0, 0, 0, // NumberOfModules 1, 2, 3, 4, 5, 6, 7, 8, // BaseOfImage 9, 0, 1, 2, 3, 4, 5, 6, // SizeOfImage, Checksum 7, 8, 9, 0, 1, 2, 3, 4, // TimeDateStamp, ModuleNameRVA 0, 0, 0, 0, 0, 0, 0, 0, // Signature, StructVersion 0, 0, 0, 0, 0, 0, 0, 0, // FileVersion 0, 0, 0, 0, 0, 0, 0, 0, // ProductVersion 0, 0, 0, 0, 0, 0, 0, 0, // FileFlagsMask, FileFlags 0, 0, 0, 0, // FileOS 0, 0, 0, 0, 0, 0, 0, 0, // FileType, FileSubType 0, 0, 0, 0, 0, 0, 0, 0, // FileDate 1, 2, 3, 4, 5, 6, 7, 8, // CvRecord 9, 0, 1, 2, 3, 4, 5, 6, // MiscRecord 7, 8, 9, 0, 1, 2, 3, 4, // Reserved0 5, 6, 7, 8, 9, 0, 1, 2, // Reserved1 }; auto ExpectedFile = create(StreamTooShort); ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded()); const MinidumpFile &File = **ExpectedFile; EXPECT_THAT_EXPECTED(File.getModuleList(), Failed<BinaryError>()); }
Expected<std::vector<typename ELFT::Rela>> ELFFile<ELFT>::android_relas(const Elf_Shdr *Sec) const { // This function reads relocations in Android's packed relocation format, // which is based on SLEB128 and delta encoding. Expected<ArrayRef<uint8_t>> ContentsOrErr = getSectionContents(Sec); if (!ContentsOrErr) return ContentsOrErr.takeError(); const uint8_t *Cur = ContentsOrErr->begin(); const uint8_t *End = ContentsOrErr->end(); if (ContentsOrErr->size() < 4 || Cur[0] != 'A' || Cur[1] != 'P' || Cur[2] != 'S' || Cur[3] != '2') return createError("invalid packed relocation header"); Cur += 4; const char *ErrStr = nullptr; auto ReadSLEB = [&]() -> int64_t { if (ErrStr) return 0; unsigned Len; int64_t Result = decodeSLEB128(Cur, &Len, End, &ErrStr); Cur += Len; return Result; }; uint64_t NumRelocs = ReadSLEB(); uint64_t Offset = ReadSLEB(); uint64_t Addend = 0; if (ErrStr) return createError(ErrStr); std::vector<Elf_Rela> Relocs; Relocs.reserve(NumRelocs); while (NumRelocs) { uint64_t NumRelocsInGroup = ReadSLEB(); if (NumRelocsInGroup > NumRelocs) return createError("relocation group unexpectedly large"); NumRelocs -= NumRelocsInGroup; uint64_t GroupFlags = ReadSLEB(); bool GroupedByInfo = GroupFlags & ELF::RELOCATION_GROUPED_BY_INFO_FLAG; bool GroupedByOffsetDelta = GroupFlags & ELF::RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG; bool GroupedByAddend = GroupFlags & ELF::RELOCATION_GROUPED_BY_ADDEND_FLAG; bool GroupHasAddend = GroupFlags & ELF::RELOCATION_GROUP_HAS_ADDEND_FLAG; uint64_t GroupOffsetDelta; if (GroupedByOffsetDelta) GroupOffsetDelta = ReadSLEB(); uint64_t GroupRInfo; if (GroupedByInfo) GroupRInfo = ReadSLEB(); if (GroupedByAddend && GroupHasAddend) Addend += ReadSLEB(); if (!GroupHasAddend) Addend = 0; for (uint64_t I = 0; I != NumRelocsInGroup; ++I) { Elf_Rela R; Offset += GroupedByOffsetDelta ? GroupOffsetDelta : ReadSLEB(); R.r_offset = Offset; R.r_info = GroupedByInfo ? GroupRInfo : ReadSLEB(); if (GroupHasAddend && !GroupedByAddend) Addend += ReadSLEB(); R.r_addend = Addend; Relocs.push_back(R); if (ErrStr) return createError(ErrStr); } if (ErrStr) return createError(ErrStr); } return Relocs; }