diff options
Diffstat (limited to 'tools/llvm-readobj')
-rw-r--r-- | tools/llvm-readobj/ARMEHABIPrinter.h | 19 | ||||
-rw-r--r-- | tools/llvm-readobj/ARMWinEHPrinter.cpp | 9 | ||||
-rw-r--r-- | tools/llvm-readobj/COFFDumper.cpp | 362 | ||||
-rw-r--r-- | tools/llvm-readobj/DwarfCFIEHPrinter.h | 54 | ||||
-rw-r--r-- | tools/llvm-readobj/ELFDumper.cpp | 1648 | ||||
-rw-r--r-- | tools/llvm-readobj/MachODumper.cpp | 61 | ||||
-rw-r--r-- | tools/llvm-readobj/ObjDumper.cpp | 32 | ||||
-rw-r--r-- | tools/llvm-readobj/ObjDumper.h | 11 | ||||
-rw-r--r-- | tools/llvm-readobj/WasmDumper.cpp | 7 | ||||
-rw-r--r-- | tools/llvm-readobj/Win64EHDumper.cpp | 13 | ||||
-rw-r--r-- | tools/llvm-readobj/WindowsResourceDumper.cpp | 8 | ||||
-rw-r--r-- | tools/llvm-readobj/XCOFFDumper.cpp | 402 | ||||
-rw-r--r-- | tools/llvm-readobj/llvm-readobj.cpp | 148 | ||||
-rw-r--r-- | tools/llvm-readobj/llvm-readobj.h | 25 |
14 files changed, 2048 insertions, 751 deletions
diff --git a/tools/llvm-readobj/ARMEHABIPrinter.h b/tools/llvm-readobj/ARMEHABIPrinter.h index 11f9d6166a59..2c0912038c31 100644 --- a/tools/llvm-readobj/ARMEHABIPrinter.h +++ b/tools/llvm-readobj/ARMEHABIPrinter.h @@ -329,6 +329,7 @@ class PrinterContext { ScopedPrinter &SW; const object::ELFFile<ET> *ELF; + StringRef FileName; const Elf_Shdr *Symtab; ArrayRef<Elf_Word> ShndxTable; @@ -352,8 +353,8 @@ class PrinterContext { public: PrinterContext(ScopedPrinter &SW, const object::ELFFile<ET> *ELF, - const Elf_Shdr *Symtab) - : SW(SW), ELF(ELF), Symtab(Symtab) {} + StringRef FileName, const Elf_Shdr *Symtab) + : SW(SW), ELF(ELF), FileName(FileName), Symtab(Symtab) {} void PrintUnwindInformation() const; }; @@ -369,10 +370,10 @@ PrinterContext<ET>::FunctionAtAddress(unsigned Section, return readobj_error::unknown_symbol; auto StrTableOrErr = ELF->getStringTableForSymtab(*Symtab); if (!StrTableOrErr) - error(StrTableOrErr.takeError()); + reportError(StrTableOrErr.takeError(), FileName); StringRef StrTable = *StrTableOrErr; - for (const Elf_Sym &Sym : unwrapOrError(ELF->symbols(Symtab))) + for (const Elf_Sym &Sym : unwrapOrError(FileName, ELF->symbols(Symtab))) if (Sym.st_shndx == Section && Sym.st_value == Address && Sym.getType() == ELF::STT_FUNC) { auto NameOrErr = Sym.getName(StrTable); @@ -398,16 +399,16 @@ PrinterContext<ET>::FindExceptionTable(unsigned IndexSectionIndex, /// handling table. Use this symbol to recover the actual exception handling /// table. - for (const Elf_Shdr &Sec : unwrapOrError(ELF->sections())) { + for (const Elf_Shdr &Sec : unwrapOrError(FileName, ELF->sections())) { if (Sec.sh_type != ELF::SHT_REL || Sec.sh_info != IndexSectionIndex) continue; auto SymTabOrErr = ELF->getSection(Sec.sh_link); if (!SymTabOrErr) - error(SymTabOrErr.takeError()); + reportError(SymTabOrErr.takeError(), FileName); const Elf_Shdr *SymTab = *SymTabOrErr; - for (const Elf_Rel &R : unwrapOrError(ELF->rels(&Sec))) { + for (const Elf_Rel &R : unwrapOrError(FileName, ELF->rels(&Sec))) { if (R.r_offset != static_cast<unsigned>(IndexTableOffset)) continue; @@ -417,7 +418,7 @@ PrinterContext<ET>::FindExceptionTable(unsigned IndexSectionIndex, RelA.r_addend = 0; const Elf_Sym *Symbol = - unwrapOrError(ELF->getRelocationSymbol(&RelA, SymTab)); + unwrapOrError(FileName, ELF->getRelocationSymbol(&RelA, SymTab)); auto Ret = ELF->getSection(Symbol, SymTab, ShndxTable); if (!Ret) @@ -570,7 +571,7 @@ void PrinterContext<ET>::PrintUnwindInformation() const { DictScope UI(SW, "UnwindInformation"); int SectionIndex = 0; - for (const Elf_Shdr &Sec : unwrapOrError(ELF->sections())) { + for (const Elf_Shdr &Sec : unwrapOrError(FileName, ELF->sections())) { if (Sec.sh_type == ELF::SHT_ARM_EXIDX) { DictScope UIT(SW, "UnwindIndexTable"); diff --git a/tools/llvm-readobj/ARMWinEHPrinter.cpp b/tools/llvm-readobj/ARMWinEHPrinter.cpp index 4de14e2e78d5..3e026f58871b 100644 --- a/tools/llvm-readobj/ARMWinEHPrinter.cpp +++ b/tools/llvm-readobj/ARMWinEHPrinter.cpp @@ -842,8 +842,10 @@ bool Decoder::dumpXDataRecord(const COFFObjectFile &COFF, if ((int64_t)(Contents.size() - Offset - 4 * HeaderWords(XData) - (XData.E() ? 0 : XData.EpilogueCount() * 4) - - (XData.X() ? 8 : 0)) < (int64_t)ByteCodeLength) + (XData.X() ? 8 : 0)) < (int64_t)ByteCodeLength) { + SW.flush(); report_fatal_error("Malformed unwind data"); + } if (XData.E()) { ArrayRef<uint8_t> UC = XData.UnwindByteCode(); @@ -1039,10 +1041,7 @@ bool Decoder::dumpPackedEntry(const object::COFFObjectFile &COFF, } FunctionAddress = *FunctionAddressOrErr; } else { - const pe32_header *PEHeader; - if (COFF.getPE32Header(PEHeader)) - return false; - FunctionAddress = PEHeader->ImageBase + RF.BeginAddress; + FunctionAddress = COFF.getPE32Header()->ImageBase + RF.BeginAddress; } SW.printString("Function", formatSymbol(FunctionName, FunctionAddress)); diff --git a/tools/llvm-readobj/COFFDumper.cpp b/tools/llvm-readobj/COFFDumper.cpp index 4c2e39dfa3cc..9b2c6adb9d93 100644 --- a/tools/llvm-readobj/COFFDumper.cpp +++ b/tools/llvm-readobj/COFFDumper.cpp @@ -60,6 +60,10 @@ using namespace llvm::codeview; using namespace llvm::support; using namespace llvm::Win64EH; +static inline Error createError(const Twine &Err) { + return make_error<StringError>(Err, object_error::parse_failed); +} + namespace { struct LoadConfigTables { @@ -167,9 +171,6 @@ private: void printDelayImportedSymbols( const DelayImportDirectoryEntryRef &I, iterator_range<imported_symbol_iterator> Range); - ErrorOr<const coff_resource_dir_entry &> - getResourceDirectoryTableEntry(const coff_resource_dir_table &Table, - uint32_t Index); typedef DenseMap<const coff_section*, std::vector<RelocationRef> > RelocMapTy; @@ -627,14 +628,10 @@ void COFFDumper::printFileHeaders() { // Print PE header. This header does not exist if this is an object file and // not an executable. - const pe32_header *PEHeader = nullptr; - error(Obj->getPE32Header(PEHeader)); - if (PEHeader) + if (const pe32_header *PEHeader = Obj->getPE32Header()) printPEHeader<pe32_header>(PEHeader); - const pe32plus_header *PEPlusHeader = nullptr; - error(Obj->getPE32PlusHeader(PEPlusHeader)); - if (PEPlusHeader) + if (const pe32plus_header *PEPlusHeader = Obj->getPE32PlusHeader()) printPEHeader<pe32plus_header>(PEPlusHeader); if (const dos_header *DH = Obj->getDOSHeader()) @@ -728,7 +725,9 @@ void COFFDumper::printCOFFDebugDirectory() { if (D.Type == COFF::IMAGE_DEBUG_TYPE_CODEVIEW) { const codeview::DebugInfo *DebugInfo; StringRef PDBFileName; - error(Obj->getDebugPDBInfo(&D, DebugInfo, PDBFileName)); + if (std::error_code EC = Obj->getDebugPDBInfo(&D, DebugInfo, PDBFileName)) + reportError(errorCodeToError(EC), Obj->getFileName()); + DictScope PDBScope(W, "PDBInfo"); W.printHex("PDBSignature", DebugInfo->Signature.CVSignature); if (DebugInfo->Signature.CVSignature == OMF::Signature::PDB70) { @@ -740,8 +739,9 @@ void COFFDumper::printCOFFDebugDirectory() { // FIXME: Type values of 12 and 13 are commonly observed but are not in // the documented type enum. Figure out what they mean. ArrayRef<uint8_t> RawData; - error( - Obj->getRvaAndSizeAsBytes(D.AddressOfRawData, D.SizeOfData, RawData)); + if (std::error_code EC = Obj->getRvaAndSizeAsBytes(D.AddressOfRawData, + D.SizeOfData, RawData)) + reportError(errorCodeToError(EC), Obj->getFileName()); W.printBinaryBlock("RawData", RawData); } } @@ -750,8 +750,11 @@ void COFFDumper::printCOFFDebugDirectory() { void COFFDumper::printRVATable(uint64_t TableVA, uint64_t Count, uint64_t EntrySize, PrintExtraCB PrintExtra) { uintptr_t TableStart, TableEnd; - error(Obj->getVaPtr(TableVA, TableStart)); - error(Obj->getVaPtr(TableVA + Count * EntrySize - 1, TableEnd)); + if (std::error_code EC = Obj->getVaPtr(TableVA, TableStart)) + reportError(errorCodeToError(EC), Obj->getFileName()); + if (std::error_code EC = + Obj->getVaPtr(TableVA + Count * EntrySize - 1, TableEnd)) + reportError(errorCodeToError(EC), Obj->getFileName()); TableEnd++; for (uintptr_t I = TableStart; I < TableEnd; I += EntrySize) { uint32_t RVA = *reinterpret_cast<const ulittle32_t *>(I); @@ -887,16 +890,14 @@ void COFFDumper::printBaseOfDataField(const pe32plus_header *) {} void COFFDumper::printCodeViewDebugInfo() { // Print types first to build CVUDTNames, then print symbols. for (const SectionRef &S : Obj->sections()) { - StringRef SectionName; - error(S.getName(SectionName)); + StringRef SectionName = unwrapOrError(Obj->getFileName(), S.getName()); // .debug$T is a standard CodeView type section, while .debug$P is the same // format but used for MSVC precompiled header object files. if (SectionName == ".debug$T" || SectionName == ".debug$P") printCodeViewTypeSection(SectionName, S); } for (const SectionRef &S : Obj->sections()) { - StringRef SectionName; - error(S.getName(SectionName)); + StringRef SectionName = unwrapOrError(Obj->getFileName(), S.getName()); if (SectionName == ".debug$S") printCodeViewSymbolSection(SectionName, S); } @@ -908,32 +909,40 @@ void COFFDumper::initializeFileAndStringTables(BinaryStreamReader &Reader) { // The section consists of a number of subsection in the following format: // |SubSectionType|SubSectionSize|Contents...| uint32_t SubType, SubSectionSize; - error(Reader.readInteger(SubType)); - error(Reader.readInteger(SubSectionSize)); + + if (Error E = Reader.readInteger(SubType)) + reportError(std::move(E), Obj->getFileName()); + if (Error E = Reader.readInteger(SubSectionSize)) + reportError(std::move(E), Obj->getFileName()); StringRef Contents; - error(Reader.readFixedString(Contents, SubSectionSize)); + if (Error E = Reader.readFixedString(Contents, SubSectionSize)) + reportError(std::move(E), Obj->getFileName()); BinaryStreamRef ST(Contents, support::little); switch (DebugSubsectionKind(SubType)) { case DebugSubsectionKind::FileChecksums: - error(CVFileChecksumTable.initialize(ST)); + if (Error E = CVFileChecksumTable.initialize(ST)) + reportError(std::move(E), Obj->getFileName()); break; case DebugSubsectionKind::StringTable: - error(CVStringTable.initialize(ST)); + if (Error E = CVStringTable.initialize(ST)) + reportError(std::move(E), Obj->getFileName()); break; default: break; } uint32_t PaddedSize = alignTo(SubSectionSize, 4); - error(Reader.skip(PaddedSize - SubSectionSize)); + if (Error E = Reader.skip(PaddedSize - SubSectionSize)) + reportError(std::move(E), Obj->getFileName()); } } void COFFDumper::printCodeViewSymbolSection(StringRef SectionName, const SectionRef &Section) { - StringRef SectionContents = unwrapOrError(Section.getContents()); + StringRef SectionContents = + unwrapOrError(Obj->getFileName(), Section.getContents()); StringRef Data = SectionContents; SmallVector<StringRef, 10> FunctionNames; @@ -944,10 +953,13 @@ void COFFDumper::printCodeViewSymbolSection(StringRef SectionName, W.printNumber("Section", SectionName, Obj->getSectionID(Section)); uint32_t Magic; - error(consume(Data, Magic)); + if (Error E = consume(Data, Magic)) + reportError(std::move(E), Obj->getFileName()); + W.printHex("Magic", Magic); if (Magic != COFF::DEBUG_SECTION_MAGIC) - return error(object_error::parse_failed); + reportError(errorCodeToError(object_error::parse_failed), + Obj->getFileName()); BinaryStreamReader FSReader(Data, support::little); initializeFileAndStringTables(FSReader); @@ -957,8 +969,10 @@ void COFFDumper::printCodeViewSymbolSection(StringRef SectionName, // The section consists of a number of subsection in the following format: // |SubSectionType|SubSectionSize|Contents...| uint32_t SubType, SubSectionSize; - error(consume(Data, SubType)); - error(consume(Data, SubSectionSize)); + if (Error E = consume(Data, SubType)) + reportError(std::move(E), Obj->getFileName()); + if (Error E = consume(Data, SubSectionSize)) + reportError(std::move(E), Obj->getFileName()); ListScope S(W, "Subsection"); // Dump the subsection as normal even if the ignore bit is set. @@ -971,7 +985,8 @@ void COFFDumper::printCodeViewSymbolSection(StringRef SectionName, // Get the contents of the subsection. if (SubSectionSize > Data.size()) - return error(object_error::parse_failed); + return reportError(errorCodeToError(object_error::parse_failed), + Obj->getFileName()); StringRef Contents = Data.substr(0, SubSectionSize); // Add SubSectionSize to the current offset and align that offset to find @@ -980,7 +995,8 @@ void COFFDumper::printCodeViewSymbolSection(StringRef SectionName, size_t NextOffset = SectionOffset + SubSectionSize; NextOffset = alignTo(NextOffset, 4); if (NextOffset > SectionContents.size()) - return error(object_error::parse_failed); + return reportError(errorCodeToError(object_error::parse_failed), + Obj->getFileName()); Data = SectionContents.drop_front(NextOffset); // Optionally print the subsection bytes in case our parsing gets confused @@ -1010,17 +1026,21 @@ void COFFDumper::printCodeViewSymbolSection(StringRef SectionName, if (SubSectionSize < 12) { // There should be at least three words to store two function // relocations and size of the code. - error(object_error::parse_failed); + reportError(errorCodeToError(object_error::parse_failed), + Obj->getFileName()); return; } StringRef LinkageName; - error(resolveSymbolName(Obj->getCOFFSection(Section), SectionOffset, - LinkageName)); + if (std::error_code EC = resolveSymbolName(Obj->getCOFFSection(Section), + SectionOffset, LinkageName)) + reportError(errorCodeToError(EC), Obj->getFileName()); + W.printString("LinkageName", LinkageName); if (FunctionLineTables.count(LinkageName) != 0) { // Saw debug info for this function already? - error(object_error::parse_failed); + reportError(errorCodeToError(object_error::parse_failed), + Obj->getFileName()); return; } @@ -1033,17 +1053,21 @@ void COFFDumper::printCodeViewSymbolSection(StringRef SectionName, BinaryStreamReader SR(Contents, llvm::support::little); DebugFrameDataSubsectionRef FrameData; - error(FrameData.initialize(SR)); + if (Error E = FrameData.initialize(SR)) + reportError(std::move(E), Obj->getFileName()); StringRef LinkageName; - error(resolveSymbolName(Obj->getCOFFSection(Section), SectionContents, - FrameData.getRelocPtr(), LinkageName)); + if (std::error_code EC = + resolveSymbolName(Obj->getCOFFSection(Section), SectionContents, + FrameData.getRelocPtr(), LinkageName)) + reportError(errorCodeToError(EC), Obj->getFileName()); W.printString("LinkageName", LinkageName); // To find the active frame description, search this array for the // smallest PC range that includes the current PC. for (const auto &FD : FrameData) { - StringRef FrameFunc = error(CVStringTable.getString(FD.FrameFunc)); + StringRef FrameFunc = unwrapOrError( + Obj->getFileName(), CVStringTable.getString(FD.FrameFunc)); DictScope S(W, "FrameData"); W.printHex("RvaStart", FD.RvaStart); @@ -1094,7 +1118,8 @@ void COFFDumper::printCodeViewSymbolSection(StringRef SectionName, BinaryStreamReader Reader(FunctionLineTables[Name], support::little); DebugLinesSubsectionRef LineInfo; - error(LineInfo.initialize(Reader)); + if (Error E = LineInfo.initialize(Reader)) + reportError(std::move(E), Obj->getFileName()); W.printHex("Flags", LineInfo.header()->Flags); W.printHex("CodeSize", LineInfo.header()->CodeSize); @@ -1105,7 +1130,8 @@ void COFFDumper::printCodeViewSymbolSection(StringRef SectionName, uint32_t ColumnIndex = 0; for (const auto &Line : Entry.LineNumbers) { if (Line.Offset >= LineInfo.header()->CodeSize) { - error(object_error::parse_failed); + reportError(errorCodeToError(object_error::parse_failed), + Obj->getFileName()); return; } @@ -1136,21 +1162,20 @@ void COFFDumper::printCodeViewSymbolsSubsection(StringRef Subsection, StringRef SectionContents) { ArrayRef<uint8_t> BinaryData(Subsection.bytes_begin(), Subsection.bytes_end()); - auto CODD = llvm::make_unique<COFFObjectDumpDelegate>(*this, Section, Obj, + auto CODD = std::make_unique<COFFObjectDumpDelegate>(*this, Section, Obj, SectionContents); CVSymbolDumper CVSD(W, Types, CodeViewContainer::ObjectFile, std::move(CODD), CompilationCPUType, opts::CodeViewSubsectionBytes); CVSymbolArray Symbols; BinaryStreamReader Reader(BinaryData, llvm::support::little); - if (auto EC = Reader.readArray(Symbols, Reader.getLength())) { - consumeError(std::move(EC)); + if (Error E = Reader.readArray(Symbols, Reader.getLength())) { W.flush(); - error(object_error::parse_failed); + reportError(std::move(E), Obj->getFileName()); } - if (auto EC = CVSD.dump(Symbols)) { + if (Error E = CVSD.dump(Symbols)) { W.flush(); - error(std::move(EC)); + reportError(std::move(E), Obj->getFileName()); } CompilationCPUType = CVSD.getCompilationCPUType(); W.flush(); @@ -1159,12 +1184,14 @@ void COFFDumper::printCodeViewSymbolsSubsection(StringRef Subsection, void COFFDumper::printCodeViewFileChecksums(StringRef Subsection) { BinaryStreamRef Stream(Subsection, llvm::support::little); DebugChecksumsSubsectionRef Checksums; - error(Checksums.initialize(Stream)); + if (Error E = Checksums.initialize(Stream)) + reportError(std::move(E), Obj->getFileName()); for (auto &FC : Checksums) { DictScope S(W, "FileChecksum"); - StringRef Filename = error(CVStringTable.getString(FC.FileNameOffset)); + StringRef Filename = unwrapOrError( + Obj->getFileName(), CVStringTable.getString(FC.FileNameOffset)); W.printHex("Filename", Filename, FC.FileNameOffset); W.printHex("ChecksumSize", FC.Checksum.size()); W.printEnum("ChecksumKind", uint8_t(FC.Kind), @@ -1177,7 +1204,8 @@ void COFFDumper::printCodeViewFileChecksums(StringRef Subsection) { void COFFDumper::printCodeViewInlineeLines(StringRef Subsection) { BinaryStreamReader SR(Subsection, llvm::support::little); DebugInlineeLinesSubsectionRef Lines; - error(Lines.initialize(SR)); + if (Error E = Lines.initialize(SR)) + reportError(std::move(E), Obj->getFileName()); for (auto &Line : Lines) { DictScope S(W, "InlineeSourceLine"); @@ -1198,15 +1226,18 @@ void COFFDumper::printCodeViewInlineeLines(StringRef Subsection) { StringRef COFFDumper::getFileNameForFileOffset(uint32_t FileOffset) { // The file checksum subsection should precede all references to it. if (!CVFileChecksumTable.valid() || !CVStringTable.valid()) - error(object_error::parse_failed); + reportError(errorCodeToError(object_error::parse_failed), + Obj->getFileName()); auto Iter = CVFileChecksumTable.getArray().at(FileOffset); // Check if the file checksum table offset is valid. if (Iter == CVFileChecksumTable.end()) - error(object_error::parse_failed); + reportError(errorCodeToError(object_error::parse_failed), + Obj->getFileName()); - return error(CVStringTable.getString(Iter->FileNameOffset)); + return unwrapOrError(Obj->getFileName(), + CVStringTable.getString(Iter->FileNameOffset)); } void COFFDumper::printFileNameForOffset(StringRef Label, uint32_t FileOffset) { @@ -1219,35 +1250,38 @@ void COFFDumper::mergeCodeViewTypes(MergingTypeTableBuilder &CVIDs, GlobalTypeTableBuilder &GlobalCVTypes, bool GHash) { for (const SectionRef &S : Obj->sections()) { - StringRef SectionName; - error(S.getName(SectionName)); + StringRef SectionName = unwrapOrError(Obj->getFileName(), S.getName()); if (SectionName == ".debug$T") { - StringRef Data = unwrapOrError(S.getContents()); + StringRef Data = unwrapOrError(Obj->getFileName(), S.getContents()); uint32_t Magic; - error(consume(Data, Magic)); + if (Error E = consume(Data, Magic)) + reportError(std::move(E), Obj->getFileName()); + if (Magic != 4) - error(object_error::parse_failed); + reportError(errorCodeToError(object_error::parse_failed), + Obj->getFileName()); CVTypeArray Types; BinaryStreamReader Reader(Data, llvm::support::little); if (auto EC = Reader.readArray(Types, Reader.getLength())) { consumeError(std::move(EC)); W.flush(); - error(object_error::parse_failed); + reportError(errorCodeToError(object_error::parse_failed), + Obj->getFileName()); } SmallVector<TypeIndex, 128> SourceToDest; Optional<uint32_t> PCHSignature; if (GHash) { std::vector<GloballyHashedType> Hashes = GloballyHashedType::hashTypes(Types); - if (auto EC = + if (Error E = mergeTypeAndIdRecords(GlobalCVIDs, GlobalCVTypes, SourceToDest, Types, Hashes, PCHSignature)) - return error(std::move(EC)); + return reportError(std::move(E), Obj->getFileName()); } else { - if (auto EC = mergeTypeAndIdRecords(CVIDs, CVTypes, SourceToDest, Types, + if (Error E = mergeTypeAndIdRecords(CVIDs, CVTypes, SourceToDest, Types, PCHSignature)) - return error(std::move(EC)); + return reportError(std::move(E), Obj->getFileName()); } } } @@ -1258,20 +1292,25 @@ void COFFDumper::printCodeViewTypeSection(StringRef SectionName, ListScope D(W, "CodeViewTypes"); W.printNumber("Section", SectionName, Obj->getSectionID(Section)); - StringRef Data = unwrapOrError(Section.getContents()); + StringRef Data = unwrapOrError(Obj->getFileName(), Section.getContents()); if (opts::CodeViewSubsectionBytes) W.printBinaryBlock("Data", Data); uint32_t Magic; - error(consume(Data, Magic)); + if (Error E = consume(Data, Magic)) + reportError(std::move(E), Obj->getFileName()); + W.printHex("Magic", Magic); if (Magic != COFF::DEBUG_SECTION_MAGIC) - return error(object_error::parse_failed); + reportError(errorCodeToError(object_error::parse_failed), + Obj->getFileName()); Types.reset(Data, 100); TypeDumpVisitor TDV(Types, &W, opts::CodeViewSubsectionBytes); - error(codeview::visitTypeStream(Types, TDV)); + if (Error E = codeview::visitTypeStream(Types, TDV)) + reportError(std::move(E), Obj->getFileName()); + W.flush(); } @@ -1282,8 +1321,7 @@ void COFFDumper::printSectionHeaders() { ++SectionNumber; const coff_section *Section = Obj->getCOFFSection(Sec); - StringRef Name; - error(Sec.getName(Name)); + StringRef Name = unwrapOrError(Obj->getFileName(), Sec.getName()); DictScope D(W, "Section"); W.printNumber("Number", SectionNumber); @@ -1318,7 +1356,7 @@ void COFFDumper::printSectionHeaders() { if (opts::SectionData && !(Section->Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA)) { - StringRef Data = unwrapOrError(Sec.getContents()); + StringRef Data = unwrapOrError(Obj->getFileName(), Sec.getContents()); W.printBinaryBlock("SectionData", Data); } } @@ -1330,8 +1368,7 @@ void COFFDumper::printRelocations() { int SectionNumber = 0; for (const SectionRef &Section : Obj->sections()) { ++SectionNumber; - StringRef Name; - error(Section.getName(Name)); + StringRef Name = unwrapOrError(Obj->getFileName(), Section.getName()); bool PrintedGroup = false; for (const RelocationRef &Reloc : Section.relocations()) { @@ -1362,7 +1399,9 @@ void COFFDumper::printRelocation(const SectionRef &Section, int64_t SymbolIndex = -1; if (Symbol != Obj->symbol_end()) { Expected<StringRef> SymbolNameOrErr = Symbol->getName(); - error(errorToErrorCode(SymbolNameOrErr.takeError())); + if (!SymbolNameOrErr) + reportError(SymbolNameOrErr.takeError(), Obj->getFileName()); + SymbolName = *SymbolNameOrErr; SymbolIndex = Obj->getSymbolIndex(Obj->getCOFFSymbol(*Symbol)); } @@ -1439,7 +1478,8 @@ void COFFDumper::printSymbol(const SymbolRef &Sym) { for (uint8_t I = 0; I < Symbol.getNumberOfAuxSymbols(); ++I) { if (Symbol.isFunctionDefinition()) { const coff_aux_function_definition *Aux; - error(getSymbolAuxData(Obj, Symbol, I, Aux)); + if (std::error_code EC = getSymbolAuxData(Obj, Symbol, I, Aux)) + reportError(errorCodeToError(EC), Obj->getFileName()); DictScope AS(W, "AuxFunctionDef"); W.printNumber("TagIndex", Aux->TagIndex); @@ -1449,15 +1489,16 @@ void COFFDumper::printSymbol(const SymbolRef &Sym) { } else if (Symbol.isAnyUndefined()) { const coff_aux_weak_external *Aux; - error(getSymbolAuxData(Obj, Symbol, I, Aux)); + if (std::error_code EC = getSymbolAuxData(Obj, Symbol, I, Aux)) + reportError(errorCodeToError(EC), Obj->getFileName()); Expected<COFFSymbolRef> Linked = Obj->getSymbol(Aux->TagIndex); + if (!Linked) + reportError(Linked.takeError(), Obj->getFileName()); + StringRef LinkedName; - std::error_code EC = errorToErrorCode(Linked.takeError()); - if (EC || (EC = Obj->getSymbolName(*Linked, LinkedName))) { - LinkedName = ""; - error(EC); - } + if (std::error_code EC = Obj->getSymbolName(*Linked, LinkedName)) + reportError(errorCodeToError(EC), Obj->getFileName()); DictScope AS(W, "AuxWeakExternal"); W.printNumber("Linked", LinkedName, Aux->TagIndex); @@ -1466,8 +1507,8 @@ void COFFDumper::printSymbol(const SymbolRef &Sym) { } else if (Symbol.isFileRecord()) { const char *FileName; - error(getSymbolAuxData(Obj, Symbol, I, FileName)); - + if (std::error_code EC = getSymbolAuxData(Obj, Symbol, I, FileName)) + reportError(errorCodeToError(EC), Obj->getFileName()); DictScope AS(W, "AuxFileRecord"); StringRef Name(FileName, Symbol.getNumberOfAuxSymbols() * @@ -1476,7 +1517,8 @@ void COFFDumper::printSymbol(const SymbolRef &Sym) { break; } else if (Symbol.isSectionDefinition()) { const coff_aux_section_definition *Aux; - error(getSymbolAuxData(Obj, Symbol, I, Aux)); + if (std::error_code EC = getSymbolAuxData(Obj, Symbol, I, Aux)) + reportError(errorCodeToError(EC), Obj->getFileName()); int32_t AuxNumber = Aux->getNumber(Symbol.isBigObj()); @@ -1493,26 +1535,27 @@ void COFFDumper::printSymbol(const SymbolRef &Sym) { const coff_section *Assoc; StringRef AssocName = ""; if (std::error_code EC = Obj->getSection(AuxNumber, Assoc)) - error(EC); + reportError(errorCodeToError(EC), Obj->getFileName()); Expected<StringRef> Res = getSectionName(Obj, AuxNumber, Assoc); if (!Res) - error(Res.takeError()); + reportError(Res.takeError(), Obj->getFileName()); AssocName = *Res; W.printNumber("AssocSection", AssocName, AuxNumber); } } else if (Symbol.isCLRToken()) { const coff_aux_clr_token *Aux; - error(getSymbolAuxData(Obj, Symbol, I, Aux)); + if (std::error_code EC = getSymbolAuxData(Obj, Symbol, I, Aux)) + reportError(errorCodeToError(EC), Obj->getFileName()); Expected<COFFSymbolRef> ReferredSym = Obj->getSymbol(Aux->SymbolTableIndex); + if (!ReferredSym) + reportError(ReferredSym.takeError(), Obj->getFileName()); + StringRef ReferredName; - std::error_code EC = errorToErrorCode(ReferredSym.takeError()); - if (EC || (EC = Obj->getSymbolName(*ReferredSym, ReferredName))) { - ReferredName = ""; - error(EC); - } + if (std::error_code EC = Obj->getSymbolName(*ReferredSym, ReferredName)) + reportError(errorCodeToError(EC), Obj->getFileName()); DictScope AS(W, "AuxCLRToken"); W.printNumber("AuxType", Aux->AuxType); @@ -1578,9 +1621,11 @@ void COFFDumper::printImportedSymbols( iterator_range<imported_symbol_iterator> Range) { for (const ImportedSymbolRef &I : Range) { StringRef Sym; - error(I.getSymbolName(Sym)); + if (std::error_code EC = I.getSymbolName(Sym)) + reportError(errorCodeToError(EC), Obj->getFileName()); uint16_t Ordinal; - error(I.getOrdinal(Ordinal)); + if (std::error_code EC = I.getOrdinal(Ordinal)) + reportError(errorCodeToError(EC), Obj->getFileName()); W.printNumber("Symbol", Sym, Ordinal); } } @@ -1592,12 +1637,17 @@ void COFFDumper::printDelayImportedSymbols( for (const ImportedSymbolRef &S : Range) { DictScope Import(W, "Import"); StringRef Sym; - error(S.getSymbolName(Sym)); + if (std::error_code EC = S.getSymbolName(Sym)) + reportError(errorCodeToError(EC), Obj->getFileName()); + uint16_t Ordinal; - error(S.getOrdinal(Ordinal)); + if (std::error_code EC = S.getOrdinal(Ordinal)) + reportError(errorCodeToError(EC), Obj->getFileName()); W.printNumber("Symbol", Sym, Ordinal); + uint64_t Addr; - error(I.getImportAddress(Index++, Addr)); + if (std::error_code EC = I.getImportAddress(Index++, Addr)) + reportError(errorCodeToError(EC), Obj->getFileName()); W.printHex("Address", Addr); } } @@ -1607,13 +1657,16 @@ void COFFDumper::printCOFFImports() { for (const ImportDirectoryEntryRef &I : Obj->import_directories()) { DictScope Import(W, "Import"); StringRef Name; - error(I.getName(Name)); + if (std::error_code EC = I.getName(Name)) + reportError(errorCodeToError(EC), Obj->getFileName()); W.printString("Name", Name); uint32_t ILTAddr; - error(I.getImportLookupTableRVA(ILTAddr)); + if (std::error_code EC = I.getImportLookupTableRVA(ILTAddr)) + reportError(errorCodeToError(EC), Obj->getFileName()); W.printHex("ImportLookupTableRVA", ILTAddr); uint32_t IATAddr; - error(I.getImportAddressTableRVA(IATAddr)); + if (std::error_code EC = I.getImportAddressTableRVA(IATAddr)) + reportError(errorCodeToError(EC), Obj->getFileName()); W.printHex("ImportAddressTableRVA", IATAddr); // The import lookup table can be missing with certain older linkers, so // fall back to the import address table in that case. @@ -1627,10 +1680,12 @@ void COFFDumper::printCOFFImports() { for (const DelayImportDirectoryEntryRef &I : Obj->delay_import_directories()) { DictScope Import(W, "DelayImport"); StringRef Name; - error(I.getName(Name)); + if (std::error_code EC = I.getName(Name)) + reportError(errorCodeToError(EC), Obj->getFileName()); W.printString("Name", Name); const delay_import_directory_table_entry *Table; - error(I.getDelayImportTable(Table)); + if (std::error_code EC = I.getDelayImportTable(Table)) + reportError(errorCodeToError(EC), Obj->getFileName()); W.printHex("Attributes", Table->Attributes); W.printHex("ModuleHandle", Table->ModuleHandle); W.printHex("ImportAddressTable", Table->DelayImportAddressTable); @@ -1648,9 +1703,12 @@ void COFFDumper::printCOFFExports() { StringRef Name; uint32_t Ordinal, RVA; - error(E.getSymbolName(Name)); - error(E.getOrdinal(Ordinal)); - error(E.getExportRVA(RVA)); + if (std::error_code EC = E.getSymbolName(Name)) + reportError(errorCodeToError(EC), Obj->getFileName()); + if (std::error_code EC = E.getOrdinal(Ordinal)) + reportError(errorCodeToError(EC), Obj->getFileName()); + if (std::error_code EC = E.getExportRVA(RVA)) + reportError(errorCodeToError(EC), Obj->getFileName()); W.printNumber("Ordinal", Ordinal); W.printString("Name", Name); @@ -1660,13 +1718,12 @@ void COFFDumper::printCOFFExports() { void COFFDumper::printCOFFDirectives() { for (const SectionRef &Section : Obj->sections()) { - StringRef Name; - - error(Section.getName(Name)); + StringRef Name = unwrapOrError(Obj->getFileName(), Section.getName()); if (Name != ".drectve") continue; - StringRef Contents = unwrapOrError(Section.getContents()); + StringRef Contents = + unwrapOrError(Obj->getFileName(), Section.getContents()); W.printString("Directive(s)", Contents); } } @@ -1689,8 +1746,10 @@ void COFFDumper::printCOFFBaseReloc() { for (const BaseRelocRef &I : Obj->base_relocs()) { uint8_t Type; uint32_t RVA; - error(I.getRVA(RVA)); - error(I.getType(Type)); + if (std::error_code EC = I.getRVA(RVA)) + reportError(errorCodeToError(EC), Obj->getFileName()); + if (std::error_code EC = I.getType(Type)) + reportError(errorCodeToError(EC), Obj->getFileName()); DictScope Import(W, "Entry"); W.printString("Type", getBaseRelocTypeName(Type)); W.printHex("Address", RVA); @@ -1700,16 +1759,18 @@ void COFFDumper::printCOFFBaseReloc() { void COFFDumper::printCOFFResources() { ListScope ResourcesD(W, "Resources"); for (const SectionRef &S : Obj->sections()) { - StringRef Name; - error(S.getName(Name)); + StringRef Name = unwrapOrError(Obj->getFileName(), S.getName()); if (!Name.startswith(".rsrc")) continue; - StringRef Ref = unwrapOrError(S.getContents()); + StringRef Ref = unwrapOrError(Obj->getFileName(), S.getContents()); if ((Name == ".rsrc") || (Name == ".rsrc$01")) { - ResourceSectionRef RSF(Ref); - auto &BaseTable = unwrapOrError(RSF.getBaseTable()); + ResourceSectionRef RSF; + Error E = RSF.load(Obj, S); + if (E) + reportError(std::move(E), Obj->getFileName()); + auto &BaseTable = unwrapOrError(Obj->getFileName(), RSF.getBaseTable()); W.printNumber("Total Number of Resources", countTotalTableEntries(RSF, BaseTable, "Type")); W.printHex("Base Table Address", @@ -1729,14 +1790,15 @@ COFFDumper::countTotalTableEntries(ResourceSectionRef RSF, uint32_t TotalEntries = 0; for (int i = 0; i < Table.NumberOfNameEntries + Table.NumberOfIDEntries; i++) { - auto Entry = unwrapOrError(getResourceDirectoryTableEntry(Table, i)); + auto Entry = unwrapOrError(Obj->getFileName(), RSF.getTableEntry(Table, i)); if (Entry.Offset.isSubDir()) { StringRef NextLevel; if (Level == "Name") NextLevel = "Language"; else NextLevel = "Name"; - auto &NextTable = unwrapOrError(RSF.getEntrySubDir(Entry)); + auto &NextTable = + unwrapOrError(Obj->getFileName(), RSF.getEntrySubDir(Entry)); TotalEntries += countTotalTableEntries(RSF, NextTable, NextLevel); } else { TotalEntries += 1; @@ -1755,13 +1817,13 @@ void COFFDumper::printResourceDirectoryTable( // Iterate through level in resource directory tree. for (int i = 0; i < Table.NumberOfNameEntries + Table.NumberOfIDEntries; i++) { - auto Entry = unwrapOrError(getResourceDirectoryTableEntry(Table, i)); + auto Entry = unwrapOrError(Obj->getFileName(), RSF.getTableEntry(Table, i)); StringRef Name; SmallString<20> IDStr; raw_svector_ostream OS(IDStr); if (i < Table.NumberOfNameEntries) { ArrayRef<UTF16> RawEntryNameString = - unwrapOrError(RSF.getEntryNameString(Entry)); + unwrapOrError(Obj->getFileName(), RSF.getEntryNameString(Entry)); std::vector<UTF16> EndianCorrectedNameString; if (llvm::sys::IsBigEndianHost) { EndianCorrectedNameString.resize(RawEntryNameString.size() + 1); @@ -1772,14 +1834,14 @@ void COFFDumper::printResourceDirectoryTable( } std::string EntryNameString; if (!llvm::convertUTF16ToUTF8String(RawEntryNameString, EntryNameString)) - error(object_error::parse_failed); + reportError(errorCodeToError(object_error::parse_failed), + Obj->getFileName()); OS << ": "; OS << EntryNameString; } else { if (Level == "Type") { OS << ": "; printResourceTypeName(Entry.Identifier.ID, OS); - IDStr = IDStr.slice(0, IDStr.find_first_of(")", 0) + 1); } else { OS << ": (ID " << Entry.Identifier.ID << ")"; } @@ -1793,7 +1855,8 @@ void COFFDumper::printResourceDirectoryTable( NextLevel = "Language"; else NextLevel = "Name"; - auto &NextTable = unwrapOrError(RSF.getEntrySubDir(Entry)); + auto &NextTable = + unwrapOrError(Obj->getFileName(), RSF.getEntrySubDir(Entry)); printResourceDirectoryTable(RSF, NextTable, NextLevel); } else { W.printHex("Entry Offset", Entry.Offset.value()); @@ -1804,24 +1867,29 @@ void COFFDumper::printResourceDirectoryTable( W.printNumber("Major Version", Table.MajorVersion); W.printNumber("Minor Version", Table.MinorVersion); W.printNumber("Characteristics", Table.Characteristics); + ListScope DataScope(W, "Data"); + auto &DataEntry = + unwrapOrError(Obj->getFileName(), RSF.getEntryData(Entry)); + W.printHex("DataRVA", DataEntry.DataRVA); + W.printNumber("DataSize", DataEntry.DataSize); + W.printNumber("Codepage", DataEntry.Codepage); + W.printNumber("Reserved", DataEntry.Reserved); + StringRef Contents = + unwrapOrError(Obj->getFileName(), RSF.getContents(DataEntry)); + W.printBinaryBlock("Data", Contents); } } } -ErrorOr<const coff_resource_dir_entry &> -COFFDumper::getResourceDirectoryTableEntry(const coff_resource_dir_table &Table, - uint32_t Index) { - if (Index >= (uint32_t)(Table.NumberOfNameEntries + Table.NumberOfIDEntries)) - return object_error::parse_failed; - auto TablePtr = reinterpret_cast<const coff_resource_dir_entry *>(&Table + 1); - return TablePtr[Index]; -} - void COFFDumper::printStackMap() const { object::SectionRef StackMapSection; for (auto Sec : Obj->sections()) { StringRef Name; - Sec.getName(Name); + if (Expected<StringRef> NameOrErr = Sec.getName()) + Name = *NameOrErr; + else + consumeError(NameOrErr.takeError()); + if (Name == ".llvm_stackmaps") { StackMapSection = Sec; break; @@ -1831,7 +1899,8 @@ void COFFDumper::printStackMap() const { if (StackMapSection == object::SectionRef()) return; - StringRef StackMapContents = unwrapOrError(StackMapSection.getContents()); + StringRef StackMapContents = + unwrapOrError(Obj->getFileName(), StackMapSection.getContents()); ArrayRef<uint8_t> StackMapContentsArray = arrayRefFromStringRef(StackMapContents); @@ -1847,7 +1916,11 @@ void COFFDumper::printAddrsig() { object::SectionRef AddrsigSection; for (auto Sec : Obj->sections()) { StringRef Name; - Sec.getName(Name); + if (Expected<StringRef> NameOrErr = Sec.getName()) + Name = *NameOrErr; + else + consumeError(NameOrErr.takeError()); + if (Name == ".llvm_addrsig") { AddrsigSection = Sec; break; @@ -1857,7 +1930,8 @@ void COFFDumper::printAddrsig() { if (AddrsigSection == object::SectionRef()) return; - StringRef AddrsigContents = unwrapOrError(AddrsigSection.getContents()); + StringRef AddrsigContents = + unwrapOrError(Obj->getFileName(), AddrsigSection.getContents()); ArrayRef<uint8_t> AddrsigContentsArray(AddrsigContents.bytes_begin(), AddrsigContents.size()); @@ -1869,15 +1943,15 @@ void COFFDumper::printAddrsig() { const char *Err; uint64_t SymIndex = decodeULEB128(Cur, &Size, End, &Err); if (Err) - reportError(Err); + reportError(createError(Err), Obj->getFileName()); Expected<COFFSymbolRef> Sym = Obj->getSymbol(SymIndex); + if (!Sym) + reportError(Sym.takeError(), Obj->getFileName()); + StringRef SymName; - std::error_code EC = errorToErrorCode(Sym.takeError()); - if (EC || (EC = Obj->getSymbolName(*Sym, SymName))) { - SymName = ""; - error(EC); - } + if (std::error_code EC = Obj->getSymbolName(*Sym, SymName)) + reportError(errorCodeToError(EC), Obj->getFileName()); W.printNumber("Sym", SymName, SymIndex); Cur += Size; @@ -1891,7 +1965,8 @@ void llvm::dumpCodeViewMergedTypes(ScopedPrinter &Writer, { ListScope S(Writer, "MergedTypeStream"); TypeDumpVisitor TDV(TpiTypes, &Writer, opts::CodeViewSubsectionBytes); - error(codeview::visitTypeStream(TpiTypes, TDV)); + if (Error Err = codeview::visitTypeStream(TpiTypes, TDV)) + reportError(std::move(Err), "<?>"); Writer.flush(); } @@ -1902,7 +1977,8 @@ void llvm::dumpCodeViewMergedTypes(ScopedPrinter &Writer, ListScope S(Writer, "MergedIDStream"); TypeDumpVisitor TDV(TpiTypes, &Writer, opts::CodeViewSubsectionBytes); TDV.setIpiTypes(IpiTypes); - error(codeview::visitTypeStream(IpiTypes, TDV)); + if (Error Err = codeview::visitTypeStream(IpiTypes, TDV)) + reportError(std::move(Err), "<?>"); Writer.flush(); } } diff --git a/tools/llvm-readobj/DwarfCFIEHPrinter.h b/tools/llvm-readobj/DwarfCFIEHPrinter.h index 7055510ef2f2..0a365d4fe72a 100644 --- a/tools/llvm-readobj/DwarfCFIEHPrinter.h +++ b/tools/llvm-readobj/DwarfCFIEHPrinter.h @@ -44,12 +44,12 @@ public: void printUnwindInformation() const; }; -template <class ELFO> -static const typename ELFO::Elf_Shdr *findSectionByAddress(const ELFO *Obj, - uint64_t Addr) { - auto Sections = Obj->sections(); +template <class ELFT> +static const typename object::ELFObjectFile<ELFT>::Elf_Shdr * +findSectionByAddress(const object::ELFObjectFile<ELFT> *ObjF, uint64_t Addr) { + auto Sections = ObjF->getELFFile()->sections(); if (Error E = Sections.takeError()) - reportError(toString(std::move(E))); + reportError(std::move(E), ObjF->getFileName()); for (const auto &Shdr : *Sections) if (Shdr.sh_addr == Addr) @@ -64,13 +64,15 @@ void PrinterContext<ELFT>::printUnwindInformation() const { auto PHs = Obj->program_headers(); if (Error E = PHs.takeError()) - reportError(toString(std::move(E))); + reportError(std::move(E), ObjF->getFileName()); for (const auto &Phdr : *PHs) { if (Phdr.p_type == ELF::PT_GNU_EH_FRAME) { EHFramePhdr = &Phdr; if (Phdr.p_memsz != Phdr.p_filesz) - reportError("p_memsz does not match p_filesz for GNU_EH_FRAME"); + reportError(object::createError( + "p_memsz does not match p_filesz for GNU_EH_FRAME"), + ObjF->getFileName()); break; } } @@ -81,12 +83,12 @@ void PrinterContext<ELFT>::printUnwindInformation() const { auto Sections = Obj->sections(); if (Error E = Sections.takeError()) - reportError(toString(std::move(E))); + reportError(std::move(E), ObjF->getFileName()); for (const auto &Shdr : *Sections) { auto SectionName = Obj->getSectionName(&Shdr); if (Error E = SectionName.takeError()) - reportError(toString(std::move(E))); + reportError(std::move(E), ObjF->getFileName()); if (*SectionName == ".eh_frame") printEHFrame(&Shdr); @@ -97,49 +99,52 @@ template <typename ELFT> void PrinterContext<ELFT>::printEHFrameHdr(uint64_t EHFrameHdrOffset, uint64_t EHFrameHdrAddress, uint64_t EHFrameHdrSize) const { - ListScope L(W, "EH_FRAME Header"); + DictScope L(W, "EHFrameHeader"); W.startLine() << format("Address: 0x%" PRIx64 "\n", EHFrameHdrAddress); W.startLine() << format("Offset: 0x%" PRIx64 "\n", EHFrameHdrOffset); W.startLine() << format("Size: 0x%" PRIx64 "\n", EHFrameHdrSize); const object::ELFFile<ELFT> *Obj = ObjF->getELFFile(); - const auto *EHFrameHdrShdr = findSectionByAddress(Obj, EHFrameHdrAddress); + const auto *EHFrameHdrShdr = findSectionByAddress(ObjF, EHFrameHdrAddress); if (EHFrameHdrShdr) { auto SectionName = Obj->getSectionName(EHFrameHdrShdr); if (Error E = SectionName.takeError()) - reportError(toString(std::move(E))); + reportError(std::move(E), ObjF->getFileName()); W.printString("Corresponding Section", *SectionName); } - DataExtractor DE( - StringRef(reinterpret_cast<const char *>(Obj->base()) + EHFrameHdrOffset, - EHFrameHdrSize), - ELFT::TargetEndianness == support::endianness::little, - ELFT::Is64Bits ? 8 : 4); + DataExtractor DE(makeArrayRef(Obj->base() + EHFrameHdrOffset, EHFrameHdrSize), + ELFT::TargetEndianness == support::endianness::little, + ELFT::Is64Bits ? 8 : 4); DictScope D(W, "Header"); - uint32_t Offset = 0; + uint64_t Offset = 0; auto Version = DE.getU8(&Offset); W.printNumber("version", Version); if (Version != 1) - reportError("only version 1 of .eh_frame_hdr is supported"); + reportError( + object::createError("only version 1 of .eh_frame_hdr is supported"), + ObjF->getFileName()); uint64_t EHFramePtrEnc = DE.getU8(&Offset); W.startLine() << format("eh_frame_ptr_enc: 0x%" PRIx64 "\n", EHFramePtrEnc); if (EHFramePtrEnc != (dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4)) - reportError("unexpected encoding eh_frame_ptr_enc"); + reportError(object::createError("unexpected encoding eh_frame_ptr_enc"), + ObjF->getFileName()); uint64_t FDECountEnc = DE.getU8(&Offset); W.startLine() << format("fde_count_enc: 0x%" PRIx64 "\n", FDECountEnc); if (FDECountEnc != dwarf::DW_EH_PE_udata4) - reportError("unexpected encoding fde_count_enc"); + reportError(object::createError("unexpected encoding fde_count_enc"), + ObjF->getFileName()); uint64_t TableEnc = DE.getU8(&Offset); W.startLine() << format("table_enc: 0x%" PRIx64 "\n", TableEnc); if (TableEnc != (dwarf::DW_EH_PE_datarel | dwarf::DW_EH_PE_sdata4)) - reportError("unexpected encoding table_enc"); + reportError(object::createError("unexpected encoding table_enc"), + ObjF->getFileName()); auto EHFramePtr = DE.getSigned(&Offset, 4) + EHFrameHdrAddress + 4; W.startLine() << format("eh_frame_ptr: 0x%" PRIx64 "\n", EHFramePtr); @@ -158,7 +163,8 @@ void PrinterContext<ELFT>::printEHFrameHdr(uint64_t EHFrameHdrOffset, W.startLine() << format("address: 0x%" PRIx64 "\n", Address); if (InitialPC < PrevPC) - reportError("initial_location is out of order"); + reportError(object::createError("initial_location is out of order"), + ObjF->getFileName()); PrevPC = InitialPC; ++NumEntries; @@ -178,7 +184,7 @@ void PrinterContext<ELFT>::printEHFrame( const object::ELFFile<ELFT> *Obj = ObjF->getELFFile(); auto Result = Obj->getSectionContents(EHFrameShdr); if (Error E = Result.takeError()) - reportError(toString(std::move(E))); + reportError(std::move(E), ObjF->getFileName()); auto Contents = Result.get(); DWARFDataExtractor DE( diff --git a/tools/llvm-readobj/ELFDumper.cpp b/tools/llvm-readobj/ELFDumper.cpp index 4e1cb7d544e7..57144882c4b4 100644 --- a/tools/llvm-readobj/ELFDumper.cpp +++ b/tools/llvm-readobj/ELFDumper.cpp @@ -20,6 +20,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/MapVector.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/STLExtras.h" @@ -36,6 +37,7 @@ #include "llvm/Object/ELFTypes.h" #include "llvm/Object/Error.h" #include "llvm/Object/ObjectFile.h" +#include "llvm/Object/RelocationResolver.h" #include "llvm/Object/StackMapParser.h" #include "llvm/Support/AMDGPUMetadata.h" #include "llvm/Support/ARMAttributeParser.h" @@ -61,6 +63,7 @@ #include <memory> #include <string> #include <system_error> +#include <unordered_set> #include <vector> using namespace llvm; @@ -119,9 +122,9 @@ template <class ELFT> class DumpStyle; /// the size, entity size and virtual address are different entries in arbitrary /// order (DT_REL, DT_RELSZ, DT_RELENT for example). struct DynRegionInfo { - DynRegionInfo() = default; - DynRegionInfo(const void *A, uint64_t S, uint64_t ES) - : Addr(A), Size(S), EntSize(ES) {} + DynRegionInfo(StringRef ObjName) : FileName(ObjName) {} + DynRegionInfo(const void *A, uint64_t S, uint64_t ES, StringRef ObjName) + : Addr(A), Size(S), EntSize(ES), FileName(ObjName) {} /// Address in current address space. const void *Addr = nullptr; @@ -130,14 +133,18 @@ struct DynRegionInfo { /// Size of each entity in the region. uint64_t EntSize = 0; + /// Name of the file. Used for error reporting. + StringRef FileName; + template <typename Type> ArrayRef<Type> getAsArrayRef() const { const Type *Start = reinterpret_cast<const Type *>(Addr); if (!Start) return {Start, Start}; if (EntSize != sizeof(Type) || Size % EntSize) { // TODO: Add a section index to this warning. - reportWarning("invalid section size (" + Twine(Size) + - ") or entity size (" + Twine(EntSize) + ")"); + reportWarning(createError("invalid section size (" + Twine(Size) + + ") or entity size (" + Twine(EntSize) + ")"), + FileName); return {Start, Start}; } return {Start, Start + (Size / EntSize)}; @@ -166,11 +173,7 @@ public: void printVersionInfo() override; void printGroupSections() override; - void printAttributes() override; - void printMipsPLTGOT() override; - void printMipsABIFlags() override; - void printMipsReginfo() override; - void printMipsOptions() override; + void printArchSpecificInfo() override; void printStackMap() const override; @@ -182,6 +185,7 @@ public: void printNotes() override; void printELFLinkerOptions() override; + void printStackSizes() override; const object::ELFObjectFile<ELFT> *getElfObject() const { return ObjF; }; @@ -195,20 +199,27 @@ private: if (DRI.Addr < Obj->base() || reinterpret_cast<const uint8_t *>(DRI.Addr) + DRI.Size > Obj->base() + Obj->getBufSize()) - error(llvm::object::object_error::parse_failed); + reportError(errorCodeToError(llvm::object::object_error::parse_failed), + ObjF->getFileName()); return DRI; } DynRegionInfo createDRIFrom(const Elf_Phdr *P, uintX_t EntSize) { - return checkDRI( - {ObjF->getELFFile()->base() + P->p_offset, P->p_filesz, EntSize}); + return checkDRI({ObjF->getELFFile()->base() + P->p_offset, P->p_filesz, + EntSize, ObjF->getFileName()}); } DynRegionInfo createDRIFrom(const Elf_Shdr *S) { - return checkDRI( - {ObjF->getELFFile()->base() + S->sh_offset, S->sh_size, S->sh_entsize}); + return checkDRI({ObjF->getELFFile()->base() + S->sh_offset, S->sh_size, + S->sh_entsize, ObjF->getFileName()}); } + void printAttributes(); + void printMipsReginfo(); + void printMipsOptions(); + + std::pair<const Elf_Phdr *, const Elf_Shdr *> + findDynamic(const ELFFile<ELFT> *Obj); void loadDynamicTable(const ELFFile<ELFT> *Obj); void parseDynamicTable(); @@ -226,7 +237,7 @@ private: DynRegionInfo DynSymRegion; DynRegionInfo DynamicTable; StringRef DynamicStringTable; - StringRef SOName = "<Not found>"; + std::string SOName = "<Not found>"; const Elf_Hash *HashTable = nullptr; const Elf_GnuHash *GnuHashTable = nullptr; const Elf_Shdr *DotSymtabSec = nullptr; @@ -291,7 +302,8 @@ public: void getSectionNameIndex(const Elf_Sym *Symbol, const Elf_Sym *FirstSym, StringRef &SectionName, unsigned &SectionIndex) const; - std::string getStaticSymbolName(uint32_t Index) const; + Expected<std::string> getStaticSymbolName(uint32_t Index) const; + std::string getDynamicString(uint64_t Value) const; StringRef getSymbolVersionByIndex(StringRef StrTab, uint32_t VersionSymbolIndex, bool &IsDefault) const; @@ -328,16 +340,27 @@ void ELFDumper<ELFT>::printSymbolsHelper(bool IsDynamic) const { } else { if (!DotSymtabSec) return; - StrTable = unwrapOrError(Obj->getStringTableForSymtab(*DotSymtabSec)); - Syms = unwrapOrError(Obj->symbols(DotSymtabSec)); - SymtabName = unwrapOrError(Obj->getSectionName(DotSymtabSec)); + StrTable = unwrapOrError(ObjF->getFileName(), + Obj->getStringTableForSymtab(*DotSymtabSec)); + Syms = unwrapOrError(ObjF->getFileName(), Obj->symbols(DotSymtabSec)); + SymtabName = + unwrapOrError(ObjF->getFileName(), Obj->getSectionName(DotSymtabSec)); Entries = DotSymtabSec->getEntityCount(); } if (Syms.begin() == Syms.end()) return; - ELFDumperStyle->printSymtabMessage(Obj, SymtabName, Entries); + + // The st_other field has 2 logical parts. The first two bits hold the symbol + // visibility (STV_*) and the remainder hold other platform-specific values. + bool NonVisibilityBitsUsed = llvm::find_if(Syms, [](const Elf_Sym &S) { + return S.st_other & ~0x3; + }) != Syms.end(); + + ELFDumperStyle->printSymtabMessage(Obj, SymtabName, Entries, + NonVisibilityBitsUsed); for (const auto &Sym : Syms) - ELFDumperStyle->printSymbol(Obj, &Sym, Syms.begin(), StrTable, IsDynamic); + ELFDumperStyle->printSymbol(Obj, &Sym, Syms.begin(), StrTable, IsDynamic, + NonVisibilityBitsUsed); } template <class ELFT> class MipsGOTParser; @@ -346,8 +369,20 @@ template <typename ELFT> class DumpStyle { public: using Elf_Shdr = typename ELFT::Shdr; using Elf_Sym = typename ELFT::Sym; + using Elf_Addr = typename ELFT::Addr; + + DumpStyle(ELFDumper<ELFT> *Dumper) : Dumper(Dumper) { + FileName = this->Dumper->getElfObject()->getFileName(); + + // Dumper reports all non-critical errors as warnings. + // It does not print the same warning more than once. + WarningHandler = [this](const Twine &Msg) { + if (Warnings.insert(Msg.str()).second) + reportWarning(createError(Msg), FileName); + return Error::success(); + }; + } - DumpStyle(ELFDumper<ELFT> *Dumper) : Dumper(Dumper) {} virtual ~DumpStyle() = default; virtual void printFileHeaders(const ELFFile<ELFT> *Obj) = 0; @@ -360,10 +395,10 @@ public: virtual void printDynamic(const ELFFile<ELFT> *Obj) {} virtual void printDynamicRelocations(const ELFFile<ELFT> *Obj) = 0; virtual void printSymtabMessage(const ELFFile<ELFT> *Obj, StringRef Name, - size_t Offset) {} + size_t Offset, bool NonVisibilityBitsUsed) {} virtual void printSymbol(const ELFFile<ELFT> *Obj, const Elf_Sym *Symbol, const Elf_Sym *FirstSym, StringRef StrTable, - bool IsDynamic) = 0; + bool IsDynamic, bool NonVisibilityBitsUsed) = 0; virtual void printProgramHeaders(const ELFFile<ELFT> *Obj, bool PrintProgramHeaders, cl::boolOrDefault PrintSectionMapping) = 0; @@ -378,11 +413,31 @@ public: virtual void printAddrsig(const ELFFile<ELFT> *Obj) = 0; virtual void printNotes(const ELFFile<ELFT> *Obj) = 0; virtual void printELFLinkerOptions(const ELFFile<ELFT> *Obj) = 0; + virtual void printStackSizes(const ELFObjectFile<ELFT> *Obj) = 0; + void printNonRelocatableStackSizes(const ELFObjectFile<ELFT> *Obj, + std::function<void()> PrintHeader); + void printRelocatableStackSizes(const ELFObjectFile<ELFT> *Obj, + std::function<void()> PrintHeader); + void printFunctionStackSize(const ELFObjectFile<ELFT> *Obj, uint64_t SymValue, + SectionRef FunctionSec, + const StringRef SectionName, DataExtractor Data, + uint64_t *Offset); + void printStackSize(const ELFObjectFile<ELFT> *Obj, RelocationRef Rel, + SectionRef FunctionSec, + const StringRef &StackSizeSectionName, + const RelocationResolver &Resolver, DataExtractor Data); + virtual void printStackSizeEntry(uint64_t Size, StringRef FuncName) = 0; virtual void printMipsGOT(const MipsGOTParser<ELFT> &Parser) = 0; virtual void printMipsPLT(const MipsGOTParser<ELFT> &Parser) = 0; + virtual void printMipsABIFlags(const ELFObjectFile<ELFT> *Obj) = 0; const ELFDumper<ELFT> *dumper() const { return Dumper; } +protected: + std::function<Error(const Twine &Msg)> WarningHandler; + StringRef FileName; + private: + std::unordered_set<std::string> Warnings; const ELFDumper<ELFT> *Dumper; }; @@ -407,8 +462,8 @@ public: void printHashSymbols(const ELFO *Obj) override; void printDynamic(const ELFFile<ELFT> *Obj) override; void printDynamicRelocations(const ELFO *Obj) override; - void printSymtabMessage(const ELFO *Obj, StringRef Name, - size_t Offset) override; + void printSymtabMessage(const ELFO *Obj, StringRef Name, size_t Offset, + bool NonVisibilityBitsUsed) override; void printProgramHeaders(const ELFO *Obj, bool PrintProgramHeaders, cl::boolOrDefault PrintSectionMapping) override; void printVersionSymbolSection(const ELFFile<ELFT> *Obj, @@ -422,8 +477,11 @@ public: void printAddrsig(const ELFFile<ELFT> *Obj) override; void printNotes(const ELFFile<ELFT> *Obj) override; void printELFLinkerOptions(const ELFFile<ELFT> *Obj) override; + void printStackSizes(const ELFObjectFile<ELFT> *Obj) override; + void printStackSizeEntry(uint64_t Size, StringRef FuncName) override; void printMipsGOT(const MipsGOTParser<ELFT> &Parser) override; void printMipsPLT(const MipsGOTParser<ELFT> &Parser) override; + void printMipsABIFlags(const ELFObjectFile<ELFT> *Obj) override; private: struct Field { @@ -484,7 +542,8 @@ private: void printRelocation(const ELFO *Obj, const Elf_Sym *Sym, StringRef SymbolName, const Elf_Rela &R, bool IsRela); void printSymbol(const ELFO *Obj, const Elf_Sym *Symbol, const Elf_Sym *First, - StringRef StrTable, bool IsDynamic) override; + StringRef StrTable, bool IsDynamic, + bool NonVisibilityBitsUsed) override; std::string getSymbolSectionNdx(const ELFO *Obj, const Elf_Sym *Symbol, const Elf_Sym *FirstSym); void printDynamicRelocation(const ELFO *Obj, Elf_Rela R, bool IsRela); @@ -525,8 +584,11 @@ public: void printAddrsig(const ELFFile<ELFT> *Obj) override; void printNotes(const ELFFile<ELFT> *Obj) override; void printELFLinkerOptions(const ELFFile<ELFT> *Obj) override; + void printStackSizes(const ELFObjectFile<ELFT> *Obj) override; + void printStackSizeEntry(uint64_t Size, StringRef FuncName) override; void printMipsGOT(const MipsGOTParser<ELFT> &Parser) override; void printMipsPLT(const MipsGOTParser<ELFT> &Parser) override; + void printMipsABIFlags(const ELFObjectFile<ELFT> *Obj) override; private: void printRelocation(const ELFO *Obj, Elf_Rela Rel, const Elf_Shdr *SymTab); @@ -534,7 +596,8 @@ private: void printSymbols(const ELFO *Obj); void printDynamicSymbols(const ELFO *Obj); void printSymbol(const ELFO *Obj, const Elf_Sym *Symbol, const Elf_Sym *First, - StringRef StrTable, bool IsDynamic) override; + StringRef StrTable, bool IsDynamic, + bool /*NonVisibilityBitsUsed*/) override; void printProgramHeaders(const ELFO *Obj); void printSectionMapping(const ELFO *Obj) {} @@ -680,9 +743,9 @@ StringRef ELFDumper<ELFT>::getSymbolVersion(StringRef StrTab, sizeof(Elf_Sym); // Get the corresponding version index entry. - const Elf_Versym *Versym = - unwrapOrError(ObjF->getELFFile()->template getEntry<Elf_Versym>( - SymbolVersionSection, EntryIndex)); + const Elf_Versym *Versym = unwrapOrError( + ObjF->getFileName(), ObjF->getELFFile()->template getEntry<Elf_Versym>( + SymbolVersionSection, EntryIndex)); return this->getSymbolVersionByIndex(StrTab, Versym->vs_index, IsDefault); } @@ -691,15 +754,22 @@ static std::string maybeDemangle(StringRef Name) { } template <typename ELFT> -std::string ELFDumper<ELFT>::getStaticSymbolName(uint32_t Index) const { +Expected<std::string> +ELFDumper<ELFT>::getStaticSymbolName(uint32_t Index) const { const ELFFile<ELFT> *Obj = ObjF->getELFFile(); - StringRef StrTable = - unwrapOrError(Obj->getStringTableForSymtab(*DotSymtabSec)); - Elf_Sym_Range Syms = unwrapOrError(Obj->symbols(DotSymtabSec)); - if (Index >= Syms.size()) - reportError("Invalid symbol index"); - const Elf_Sym *Sym = &Syms[Index]; - return maybeDemangle(unwrapOrError(Sym->getName(StrTable))); + Expected<const typename ELFT::Sym *> SymOrErr = + Obj->getSymbol(DotSymtabSec, Index); + if (!SymOrErr) + return SymOrErr.takeError(); + + Expected<StringRef> StrTabOrErr = Obj->getStringTableForSymtab(*DotSymtabSec); + if (!StrTabOrErr) + return StrTabOrErr.takeError(); + + Expected<StringRef> NameOrErr = (*SymOrErr)->getName(*StrTabOrErr); + if (!NameOrErr) + return NameOrErr.takeError(); + return maybeDemangle(*NameOrErr); } template <typename ELFT> @@ -717,7 +787,7 @@ StringRef ELFDumper<ELFT>::getSymbolVersionByIndex(StringRef StrTab, // Lookup this symbol in the version table. LoadVersionMap(); if (VersionIndex >= VersionMap.size() || VersionMap[VersionIndex].isNull()) - reportError("Invalid version entry"); + reportError(createError("Invalid version entry"), ObjF->getFileName()); const VersionMapEntry &Entry = VersionMap[VersionIndex]; // Get the version name string. @@ -731,7 +801,7 @@ StringRef ELFDumper<ELFT>::getSymbolVersionByIndex(StringRef StrTab, IsDefault = false; } if (NameOffset >= StrTab.size()) - reportError("Invalid string offset"); + reportError(createError("Invalid string offset"), ObjF->getFileName()); return StrTab.data() + NameOffset; } @@ -739,14 +809,14 @@ template <typename ELFT> std::string ELFDumper<ELFT>::getFullSymbolName(const Elf_Sym *Symbol, StringRef StrTable, bool IsDynamic) const { - std::string SymbolName = - maybeDemangle(unwrapOrError(Symbol->getName(StrTable))); + std::string SymbolName = maybeDemangle( + unwrapOrError(ObjF->getFileName(), Symbol->getName(StrTable))); if (SymbolName.empty() && Symbol->getType() == ELF::STT_SECTION) { unsigned SectionIndex; StringRef SectionName; - Elf_Sym_Range Syms = - unwrapOrError(ObjF->getELFFile()->symbols(DotSymtabSec)); + Elf_Sym_Range Syms = unwrapOrError( + ObjF->getFileName(), ObjF->getELFFile()->symbols(DotSymtabSec)); getSectionNameIndex(Symbol, Syms.begin(), SectionName, SectionIndex); return SectionName; } @@ -783,31 +853,32 @@ void ELFDumper<ELFT>::getSectionNameIndex(const Elf_Sym *Symbol, SectionName = "Reserved"; else { if (SectionIndex == SHN_XINDEX) - SectionIndex = unwrapOrError(object::getExtendedSymbolTableIndex<ELFT>( - Symbol, FirstSym, ShndxTable)); + SectionIndex = unwrapOrError(ObjF->getFileName(), + object::getExtendedSymbolTableIndex<ELFT>( + Symbol, FirstSym, ShndxTable)); const ELFFile<ELFT> *Obj = ObjF->getELFFile(); const typename ELFT::Shdr *Sec = - unwrapOrError(Obj->getSection(SectionIndex)); - SectionName = unwrapOrError(Obj->getSectionName(Sec)); + unwrapOrError(ObjF->getFileName(), Obj->getSection(SectionIndex)); + SectionName = unwrapOrError(ObjF->getFileName(), Obj->getSectionName(Sec)); } } template <class ELFO> static const typename ELFO::Elf_Shdr * -findNotEmptySectionByAddress(const ELFO *Obj, uint64_t Addr) { - for (const auto &Shdr : unwrapOrError(Obj->sections())) +findNotEmptySectionByAddress(const ELFO *Obj, StringRef FileName, + uint64_t Addr) { + for (const auto &Shdr : unwrapOrError(FileName, Obj->sections())) if (Shdr.sh_addr == Addr && Shdr.sh_size > 0) return &Shdr; return nullptr; } template <class ELFO> -static const typename ELFO::Elf_Shdr *findSectionByName(const ELFO &Obj, - StringRef Name) { - for (const auto &Shdr : unwrapOrError(Obj.sections())) { - if (Name == unwrapOrError(Obj.getSectionName(&Shdr))) +static const typename ELFO::Elf_Shdr * +findSectionByName(const ELFO &Obj, StringRef FileName, StringRef Name) { + for (const auto &Shdr : unwrapOrError(FileName, Obj.sections())) + if (Name == unwrapOrError(FileName, Obj.getSectionName(&Shdr))) return &Shdr; - } return nullptr; } @@ -1356,10 +1427,12 @@ static const char *getElfMipsOptionsOdkType(unsigned Odk) { } template <typename ELFT> -void ELFDumper<ELFT>::loadDynamicTable(const ELFFile<ELFT> *Obj) { +std::pair<const typename ELFT::Phdr *, const typename ELFT::Shdr *> +ELFDumper<ELFT>::findDynamic(const ELFFile<ELFT> *Obj) { // Try to locate the PT_DYNAMIC header. const Elf_Phdr *DynamicPhdr = nullptr; - for (const Elf_Phdr &Phdr : unwrapOrError(Obj->program_headers())) { + for (const Elf_Phdr &Phdr : + unwrapOrError(ObjF->getFileName(), Obj->program_headers())) { if (Phdr.p_type != ELF::PT_DYNAMIC) continue; DynamicPhdr = &Phdr; @@ -1368,61 +1441,132 @@ void ELFDumper<ELFT>::loadDynamicTable(const ELFFile<ELFT> *Obj) { // Try to locate the .dynamic section in the sections header table. const Elf_Shdr *DynamicSec = nullptr; - for (const Elf_Shdr &Sec : unwrapOrError(Obj->sections())) { + for (const Elf_Shdr &Sec : + unwrapOrError(ObjF->getFileName(), Obj->sections())) { if (Sec.sh_type != ELF::SHT_DYNAMIC) continue; DynamicSec = &Sec; break; } - // Information in the section header has priority over the information - // in a PT_DYNAMIC header. + if (DynamicPhdr && DynamicPhdr->p_offset + DynamicPhdr->p_filesz > + ObjF->getMemoryBufferRef().getBufferSize()) { + reportWarning( + createError( + "PT_DYNAMIC segment offset + size exceeds the size of the file"), + ObjF->getFileName()); + // Don't use the broken dynamic header. + DynamicPhdr = nullptr; + } + + if (DynamicPhdr && DynamicSec) { + StringRef Name = + unwrapOrError(ObjF->getFileName(), Obj->getSectionName(DynamicSec)); + if (DynamicSec->sh_addr + DynamicSec->sh_size > + DynamicPhdr->p_vaddr + DynamicPhdr->p_memsz || + DynamicSec->sh_addr < DynamicPhdr->p_vaddr) + reportWarning(createError("The SHT_DYNAMIC section '" + Name + + "' is not contained within the " + "PT_DYNAMIC segment"), + ObjF->getFileName()); + + if (DynamicSec->sh_addr != DynamicPhdr->p_vaddr) + reportWarning(createError("The SHT_DYNAMIC section '" + Name + + "' is not at the start of " + "PT_DYNAMIC segment"), + ObjF->getFileName()); + } + + return std::make_pair(DynamicPhdr, DynamicSec); +} + +template <typename ELFT> +void ELFDumper<ELFT>::loadDynamicTable(const ELFFile<ELFT> *Obj) { + const Elf_Phdr *DynamicPhdr; + const Elf_Shdr *DynamicSec; + std::tie(DynamicPhdr, DynamicSec) = findDynamic(Obj); + if (!DynamicPhdr && !DynamicSec) + return; + + DynRegionInfo FromPhdr(ObjF->getFileName()); + bool IsPhdrTableValid = false; + if (DynamicPhdr) { + FromPhdr = createDRIFrom(DynamicPhdr, sizeof(Elf_Dyn)); + IsPhdrTableValid = !FromPhdr.getAsArrayRef<Elf_Dyn>().empty(); + } + + // Locate the dynamic table described in a section header. // Ignore sh_entsize and use the expected value for entry size explicitly. - // This allows us to dump the dynamic sections with a broken sh_entsize + // This allows us to dump dynamic sections with a broken sh_entsize // field. + DynRegionInfo FromSec(ObjF->getFileName()); + bool IsSecTableValid = false; if (DynamicSec) { - DynamicTable = checkDRI({ObjF->getELFFile()->base() + DynamicSec->sh_offset, - DynamicSec->sh_size, sizeof(Elf_Dyn)}); - parseDynamicTable(); + FromSec = + checkDRI({ObjF->getELFFile()->base() + DynamicSec->sh_offset, + DynamicSec->sh_size, sizeof(Elf_Dyn), ObjF->getFileName()}); + IsSecTableValid = !FromSec.getAsArrayRef<Elf_Dyn>().empty(); } - // If we have a PT_DYNAMIC header, we will either check the found dynamic - // section or take the dynamic table data directly from the header. - if (!DynamicPhdr) + // When we only have information from one of the SHT_DYNAMIC section header or + // PT_DYNAMIC program header, just use that. + if (!DynamicPhdr || !DynamicSec) { + if ((DynamicPhdr && IsPhdrTableValid) || (DynamicSec && IsSecTableValid)) { + DynamicTable = DynamicPhdr ? FromPhdr : FromSec; + parseDynamicTable(); + } else { + reportWarning(createError("no valid dynamic table was found"), + ObjF->getFileName()); + } return; + } - if (DynamicPhdr->p_offset + DynamicPhdr->p_filesz > - ObjF->getMemoryBufferRef().getBufferSize()) - reportError( - "PT_DYNAMIC segment offset + size exceeds the size of the file"); + // At this point we have tables found from the section header and from the + // dynamic segment. Usually they match, but we have to do sanity checks to + // verify that. - if (!DynamicSec) { - DynamicTable = createDRIFrom(DynamicPhdr, sizeof(Elf_Dyn)); - parseDynamicTable(); + if (FromPhdr.Addr != FromSec.Addr) + reportWarning(createError("SHT_DYNAMIC section header and PT_DYNAMIC " + "program header disagree about " + "the location of the dynamic table"), + ObjF->getFileName()); + + if (!IsPhdrTableValid && !IsSecTableValid) { + reportWarning(createError("no valid dynamic table was found"), + ObjF->getFileName()); return; } - StringRef Name = unwrapOrError(Obj->getSectionName(DynamicSec)); - if (DynamicSec->sh_addr + DynamicSec->sh_size > - DynamicPhdr->p_vaddr + DynamicPhdr->p_memsz || - DynamicSec->sh_addr < DynamicPhdr->p_vaddr) - reportWarning("The SHT_DYNAMIC section '" + Name + - "' is not contained within the " - "PT_DYNAMIC segment"); + // Information in the PT_DYNAMIC program header has priority over the information + // in a section header. + if (IsPhdrTableValid) { + if (!IsSecTableValid) + reportWarning( + createError( + "SHT_DYNAMIC dynamic table is invalid: PT_DYNAMIC will be used"), + ObjF->getFileName()); + DynamicTable = FromPhdr; + } else { + reportWarning( + createError( + "PT_DYNAMIC dynamic table is invalid: SHT_DYNAMIC will be used"), + ObjF->getFileName()); + DynamicTable = FromSec; + } - if (DynamicSec->sh_addr != DynamicPhdr->p_vaddr) - reportWarning("The SHT_DYNAMIC section '" + Name + - "' is not at the start of " - "PT_DYNAMIC segment"); + parseDynamicTable(); } template <typename ELFT> ELFDumper<ELFT>::ELFDumper(const object::ELFObjectFile<ELFT> *ObjF, - ScopedPrinter &Writer) - : ObjDumper(Writer), ObjF(ObjF) { + ScopedPrinter &Writer) + : ObjDumper(Writer), ObjF(ObjF), DynRelRegion(ObjF->getFileName()), + DynRelaRegion(ObjF->getFileName()), DynRelrRegion(ObjF->getFileName()), + DynPLTRelRegion(ObjF->getFileName()), DynSymRegion(ObjF->getFileName()), + DynamicTable(ObjF->getFileName()) { const ELFFile<ELFT> *Obj = ObjF->getELFFile(); - - for (const Elf_Shdr &Sec : unwrapOrError(Obj->sections())) { + for (const Elf_Shdr &Sec : + unwrapOrError(ObjF->getFileName(), Obj->sections())) { switch (Sec.sh_type) { case ELF::SHT_SYMTAB: if (!DotSymtabSec) @@ -1433,16 +1577,17 @@ ELFDumper<ELFT>::ELFDumper(const object::ELFObjectFile<ELFT> *ObjF, DynSymRegion = createDRIFrom(&Sec); // This is only used (if Elf_Shdr present)for naming section in GNU // style - DynSymtabName = unwrapOrError(Obj->getSectionName(&Sec)); + DynSymtabName = + unwrapOrError(ObjF->getFileName(), Obj->getSectionName(&Sec)); if (Expected<StringRef> E = Obj->getStringTableForSymtab(Sec)) DynamicStringTable = *E; else - warn(E.takeError()); + reportWarning(E.takeError(), ObjF->getFileName()); } break; case ELF::SHT_SYMTAB_SHNDX: - ShndxTable = unwrapOrError(Obj->getSHNDXTable(Sec)); + ShndxTable = unwrapOrError(ObjF->getFileName(), Obj->getSHNDXTable(Sec)); break; case ELF::SHT_GNU_versym: if (!SymbolVersionSection) @@ -1547,10 +1692,13 @@ template <typename ELFT> void ELFDumper<ELFT>::parseDynamicTable() { auto toMappedAddr = [&](uint64_t Tag, uint64_t VAddr) -> const uint8_t * { auto MappedAddrOrError = ObjF->getELFFile()->toMappedAddr(VAddr); if (!MappedAddrOrError) { - reportWarning("Unable to parse DT_" + - Twine(getTypeString( - ObjF->getELFFile()->getHeader()->e_machine, Tag)) + - ": " + llvm::toString(MappedAddrOrError.takeError())); + Error Err = + createError("Unable to parse DT_" + + Twine(getTypeString( + ObjF->getELFFile()->getHeader()->e_machine, Tag)) + + ": " + llvm::toString(MappedAddrOrError.takeError())); + + reportWarning(std::move(Err), ObjF->getFileName()); return nullptr; } return MappedAddrOrError.get(); @@ -1576,10 +1724,29 @@ template <typename ELFT> void ELFDumper<ELFT>::parseDynamicTable() { case ELF::DT_STRSZ: StringTableSize = Dyn.getVal(); break; - case ELF::DT_SYMTAB: - DynSymRegion.Addr = toMappedAddr(Dyn.getTag(), Dyn.getPtr()); - DynSymRegion.EntSize = sizeof(Elf_Sym); + case ELF::DT_SYMTAB: { + // Often we find the information about the dynamic symbol table + // location in the SHT_DYNSYM section header. However, the value in + // DT_SYMTAB has priority, because it is used by dynamic loaders to + // locate .dynsym at runtime. The location we find in the section header + // and the location we find here should match. If we can't map the + // DT_SYMTAB value to an address (e.g. when there are no program headers), we + // ignore its value. + if (const uint8_t *VA = toMappedAddr(Dyn.getTag(), Dyn.getPtr())) { + // EntSize is non-zero if the dynamic symbol table has been found via a + // section header. + if (DynSymRegion.EntSize && VA != DynSymRegion.Addr) + reportWarning( + createError( + "SHT_DYNSYM section header and DT_SYMTAB disagree about " + "the location of the dynamic symbol table"), + ObjF->getFileName()); + + DynSymRegion.Addr = VA; + DynSymRegion.EntSize = sizeof(Elf_Sym); + } break; + } case ELF::DT_RELA: DynRelaRegion.Addr = toMappedAddr(Dyn.getTag(), Dyn.getPtr()); break; @@ -1619,8 +1786,9 @@ template <typename ELFT> void ELFDumper<ELFT>::parseDynamicTable() { else if (Dyn.getVal() == DT_RELA) DynPLTRelRegion.EntSize = sizeof(Elf_Rela); else - reportError(Twine("unknown DT_PLTREL value of ") + - Twine((uint64_t)Dyn.getVal())); + reportError(createError(Twine("unknown DT_PLTREL value of ") + + Twine((uint64_t)Dyn.getVal())), + ObjF->getFileName()); break; case ELF::DT_JMPREL: DynPLTRelRegion.Addr = toMappedAddr(Dyn.getTag(), Dyn.getPtr()); @@ -1632,8 +1800,7 @@ template <typename ELFT> void ELFDumper<ELFT>::parseDynamicTable() { } if (StringTableBegin) DynamicStringTable = StringRef(StringTableBegin, StringTableSize); - if (SONameOffset && SONameOffset < DynamicStringTable.size()) - SOName = DynamicStringTable.data() + SONameOffset; + SOName = getDynamicString(SONameOffset); } template <typename ELFT> @@ -1715,6 +1882,10 @@ template <class ELFT> void ELFDumper<ELFT>::printELFLinkerOptions() { ELFDumperStyle->printELFLinkerOptions(ObjF->getELFFile()); } +template <class ELFT> void ELFDumper<ELFT>::printStackSizes() { + ELFDumperStyle->printStackSizes(ObjF); +} + #define LLVM_READOBJ_DT_FLAG_ENT(prefix, enum) \ { #enum, prefix##_##enum } @@ -1953,13 +2124,7 @@ void ELFDumper<ELFT>::printDynamicEntry(raw_ostream &OS, uint64_t Type, {DT_RPATH, "Library rpath"}, {DT_RUNPATH, "Library runpath"}, }; - OS << TagNames.at(Type) << ": "; - if (DynamicStringTable.empty()) - OS << "<String table is empty or was not found> "; - else if (Value < DynamicStringTable.size()) - OS << "[" << StringRef(DynamicStringTable.data() + Value) << "]"; - else - OS << "<Invalid offset 0x" << utohexstr(Value) << ">"; + OS << TagNames.at(Type) << ": [" << getDynamicString(Value) << "]"; break; } case DT_FLAGS: @@ -1974,6 +2139,15 @@ void ELFDumper<ELFT>::printDynamicEntry(raw_ostream &OS, uint64_t Type, } } +template <class ELFT> +std::string ELFDumper<ELFT>::getDynamicString(uint64_t Value) const { + if (DynamicStringTable.empty()) + return "<String table is empty or was not found>"; + if (Value < DynamicStringTable.size()) + return DynamicStringTable.data() + Value; + return Twine("<Invalid offset 0x" + utohexstr(Value) + ">").str(); +} + template <class ELFT> void ELFDumper<ELFT>::printUnwindInfo() { DwarfCFIEH::PrinterContext<ELFT> Ctx(W, ObjF); Ctx.printUnwindInformation(); @@ -1985,7 +2159,8 @@ template <> void ELFDumper<ELF32LE>::printUnwindInfo() { const ELFFile<ELF32LE> *Obj = ObjF->getELFFile(); const unsigned Machine = Obj->getHeader()->e_machine; if (Machine == EM_ARM) { - ARM::EHABI::PrinterContext<ELF32LE> Ctx(W, Obj, DotSymtabSec); + ARM::EHABI::PrinterContext<ELF32LE> Ctx(W, Obj, ObjF->getFileName(), + DotSymtabSec); Ctx.PrintUnwindInformation(); } DwarfCFIEH::PrinterContext<ELF32LE> Ctx(W, ObjF); @@ -2001,17 +2176,10 @@ template <class ELFT> void ELFDumper<ELFT>::printDynamicTable() { template <class ELFT> void ELFDumper<ELFT>::printNeededLibraries() { ListScope D(W, "NeededLibraries"); - using LibsTy = std::vector<StringRef>; - LibsTy Libs; - + std::vector<std::string> Libs; for (const auto &Entry : dynamic_table()) - if (Entry.d_tag == ELF::DT_NEEDED) { - uint64_t Value = Entry.d_un.d_val; - if (Value < DynamicStringTable.size()) - Libs.push_back(StringRef(DynamicStringTable.data() + Value)); - else - Libs.push_back("<Library name index out of range>"); - } + if (Entry.d_tag == ELF::DT_NEEDED) + Libs.push_back(getDynamicString(Entry.d_un.d_val)); llvm::stable_sort(Libs); @@ -2042,7 +2210,7 @@ template <typename ELFT> void ELFDumper<ELFT>::printGnuHashTable() { Elf_Sym_Range Syms = dynamic_symbols(); unsigned NumSyms = std::distance(Syms.begin(), Syms.end()); if (!NumSyms) - reportError("No dynamic symbol section"); + reportError(createError("No dynamic symbol section"), ObjF->getFileName()); W.printHexList("Values", GnuHashTable->values(NumSyms)); } @@ -2050,6 +2218,30 @@ template <typename ELFT> void ELFDumper<ELFT>::printLoadName() { W.printString("LoadName", SOName); } +template <class ELFT> void ELFDumper<ELFT>::printArchSpecificInfo() { + const ELFFile<ELFT> *Obj = ObjF->getELFFile(); + switch (Obj->getHeader()->e_machine) { + case EM_ARM: + printAttributes(); + break; + case EM_MIPS: { + ELFDumperStyle->printMipsABIFlags(ObjF); + printMipsOptions(); + printMipsReginfo(); + + MipsGOTParser<ELFT> Parser(Obj, ObjF->getFileName(), dynamic_table(), + dynamic_symbols()); + if (Parser.hasGot()) + ELFDumperStyle->printMipsGOT(Parser); + if (Parser.hasPlt()) + ELFDumperStyle->printMipsPLT(Parser); + break; + } + default: + break; + } +} + template <class ELFT> void ELFDumper<ELFT>::printAttributes() { W.startLine() << "Attributes not implemented.\n"; } @@ -2064,11 +2256,13 @@ template <> void ELFDumper<ELF32LE>::printAttributes() { } DictScope BA(W, "BuildAttributes"); - for (const ELFO::Elf_Shdr &Sec : unwrapOrError(Obj->sections())) { + for (const ELFO::Elf_Shdr &Sec : + unwrapOrError(ObjF->getFileName(), Obj->sections())) { if (Sec.sh_type != ELF::SHT_ARM_ATTRIBUTES) continue; - ArrayRef<uint8_t> Contents = unwrapOrError(Obj->getSectionContents(&Sec)); + ArrayRef<uint8_t> Contents = + unwrapOrError(ObjF->getFileName(), Obj->getSectionContents(&Sec)); if (Contents[0] != ARMBuildAttrs::Format_Version) { errs() << "unrecognised FormatVersion: 0x" << Twine::utohexstr(Contents[0]) << '\n'; @@ -2092,7 +2286,8 @@ public: const bool IsStatic; const ELFO * const Obj; - MipsGOTParser(const ELFO *Obj, Elf_Dyn_Range DynTable, Elf_Sym_Range DynSyms); + MipsGOTParser(const ELFO *Obj, StringRef FileName, Elf_Dyn_Range DynTable, + Elf_Sym_Range DynSyms); bool hasGot() const { return !GotEntries.empty(); } bool hasPlt() const { return !PltEntries.empty(); } @@ -2126,6 +2321,8 @@ private: const Elf_Shdr *PltSec; const Elf_Shdr *PltRelSec; const Elf_Shdr *PltSymTable; + StringRef FileName; + Elf_Sym_Range GotDynSyms; StringRef PltStrTable; @@ -2136,21 +2333,24 @@ private: } // end anonymous namespace template <class ELFT> -MipsGOTParser<ELFT>::MipsGOTParser(const ELFO *Obj, Elf_Dyn_Range DynTable, +MipsGOTParser<ELFT>::MipsGOTParser(const ELFO *Obj, StringRef FileName, + Elf_Dyn_Range DynTable, Elf_Sym_Range DynSyms) : IsStatic(DynTable.empty()), Obj(Obj), GotSec(nullptr), LocalNum(0), - GlobalNum(0), PltSec(nullptr), PltRelSec(nullptr), PltSymTable(nullptr) { + GlobalNum(0), PltSec(nullptr), PltRelSec(nullptr), PltSymTable(nullptr), + FileName(FileName) { // See "Global Offset Table" in Chapter 5 in the following document // for detailed GOT description. // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf // Find static GOT secton. if (IsStatic) { - GotSec = findSectionByName(*Obj, ".got"); + GotSec = findSectionByName(*Obj, FileName, ".got"); if (!GotSec) - reportError("Cannot find .got section"); + return; - ArrayRef<uint8_t> Content = unwrapOrError(Obj->getSectionContents(GotSec)); + ArrayRef<uint8_t> Content = + unwrapOrError(FileName, Obj->getSectionContents(GotSec)); GotEntries = Entries(reinterpret_cast<const Entry *>(Content.data()), Content.size() / sizeof(Entry)); LocalNum = GotEntries.size(); @@ -2194,17 +2394,21 @@ MipsGOTParser<ELFT>::MipsGOTParser(const ELFO *Obj, Elf_Dyn_Range DynTable, size_t DynSymTotal = DynSyms.size(); if (*DtGotSym > DynSymTotal) - reportError("MIPS_GOTSYM exceeds a number of dynamic symbols"); + reportError( + createError("MIPS_GOTSYM exceeds a number of dynamic symbols"), + FileName); - GotSec = findNotEmptySectionByAddress(Obj, *DtPltGot); + GotSec = findNotEmptySectionByAddress(Obj, FileName, *DtPltGot); if (!GotSec) - reportError("There is no not empty GOT section at 0x" + - Twine::utohexstr(*DtPltGot)); + reportError(createError("There is no not empty GOT section at 0x" + + Twine::utohexstr(*DtPltGot)), + FileName); LocalNum = *DtLocalGotNum; GlobalNum = DynSymTotal - *DtGotSym; - ArrayRef<uint8_t> Content = unwrapOrError(Obj->getSectionContents(GotSec)); + ArrayRef<uint8_t> Content = + unwrapOrError(FileName, Obj->getSectionContents(GotSec)); GotEntries = Entries(reinterpret_cast<const Entry *>(Content.data()), Content.size() / sizeof(Entry)); GotDynSyms = DynSyms.drop_front(*DtGotSym); @@ -2217,23 +2421,24 @@ MipsGOTParser<ELFT>::MipsGOTParser(const ELFO *Obj, Elf_Dyn_Range DynTable, if (!DtJmpRel) report_fatal_error("Cannot find JMPREL dynamic table tag."); - PltSec = findNotEmptySectionByAddress(Obj, *DtMipsPltGot); + PltSec = findNotEmptySectionByAddress(Obj, FileName, * DtMipsPltGot); if (!PltSec) report_fatal_error("There is no not empty PLTGOT section at 0x " + Twine::utohexstr(*DtMipsPltGot)); - PltRelSec = findNotEmptySectionByAddress(Obj, *DtJmpRel); + PltRelSec = findNotEmptySectionByAddress(Obj, FileName, * DtJmpRel); if (!PltRelSec) report_fatal_error("There is no not empty RELPLT section at 0x" + Twine::utohexstr(*DtJmpRel)); ArrayRef<uint8_t> PltContent = - unwrapOrError(Obj->getSectionContents(PltSec)); + unwrapOrError(FileName, Obj->getSectionContents(PltSec)); PltEntries = Entries(reinterpret_cast<const Entry *>(PltContent.data()), PltContent.size() / sizeof(Entry)); - PltSymTable = unwrapOrError(Obj->getSection(PltRelSec->sh_link)); - PltStrTable = unwrapOrError(Obj->getStringTableForSymtab(*PltSymTable)); + PltSymTable = unwrapOrError(FileName, Obj->getSection(PltRelSec->sh_link)); + PltStrTable = + unwrapOrError(FileName, Obj->getStringTableForSymtab(*PltSymTable)); } } @@ -2334,26 +2539,16 @@ const typename MipsGOTParser<ELFT>::Elf_Sym * MipsGOTParser<ELFT>::getPltSym(const Entry *E) const { int64_t Offset = std::distance(getPltEntries().data(), E); if (PltRelSec->sh_type == ELF::SHT_REL) { - Elf_Rel_Range Rels = unwrapOrError(Obj->rels(PltRelSec)); - return unwrapOrError(Obj->getRelocationSymbol(&Rels[Offset], PltSymTable)); + Elf_Rel_Range Rels = unwrapOrError(FileName, Obj->rels(PltRelSec)); + return unwrapOrError(FileName, + Obj->getRelocationSymbol(&Rels[Offset], PltSymTable)); } else { - Elf_Rela_Range Rels = unwrapOrError(Obj->relas(PltRelSec)); - return unwrapOrError(Obj->getRelocationSymbol(&Rels[Offset], PltSymTable)); + Elf_Rela_Range Rels = unwrapOrError(FileName, Obj->relas(PltRelSec)); + return unwrapOrError(FileName, + Obj->getRelocationSymbol(&Rels[Offset], PltSymTable)); } } -template <class ELFT> void ELFDumper<ELFT>::printMipsPLTGOT() { - const ELFFile<ELFT> *Obj = ObjF->getELFFile(); - if (Obj->getHeader()->e_machine != EM_MIPS) - reportError("MIPS PLT GOT is available for MIPS targets only"); - - MipsGOTParser<ELFT> Parser(Obj, dynamic_table(), dynamic_symbols()); - if (Parser.hasGot()) - ELFDumperStyle->printMipsGOT(Parser); - if (Parser.hasPlt()) - ELFDumperStyle->printMipsPLT(Parser); -} - static const EnumEntry<unsigned> ElfMipsISAExtType[] = { {"None", Mips::AFL_EXT_NONE}, {"Broadcom SB-1", Mips::AFL_EXT_SB1}, @@ -2427,41 +2622,6 @@ static int getMipsRegisterSize(uint8_t Flag) { } } -template <class ELFT> void ELFDumper<ELFT>::printMipsABIFlags() { - const ELFFile<ELFT> *Obj = ObjF->getELFFile(); - const Elf_Shdr *Shdr = findSectionByName(*Obj, ".MIPS.abiflags"); - if (!Shdr) { - W.startLine() << "There is no .MIPS.abiflags section in the file.\n"; - return; - } - ArrayRef<uint8_t> Sec = unwrapOrError(Obj->getSectionContents(Shdr)); - if (Sec.size() != sizeof(Elf_Mips_ABIFlags<ELFT>)) { - W.startLine() << "The .MIPS.abiflags section has a wrong size.\n"; - return; - } - - auto *Flags = reinterpret_cast<const Elf_Mips_ABIFlags<ELFT> *>(Sec.data()); - - raw_ostream &OS = W.getOStream(); - DictScope GS(W, "MIPS ABI Flags"); - - W.printNumber("Version", Flags->version); - W.startLine() << "ISA: "; - if (Flags->isa_rev <= 1) - OS << format("MIPS%u", Flags->isa_level); - else - OS << format("MIPS%ur%u", Flags->isa_level, Flags->isa_rev); - OS << "\n"; - W.printEnum("ISA Extension", Flags->isa_ext, makeArrayRef(ElfMipsISAExtType)); - W.printFlags("ASEs", Flags->ases, makeArrayRef(ElfMipsASEFlags)); - W.printEnum("FP ABI", Flags->fp_abi, makeArrayRef(ElfMipsFpABIType)); - W.printNumber("GPR size", getMipsRegisterSize(Flags->gpr_size)); - W.printNumber("CPR1 size", getMipsRegisterSize(Flags->cpr1_size)); - W.printNumber("CPR2 size", getMipsRegisterSize(Flags->cpr2_size)); - W.printFlags("Flags 1", Flags->flags1, makeArrayRef(ElfMipsFlags1)); - W.printHex("Flags 2", Flags->flags2); -} - template <class ELFT> static void printMipsReginfoData(ScopedPrinter &W, const Elf_Mips_RegInfo<ELFT> &Reginfo) { @@ -2475,12 +2635,13 @@ static void printMipsReginfoData(ScopedPrinter &W, template <class ELFT> void ELFDumper<ELFT>::printMipsReginfo() { const ELFFile<ELFT> *Obj = ObjF->getELFFile(); - const Elf_Shdr *Shdr = findSectionByName(*Obj, ".reginfo"); + const Elf_Shdr *Shdr = findSectionByName(*Obj, ObjF->getFileName(), ".reginfo"); if (!Shdr) { W.startLine() << "There is no .reginfo section in the file.\n"; return; } - ArrayRef<uint8_t> Sec = unwrapOrError(Obj->getSectionContents(Shdr)); + ArrayRef<uint8_t> Sec = + unwrapOrError(ObjF->getFileName(), Obj->getSectionContents(Shdr)); if (Sec.size() != sizeof(Elf_Mips_RegInfo<ELFT>)) { W.startLine() << "The .reginfo section has a wrong size.\n"; return; @@ -2493,7 +2654,8 @@ template <class ELFT> void ELFDumper<ELFT>::printMipsReginfo() { template <class ELFT> void ELFDumper<ELFT>::printMipsOptions() { const ELFFile<ELFT> *Obj = ObjF->getELFFile(); - const Elf_Shdr *Shdr = findSectionByName(*Obj, ".MIPS.options"); + const Elf_Shdr *Shdr = + findSectionByName(*Obj, ObjF->getFileName(), ".MIPS.options"); if (!Shdr) { W.startLine() << "There is no .MIPS.options section in the file.\n"; return; @@ -2501,7 +2663,8 @@ template <class ELFT> void ELFDumper<ELFT>::printMipsOptions() { DictScope GS(W, "MIPS Options"); - ArrayRef<uint8_t> Sec = unwrapOrError(Obj->getSectionContents(Shdr)); + ArrayRef<uint8_t> Sec = + unwrapOrError(ObjF->getFileName(), Obj->getSectionContents(Shdr)); while (!Sec.empty()) { if (Sec.size() < sizeof(Elf_Mips_Options<ELFT>)) { W.startLine() << "The .MIPS.options section has a wrong size.\n"; @@ -2524,8 +2687,9 @@ template <class ELFT> void ELFDumper<ELFT>::printMipsOptions() { template <class ELFT> void ELFDumper<ELFT>::printStackMap() const { const ELFFile<ELFT> *Obj = ObjF->getELFFile(); const Elf_Shdr *StackMapSection = nullptr; - for (const auto &Sec : unwrapOrError(Obj->sections())) { - StringRef Name = unwrapOrError(Obj->getSectionName(&Sec)); + for (const auto &Sec : unwrapOrError(ObjF->getFileName(), Obj->sections())) { + StringRef Name = + unwrapOrError(ObjF->getFileName(), Obj->getSectionName(&Sec)); if (Name == ".llvm_stackmaps") { StackMapSection = &Sec; break; @@ -2535,8 +2699,8 @@ template <class ELFT> void ELFDumper<ELFT>::printStackMap() const { if (!StackMapSection) return; - ArrayRef<uint8_t> StackMapContentsArray = - unwrapOrError(Obj->getSectionContents(StackMapSection)); + ArrayRef<uint8_t> StackMapContentsArray = unwrapOrError( + ObjF->getFileName(), Obj->getSectionContents(StackMapSection)); prettyPrintStackMap( W, StackMapParser<ELFT::TargetEndianness>(StackMapContentsArray)); @@ -2560,24 +2724,26 @@ static inline void printFields(formatted_raw_ostream &OS, StringRef Str1, } template <class ELFT> -static std::string getSectionHeadersNumString(const ELFFile<ELFT> *Obj) { +static std::string getSectionHeadersNumString(const ELFFile<ELFT> *Obj, + StringRef FileName) { const typename ELFT::Ehdr *ElfHeader = Obj->getHeader(); if (ElfHeader->e_shnum != 0) return to_string(ElfHeader->e_shnum); - ArrayRef<typename ELFT::Shdr> Arr = unwrapOrError(Obj->sections()); + ArrayRef<typename ELFT::Shdr> Arr = unwrapOrError(FileName, Obj->sections()); if (Arr.empty()) return "0"; return "0 (" + to_string(Arr[0].sh_size) + ")"; } template <class ELFT> -static std::string getSectionHeaderTableIndexString(const ELFFile<ELFT> *Obj) { +static std::string getSectionHeaderTableIndexString(const ELFFile<ELFT> *Obj, + StringRef FileName) { const typename ELFT::Ehdr *ElfHeader = Obj->getHeader(); if (ElfHeader->e_shstrndx != SHN_XINDEX) return to_string(ElfHeader->e_shstrndx); - ArrayRef<typename ELFT::Shdr> Arr = unwrapOrError(Obj->sections()); + ArrayRef<typename ELFT::Shdr> Arr = unwrapOrError(FileName, Obj->sections()); if (Arr.empty()) return "65535 (corrupt: out of range)"; return to_string(ElfHeader->e_shstrndx) + " (" + to_string(Arr[0].sh_link) + @@ -2639,9 +2805,9 @@ template <class ELFT> void GNUStyle<ELFT>::printFileHeaders(const ELFO *Obj) { printFields(OS, "Number of program headers:", Str); Str = to_string(e->e_shentsize) + " (bytes)"; printFields(OS, "Size of section headers:", Str); - Str = getSectionHeadersNumString(Obj); + Str = getSectionHeadersNumString(Obj, this->FileName); printFields(OS, "Number of section headers:", Str); - Str = getSectionHeaderTableIndexString(Obj); + Str = getSectionHeaderTableIndexString(Obj, this->FileName); printFields(OS, "Section header string table index:", Str); } @@ -2663,26 +2829,29 @@ struct GroupSection { }; template <class ELFT> -std::vector<GroupSection> getGroups(const ELFFile<ELFT> *Obj) { +std::vector<GroupSection> getGroups(const ELFFile<ELFT> *Obj, + StringRef FileName) { using Elf_Shdr = typename ELFT::Shdr; using Elf_Sym = typename ELFT::Sym; using Elf_Word = typename ELFT::Word; std::vector<GroupSection> Ret; uint64_t I = 0; - for (const Elf_Shdr &Sec : unwrapOrError(Obj->sections())) { + for (const Elf_Shdr &Sec : unwrapOrError(FileName, Obj->sections())) { ++I; if (Sec.sh_type != ELF::SHT_GROUP) continue; - const Elf_Shdr *Symtab = unwrapOrError(Obj->getSection(Sec.sh_link)); - StringRef StrTable = unwrapOrError(Obj->getStringTableForSymtab(*Symtab)); - const Elf_Sym *Sym = - unwrapOrError(Obj->template getEntry<Elf_Sym>(Symtab, Sec.sh_info)); - auto Data = - unwrapOrError(Obj->template getSectionContentsAsArray<Elf_Word>(&Sec)); + const Elf_Shdr *Symtab = + unwrapOrError(FileName, Obj->getSection(Sec.sh_link)); + StringRef StrTable = + unwrapOrError(FileName, Obj->getStringTableForSymtab(*Symtab)); + const Elf_Sym *Sym = unwrapOrError( + FileName, Obj->template getEntry<Elf_Sym>(Symtab, Sec.sh_info)); + auto Data = unwrapOrError( + FileName, Obj->template getSectionContentsAsArray<Elf_Word>(&Sec)); - StringRef Name = unwrapOrError(Obj->getSectionName(&Sec)); + StringRef Name = unwrapOrError(FileName, Obj->getSectionName(&Sec)); StringRef Signature = StrTable.data() + Sym->st_name; Ret.push_back({Name, maybeDemangle(Signature), @@ -2695,8 +2864,8 @@ std::vector<GroupSection> getGroups(const ELFFile<ELFT> *Obj) { std::vector<GroupMember> &GM = Ret.back().Members; for (uint32_t Ndx : Data.slice(1)) { - auto Sec = unwrapOrError(Obj->getSection(Ndx)); - const StringRef Name = unwrapOrError(Obj->getSectionName(Sec)); + auto Sec = unwrapOrError(FileName, Obj->getSection(Ndx)); + const StringRef Name = unwrapOrError(FileName, Obj->getSectionName(Sec)); GM.push_back({Name, Ndx}); } } @@ -2715,7 +2884,7 @@ mapSectionsToGroups(ArrayRef<GroupSection> Groups) { } // namespace template <class ELFT> void GNUStyle<ELFT>::printGroupSections(const ELFO *Obj) { - std::vector<GroupSection> V = getGroups<ELFT>(Obj); + std::vector<GroupSection> V = getGroups<ELFT>(Obj, this->FileName); DenseMap<uint64_t, const GroupSection *> Map = mapSectionsToGroups(V); for (const GroupSection &G : V) { OS << "\n" @@ -2745,14 +2914,17 @@ template <class ELFT> void GNUStyle<ELFT>::printGroupSections(const ELFO *Obj) { template <class ELFT> void GNUStyle<ELFT>::printRelocation(const ELFO *Obj, const Elf_Shdr *SymTab, const Elf_Rela &R, bool IsRela) { - const Elf_Sym *Sym = unwrapOrError(Obj->getRelocationSymbol(&R, SymTab)); + const Elf_Sym *Sym = + unwrapOrError(this->FileName, Obj->getRelocationSymbol(&R, SymTab)); std::string TargetName; if (Sym && Sym->getType() == ELF::STT_SECTION) { const Elf_Shdr *Sec = unwrapOrError( + this->FileName, Obj->getSection(Sym, SymTab, this->dumper()->getShndxTable())); - TargetName = unwrapOrError(Obj->getSectionName(Sec)); + TargetName = unwrapOrError(this->FileName, Obj->getSectionName(Sec)); } else if (Sym) { - StringRef StrTable = unwrapOrError(Obj->getStringTableForSymtab(*SymTab)); + StringRef StrTable = + unwrapOrError(this->FileName, Obj->getStringTableForSymtab(*SymTab)); TargetName = this->dumper()->getFullSymbolName( Sym, StrTable, SymTab->sh_type == SHT_DYNSYM /* IsDynamic */); } @@ -2821,21 +2993,21 @@ template <class ELFT> void GNUStyle<ELFT>::printRelocHeader(unsigned SType) { template <class ELFT> void GNUStyle<ELFT>::printRelocations(const ELFO *Obj) { bool HasRelocSections = false; - for (const Elf_Shdr &Sec : unwrapOrError(Obj->sections())) { + for (const Elf_Shdr &Sec : unwrapOrError(this->FileName, Obj->sections())) { if (Sec.sh_type != ELF::SHT_REL && Sec.sh_type != ELF::SHT_RELA && Sec.sh_type != ELF::SHT_RELR && Sec.sh_type != ELF::SHT_ANDROID_REL && Sec.sh_type != ELF::SHT_ANDROID_RELA && Sec.sh_type != ELF::SHT_ANDROID_RELR) continue; HasRelocSections = true; - StringRef Name = unwrapOrError(Obj->getSectionName(&Sec)); + StringRef Name = unwrapOrError(this->FileName, Obj->getSectionName(&Sec)); unsigned Entries = Sec.getEntityCount(); std::vector<Elf_Rela> AndroidRelas; if (Sec.sh_type == ELF::SHT_ANDROID_REL || Sec.sh_type == ELF::SHT_ANDROID_RELA) { // Android's packed relocation section needs to be unpacked first // to get the actual number of entries. - AndroidRelas = unwrapOrError(Obj->android_relas(&Sec)); + AndroidRelas = unwrapOrError(this->FileName, Obj->android_relas(&Sec)); Entries = AndroidRelas.size(); } std::vector<Elf_Rela> RelrRelas; @@ -2843,8 +3015,8 @@ template <class ELFT> void GNUStyle<ELFT>::printRelocations(const ELFO *Obj) { Sec.sh_type == ELF::SHT_ANDROID_RELR)) { // .relr.dyn relative relocation section needs to be unpacked first // to get the actual number of entries. - Elf_Relr_Range Relrs = unwrapOrError(Obj->relrs(&Sec)); - RelrRelas = unwrapOrError(Obj->decode_relrs(Relrs)); + Elf_Relr_Range Relrs = unwrapOrError(this->FileName, Obj->relrs(&Sec)); + RelrRelas = unwrapOrError(this->FileName, Obj->decode_relrs(Relrs)); Entries = RelrRelas.size(); } uintX_t Offset = Sec.sh_offset; @@ -2852,10 +3024,11 @@ template <class ELFT> void GNUStyle<ELFT>::printRelocations(const ELFO *Obj) { << to_hexString(Offset, false) << " contains " << Entries << " entries:\n"; printRelocHeader(Sec.sh_type); - const Elf_Shdr *SymTab = unwrapOrError(Obj->getSection(Sec.sh_link)); + const Elf_Shdr *SymTab = + unwrapOrError(this->FileName, Obj->getSection(Sec.sh_link)); switch (Sec.sh_type) { case ELF::SHT_REL: - for (const auto &R : unwrapOrError(Obj->rels(&Sec))) { + for (const auto &R : unwrapOrError(this->FileName, Obj->rels(&Sec))) { Elf_Rela Rela; Rela.r_offset = R.r_offset; Rela.r_info = R.r_info; @@ -2864,13 +3037,13 @@ template <class ELFT> void GNUStyle<ELFT>::printRelocations(const ELFO *Obj) { } break; case ELF::SHT_RELA: - for (const auto &R : unwrapOrError(Obj->relas(&Sec))) + for (const auto &R : unwrapOrError(this->FileName, Obj->relas(&Sec))) printRelocation(Obj, SymTab, R, true); break; case ELF::SHT_RELR: case ELF::SHT_ANDROID_RELR: if (opts::RawRelr) - for (const auto &R : unwrapOrError(Obj->relrs(&Sec))) + for (const auto &R : unwrapOrError(this->FileName, Obj->relrs(&Sec))) OS << to_string(format_hex_no_prefix(R, ELFT::Is64Bits ? 16 : 8)) << "\n"; else @@ -2992,6 +3165,12 @@ static std::string getSectionTypeString(unsigned Arch, unsigned Type) { return "LLVM_ADDRSIG"; case SHT_LLVM_DEPENDENT_LIBRARIES: return "LLVM_DEPENDENT_LIBRARIES"; + case SHT_LLVM_SYMPART: + return "LLVM_SYMPART"; + case SHT_LLVM_PART_EHDR: + return "LLVM_PART_EHDR"; + case SHT_LLVM_PART_PHDR: + return "LLVM_PART_PHDR"; // FIXME: Parse processor specific GNU attributes case SHT_GNU_ATTRIBUTES: return "ATTRIBUTES"; @@ -3010,29 +3189,9 @@ static std::string getSectionTypeString(unsigned Arch, unsigned Type) { } template <class ELFT> -static StringRef getSectionName(const typename ELFT::Shdr &Sec, - const ELFObjectFile<ELFT> &ElfObj, - ArrayRef<typename ELFT::Shdr> Sections) { - const ELFFile<ELFT> &Obj = *ElfObj.getELFFile(); - uint32_t Index = Obj.getHeader()->e_shstrndx; - if (Index == ELF::SHN_XINDEX) - Index = Sections[0].sh_link; - if (!Index) // no section string table. - return ""; - // TODO: Test a case when the sh_link of the section with index 0 is broken. - if (Index >= Sections.size()) - reportError(ElfObj.getFileName(), - createError("section header string table index " + - Twine(Index) + " does not exist")); - StringRef Data = toStringRef(unwrapOrError( - Obj.template getSectionContentsAsArray<uint8_t>(&Sections[Index]))); - return unwrapOrError(Obj.getSectionName(&Sec, Data)); -} - -template <class ELFT> void GNUStyle<ELFT>::printSectionHeaders(const ELFO *Obj) { unsigned Bias = ELFT::Is64Bits ? 0 : 8; - ArrayRef<Elf_Shdr> Sections = unwrapOrError(Obj->sections()); + ArrayRef<Elf_Shdr> Sections = unwrapOrError(this->FileName, Obj->sections()); OS << "There are " << to_string(Sections.size()) << " section headers, starting at offset " << "0x" << to_hexString(Obj->getHeader()->e_shoff, false) << ":\n\n"; @@ -3050,7 +3209,8 @@ void GNUStyle<ELFT>::printSectionHeaders(const ELFO *Obj) { size_t SectionIndex = 0; for (const Elf_Shdr &Sec : Sections) { Fields[0].Str = to_string(SectionIndex); - Fields[1].Str = getSectionName(Sec, *ElfObj, Sections); + Fields[1].Str = unwrapOrError<StringRef>( + ElfObj->getFileName(), Obj->getSectionName(&Sec, this->WarningHandler)); Fields[2].Str = getSectionTypeString(Obj->getHeader()->e_machine, Sec.sh_type); Fields[3].Str = @@ -3089,7 +3249,8 @@ void GNUStyle<ELFT>::printSectionHeaders(const ELFO *Obj) { template <class ELFT> void GNUStyle<ELFT>::printSymtabMessage(const ELFO *Obj, StringRef Name, - size_t Entries) { + size_t Entries, + bool NonVisibilityBitsUsed) { if (!Name.empty()) OS << "\nSymbol table '" << Name << "' contains " << Entries << " entries:\n"; @@ -3097,9 +3258,13 @@ void GNUStyle<ELFT>::printSymtabMessage(const ELFO *Obj, StringRef Name, OS << "\n Symbol table for image:\n"; if (ELFT::Is64Bits) - OS << " Num: Value Size Type Bind Vis Ndx Name\n"; + OS << " Num: Value Size Type Bind Vis"; else - OS << " Num: Value Size Type Bind Vis Ndx Name\n"; + OS << " Num: Value Size Type Bind Vis"; + + if (NonVisibilityBitsUsed) + OS << " "; + OS << " Ndx Name\n"; } template <class ELFT> @@ -3115,10 +3280,11 @@ std::string GNUStyle<ELFT>::getSymbolSectionNdx(const ELFO *Obj, case ELF::SHN_COMMON: return "COM"; case ELF::SHN_XINDEX: - return to_string( - format_decimal(unwrapOrError(object::getExtendedSymbolTableIndex<ELFT>( - Symbol, FirstSym, this->dumper()->getShndxTable())), - 3)); + return to_string(format_decimal( + unwrapOrError(this->FileName, + object::getExtendedSymbolTableIndex<ELFT>( + Symbol, FirstSym, this->dumper()->getShndxTable())), + 3)); default: // Find if: // Processor specific @@ -3142,7 +3308,7 @@ std::string GNUStyle<ELFT>::getSymbolSectionNdx(const ELFO *Obj, template <class ELFT> void GNUStyle<ELFT>::printSymbol(const ELFO *Obj, const Elf_Sym *Symbol, const Elf_Sym *FirstSym, StringRef StrTable, - bool IsDynamic) { + bool IsDynamic, bool NonVisibilityBitsUsed) { static int Idx = 0; static bool Dynamic = true; @@ -3156,7 +3322,7 @@ void GNUStyle<ELFT>::printSymbol(const ELFO *Obj, const Elf_Sym *Symbol, unsigned Bias = ELFT::Is64Bits ? 8 : 0; Field Fields[8] = {0, 8, 17 + Bias, 23 + Bias, - 31 + Bias, 38 + Bias, 47 + Bias, 51 + Bias}; + 31 + Bias, 38 + Bias, 48 + Bias, 51 + Bias}; Fields[0].Str = to_string(format_decimal(Idx++, 6)) + ":"; Fields[1].Str = to_string( format_hex_no_prefix(Symbol->st_value, ELFT::Is64Bits ? 16 : 8)); @@ -3173,7 +3339,13 @@ void GNUStyle<ELFT>::printSymbol(const ELFO *Obj, const Elf_Sym *Symbol, printEnum(Symbol->getBinding(), makeArrayRef(ElfSymbolBindings)); Fields[5].Str = printEnum(Symbol->getVisibility(), makeArrayRef(ElfSymbolVisibilities)); + if (Symbol->st_other & ~0x3) + Fields[5].Str += + " [<other: " + to_string(format_hex(Symbol->st_other, 2)) + ">]"; + + Fields[6].Column += NonVisibilityBitsUsed ? 13 : 0; Fields[6].Str = getSymbolSectionNdx(Obj, Symbol, FirstSym); + Fields[7].Str = this->dumper()->getFullSymbolName(Symbol, StrTable, IsDynamic); for (auto &Entry : Fields) @@ -3193,7 +3365,7 @@ void GNUStyle<ELFT>::printHashedSymbol(const ELFO *Obj, const Elf_Sym *FirstSym, const auto Symbol = FirstSym + Sym; Fields[2].Str = to_string( - format_hex_no_prefix(Symbol->st_value, ELFT::Is64Bits ? 18 : 8)); + format_hex_no_prefix(Symbol->st_value, ELFT::Is64Bits ? 16 : 8)); Fields[3].Str = to_string(format_decimal(Symbol->st_size, 5)); unsigned char SymbolType = Symbol->getType(); @@ -3246,10 +3418,21 @@ template <class ELFT> void GNUStyle<ELFT>::printHashSymbols(const ELFO *Obj) { for (uint32_t Buc = 0; Buc < SysVHash->nbucket; Buc++) { if (Buckets[Buc] == ELF::STN_UNDEF) continue; + std::vector<bool> Visited(SysVHash->nchain); for (uint32_t Ch = Buckets[Buc]; Ch < SysVHash->nchain; Ch = Chains[Ch]) { if (Ch == ELF::STN_UNDEF) break; + + if (Visited[Ch]) { + reportWarning( + createError(".hash section is invalid: bucket " + Twine(Ch) + + ": a cycle was detected in the linked chain"), + this->FileName); + break; + } + printHashedSymbol(Obj, &DynSyms[0], Ch, StringTable, Buc); + Visited[Ch] = true; } } } @@ -3380,7 +3563,8 @@ void GNUStyle<ELFT>::printProgramHeaders(const ELFO *Obj) { unsigned Width = ELFT::Is64Bits ? 18 : 10; unsigned SizeWidth = ELFT::Is64Bits ? 8 : 7; - for (const auto &Phdr : unwrapOrError(Obj->program_headers())) { + for (const auto &Phdr : + unwrapOrError(this->FileName, Obj->program_headers())) { Fields[0].Str = getElfPtType(Header->e_machine, Phdr.p_type); Fields[1].Str = to_string(format_hex(Phdr.p_offset, 8)); Fields[2].Str = to_string(format_hex(Phdr.p_vaddr, Width)); @@ -3404,10 +3588,11 @@ void GNUStyle<ELFT>::printSectionMapping(const ELFO *Obj) { OS << "\n Section to Segment mapping:\n Segment Sections...\n"; DenseSet<const Elf_Shdr *> BelongsToSegment; int Phnum = 0; - for (const Elf_Phdr &Phdr : unwrapOrError(Obj->program_headers())) { + for (const Elf_Phdr &Phdr : + unwrapOrError(this->FileName, Obj->program_headers())) { std::string Sections; OS << format(" %2.2d ", Phnum++); - for (const Elf_Shdr &Sec : unwrapOrError(Obj->sections())) { + for (const Elf_Shdr &Sec : unwrapOrError(this->FileName, Obj->sections())) { // Check if each section is in a segment and then print mapping. // readelf additionally makes sure it does not print zero sized sections // at end of segments and for PT_DYNAMIC both start and end of section @@ -3418,7 +3603,9 @@ void GNUStyle<ELFT>::printSectionMapping(const ELFO *Obj) { if (!TbssInNonTLS && checkTLSSections(Phdr, Sec) && checkoffsets(Phdr, Sec) && checkVMA(Phdr, Sec) && checkPTDynamic(Phdr, Sec) && (Sec.sh_type != ELF::SHT_NULL)) { - Sections += unwrapOrError(Obj->getSectionName(&Sec)).str() + " "; + Sections += + unwrapOrError(this->FileName, Obj->getSectionName(&Sec)).str() + + " "; BelongsToSegment.insert(&Sec); } } @@ -3428,9 +3615,10 @@ void GNUStyle<ELFT>::printSectionMapping(const ELFO *Obj) { // Display sections that do not belong to a segment. std::string Sections; - for (const Elf_Shdr &Sec : unwrapOrError(Obj->sections())) { + for (const Elf_Shdr &Sec : unwrapOrError(this->FileName, Obj->sections())) { if (BelongsToSegment.find(&Sec) == BelongsToSegment.end()) - Sections += unwrapOrError(Obj->getSectionName(&Sec)).str() + ' '; + Sections += + unwrapOrError(this->FileName, Obj->getSectionName(&Sec)).str() + ' '; } if (!Sections.empty()) { OS << " None " << Sections << '\n'; @@ -3438,14 +3626,40 @@ void GNUStyle<ELFT>::printSectionMapping(const ELFO *Obj) { } } +namespace { +template <class ELFT> struct RelSymbol { + const typename ELFT::Sym *Sym; + std::string Name; +}; + +template <class ELFT> +RelSymbol<ELFT> getSymbolForReloc(const ELFFile<ELFT> *Obj, StringRef FileName, + const ELFDumper<ELFT> *Dumper, + const typename ELFT::Rela &Reloc) { + uint32_t SymIndex = Reloc.getSymbol(Obj->isMips64EL()); + const typename ELFT::Sym *Sym = Dumper->dynamic_symbols().begin() + SymIndex; + Expected<StringRef> ErrOrName = Sym->getName(Dumper->getDynamicStringTable()); + + std::string Name; + if (ErrOrName) { + Name = maybeDemangle(*ErrOrName); + } else { + reportWarning( + createError("unable to get name of the dynamic symbol with index " + + Twine(SymIndex) + ": " + toString(ErrOrName.takeError())), + FileName); + Name = "<corrupt>"; + } + + return {Sym, std::move(Name)}; +} +} // namespace + template <class ELFT> void GNUStyle<ELFT>::printDynamicRelocation(const ELFO *Obj, Elf_Rela R, bool IsRela) { - uint32_t SymIndex = R.getSymbol(Obj->isMips64EL()); - const Elf_Sym *Sym = this->dumper()->dynamic_symbols().begin() + SymIndex; - std::string SymbolName = maybeDemangle( - unwrapOrError(Sym->getName(this->dumper()->getDynamicStringTable()))); - printRelocation(Obj, Sym, SymbolName, R, IsRela); + RelSymbol<ELFT> S = getSymbolForReloc(Obj, this->FileName, this->dumper(), R); + printRelocation(Obj, S.Sym, S.Name, R, IsRela); } template <class ELFT> void GNUStyle<ELFT>::printDynamic(const ELFO *Obj) { @@ -3518,7 +3732,8 @@ void GNUStyle<ELFT>::printDynamicRelocations(const ELFO *Obj) { << " contains " << DynRelrRegion.Size << " bytes:\n"; printRelocHeader(ELF::SHT_REL); Elf_Relr_Range Relrs = this->dumper()->dyn_relrs(); - std::vector<Elf_Rela> RelrRelas = unwrapOrError(Obj->decode_relrs(Relrs)); + std::vector<Elf_Rela> RelrRelas = + unwrapOrError(this->FileName, Obj->decode_relrs(Relrs)); for (const Elf_Rela &Rela : RelrRelas) { printDynamicRelocation(Obj, Rela, false); } @@ -3550,14 +3765,15 @@ template <class ELFT> static void printGNUVersionSectionProlog(formatted_raw_ostream &OS, const Twine &Name, unsigned EntriesNum, const ELFFile<ELFT> *Obj, - const typename ELFT::Shdr *Sec) { - StringRef SecName = unwrapOrError(Obj->getSectionName(Sec)); + const typename ELFT::Shdr *Sec, + StringRef FileName) { + StringRef SecName = unwrapOrError(FileName, Obj->getSectionName(Sec)); OS << Name << " section '" << SecName << "' " << "contains " << EntriesNum << " entries:\n"; const typename ELFT::Shdr *SymTab = - unwrapOrError(Obj->getSection(Sec->sh_link)); - StringRef SymTabName = unwrapOrError(Obj->getSectionName(SymTab)); + unwrapOrError(FileName, Obj->getSection(Sec->sh_link)); + StringRef SymTabName = unwrapOrError(FileName, Obj->getSectionName(SymTab)); OS << " Addr: " << format_hex_no_prefix(Sec->sh_addr, 16) << " Offset: " << format_hex(Sec->sh_offset, 8) << " Link: " << Sec->sh_link << " (" << SymTabName << ")\n"; @@ -3570,7 +3786,8 @@ void GNUStyle<ELFT>::printVersionSymbolSection(const ELFFile<ELFT> *Obj, return; unsigned Entries = Sec->sh_size / sizeof(Elf_Versym); - printGNUVersionSectionProlog(OS, "Version symbols", Entries, Obj, Sec); + printGNUVersionSectionProlog(OS, "Version symbols", Entries, Obj, Sec, + this->FileName); const uint8_t *VersymBuf = reinterpret_cast<const uint8_t *>(Obj->base() + Sec->sh_offset); @@ -3642,14 +3859,17 @@ void GNUStyle<ELFT>::printVersionDefinitionSection(const ELFFile<ELFT> *Obj, return; unsigned VerDefsNum = Sec->sh_info; - printGNUVersionSectionProlog(OS, "Version definition", VerDefsNum, Obj, Sec); + printGNUVersionSectionProlog(OS, "Version definition", VerDefsNum, Obj, Sec, + this->FileName); - const Elf_Shdr *StrTabSec = unwrapOrError(Obj->getSection(Sec->sh_link)); + const Elf_Shdr *StrTabSec = + unwrapOrError(this->FileName, Obj->getSection(Sec->sh_link)); StringRef StringTable( reinterpret_cast<const char *>(Obj->base() + StrTabSec->sh_offset), (size_t)StrTabSec->sh_size); - const uint8_t *VerdefBuf = unwrapOrError(Obj->getSectionContents(Sec)).data(); + const uint8_t *VerdefBuf = + unwrapOrError(this->FileName, Obj->getSectionContents(Sec)).data(); const uint8_t *Begin = VerdefBuf; while (VerDefsNum--) { @@ -3684,11 +3904,14 @@ void GNUStyle<ELFT>::printVersionDependencySection(const ELFFile<ELFT> *Obj, return; unsigned VerneedNum = Sec->sh_info; - printGNUVersionSectionProlog(OS, "Version needs", VerneedNum, Obj, Sec); + printGNUVersionSectionProlog(OS, "Version needs", VerneedNum, Obj, Sec, + this->FileName); - ArrayRef<uint8_t> SecData = unwrapOrError(Obj->getSectionContents(Sec)); + ArrayRef<uint8_t> SecData = + unwrapOrError(this->FileName, Obj->getSectionContents(Sec)); - const Elf_Shdr *StrTabSec = unwrapOrError(Obj->getSection(Sec->sh_link)); + const Elf_Shdr *StrTabSec = + unwrapOrError(this->FileName, Obj->getSection(Sec->sh_link)); StringRef StringTable = { reinterpret_cast<const char *>(Obj->base() + StrTabSec->sh_offset), (size_t)StrTabSec->sh_size}; @@ -3745,9 +3968,21 @@ void GNUStyle<ELFT>::printHashHistogram(const ELFFile<ELFT> *Obj) { // Go over all buckets and and note chain lengths of each bucket (total // unique chain lengths). for (size_t B = 0; B < NBucket; B++) { - for (size_t C = Buckets[B]; C > 0 && C < NChain; C = Chains[C]) + std::vector<bool> Visited(NChain); + for (size_t C = Buckets[B]; C < NChain; C = Chains[C]) { + if (C == ELF::STN_UNDEF) + break; + if (Visited[C]) { + reportWarning( + createError(".hash section is invalid: bucket " + Twine(C) + + ": a cycle was detected in the linked chain"), + this->FileName); + break; + } + Visited[C] = true; if (MaxChain <= ++ChainLen[B]) MaxChain++; + } TotalSyms += ChainLen[B]; } @@ -3829,7 +4064,7 @@ void GNUStyle<ELFT>::printCGProfile(const ELFFile<ELFT> *Obj) { template <class ELFT> void GNUStyle<ELFT>::printAddrsig(const ELFFile<ELFT> *Obj) { - OS << "GNUStyle::printAddrsig not implemented\n"; + reportError(createError("--addrsig: not implemented"), this->FileName); } static StringRef getGenericNoteTypeName(const uint32_t NT) { @@ -3850,6 +4085,86 @@ static StringRef getGenericNoteTypeName(const uint32_t NT) { return ""; } +static StringRef getCoreNoteTypeName(const uint32_t NT) { + static const struct { + uint32_t ID; + const char *Name; + } Notes[] = { + {ELF::NT_PRSTATUS, "NT_PRSTATUS (prstatus structure)"}, + {ELF::NT_FPREGSET, "NT_FPREGSET (floating point registers)"}, + {ELF::NT_PRPSINFO, "NT_PRPSINFO (prpsinfo structure)"}, + {ELF::NT_TASKSTRUCT, "NT_TASKSTRUCT (task structure)"}, + {ELF::NT_AUXV, "NT_AUXV (auxiliary vector)"}, + {ELF::NT_PSTATUS, "NT_PSTATUS (pstatus structure)"}, + {ELF::NT_FPREGS, "NT_FPREGS (floating point registers)"}, + {ELF::NT_PSINFO, "NT_PSINFO (psinfo structure)"}, + {ELF::NT_LWPSTATUS, "NT_LWPSTATUS (lwpstatus_t structure)"}, + {ELF::NT_LWPSINFO, "NT_LWPSINFO (lwpsinfo_t structure)"}, + {ELF::NT_WIN32PSTATUS, "NT_WIN32PSTATUS (win32_pstatus structure)"}, + + {ELF::NT_PPC_VMX, "NT_PPC_VMX (ppc Altivec registers)"}, + {ELF::NT_PPC_VSX, "NT_PPC_VSX (ppc VSX registers)"}, + {ELF::NT_PPC_TAR, "NT_PPC_TAR (ppc TAR register)"}, + {ELF::NT_PPC_PPR, "NT_PPC_PPR (ppc PPR register)"}, + {ELF::NT_PPC_DSCR, "NT_PPC_DSCR (ppc DSCR register)"}, + {ELF::NT_PPC_EBB, "NT_PPC_EBB (ppc EBB registers)"}, + {ELF::NT_PPC_PMU, "NT_PPC_PMU (ppc PMU registers)"}, + {ELF::NT_PPC_TM_CGPR, "NT_PPC_TM_CGPR (ppc checkpointed GPR registers)"}, + {ELF::NT_PPC_TM_CFPR, + "NT_PPC_TM_CFPR (ppc checkpointed floating point registers)"}, + {ELF::NT_PPC_TM_CVMX, + "NT_PPC_TM_CVMX (ppc checkpointed Altivec registers)"}, + {ELF::NT_PPC_TM_CVSX, "NT_PPC_TM_CVSX (ppc checkpointed VSX registers)"}, + {ELF::NT_PPC_TM_SPR, "NT_PPC_TM_SPR (ppc TM special purpose registers)"}, + {ELF::NT_PPC_TM_CTAR, "NT_PPC_TM_CTAR (ppc checkpointed TAR register)"}, + {ELF::NT_PPC_TM_CPPR, "NT_PPC_TM_CPPR (ppc checkpointed PPR register)"}, + {ELF::NT_PPC_TM_CDSCR, + "NT_PPC_TM_CDSCR (ppc checkpointed DSCR register)"}, + + {ELF::NT_386_TLS, "NT_386_TLS (x86 TLS information)"}, + {ELF::NT_386_IOPERM, "NT_386_IOPERM (x86 I/O permissions)"}, + {ELF::NT_X86_XSTATE, "NT_X86_XSTATE (x86 XSAVE extended state)"}, + + {ELF::NT_S390_HIGH_GPRS, + "NT_S390_HIGH_GPRS (s390 upper register halves)"}, + {ELF::NT_S390_TIMER, "NT_S390_TIMER (s390 timer register)"}, + {ELF::NT_S390_TODCMP, "NT_S390_TODCMP (s390 TOD comparator register)"}, + {ELF::NT_S390_TODPREG, + "NT_S390_TODPREG (s390 TOD programmable register)"}, + {ELF::NT_S390_CTRS, "NT_S390_CTRS (s390 control registers)"}, + {ELF::NT_S390_PREFIX, "NT_S390_PREFIX (s390 prefix register)"}, + {ELF::NT_S390_LAST_BREAK, + "NT_S390_LAST_BREAK (s390 last breaking event address)"}, + {ELF::NT_S390_SYSTEM_CALL, + "NT_S390_SYSTEM_CALL (s390 system call restart data)"}, + {ELF::NT_S390_TDB, "NT_S390_TDB (s390 transaction diagnostic block)"}, + {ELF::NT_S390_VXRS_LOW, + "NT_S390_VXRS_LOW (s390 vector registers 0-15 upper half)"}, + {ELF::NT_S390_VXRS_HIGH, + "NT_S390_VXRS_HIGH (s390 vector registers 16-31)"}, + {ELF::NT_S390_GS_CB, "NT_S390_GS_CB (s390 guarded-storage registers)"}, + {ELF::NT_S390_GS_BC, + "NT_S390_GS_BC (s390 guarded-storage broadcast control)"}, + + {ELF::NT_ARM_VFP, "NT_ARM_VFP (arm VFP registers)"}, + {ELF::NT_ARM_TLS, "NT_ARM_TLS (AArch TLS registers)"}, + {ELF::NT_ARM_HW_BREAK, + "NT_ARM_HW_BREAK (AArch hardware breakpoint registers)"}, + {ELF::NT_ARM_HW_WATCH, + "NT_ARM_HW_WATCH (AArch hardware watchpoint registers)"}, + + {ELF::NT_FILE, "NT_FILE (mapped files)"}, + {ELF::NT_PRXFPREG, "NT_PRXFPREG (user_xfpregs structure)"}, + {ELF::NT_SIGINFO, "NT_SIGINFO (siginfo_t data)"}, + }; + + for (const auto &Note : Notes) + if (Note.ID == NT) + return Note.Name; + + return ""; +} + static std::string getGNUNoteTypeName(const uint32_t NT) { static const struct { uint32_t ID; @@ -4207,13 +4522,85 @@ static AMDGPUNote getAMDGPUNote(uint32_t NoteType, ArrayRef<uint8_t> Desc) { } } +struct CoreFileMapping { + uint64_t Start, End, Offset; + StringRef Filename; +}; + +struct CoreNote { + uint64_t PageSize; + std::vector<CoreFileMapping> Mappings; +}; + +static Expected<CoreNote> readCoreNote(DataExtractor Desc) { + // Expected format of the NT_FILE note description: + // 1. # of file mappings (call it N) + // 2. Page size + // 3. N (start, end, offset) triples + // 4. N packed filenames (null delimited) + // Each field is an Elf_Addr, except for filenames which are char* strings. + + CoreNote Ret; + const int Bytes = Desc.getAddressSize(); + + if (!Desc.isValidOffsetForAddress(2)) + return createStringError(object_error::parse_failed, + "malformed note: header too short"); + if (Desc.getData().back() != 0) + return createStringError(object_error::parse_failed, + "malformed note: not NUL terminated"); + + uint64_t DescOffset = 0; + uint64_t FileCount = Desc.getAddress(&DescOffset); + Ret.PageSize = Desc.getAddress(&DescOffset); + + if (!Desc.isValidOffsetForAddress(3 * FileCount * Bytes)) + return createStringError(object_error::parse_failed, + "malformed note: too short for number of files"); + + uint64_t FilenamesOffset = 0; + DataExtractor Filenames( + Desc.getData().drop_front(DescOffset + 3 * FileCount * Bytes), + Desc.isLittleEndian(), Desc.getAddressSize()); + + Ret.Mappings.resize(FileCount); + for (CoreFileMapping &Mapping : Ret.Mappings) { + if (!Filenames.isValidOffsetForDataOfSize(FilenamesOffset, 1)) + return createStringError(object_error::parse_failed, + "malformed note: too few filenames"); + Mapping.Start = Desc.getAddress(&DescOffset); + Mapping.End = Desc.getAddress(&DescOffset); + Mapping.Offset = Desc.getAddress(&DescOffset); + Mapping.Filename = Filenames.getCStrRef(&FilenamesOffset); + } + + return Ret; +} + +template <typename ELFT> +static void printCoreNote(raw_ostream &OS, const CoreNote &Note) { + // Length of "0x<address>" string. + const int FieldWidth = ELFT::Is64Bits ? 18 : 10; + + OS << " Page size: " << format_decimal(Note.PageSize, 0) << '\n'; + OS << " " << right_justify("Start", FieldWidth) << " " + << right_justify("End", FieldWidth) << " " + << right_justify("Page Offset", FieldWidth) << '\n'; + for (const CoreFileMapping &Mapping : Note.Mappings) { + OS << " " << format_hex(Mapping.Start, FieldWidth) << " " + << format_hex(Mapping.End, FieldWidth) << " " + << format_hex(Mapping.Offset, FieldWidth) << "\n " + << Mapping.Filename << '\n'; + } +} + template <class ELFT> void GNUStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) { auto PrintHeader = [&](const typename ELFT::Off Offset, const typename ELFT::Addr Size) { OS << "Displaying notes found at file offset " << format_hex(Offset, 10) << " with length " << format_hex(Size, 10) << ":\n" - << " Owner Data size\tDescription\n"; + << " Owner Data size \tDescription\n"; }; auto ProcessNote = [&](const Elf_Note &Note) { @@ -4221,55 +4608,81 @@ void GNUStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) { ArrayRef<uint8_t> Descriptor = Note.getDesc(); Elf_Word Type = Note.getType(); - OS << " " << Name << std::string(22 - Name.size(), ' ') + // Print the note owner/type. + OS << " " << left_justify(Name, 20) << ' ' << format_hex(Descriptor.size(), 10) << '\t'; - if (Name == "GNU") { OS << getGNUNoteTypeName(Type) << '\n'; - printGNUNote<ELFT>(OS, Type, Descriptor); } else if (Name == "FreeBSD") { OS << getFreeBSDNoteTypeName(Type) << '\n'; } else if (Name == "AMD") { OS << getAMDNoteTypeName(Type) << '\n'; + } else if (Name == "AMDGPU") { + OS << getAMDGPUNoteTypeName(Type) << '\n'; + } else { + StringRef NoteType = Obj->getHeader()->e_type == ELF::ET_CORE + ? getCoreNoteTypeName(Type) + : getGenericNoteTypeName(Type); + if (!NoteType.empty()) + OS << NoteType << '\n'; + else + OS << "Unknown note type: (" << format_hex(Type, 10) << ")\n"; + } + + // Print the description, or fallback to printing raw bytes for unknown + // owners. + if (Name == "GNU") { + printGNUNote<ELFT>(OS, Type, Descriptor); + } else if (Name == "AMD") { const AMDNote N = getAMDNote<ELFT>(Type, Descriptor); if (!N.Type.empty()) OS << " " << N.Type << ":\n " << N.Value << '\n'; } else if (Name == "AMDGPU") { - OS << getAMDGPUNoteTypeName(Type) << '\n'; const AMDGPUNote N = getAMDGPUNote<ELFT>(Type, Descriptor); if (!N.Type.empty()) OS << " " << N.Type << ":\n " << N.Value << '\n'; - } else { - StringRef NoteType = getGenericNoteTypeName(Type); - if (!NoteType.empty()) - OS << NoteType; - else - OS << "Unknown note type: (" << format_hex(Type, 10) << ')'; + } else if (Name == "CORE") { + if (Type == ELF::NT_FILE) { + DataExtractor DescExtractor(Descriptor, + ELFT::TargetEndianness == support::little, + sizeof(Elf_Addr)); + Expected<CoreNote> Note = readCoreNote(DescExtractor); + if (Note) + printCoreNote<ELFT>(OS, *Note); + else + reportWarning(Note.takeError(), this->FileName); + } + } else if (!Descriptor.empty()) { + OS << " description data:"; + for (uint8_t B : Descriptor) + OS << " " << format("%02x", B); + OS << '\n'; } - OS << '\n'; }; - if (Obj->getHeader()->e_type == ELF::ET_CORE) { - for (const auto &P : unwrapOrError(Obj->program_headers())) { - if (P.p_type != PT_NOTE) + ArrayRef<Elf_Shdr> Sections = unwrapOrError(this->FileName, Obj->sections()); + if (Obj->getHeader()->e_type != ELF::ET_CORE && !Sections.empty()) { + for (const auto &S : Sections) { + if (S.sh_type != SHT_NOTE) continue; - PrintHeader(P.p_offset, P.p_filesz); + PrintHeader(S.sh_offset, S.sh_size); Error Err = Error::success(); - for (const auto &Note : Obj->notes(P, Err)) + for (const auto &Note : Obj->notes(S, Err)) ProcessNote(Note); if (Err) - error(std::move(Err)); + reportError(std::move(Err), this->FileName); } } else { - for (const auto &S : unwrapOrError(Obj->sections())) { - if (S.sh_type != SHT_NOTE) + for (const auto &P : + unwrapOrError(this->FileName, Obj->program_headers())) { + if (P.p_type != PT_NOTE) continue; - PrintHeader(S.sh_offset, S.sh_size); + PrintHeader(P.p_offset, P.p_filesz); Error Err = Error::success(); - for (const auto &Note : Obj->notes(S, Err)) + for (const auto &Note : Obj->notes(P, Err)) ProcessNote(Note); if (Err) - error(std::move(Err)); + reportError(std::move(Err), this->FileName); } } } @@ -4279,6 +4692,294 @@ void GNUStyle<ELFT>::printELFLinkerOptions(const ELFFile<ELFT> *Obj) { OS << "printELFLinkerOptions not implemented!\n"; } +// Used for printing section names in places where possible errors can be +// ignored. +static StringRef getSectionName(const SectionRef &Sec) { + Expected<StringRef> NameOrErr = Sec.getName(); + if (NameOrErr) + return *NameOrErr; + consumeError(NameOrErr.takeError()); + return "<?>"; +} + +// Used for printing symbol names in places where possible errors can be +// ignored. +static std::string getSymbolName(const ELFSymbolRef &Sym) { + Expected<StringRef> NameOrErr = Sym.getName(); + if (NameOrErr) + return maybeDemangle(*NameOrErr); + consumeError(NameOrErr.takeError()); + return "<?>"; +} + +template <class ELFT> +void DumpStyle<ELFT>::printFunctionStackSize( + const ELFObjectFile<ELFT> *Obj, uint64_t SymValue, SectionRef FunctionSec, + const StringRef SectionName, DataExtractor Data, uint64_t *Offset) { + // This function ignores potentially erroneous input, unless it is directly + // related to stack size reporting. + SymbolRef FuncSym; + for (const ELFSymbolRef &Symbol : Obj->symbols()) { + Expected<uint64_t> SymAddrOrErr = Symbol.getAddress(); + if (!SymAddrOrErr) { + consumeError(SymAddrOrErr.takeError()); + continue; + } + if (Symbol.getELFType() == ELF::STT_FUNC && *SymAddrOrErr == SymValue) { + // Check if the symbol is in the right section. + if (FunctionSec.containsSymbol(Symbol)) { + FuncSym = Symbol; + break; + } + } + } + + std::string FuncName = "?"; + // A valid SymbolRef has a non-null object file pointer. + if (FuncSym.BasicSymbolRef::getObject()) + FuncName = getSymbolName(FuncSym); + else + reportWarning( + createError("could not identify function symbol for stack size entry"), + Obj->getFileName()); + + // Extract the size. The expectation is that Offset is pointing to the right + // place, i.e. past the function address. + uint64_t PrevOffset = *Offset; + uint64_t StackSize = Data.getULEB128(Offset); + // getULEB128() does not advance Offset if it is not able to extract a valid + // integer. + if (*Offset == PrevOffset) + reportError( + createStringError(object_error::parse_failed, + "could not extract a valid stack size in section %s", + SectionName.data()), + Obj->getFileName()); + + printStackSizeEntry(StackSize, FuncName); +} + +template <class ELFT> +void GNUStyle<ELFT>::printStackSizeEntry(uint64_t Size, StringRef FuncName) { + OS.PadToColumn(2); + OS << format_decimal(Size, 11); + OS.PadToColumn(18); + OS << FuncName << "\n"; +} + +template <class ELFT> +void DumpStyle<ELFT>::printStackSize(const ELFObjectFile<ELFT> *Obj, + RelocationRef Reloc, + SectionRef FunctionSec, + const StringRef &StackSizeSectionName, + const RelocationResolver &Resolver, + DataExtractor Data) { + // This function ignores potentially erroneous input, unless it is directly + // related to stack size reporting. + object::symbol_iterator RelocSym = Reloc.getSymbol(); + uint64_t RelocSymValue = 0; + StringRef FileStr = Obj->getFileName(); + if (RelocSym != Obj->symbol_end()) { + // Ensure that the relocation symbol is in the function section, i.e. the + // section where the functions whose stack sizes we are reporting are + // located. + auto SectionOrErr = RelocSym->getSection(); + if (!SectionOrErr) { + reportWarning( + createError("cannot identify the section for relocation symbol '" + + getSymbolName(*RelocSym) + "'"), + FileStr); + consumeError(SectionOrErr.takeError()); + } else if (*SectionOrErr != FunctionSec) { + reportWarning(createError("relocation symbol '" + + getSymbolName(*RelocSym) + + "' is not in the expected section"), + FileStr); + // Pretend that the symbol is in the correct section and report its + // stack size anyway. + FunctionSec = **SectionOrErr; + } + + Expected<uint64_t> RelocSymValueOrErr = RelocSym->getValue(); + if (RelocSymValueOrErr) + RelocSymValue = *RelocSymValueOrErr; + else + consumeError(RelocSymValueOrErr.takeError()); + } + + uint64_t Offset = Reloc.getOffset(); + if (!Data.isValidOffsetForDataOfSize(Offset, sizeof(Elf_Addr) + 1)) + reportError( + createStringError(object_error::parse_failed, + "found invalid relocation offset into section %s " + "while trying to extract a stack size entry", + StackSizeSectionName.data()), + FileStr); + + uint64_t Addend = Data.getAddress(&Offset); + uint64_t SymValue = Resolver(Reloc, RelocSymValue, Addend); + this->printFunctionStackSize(Obj, SymValue, FunctionSec, StackSizeSectionName, + Data, &Offset); +} + +template <class ELFT> +void DumpStyle<ELFT>::printNonRelocatableStackSizes( + const ELFObjectFile<ELFT> *Obj, std::function<void()> PrintHeader) { + // This function ignores potentially erroneous input, unless it is directly + // related to stack size reporting. + const ELFFile<ELFT> *EF = Obj->getELFFile(); + StringRef FileStr = Obj->getFileName(); + for (const SectionRef &Sec : Obj->sections()) { + StringRef SectionName = getSectionName(Sec); + if (SectionName != ".stack_sizes") + continue; + PrintHeader(); + const Elf_Shdr *ElfSec = Obj->getSection(Sec.getRawDataRefImpl()); + ArrayRef<uint8_t> Contents = + unwrapOrError(this->FileName, EF->getSectionContents(ElfSec)); + DataExtractor Data(Contents, Obj->isLittleEndian(), sizeof(Elf_Addr)); + // A .stack_sizes section header's sh_link field is supposed to point + // to the section that contains the functions whose stack sizes are + // described in it. + const Elf_Shdr *FunctionELFSec = + unwrapOrError(this->FileName, EF->getSection(ElfSec->sh_link)); + uint64_t Offset = 0; + while (Offset < Contents.size()) { + // The function address is followed by a ULEB representing the stack + // size. Check for an extra byte before we try to process the entry. + if (!Data.isValidOffsetForDataOfSize(Offset, sizeof(Elf_Addr) + 1)) { + reportError( + createStringError( + object_error::parse_failed, + "section %s ended while trying to extract a stack size entry", + SectionName.data()), + FileStr); + } + uint64_t SymValue = Data.getAddress(&Offset); + printFunctionStackSize(Obj, SymValue, Obj->toSectionRef(FunctionELFSec), + SectionName, Data, &Offset); + } + } +} + +template <class ELFT> +void DumpStyle<ELFT>::printRelocatableStackSizes( + const ELFObjectFile<ELFT> *Obj, std::function<void()> PrintHeader) { + const ELFFile<ELFT> *EF = Obj->getELFFile(); + + // Build a map between stack size sections and their corresponding relocation + // sections. + llvm::MapVector<SectionRef, SectionRef> StackSizeRelocMap; + const SectionRef NullSection{}; + + for (const SectionRef &Sec : Obj->sections()) { + StringRef SectionName; + if (Expected<StringRef> NameOrErr = Sec.getName()) + SectionName = *NameOrErr; + else + consumeError(NameOrErr.takeError()); + + // A stack size section that we haven't encountered yet is mapped to the + // null section until we find its corresponding relocation section. + if (SectionName == ".stack_sizes") + if (StackSizeRelocMap.count(Sec) == 0) { + StackSizeRelocMap[Sec] = NullSection; + continue; + } + + // Check relocation sections if they are relocating contents of a + // stack sizes section. + const Elf_Shdr *ElfSec = Obj->getSection(Sec.getRawDataRefImpl()); + uint32_t SectionType = ElfSec->sh_type; + if (SectionType != ELF::SHT_RELA && SectionType != ELF::SHT_REL) + continue; + + Expected<section_iterator> RelSecOrErr = Sec.getRelocatedSection(); + if (!RelSecOrErr) + reportError(createStringError(object_error::parse_failed, + "%s: failed to get a relocated section: %s", + SectionName.data(), + toString(RelSecOrErr.takeError()).c_str()), + Obj->getFileName()); + + const Elf_Shdr *ContentsSec = + Obj->getSection((*RelSecOrErr)->getRawDataRefImpl()); + Expected<StringRef> ContentsSectionNameOrErr = + EF->getSectionName(ContentsSec); + if (!ContentsSectionNameOrErr) { + consumeError(ContentsSectionNameOrErr.takeError()); + continue; + } + if (*ContentsSectionNameOrErr != ".stack_sizes") + continue; + // Insert a mapping from the stack sizes section to its relocation section. + StackSizeRelocMap[Obj->toSectionRef(ContentsSec)] = Sec; + } + + for (const auto &StackSizeMapEntry : StackSizeRelocMap) { + PrintHeader(); + const SectionRef &StackSizesSec = StackSizeMapEntry.first; + const SectionRef &RelocSec = StackSizeMapEntry.second; + + // Warn about stack size sections without a relocation section. + StringRef StackSizeSectionName = getSectionName(StackSizesSec); + if (RelocSec == NullSection) { + reportWarning(createError("section " + StackSizeSectionName + + " does not have a corresponding " + "relocation section"), + Obj->getFileName()); + continue; + } + + // A .stack_sizes section header's sh_link field is supposed to point + // to the section that contains the functions whose stack sizes are + // described in it. + const Elf_Shdr *StackSizesELFSec = + Obj->getSection(StackSizesSec.getRawDataRefImpl()); + const SectionRef FunctionSec = Obj->toSectionRef(unwrapOrError( + this->FileName, EF->getSection(StackSizesELFSec->sh_link))); + + bool (*IsSupportedFn)(uint64_t); + RelocationResolver Resolver; + std::tie(IsSupportedFn, Resolver) = getRelocationResolver(*Obj); + auto Contents = unwrapOrError(this->FileName, StackSizesSec.getContents()); + DataExtractor Data(Contents, Obj->isLittleEndian(), sizeof(Elf_Addr)); + for (const RelocationRef &Reloc : RelocSec.relocations()) { + if (!IsSupportedFn || !IsSupportedFn(Reloc.getType())) + reportError(createStringError( + object_error::parse_failed, + "unsupported relocation type in section %s: %s", + getSectionName(RelocSec).data(), + EF->getRelocationTypeName(Reloc.getType()).data()), + Obj->getFileName()); + this->printStackSize(Obj, Reloc, FunctionSec, StackSizeSectionName, + Resolver, Data); + } + } +} + +template <class ELFT> +void GNUStyle<ELFT>::printStackSizes(const ELFObjectFile<ELFT> *Obj) { + bool HeaderHasBeenPrinted = false; + auto PrintHeader = [&]() { + if (HeaderHasBeenPrinted) + return; + OS << "\nStack Sizes:\n"; + OS.PadToColumn(9); + OS << "Size"; + OS.PadToColumn(18); + OS << "Function\n"; + HeaderHasBeenPrinted = true; + }; + + // For non-relocatable objects, look directly for sections whose name starts + // with .stack_sizes and process the contents. + if (Obj->isRelocatableObject()) + this->printRelocatableStackSizes(Obj, PrintHeader); + else + this->printNonRelocatableStackSizes(Obj, PrintHeader); +} + template <class ELFT> void GNUStyle<ELFT>::printMipsGOT(const MipsGOTParser<ELFT> &Parser) { size_t Bias = ELFT::Is64Bits ? 8 : 0; @@ -4402,6 +5103,45 @@ void GNUStyle<ELFT>::printMipsPLT(const MipsGOTParser<ELFT> &Parser) { } } +template <class ELFT> +void GNUStyle<ELFT>::printMipsABIFlags(const ELFObjectFile<ELFT> *ObjF) { + const ELFFile<ELFT> *Obj = ObjF->getELFFile(); + const Elf_Shdr *Shdr = + findSectionByName(*Obj, ObjF->getFileName(), ".MIPS.abiflags"); + if (!Shdr) + return; + + ArrayRef<uint8_t> Sec = + unwrapOrError(ObjF->getFileName(), Obj->getSectionContents(Shdr)); + if (Sec.size() != sizeof(Elf_Mips_ABIFlags<ELFT>)) + reportError(createError(".MIPS.abiflags section has a wrong size"), + ObjF->getFileName()); + + auto *Flags = reinterpret_cast<const Elf_Mips_ABIFlags<ELFT> *>(Sec.data()); + + OS << "MIPS ABI Flags Version: " << Flags->version << "\n\n"; + OS << "ISA: MIPS" << int(Flags->isa_level); + if (Flags->isa_rev > 1) + OS << "r" << int(Flags->isa_rev); + OS << "\n"; + OS << "GPR size: " << getMipsRegisterSize(Flags->gpr_size) << "\n"; + OS << "CPR1 size: " << getMipsRegisterSize(Flags->cpr1_size) << "\n"; + OS << "CPR2 size: " << getMipsRegisterSize(Flags->cpr2_size) << "\n"; + OS << "FP ABI: " << printEnum(Flags->fp_abi, makeArrayRef(ElfMipsFpABIType)) + << "\n"; + OS << "ISA Extension: " + << printEnum(Flags->isa_ext, makeArrayRef(ElfMipsISAExtType)) << "\n"; + if (Flags->ases == 0) + OS << "ASEs: None\n"; + else + // FIXME: Print each flag on a separate line. + OS << "ASEs: " << printFlags(Flags->ases, makeArrayRef(ElfMipsASEFlags)) + << "\n"; + OS << "FLAGS 1: " << format_hex_no_prefix(Flags->flags1, 8, false) << "\n"; + OS << "FLAGS 2: " << format_hex_no_prefix(Flags->flags2, 8, false) << "\n"; + OS << "\n"; +} + template <class ELFT> void LLVMStyle<ELFT>::printFileHeaders(const ELFO *Obj) { const Elf_Ehdr *E = Obj->getHeader(); { @@ -4455,16 +5195,17 @@ template <class ELFT> void LLVMStyle<ELFT>::printFileHeaders(const ELFO *Obj) { W.printNumber("ProgramHeaderEntrySize", E->e_phentsize); W.printNumber("ProgramHeaderCount", E->e_phnum); W.printNumber("SectionHeaderEntrySize", E->e_shentsize); - W.printString("SectionHeaderCount", getSectionHeadersNumString(Obj)); + W.printString("SectionHeaderCount", + getSectionHeadersNumString(Obj, this->FileName)); W.printString("StringTableSectionIndex", - getSectionHeaderTableIndexString(Obj)); + getSectionHeaderTableIndexString(Obj, this->FileName)); } } template <class ELFT> void LLVMStyle<ELFT>::printGroupSections(const ELFO *Obj) { DictScope Lists(W, "Groups"); - std::vector<GroupSection> V = getGroups<ELFT>(Obj); + std::vector<GroupSection> V = getGroups<ELFT>(Obj, this->FileName); DenseMap<uint64_t, const GroupSection *> Map = mapSectionsToGroups(V); for (const GroupSection &G : V) { DictScope D(W, "Group"); @@ -4499,7 +5240,7 @@ template <class ELFT> void LLVMStyle<ELFT>::printRelocations(const ELFO *Obj) { ListScope D(W, "Relocations"); int SectionNumber = -1; - for (const Elf_Shdr &Sec : unwrapOrError(Obj->sections())) { + for (const Elf_Shdr &Sec : unwrapOrError(this->FileName, Obj->sections())) { ++SectionNumber; if (Sec.sh_type != ELF::SHT_REL && Sec.sh_type != ELF::SHT_RELA && @@ -4508,7 +5249,7 @@ template <class ELFT> void LLVMStyle<ELFT>::printRelocations(const ELFO *Obj) { Sec.sh_type != ELF::SHT_ANDROID_RELR) continue; - StringRef Name = unwrapOrError(Obj->getSectionName(&Sec)); + StringRef Name = unwrapOrError(this->FileName, Obj->getSectionName(&Sec)); W.startLine() << "Section (" << SectionNumber << ") " << Name << " {\n"; W.indent(); @@ -4522,11 +5263,12 @@ template <class ELFT> void LLVMStyle<ELFT>::printRelocations(const ELFO *Obj) { template <class ELFT> void LLVMStyle<ELFT>::printRelocations(const Elf_Shdr *Sec, const ELFO *Obj) { - const Elf_Shdr *SymTab = unwrapOrError(Obj->getSection(Sec->sh_link)); + const Elf_Shdr *SymTab = + unwrapOrError(this->FileName, Obj->getSection(Sec->sh_link)); switch (Sec->sh_type) { case ELF::SHT_REL: - for (const Elf_Rel &R : unwrapOrError(Obj->rels(Sec))) { + for (const Elf_Rel &R : unwrapOrError(this->FileName, Obj->rels(Sec))) { Elf_Rela Rela; Rela.r_offset = R.r_offset; Rela.r_info = R.r_info; @@ -4535,17 +5277,18 @@ void LLVMStyle<ELFT>::printRelocations(const Elf_Shdr *Sec, const ELFO *Obj) { } break; case ELF::SHT_RELA: - for (const Elf_Rela &R : unwrapOrError(Obj->relas(Sec))) + for (const Elf_Rela &R : unwrapOrError(this->FileName, Obj->relas(Sec))) printRelocation(Obj, R, SymTab); break; case ELF::SHT_RELR: case ELF::SHT_ANDROID_RELR: { - Elf_Relr_Range Relrs = unwrapOrError(Obj->relrs(Sec)); + Elf_Relr_Range Relrs = unwrapOrError(this->FileName, Obj->relrs(Sec)); if (opts::RawRelr) { for (const Elf_Relr &R : Relrs) W.startLine() << W.hex(R) << "\n"; } else { - std::vector<Elf_Rela> RelrRelas = unwrapOrError(Obj->decode_relrs(Relrs)); + std::vector<Elf_Rela> RelrRelas = + unwrapOrError(this->FileName, Obj->decode_relrs(Relrs)); for (const Elf_Rela &R : RelrRelas) printRelocation(Obj, R, SymTab); } @@ -4553,7 +5296,8 @@ void LLVMStyle<ELFT>::printRelocations(const Elf_Shdr *Sec, const ELFO *Obj) { } case ELF::SHT_ANDROID_REL: case ELF::SHT_ANDROID_RELA: - for (const Elf_Rela &R : unwrapOrError(Obj->android_relas(Sec))) + for (const Elf_Rela &R : + unwrapOrError(this->FileName, Obj->android_relas(Sec))) printRelocation(Obj, R, SymTab); break; } @@ -4565,13 +5309,16 @@ void LLVMStyle<ELFT>::printRelocation(const ELFO *Obj, Elf_Rela Rel, SmallString<32> RelocName; Obj->getRelocationTypeName(Rel.getType(Obj->isMips64EL()), RelocName); std::string TargetName; - const Elf_Sym *Sym = unwrapOrError(Obj->getRelocationSymbol(&Rel, SymTab)); + const Elf_Sym *Sym = + unwrapOrError(this->FileName, Obj->getRelocationSymbol(&Rel, SymTab)); if (Sym && Sym->getType() == ELF::STT_SECTION) { const Elf_Shdr *Sec = unwrapOrError( + this->FileName, Obj->getSection(Sym, SymTab, this->dumper()->getShndxTable())); - TargetName = unwrapOrError(Obj->getSectionName(Sec)); + TargetName = unwrapOrError(this->FileName, Obj->getSectionName(Sec)); } else if (Sym) { - StringRef StrTable = unwrapOrError(Obj->getStringTableForSymtab(*SymTab)); + StringRef StrTable = + unwrapOrError(this->FileName, Obj->getStringTableForSymtab(*SymTab)); TargetName = this->dumper()->getFullSymbolName( Sym, StrTable, SymTab->sh_type == SHT_DYNSYM /* IsDynamic */); } @@ -4596,10 +5343,11 @@ void LLVMStyle<ELFT>::printSectionHeaders(const ELFO *Obj) { ListScope SectionsD(W, "Sections"); int SectionIndex = -1; - ArrayRef<Elf_Shdr> Sections = unwrapOrError(Obj->sections()); + ArrayRef<Elf_Shdr> Sections = unwrapOrError(this->FileName, Obj->sections()); const ELFObjectFile<ELFT> *ElfObj = this->dumper()->getElfObject(); for (const Elf_Shdr &Sec : Sections) { - StringRef Name = getSectionName(Sec, *ElfObj, Sections); + StringRef Name = unwrapOrError( + ElfObj->getFileName(), Obj->getSectionName(&Sec, this->WarningHandler)); DictScope SectionD(W, "Section"); W.printNumber("Index", ++SectionIndex); W.printNumber("Name", Name, Sec.sh_name); @@ -4652,19 +5400,25 @@ void LLVMStyle<ELFT>::printSectionHeaders(const ELFO *Obj) { if (opts::SectionSymbols) { ListScope D(W, "Symbols"); const Elf_Shdr *Symtab = this->dumper()->getDotSymtabSec(); - StringRef StrTable = unwrapOrError(Obj->getStringTableForSymtab(*Symtab)); + StringRef StrTable = + unwrapOrError(this->FileName, Obj->getStringTableForSymtab(*Symtab)); - for (const Elf_Sym &Sym : unwrapOrError(Obj->symbols(Symtab))) { + for (const Elf_Sym &Sym : + unwrapOrError(this->FileName, Obj->symbols(Symtab))) { const Elf_Shdr *SymSec = unwrapOrError( + this->FileName, Obj->getSection(&Sym, Symtab, this->dumper()->getShndxTable())); if (SymSec == &Sec) - printSymbol(Obj, &Sym, unwrapOrError(Obj->symbols(Symtab)).begin(), - StrTable, false); + printSymbol( + Obj, &Sym, + unwrapOrError(this->FileName, Obj->symbols(Symtab)).begin(), + StrTable, false, false); } } if (opts::SectionData && Sec.sh_type != ELF::SHT_NOBITS) { - ArrayRef<uint8_t> Data = unwrapOrError(Obj->getSectionContents(&Sec)); + ArrayRef<uint8_t> Data = + unwrapOrError(this->FileName, Obj->getSectionContents(&Sec)); W.printBinaryBlock( "SectionData", StringRef(reinterpret_cast<const char *>(Data.data()), Data.size())); @@ -4675,7 +5429,8 @@ void LLVMStyle<ELFT>::printSectionHeaders(const ELFO *Obj) { template <class ELFT> void LLVMStyle<ELFT>::printSymbol(const ELFO *Obj, const Elf_Sym *Symbol, const Elf_Sym *First, StringRef StrTable, - bool IsDynamic) { + bool IsDynamic, + bool /*NonVisibilityBitsUsed*/) { unsigned SectionIndex = 0; StringRef SectionName; this->dumper()->getSectionNameIndex(Symbol, First, SectionName, SectionIndex); @@ -4786,7 +5541,8 @@ void LLVMStyle<ELFT>::printDynamicRelocations(const ELFO *Obj) { } if (DynRelrRegion.Size > 0) { Elf_Relr_Range Relrs = this->dumper()->dyn_relrs(); - std::vector<Elf_Rela> RelrRelas = unwrapOrError(Obj->decode_relrs(Relrs)); + std::vector<Elf_Rela> RelrRelas = + unwrapOrError(this->FileName, Obj->decode_relrs(Relrs)); for (const Elf_Rela &Rela : RelrRelas) printDynamicRelocation(Obj, Rela); } @@ -4809,11 +5565,9 @@ template <class ELFT> void LLVMStyle<ELFT>::printDynamicRelocation(const ELFO *Obj, Elf_Rela Rel) { SmallString<32> RelocName; Obj->getRelocationTypeName(Rel.getType(Obj->isMips64EL()), RelocName); - std::string SymbolName; - uint32_t SymIndex = Rel.getSymbol(Obj->isMips64EL()); - const Elf_Sym *Sym = this->dumper()->dynamic_symbols().begin() + SymIndex; - SymbolName = maybeDemangle( - unwrapOrError(Sym->getName(this->dumper()->getDynamicStringTable()))); + std::string SymbolName = + getSymbolForReloc(Obj, this->FileName, this->dumper(), Rel).Name; + if (opts::ExpandRelocs) { DictScope Group(W, "Relocation"); W.printHex("Offset", Rel.r_offset); @@ -4842,7 +5596,8 @@ template <class ELFT> void LLVMStyle<ELFT>::printProgramHeaders(const ELFO *Obj) { ListScope L(W, "ProgramHeaders"); - for (const Elf_Phdr &Phdr : unwrapOrError(Obj->program_headers())) { + for (const Elf_Phdr &Phdr : + unwrapOrError(this->FileName, Obj->program_headers())) { DictScope P(W, "ProgramHeader"); W.printHex("Type", getElfSegmentType(Obj->getHeader()->e_machine, Phdr.p_type), @@ -4860,23 +5615,16 @@ void LLVMStyle<ELFT>::printProgramHeaders(const ELFO *Obj) { template <class ELFT> void LLVMStyle<ELFT>::printVersionSymbolSection(const ELFFile<ELFT> *Obj, const Elf_Shdr *Sec) { - DictScope SS(W, "Version symbols"); + ListScope SS(W, "VersionSymbols"); if (!Sec) return; - StringRef SecName = unwrapOrError(Obj->getSectionName(Sec)); - W.printNumber("Section Name", SecName, Sec->sh_name); - W.printHex("Address", Sec->sh_addr); - W.printHex("Offset", Sec->sh_offset); - W.printNumber("Link", Sec->sh_link); - const uint8_t *VersymBuf = reinterpret_cast<const uint8_t *>(Obj->base() + Sec->sh_offset); const ELFDumper<ELFT> *Dumper = this->dumper(); StringRef StrTable = Dumper->getDynamicStringTable(); // Same number of entries in the dynamic symbol table (DT_SYMTAB). - ListScope Syms(W, "Symbols"); for (const Elf_Sym &Sym : Dumper->dynamic_symbols()) { DictScope S(W, "Symbol"); const Elf_Versym *Versym = reinterpret_cast<const Elf_Versym *>(VersymBuf); @@ -4891,7 +5639,7 @@ void LLVMStyle<ELFT>::printVersionSymbolSection(const ELFFile<ELFT> *Obj, template <class ELFT> void LLVMStyle<ELFT>::printVersionDefinitionSection(const ELFFile<ELFT> *Obj, const Elf_Shdr *Sec) { - DictScope SD(W, "SHT_GNU_verdef"); + ListScope SD(W, "VersionDefinitions"); if (!Sec) return; @@ -4899,7 +5647,8 @@ void LLVMStyle<ELFT>::printVersionDefinitionSection(const ELFFile<ELFT> *Obj, reinterpret_cast<const uint8_t *>(Obj->base() + Sec->sh_offset); const uint8_t *SecEndAddress = SecStartAddress + Sec->sh_size; const uint8_t *VerdefBuf = SecStartAddress; - const Elf_Shdr *StrTab = unwrapOrError(Obj->getSection(Sec->sh_link)); + const Elf_Shdr *StrTab = + unwrapOrError(this->FileName, Obj->getSection(Sec->sh_link)); unsigned VerDefsNum = Sec->sh_info; while (VerDefsNum--) { @@ -4938,13 +5687,14 @@ void LLVMStyle<ELFT>::printVersionDefinitionSection(const ELFFile<ELFT> *Obj, template <class ELFT> void LLVMStyle<ELFT>::printVersionDependencySection(const ELFFile<ELFT> *Obj, const Elf_Shdr *Sec) { - DictScope SD(W, "SHT_GNU_verneed"); + ListScope SD(W, "VersionRequirements"); if (!Sec) return; const uint8_t *SecData = reinterpret_cast<const uint8_t *>(Obj->base() + Sec->sh_offset); - const Elf_Shdr *StrTab = unwrapOrError(Obj->getSection(Sec->sh_link)); + const Elf_Shdr *StrTab = + unwrapOrError(this->FileName, Obj->getSection(Sec->sh_link)); const uint8_t *VerneedBuf = SecData; unsigned VerneedNum = Sec->sh_info; @@ -4986,37 +5736,62 @@ void LLVMStyle<ELFT>::printCGProfile(const ELFFile<ELFT> *Obj) { ListScope L(W, "CGProfile"); if (!this->dumper()->getDotCGProfileSec()) return; - auto CGProfile = - unwrapOrError(Obj->template getSectionContentsAsArray<Elf_CGProfile>( - this->dumper()->getDotCGProfileSec())); + auto CGProfile = unwrapOrError( + this->FileName, Obj->template getSectionContentsAsArray<Elf_CGProfile>( + this->dumper()->getDotCGProfileSec())); for (const Elf_CGProfile &CGPE : CGProfile) { DictScope D(W, "CGProfileEntry"); - W.printNumber("From", this->dumper()->getStaticSymbolName(CGPE.cgp_from), - CGPE.cgp_from); - W.printNumber("To", this->dumper()->getStaticSymbolName(CGPE.cgp_to), - CGPE.cgp_to); + W.printNumber( + "From", + unwrapOrError(this->FileName, + this->dumper()->getStaticSymbolName(CGPE.cgp_from)), + CGPE.cgp_from); + W.printNumber( + "To", + unwrapOrError(this->FileName, + this->dumper()->getStaticSymbolName(CGPE.cgp_to)), + CGPE.cgp_to); W.printNumber("Weight", CGPE.cgp_weight); } } +static Expected<std::vector<uint64_t>> toULEB128Array(ArrayRef<uint8_t> Data) { + std::vector<uint64_t> Ret; + const uint8_t *Cur = Data.begin(); + const uint8_t *End = Data.end(); + while (Cur != End) { + unsigned Size; + const char *Err; + Ret.push_back(decodeULEB128(Cur, &Size, End, &Err)); + if (Err) + return createError(Err); + Cur += Size; + } + return Ret; +} + template <class ELFT> void LLVMStyle<ELFT>::printAddrsig(const ELFFile<ELFT> *Obj) { ListScope L(W, "Addrsig"); if (!this->dumper()->getDotAddrsigSec()) return; ArrayRef<uint8_t> Contents = unwrapOrError( + this->FileName, Obj->getSectionContents(this->dumper()->getDotAddrsigSec())); - const uint8_t *Cur = Contents.begin(); - const uint8_t *End = Contents.end(); - while (Cur != End) { - unsigned Size; - const char *Err; - uint64_t SymIndex = decodeULEB128(Cur, &Size, End, &Err); - if (Err) - reportError(Err); - W.printNumber("Sym", this->dumper()->getStaticSymbolName(SymIndex), - SymIndex); - Cur += Size; + Expected<std::vector<uint64_t>> V = toULEB128Array(Contents); + if (!V) { + reportWarning(V.takeError(), this->FileName); + return; + } + + for (uint64_t Sym : *V) { + Expected<std::string> NameOrErr = this->dumper()->getStaticSymbolName(Sym); + if (NameOrErr) { + W.printNumber("Sym", *NameOrErr, Sym); + continue; + } + reportWarning(NameOrErr.takeError(), this->FileName); + W.printNumber("Sym", "<?>", Sym); } } @@ -5051,6 +5826,17 @@ static void printGNUNoteLLVMStyle(uint32_t NoteType, ArrayRef<uint8_t> Desc, } } +static void printCoreNoteLLVMStyle(const CoreNote &Note, ScopedPrinter &W) { + W.printNumber("Page Size", Note.PageSize); + for (const CoreFileMapping &Mapping : Note.Mappings) { + ListScope D(W, "Mapping"); + W.printHex("Start", Mapping.Start); + W.printHex("End", Mapping.End); + W.printHex("Offset", Mapping.Offset); + W.printString("Filename", Mapping.Filename); + } +} + template <class ELFT> void LLVMStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) { ListScope L(W, "Notes"); @@ -5067,56 +5853,81 @@ void LLVMStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) { ArrayRef<uint8_t> Descriptor = Note.getDesc(); Elf_Word Type = Note.getType(); + // Print the note owner/type. W.printString("Owner", Name); W.printHex("Data size", Descriptor.size()); if (Name == "GNU") { W.printString("Type", getGNUNoteTypeName(Type)); - printGNUNoteLLVMStyle<ELFT>(Type, Descriptor, W); } else if (Name == "FreeBSD") { W.printString("Type", getFreeBSDNoteTypeName(Type)); } else if (Name == "AMD") { W.printString("Type", getAMDNoteTypeName(Type)); - const AMDNote N = getAMDNote<ELFT>(Type, Descriptor); - if (!N.Type.empty()) - W.printString(N.Type, N.Value); } else if (Name == "AMDGPU") { W.printString("Type", getAMDGPUNoteTypeName(Type)); - const AMDGPUNote N = getAMDGPUNote<ELFT>(Type, Descriptor); - if (!N.Type.empty()) - W.printString(N.Type, N.Value); } else { - StringRef NoteType = getGenericNoteTypeName(Type); + StringRef NoteType = Obj->getHeader()->e_type == ELF::ET_CORE + ? getCoreNoteTypeName(Type) + : getGenericNoteTypeName(Type); if (!NoteType.empty()) W.printString("Type", NoteType); else W.printString("Type", "Unknown (" + to_string(format_hex(Type, 10)) + ")"); } + + // Print the description, or fallback to printing raw bytes for unknown + // owners. + if (Name == "GNU") { + printGNUNoteLLVMStyle<ELFT>(Type, Descriptor, W); + } else if (Name == "AMD") { + const AMDNote N = getAMDNote<ELFT>(Type, Descriptor); + if (!N.Type.empty()) + W.printString(N.Type, N.Value); + } else if (Name == "AMDGPU") { + const AMDGPUNote N = getAMDGPUNote<ELFT>(Type, Descriptor); + if (!N.Type.empty()) + W.printString(N.Type, N.Value); + } else if (Name == "CORE") { + if (Type == ELF::NT_FILE) { + DataExtractor DescExtractor(Descriptor, + ELFT::TargetEndianness == support::little, + sizeof(Elf_Addr)); + Expected<CoreNote> Note = readCoreNote(DescExtractor); + if (Note) + printCoreNoteLLVMStyle(*Note, W); + else + reportWarning(Note.takeError(), this->FileName); + } + } else if (!Descriptor.empty()) { + W.printBinaryBlock("Description data", Descriptor); + } }; - if (Obj->getHeader()->e_type == ELF::ET_CORE) { - for (const auto &P : unwrapOrError(Obj->program_headers())) { - if (P.p_type != PT_NOTE) + ArrayRef<Elf_Shdr> Sections = unwrapOrError(this->FileName, Obj->sections()); + if (Obj->getHeader()->e_type != ELF::ET_CORE && !Sections.empty()) { + for (const auto &S : Sections) { + if (S.sh_type != SHT_NOTE) continue; DictScope D(W, "NoteSection"); - PrintHeader(P.p_offset, P.p_filesz); + PrintHeader(S.sh_offset, S.sh_size); Error Err = Error::success(); - for (const auto &Note : Obj->notes(P, Err)) + for (const auto &Note : Obj->notes(S, Err)) ProcessNote(Note); if (Err) - error(std::move(Err)); + reportError(std::move(Err), this->FileName); } } else { - for (const auto &S : unwrapOrError(Obj->sections())) { - if (S.sh_type != SHT_NOTE) + for (const auto &P : + unwrapOrError(this->FileName, Obj->program_headers())) { + if (P.p_type != PT_NOTE) continue; DictScope D(W, "NoteSection"); - PrintHeader(S.sh_offset, S.sh_size); + PrintHeader(P.p_offset, P.p_filesz); Error Err = Error::success(); - for (const auto &Note : Obj->notes(S, Err)) + for (const auto &Note : Obj->notes(P, Err)) ProcessNote(Note); if (Err) - error(std::move(Err)); + reportError(std::move(Err), this->FileName); } } } @@ -5125,11 +5936,12 @@ template <class ELFT> void LLVMStyle<ELFT>::printELFLinkerOptions(const ELFFile<ELFT> *Obj) { ListScope L(W, "LinkerOptions"); - for (const Elf_Shdr &Shdr : unwrapOrError(Obj->sections())) { + for (const Elf_Shdr &Shdr : unwrapOrError(this->FileName, Obj->sections())) { if (Shdr.sh_type != ELF::SHT_LLVM_LINKER_OPTIONS) continue; - ArrayRef<uint8_t> Contents = unwrapOrError(Obj->getSectionContents(&Shdr)); + ArrayRef<uint8_t> Contents = + unwrapOrError(this->FileName, Obj->getSectionContents(&Shdr)); for (const uint8_t *P = Contents.begin(), *E = Contents.end(); P < E; ) { StringRef Key = StringRef(reinterpret_cast<const char *>(P)); StringRef Value = @@ -5143,6 +5955,22 @@ void LLVMStyle<ELFT>::printELFLinkerOptions(const ELFFile<ELFT> *Obj) { } template <class ELFT> +void LLVMStyle<ELFT>::printStackSizes(const ELFObjectFile<ELFT> *Obj) { + ListScope L(W, "StackSizes"); + if (Obj->isRelocatableObject()) + this->printRelocatableStackSizes(Obj, []() {}); + else + this->printNonRelocatableStackSizes(Obj, []() {}); +} + +template <class ELFT> +void LLVMStyle<ELFT>::printStackSizeEntry(uint64_t Size, StringRef FuncName) { + DictScope D(W, "Entry"); + W.printString("Function", FuncName); + W.printHex("Size", Size); +} + +template <class ELFT> void LLVMStyle<ELFT>::printMipsGOT(const MipsGOTParser<ELFT> &Parser) { auto PrintEntry = [&](const Elf_Addr *E) { W.printHex("Address", Parser.getGotAddress(E)); @@ -5252,3 +6080,41 @@ void LLVMStyle<ELFT>::printMipsPLT(const MipsGOTParser<ELFT> &Parser) { } } } + +template <class ELFT> +void LLVMStyle<ELFT>::printMipsABIFlags(const ELFObjectFile<ELFT> *ObjF) { + const ELFFile<ELFT> *Obj = ObjF->getELFFile(); + const Elf_Shdr *Shdr = + findSectionByName(*Obj, ObjF->getFileName(), ".MIPS.abiflags"); + if (!Shdr) { + W.startLine() << "There is no .MIPS.abiflags section in the file.\n"; + return; + } + ArrayRef<uint8_t> Sec = + unwrapOrError(ObjF->getFileName(), Obj->getSectionContents(Shdr)); + if (Sec.size() != sizeof(Elf_Mips_ABIFlags<ELFT>)) { + W.startLine() << "The .MIPS.abiflags section has a wrong size.\n"; + return; + } + + auto *Flags = reinterpret_cast<const Elf_Mips_ABIFlags<ELFT> *>(Sec.data()); + + raw_ostream &OS = W.getOStream(); + DictScope GS(W, "MIPS ABI Flags"); + + W.printNumber("Version", Flags->version); + W.startLine() << "ISA: "; + if (Flags->isa_rev <= 1) + OS << format("MIPS%u", Flags->isa_level); + else + OS << format("MIPS%ur%u", Flags->isa_level, Flags->isa_rev); + OS << "\n"; + W.printEnum("ISA Extension", Flags->isa_ext, makeArrayRef(ElfMipsISAExtType)); + W.printFlags("ASEs", Flags->ases, makeArrayRef(ElfMipsASEFlags)); + W.printEnum("FP ABI", Flags->fp_abi, makeArrayRef(ElfMipsFpABIType)); + W.printNumber("GPR size", getMipsRegisterSize(Flags->gpr_size)); + W.printNumber("CPR1 size", getMipsRegisterSize(Flags->cpr1_size)); + W.printNumber("CPR2 size", getMipsRegisterSize(Flags->cpr2_size)); + W.printFlags("Flags 1", Flags->flags1, makeArrayRef(ElfMipsFlags1)); + W.printHex("Flags 2", Flags->flags2); +} diff --git a/tools/llvm-readobj/MachODumper.cpp b/tools/llvm-readobj/MachODumper.cpp index 32a3866eb2f2..20a60b3df699 100644 --- a/tools/llvm-readobj/MachODumper.cpp +++ b/tools/llvm-readobj/MachODumper.cpp @@ -214,6 +214,31 @@ static const EnumEntry<uint32_t> MachOHeaderFlags[] = { LLVM_READOBJ_ENUM_ENT(MachO, MH_APP_EXTENSION_SAFE), }; +static const EnumEntry<unsigned> MachOSectionTypes[] = { + { "Regular" , MachO::S_REGULAR }, + { "ZeroFill" , MachO::S_ZEROFILL }, + { "CStringLiterals" , MachO::S_CSTRING_LITERALS }, + { "4ByteLiterals" , MachO::S_4BYTE_LITERALS }, + { "8ByteLiterals" , MachO::S_8BYTE_LITERALS }, + { "LiteralPointers" , MachO::S_LITERAL_POINTERS }, + { "NonLazySymbolPointers" , MachO::S_NON_LAZY_SYMBOL_POINTERS }, + { "LazySymbolPointers" , MachO::S_LAZY_SYMBOL_POINTERS }, + { "SymbolStubs" , MachO::S_SYMBOL_STUBS }, + { "ModInitFuncPointers" , MachO::S_MOD_INIT_FUNC_POINTERS }, + { "ModTermFuncPointers" , MachO::S_MOD_TERM_FUNC_POINTERS }, + { "Coalesced" , MachO::S_COALESCED }, + { "GBZeroFill" , MachO::S_GB_ZEROFILL }, + { "Interposing" , MachO::S_INTERPOSING }, + { "16ByteLiterals" , MachO::S_16BYTE_LITERALS }, + { "DTraceDOF" , MachO::S_DTRACE_DOF }, + { "LazyDylibSymbolPointers" , MachO::S_LAZY_DYLIB_SYMBOL_POINTERS }, + { "ThreadLocalRegular" , MachO::S_THREAD_LOCAL_REGULAR }, + { "ThreadLocalZerofill" , MachO::S_THREAD_LOCAL_ZEROFILL }, + { "ThreadLocalVariables" , MachO::S_THREAD_LOCAL_VARIABLES }, + { "ThreadLocalVariablePointers" , MachO::S_THREAD_LOCAL_VARIABLE_POINTERS }, + { "ThreadLocalInitFunctionPointers", MachO::S_THREAD_LOCAL_INIT_FUNCTION_POINTERS } +}; + static const EnumEntry<unsigned> MachOSectionAttributes[] = { { "LocReloc" , 1 << 0 /*S_ATTR_LOC_RELOC */ }, { "ExtReloc" , 1 << 1 /*S_ATTR_EXT_RELOC */ }, @@ -440,10 +465,7 @@ void MachODumper::printSectionHeaders(const MachOObjectFile *Obj) { MachOSection MOSection; getSection(Obj, Section.getRawDataRefImpl(), MOSection); DataRefImpl DR = Section.getRawDataRefImpl(); - - StringRef Name; - error(Section.getName(Name)); - + StringRef Name = unwrapOrError(Obj->getFileName(), Section.getName()); ArrayRef<char> RawName = Obj->getSectionRawName(DR); StringRef SegmentName = Obj->getSectionFinalSegmentName(DR); ArrayRef<char> RawSegmentName = Obj->getSectionRawFinalSegmentName(DR); @@ -459,7 +481,7 @@ void MachODumper::printSectionHeaders(const MachOObjectFile *Obj) { W.printHex("RelocationOffset", MOSection.RelocationTableOffset); W.printNumber("RelocationCount", MOSection.NumRelocationTableEntries); W.printEnum("Type", MOSection.Flags & 0xFF, - makeArrayRef(MachOSectionAttributes)); + makeArrayRef(MachOSectionTypes)); W.printFlags("Attributes", MOSection.Flags >> 8, makeArrayRef(MachOSectionAttributes)); W.printHex("Reserved1", MOSection.Reserved1); @@ -484,7 +506,8 @@ void MachODumper::printSectionHeaders(const MachOObjectFile *Obj) { } if (opts::SectionData && !Section.isBSS()) - W.printBinaryBlock("SectionData", unwrapOrError(Section.getContents())); + W.printBinaryBlock("SectionData", unwrapOrError(Obj->getFileName(), + Section.getContents())); } } @@ -493,9 +516,7 @@ void MachODumper::printRelocations() { std::error_code EC; for (const SectionRef &Section : Obj->sections()) { - StringRef Name; - error(Section.getName(Name)); - + StringRef Name = unwrapOrError(Obj->getFileName(), Section.getName()); bool PrintedGroup = false; for (const RelocationRef &Reloc : Section.relocations()) { if (!PrintedGroup) { @@ -535,14 +556,13 @@ void MachODumper::printRelocation(const MachOObjectFile *Obj, if (Symbol != Obj->symbol_end()) { Expected<StringRef> TargetNameOrErr = Symbol->getName(); if (!TargetNameOrErr) - error(errorToErrorCode(TargetNameOrErr.takeError())); + reportError(TargetNameOrErr.takeError(), Obj->getFileName()); TargetName = *TargetNameOrErr; } } else if (!IsScattered) { section_iterator SecI = Obj->getRelocationSection(DR); - if (SecI != Obj->section_end()) { - error(SecI->getName(TargetName)); - } + if (SecI != Obj->section_end()) + TargetName = unwrapOrError(Obj->getFileName(), SecI->getName()); } if (TargetName.empty()) TargetName = "-"; @@ -610,10 +630,12 @@ void MachODumper::printSymbol(const SymbolRef &Symbol) { StringRef SectionName = ""; Expected<section_iterator> SecIOrErr = Symbol.getSection(); - error(errorToErrorCode(SecIOrErr.takeError())); + if (!SecIOrErr) + reportError(SecIOrErr.takeError(), Obj->getFileName()); + section_iterator SecI = *SecIOrErr; if (SecI != Obj->section_end()) - error(SecI->getName(SectionName)); + SectionName = unwrapOrError(Obj->getFileName(), SecI->getName()); DictScope D(W, "Symbol"); W.printNumber("Name", SymbolName, MOSymbol.StringIndex); @@ -643,7 +665,11 @@ void MachODumper::printStackMap() const { object::SectionRef StackMapSection; for (auto Sec : Obj->sections()) { StringRef Name; - Sec.getName(Name); + if (Expected<StringRef> NameOrErr = Sec.getName()) + Name = *NameOrErr; + else + consumeError(NameOrErr.takeError()); + if (Name == "__llvm_stackmaps") { StackMapSection = Sec; break; @@ -653,7 +679,8 @@ void MachODumper::printStackMap() const { if (StackMapSection == object::SectionRef()) return; - StringRef StackMapContents = unwrapOrError(StackMapSection.getContents()); + StringRef StackMapContents = + unwrapOrError(Obj->getFileName(), StackMapSection.getContents()); ArrayRef<uint8_t> StackMapContentsArray = arrayRefFromStringRef(StackMapContents); diff --git a/tools/llvm-readobj/ObjDumper.cpp b/tools/llvm-readobj/ObjDumper.cpp index 0a9e22c8a71c..9e5ebd99ac37 100644 --- a/tools/llvm-readobj/ObjDumper.cpp +++ b/tools/llvm-readobj/ObjDumper.cpp @@ -23,6 +23,10 @@ namespace llvm { +static inline Error createError(const Twine &Msg) { + return createStringError(object::object_error::parse_failed, Msg); +} + ObjDumper::ObjDumper(ScopedPrinter &Writer) : W(Writer) {} ObjDumper::~ObjDumper() { @@ -49,8 +53,7 @@ getSectionRefsByNameOrIndex(const object::ObjectFile *Obj, SecIndex = Obj->isELF() ? 0 : 1; for (object::SectionRef SecRef : Obj->sections()) { - StringRef SecName; - error(SecRef.getName(SecName)); + StringRef SecName = unwrapOrError(Obj->getFileName(), SecRef.getName()); auto NameIt = SecNames.find(SecName); if (NameIt != SecNames.end()) NameIt->second = true; @@ -64,10 +67,15 @@ getSectionRefsByNameOrIndex(const object::ObjectFile *Obj, for (const std::pair<std::string, bool> &S : SecNames) if (!S.second) - reportWarning(formatv("could not find section '{0}'", S.first).str()); + reportWarning( + createError(formatv("could not find section '{0}'", S.first).str()), + Obj->getFileName()); + for (std::pair<unsigned, bool> S : SecIndices) if (!S.second) - reportWarning(formatv("could not find section {0}", S.first).str()); + reportWarning( + createError(formatv("could not find section {0}", S.first).str()), + Obj->getFileName()); return Ret; } @@ -77,14 +85,16 @@ void ObjDumper::printSectionsAsString(const object::ObjectFile *Obj, bool First = true; for (object::SectionRef Section : getSectionRefsByNameOrIndex(Obj, Sections)) { - StringRef SectionName; - error(Section.getName(SectionName)); + StringRef SectionName = + unwrapOrError(Obj->getFileName(), Section.getName()); + if (!First) W.startLine() << '\n'; First = false; W.startLine() << "String dump of section '" << SectionName << "':\n"; - StringRef SectionContent = unwrapOrError(Section.getContents()); + StringRef SectionContent = + unwrapOrError(Obj->getFileName(), Section.getContents()); const uint8_t *SecContent = SectionContent.bytes_begin(); const uint8_t *CurrentWord = SecContent; @@ -110,14 +120,16 @@ void ObjDumper::printSectionsAsHex(const object::ObjectFile *Obj, bool First = true; for (object::SectionRef Section : getSectionRefsByNameOrIndex(Obj, Sections)) { - StringRef SectionName; - error(Section.getName(SectionName)); + StringRef SectionName = + unwrapOrError(Obj->getFileName(), Section.getName()); + if (!First) W.startLine() << '\n'; First = false; W.startLine() << "Hex dump of section '" << SectionName << "':\n"; - StringRef SectionContent = unwrapOrError(Section.getContents()); + StringRef SectionContent = + unwrapOrError(Obj->getFileName(), Section.getContents()); const uint8_t *SecContent = SectionContent.bytes_begin(); const uint8_t *SecEnd = SecContent + SectionContent.size(); diff --git a/tools/llvm-readobj/ObjDumper.h b/tools/llvm-readobj/ObjDumper.h index aaabfa2ca2e8..2ba441342499 100644 --- a/tools/llvm-readobj/ObjDumper.h +++ b/tools/llvm-readobj/ObjDumper.h @@ -68,15 +68,8 @@ public: virtual void printAddrsig() {} virtual void printNotes() {} virtual void printELFLinkerOptions() {} - - // Only implemented for ARM ELF at this time. - virtual void printAttributes() { } - - // Only implemented for MIPS ELF at this time. - virtual void printMipsPLTGOT() { } - virtual void printMipsABIFlags() { } - virtual void printMipsReginfo() { } - virtual void printMipsOptions() { } + virtual void printStackSizes() {} + virtual void printArchSpecificInfo() { } // Only implemented for PE/COFF. virtual void printCOFFImports() { } diff --git a/tools/llvm-readobj/WasmDumper.cpp b/tools/llvm-readobj/WasmDumper.cpp index 041a9a15bdb6..dfab9f40d71b 100644 --- a/tools/llvm-readobj/WasmDumper.cpp +++ b/tools/llvm-readobj/WasmDumper.cpp @@ -51,6 +51,7 @@ static const EnumEntry<unsigned> WasmSymbolFlags[] = { ENUM_ENTRY(UNDEFINED), ENUM_ENTRY(EXPORTED), ENUM_ENTRY(EXPLICIT_NAME), + ENUM_ENTRY(NO_STRIP), #undef ENUM_ENTRY }; @@ -90,7 +91,7 @@ void WasmDumper::printRelocation(const SectionRef &Section, StringRef SymName; symbol_iterator SI = Reloc.getSymbol(); if (SI != Obj->symbol_end()) - SymName = error(SI->getName()); + SymName = unwrapOrError(Obj->getFileName(), SI->getName()); bool HasAddend = false; switch (RelocType) { @@ -133,8 +134,8 @@ void WasmDumper::printRelocations() { int SectionNumber = 0; for (const SectionRef &Section : Obj->sections()) { bool PrintedGroup = false; - StringRef Name; - error(Section.getName(Name)); + StringRef Name = unwrapOrError(Obj->getFileName(), Section.getName()); + ++SectionNumber; for (const RelocationRef &Reloc : Section.relocations()) { diff --git a/tools/llvm-readobj/Win64EHDumper.cpp b/tools/llvm-readobj/Win64EHDumper.cpp index e64b8f157180..fa268ce9d434 100644 --- a/tools/llvm-readobj/Win64EHDumper.cpp +++ b/tools/llvm-readobj/Win64EHDumper.cpp @@ -289,7 +289,9 @@ void Dumper::printRuntimeFunction(const Context &Ctx, resolveRelocation(Ctx, Section, SectionOffset + 8, XData, Offset); ArrayRef<uint8_t> Contents; - error(Ctx.COFF.getSectionContents(XData, Contents)); + if (Error E = Ctx.COFF.getSectionContents(XData, Contents)) + reportError(std::move(E), Ctx.COFF.getFileName()); + if (Contents.empty()) return; @@ -304,14 +306,19 @@ void Dumper::printRuntimeFunction(const Context &Ctx, void Dumper::printData(const Context &Ctx) { for (const auto &Section : Ctx.COFF.sections()) { StringRef Name; - Section.getName(Name); + if (Expected<StringRef> NameOrErr = Section.getName()) + Name = *NameOrErr; + else + consumeError(NameOrErr.takeError()); if (Name != ".pdata" && !Name.startswith(".pdata$")) continue; const coff_section *PData = Ctx.COFF.getCOFFSection(Section); ArrayRef<uint8_t> Contents; - error(Ctx.COFF.getSectionContents(PData, Contents)); + + if (Error E = Ctx.COFF.getSectionContents(PData, Contents)) + reportError(std::move(E), Ctx.COFF.getFileName()); if (Contents.empty()) continue; diff --git a/tools/llvm-readobj/WindowsResourceDumper.cpp b/tools/llvm-readobj/WindowsResourceDumper.cpp index 13989f696d9d..a2fb6aac3f93 100644 --- a/tools/llvm-readobj/WindowsResourceDumper.cpp +++ b/tools/llvm-readobj/WindowsResourceDumper.cpp @@ -56,8 +56,12 @@ void Dumper::printEntry(const ResourceEntryRef &Ref) { if (Ref.checkTypeString()) { auto NarrowStr = stripUTF16(Ref.getTypeString()); SW.printString("Resource type (string)", NarrowStr); - } else - SW.printNumber("Resource type (int)", Ref.getTypeID()); + } else { + SmallString<20> IDStr; + raw_svector_ostream OS(IDStr); + printResourceTypeName(Ref.getTypeID(), OS); + SW.printString("Resource type (int)", IDStr); + } if (Ref.checkNameString()) { auto NarrowStr = stripUTF16(Ref.getNameString()); diff --git a/tools/llvm-readobj/XCOFFDumper.cpp b/tools/llvm-readobj/XCOFFDumper.cpp index 6f260f91537f..fe95b6d1b494 100644 --- a/tools/llvm-readobj/XCOFFDumper.cpp +++ b/tools/llvm-readobj/XCOFFDumper.cpp @@ -22,6 +22,12 @@ using namespace object; namespace { class XCOFFDumper : public ObjDumper { + enum { + SymbolTypeMask = 0x07, + SymbolAlignmentMask = 0xF8, + SymbolAlignmentBitOffset = 3 + }; + public: XCOFFDumper(const XCOFFObjectFile &Obj, ScopedPrinter &Writer) : ObjDumper(Writer), Obj(Obj) {} @@ -37,11 +43,21 @@ public: private: template <typename T> void printSectionHeaders(ArrayRef<T> Sections); - - const XCOFFObjectFile &Obj; + template <typename T> void printGenericSectionHeader(T &Sec) const; + template <typename T> void printOverflowSectionHeader(T &Sec) const; + void printFileAuxEnt(const XCOFFFileAuxEnt *AuxEntPtr); + void printCsectAuxEnt32(const XCOFFCsectAuxEnt32 *AuxEntPtr); + void printSectAuxEntForStat(const XCOFFSectAuxEntForStat *AuxEntPtr); + void printSymbol(const SymbolRef &); // Least significant 3 bits are reserved. static constexpr unsigned SectionFlagsReservedMask = 0x7; + + // The low order 16 bits of section flags denotes the section type. + static constexpr unsigned SectionFlagsTypeMask = 0xffffu; + + void printRelocations(ArrayRef<XCOFFSectionHeader32> Sections); + const XCOFFObjectFile &Obj; }; } // anonymous namespace @@ -100,11 +116,315 @@ void XCOFFDumper::printSectionHeaders() { } void XCOFFDumper::printRelocations() { - llvm_unreachable("Unimplemented functionality for XCOFFDumper"); + if (Obj.is64Bit()) + llvm_unreachable("64-bit relocation output not implemented!"); + else + printRelocations(Obj.sections32()); +} + +static const EnumEntry<XCOFF::RelocationType> RelocationTypeNameclass[] = { +#define ECase(X) \ + { #X, XCOFF::X } + ECase(R_POS), ECase(R_RL), ECase(R_RLA), ECase(R_NEG), + ECase(R_REL), ECase(R_TOC), ECase(R_TRL), ECase(R_TRLA), + ECase(R_GL), ECase(R_TCL), ECase(R_REF), ECase(R_BA), + ECase(R_BR), ECase(R_RBA), ECase(R_RBR), ECase(R_TLS), + ECase(R_TLS_IE), ECase(R_TLS_LD), ECase(R_TLS_LE), ECase(R_TLSM), + ECase(R_TLSML), ECase(R_TOCU), ECase(R_TOCL) +#undef ECase +}; + +void XCOFFDumper::printRelocations(ArrayRef<XCOFFSectionHeader32> Sections) { + if (!opts::ExpandRelocs) + report_fatal_error("Unexpanded relocation output not implemented."); + + ListScope LS(W, "Relocations"); + uint16_t Index = 0; + for (const auto &Sec : Sections) { + ++Index; + // Only the .text, .data, .tdata, and STYP_DWARF sections have relocation. + if (Sec.Flags != XCOFF::STYP_TEXT && Sec.Flags != XCOFF::STYP_DATA && + Sec.Flags != XCOFF::STYP_TDATA && Sec.Flags != XCOFF::STYP_DWARF) + continue; + auto Relocations = unwrapOrError(Obj.getFileName(), Obj.relocations(Sec)); + if (Relocations.empty()) + continue; + + W.startLine() << "Section (index: " << Index << ") " << Sec.getName() + << " {\n"; + for (auto Reloc : Relocations) { + StringRef SymbolName = unwrapOrError( + Obj.getFileName(), Obj.getSymbolNameByIndex(Reloc.SymbolIndex)); + + DictScope RelocScope(W, "Relocation"); + W.printHex("Virtual Address", Reloc.VirtualAddress); + W.printNumber("Symbol", SymbolName, Reloc.SymbolIndex); + W.printString("IsSigned", Reloc.isRelocationSigned() ? "Yes" : "No"); + W.printNumber("FixupBitValue", Reloc.isFixupIndicated() ? 1 : 0); + W.printNumber("Length", Reloc.getRelocatedLength()); + W.printEnum("Type", (uint8_t)Reloc.Type, + makeArrayRef(RelocationTypeNameclass)); + } + W.unindent(); + W.startLine() << "}\n"; + } +} + +static const EnumEntry<XCOFF::CFileStringType> FileStringType[] = { +#define ECase(X) \ + { #X, XCOFF::X } + ECase(XFT_FN), ECase(XFT_CT), ECase(XFT_CV), ECase(XFT_CD) +#undef ECase +}; + +void XCOFFDumper::printFileAuxEnt(const XCOFFFileAuxEnt *AuxEntPtr) { + if (Obj.is64Bit()) + report_fatal_error( + "Printing for File Auxiliary Entry in 64-bit is unimplemented."); + StringRef FileName = + unwrapOrError(Obj.getFileName(), Obj.getCFileName(AuxEntPtr)); + DictScope SymDs(W, "File Auxiliary Entry"); + W.printNumber("Index", + Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr))); + W.printString("Name", FileName); + W.printEnum("Type", static_cast<uint8_t>(AuxEntPtr->Type), + makeArrayRef(FileStringType)); +} + +static const EnumEntry<XCOFF::StorageMappingClass> CsectStorageMappingClass[] = + { +#define ECase(X) \ + { #X, XCOFF::X } + ECase(XMC_PR), ECase(XMC_RO), ECase(XMC_DB), + ECase(XMC_GL), ECase(XMC_XO), ECase(XMC_SV), + ECase(XMC_SV64), ECase(XMC_SV3264), ECase(XMC_TI), + ECase(XMC_TB), ECase(XMC_RW), ECase(XMC_TC0), + ECase(XMC_TC), ECase(XMC_TD), ECase(XMC_DS), + ECase(XMC_UA), ECase(XMC_BS), ECase(XMC_UC), + ECase(XMC_TL), ECase(XMC_TE) +#undef ECase +}; + +static const EnumEntry<XCOFF::SymbolType> CsectSymbolTypeClass[] = { +#define ECase(X) \ + { #X, XCOFF::X } + ECase(XTY_ER), ECase(XTY_SD), ECase(XTY_LD), ECase(XTY_CM) +#undef ECase +}; + +void XCOFFDumper::printCsectAuxEnt32(const XCOFFCsectAuxEnt32 *AuxEntPtr) { + assert(!Obj.is64Bit() && "32-bit interface called on 64-bit object file."); + + DictScope SymDs(W, "CSECT Auxiliary Entry"); + W.printNumber("Index", + Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr))); + if ((AuxEntPtr->SymbolAlignmentAndType & SymbolTypeMask) == XCOFF::XTY_LD) + W.printNumber("ContainingCsectSymbolIndex", AuxEntPtr->SectionOrLength); + else + W.printNumber("SectionLen", AuxEntPtr->SectionOrLength); + W.printHex("ParameterHashIndex", AuxEntPtr->ParameterHashIndex); + W.printHex("TypeChkSectNum", AuxEntPtr->TypeChkSectNum); + // Print out symbol alignment and type. + W.printNumber("SymbolAlignmentLog2", + (AuxEntPtr->SymbolAlignmentAndType & SymbolAlignmentMask) >> + SymbolAlignmentBitOffset); + W.printEnum("SymbolType", AuxEntPtr->SymbolAlignmentAndType & SymbolTypeMask, + makeArrayRef(CsectSymbolTypeClass)); + W.printEnum("StorageMappingClass", + static_cast<uint8_t>(AuxEntPtr->StorageMappingClass), + makeArrayRef(CsectStorageMappingClass)); + W.printHex("StabInfoIndex", AuxEntPtr->StabInfoIndex); + W.printHex("StabSectNum", AuxEntPtr->StabSectNum); +} + +void XCOFFDumper::printSectAuxEntForStat( + const XCOFFSectAuxEntForStat *AuxEntPtr) { + assert(!Obj.is64Bit() && "32-bit interface called on 64-bit object file."); + + DictScope SymDs(W, "Sect Auxiliary Entry For Stat"); + W.printNumber("Index", + Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr))); + W.printNumber("SectionLength", AuxEntPtr->SectionLength); + + // Unlike the corresponding fields in the section header, NumberOfRelocEnt + // and NumberOfLineNum do not handle values greater than 65535. + W.printNumber("NumberOfRelocEnt", AuxEntPtr->NumberOfRelocEnt); + W.printNumber("NumberOfLineNum", AuxEntPtr->NumberOfLineNum); +} + +static const EnumEntry<XCOFF::StorageClass> SymStorageClass[] = { +#define ECase(X) \ + { #X, XCOFF::X } + ECase(C_NULL), ECase(C_AUTO), ECase(C_EXT), ECase(C_STAT), + ECase(C_REG), ECase(C_EXTDEF), ECase(C_LABEL), ECase(C_ULABEL), + ECase(C_MOS), ECase(C_ARG), ECase(C_STRTAG), ECase(C_MOU), + ECase(C_UNTAG), ECase(C_TPDEF), ECase(C_USTATIC), ECase(C_ENTAG), + ECase(C_MOE), ECase(C_REGPARM), ECase(C_FIELD), ECase(C_BLOCK), + ECase(C_FCN), ECase(C_EOS), ECase(C_FILE), ECase(C_LINE), + ECase(C_ALIAS), ECase(C_HIDDEN), ECase(C_HIDEXT), ECase(C_BINCL), + ECase(C_EINCL), ECase(C_INFO), ECase(C_WEAKEXT), ECase(C_DWARF), + ECase(C_GSYM), ECase(C_LSYM), ECase(C_PSYM), ECase(C_RSYM), + ECase(C_RPSYM), ECase(C_STSYM), ECase(C_TCSYM), ECase(C_BCOMM), + ECase(C_ECOML), ECase(C_ECOMM), ECase(C_DECL), ECase(C_ENTRY), + ECase(C_FUN), ECase(C_BSTAT), ECase(C_ESTAT), ECase(C_GTLS), + ECase(C_STTLS), ECase(C_EFCN) +#undef ECase +}; + +static StringRef GetSymbolValueName(XCOFF::StorageClass SC) { + switch (SC) { + case XCOFF::C_EXT: + case XCOFF::C_WEAKEXT: + case XCOFF::C_HIDEXT: + case XCOFF::C_STAT: + return "Value (RelocatableAddress)"; + case XCOFF::C_FILE: + return "Value (SymbolTableIndex)"; + case XCOFF::C_FCN: + case XCOFF::C_BLOCK: + case XCOFF::C_FUN: + case XCOFF::C_STSYM: + case XCOFF::C_BINCL: + case XCOFF::C_EINCL: + case XCOFF::C_INFO: + case XCOFF::C_BSTAT: + case XCOFF::C_LSYM: + case XCOFF::C_PSYM: + case XCOFF::C_RPSYM: + case XCOFF::C_RSYM: + case XCOFF::C_ECOML: + case XCOFF::C_DWARF: + assert(false && "This StorageClass for the symbol is not yet implemented."); + return ""; + default: + return "Value"; + } +} + +static const EnumEntry<XCOFF::CFileLangId> CFileLangIdClass[] = { +#define ECase(X) \ + { #X, XCOFF::X } + ECase(TB_C), ECase(TB_CPLUSPLUS) +#undef ECase +}; + +static const EnumEntry<XCOFF::CFileCpuId> CFileCpuIdClass[] = { +#define ECase(X) \ + { #X, XCOFF::X } + ECase(TCPU_PPC64), ECase(TCPU_COM), ECase(TCPU_970) +#undef ECase +}; + +void XCOFFDumper::printSymbol(const SymbolRef &S) { + if (Obj.is64Bit()) + report_fatal_error("64-bit support is unimplemented."); + + DataRefImpl SymbolDRI = S.getRawDataRefImpl(); + const XCOFFSymbolEntry *SymbolEntPtr = Obj.toSymbolEntry(SymbolDRI); + + XCOFFSymbolRef XCOFFSymRef(SymbolDRI, &Obj); + uint8_t NumberOfAuxEntries = XCOFFSymRef.getNumberOfAuxEntries(); + + DictScope SymDs(W, "Symbol"); + + StringRef SymbolName = + unwrapOrError(Obj.getFileName(), Obj.getSymbolName(SymbolDRI)); + + W.printNumber("Index", + Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(SymbolEntPtr))); + W.printString("Name", SymbolName); + W.printHex(GetSymbolValueName(SymbolEntPtr->StorageClass), + SymbolEntPtr->Value); + + StringRef SectionName = + unwrapOrError(Obj.getFileName(), Obj.getSymbolSectionName(SymbolEntPtr)); + + W.printString("Section", SectionName); + if (XCOFFSymRef.getStorageClass() == XCOFF::C_FILE) { + W.printEnum("Source Language ID", + SymbolEntPtr->CFileLanguageIdAndTypeId.LanguageId, + makeArrayRef(CFileLangIdClass)); + W.printEnum("CPU Version ID", + SymbolEntPtr->CFileLanguageIdAndTypeId.CpuTypeId, + makeArrayRef(CFileCpuIdClass)); + } else + W.printHex("Type", SymbolEntPtr->SymbolType); + + W.printEnum("StorageClass", static_cast<uint8_t>(SymbolEntPtr->StorageClass), + makeArrayRef(SymStorageClass)); + W.printNumber("NumberOfAuxEntries", SymbolEntPtr->NumberOfAuxEntries); + + if (NumberOfAuxEntries == 0) + return; + + switch (XCOFFSymRef.getStorageClass()) { + case XCOFF::C_FILE: + // If the symbol is C_FILE and has auxiliary entries... + for (int i = 1; i <= NumberOfAuxEntries; i++) { + const XCOFFFileAuxEnt *FileAuxEntPtr = + reinterpret_cast<const XCOFFFileAuxEnt *>(SymbolEntPtr + i); +#ifndef NDEBUG + Obj.checkSymbolEntryPointer(reinterpret_cast<uintptr_t>(FileAuxEntPtr)); +#endif + printFileAuxEnt(FileAuxEntPtr); + } + break; + case XCOFF::C_EXT: + case XCOFF::C_WEAKEXT: + case XCOFF::C_HIDEXT: + // If the symbol is for a function, and it has more than 1 auxiliary entry, + // then one of them must be function auxiliary entry which we do not + // support yet. + if (XCOFFSymRef.isFunction() && NumberOfAuxEntries >= 2) + report_fatal_error("Function auxiliary entry printing is unimplemented."); + + // If there is more than 1 auxiliary entry, instead of printing out + // error information, print out the raw Auxiliary entry from 1st till + // the last - 1. The last one must be a CSECT Auxiliary Entry. + for (int i = 1; i < NumberOfAuxEntries; i++) { + W.startLine() << "!Unexpected raw auxiliary entry data:\n"; + W.startLine() << format_bytes( + ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(SymbolEntPtr + i), + XCOFF::SymbolTableEntrySize)); + } + + // The symbol's last auxiliary entry is a CSECT Auxiliary Entry. + printCsectAuxEnt32(XCOFFSymRef.getXCOFFCsectAuxEnt32()); + break; + case XCOFF::C_STAT: + if (NumberOfAuxEntries > 1) + report_fatal_error( + "C_STAT symbol should not have more than 1 auxiliary entry."); + + const XCOFFSectAuxEntForStat *StatAuxEntPtr; + StatAuxEntPtr = + reinterpret_cast<const XCOFFSectAuxEntForStat *>(SymbolEntPtr + 1); +#ifndef NDEBUG + Obj.checkSymbolEntryPointer(reinterpret_cast<uintptr_t>(StatAuxEntPtr)); +#endif + printSectAuxEntForStat(StatAuxEntPtr); + break; + case XCOFF::C_DWARF: + case XCOFF::C_BLOCK: + case XCOFF::C_FCN: + report_fatal_error("Symbol table entry printing for this storage class " + "type is unimplemented."); + break; + default: + for (int i = 1; i <= NumberOfAuxEntries; i++) { + W.startLine() << "!Unexpected raw auxiliary entry data:\n"; + W.startLine() << format_bytes( + ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(SymbolEntPtr + i), + XCOFF::SymbolTableEntrySize)); + } + break; + } } void XCOFFDumper::printSymbols() { - llvm_unreachable("Unimplemented functionality for XCOFFDumper"); + ListScope Group(W, "Symbols"); + for (const SymbolRef &S : Obj.symbols()) + printSymbol(S); } void XCOFFDumper::printDynamicSymbols() { @@ -135,6 +455,39 @@ static const EnumEntry<XCOFF::SectionTypeFlags> SectionTypeFlagsNames[] = { }; template <typename T> +void XCOFFDumper::printOverflowSectionHeader(T &Sec) const { + if (Obj.is64Bit()) { + reportWarning(make_error<StringError>("An 64-bit XCOFF object file may not " + "contain an overflow section header.", + object_error::parse_failed), + Obj.getFileName()); + } + + W.printString("Name", Sec.getName()); + W.printNumber("NumberOfRelocations", Sec.PhysicalAddress); + W.printNumber("NumberOfLineNumbers", Sec.VirtualAddress); + W.printHex("Size", Sec.SectionSize); + W.printHex("RawDataOffset", Sec.FileOffsetToRawData); + W.printHex("RelocationPointer", Sec.FileOffsetToRelocationInfo); + W.printHex("LineNumberPointer", Sec.FileOffsetToLineNumberInfo); + W.printNumber("IndexOfSectionOverflowed", Sec.NumberOfRelocations); + W.printNumber("IndexOfSectionOverflowed", Sec.NumberOfLineNumbers); +} + +template <typename T> +void XCOFFDumper::printGenericSectionHeader(T &Sec) const { + W.printString("Name", Sec.getName()); + W.printHex("PhysicalAddress", Sec.PhysicalAddress); + W.printHex("VirtualAddress", Sec.VirtualAddress); + W.printHex("Size", Sec.SectionSize); + W.printHex("RawDataOffset", Sec.FileOffsetToRawData); + W.printHex("RelocationPointer", Sec.FileOffsetToRelocationInfo); + W.printHex("LineNumberPointer", Sec.FileOffsetToLineNumberInfo); + W.printNumber("NumberOfRelocations", Sec.NumberOfRelocations); + W.printNumber("NumberOfLineNumbers", Sec.NumberOfLineNumbers); +} + +template <typename T> void XCOFFDumper::printSectionHeaders(ArrayRef<T> Sections) { ListScope Group(W, "Sections"); @@ -143,27 +496,28 @@ void XCOFFDumper::printSectionHeaders(ArrayRef<T> Sections) { DictScope SecDS(W, "Section"); W.printNumber("Index", Index++); - W.printString("Name", Sec.getName()); - - W.printHex("PhysicalAddress", Sec.PhysicalAddress); - W.printHex("VirtualAddress", Sec.VirtualAddress); - W.printHex("Size", Sec.SectionSize); - W.printHex("RawDataOffset", Sec.FileOffsetToRawData); - W.printHex("RelocationPointer", Sec.FileOffsetToRelocationInfo); - W.printHex("LineNumberPointer", Sec.FileOffsetToLineNumberInfo); - - // TODO Need to add overflow handling when NumberOfX == _OVERFLOW_MARKER - // in 32-bit object files. - W.printNumber("NumberOfRelocations", Sec.NumberOfRelocations); - W.printNumber("NumberOfLineNumbers", Sec.NumberOfLineNumbers); - - // The most significant 16-bits represent the DWARF section subtype. For - // now we just dump the section type flags. - uint16_t Flags = Sec.Flags & 0xffffu; - if (Flags & SectionFlagsReservedMask) - W.printHex("Flags", "Reserved", Flags); + + uint16_t SectionType = Sec.Flags & SectionFlagsTypeMask; + switch (SectionType) { + case XCOFF::STYP_OVRFLO: + printOverflowSectionHeader(Sec); + break; + case XCOFF::STYP_LOADER: + case XCOFF::STYP_EXCEPT: + case XCOFF::STYP_TYPCHK: + // TODO The interpretation of loader, exception and type check section + // headers are different from that of generic section headers. We will + // implement them later. We interpret them as generic section headers for + // now. + default: + printGenericSectionHeader(Sec); + break; + } + // For now we just dump the section type portion of the flags. + if (SectionType & SectionFlagsReservedMask) + W.printHex("Flags", "Reserved", SectionType); else - W.printEnum("Type", Flags, makeArrayRef(SectionTypeFlagsNames)); + W.printEnum("Type", SectionType, makeArrayRef(SectionTypeFlagsNames)); } if (opts::SectionRelocations) diff --git a/tools/llvm-readobj/llvm-readobj.cpp b/tools/llvm-readobj/llvm-readobj.cpp index 1bd5bb74bf29..4db13897879d 100644 --- a/tools/llvm-readobj/llvm-readobj.cpp +++ b/tools/llvm-readobj/llvm-readobj.cpp @@ -231,26 +231,11 @@ namespace opts { "codeview-subsection-bytes", cl::desc("Dump raw contents of codeview debug sections and records")); - // --arm-attributes - cl::opt<bool> ARMAttributes("arm-attributes", - cl::desc("Display the ARM attributes section")); - - // --mips-plt-got - cl::opt<bool> - MipsPLTGOT("mips-plt-got", - cl::desc("Display the MIPS GOT and PLT GOT sections")); - - // --mips-abi-flags - cl::opt<bool> MipsABIFlags("mips-abi-flags", - cl::desc("Display the MIPS.abiflags section")); - - // --mips-reginfo - cl::opt<bool> MipsReginfo("mips-reginfo", - cl::desc("Display the MIPS .reginfo section")); - - // --mips-options - cl::opt<bool> MipsOptions("mips-options", - cl::desc("Display the MIPS .MIPS.options section")); + // --arch-specific + cl::opt<bool> ArchSpecificInfo("arch-specific", + cl::desc("Displays architecture-specific information, if there is any.")); + cl::alias ArchSpecifcInfoShort("A", cl::desc("Alias for --arch-specific"), + cl::aliasopt(ArchSpecificInfo), cl::NotHidden); // --coff-imports cl::opt<bool> @@ -324,6 +309,11 @@ namespace opts { PrintStackMap("stackmap", cl::desc("Display contents of stackmap section")); + // --stack-sizes + cl::opt<bool> + PrintStackSizes("stack-sizes", + cl::desc("Display contents of all stack sizes sections")); + // --version-info, -V cl::opt<bool> VersionInfo("version-info", @@ -368,63 +358,45 @@ namespace opts { HelpResponse("\nPass @FILE as argument to read options from FILE.\n"); } // namespace opts +static StringRef ToolName; + namespace llvm { -LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg) { +LLVM_ATTRIBUTE_NORETURN static void error(Twine Msg) { + // Flush the standard output to print the error at a + // proper place. fouts().flush(); errs() << "\n"; - WithColor::error(errs()) << Msg << "\n"; + WithColor::error(errs(), ToolName) << Msg << "\n"; exit(1); } -void reportError(StringRef Input, Error Err) { +LLVM_ATTRIBUTE_NORETURN void reportError(Error Err, StringRef Input) { + assert(Err); if (Input == "-") Input = "<stdin>"; - error(createFileError(Input, std::move(Err))); + handleAllErrors(createFileError(Input, std::move(Err)), + [&](const ErrorInfoBase &EI) { error(EI.message()); }); + llvm_unreachable("error() call should never return"); } -void reportWarning(Twine Msg) { - fouts().flush(); - errs() << "\n"; - WithColor::warning(errs()) << Msg << "\n"; -} - -void warn(Error Err) { - handleAllErrors(std::move(Err), [&](const ErrorInfoBase &EI) { - reportWarning(EI.message()); - }); -} - -void error(Error EC) { - if (!EC) - return; - handleAllErrors(std::move(EC), - [&](const ErrorInfoBase &EI) { reportError(EI.message()); }); -} +void reportWarning(Error Err, StringRef Input) { + assert(Err); + if (Input == "-") + Input = "<stdin>"; -void error(std::error_code EC) { - if (!EC) - return; - reportError(EC.message()); + // Flush the standard output to print the warning at a + // proper place. + fouts().flush(); + handleAllErrors( + createFileError(Input, std::move(Err)), [&](const ErrorInfoBase &EI) { + errs() << "\n"; + WithColor::warning(errs(), ToolName) << EI.message() << "\n"; + }); } } // namespace llvm -static void reportError(StringRef Input, std::error_code EC) { - reportError(Input, errorCodeToError(EC)); -} - -static bool isMipsArch(unsigned Arch) { - switch (Arch) { - case llvm::Triple::mips: - case llvm::Triple::mipsel: - case llvm::Triple::mips64: - case llvm::Triple::mips64el: - return true; - default: - return false; - } -} namespace { struct ReadObjTypeTableBuilder { ReadObjTypeTableBuilder() @@ -471,19 +443,19 @@ static void dumpObject(const ObjectFile *Obj, ScopedPrinter &Writer, std::unique_ptr<ObjDumper> Dumper; if (std::error_code EC = createDumper(Obj, Writer, Dumper)) - reportError(FileStr, EC); + reportError(errorCodeToError(EC), FileStr); - Writer.startLine() << "\n"; - if (opts::Output == opts::LLVM) { + if (opts::Output == opts::LLVM || opts::InputFilenames.size() > 1 || A) { + Writer.startLine() << "\n"; Writer.printString("File", FileStr); + } + if (opts::Output == opts::LLVM) { Writer.printString("Format", Obj->getFileFormatName()); Writer.printString("Arch", Triple::getArchTypeName( (llvm::Triple::ArchType)Obj->getArch())); Writer.printString("AddressSize", formatv("{0}bit", 8 * Obj->getBytesInAddress())); Dumper->printLoadName(); - } else if (opts::Output == opts::GNU && A) { - Writer.printString("File", FileStr); } if (opts::FileHeaders) @@ -519,19 +491,8 @@ static void dumpObject(const ObjectFile *Obj, ScopedPrinter &Writer, if (Obj->isELF()) { if (opts::ELFLinkerOptions) Dumper->printELFLinkerOptions(); - if (Obj->getArch() == llvm::Triple::arm) - if (opts::ARMAttributes) - Dumper->printAttributes(); - if (isMipsArch(Obj->getArch())) { - if (opts::MipsPLTGOT) - Dumper->printMipsPLTGOT(); - if (opts::MipsABIFlags) - Dumper->printMipsABIFlags(); - if (opts::MipsReginfo) - Dumper->printMipsReginfo(); - if (opts::MipsOptions) - Dumper->printMipsOptions(); - } + if (opts::ArchSpecificInfo) + Dumper->printArchSpecificInfo(); if (opts::SectionGroups) Dumper->printGroupSections(); if (opts::HashHistogram) @@ -583,6 +544,8 @@ static void dumpObject(const ObjectFile *Obj, ScopedPrinter &Writer, } if (opts::PrintStackMap) Dumper->printStackMap(); + if (opts::PrintStackSizes) + Dumper->printStackSizes(); } /// Dumps each object file in \a Arc; @@ -591,9 +554,8 @@ static void dumpArchive(const Archive *Arc, ScopedPrinter &Writer) { for (auto &Child : Arc->children(Err)) { Expected<std::unique_ptr<Binary>> ChildOrErr = Child.getAsBinary(); if (!ChildOrErr) { - if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError())) { - reportError(Arc->getFileName(), std::move(E)); - } + if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError())) + reportError(std::move(E), Arc->getFileName()); continue; } if (ObjectFile *Obj = dyn_cast<ObjectFile>(&*ChildOrErr.get())) @@ -601,10 +563,11 @@ static void dumpArchive(const Archive *Arc, ScopedPrinter &Writer) { else if (COFFImportFile *Imp = dyn_cast<COFFImportFile>(&*ChildOrErr.get())) dumpCOFFImportFile(Imp, Writer); else - reportError(Arc->getFileName(), readobj_error::unrecognized_file_format); + reportError(errorCodeToError(readobj_error::unrecognized_file_format), + Arc->getFileName()); } if (Err) - reportError(Arc->getFileName(), std::move(Err)); + reportError(std::move(Err), Arc->getFileName()); } /// Dumps each object file in \a MachO Universal Binary; @@ -614,9 +577,8 @@ static void dumpMachOUniversalBinary(const MachOUniversalBinary *UBinary, Expected<std::unique_ptr<MachOObjectFile>> ObjOrErr = Obj.getAsObjectFile(); if (ObjOrErr) dumpObject(&*ObjOrErr.get(), Writer); - else if (auto E = isNotObjectErrorInvalidFileType(ObjOrErr.takeError())) { - reportError(UBinary->getFileName(), ObjOrErr.takeError()); - } + else if (auto E = isNotObjectErrorInvalidFileType(ObjOrErr.takeError())) + reportError(ObjOrErr.takeError(), UBinary->getFileName()); else if (Expected<std::unique_ptr<Archive>> AOrErr = Obj.getAsArchive()) dumpArchive(&*AOrErr.get(), Writer); } @@ -627,7 +589,7 @@ static void dumpWindowsResourceFile(WindowsResource *WinRes, ScopedPrinter &Printer) { WindowsRes::Dumper Dumper(WinRes, Printer); if (auto Err = Dumper.printData()) - reportError(WinRes->getFileName(), std::move(Err)); + reportError(std::move(Err), WinRes->getFileName()); } @@ -636,7 +598,7 @@ static void dumpInput(StringRef File, ScopedPrinter &Writer) { // Attempt to open the binary. Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(File); if (!BinaryOrErr) - reportError(File, BinaryOrErr.takeError()); + reportError(BinaryOrErr.takeError(), File); Binary &Binary = *BinaryOrErr.get().getBinary(); if (Archive *Arc = dyn_cast<Archive>(&Binary)) @@ -651,7 +613,8 @@ static void dumpInput(StringRef File, ScopedPrinter &Writer) { else if (WindowsResource *WinRes = dyn_cast<WindowsResource>(&Binary)) dumpWindowsResourceFile(WinRes, Writer); else - reportError(File, readobj_error::unrecognized_file_format); + reportError(errorCodeToError(readobj_error::unrecognized_file_format), + File); CVTypes.Binaries.push_back(std::move(*BinaryOrErr)); } @@ -702,6 +665,7 @@ static void registerReadelfAliases() { int main(int argc, const char *argv[]) { InitLLVM X(argc, argv); + ToolName = argv[0]; // Register the target printer for --version. cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion); @@ -727,6 +691,10 @@ int main(int argc, const char *argv[]) { opts::UnwindInfo = true; opts::SectionGroups = true; opts::HashHistogram = true; + if (opts::Output == opts::LLVM) { + opts::Addrsig = true; + opts::PrintStackSizes = true; + } } if (opts::Headers) { diff --git a/tools/llvm-readobj/llvm-readobj.h b/tools/llvm-readobj/llvm-readobj.h index 0e02da4cb847..d9813f5dea62 100644 --- a/tools/llvm-readobj/llvm-readobj.h +++ b/tools/llvm-readobj/llvm-readobj.h @@ -21,30 +21,13 @@ namespace llvm { } // Various helper functions. - LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg); - void reportError(StringRef Input, Error Err); - void reportWarning(Twine Msg); - void warn(llvm::Error Err); - void error(std::error_code EC); - void error(llvm::Error EC); - template <typename T> T error(llvm::Expected<T> &&E) { - error(E.takeError()); - return std::move(*E); - } + LLVM_ATTRIBUTE_NORETURN void reportError(Error Err, StringRef Input); + void reportWarning(Error Err, StringRef Input); - template <class T> T unwrapOrError(ErrorOr<T> EO) { - if (EO) - return *EO; - reportError(EO.getError().message()); - } - template <class T> T unwrapOrError(Expected<T> EO) { + template <class T> T unwrapOrError(StringRef Input, Expected<T> EO) { if (EO) return *EO; - std::string Buf; - raw_string_ostream OS(Buf); - logAllUnhandledErrors(EO.takeError(), OS); - OS.flush(); - reportError(Buf); + reportError(EO.takeError(), Input); } } // namespace llvm |