diff options
Diffstat (limited to 'contrib/llvm/tools/llvm-readobj')
-rw-r--r-- | contrib/llvm/tools/llvm-readobj/ARMAttributeParser.cpp | 72 | ||||
-rw-r--r-- | contrib/llvm/tools/llvm-readobj/ARMEHABIPrinter.h | 64 | ||||
-rw-r--r-- | contrib/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp | 5 | ||||
-rw-r--r-- | contrib/llvm/tools/llvm-readobj/COFFDumper.cpp | 120 | ||||
-rw-r--r-- | contrib/llvm/tools/llvm-readobj/COFFImportDumper.cpp | 52 | ||||
-rw-r--r-- | contrib/llvm/tools/llvm-readobj/ELFDumper.cpp | 907 | ||||
-rw-r--r-- | contrib/llvm/tools/llvm-readobj/MachODumper.cpp | 240 | ||||
-rw-r--r-- | contrib/llvm/tools/llvm-readobj/ObjDumper.h | 19 | ||||
-rw-r--r-- | contrib/llvm/tools/llvm-readobj/StreamWriter.h | 32 | ||||
-rw-r--r-- | contrib/llvm/tools/llvm-readobj/Win64EHDumper.cpp | 21 | ||||
-rw-r--r-- | contrib/llvm/tools/llvm-readobj/llvm-readobj.cpp | 145 | ||||
-rw-r--r-- | contrib/llvm/tools/llvm-readobj/llvm-readobj.h | 4 |
12 files changed, 1283 insertions, 398 deletions
diff --git a/contrib/llvm/tools/llvm-readobj/ARMAttributeParser.cpp b/contrib/llvm/tools/llvm-readobj/ARMAttributeParser.cpp index e2d7191..688d349 100644 --- a/contrib/llvm/tools/llvm-readobj/ARMAttributeParser.cpp +++ b/contrib/llvm/tools/llvm-readobj/ARMAttributeParser.cpp @@ -118,7 +118,7 @@ void ARMAttributeParser::PrintAttribute(unsigned Tag, unsigned Value, void ARMAttributeParser::CPU_arch(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { + static const char *const Strings[] = { "Pre-v4", "ARM v4", "ARM v4T", "ARM v5T", "ARM v5TE", "ARM v5TEJ", "ARM v6", "ARM v6KZ", "ARM v6T2", "ARM v6K", "ARM v7", "ARM v6-M", "ARM v6S-M", "ARM v7E-M", "ARM v8" @@ -149,7 +149,7 @@ void ARMAttributeParser::CPU_arch_profile(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::ARM_ISA_use(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { "Not Permitted", "Permitted" }; + static const char *const Strings[] = { "Not Permitted", "Permitted" }; uint64_t Value = ParseInteger(Data, Offset); StringRef ValueDesc = @@ -159,7 +159,7 @@ void ARMAttributeParser::ARM_ISA_use(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::THUMB_ISA_use(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { "Not Permitted", "Thumb-1", "Thumb-2" }; + static const char *const Strings[] = { "Not Permitted", "Thumb-1", "Thumb-2" }; uint64_t Value = ParseInteger(Data, Offset); StringRef ValueDesc = @@ -169,7 +169,7 @@ void ARMAttributeParser::THUMB_ISA_use(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::FP_arch(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { + static const char *const Strings[] = { "Not Permitted", "VFPv1", "VFPv2", "VFPv3", "VFPv3-D16", "VFPv4", "VFPv4-D16", "ARMv8-a FP", "ARMv8-a FP-D16" }; @@ -182,7 +182,7 @@ void ARMAttributeParser::FP_arch(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::WMMX_arch(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { "Not Permitted", "WMMXv1", "WMMXv2" }; + static const char *const Strings[] = { "Not Permitted", "WMMXv1", "WMMXv2" }; uint64_t Value = ParseInteger(Data, Offset); StringRef ValueDesc = @@ -192,8 +192,8 @@ void ARMAttributeParser::WMMX_arch(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::Advanced_SIMD_arch(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { - "Not Permitted", "NEONv1", "NEONv2+FMA", "ARMv8-a NEON" + static const char *const Strings[] = { + "Not Permitted", "NEONv1", "NEONv2+FMA", "ARMv8-a NEON", "ARMv8.1-a NEON" }; uint64_t Value = ParseInteger(Data, Offset); @@ -204,7 +204,7 @@ void ARMAttributeParser::Advanced_SIMD_arch(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::PCS_config(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { + static const char *const Strings[] = { "None", "Bare Platform", "Linux Application", "Linux DSO", "Palm OS 2004", "Reserved (Palm OS)", "Symbian OS 2004", "Reserved (Symbian OS)" }; @@ -217,7 +217,7 @@ void ARMAttributeParser::PCS_config(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::ABI_PCS_R9_use(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { "v6", "Static Base", "TLS", "Unused" }; + static const char *const Strings[] = { "v6", "Static Base", "TLS", "Unused" }; uint64_t Value = ParseInteger(Data, Offset); StringRef ValueDesc = @@ -227,7 +227,7 @@ void ARMAttributeParser::ABI_PCS_R9_use(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::ABI_PCS_RW_data(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { + static const char *const Strings[] = { "Absolute", "PC-relative", "SB-relative", "Not Permitted" }; @@ -239,7 +239,9 @@ void ARMAttributeParser::ABI_PCS_RW_data(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::ABI_PCS_RO_data(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { "Absolute", "PC-relative", "Not Permitted" }; + static const char *const Strings[] = { + "Absolute", "PC-relative", "Not Permitted" + }; uint64_t Value = ParseInteger(Data, Offset); StringRef ValueDesc = @@ -249,7 +251,9 @@ void ARMAttributeParser::ABI_PCS_RO_data(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::ABI_PCS_GOT_use(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { "Not Permitted", "Direct", "GOT-Indirect" }; + static const char *const Strings[] = { + "Not Permitted", "Direct", "GOT-Indirect" + }; uint64_t Value = ParseInteger(Data, Offset); StringRef ValueDesc = @@ -259,7 +263,7 @@ void ARMAttributeParser::ABI_PCS_GOT_use(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::ABI_PCS_wchar_t(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { + static const char *const Strings[] = { "Not Permitted", "Unknown", "2-byte", "Unknown", "4-byte" }; @@ -271,7 +275,7 @@ void ARMAttributeParser::ABI_PCS_wchar_t(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::ABI_FP_rounding(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { "IEEE-754", "Runtime" }; + static const char *const Strings[] = { "IEEE-754", "Runtime" }; uint64_t Value = ParseInteger(Data, Offset); StringRef ValueDesc = @@ -281,7 +285,9 @@ void ARMAttributeParser::ABI_FP_rounding(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::ABI_FP_denormal(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { "Unsupported", "IEEE-754", "Sign Only" }; + static const char *const Strings[] = { + "Unsupported", "IEEE-754", "Sign Only" + }; uint64_t Value = ParseInteger(Data, Offset); StringRef ValueDesc = @@ -291,7 +297,7 @@ void ARMAttributeParser::ABI_FP_denormal(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::ABI_FP_exceptions(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { "Not Permitted", "IEEE-754" }; + static const char *const Strings[] = { "Not Permitted", "IEEE-754" }; uint64_t Value = ParseInteger(Data, Offset); StringRef ValueDesc = @@ -302,7 +308,7 @@ void ARMAttributeParser::ABI_FP_exceptions(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::ABI_FP_user_exceptions(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { "Not Permitted", "IEEE-754" }; + static const char *const Strings[] = { "Not Permitted", "IEEE-754" }; uint64_t Value = ParseInteger(Data, Offset); StringRef ValueDesc = @@ -312,7 +318,7 @@ void ARMAttributeParser::ABI_FP_user_exceptions(AttrType Tag, void ARMAttributeParser::ABI_FP_number_model(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { + static const char *const Strings[] = { "Not Permitted", "Finite Only", "RTABI", "IEEE-754" }; @@ -324,7 +330,7 @@ void ARMAttributeParser::ABI_FP_number_model(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::ABI_align_needed(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { + static const char *const Strings[] = { "Not Permitted", "8-byte alignment", "4-byte alignment", "Reserved" }; @@ -344,7 +350,7 @@ void ARMAttributeParser::ABI_align_needed(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::ABI_align_preserved(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { + static const char *const Strings[] = { "Not Required", "8-byte data alignment", "8-byte data and code alignment", "Reserved" }; @@ -365,7 +371,7 @@ void ARMAttributeParser::ABI_align_preserved(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::ABI_enum_size(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { + static const char *const Strings[] = { "Not Permitted", "Packed", "Int32", "External Int32" }; @@ -377,7 +383,7 @@ void ARMAttributeParser::ABI_enum_size(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::ABI_HardFP_use(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { + static const char *const Strings[] = { "Tag_FP_arch", "Single-Precision", "Reserved", "Tag_FP_arch (deprecated)" }; @@ -389,7 +395,7 @@ void ARMAttributeParser::ABI_HardFP_use(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::ABI_VFP_args(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { + static const char *const Strings[] = { "AAPCS", "AAPCS VFP", "Custom", "Not Permitted" }; @@ -401,7 +407,7 @@ void ARMAttributeParser::ABI_VFP_args(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::ABI_WMMX_args(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { "AAPCS", "iWMMX", "Custom" }; + static const char *const Strings[] = { "AAPCS", "iWMMX", "Custom" }; uint64_t Value = ParseInteger(Data, Offset); StringRef ValueDesc = @@ -412,7 +418,7 @@ void ARMAttributeParser::ABI_WMMX_args(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::ABI_optimization_goals(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { + static const char *const Strings[] = { "None", "Speed", "Aggressive Speed", "Size", "Aggressive Size", "Debugging", "Best Debugging" }; @@ -426,7 +432,7 @@ void ARMAttributeParser::ABI_optimization_goals(AttrType Tag, void ARMAttributeParser::ABI_FP_optimization_goals(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { + static const char *const Strings[] = { "None", "Speed", "Aggressive Speed", "Size", "Aggressive Size", "Accuracy", "Best Accuracy" }; @@ -461,7 +467,7 @@ void ARMAttributeParser::compatibility(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::CPU_unaligned_access(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { "Not Permitted", "v6-style" }; + static const char *const Strings[] = { "Not Permitted", "v6-style" }; uint64_t Value = ParseInteger(Data, Offset); StringRef ValueDesc = @@ -471,7 +477,7 @@ void ARMAttributeParser::CPU_unaligned_access(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::FP_HP_extension(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { "If Available", "Permitted" }; + static const char *const Strings[] = { "If Available", "Permitted" }; uint64_t Value = ParseInteger(Data, Offset); StringRef ValueDesc = @@ -481,7 +487,7 @@ void ARMAttributeParser::FP_HP_extension(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::ABI_FP_16bit_format(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { "Not Permitted", "IEEE-754", "VFPv3" }; + static const char *const Strings[] = { "Not Permitted", "IEEE-754", "VFPv3" }; uint64_t Value = ParseInteger(Data, Offset); StringRef ValueDesc = @@ -491,7 +497,7 @@ void ARMAttributeParser::ABI_FP_16bit_format(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::MPextension_use(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { "Not Permitted", "Permitted" }; + static const char *const Strings[] = { "Not Permitted", "Permitted" }; uint64_t Value = ParseInteger(Data, Offset); StringRef ValueDesc = @@ -501,7 +507,7 @@ void ARMAttributeParser::MPextension_use(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::DIV_use(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { + static const char *const Strings[] = { "If Available", "Not Permitted", "Permitted" }; @@ -513,7 +519,7 @@ void ARMAttributeParser::DIV_use(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::T2EE_use(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { "Not Permitted", "Permitted" }; + static const char *const Strings[] = { "Not Permitted", "Permitted" }; uint64_t Value = ParseInteger(Data, Offset); StringRef ValueDesc = @@ -523,7 +529,7 @@ void ARMAttributeParser::T2EE_use(AttrType Tag, const uint8_t *Data, void ARMAttributeParser::Virtualization_use(AttrType Tag, const uint8_t *Data, uint32_t &Offset) { - static const char *Strings[] = { + static const char *const Strings[] = { "Not Permitted", "TrustZone", "Virtualization Extensions", "TrustZone + Virtualization Extensions" }; diff --git a/contrib/llvm/tools/llvm-readobj/ARMEHABIPrinter.h b/contrib/llvm/tools/llvm-readobj/ARMEHABIPrinter.h index dd2490d..beb5fd4 100644 --- a/contrib/llvm/tools/llvm-readobj/ARMEHABIPrinter.h +++ b/contrib/llvm/tools/llvm-readobj/ARMEHABIPrinter.h @@ -305,13 +305,15 @@ void OpcodeDecoder::Decode(const uint8_t *Opcodes, off_t Offset, size_t Length) template <typename ET> class PrinterContext { - StreamWriter &SW; - const object::ELFFile<ET> *ELF; - typedef typename object::ELFFile<ET>::Elf_Sym Elf_Sym; typedef typename object::ELFFile<ET>::Elf_Shdr Elf_Shdr; + typedef typename object::ELFFile<ET>::Elf_Rel Elf_Rel; + typedef typename object::ELFFile<ET>::Elf_Word Elf_Word; - typedef typename object::ELFFile<ET>::Elf_Rel_Iter Elf_Rel_iterator; + StreamWriter &SW; + const object::ELFFile<ET> *ELF; + const Elf_Shdr *Symtab; + ArrayRef<Elf_Word> ShndxTable; static const size_t IndexTableEntrySize; @@ -332,8 +334,9 @@ class PrinterContext { void PrintOpcodes(const uint8_t *Entry, size_t Length, off_t Offset) const; public: - PrinterContext(StreamWriter &Writer, const object::ELFFile<ET> *File) - : SW(Writer), ELF(File) {} + PrinterContext(StreamWriter &SW, const object::ELFFile<ET> *ELF, + const Elf_Shdr *Symtab) + : SW(SW), ELF(ELF), Symtab(Symtab) {} void PrintUnwindInformation() const; }; @@ -345,10 +348,14 @@ template <typename ET> ErrorOr<StringRef> PrinterContext<ET>::FunctionAtAddress(unsigned Section, uint64_t Address) const { - for (const Elf_Sym &Sym : ELF->symbols()) + ErrorOr<StringRef> StrTableOrErr = ELF->getStringTableForSymtab(*Symtab); + error(StrTableOrErr.getError()); + StringRef StrTable = *StrTableOrErr; + + for (const Elf_Sym &Sym : ELF->symbols(Symtab)) if (Sym.st_shndx == Section && Sym.st_value == Address && Sym.getType() == ELF::STT_FUNC) - return ELF->getSymbolName(&Sym, false); + return Sym.getName(StrTable); return readobj_error::unknown_symbol; } @@ -365,24 +372,29 @@ PrinterContext<ET>::FindExceptionTable(unsigned IndexSectionIndex, /// table. for (const Elf_Shdr &Sec : ELF->sections()) { - if (Sec.sh_type == ELF::SHT_REL && Sec.sh_info == IndexSectionIndex) { - for (Elf_Rel_iterator RI = ELF->rel_begin(&Sec), RE = ELF->rel_end(&Sec); - RI != RE; ++RI) { - if (RI->r_offset == static_cast<unsigned>(IndexTableOffset)) { - typename object::ELFFile<ET>::Elf_Rela RelA; - RelA.r_offset = RI->r_offset; - RelA.r_info = RI->r_info; - RelA.r_addend = 0; - - std::pair<const Elf_Shdr *, const Elf_Sym *> Symbol = - ELF->getRelocationSymbol(&Sec, &RelA); - - ErrorOr<const Elf_Shdr *> Ret = ELF->getSection(Symbol.second); - if (std::error_code EC = Ret.getError()) - report_fatal_error(EC.message()); - return *Ret; - } - } + if (Sec.sh_type != ELF::SHT_REL || Sec.sh_info != IndexSectionIndex) + continue; + + ErrorOr<const Elf_Shdr *> SymTabOrErr = ELF->getSection(Sec.sh_link); + error(SymTabOrErr.getError()); + const Elf_Shdr *SymTab = *SymTabOrErr; + + for (const Elf_Rel &R : ELF->rels(&Sec)) { + if (R.r_offset != static_cast<unsigned>(IndexTableOffset)) + continue; + + typename object::ELFFile<ET>::Elf_Rela RelA; + RelA.r_offset = R.r_offset; + RelA.r_info = R.r_info; + RelA.r_addend = 0; + + const Elf_Sym *Symbol = ELF->getRelocationSymbol(&RelA, SymTab); + + ErrorOr<const Elf_Shdr *> Ret = + ELF->getSection(Symbol, SymTab, ShndxTable); + if (std::error_code EC = Ret.getError()) + report_fatal_error(EC.message()); + return *Ret; } } return nullptr; diff --git a/contrib/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp b/contrib/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp index bf5ff8e..650955d 100644 --- a/contrib/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp +++ b/contrib/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp @@ -630,9 +630,10 @@ bool Decoder::dumpUnpackedEntry(const COFFObjectFile &COFF, SW.printString("ExceptionRecord", formatSymbol(*Name, Address)); - section_iterator SI = COFF.section_end(); - if (XDataRecord->getSection(SI)) + ErrorOr<section_iterator> SIOrErr = XDataRecord->getSection(); + if (!SIOrErr) return false; + section_iterator SI = *SIOrErr; return dumpXDataRecord(COFF, *SI, FunctionAddress, Address); } else { diff --git a/contrib/llvm/tools/llvm-readobj/COFFDumper.cpp b/contrib/llvm/tools/llvm-readobj/COFFDumper.cpp index cf897d7..516d1cf 100644 --- a/contrib/llvm/tools/llvm-readobj/COFFDumper.cpp +++ b/contrib/llvm/tools/llvm-readobj/COFFDumper.cpp @@ -60,6 +60,7 @@ public: void printCOFFExports() override; void printCOFFDirectives() override; void printCOFFBaseReloc() override; + void printCodeViewDebugInfo() override; void printStackMap() const override; private: void printSymbol(const SymbolRef &Sym); @@ -71,7 +72,7 @@ private: void printBaseOfDataField(const pe32_header *Hdr); void printBaseOfDataField(const pe32plus_header *Hdr); - void printCodeViewDebugInfo(const SectionRef &Section); + void printCodeViewSection(const SectionRef &Section); void printCodeViewSymbolsSubsection(StringRef Subsection, const SectionRef &Section, @@ -219,6 +220,7 @@ static const EnumEntry<COFF::DLLCharacteristics> PEDLLCharacteristics[] = { static const EnumEntry<COFF::SectionCharacteristics> ImageSectionCharacteristics[] = { + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_TYPE_NOLOAD ), LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_TYPE_NO_PAD ), LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_CNT_CODE ), LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_CNT_INITIALIZED_DATA ), @@ -385,14 +387,12 @@ 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; - if (error(Obj->getPE32Header(PEHeader))) - return; + error(Obj->getPE32Header(PEHeader)); if (PEHeader) printPEHeader<pe32_header>(PEHeader); const pe32plus_header *PEPlusHeader = nullptr; - if (error(Obj->getPE32PlusHeader(PEPlusHeader))) - return; + error(Obj->getPE32PlusHeader(PEPlusHeader)); if (PEPlusHeader) printPEHeader<pe32plus_header>(PEPlusHeader); @@ -475,10 +475,18 @@ void COFFDumper::printBaseOfDataField(const pe32_header *Hdr) { void COFFDumper::printBaseOfDataField(const pe32plus_header *) {} -void COFFDumper::printCodeViewDebugInfo(const SectionRef &Section) { +void COFFDumper::printCodeViewDebugInfo() { + for (const SectionRef &S : Obj->sections()) { + StringRef SecName; + error(S.getName(SecName)); + if (SecName == ".debug$S") + printCodeViewSection(S); + } +} + +void COFFDumper::printCodeViewSection(const SectionRef &Section) { StringRef Data; - if (error(Section.getContents(Data))) - return; + error(Section.getContents(Data)); SmallVector<StringRef, 10> FunctionNames; StringMap<StringRef> FunctionLineTables; @@ -518,8 +526,7 @@ void COFFDumper::printCodeViewDebugInfo(const SectionRef &Section) { switch (SubSectionType) { case COFF::DEBUG_SYMBOL_SUBSECTION: - if (opts::SectionSymbols) - printCodeViewSymbolsSubsection(Contents, Section, Offset); + printCodeViewSymbolsSubsection(Contents, Section, Offset); break; case COFF::DEBUG_LINE_TABLE_SUBSECTION: { // Holds a PC to file:line table. Some data to parse this subsection is @@ -533,19 +540,18 @@ void COFFDumper::printCodeViewDebugInfo(const SectionRef &Section) { return; } - StringRef FunctionName; - if (error(resolveSymbolName(Obj->getCOFFSection(Section), Offset, - FunctionName))) - return; - W.printString("FunctionName", FunctionName); - if (FunctionLineTables.count(FunctionName) != 0) { + StringRef LinkageName; + error(resolveSymbolName(Obj->getCOFFSection(Section), Offset, + LinkageName)); + W.printString("LinkageName", LinkageName); + if (FunctionLineTables.count(LinkageName) != 0) { // Saw debug info for this function already? error(object_error::parse_failed); return; } - FunctionLineTables[FunctionName] = Contents; - FunctionNames.push_back(FunctionName); + FunctionLineTables[LinkageName] = Contents; + FunctionNames.push_back(LinkageName); break; } case COFF::DEBUG_STRING_TABLE_SUBSECTION: @@ -582,7 +588,7 @@ void COFFDumper::printCodeViewDebugInfo(const SectionRef &Section) { for (unsigned I = 0, E = FunctionNames.size(); I != E; ++I) { StringRef Name = FunctionNames[I]; ListScope S(W, "FunctionLineTable"); - W.printString("FunctionName", Name); + W.printString("LinkageName", Name); DataExtractor DE(FunctionLineTables[Name], true, 4); uint32_t Offset = 6; // Skip relocations. @@ -695,9 +701,8 @@ void COFFDumper::printCodeViewSymbolsSubsection(StringRef Subsection, uint32_t CodeSize = DE.getU32(&Offset); DE.getU8(&Offset, Unused, 12); StringRef SectionName; - if (error(resolveSymbolName(Obj->getCOFFSection(Section), - OffsetInSection + Offset, SectionName))) - return; + error(resolveSymbolName(Obj->getCOFFSection(Section), + OffsetInSection + Offset, SectionName)); Offset += 4; DE.getU8(&Offset, Unused, 3); StringRef DisplayName = DE.getCStr(&Offset); @@ -748,8 +753,7 @@ void COFFDumper::printSections() { const coff_section *Section = Obj->getCOFFSection(Sec); StringRef Name; - if (error(Sec.getName(Name))) - Name = ""; + error(Sec.getName(Name)); DictScope D(W, "Section"); W.printNumber("Number", SectionNumber); @@ -782,14 +786,10 @@ void COFFDumper::printSections() { } } - if (Name == ".debug$S" && opts::CodeView) - printCodeViewDebugInfo(Sec); - if (opts::SectionData && !(Section->Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA)) { StringRef Data; - if (error(Sec.getContents(Data))) - break; + error(Sec.getContents(Data)); W.printBinaryBlock("SectionData", Data); } @@ -803,8 +803,7 @@ void COFFDumper::printRelocations() { for (const SectionRef &Section : Obj->sections()) { ++SectionNumber; StringRef Name; - if (error(Section.getName(Name))) - continue; + error(Section.getName(Name)); bool PrintedGroup = false; for (const RelocationRef &Reloc : Section.relocations()) { @@ -834,8 +833,7 @@ void COFFDumper::printRelocation(const SectionRef &Section, symbol_iterator Symbol = Reloc.getSymbol(); if (Symbol != Obj->symbol_end()) { ErrorOr<StringRef> SymbolNameOrErr = Symbol->getName(); - if (error(SymbolNameOrErr.getError())) - return; + error(SymbolNameOrErr.getError()); SymbolName = *SymbolNameOrErr; } @@ -914,8 +912,7 @@ void COFFDumper::printSymbol(const SymbolRef &Sym) { for (uint8_t I = 0; I < Symbol.getNumberOfAuxSymbols(); ++I) { if (Symbol.isFunctionDefinition()) { const coff_aux_function_definition *Aux; - if (error(getSymbolAuxData(Obj, Symbol, I, Aux))) - break; + error(getSymbolAuxData(Obj, Symbol, I, Aux)); DictScope AS(W, "AuxFunctionDef"); W.printNumber("TagIndex", Aux->TagIndex); @@ -925,8 +922,7 @@ void COFFDumper::printSymbol(const SymbolRef &Sym) { } else if (Symbol.isAnyUndefined()) { const coff_aux_weak_external *Aux; - if (error(getSymbolAuxData(Obj, Symbol, I, Aux))) - break; + error(getSymbolAuxData(Obj, Symbol, I, Aux)); ErrorOr<COFFSymbolRef> Linked = Obj->getSymbol(Aux->TagIndex); StringRef LinkedName; @@ -943,8 +939,7 @@ void COFFDumper::printSymbol(const SymbolRef &Sym) { } else if (Symbol.isFileRecord()) { const char *FileName; - if (error(getSymbolAuxData(Obj, Symbol, I, FileName))) - break; + error(getSymbolAuxData(Obj, Symbol, I, FileName)); DictScope AS(W, "AuxFileRecord"); @@ -954,8 +949,7 @@ void COFFDumper::printSymbol(const SymbolRef &Sym) { break; } else if (Symbol.isSectionDefinition()) { const coff_aux_section_definition *Aux; - if (error(getSymbolAuxData(Obj, Symbol, I, Aux))) - break; + error(getSymbolAuxData(Obj, Symbol, I, Aux)); int32_t AuxNumber = Aux->getNumber(Symbol.isBigObj()); @@ -986,8 +980,7 @@ void COFFDumper::printSymbol(const SymbolRef &Sym) { } } else if (Symbol.isCLRToken()) { const coff_aux_clr_token *Aux; - if (error(getSymbolAuxData(Obj, Symbol, I, Aux))) - break; + error(getSymbolAuxData(Obj, Symbol, I, Aux)); ErrorOr<COFFSymbolRef> ReferredSym = Obj->getSymbol(Aux->SymbolTableIndex); @@ -1040,9 +1033,9 @@ void COFFDumper::printImportedSymbols( iterator_range<imported_symbol_iterator> Range) { for (const ImportedSymbolRef &I : Range) { StringRef Sym; - if (error(I.getSymbolName(Sym))) return; + error(I.getSymbolName(Sym)); uint16_t Ordinal; - if (error(I.getOrdinal(Ordinal))) return; + error(I.getOrdinal(Ordinal)); W.printNumber("Symbol", Sym, Ordinal); } } @@ -1054,12 +1047,12 @@ void COFFDumper::printDelayImportedSymbols( for (const ImportedSymbolRef &S : Range) { DictScope Import(W, "Import"); StringRef Sym; - if (error(S.getSymbolName(Sym))) return; + error(S.getSymbolName(Sym)); uint16_t Ordinal; - if (error(S.getOrdinal(Ordinal))) return; + error(S.getOrdinal(Ordinal)); W.printNumber("Symbol", Sym, Ordinal); uint64_t Addr; - if (error(I.getImportAddress(Index++, Addr))) return; + error(I.getImportAddress(Index++, Addr)); W.printHex("Address", Addr); } } @@ -1069,12 +1062,12 @@ void COFFDumper::printCOFFImports() { for (const ImportDirectoryEntryRef &I : Obj->import_directories()) { DictScope Import(W, "Import"); StringRef Name; - if (error(I.getName(Name))) return; + error(I.getName(Name)); W.printString("Name", Name); uint32_t Addr; - if (error(I.getImportLookupTableRVA(Addr))) return; + error(I.getImportLookupTableRVA(Addr)); W.printHex("ImportLookupTableRVA", Addr); - if (error(I.getImportAddressTableRVA(Addr))) return; + error(I.getImportAddressTableRVA(Addr)); W.printHex("ImportAddressTableRVA", Addr); printImportedSymbols(I.imported_symbols()); } @@ -1083,10 +1076,10 @@ void COFFDumper::printCOFFImports() { for (const DelayImportDirectoryEntryRef &I : Obj->delay_import_directories()) { DictScope Import(W, "DelayImport"); StringRef Name; - if (error(I.getName(Name))) return; + error(I.getName(Name)); W.printString("Name", Name); const delay_import_directory_table_entry *Table; - if (error(I.getDelayImportTable(Table))) return; + error(I.getDelayImportTable(Table)); W.printHex("Attributes", Table->Attributes); W.printHex("ModuleHandle", Table->ModuleHandle); W.printHex("ImportAddressTable", Table->DelayImportAddressTable); @@ -1104,12 +1097,9 @@ void COFFDumper::printCOFFExports() { StringRef Name; uint32_t Ordinal, RVA; - if (error(E.getSymbolName(Name))) - continue; - if (error(E.getOrdinal(Ordinal))) - continue; - if (error(E.getExportRVA(RVA))) - continue; + error(E.getSymbolName(Name)); + error(E.getOrdinal(Ordinal)); + error(E.getExportRVA(RVA)); W.printNumber("Ordinal", Ordinal); W.printString("Name", Name); @@ -1122,13 +1112,11 @@ void COFFDumper::printCOFFDirectives() { StringRef Contents; StringRef Name; - if (error(Section.getName(Name))) - continue; + error(Section.getName(Name)); if (Name != ".drectve") continue; - if (error(Section.getContents(Contents))) - return; + error(Section.getContents(Contents)); W.printString("Directive(s)", Contents); } @@ -1152,10 +1140,8 @@ void COFFDumper::printCOFFBaseReloc() { for (const BaseRelocRef &I : Obj->base_relocs()) { uint8_t Type; uint32_t RVA; - if (error(I.getRVA(RVA))) - continue; - if (error(I.getType(Type))) - continue; + error(I.getRVA(RVA)); + error(I.getType(Type)); DictScope Import(W, "Entry"); W.printString("Type", getBaseRelocTypeName(Type)); W.printHex("Address", RVA); diff --git a/contrib/llvm/tools/llvm-readobj/COFFImportDumper.cpp b/contrib/llvm/tools/llvm-readobj/COFFImportDumper.cpp new file mode 100644 index 0000000..83715e6 --- /dev/null +++ b/contrib/llvm/tools/llvm-readobj/COFFImportDumper.cpp @@ -0,0 +1,52 @@ +//===-- COFFImportDumper.cpp - COFF import library dumper -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file implements the COFF import library dumper for llvm-readobj. +/// +//===----------------------------------------------------------------------===// + +#include "Error.h" +#include "ObjDumper.h" +#include "llvm-readobj.h" +#include "llvm/Object/COFF.h" +#include "llvm/Object/COFFImportFile.h" +#include "llvm/Support/COFF.h" + +using namespace llvm::object; + +namespace llvm { + +void dumpCOFFImportFile(const COFFImportFile *File) { + outs() << '\n'; + outs() << "File: " << File->getFileName() << "\n"; + outs() << "Format: COFF-import-file\n"; + + const coff_import_header *H = File->getCOFFImportHeader(); + switch (H->getType()) { + case COFF::IMPORT_CODE: outs() << "Type: code\n"; break; + case COFF::IMPORT_DATA: outs() << "Type: data\n"; break; + case COFF::IMPORT_CONST: outs() << "Type: const\n"; break; + } + + switch (H->getNameType()) { + case COFF::IMPORT_ORDINAL: outs() << "Name type: ordinal\n"; break; + case COFF::IMPORT_NAME: outs() << "Name type: name\n"; break; + case COFF::IMPORT_NAME_NOPREFIX: outs() << "Name type: noprefix\n"; break; + case COFF::IMPORT_NAME_UNDECORATE: outs() << "Name type: undecorate\n"; break; + } + + for (const object::BasicSymbolRef &Sym : File->symbols()) { + outs() << "Symbol: "; + Sym.printName(outs()); + outs() << "\n"; + } +} + +} // namespace llvm diff --git a/contrib/llvm/tools/llvm-readobj/ELFDumper.cpp b/contrib/llvm/tools/llvm-readobj/ELFDumper.cpp index 1cdf552..02397f3 100644 --- a/contrib/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/contrib/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -42,8 +42,7 @@ namespace { template<typename ELFT> class ELFDumper : public ObjDumper { public: - ELFDumper(const ELFFile<ELFT> *Obj, StreamWriter &Writer) - : ObjDumper(Writer), Obj(Obj) {} + ELFDumper(const ELFFile<ELFT> *Obj, StreamWriter &Writer); void printFileHeaders() override; void printSections() override; @@ -57,6 +56,9 @@ public: void printNeededLibraries() override; void printProgramHeaders() override; void printHashTable() override; + void printGnuHashTable() override; + void printLoadName() override; + void printVersionInfo() override; void printAttributes() override; void printMipsPLTGOT() override; @@ -69,13 +71,114 @@ private: typedef ELFFile<ELFT> ELFO; typedef typename ELFO::Elf_Shdr Elf_Shdr; typedef typename ELFO::Elf_Sym Elf_Sym; - - void printSymbol(const Elf_Sym *Symbol, bool IsDynamic); + typedef typename ELFO::Elf_Dyn Elf_Dyn; + typedef typename ELFO::Elf_Dyn_Range Elf_Dyn_Range; + typedef typename ELFO::Elf_Rel Elf_Rel; + typedef typename ELFO::Elf_Rela Elf_Rela; + typedef typename ELFO::Elf_Rela_Range Elf_Rela_Range; + typedef typename ELFO::Elf_Phdr Elf_Phdr; + typedef typename ELFO::Elf_Half Elf_Half; + typedef typename ELFO::Elf_Hash Elf_Hash; + typedef typename ELFO::Elf_GnuHash Elf_GnuHash; + typedef typename ELFO::Elf_Ehdr Elf_Ehdr; + typedef typename ELFO::Elf_Word Elf_Word; + typedef typename ELFO::uintX_t uintX_t; + typedef typename ELFO::Elf_Versym Elf_Versym; + typedef typename ELFO::Elf_Verneed Elf_Verneed; + typedef typename ELFO::Elf_Vernaux Elf_Vernaux; + typedef typename ELFO::Elf_Verdef Elf_Verdef; + typedef typename ELFO::Elf_Verdaux Elf_Verdaux; + + /// \brief Represents a region described by entries in the .dynamic table. + struct DynRegionInfo { + DynRegionInfo() : Addr(nullptr), Size(0), EntSize(0) {} + /// \brief Address in current address space. + const void *Addr; + /// \brief Size in bytes of the region. + uintX_t Size; + /// \brief Size of each entity in the region. + uintX_t EntSize; + }; + + void printSymbolsHelper(bool IsDynamic); + void printSymbol(const Elf_Sym *Symbol, const Elf_Shdr *SymTab, + StringRef StrTable, bool IsDynamic); void printRelocations(const Elf_Shdr *Sec); - void printRelocation(const Elf_Shdr *Sec, typename ELFO::Elf_Rela Rel); + void printRelocation(Elf_Rela Rel, const Elf_Shdr *SymTab); + void printValue(uint64_t Type, uint64_t Value); + + const Elf_Rela *dyn_rela_begin() const; + const Elf_Rela *dyn_rela_end() const; + Elf_Rela_Range dyn_relas() const; + StringRef getDynamicString(uint64_t Offset) const; + const Elf_Dyn *dynamic_table_begin() const { + ErrorOr<const Elf_Dyn *> Ret = Obj->dynamic_table_begin(DynamicProgHeader); + error(Ret.getError()); + return *Ret; + } + const Elf_Dyn *dynamic_table_end() const { + ErrorOr<const Elf_Dyn *> Ret = Obj->dynamic_table_end(DynamicProgHeader); + error(Ret.getError()); + return *Ret; + } + StringRef getSymbolVersion(StringRef StrTab, const Elf_Sym *symb, + bool &IsDefault); + void LoadVersionMap(); + void LoadVersionNeeds(const Elf_Shdr *ec) const; + void LoadVersionDefs(const Elf_Shdr *sec) const; const ELFO *Obj; + DynRegionInfo DynRelaRegion; + const Elf_Phdr *DynamicProgHeader = nullptr; + StringRef DynamicStringTable; + const Elf_Sym *DynSymStart = nullptr; + StringRef SOName; + const Elf_Hash *HashTable = nullptr; + const Elf_GnuHash *GnuHashTable = nullptr; + const Elf_Shdr *DotDynSymSec = nullptr; + const Elf_Shdr *DotSymtabSec = nullptr; + ArrayRef<Elf_Word> ShndxTable; + + const Elf_Shdr *dot_gnu_version_sec = nullptr; // .gnu.version + const Elf_Shdr *dot_gnu_version_r_sec = nullptr; // .gnu.version_r + const Elf_Shdr *dot_gnu_version_d_sec = nullptr; // .gnu.version_d + + // Records for each version index the corresponding Verdef or Vernaux entry. + // This is filled the first time LoadVersionMap() is called. + class VersionMapEntry : public PointerIntPair<const void *, 1> { + public: + // If the integer is 0, this is an Elf_Verdef*. + // If the integer is 1, this is an Elf_Vernaux*. + VersionMapEntry() : PointerIntPair<const void *, 1>(nullptr, 0) {} + VersionMapEntry(const Elf_Verdef *verdef) + : PointerIntPair<const void *, 1>(verdef, 0) {} + VersionMapEntry(const Elf_Vernaux *vernaux) + : PointerIntPair<const void *, 1>(vernaux, 1) {} + bool isNull() const { return getPointer() == nullptr; } + bool isVerdef() const { return !isNull() && getInt() == 0; } + bool isVernaux() const { return !isNull() && getInt() == 1; } + const Elf_Verdef *getVerdef() const { + return isVerdef() ? (const Elf_Verdef *)getPointer() : nullptr; + } + const Elf_Vernaux *getVernaux() const { + return isVernaux() ? (const Elf_Vernaux *)getPointer() : nullptr; + } + }; + mutable SmallVector<VersionMapEntry, 16> VersionMap; + +public: + Elf_Dyn_Range dynamic_table() const { + ErrorOr<Elf_Dyn_Range> Ret = Obj->dynamic_table(DynamicProgHeader); + error(Ret.getError()); + return *Ret; + } + + std::string getFullSymbolName(const Elf_Sym *Symbol, StringRef StrTable, + bool IsDynamic); + const Elf_Shdr *getDotDynSymSec() const { return DotDynSymSec; } + const Elf_Shdr *getDotSymtabSec() const { return DotSymtabSec; } + ArrayRef<Elf_Word> getShndxTable() { return ShndxTable; } }; template <class T> T errorOrDefault(ErrorOr<T> Val, T Default = T()) { @@ -122,30 +225,246 @@ std::error_code createELFDumper(const object::ObjectFile *Obj, } // namespace llvm -template <typename ELFO> -static std::string getFullSymbolName(const ELFO &Obj, - const typename ELFO::Elf_Sym *Symbol, - bool IsDynamic) { - StringRef SymbolName = errorOrDefault(Obj.getSymbolName(Symbol, IsDynamic)); +// Iterate through the versions needed section, and place each Elf_Vernaux +// in the VersionMap according to its index. +template <class ELFT> +void ELFDumper<ELFT>::LoadVersionNeeds(const Elf_Shdr *sec) const { + unsigned vn_size = sec->sh_size; // Size of section in bytes + unsigned vn_count = sec->sh_info; // Number of Verneed entries + const char *sec_start = (const char *)Obj->base() + sec->sh_offset; + const char *sec_end = sec_start + vn_size; + // The first Verneed entry is at the start of the section. + const char *p = sec_start; + for (unsigned i = 0; i < vn_count; i++) { + if (p + sizeof(Elf_Verneed) > sec_end) + report_fatal_error("Section ended unexpectedly while scanning " + "version needed records."); + const Elf_Verneed *vn = reinterpret_cast<const Elf_Verneed *>(p); + if (vn->vn_version != ELF::VER_NEED_CURRENT) + report_fatal_error("Unexpected verneed version"); + // Iterate through the Vernaux entries + const char *paux = p + vn->vn_aux; + for (unsigned j = 0; j < vn->vn_cnt; j++) { + if (paux + sizeof(Elf_Vernaux) > sec_end) + report_fatal_error("Section ended unexpected while scanning auxiliary " + "version needed records."); + const Elf_Vernaux *vna = reinterpret_cast<const Elf_Vernaux *>(paux); + size_t index = vna->vna_other & ELF::VERSYM_VERSION; + if (index >= VersionMap.size()) + VersionMap.resize(index + 1); + VersionMap[index] = VersionMapEntry(vna); + paux += vna->vna_next; + } + p += vn->vn_next; + } +} + +// Iterate through the version definitions, and place each Elf_Verdef +// in the VersionMap according to its index. +template <class ELFT> +void ELFDumper<ELFT>::LoadVersionDefs(const Elf_Shdr *sec) const { + unsigned vd_size = sec->sh_size; // Size of section in bytes + unsigned vd_count = sec->sh_info; // Number of Verdef entries + const char *sec_start = (const char *)Obj->base() + sec->sh_offset; + const char *sec_end = sec_start + vd_size; + // The first Verdef entry is at the start of the section. + const char *p = sec_start; + for (unsigned i = 0; i < vd_count; i++) { + if (p + sizeof(Elf_Verdef) > sec_end) + report_fatal_error("Section ended unexpectedly while scanning " + "version definitions."); + const Elf_Verdef *vd = reinterpret_cast<const Elf_Verdef *>(p); + if (vd->vd_version != ELF::VER_DEF_CURRENT) + report_fatal_error("Unexpected verdef version"); + size_t index = vd->vd_ndx & ELF::VERSYM_VERSION; + if (index >= VersionMap.size()) + VersionMap.resize(index + 1); + VersionMap[index] = VersionMapEntry(vd); + p += vd->vd_next; + } +} + +template <class ELFT> void ELFDumper<ELFT>::LoadVersionMap() { + // If there is no dynamic symtab or version table, there is nothing to do. + if (!DynSymStart || !dot_gnu_version_sec) + return; + + // Has the VersionMap already been loaded? + if (VersionMap.size() > 0) + return; + + // The first two version indexes are reserved. + // Index 0 is LOCAL, index 1 is GLOBAL. + VersionMap.push_back(VersionMapEntry()); + VersionMap.push_back(VersionMapEntry()); + + if (dot_gnu_version_d_sec) + LoadVersionDefs(dot_gnu_version_d_sec); + + if (dot_gnu_version_r_sec) + LoadVersionNeeds(dot_gnu_version_r_sec); +} + + +template <typename ELFO, class ELFT> +static void printVersionSymbolSection(ELFDumper<ELFT> *Dumper, + const ELFO *Obj, + const typename ELFO::Elf_Shdr *Sec, + StreamWriter &W) { + DictScope SS(W, "Version symbols"); + if (!Sec) + return; + StringRef Name = errorOrDefault(Obj->getSectionName(Sec)); + W.printNumber("Section Name", Name, Sec->sh_name); + W.printHex("Address", Sec->sh_addr); + W.printHex("Offset", Sec->sh_offset); + W.printNumber("Link", Sec->sh_link); + + const typename ELFO::Elf_Shdr *DynSymSec = Dumper->getDotDynSymSec(); + const uint8_t *P = (const uint8_t *)Obj->base() + Sec->sh_offset; + ErrorOr<StringRef> StrTableOrErr = + Obj->getStringTableForSymtab(*DynSymSec); + error(StrTableOrErr.getError()); + + // Same number of entries in the dynamic symbol table (DT_SYMTAB). + ListScope Syms(W, "Symbols"); + for (const typename ELFO::Elf_Sym &Sym : Obj->symbols(DynSymSec)) { + DictScope S(W, "Symbol"); + std::string FullSymbolName = + Dumper->getFullSymbolName(&Sym, *StrTableOrErr, true /* IsDynamic */); + W.printNumber("Version", *P); + W.printString("Name", FullSymbolName); + P += sizeof(typename ELFO::Elf_Half); + } +} + +template <typename ELFO, class ELFT> +static void printVersionDefinitionSection(ELFDumper<ELFT> *Dumper, + const ELFO *Obj, + const typename ELFO::Elf_Shdr *Sec, + StreamWriter &W) { + DictScope SD(W, "Version definition"); + if (!Sec) + return; + StringRef Name = errorOrDefault(Obj->getSectionName(Sec)); + W.printNumber("Section Name", Name, Sec->sh_name); + W.printHex("Address", Sec->sh_addr); + W.printHex("Offset", Sec->sh_offset); + W.printNumber("Link", Sec->sh_link); + + unsigned verdef_entries = 0; + // The number of entries in the section SHT_GNU_verdef + // is determined by DT_VERDEFNUM tag. + for (const typename ELFO::Elf_Dyn &Dyn : Dumper->dynamic_table()) { + if (Dyn.d_tag == DT_VERDEFNUM) + verdef_entries = Dyn.d_un.d_val; + } + const uint8_t *SecStartAddress = + (const uint8_t *)Obj->base() + Sec->sh_offset; + const uint8_t *SecEndAddress = SecStartAddress + Sec->sh_size; + const uint8_t *P = SecStartAddress; + ErrorOr<const typename ELFO::Elf_Shdr *> StrTabOrErr = + Obj->getSection(Sec->sh_link); + error(StrTabOrErr.getError()); + + ListScope Entries(W, "Entries"); + for (unsigned i = 0; i < verdef_entries; ++i) { + if (P + sizeof(typename ELFO::Elf_Verdef) > SecEndAddress) + report_fatal_error("invalid offset in the section"); + auto *VD = reinterpret_cast<const typename ELFO::Elf_Verdef *>(P); + DictScope Entry(W, "Entry"); + W.printHex("Offset", (uintptr_t)P - (uintptr_t)SecStartAddress); + W.printNumber("Rev", VD->vd_version); + // FIXME: print something more readable. + W.printNumber("Flags", VD->vd_flags); + W.printNumber("Index", VD->vd_ndx); + W.printNumber("Cnt", VD->vd_cnt); + W.printString("Name", StringRef((const char *)(Obj->base() + + (*StrTabOrErr)->sh_offset + + VD->getAux()->vda_name))); + P += VD->vd_next; + } +} + +template <typename ELFT> void ELFDumper<ELFT>::printVersionInfo() { + // Dump version symbol section. + printVersionSymbolSection(this, Obj, dot_gnu_version_sec, W); + + // Dump version definition section. + printVersionDefinitionSection(this, Obj, dot_gnu_version_d_sec, W); +} + +template <typename ELFT> +StringRef ELFDumper<ELFT>::getSymbolVersion(StringRef StrTab, + const Elf_Sym *symb, + bool &IsDefault) { + // This is a dynamic symbol. Look in the GNU symbol version table. + if (!dot_gnu_version_sec) { + // No version table. + IsDefault = false; + return StringRef(""); + } + + // Determine the position in the symbol table of this entry. + size_t entry_index = (reinterpret_cast<uintptr_t>(symb) - + reinterpret_cast<uintptr_t>(DynSymStart)) / + sizeof(Elf_Sym); + + // Get the corresponding version index entry + const Elf_Versym *vs = + Obj->template getEntry<Elf_Versym>(dot_gnu_version_sec, entry_index); + size_t version_index = vs->vs_index & ELF::VERSYM_VERSION; + + // Special markers for unversioned symbols. + if (version_index == ELF::VER_NDX_LOCAL || + version_index == ELF::VER_NDX_GLOBAL) { + IsDefault = false; + return StringRef(""); + } + + // Lookup this symbol in the version table + LoadVersionMap(); + if (version_index >= VersionMap.size() || VersionMap[version_index].isNull()) + reportError("Invalid version entry"); + const VersionMapEntry &entry = VersionMap[version_index]; + + // Get the version name string + size_t name_offset; + if (entry.isVerdef()) { + // The first Verdaux entry holds the name. + name_offset = entry.getVerdef()->getAux()->vda_name; + IsDefault = !(vs->vs_index & ELF::VERSYM_HIDDEN); + } else { + name_offset = entry.getVernaux()->vna_name; + IsDefault = false; + } + if (name_offset >= StrTab.size()) + reportError("Invalid string offset"); + return StringRef(StrTab.data() + name_offset); +} + +template <typename ELFT> +std::string ELFDumper<ELFT>::getFullSymbolName(const Elf_Sym *Symbol, + StringRef StrTable, + bool IsDynamic) { + StringRef SymbolName = errorOrDefault(Symbol->getName(StrTable)); if (!IsDynamic) return SymbolName; std::string FullSymbolName(SymbolName); bool IsDefault; - ErrorOr<StringRef> Version = - Obj.getSymbolVersion(nullptr, &*Symbol, IsDefault); - if (Version) { - FullSymbolName += (IsDefault ? "@@" : "@"); - FullSymbolName += *Version; - } else - error(Version.getError()); + StringRef Version = getSymbolVersion(StrTable, &*Symbol, IsDefault); + FullSymbolName += (IsDefault ? "@@" : "@"); + FullSymbolName += Version; return FullSymbolName; } template <typename ELFO> static void getSectionNameIndex(const ELFO &Obj, const typename ELFO::Elf_Sym *Symbol, + const typename ELFO::Elf_Shdr *SymTab, + ArrayRef<typename ELFO::Elf_Word> ShndxTable, StringRef &SectionName, unsigned &SectionIndex) { SectionIndex = Symbol->st_shndx; if (Symbol->isUndefined()) @@ -162,25 +481,26 @@ getSectionNameIndex(const ELFO &Obj, const typename ELFO::Elf_Sym *Symbol, SectionName = "Reserved"; else { if (SectionIndex == SHN_XINDEX) - SectionIndex = Obj.getExtendedSymbolTableIndex(&*Symbol); + SectionIndex = + Obj.getExtendedSymbolTableIndex(Symbol, SymTab, ShndxTable); ErrorOr<const typename ELFO::Elf_Shdr *> Sec = Obj.getSection(SectionIndex); - if (!error(Sec.getError())) - SectionName = errorOrDefault(Obj.getSectionName(*Sec)); + error(Sec.getError()); + SectionName = errorOrDefault(Obj.getSectionName(*Sec)); } } -template <class ELFT> -static const typename ELFFile<ELFT>::Elf_Shdr * -findSectionByAddress(const ELFFile<ELFT> *Obj, uint64_t Addr) { +template <class ELFO> +static const typename ELFO::Elf_Shdr *findSectionByAddress(const ELFO *Obj, + uint64_t Addr) { for (const auto &Shdr : Obj->sections()) if (Shdr.sh_addr == Addr) return &Shdr; return nullptr; } -template <class ELFT> -static const typename ELFFile<ELFT>::Elf_Shdr * -findSectionByName(const ELFFile<ELFT> &Obj, StringRef Name) { +template <class ELFO> +static const typename ELFO::Elf_Shdr *findSectionByName(const ELFO &Obj, + StringRef Name) { for (const auto &Shdr : Obj.sections()) { if (Name == errorOrDefault(Obj.getSectionName(&Shdr))) return &Shdr; @@ -409,6 +729,12 @@ static const EnumEntry<unsigned> ElfSymbolTypes[] = { { "GNU_IFunc", ELF::STT_GNU_IFUNC } }; +static const EnumEntry<unsigned> AMDGPUSymbolTypes[] = { + { "AMDGPU_HSA_KERNEL", ELF::STT_AMDGPU_HSA_KERNEL }, + { "AMDGPU_HSA_INDIRECT_FUNCTION", ELF::STT_AMDGPU_HSA_INDIRECT_FUNCTION }, + { "AMDGPU_HSA_METADATA", ELF::STT_AMDGPU_HSA_METADATA } +}; + static const char *getElfSectionType(unsigned Arch, unsigned Type) { switch (Arch) { case ELF::EM_ARM: @@ -473,13 +799,24 @@ static const EnumEntry<unsigned> ElfSectionFlags[] = { LLVM_READOBJ_ENUM_ENT(ELF, SHF_TLS ), LLVM_READOBJ_ENUM_ENT(ELF, XCORE_SHF_CP_SECTION), LLVM_READOBJ_ENUM_ENT(ELF, XCORE_SHF_DP_SECTION), - LLVM_READOBJ_ENUM_ENT(ELF, SHF_MIPS_NOSTRIP ) + LLVM_READOBJ_ENUM_ENT(ELF, SHF_MIPS_NOSTRIP ), + LLVM_READOBJ_ENUM_ENT(ELF, SHF_AMDGPU_HSA_GLOBAL), + LLVM_READOBJ_ENUM_ENT(ELF, SHF_AMDGPU_HSA_READONLY), + LLVM_READOBJ_ENUM_ENT(ELF, SHF_AMDGPU_HSA_CODE), + LLVM_READOBJ_ENUM_ENT(ELF, SHF_AMDGPU_HSA_AGENT) }; static const char *getElfSegmentType(unsigned Arch, unsigned Type) { // Check potentially overlapped processor-specific // program header type. switch (Arch) { + case ELF::EM_AMDGPU: + switch (Type) { + LLVM_READOBJ_ENUM_CASE(ELF, PT_AMDGPU_HSA_LOAD_GLOBAL_PROGRAM); + LLVM_READOBJ_ENUM_CASE(ELF, PT_AMDGPU_HSA_LOAD_GLOBAL_AGENT); + LLVM_READOBJ_ENUM_CASE(ELF, PT_AMDGPU_HSA_LOAD_READONLY_AGENT); + LLVM_READOBJ_ENUM_CASE(ELF, PT_AMDGPU_HSA_LOAD_CODE_AGENT); + } case ELF::EM_ARM: switch (Type) { LLVM_READOBJ_ENUM_CASE(ELF, PT_ARM_EXIDX); @@ -565,9 +902,138 @@ static const EnumEntry<unsigned> ElfHeaderMipsFlags[] = { LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ARCH_64R6) }; +template <typename ELFT> +ELFDumper<ELFT>::ELFDumper(const ELFFile<ELFT> *Obj, StreamWriter &Writer) + : ObjDumper(Writer), Obj(Obj) { + + SmallVector<const Elf_Phdr *, 4> LoadSegments; + for (const Elf_Phdr &Phdr : Obj->program_headers()) { + if (Phdr.p_type == ELF::PT_DYNAMIC) { + DynamicProgHeader = &Phdr; + continue; + } + if (Phdr.p_type != ELF::PT_LOAD || Phdr.p_filesz == 0) + continue; + LoadSegments.push_back(&Phdr); + } + + auto toMappedAddr = [&](uint64_t VAddr) -> const uint8_t * { + const Elf_Phdr **I = std::upper_bound( + LoadSegments.begin(), LoadSegments.end(), VAddr, compareAddr<ELFT>); + if (I == LoadSegments.begin()) + report_fatal_error("Virtual address is not in any segment"); + --I; + const Elf_Phdr &Phdr = **I; + uint64_t Delta = VAddr - Phdr.p_vaddr; + if (Delta >= Phdr.p_filesz) + report_fatal_error("Virtual address is not in any segment"); + return Obj->base() + Phdr.p_offset + Delta; + }; + + uint64_t SONameOffset = 0; + const char *StringTableBegin = nullptr; + uint64_t StringTableSize = 0; + for (const Elf_Dyn &Dyn : dynamic_table()) { + switch (Dyn.d_tag) { + case ELF::DT_HASH: + HashTable = + reinterpret_cast<const Elf_Hash *>(toMappedAddr(Dyn.getPtr())); + break; + case ELF::DT_GNU_HASH: + GnuHashTable = + reinterpret_cast<const Elf_GnuHash *>(toMappedAddr(Dyn.getPtr())); + break; + case ELF::DT_RELA: + DynRelaRegion.Addr = toMappedAddr(Dyn.getPtr()); + break; + case ELF::DT_RELASZ: + DynRelaRegion.Size = Dyn.getVal(); + break; + case ELF::DT_RELAENT: + DynRelaRegion.EntSize = Dyn.getVal(); + break; + case ELF::DT_SONAME: + SONameOffset = Dyn.getVal(); + break; + case ELF::DT_STRTAB: + StringTableBegin = (const char *)toMappedAddr(Dyn.getPtr()); + break; + case ELF::DT_STRSZ: + StringTableSize = Dyn.getVal(); + break; + case ELF::DT_SYMTAB: + DynSymStart = + reinterpret_cast<const Elf_Sym *>(toMappedAddr(Dyn.getPtr())); + break; + } + } + if (StringTableBegin) + DynamicStringTable = StringRef(StringTableBegin, StringTableSize); + if (SONameOffset) + SOName = getDynamicString(SONameOffset); + + for (const Elf_Shdr &Sec : Obj->sections()) { + switch (Sec.sh_type) { + case ELF::SHT_GNU_versym: + if (dot_gnu_version_sec != nullptr) + reportError("Multiple SHT_GNU_versym"); + dot_gnu_version_sec = &Sec; + break; + case ELF::SHT_GNU_verdef: + if (dot_gnu_version_d_sec != nullptr) + reportError("Multiple SHT_GNU_verdef"); + dot_gnu_version_d_sec = &Sec; + break; + case ELF::SHT_GNU_verneed: + if (dot_gnu_version_r_sec != nullptr) + reportError("Multilpe SHT_GNU_verneed"); + dot_gnu_version_r_sec = &Sec; + break; + case ELF::SHT_DYNSYM: + if (DotDynSymSec != nullptr) + reportError("Multilpe SHT_DYNSYM"); + DotDynSymSec = &Sec; + break; + case ELF::SHT_SYMTAB: + if (DotSymtabSec != nullptr) + reportError("Multilpe SHT_SYMTAB"); + DotSymtabSec = &Sec; + break; + case ELF::SHT_SYMTAB_SHNDX: { + ErrorOr<ArrayRef<Elf_Word>> TableOrErr = Obj->getSHNDXTable(Sec); + error(TableOrErr.getError()); + ShndxTable = *TableOrErr; + break; + } + } + } +} + +template <typename ELFT> +const typename ELFDumper<ELFT>::Elf_Rela * +ELFDumper<ELFT>::dyn_rela_begin() const { + if (DynRelaRegion.Size && DynRelaRegion.EntSize != sizeof(Elf_Rela)) + report_fatal_error("Invalid relocation entry size"); + return reinterpret_cast<const Elf_Rela *>(DynRelaRegion.Addr); +} + +template <typename ELFT> +const typename ELFDumper<ELFT>::Elf_Rela * +ELFDumper<ELFT>::dyn_rela_end() const { + uint64_t Size = DynRelaRegion.Size; + if (Size % sizeof(Elf_Rela)) + report_fatal_error("Invalid relocation table size"); + return dyn_rela_begin() + Size / sizeof(Elf_Rela); +} + +template <typename ELFT> +typename ELFDumper<ELFT>::Elf_Rela_Range ELFDumper<ELFT>::dyn_relas() const { + return make_range(dyn_rela_begin(), dyn_rela_end()); +} + template<class ELFT> void ELFDumper<ELFT>::printFileHeaders() { - const typename ELFO::Elf_Ehdr *Header = Obj->getHeader(); + const Elf_Ehdr *Header = Obj->getHeader(); { DictScope D(W, "ElfHeader"); @@ -618,7 +1084,7 @@ void ELFDumper<ELFT>::printSections() { ListScope SectionsD(W, "Sections"); int SectionIndex = -1; - for (const typename ELFO::Elf_Shdr &Sec : Obj->sections()) { + for (const Elf_Shdr &Sec : Obj->sections()) { ++SectionIndex; StringRef Name = errorOrDefault(Obj->getSectionName(&Sec)); @@ -645,12 +1111,18 @@ void ELFDumper<ELFT>::printSections() { if (opts::SectionSymbols) { ListScope D(W, "Symbols"); - for (const typename ELFO::Elf_Sym &Sym : Obj->symbols()) { - ErrorOr<const Elf_Shdr *> SymSec = Obj->getSection(&Sym); + const Elf_Shdr *Symtab = DotSymtabSec; + ErrorOr<StringRef> StrTableOrErr = Obj->getStringTableForSymtab(*Symtab); + error(StrTableOrErr.getError()); + StringRef StrTable = *StrTableOrErr; + + for (const Elf_Sym &Sym : Obj->symbols(Symtab)) { + ErrorOr<const Elf_Shdr *> SymSec = + Obj->getSection(&Sym, Symtab, ShndxTable); if (!SymSec) continue; if (*SymSec == &Sec) - printSymbol(&Sym, false); + printSymbol(&Sym, Symtab, StrTable, false); } } @@ -667,7 +1139,7 @@ void ELFDumper<ELFT>::printRelocations() { ListScope D(W, "Relocations"); int SectionNumber = -1; - for (const typename ELFO::Elf_Shdr &Sec : Obj->sections()) { + for (const Elf_Shdr &Sec : Obj->sections()) { ++SectionNumber; if (Sec.sh_type != ELF::SHT_REL && Sec.sh_type != ELF::SHT_RELA) @@ -689,29 +1161,25 @@ template<class ELFT> void ELFDumper<ELFT>::printDynamicRelocations() { W.startLine() << "Dynamic Relocations {\n"; W.indent(); - for (typename ELFO::Elf_Rela_Iter RelI = Obj->dyn_rela_begin(), - RelE = Obj->dyn_rela_end(); - RelI != RelE; ++RelI) { + for (const Elf_Rela &Rel : dyn_relas()) { SmallString<32> RelocName; - Obj->getRelocationTypeName(RelI->getType(Obj->isMips64EL()), RelocName); + Obj->getRelocationTypeName(Rel.getType(Obj->isMips64EL()), RelocName); StringRef SymbolName; - uint32_t SymIndex = RelI->getSymbol(Obj->isMips64EL()); - const typename ELFO::Elf_Sym *Sym = Obj->dynamic_symbol_begin() + SymIndex; - SymbolName = errorOrDefault(Obj->getSymbolName(Sym, true)); + uint32_t SymIndex = Rel.getSymbol(Obj->isMips64EL()); + const Elf_Sym *Sym = DynSymStart + SymIndex; + SymbolName = errorOrDefault(Sym->getName(DynamicStringTable)); if (opts::ExpandRelocs) { DictScope Group(W, "Relocation"); - W.printHex("Offset", RelI->r_offset); - W.printNumber("Type", RelocName, (int)RelI->getType(Obj->isMips64EL())); + W.printHex("Offset", Rel.r_offset); + W.printNumber("Type", RelocName, (int)Rel.getType(Obj->isMips64EL())); W.printString("Symbol", SymbolName.size() > 0 ? SymbolName : "-"); - W.printHex("Addend", RelI->r_addend); + W.printHex("Addend", Rel.r_addend); } else { raw_ostream& OS = W.startLine(); - OS << W.hex(RelI->r_offset) - << " " << RelocName - << " " << (SymbolName.size() > 0 ? SymbolName : "-") - << " " << W.hex(RelI->r_addend) - << "\n"; + OS << W.hex(Rel.r_offset) << " " << RelocName << " " + << (SymbolName.size() > 0 ? SymbolName : "-") << " " + << W.hex(Rel.r_addend) << "\n"; } } W.unindent(); @@ -720,51 +1188,43 @@ void ELFDumper<ELFT>::printDynamicRelocations() { template <class ELFT> void ELFDumper<ELFT>::printRelocations(const Elf_Shdr *Sec) { + ErrorOr<const Elf_Shdr *> SymTabOrErr = Obj->getSection(Sec->sh_link); + error(SymTabOrErr.getError()); + const Elf_Shdr *SymTab = *SymTabOrErr; + switch (Sec->sh_type) { case ELF::SHT_REL: - for (typename ELFO::Elf_Rel_Iter RI = Obj->rel_begin(Sec), - RE = Obj->rel_end(Sec); - RI != RE; ++RI) { - typename ELFO::Elf_Rela Rela; - Rela.r_offset = RI->r_offset; - Rela.r_info = RI->r_info; + for (const Elf_Rel &R : Obj->rels(Sec)) { + Elf_Rela Rela; + Rela.r_offset = R.r_offset; + Rela.r_info = R.r_info; Rela.r_addend = 0; - printRelocation(Sec, Rela); + printRelocation(Rela, SymTab); } break; case ELF::SHT_RELA: - for (typename ELFO::Elf_Rela_Iter RI = Obj->rela_begin(Sec), - RE = Obj->rela_end(Sec); - RI != RE; ++RI) { - printRelocation(Sec, *RI); - } + for (const Elf_Rela &R : Obj->relas(Sec)) + printRelocation(R, SymTab); break; } } template <class ELFT> -void ELFDumper<ELFT>::printRelocation(const Elf_Shdr *Sec, - typename ELFO::Elf_Rela Rel) { +void ELFDumper<ELFT>::printRelocation(Elf_Rela Rel, const Elf_Shdr *SymTab) { SmallString<32> RelocName; Obj->getRelocationTypeName(Rel.getType(Obj->isMips64EL()), RelocName); StringRef TargetName; - std::pair<const Elf_Shdr *, const Elf_Sym *> Sym = - Obj->getRelocationSymbol(Sec, &Rel); - if (Sym.second && Sym.second->getType() == ELF::STT_SECTION) { - ErrorOr<const Elf_Shdr *> Sec = Obj->getSection(Sym.second); - if (!error(Sec.getError())) { - ErrorOr<StringRef> SecName = Obj->getSectionName(*Sec); - if (SecName) - TargetName = SecName.get(); - } - } else if (Sym.first) { - const Elf_Shdr *SymTable = Sym.first; - ErrorOr<const Elf_Shdr *> StrTableSec = Obj->getSection(SymTable->sh_link); - if (!error(StrTableSec.getError())) { - ErrorOr<StringRef> StrTableOrErr = Obj->getStringTable(*StrTableSec); - if (!error(StrTableOrErr.getError())) - TargetName = errorOrDefault(Sym.second->getName(*StrTableOrErr)); - } + const Elf_Sym *Sym = Obj->getRelocationSymbol(&Rel, SymTab); + if (Sym && Sym->getType() == ELF::STT_SECTION) { + ErrorOr<const Elf_Shdr *> Sec = Obj->getSection(Sym, SymTab, ShndxTable); + error(Sec.getError()); + ErrorOr<StringRef> SecName = Obj->getSectionName(*Sec); + if (SecName) + TargetName = SecName.get(); + } else if (Sym) { + ErrorOr<StringRef> StrTableOrErr = Obj->getStringTableForSymtab(*SymTab); + error(StrTableOrErr.getError()); + TargetName = errorOrDefault(Sym->getName(*StrTableOrErr)); } if (opts::ExpandRelocs) { @@ -783,27 +1243,38 @@ void ELFDumper<ELFT>::printRelocation(const Elf_Shdr *Sec, } template<class ELFT> +void ELFDumper<ELFT>::printSymbolsHelper(bool IsDynamic) { + const Elf_Shdr *Symtab = (IsDynamic) ? DotDynSymSec : DotSymtabSec; + if (!Symtab) + return; + ErrorOr<StringRef> StrTableOrErr = Obj->getStringTableForSymtab(*Symtab); + error(StrTableOrErr.getError()); + StringRef StrTable = *StrTableOrErr; + for (const Elf_Sym &Sym : Obj->symbols(Symtab)) + printSymbol(&Sym, Symtab, StrTable, IsDynamic); +} + +template<class ELFT> void ELFDumper<ELFT>::printSymbols() { ListScope Group(W, "Symbols"); - for (const typename ELFO::Elf_Sym &Sym : Obj->symbols()) - printSymbol(&Sym, false); + printSymbolsHelper(false); } template<class ELFT> void ELFDumper<ELFT>::printDynamicSymbols() { ListScope Group(W, "DynamicSymbols"); - - for (const typename ELFO::Elf_Sym &Sym : Obj->dynamic_symbols()) - printSymbol(&Sym, true); + printSymbolsHelper(true); } template <class ELFT> -void ELFDumper<ELFT>::printSymbol(const typename ELFO::Elf_Sym *Symbol, - bool IsDynamic) { +void ELFDumper<ELFT>::printSymbol(const Elf_Sym *Symbol, const Elf_Shdr *SymTab, + StringRef StrTable, bool IsDynamic) { unsigned SectionIndex = 0; StringRef SectionName; - getSectionNameIndex(*Obj, Symbol, SectionName, SectionIndex); - std::string FullSymbolName = getFullSymbolName(*Obj, Symbol, IsDynamic); + getSectionNameIndex(*Obj, Symbol, SymTab, ShndxTable, SectionName, + SectionIndex); + std::string FullSymbolName = getFullSymbolName(Symbol, StrTable, IsDynamic); + unsigned char SymbolType = Symbol->getType(); DictScope D(W, "Symbol"); W.printNumber("Name", FullSymbolName, Symbol->st_name); @@ -811,7 +1282,11 @@ void ELFDumper<ELFT>::printSymbol(const typename ELFO::Elf_Sym *Symbol, W.printNumber("Size", Symbol->st_size); W.printEnum ("Binding", Symbol->getBinding(), makeArrayRef(ElfSymbolBindings)); - W.printEnum ("Type", Symbol->getType(), makeArrayRef(ElfSymbolTypes)); + if (Obj->getHeader()->e_machine == ELF::EM_AMDGPU && + SymbolType >= ELF::STT_LOOS && SymbolType < ELF::STT_HIOS) + W.printEnum ("Type", SymbolType, makeArrayRef(AMDGPUSymbolTypes)); + else + W.printEnum ("Type", SymbolType, makeArrayRef(ElfSymbolTypes)); W.printNumber("Other", Symbol->st_other); W.printHex("Section", SectionName, SectionIndex); } @@ -855,12 +1330,15 @@ static const char *getTypeString(uint64_t Type) { LLVM_READOBJ_TYPE_CASE(SYMENT); LLVM_READOBJ_TYPE_CASE(SYMTAB); LLVM_READOBJ_TYPE_CASE(TEXTREL); + LLVM_READOBJ_TYPE_CASE(VERDEF); + LLVM_READOBJ_TYPE_CASE(VERDEFNUM); LLVM_READOBJ_TYPE_CASE(VERNEED); LLVM_READOBJ_TYPE_CASE(VERNEEDNUM); LLVM_READOBJ_TYPE_CASE(VERSYM); LLVM_READOBJ_TYPE_CASE(RELCOUNT); LLVM_READOBJ_TYPE_CASE(GNU_HASH); LLVM_READOBJ_TYPE_CASE(MIPS_RLD_VERSION); + LLVM_READOBJ_TYPE_CASE(MIPS_RLD_MAP_REL); LLVM_READOBJ_TYPE_CASE(MIPS_FLAGS); LLVM_READOBJ_TYPE_CASE(MIPS_BASE_ADDRESS); LLVM_READOBJ_TYPE_CASE(MIPS_LOCAL_GOTNO); @@ -956,8 +1434,15 @@ void printFlags(T Value, ArrayRef<EnumEntry<TFlag>> Flags, raw_ostream &OS) { } template <class ELFT> -static void printValue(const ELFFile<ELFT> *O, uint64_t Type, uint64_t Value, - bool Is64, raw_ostream &OS) { +StringRef ELFDumper<ELFT>::getDynamicString(uint64_t Value) const { + if (Value >= DynamicStringTable.size()) + reportError("Invalid dynamic string table reference"); + return StringRef(DynamicStringTable.data() + Value); +} + +template <class ELFT> +void ELFDumper<ELFT>::printValue(uint64_t Type, uint64_t Value) { + raw_ostream &OS = W.getOStream(); switch (Type) { case DT_PLTREL: if (Value == DT_REL) { @@ -981,6 +1466,7 @@ static void printValue(const ELFFile<ELFT> *O, uint64_t Type, uint64_t Value, case DT_FINI_ARRAY: case DT_PREINIT_ARRAY: case DT_DEBUG: + case DT_VERDEF: case DT_VERNEED: case DT_VERSYM: case DT_GNU_HASH: @@ -988,11 +1474,13 @@ static void printValue(const ELFFile<ELFT> *O, uint64_t Type, uint64_t Value, case DT_MIPS_BASE_ADDRESS: case DT_MIPS_GOTSYM: case DT_MIPS_RLD_MAP: + case DT_MIPS_RLD_MAP_REL: case DT_MIPS_PLTGOT: case DT_MIPS_OPTIONS: OS << format("0x%" PRIX64, Value); break; case DT_RELCOUNT: + case DT_VERDEFNUM: case DT_VERNEEDNUM: case DT_MIPS_RLD_VERSION: case DT_MIPS_LOCAL_GOTNO: @@ -1013,14 +1501,14 @@ static void printValue(const ELFFile<ELFT> *O, uint64_t Type, uint64_t Value, OS << Value << " (bytes)"; break; case DT_NEEDED: - OS << "SharedLibrary (" << O->getDynamicString(Value) << ")"; + OS << "SharedLibrary (" << getDynamicString(Value) << ")"; break; case DT_SONAME: - OS << "LibrarySoname (" << O->getDynamicString(Value) << ")"; + OS << "LibrarySoname (" << getDynamicString(Value) << ")"; break; case DT_RPATH: case DT_RUNPATH: - OS << O->getDynamicString(Value); + OS << getDynamicString(Value); break; case DT_MIPS_FLAGS: printFlags(Value, makeArrayRef(ElfDynamicDTMipsFlags), OS); @@ -1046,7 +1534,8 @@ namespace { template <> void ELFDumper<ELFType<support::little, false>>::printUnwindInfo() { const unsigned Machine = Obj->getHeader()->e_machine; if (Machine == EM_ARM) { - ARM::EHABI::PrinterContext<ELFType<support::little, false>> Ctx(W, Obj); + ARM::EHABI::PrinterContext<ELFType<support::little, false>> Ctx( + W, Obj, DotSymtabSec); return Ctx.PrintUnwindInformation(); } W.startLine() << "UnwindInfo not implemented.\n"; @@ -1055,9 +1544,20 @@ template <> void ELFDumper<ELFType<support::little, false>>::printUnwindInfo() { template<class ELFT> void ELFDumper<ELFT>::printDynamicTable() { - auto DynTable = Obj->dynamic_table(true); + auto I = dynamic_table_begin(); + auto E = dynamic_table_end(); - ptrdiff_t Total = std::distance(DynTable.begin(), DynTable.end()); + if (I == E) + return; + + --E; + while (I != E && E->getTag() == ELF::DT_NULL) + --E; + if (E->getTag() != ELF::DT_NULL) + ++E; + ++E; + + ptrdiff_t Total = std::distance(I, E); if (Total == 0) return; @@ -1069,12 +1569,13 @@ void ELFDumper<ELFT>::printDynamicTable() { W.startLine() << " Tag" << (Is64 ? " " : " ") << "Type" << " " << "Name/Value\n"; - for (const auto &Entry : DynTable) { - W.startLine() - << " " - << format(Is64 ? "0x%016" PRIX64 : "0x%08" PRIX64, Entry.getTag()) - << " " << format("%-21s", getTypeString(Entry.getTag())); - printValue(Obj, Entry.getTag(), Entry.getVal(), Is64, OS); + while (I != E) { + const Elf_Dyn &Entry = *I; + uintX_t Tag = Entry.getTag(); + ++I; + W.startLine() << " " << format_hex(Tag, Is64 ? 18 : 10, true) << " " + << format("%-21s", getTypeString(Tag)); + printValue(Tag, Entry.getVal()); OS << "\n"; } @@ -1088,14 +1589,14 @@ void ELFDumper<ELFT>::printNeededLibraries() { typedef std::vector<StringRef> LibsTy; LibsTy Libs; - for (const auto &Entry : Obj->dynamic_table()) + for (const auto &Entry : dynamic_table()) if (Entry.d_tag == ELF::DT_NEEDED) - Libs.push_back(Obj->getDynamicString(Entry.d_un.d_val)); + Libs.push_back(getDynamicString(Entry.d_un.d_val)); std::stable_sort(Libs.begin(), Libs.end()); - for (LibsTy::const_iterator I = Libs.begin(), E = Libs.end(); I != E; ++I) { - outs() << " " << *I << "\n"; + for (const auto &L : Libs) { + outs() << " " << L << "\n"; } } @@ -1103,33 +1604,51 @@ template<class ELFT> void ELFDumper<ELFT>::printProgramHeaders() { ListScope L(W, "ProgramHeaders"); - for (typename ELFO::Elf_Phdr_Iter PI = Obj->program_header_begin(), - PE = Obj->program_header_end(); - PI != PE; ++PI) { + for (const Elf_Phdr &Phdr : Obj->program_headers()) { DictScope P(W, "ProgramHeader"); - W.printHex ("Type", - getElfSegmentType(Obj->getHeader()->e_machine, PI->p_type), - PI->p_type); - W.printHex ("Offset", PI->p_offset); - W.printHex ("VirtualAddress", PI->p_vaddr); - W.printHex ("PhysicalAddress", PI->p_paddr); - W.printNumber("FileSize", PI->p_filesz); - W.printNumber("MemSize", PI->p_memsz); - W.printFlags ("Flags", PI->p_flags, makeArrayRef(ElfSegmentFlags)); - W.printNumber("Alignment", PI->p_align); + W.printHex("Type", + getElfSegmentType(Obj->getHeader()->e_machine, Phdr.p_type), + Phdr.p_type); + W.printHex("Offset", Phdr.p_offset); + W.printHex("VirtualAddress", Phdr.p_vaddr); + W.printHex("PhysicalAddress", Phdr.p_paddr); + W.printNumber("FileSize", Phdr.p_filesz); + W.printNumber("MemSize", Phdr.p_memsz); + W.printFlags("Flags", Phdr.p_flags, makeArrayRef(ElfSegmentFlags)); + W.printNumber("Alignment", Phdr.p_align); } } template <typename ELFT> void ELFDumper<ELFT>::printHashTable() { DictScope D(W, "HashTable"); - auto HT = Obj->getHashTable(); - if (!HT) + if (!HashTable) + return; + W.printNumber("Num Buckets", HashTable->nbucket); + W.printNumber("Num Chains", HashTable->nchain); + W.printList("Buckets", HashTable->buckets()); + W.printList("Chains", HashTable->chains()); +} + +template <typename ELFT> +void ELFDumper<ELFT>::printGnuHashTable() { + DictScope D(W, "GnuHashTable"); + if (!GnuHashTable) return; - W.printNumber("Num Buckets", HT->nbucket); - W.printNumber("Num Chains", HT->nchain); - W.printList("Buckets", HT->buckets()); - W.printList("Chains", HT->chains()); + W.printNumber("Num Buckets", GnuHashTable->nbuckets); + W.printNumber("First Hashed Symbol Index", GnuHashTable->symndx); + W.printNumber("Num Mask Words", GnuHashTable->maskwords); + W.printNumber("Shift Count", GnuHashTable->shift2); + W.printHexList("Bloom Filter", GnuHashTable->filter()); + W.printList("Buckets", GnuHashTable->buckets()); + if (!DotDynSymSec) + reportError("No dynamic symbol section"); + W.printHexList("Values", + GnuHashTable->values(DotDynSymSec->getEntityCount())); +} + +template <typename ELFT> void ELFDumper<ELFT>::printLoadName() { + outs() << "LoadName: " << SOName << '\n'; } template <class ELFT> @@ -1171,21 +1690,23 @@ template <> void ELFDumper<ELFType<support::little, false>>::printAttributes() { namespace { template <class ELFT> class MipsGOTParser { public: - typedef object::ELFFile<ELFT> ObjectFile; - typedef typename ObjectFile::Elf_Shdr Elf_Shdr; - typedef typename ObjectFile::Elf_Sym Elf_Sym; + typedef object::ELFFile<ELFT> ELFO; + typedef typename ELFO::Elf_Shdr Elf_Shdr; + typedef typename ELFO::Elf_Sym Elf_Sym; + typedef typename ELFO::Elf_Dyn_Range Elf_Dyn_Range; + typedef typename ELFO::Elf_Addr GOTEntry; + typedef typename ELFO::Elf_Rel Elf_Rel; + typedef typename ELFO::Elf_Rela Elf_Rela; - MipsGOTParser(const ObjectFile *Obj, StreamWriter &W); + MipsGOTParser(ELFDumper<ELFT> *Dumper, const ELFO *Obj, + Elf_Dyn_Range DynTable, StreamWriter &W); void parseGOT(); void parsePLT(); private: - typedef typename ObjectFile::Elf_Addr GOTEntry; - typedef typename ObjectFile::template ELFEntityIterator<const GOTEntry> - GOTIter; - - const ObjectFile *Obj; + ELFDumper<ELFT> *Dumper; + const ELFO *Obj; StreamWriter &W; llvm::Optional<uint64_t> DtPltGot; llvm::Optional<uint64_t> DtLocalGotNum; @@ -1194,22 +1715,26 @@ private: llvm::Optional<uint64_t> DtJmpRel; std::size_t getGOTTotal(ArrayRef<uint8_t> GOT) const; - GOTIter makeGOTIter(ArrayRef<uint8_t> GOT, std::size_t EntryNum); - - void printGotEntry(uint64_t GotAddr, GOTIter BeginIt, GOTIter It); - void printGlobalGotEntry(uint64_t GotAddr, GOTIter BeginIt, GOTIter It, - const Elf_Sym *Sym, bool IsDynamic); - void printPLTEntry(uint64_t PLTAddr, GOTIter BeginIt, GOTIter It, - StringRef Purpose); - void printPLTEntry(uint64_t PLTAddr, GOTIter BeginIt, GOTIter It, + const GOTEntry *makeGOTIter(ArrayRef<uint8_t> GOT, std::size_t EntryNum); + + void printGotEntry(uint64_t GotAddr, const GOTEntry *BeginIt, + const GOTEntry *It); + void printGlobalGotEntry(uint64_t GotAddr, const GOTEntry *BeginIt, + const GOTEntry *It, const Elf_Sym *Sym, + StringRef StrTable, bool IsDynamic); + void printPLTEntry(uint64_t PLTAddr, const GOTEntry *BeginIt, + const GOTEntry *It, StringRef Purpose); + void printPLTEntry(uint64_t PLTAddr, const GOTEntry *BeginIt, + const GOTEntry *It, StringRef StrTable, const Elf_Sym *Sym); }; } template <class ELFT> -MipsGOTParser<ELFT>::MipsGOTParser(const ObjectFile *Obj, StreamWriter &W) - : Obj(Obj), W(W) { - for (const auto &Entry : Obj->dynamic_table()) { +MipsGOTParser<ELFT>::MipsGOTParser(ELFDumper<ELFT> *Dumper, const ELFO *Obj, + Elf_Dyn_Range DynTable, StreamWriter &W) + : Dumper(Dumper), Obj(Obj), W(W) { + for (const auto &Entry : DynTable) { switch (Entry.getTag()) { case ELF::DT_PLTGOT: DtPltGot = Entry.getVal(); @@ -1264,8 +1789,11 @@ template <class ELFT> void MipsGOTParser<ELFT>::parseGOT() { return; } - const Elf_Sym *DynSymBegin = Obj->dynamic_symbol_begin(); - const Elf_Sym *DynSymEnd = Obj->dynamic_symbol_end(); + const Elf_Shdr *DynSymSec = Dumper->getDotDynSymSec(); + ErrorOr<StringRef> StrTable = Obj->getStringTableForSymtab(*DynSymSec); + error(StrTable.getError()); + const Elf_Sym *DynSymBegin = Obj->symbol_begin(DynSymSec); + const Elf_Sym *DynSymEnd = Obj->symbol_end(DynSymSec); std::size_t DynSymTotal = std::size_t(std::distance(DynSymBegin, DynSymEnd)); if (*DtGotSym > DynSymTotal) { @@ -1280,9 +1808,9 @@ template <class ELFT> void MipsGOTParser<ELFT>::parseGOT() { return; } - GOTIter GotBegin = makeGOTIter(*GOT, 0); - GOTIter GotLocalEnd = makeGOTIter(*GOT, *DtLocalGotNum); - GOTIter It = GotBegin; + const GOTEntry *GotBegin = makeGOTIter(*GOT, 0); + const GOTEntry *GotLocalEnd = makeGOTIter(*GOT, *DtLocalGotNum); + const GOTEntry *It = GotBegin; DictScope GS(W, "Primary GOT"); @@ -1312,11 +1840,13 @@ template <class ELFT> void MipsGOTParser<ELFT>::parseGOT() { { ListScope GS(W, "Global entries"); - GOTIter GotGlobalEnd = makeGOTIter(*GOT, *DtLocalGotNum + GlobalGotNum); + const GOTEntry *GotGlobalEnd = + makeGOTIter(*GOT, *DtLocalGotNum + GlobalGotNum); const Elf_Sym *GotDynSym = DynSymBegin + *DtGotSym; for (; It != GotGlobalEnd; ++It) { DictScope D(W, "Entry"); - printGlobalGotEntry(GOTShdr->sh_addr, GotBegin, It, GotDynSym++, true); + printGlobalGotEntry(GOTShdr->sh_addr, GotBegin, It, GotDynSym++, + *StrTable, true); } } @@ -1350,10 +1880,16 @@ template <class ELFT> void MipsGOTParser<ELFT>::parsePLT() { W.startLine() << "There is no .rel.plt section in the file.\n"; return; } + ErrorOr<const Elf_Shdr *> SymTableOrErr = + Obj->getSection(PLTRelShdr->sh_link); + error(SymTableOrErr.getError()); + const Elf_Shdr *SymTable = *SymTableOrErr; + ErrorOr<StringRef> StrTable = Obj->getStringTableForSymtab(*SymTable); + error(StrTable.getError()); - GOTIter PLTBegin = makeGOTIter(*PLT, 0); - GOTIter PLTEnd = makeGOTIter(*PLT, getGOTTotal(*PLT)); - GOTIter It = PLTBegin; + const GOTEntry *PLTBegin = makeGOTIter(*PLT, 0); + const GOTEntry *PLTEnd = makeGOTIter(*PLT, getGOTTotal(*PLT)); + const GOTEntry *It = PLTBegin; DictScope GS(W, "PLT GOT"); { @@ -1367,21 +1903,19 @@ template <class ELFT> void MipsGOTParser<ELFT>::parsePLT() { switch (PLTRelShdr->sh_type) { case ELF::SHT_REL: - for (typename ObjectFile::Elf_Rel_Iter RI = Obj->rel_begin(PLTRelShdr), - RE = Obj->rel_end(PLTRelShdr); + for (const Elf_Rel *RI = Obj->rel_begin(PLTRelShdr), + *RE = Obj->rel_end(PLTRelShdr); RI != RE && It != PLTEnd; ++RI, ++It) { - const Elf_Sym *Sym = - Obj->getRelocationSymbol(&*PLTRelShdr, &*RI).second; - printPLTEntry(PLTShdr->sh_addr, PLTBegin, It, Sym); + const Elf_Sym *Sym = Obj->getRelocationSymbol(&*RI, SymTable); + printPLTEntry(PLTShdr->sh_addr, PLTBegin, It, *StrTable, Sym); } break; case ELF::SHT_RELA: - for (typename ObjectFile::Elf_Rela_Iter RI = Obj->rela_begin(PLTRelShdr), - RE = Obj->rela_end(PLTRelShdr); + for (const Elf_Rela *RI = Obj->rela_begin(PLTRelShdr), + *RE = Obj->rela_end(PLTRelShdr); RI != RE && It != PLTEnd; ++RI, ++It) { - const Elf_Sym *Sym = - Obj->getRelocationSymbol(&*PLTRelShdr, &*RI).second; - printPLTEntry(PLTShdr->sh_addr, PLTBegin, It, Sym); + const Elf_Sym *Sym = Obj->getRelocationSymbol(&*RI, SymTable); + printPLTEntry(PLTShdr->sh_addr, PLTBegin, It, *StrTable, Sym); } break; } @@ -1394,15 +1928,16 @@ std::size_t MipsGOTParser<ELFT>::getGOTTotal(ArrayRef<uint8_t> GOT) const { } template <class ELFT> -typename MipsGOTParser<ELFT>::GOTIter +const typename MipsGOTParser<ELFT>::GOTEntry * MipsGOTParser<ELFT>::makeGOTIter(ArrayRef<uint8_t> GOT, std::size_t EntryNum) { const char *Data = reinterpret_cast<const char *>(GOT.data()); - return GOTIter(sizeof(GOTEntry), Data + EntryNum * sizeof(GOTEntry)); + return reinterpret_cast<const GOTEntry *>(Data + EntryNum * sizeof(GOTEntry)); } template <class ELFT> -void MipsGOTParser<ELFT>::printGotEntry(uint64_t GotAddr, GOTIter BeginIt, - GOTIter It) { +void MipsGOTParser<ELFT>::printGotEntry(uint64_t GotAddr, + const GOTEntry *BeginIt, + const GOTEntry *It) { int64_t Offset = std::distance(BeginIt, It) * sizeof(GOTEntry); W.printHex("Address", GotAddr + Offset); W.printNumber("Access", Offset - 0x7ff0); @@ -1410,9 +1945,9 @@ void MipsGOTParser<ELFT>::printGotEntry(uint64_t GotAddr, GOTIter BeginIt, } template <class ELFT> -void MipsGOTParser<ELFT>::printGlobalGotEntry(uint64_t GotAddr, GOTIter BeginIt, - GOTIter It, const Elf_Sym *Sym, - bool IsDynamic) { +void MipsGOTParser<ELFT>::printGlobalGotEntry( + uint64_t GotAddr, const GOTEntry *BeginIt, const GOTEntry *It, + const Elf_Sym *Sym, StringRef StrTable, bool IsDynamic) { printGotEntry(GotAddr, BeginIt, It); W.printHex("Value", Sym->st_value); @@ -1420,16 +1955,19 @@ void MipsGOTParser<ELFT>::printGlobalGotEntry(uint64_t GotAddr, GOTIter BeginIt, unsigned SectionIndex = 0; StringRef SectionName; - getSectionNameIndex(*Obj, Sym, SectionName, SectionIndex); + getSectionNameIndex(*Obj, Sym, Dumper->getDotDynSymSec(), + Dumper->getShndxTable(), SectionName, SectionIndex); W.printHex("Section", SectionName, SectionIndex); - std::string FullSymbolName = getFullSymbolName(*Obj, Sym, IsDynamic); + std::string FullSymbolName = + Dumper->getFullSymbolName(Sym, StrTable, IsDynamic); W.printNumber("Name", FullSymbolName, Sym->st_name); } template <class ELFT> -void MipsGOTParser<ELFT>::printPLTEntry(uint64_t PLTAddr, GOTIter BeginIt, - GOTIter It, StringRef Purpose) { +void MipsGOTParser<ELFT>::printPLTEntry(uint64_t PLTAddr, + const GOTEntry *BeginIt, + const GOTEntry *It, StringRef Purpose) { DictScope D(W, "Entry"); int64_t Offset = std::distance(BeginIt, It) * sizeof(GOTEntry); W.printHex("Address", PLTAddr + Offset); @@ -1438,8 +1976,10 @@ void MipsGOTParser<ELFT>::printPLTEntry(uint64_t PLTAddr, GOTIter BeginIt, } template <class ELFT> -void MipsGOTParser<ELFT>::printPLTEntry(uint64_t PLTAddr, GOTIter BeginIt, - GOTIter It, const Elf_Sym *Sym) { +void MipsGOTParser<ELFT>::printPLTEntry(uint64_t PLTAddr, + const GOTEntry *BeginIt, + const GOTEntry *It, StringRef StrTable, + const Elf_Sym *Sym) { DictScope D(W, "Entry"); int64_t Offset = std::distance(BeginIt, It) * sizeof(GOTEntry); W.printHex("Address", PLTAddr + Offset); @@ -1449,10 +1989,11 @@ void MipsGOTParser<ELFT>::printPLTEntry(uint64_t PLTAddr, GOTIter BeginIt, unsigned SectionIndex = 0; StringRef SectionName; - getSectionNameIndex(*Obj, Sym, SectionName, SectionIndex); + getSectionNameIndex(*Obj, Sym, Dumper->getDotDynSymSec(), + Dumper->getShndxTable(), SectionName, SectionIndex); W.printHex("Section", SectionName, SectionIndex); - std::string FullSymbolName = getFullSymbolName(*Obj, Sym, true); + std::string FullSymbolName = Dumper->getFullSymbolName(Sym, StrTable, true); W.printNumber("Name", FullSymbolName, Sym->st_name); } @@ -1462,7 +2003,7 @@ template <class ELFT> void ELFDumper<ELFT>::printMipsPLTGOT() { return; } - MipsGOTParser<ELFT> GOTParser(Obj, W); + MipsGOTParser<ELFT> GOTParser(this, Obj, dynamic_table(), W); GOTParser.parseGOT(); GOTParser.parsePLT(); } @@ -1604,7 +2145,7 @@ template <class ELFT> void ELFDumper<ELFT>::printMipsReginfo() { } template <class ELFT> void ELFDumper<ELFT>::printStackMap() const { - const typename ELFFile<ELFT>::Elf_Shdr *StackMapSection = nullptr; + const Elf_Shdr *StackMapSection = nullptr; for (const auto &Sec : Obj->sections()) { ErrorOr<StringRef> Name = Obj->getSectionName(&Sec); if (*Name == ".llvm_stackmaps") { diff --git a/contrib/llvm/tools/llvm-readobj/MachODumper.cpp b/contrib/llvm/tools/llvm-readobj/MachODumper.cpp index adb99b0..58d2c9f 100644 --- a/contrib/llvm/tools/llvm-readobj/MachODumper.cpp +++ b/contrib/llvm/tools/llvm-readobj/MachODumper.cpp @@ -40,6 +40,14 @@ public: void printUnwindInfo() override; void printStackMap() const override; + // MachO-specific. + void printMachODataInCode() override; + void printMachOVersionMin() override; + void printMachODysymtab() override; + void printMachOSegment() override; + void printMachOIndirectSymbols() override; + void printMachOLinkerOptions () override; + private: template<class MachHeader> void printFileHeaders(const MachHeader &Header); @@ -255,6 +263,21 @@ namespace { uint32_t Flags; uint32_t Reserved1; uint32_t Reserved2; + uint32_t Reserved3; + }; + + struct MachOSegment { + std::string CmdName; + std::string SegName; + uint64_t cmdsize; + uint64_t vmaddr; + uint64_t vmsize; + uint64_t fileoff; + uint64_t filesize; + uint32_t maxprot; + uint32_t initprot; + uint32_t nsects; + uint32_t flags; }; struct MachOSymbol { @@ -266,6 +289,18 @@ namespace { }; } +static std::string getMask(uint32_t prot) +{ + // TODO (davide): This always assumes prot is valid. + // Catch mistakes and report if needed. + std::string Prot; + Prot = ""; + Prot += (prot & MachO::VM_PROT_READ) ? "r" : "-"; + Prot += (prot & MachO::VM_PROT_WRITE) ? "w" : "-"; + Prot += (prot & MachO::VM_PROT_EXECUTE) ? "x" : "-"; + return Prot; +} + static void getSection(const MachOObjectFile *Obj, DataRefImpl Sec, MachOSection &Section) { @@ -292,8 +327,40 @@ static void getSection(const MachOObjectFile *Obj, Section.Flags = Sect.flags; Section.Reserved1 = Sect.reserved1; Section.Reserved2 = Sect.reserved2; + Section.Reserved3 = Sect.reserved3; } +static void getSegment(const MachOObjectFile *Obj, + const MachOObjectFile::LoadCommandInfo &L, + MachOSegment &Segment) { + if (!Obj->is64Bit()) { + MachO::segment_command SC = Obj->getSegmentLoadCommand(L); + Segment.CmdName = "LC_SEGMENT"; + Segment.SegName = SC.segname; + Segment.cmdsize = SC.cmdsize; + Segment.vmaddr = SC.vmaddr; + Segment.vmsize = SC.vmsize; + Segment.fileoff = SC.fileoff; + Segment.filesize = SC.filesize; + Segment.maxprot = SC.maxprot; + Segment.initprot = SC.initprot; + Segment.nsects = SC.nsects; + Segment.flags = SC.flags; + return; + } + MachO::segment_command_64 SC = Obj->getSegment64LoadCommand(L); + Segment.CmdName = "LC_SEGMENT_64"; + Segment.SegName = SC.segname; + Segment.cmdsize = SC.cmdsize; + Segment.vmaddr = SC.vmaddr; + Segment.vmsize = SC.vmsize; + Segment.fileoff = SC.fileoff; + Segment.filesize = SC.filesize; + Segment.maxprot = SC.maxprot; + Segment.initprot = SC.initprot; + Segment.nsects = SC.nsects; + Segment.flags = SC.flags; +} static void getSymbol(const MachOObjectFile *Obj, DataRefImpl DRI, @@ -375,8 +442,7 @@ void MachODumper::printSections(const MachOObjectFile *Obj) { DataRefImpl DR = Section.getRawDataRefImpl(); StringRef Name; - if (error(Section.getName(Name))) - Name = ""; + error(Section.getName(Name)); ArrayRef<char> RawName = Obj->getSectionRawName(DR); StringRef SegmentName = Obj->getSectionFinalSegmentName(DR); @@ -398,6 +464,8 @@ void MachODumper::printSections(const MachOObjectFile *Obj) { makeArrayRef(MachOSectionAttributes)); W.printHex("Reserved1", MOSection.Reserved1); W.printHex("Reserved2", MOSection.Reserved2); + if (Obj->is64Bit()) + W.printHex("Reserved3", MOSection.Reserved3); if (opts::SectionRelocations) { ListScope D(W, "Relocations"); @@ -419,8 +487,7 @@ void MachODumper::printSections(const MachOObjectFile *Obj) { bool IsBSS = Section.isBSS(); if (!IsBSS) { StringRef Data; - if (error(Section.getContents(Data))) - break; + error(Section.getContents(Data)); W.printBinaryBlock("SectionData", Data); } @@ -434,8 +501,7 @@ void MachODumper::printRelocations() { std::error_code EC; for (const SectionRef &Section : Obj->sections()) { StringRef Name; - if (error(Section.getName(Name))) - continue; + error(Section.getName(Name)); bool PrintedGroup = false; for (const RelocationRef &Reloc : Section.relocations()) { @@ -475,15 +541,13 @@ void MachODumper::printRelocation(const MachOObjectFile *Obj, symbol_iterator Symbol = Reloc.getSymbol(); if (Symbol != Obj->symbol_end()) { ErrorOr<StringRef> TargetNameOrErr = Symbol->getName(); - if (error(TargetNameOrErr.getError())) - return; + error(TargetNameOrErr.getError()); TargetName = *TargetNameOrErr; } } else if (!IsScattered) { section_iterator SecI = Obj->getRelocationSection(DR); if (SecI != Obj->section_end()) { - if (error(SecI->getName(TargetName))) - return; + error(SecI->getName(TargetName)); } } if (TargetName.empty()) @@ -547,8 +611,10 @@ void MachODumper::printSymbol(const SymbolRef &Symbol) { getSymbol(Obj, Symbol.getRawDataRefImpl(), MOSymbol); StringRef SectionName = ""; - section_iterator SecI(Obj->section_begin()); - if (!error(Symbol.getSection(SecI)) && SecI != Obj->section_end()) + ErrorOr<section_iterator> SecIOrErr = Symbol.getSection(); + error(SecIOrErr.getError()); + section_iterator SecI = *SecIOrErr; + if (SecI != Obj->section_end()) error(SecI->getName(SectionName)); DictScope D(W, "Symbol"); @@ -603,3 +669,153 @@ void MachODumper::printStackMap() const { prettyPrintStackMap(llvm::outs(), StackMapV1Parser<support::big>(StackMapContentsArray)); } + +void MachODumper::printMachODataInCode() { + for (const auto &Load : Obj->load_commands()) { + if (Load.C.cmd == MachO::LC_DATA_IN_CODE) { + MachO::linkedit_data_command LLC = Obj->getLinkeditDataLoadCommand(Load); + DictScope Group(W, "DataInCode"); + W.printNumber("Data offset", LLC.dataoff); + W.printNumber("Data size", LLC.datasize); + ListScope D(W, "Data entries"); + unsigned NumRegions = LLC.datasize / sizeof(MachO::data_in_code_entry); + for (unsigned i = 0; i < NumRegions; ++i) { + MachO::data_in_code_entry DICE = Obj->getDataInCodeTableEntry( + LLC.dataoff, i); + DictScope Group(W, "Entry"); + W.printNumber("Index", i); + W.printNumber("Offset", DICE.offset); + W.printNumber("Length", DICE.length); + W.printNumber("Kind", DICE.kind); + } + } + } +} + +void MachODumper::printMachOVersionMin() { + for (const auto &Load : Obj->load_commands()) { + StringRef Cmd; + switch (Load.C.cmd) { + case MachO::LC_VERSION_MIN_MACOSX: + Cmd = "LC_VERSION_MIN_MACOSX"; + break; + case MachO::LC_VERSION_MIN_IPHONEOS: + Cmd = "LC_VERSION_MIN_IPHONEOS"; + break; + case MachO::LC_VERSION_MIN_TVOS: + Cmd = "LC_VERSION_MIN_TVOS"; + break; + case MachO::LC_VERSION_MIN_WATCHOS: + Cmd = "LC_VERSION_MIN_WATCHOS"; + break; + default: + continue; + } + + MachO::version_min_command VMC = Obj->getVersionMinLoadCommand(Load); + DictScope Group(W, "MinVersion"); + W.printString("Cmd", Cmd); + W.printNumber("Size", VMC.cmdsize); + SmallString<32> Version; + Version = utostr(MachOObjectFile::getVersionMinMajor(VMC, false)) + "." + + utostr(MachOObjectFile::getVersionMinMinor(VMC, false)); + uint32_t Update = MachOObjectFile::getVersionMinUpdate(VMC, false); + if (Update != 0) + Version += "." + utostr(MachOObjectFile::getVersionMinUpdate(VMC, false)); + W.printString("Version", Version); + SmallString<32> SDK; + if (VMC.sdk == 0) + SDK = "n/a"; + else { + SDK = utostr(MachOObjectFile::getVersionMinMajor(VMC, true)) + "." + + utostr(MachOObjectFile::getVersionMinMinor(VMC, true)); + uint32_t Update = MachOObjectFile::getVersionMinUpdate(VMC, true); + if (Update != 0) + SDK += "." + utostr(MachOObjectFile::getVersionMinUpdate(VMC, true)); + } + W.printString("SDK", SDK); + } +} + +void MachODumper::printMachODysymtab() { + for (const auto &Load : Obj->load_commands()) { + if (Load.C.cmd == MachO::LC_DYSYMTAB) { + MachO::dysymtab_command DLC = Obj->getDysymtabLoadCommand(); + DictScope Group(W, "Dysymtab"); + W.printNumber("ilocalsym", DLC.ilocalsym); + W.printNumber("nlocalsym", DLC.nlocalsym); + W.printNumber("iextdefsym", DLC.iextdefsym); + W.printNumber("nextdefsym", DLC.nextdefsym); + W.printNumber("iundefsym", DLC.iundefsym); + W.printNumber("nundefsym", DLC.nundefsym); + W.printNumber("tocoff", DLC.tocoff); + W.printNumber("ntoc", DLC.ntoc); + W.printNumber("modtaboff", DLC.modtaboff); + W.printNumber("nmodtab", DLC.nmodtab); + W.printNumber("extrefsymoff", DLC.extrefsymoff); + W.printNumber("nextrefsyms", DLC.nextrefsyms); + W.printNumber("indirectsymoff", DLC.indirectsymoff); + W.printNumber("nindirectsyms", DLC.nindirectsyms); + W.printNumber("extreloff", DLC.extreloff); + W.printNumber("nextrel", DLC.nextrel); + W.printNumber("locreloff", DLC.locreloff); + W.printNumber("nlocrel", DLC.nlocrel); + } + } +} + +void MachODumper::printMachOSegment() { + for (const auto &Load : Obj->load_commands()) { + if (Load.C.cmd == MachO::LC_SEGMENT || Load.C.cmd == MachO::LC_SEGMENT_64) { + MachOSegment MOSegment; + getSegment(Obj, Load, MOSegment); + DictScope Group(W, "Segment"); + W.printString("Cmd", MOSegment.CmdName); + W.printString("Name", MOSegment.SegName); + W.printNumber("Size", MOSegment.cmdsize); + W.printHex("vmaddr", MOSegment.vmaddr); + W.printHex("vmsize", MOSegment.vmsize); + W.printNumber("fileoff", MOSegment.fileoff); + W.printNumber("filesize", MOSegment.filesize); + W.printString("maxprot", getMask(MOSegment.maxprot)); + W.printString("initprot", getMask(MOSegment.initprot)); + W.printNumber("nsects", MOSegment.nsects); + W.printHex("flags", MOSegment.flags); + } + } +} + +void MachODumper::printMachOIndirectSymbols() { + for (const auto &Load : Obj->load_commands()) { + if (Load.C.cmd == MachO::LC_DYSYMTAB) { + MachO::dysymtab_command DLC = Obj->getDysymtabLoadCommand(); + DictScope Group(W, "Indirect Symbols"); + W.printNumber("Number", DLC.nindirectsyms); + ListScope D(W, "Symbols"); + for (unsigned i = 0; i < DLC.nindirectsyms; ++i) { + DictScope Group(W, "Entry"); + W.printNumber("Entry Index", i); + W.printHex("Symbol Index", Obj->getIndirectSymbolTableEntry(DLC, i)); + } + } + } +} + +void MachODumper::printMachOLinkerOptions() { + for (const auto &Load : Obj->load_commands()) { + if (Load.C.cmd == MachO::LC_LINKER_OPTION) { + MachO::linker_option_command LOLC = Obj->getLinkerOptionLoadCommand(Load); + DictScope Group(W, "Linker Options"); + W.printNumber("Size", LOLC.cmdsize); + ListScope D(W, "Strings"); + uint64_t DataSize = LOLC.cmdsize - sizeof(MachO::linker_option_command); + const char *P = Load.Ptr + sizeof(MachO::linker_option_command); + StringRef Data(P, DataSize); + for (unsigned i = 0; i < LOLC.count; ++i) { + std::pair<StringRef,StringRef> Split = Data.split('\0'); + W.printString("Value", Split.first); + Data = Split.second; + } + } + } +} diff --git a/contrib/llvm/tools/llvm-readobj/ObjDumper.h b/contrib/llvm/tools/llvm-readobj/ObjDumper.h index 5ecf0ec..db26d69 100644 --- a/contrib/llvm/tools/llvm-readobj/ObjDumper.h +++ b/contrib/llvm/tools/llvm-readobj/ObjDumper.h @@ -1,4 +1,4 @@ -//===-- ObjDumper.h -------------------------------------------------------===// +//===-- ObjDumper.h ---------------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -15,7 +15,8 @@ namespace llvm { namespace object { - class ObjectFile; +class COFFImportFile; +class ObjectFile; } class StreamWriter; @@ -38,6 +39,9 @@ public: virtual void printNeededLibraries() { } virtual void printProgramHeaders() { } virtual void printHashTable() { } + virtual void printGnuHashTable() { } + virtual void printLoadName() {} + virtual void printVersionInfo() {} // Only implemented for ARM ELF at this time. virtual void printAttributes() { } @@ -52,6 +56,15 @@ public: virtual void printCOFFExports() { } virtual void printCOFFDirectives() { } virtual void printCOFFBaseReloc() { } + virtual void printCodeViewDebugInfo() { } + + // Only implemented for MachO. + virtual void printMachODataInCode() { } + virtual void printMachOVersionMin() { } + virtual void printMachODysymtab() { } + virtual void printMachOSegment() { } + virtual void printMachOIndirectSymbols() { } + virtual void printMachOLinkerOptions() { } virtual void printStackMap() const = 0; @@ -71,6 +84,8 @@ std::error_code createMachODumper(const object::ObjectFile *Obj, StreamWriter &Writer, std::unique_ptr<ObjDumper> &Result); +void dumpCOFFImportFile(const object::COFFImportFile *File); + } // namespace llvm #endif diff --git a/contrib/llvm/tools/llvm-readobj/StreamWriter.h b/contrib/llvm/tools/llvm-readobj/StreamWriter.h index f3cc57e..d2dbb07 100644 --- a/contrib/llvm/tools/llvm-readobj/StreamWriter.h +++ b/contrib/llvm/tools/llvm-readobj/StreamWriter.h @@ -34,14 +34,17 @@ struct HexNumber { // unsigned type. The overloads are here so that every type that is implicitly // convertible to an integer (including enums and endian helpers) can be used // without requiring type traits or call-site changes. - HexNumber(int8_t Value) : Value(static_cast<uint8_t >(Value)) { } - HexNumber(int16_t Value) : Value(static_cast<uint16_t>(Value)) { } - HexNumber(int32_t Value) : Value(static_cast<uint32_t>(Value)) { } - HexNumber(int64_t Value) : Value(static_cast<uint64_t>(Value)) { } - HexNumber(uint8_t Value) : Value(Value) { } - HexNumber(uint16_t Value) : Value(Value) { } - HexNumber(uint32_t Value) : Value(Value) { } - HexNumber(uint64_t Value) : Value(Value) { } + HexNumber(char Value) : Value(static_cast<unsigned char>(Value)) { } + HexNumber(signed char Value) : Value(static_cast<unsigned char>(Value)) { } + HexNumber(signed short Value) : Value(static_cast<unsigned short>(Value)) { } + HexNumber(signed int Value) : Value(static_cast<unsigned int>(Value)) { } + HexNumber(signed long Value) : Value(static_cast<unsigned long>(Value)) { } + HexNumber(signed long long Value) : Value(static_cast<unsigned long long>(Value)) { } + HexNumber(unsigned char Value) : Value(Value) { } + HexNumber(unsigned short Value) : Value(Value) { } + HexNumber(unsigned int Value) : Value(Value) { } + HexNumber(unsigned long Value) : Value(Value) { } + HexNumber(unsigned long long Value) : Value(Value) { } uint64_t Value; }; @@ -194,6 +197,19 @@ public: OS << "]\n"; } + template <typename T> + void printHexList(StringRef Label, const T &List) { + startLine() << Label << ": ["; + bool Comma = false; + for (const auto &Item : List) { + if (Comma) + OS << ", "; + OS << hex(Item); + Comma = true; + } + OS << "]\n"; + } + template<typename T> void printHex(StringRef Label, T Value) { startLine() << Label << ": " << hex(Value) << "\n"; diff --git a/contrib/llvm/tools/llvm-readobj/Win64EHDumper.cpp b/contrib/llvm/tools/llvm-readobj/Win64EHDumper.cpp index f57eea2..2da5ae3 100644 --- a/contrib/llvm/tools/llvm-readobj/Win64EHDumper.cpp +++ b/contrib/llvm/tools/llvm-readobj/Win64EHDumper.cpp @@ -149,11 +149,8 @@ static std::error_code resolveRelocation(const Dumper::Context &Ctx, return EC; ResolvedAddress = *ResolvedAddressOrErr; - section_iterator SI = Ctx.COFF.section_begin(); - if (std::error_code EC = Symbol.getSection(SI)) - return EC; - - ResolvedSection = Ctx.COFF.getCOFFSection(*SI); + ErrorOr<section_iterator> SI = Symbol.getSection(); + ResolvedSection = Ctx.COFF.getCOFFSection(**SI); return std::error_code(); } @@ -257,7 +254,7 @@ void Dumper::printUnwindInfo(const Context &Ctx, const coff_section *Section, return; } - printUnwindCode(UI, ArrayRef<UnwindCode>(UCI, UCE)); + printUnwindCode(UI, makeArrayRef(UCI, UCE)); UCI = UCI + UsedSlots - 1; } } @@ -284,11 +281,11 @@ void Dumper::printRuntimeFunction(const Context &Ctx, const coff_section *XData; uint64_t Offset; - if (error(resolveRelocation(Ctx, Section, SectionOffset + 8, XData, Offset))) - return; + resolveRelocation(Ctx, Section, SectionOffset + 8, XData, Offset); ArrayRef<uint8_t> Contents; - if (error(Ctx.COFF.getSectionContents(XData, Contents)) || Contents.empty()) + error(Ctx.COFF.getSectionContents(XData, Contents)); + if (Contents.empty()) return; Offset = Offset + RF.UnwindInfoOffset; @@ -302,15 +299,15 @@ void Dumper::printRuntimeFunction(const Context &Ctx, void Dumper::printData(const Context &Ctx) { for (const auto &Section : Ctx.COFF.sections()) { StringRef Name; - if (error(Section.getName(Name))) - continue; + Section.getName(Name); if (Name != ".pdata" && !Name.startswith(".pdata$")) continue; const coff_section *PData = Ctx.COFF.getCOFFSection(Section); ArrayRef<uint8_t> Contents; - if (error(Ctx.COFF.getSectionContents(PData, Contents)) || Contents.empty()) + error(Ctx.COFF.getSectionContents(PData, Contents)); + if (Contents.empty()) continue; const RuntimeFunction *Entries = diff --git a/contrib/llvm/tools/llvm-readobj/llvm-readobj.cpp b/contrib/llvm/tools/llvm-readobj/llvm-readobj.cpp index 12afacb..fa8fee2 100644 --- a/contrib/llvm/tools/llvm-readobj/llvm-readobj.cpp +++ b/contrib/llvm/tools/llvm-readobj/llvm-readobj.cpp @@ -24,6 +24,7 @@ #include "ObjDumper.h" #include "StreamWriter.h" #include "llvm/Object/Archive.h" +#include "llvm/Object/COFFImportFile.h" #include "llvm/Object/ELFObjectFile.h" #include "llvm/Object/MachOUniversal.h" #include "llvm/Object/ObjectFile.h" @@ -131,6 +132,10 @@ namespace opts { cl::opt<bool> HashTable("hash-table", cl::desc("Display ELF hash table")); + // -gnu-hash-table + cl::opt<bool> GnuHashTable("gnu-hash-table", + cl::desc("Display ELF .gnu.hash section")); + // -expand-relocs cl::opt<bool> ExpandRelocs("expand-relocs", cl::desc("Expand each shown relocation to multiple lines")); @@ -181,25 +186,62 @@ namespace opts { COFFBaseRelocs("coff-basereloc", cl::desc("Display the PE/COFF .reloc section")); + // -macho-data-in-code + cl::opt<bool> + MachODataInCode("macho-data-in-code", + cl::desc("Display MachO Data in Code command")); + + // -macho-indirect-symbols + cl::opt<bool> + MachOIndirectSymbols("macho-indirect-symbols", + cl::desc("Display MachO indirect symbols")); + + // -macho-linker-options + cl::opt<bool> + MachOLinkerOptions("macho-linker-options", + cl::desc("Display MachO linker options")); + + // -macho-segment + cl::opt<bool> + MachOSegment("macho-segment", + cl::desc("Display MachO Segment command")); + + // -macho-version-min + cl::opt<bool> + MachOVersionMin("macho-version-min", + cl::desc("Display MachO version min command")); + + // -macho-dysymtab + cl::opt<bool> + MachODysymtab("macho-dysymtab", + cl::desc("Display MachO Dysymtab command")); + // -stackmap cl::opt<bool> PrintStackMap("stackmap", cl::desc("Display contents of stackmap section")); + // -version-info + cl::opt<bool> + VersionInfo("version-info", + cl::desc("Display ELF version sections (if present)")); + cl::alias VersionInfoShort("V", cl::desc("Alias for -version-info"), + cl::aliasopt(VersionInfo)); } // namespace opts -static int ReturnValue = EXIT_SUCCESS; - namespace llvm { -bool error(std::error_code EC) { +LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg) { + errs() << "\nError reading file: " << Msg << ".\n"; + errs().flush(); + exit(1); +} + +void error(std::error_code EC) { if (!EC) - return false; + return; - ReturnValue = EXIT_FAILURE; - outs() << "\nError reading file: " << EC.message() << ".\n"; - outs().flush(); - return true; + reportError(EC.message()); } bool relocAddressLess(RelocationRef a, RelocationRef b) { @@ -212,17 +254,14 @@ static void reportError(StringRef Input, std::error_code EC) { if (Input == "-") Input = "<stdin>"; - errs() << Input << ": " << EC.message() << "\n"; - errs().flush(); - ReturnValue = EXIT_FAILURE; + reportError(Twine(Input) + ": " + EC.message()); } static void reportError(StringRef Input, StringRef Message) { if (Input == "-") Input = "<stdin>"; - errs() << Input << ": " << Message << "\n"; - ReturnValue = EXIT_FAILURE; + reportError(Twine(Input) + ": " + Message); } static bool isMipsArch(unsigned Arch) { @@ -253,26 +292,12 @@ static std::error_code createDumper(const ObjectFile *Obj, StreamWriter &Writer, return readobj_error::unsupported_obj_file_format; } -static StringRef getLoadName(const ObjectFile *Obj) { - if (auto *ELF = dyn_cast<ELF32LEObjectFile>(Obj)) - return ELF->getLoadName(); - if (auto *ELF = dyn_cast<ELF64LEObjectFile>(Obj)) - return ELF->getLoadName(); - if (auto *ELF = dyn_cast<ELF32BEObjectFile>(Obj)) - return ELF->getLoadName(); - if (auto *ELF = dyn_cast<ELF64BEObjectFile>(Obj)) - return ELF->getLoadName(); - llvm_unreachable("Not ELF"); -} - /// @brief Dumps the specified object file. static void dumpObject(const ObjectFile *Obj) { StreamWriter Writer(outs()); std::unique_ptr<ObjDumper> Dumper; - if (std::error_code EC = createDumper(Obj, Writer, Dumper)) { + if (std::error_code EC = createDumper(Obj, Writer, Dumper)) reportError(Obj->getFileName(), EC); - return; - } outs() << '\n'; outs() << "File: " << Obj->getFileName() << "\n"; @@ -281,8 +306,7 @@ static void dumpObject(const ObjectFile *Obj) { << Triple::getArchTypeName((llvm::Triple::ArchType)Obj->getArch()) << "\n"; outs() << "AddressSize: " << (8*Obj->getBytesInAddress()) << "bit\n"; - if (Obj->isELF()) - outs() << "LoadName: " << getLoadName(Obj) << "\n"; + Dumper->printLoadName(); if (opts::FileHeaders) Dumper->printFileHeaders(); @@ -306,6 +330,10 @@ static void dumpObject(const ObjectFile *Obj) { Dumper->printProgramHeaders(); if (opts::HashTable) Dumper->printHashTable(); + if (opts::GnuHashTable) + Dumper->printGnuHashTable(); + if (opts::VersionInfo) + Dumper->printVersionInfo(); if (Obj->getArch() == llvm::Triple::arm && Obj->isELF()) if (opts::ARMAttributes) Dumper->printAttributes(); @@ -317,25 +345,43 @@ static void dumpObject(const ObjectFile *Obj) { if (opts::MipsReginfo) Dumper->printMipsReginfo(); } - if (opts::COFFImports) - Dumper->printCOFFImports(); - if (opts::COFFExports) - Dumper->printCOFFExports(); - if (opts::COFFDirectives) - Dumper->printCOFFDirectives(); - if (opts::COFFBaseRelocs) - Dumper->printCOFFBaseReloc(); - + if (Obj->isCOFF()) { + if (opts::COFFImports) + Dumper->printCOFFImports(); + if (opts::COFFExports) + Dumper->printCOFFExports(); + if (opts::COFFDirectives) + Dumper->printCOFFDirectives(); + if (opts::COFFBaseRelocs) + Dumper->printCOFFBaseReloc(); + if (opts::CodeView) + Dumper->printCodeViewDebugInfo(); + } + if (Obj->isMachO()) { + if (opts::MachODataInCode) + Dumper->printMachODataInCode(); + if (opts::MachOIndirectSymbols) + Dumper->printMachOIndirectSymbols(); + if (opts::MachOLinkerOptions) + Dumper->printMachOLinkerOptions(); + if (opts::MachOSegment) + Dumper->printMachOSegment(); + if (opts::MachOVersionMin) + Dumper->printMachOVersionMin(); + if (opts::MachODysymtab) + Dumper->printMachODysymtab(); + } if (opts::PrintStackMap) Dumper->printStackMap(); } /// @brief Dumps each object file in \a Arc; static void dumpArchive(const Archive *Arc) { - for (Archive::child_iterator ArcI = Arc->child_begin(), - ArcE = Arc->child_end(); - ArcI != ArcE; ++ArcI) { - ErrorOr<std::unique_ptr<Binary>> ChildOrErr = ArcI->getAsBinary(); + for (auto &ErrorOrChild : Arc->children()) { + if (std::error_code EC = ErrorOrChild.getError()) + reportError(Arc->getFileName(), EC.message()); + const auto &Child = *ErrorOrChild; + ErrorOr<std::unique_ptr<Binary>> ChildOrErr = Child.getAsBinary(); if (std::error_code EC = ChildOrErr.getError()) { // Ignore non-object files. if (EC != object_error::invalid_file_type) @@ -365,18 +411,11 @@ static void dumpMachOUniversalBinary(const MachOUniversalBinary *UBinary) { /// @brief Opens \a File and dumps it. static void dumpInput(StringRef File) { - // If file isn't stdin, check that it exists. - if (File != "-" && !sys::fs::exists(File)) { - reportError(File, readobj_error::file_not_found); - return; - } // Attempt to open the binary. ErrorOr<OwningBinary<Binary>> BinaryOrErr = createBinary(File); - if (std::error_code EC = BinaryOrErr.getError()) { + if (std::error_code EC = BinaryOrErr.getError()) reportError(File, EC); - return; - } Binary &Binary = *BinaryOrErr.get().getBinary(); if (Archive *Arc = dyn_cast<Archive>(&Binary)) @@ -386,6 +425,8 @@ static void dumpInput(StringRef File) { dumpMachOUniversalBinary(UBinary); else if (ObjectFile *Obj = dyn_cast<ObjectFile>(&Binary)) dumpObject(Obj); + else if (COFFImportFile *Import = dyn_cast<COFFImportFile>(&Binary)) + dumpCOFFImportFile(Import); else reportError(File, readobj_error::unrecognized_file_format); } @@ -407,5 +448,5 @@ int main(int argc, const char *argv[]) { std::for_each(opts::InputFilenames.begin(), opts::InputFilenames.end(), dumpInput); - return ReturnValue; + return 0; } diff --git a/contrib/llvm/tools/llvm-readobj/llvm-readobj.h b/contrib/llvm/tools/llvm-readobj/llvm-readobj.h index 74b9a60..5a10392 100644 --- a/contrib/llvm/tools/llvm-readobj/llvm-readobj.h +++ b/contrib/llvm/tools/llvm-readobj/llvm-readobj.h @@ -11,6 +11,7 @@ #define LLVM_TOOLS_LLVM_READOBJ_LLVM_READOBJ_H #include "llvm/Support/CommandLine.h" +#include "llvm/Support/Compiler.h" #include <string> namespace llvm { @@ -19,7 +20,8 @@ namespace llvm { } // Various helper functions. - bool error(std::error_code ec); + LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg); + void error(std::error_code ec); bool relocAddressLess(object::RelocationRef A, object::RelocationRef B); } // namespace llvm |