diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2020-01-22 20:31:01 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2020-01-22 20:31:01 +0000 |
commit | 8bcb0991864975618c09697b1aca10683346d9f0 (patch) | |
tree | 0afab28faa50e5f27698f8dd6c1921fff8d25e39 /contrib/llvm-project/llvm/tools/llvm-readobj/XCOFFDumper.cpp | |
parent | b14637d118e110006a149a79b649c5695e7f419a (diff) | |
parent | 1d5ae1026e831016fc29fd927877c86af904481f (diff) | |
download | src-8bcb0991864975618c09697b1aca10683346d9f0.tar.gz src-8bcb0991864975618c09697b1aca10683346d9f0.zip |
Merge ^/vendor/llvm/dist up to its last change, and resolve conflicts.
Notes
Notes:
svn path=/projects/clang1000-import/; revision=356992
Diffstat (limited to 'contrib/llvm-project/llvm/tools/llvm-readobj/XCOFFDumper.cpp')
-rw-r--r-- | contrib/llvm-project/llvm/tools/llvm-readobj/XCOFFDumper.cpp | 402 |
1 files changed, 378 insertions, 24 deletions
diff --git a/contrib/llvm-project/llvm/tools/llvm-readobj/XCOFFDumper.cpp b/contrib/llvm-project/llvm/tools/llvm-readobj/XCOFFDumper.cpp index 6f260f91537f..fe95b6d1b494 100644 --- a/contrib/llvm-project/llvm/tools/llvm-readobj/XCOFFDumper.cpp +++ b/contrib/llvm-project/llvm/tools/llvm-readobj/XCOFFDumper.cpp @@ -22,6 +22,12 @@ using namespace object; namespace { class XCOFFDumper : public ObjDumper { + enum { + SymbolTypeMask = 0x07, + SymbolAlignmentMask = 0xF8, + SymbolAlignmentBitOffset = 3 + }; + public: XCOFFDumper(const XCOFFObjectFile &Obj, ScopedPrinter &Writer) : ObjDumper(Writer), Obj(Obj) {} @@ -37,11 +43,21 @@ public: private: template <typename T> void printSectionHeaders(ArrayRef<T> Sections); - - const XCOFFObjectFile &Obj; + template <typename T> void printGenericSectionHeader(T &Sec) const; + template <typename T> void printOverflowSectionHeader(T &Sec) const; + void printFileAuxEnt(const XCOFFFileAuxEnt *AuxEntPtr); + void printCsectAuxEnt32(const XCOFFCsectAuxEnt32 *AuxEntPtr); + void printSectAuxEntForStat(const XCOFFSectAuxEntForStat *AuxEntPtr); + void printSymbol(const SymbolRef &); // Least significant 3 bits are reserved. static constexpr unsigned SectionFlagsReservedMask = 0x7; + + // The low order 16 bits of section flags denotes the section type. + static constexpr unsigned SectionFlagsTypeMask = 0xffffu; + + void printRelocations(ArrayRef<XCOFFSectionHeader32> Sections); + const XCOFFObjectFile &Obj; }; } // anonymous namespace @@ -100,11 +116,315 @@ void XCOFFDumper::printSectionHeaders() { } void XCOFFDumper::printRelocations() { - llvm_unreachable("Unimplemented functionality for XCOFFDumper"); + if (Obj.is64Bit()) + llvm_unreachable("64-bit relocation output not implemented!"); + else + printRelocations(Obj.sections32()); +} + +static const EnumEntry<XCOFF::RelocationType> RelocationTypeNameclass[] = { +#define ECase(X) \ + { #X, XCOFF::X } + ECase(R_POS), ECase(R_RL), ECase(R_RLA), ECase(R_NEG), + ECase(R_REL), ECase(R_TOC), ECase(R_TRL), ECase(R_TRLA), + ECase(R_GL), ECase(R_TCL), ECase(R_REF), ECase(R_BA), + ECase(R_BR), ECase(R_RBA), ECase(R_RBR), ECase(R_TLS), + ECase(R_TLS_IE), ECase(R_TLS_LD), ECase(R_TLS_LE), ECase(R_TLSM), + ECase(R_TLSML), ECase(R_TOCU), ECase(R_TOCL) +#undef ECase +}; + +void XCOFFDumper::printRelocations(ArrayRef<XCOFFSectionHeader32> Sections) { + if (!opts::ExpandRelocs) + report_fatal_error("Unexpanded relocation output not implemented."); + + ListScope LS(W, "Relocations"); + uint16_t Index = 0; + for (const auto &Sec : Sections) { + ++Index; + // Only the .text, .data, .tdata, and STYP_DWARF sections have relocation. + if (Sec.Flags != XCOFF::STYP_TEXT && Sec.Flags != XCOFF::STYP_DATA && + Sec.Flags != XCOFF::STYP_TDATA && Sec.Flags != XCOFF::STYP_DWARF) + continue; + auto Relocations = unwrapOrError(Obj.getFileName(), Obj.relocations(Sec)); + if (Relocations.empty()) + continue; + + W.startLine() << "Section (index: " << Index << ") " << Sec.getName() + << " {\n"; + for (auto Reloc : Relocations) { + StringRef SymbolName = unwrapOrError( + Obj.getFileName(), Obj.getSymbolNameByIndex(Reloc.SymbolIndex)); + + DictScope RelocScope(W, "Relocation"); + W.printHex("Virtual Address", Reloc.VirtualAddress); + W.printNumber("Symbol", SymbolName, Reloc.SymbolIndex); + W.printString("IsSigned", Reloc.isRelocationSigned() ? "Yes" : "No"); + W.printNumber("FixupBitValue", Reloc.isFixupIndicated() ? 1 : 0); + W.printNumber("Length", Reloc.getRelocatedLength()); + W.printEnum("Type", (uint8_t)Reloc.Type, + makeArrayRef(RelocationTypeNameclass)); + } + W.unindent(); + W.startLine() << "}\n"; + } +} + +static const EnumEntry<XCOFF::CFileStringType> FileStringType[] = { +#define ECase(X) \ + { #X, XCOFF::X } + ECase(XFT_FN), ECase(XFT_CT), ECase(XFT_CV), ECase(XFT_CD) +#undef ECase +}; + +void XCOFFDumper::printFileAuxEnt(const XCOFFFileAuxEnt *AuxEntPtr) { + if (Obj.is64Bit()) + report_fatal_error( + "Printing for File Auxiliary Entry in 64-bit is unimplemented."); + StringRef FileName = + unwrapOrError(Obj.getFileName(), Obj.getCFileName(AuxEntPtr)); + DictScope SymDs(W, "File Auxiliary Entry"); + W.printNumber("Index", + Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr))); + W.printString("Name", FileName); + W.printEnum("Type", static_cast<uint8_t>(AuxEntPtr->Type), + makeArrayRef(FileStringType)); +} + +static const EnumEntry<XCOFF::StorageMappingClass> CsectStorageMappingClass[] = + { +#define ECase(X) \ + { #X, XCOFF::X } + ECase(XMC_PR), ECase(XMC_RO), ECase(XMC_DB), + ECase(XMC_GL), ECase(XMC_XO), ECase(XMC_SV), + ECase(XMC_SV64), ECase(XMC_SV3264), ECase(XMC_TI), + ECase(XMC_TB), ECase(XMC_RW), ECase(XMC_TC0), + ECase(XMC_TC), ECase(XMC_TD), ECase(XMC_DS), + ECase(XMC_UA), ECase(XMC_BS), ECase(XMC_UC), + ECase(XMC_TL), ECase(XMC_TE) +#undef ECase +}; + +static const EnumEntry<XCOFF::SymbolType> CsectSymbolTypeClass[] = { +#define ECase(X) \ + { #X, XCOFF::X } + ECase(XTY_ER), ECase(XTY_SD), ECase(XTY_LD), ECase(XTY_CM) +#undef ECase +}; + +void XCOFFDumper::printCsectAuxEnt32(const XCOFFCsectAuxEnt32 *AuxEntPtr) { + assert(!Obj.is64Bit() && "32-bit interface called on 64-bit object file."); + + DictScope SymDs(W, "CSECT Auxiliary Entry"); + W.printNumber("Index", + Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr))); + if ((AuxEntPtr->SymbolAlignmentAndType & SymbolTypeMask) == XCOFF::XTY_LD) + W.printNumber("ContainingCsectSymbolIndex", AuxEntPtr->SectionOrLength); + else + W.printNumber("SectionLen", AuxEntPtr->SectionOrLength); + W.printHex("ParameterHashIndex", AuxEntPtr->ParameterHashIndex); + W.printHex("TypeChkSectNum", AuxEntPtr->TypeChkSectNum); + // Print out symbol alignment and type. + W.printNumber("SymbolAlignmentLog2", + (AuxEntPtr->SymbolAlignmentAndType & SymbolAlignmentMask) >> + SymbolAlignmentBitOffset); + W.printEnum("SymbolType", AuxEntPtr->SymbolAlignmentAndType & SymbolTypeMask, + makeArrayRef(CsectSymbolTypeClass)); + W.printEnum("StorageMappingClass", + static_cast<uint8_t>(AuxEntPtr->StorageMappingClass), + makeArrayRef(CsectStorageMappingClass)); + W.printHex("StabInfoIndex", AuxEntPtr->StabInfoIndex); + W.printHex("StabSectNum", AuxEntPtr->StabSectNum); +} + +void XCOFFDumper::printSectAuxEntForStat( + const XCOFFSectAuxEntForStat *AuxEntPtr) { + assert(!Obj.is64Bit() && "32-bit interface called on 64-bit object file."); + + DictScope SymDs(W, "Sect Auxiliary Entry For Stat"); + W.printNumber("Index", + Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr))); + W.printNumber("SectionLength", AuxEntPtr->SectionLength); + + // Unlike the corresponding fields in the section header, NumberOfRelocEnt + // and NumberOfLineNum do not handle values greater than 65535. + W.printNumber("NumberOfRelocEnt", AuxEntPtr->NumberOfRelocEnt); + W.printNumber("NumberOfLineNum", AuxEntPtr->NumberOfLineNum); +} + +static const EnumEntry<XCOFF::StorageClass> SymStorageClass[] = { +#define ECase(X) \ + { #X, XCOFF::X } + ECase(C_NULL), ECase(C_AUTO), ECase(C_EXT), ECase(C_STAT), + ECase(C_REG), ECase(C_EXTDEF), ECase(C_LABEL), ECase(C_ULABEL), + ECase(C_MOS), ECase(C_ARG), ECase(C_STRTAG), ECase(C_MOU), + ECase(C_UNTAG), ECase(C_TPDEF), ECase(C_USTATIC), ECase(C_ENTAG), + ECase(C_MOE), ECase(C_REGPARM), ECase(C_FIELD), ECase(C_BLOCK), + ECase(C_FCN), ECase(C_EOS), ECase(C_FILE), ECase(C_LINE), + ECase(C_ALIAS), ECase(C_HIDDEN), ECase(C_HIDEXT), ECase(C_BINCL), + ECase(C_EINCL), ECase(C_INFO), ECase(C_WEAKEXT), ECase(C_DWARF), + ECase(C_GSYM), ECase(C_LSYM), ECase(C_PSYM), ECase(C_RSYM), + ECase(C_RPSYM), ECase(C_STSYM), ECase(C_TCSYM), ECase(C_BCOMM), + ECase(C_ECOML), ECase(C_ECOMM), ECase(C_DECL), ECase(C_ENTRY), + ECase(C_FUN), ECase(C_BSTAT), ECase(C_ESTAT), ECase(C_GTLS), + ECase(C_STTLS), ECase(C_EFCN) +#undef ECase +}; + +static StringRef GetSymbolValueName(XCOFF::StorageClass SC) { + switch (SC) { + case XCOFF::C_EXT: + case XCOFF::C_WEAKEXT: + case XCOFF::C_HIDEXT: + case XCOFF::C_STAT: + return "Value (RelocatableAddress)"; + case XCOFF::C_FILE: + return "Value (SymbolTableIndex)"; + case XCOFF::C_FCN: + case XCOFF::C_BLOCK: + case XCOFF::C_FUN: + case XCOFF::C_STSYM: + case XCOFF::C_BINCL: + case XCOFF::C_EINCL: + case XCOFF::C_INFO: + case XCOFF::C_BSTAT: + case XCOFF::C_LSYM: + case XCOFF::C_PSYM: + case XCOFF::C_RPSYM: + case XCOFF::C_RSYM: + case XCOFF::C_ECOML: + case XCOFF::C_DWARF: + assert(false && "This StorageClass for the symbol is not yet implemented."); + return ""; + default: + return "Value"; + } +} + +static const EnumEntry<XCOFF::CFileLangId> CFileLangIdClass[] = { +#define ECase(X) \ + { #X, XCOFF::X } + ECase(TB_C), ECase(TB_CPLUSPLUS) +#undef ECase +}; + +static const EnumEntry<XCOFF::CFileCpuId> CFileCpuIdClass[] = { +#define ECase(X) \ + { #X, XCOFF::X } + ECase(TCPU_PPC64), ECase(TCPU_COM), ECase(TCPU_970) +#undef ECase +}; + +void XCOFFDumper::printSymbol(const SymbolRef &S) { + if (Obj.is64Bit()) + report_fatal_error("64-bit support is unimplemented."); + + DataRefImpl SymbolDRI = S.getRawDataRefImpl(); + const XCOFFSymbolEntry *SymbolEntPtr = Obj.toSymbolEntry(SymbolDRI); + + XCOFFSymbolRef XCOFFSymRef(SymbolDRI, &Obj); + uint8_t NumberOfAuxEntries = XCOFFSymRef.getNumberOfAuxEntries(); + + DictScope SymDs(W, "Symbol"); + + StringRef SymbolName = + unwrapOrError(Obj.getFileName(), Obj.getSymbolName(SymbolDRI)); + + W.printNumber("Index", + Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(SymbolEntPtr))); + W.printString("Name", SymbolName); + W.printHex(GetSymbolValueName(SymbolEntPtr->StorageClass), + SymbolEntPtr->Value); + + StringRef SectionName = + unwrapOrError(Obj.getFileName(), Obj.getSymbolSectionName(SymbolEntPtr)); + + W.printString("Section", SectionName); + if (XCOFFSymRef.getStorageClass() == XCOFF::C_FILE) { + W.printEnum("Source Language ID", + SymbolEntPtr->CFileLanguageIdAndTypeId.LanguageId, + makeArrayRef(CFileLangIdClass)); + W.printEnum("CPU Version ID", + SymbolEntPtr->CFileLanguageIdAndTypeId.CpuTypeId, + makeArrayRef(CFileCpuIdClass)); + } else + W.printHex("Type", SymbolEntPtr->SymbolType); + + W.printEnum("StorageClass", static_cast<uint8_t>(SymbolEntPtr->StorageClass), + makeArrayRef(SymStorageClass)); + W.printNumber("NumberOfAuxEntries", SymbolEntPtr->NumberOfAuxEntries); + + if (NumberOfAuxEntries == 0) + return; + + switch (XCOFFSymRef.getStorageClass()) { + case XCOFF::C_FILE: + // If the symbol is C_FILE and has auxiliary entries... + for (int i = 1; i <= NumberOfAuxEntries; i++) { + const XCOFFFileAuxEnt *FileAuxEntPtr = + reinterpret_cast<const XCOFFFileAuxEnt *>(SymbolEntPtr + i); +#ifndef NDEBUG + Obj.checkSymbolEntryPointer(reinterpret_cast<uintptr_t>(FileAuxEntPtr)); +#endif + printFileAuxEnt(FileAuxEntPtr); + } + break; + case XCOFF::C_EXT: + case XCOFF::C_WEAKEXT: + case XCOFF::C_HIDEXT: + // If the symbol is for a function, and it has more than 1 auxiliary entry, + // then one of them must be function auxiliary entry which we do not + // support yet. + if (XCOFFSymRef.isFunction() && NumberOfAuxEntries >= 2) + report_fatal_error("Function auxiliary entry printing is unimplemented."); + + // If there is more than 1 auxiliary entry, instead of printing out + // error information, print out the raw Auxiliary entry from 1st till + // the last - 1. The last one must be a CSECT Auxiliary Entry. + for (int i = 1; i < NumberOfAuxEntries; i++) { + W.startLine() << "!Unexpected raw auxiliary entry data:\n"; + W.startLine() << format_bytes( + ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(SymbolEntPtr + i), + XCOFF::SymbolTableEntrySize)); + } + + // The symbol's last auxiliary entry is a CSECT Auxiliary Entry. + printCsectAuxEnt32(XCOFFSymRef.getXCOFFCsectAuxEnt32()); + break; + case XCOFF::C_STAT: + if (NumberOfAuxEntries > 1) + report_fatal_error( + "C_STAT symbol should not have more than 1 auxiliary entry."); + + const XCOFFSectAuxEntForStat *StatAuxEntPtr; + StatAuxEntPtr = + reinterpret_cast<const XCOFFSectAuxEntForStat *>(SymbolEntPtr + 1); +#ifndef NDEBUG + Obj.checkSymbolEntryPointer(reinterpret_cast<uintptr_t>(StatAuxEntPtr)); +#endif + printSectAuxEntForStat(StatAuxEntPtr); + break; + case XCOFF::C_DWARF: + case XCOFF::C_BLOCK: + case XCOFF::C_FCN: + report_fatal_error("Symbol table entry printing for this storage class " + "type is unimplemented."); + break; + default: + for (int i = 1; i <= NumberOfAuxEntries; i++) { + W.startLine() << "!Unexpected raw auxiliary entry data:\n"; + W.startLine() << format_bytes( + ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(SymbolEntPtr + i), + XCOFF::SymbolTableEntrySize)); + } + break; + } } void XCOFFDumper::printSymbols() { - llvm_unreachable("Unimplemented functionality for XCOFFDumper"); + ListScope Group(W, "Symbols"); + for (const SymbolRef &S : Obj.symbols()) + printSymbol(S); } void XCOFFDumper::printDynamicSymbols() { @@ -135,6 +455,39 @@ static const EnumEntry<XCOFF::SectionTypeFlags> SectionTypeFlagsNames[] = { }; template <typename T> +void XCOFFDumper::printOverflowSectionHeader(T &Sec) const { + if (Obj.is64Bit()) { + reportWarning(make_error<StringError>("An 64-bit XCOFF object file may not " + "contain an overflow section header.", + object_error::parse_failed), + Obj.getFileName()); + } + + W.printString("Name", Sec.getName()); + W.printNumber("NumberOfRelocations", Sec.PhysicalAddress); + W.printNumber("NumberOfLineNumbers", Sec.VirtualAddress); + W.printHex("Size", Sec.SectionSize); + W.printHex("RawDataOffset", Sec.FileOffsetToRawData); + W.printHex("RelocationPointer", Sec.FileOffsetToRelocationInfo); + W.printHex("LineNumberPointer", Sec.FileOffsetToLineNumberInfo); + W.printNumber("IndexOfSectionOverflowed", Sec.NumberOfRelocations); + W.printNumber("IndexOfSectionOverflowed", Sec.NumberOfLineNumbers); +} + +template <typename T> +void XCOFFDumper::printGenericSectionHeader(T &Sec) const { + W.printString("Name", Sec.getName()); + W.printHex("PhysicalAddress", Sec.PhysicalAddress); + W.printHex("VirtualAddress", Sec.VirtualAddress); + W.printHex("Size", Sec.SectionSize); + W.printHex("RawDataOffset", Sec.FileOffsetToRawData); + W.printHex("RelocationPointer", Sec.FileOffsetToRelocationInfo); + W.printHex("LineNumberPointer", Sec.FileOffsetToLineNumberInfo); + W.printNumber("NumberOfRelocations", Sec.NumberOfRelocations); + W.printNumber("NumberOfLineNumbers", Sec.NumberOfLineNumbers); +} + +template <typename T> void XCOFFDumper::printSectionHeaders(ArrayRef<T> Sections) { ListScope Group(W, "Sections"); @@ -143,27 +496,28 @@ void XCOFFDumper::printSectionHeaders(ArrayRef<T> Sections) { DictScope SecDS(W, "Section"); W.printNumber("Index", Index++); - W.printString("Name", Sec.getName()); - - W.printHex("PhysicalAddress", Sec.PhysicalAddress); - W.printHex("VirtualAddress", Sec.VirtualAddress); - W.printHex("Size", Sec.SectionSize); - W.printHex("RawDataOffset", Sec.FileOffsetToRawData); - W.printHex("RelocationPointer", Sec.FileOffsetToRelocationInfo); - W.printHex("LineNumberPointer", Sec.FileOffsetToLineNumberInfo); - - // TODO Need to add overflow handling when NumberOfX == _OVERFLOW_MARKER - // in 32-bit object files. - W.printNumber("NumberOfRelocations", Sec.NumberOfRelocations); - W.printNumber("NumberOfLineNumbers", Sec.NumberOfLineNumbers); - - // The most significant 16-bits represent the DWARF section subtype. For - // now we just dump the section type flags. - uint16_t Flags = Sec.Flags & 0xffffu; - if (Flags & SectionFlagsReservedMask) - W.printHex("Flags", "Reserved", Flags); + + uint16_t SectionType = Sec.Flags & SectionFlagsTypeMask; + switch (SectionType) { + case XCOFF::STYP_OVRFLO: + printOverflowSectionHeader(Sec); + break; + case XCOFF::STYP_LOADER: + case XCOFF::STYP_EXCEPT: + case XCOFF::STYP_TYPCHK: + // TODO The interpretation of loader, exception and type check section + // headers are different from that of generic section headers. We will + // implement them later. We interpret them as generic section headers for + // now. + default: + printGenericSectionHeader(Sec); + break; + } + // For now we just dump the section type portion of the flags. + if (SectionType & SectionFlagsReservedMask) + W.printHex("Flags", "Reserved", SectionType); else - W.printEnum("Type", Flags, makeArrayRef(SectionTypeFlagsNames)); + W.printEnum("Type", SectionType, makeArrayRef(SectionTypeFlagsNames)); } if (opts::SectionRelocations) |