| //===-- XCOFFDumper.cpp - XCOFF dumping utility -----------------*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file implements an XCOFF specific dumper for llvm-readobj. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "Error.h" |
| #include "ObjDumper.h" |
| #include "llvm-readobj.h" |
| #include "llvm/Object/XCOFFObjectFile.h" |
| #include "llvm/Support/ScopedPrinter.h" |
| |
| using namespace llvm; |
| 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) {} |
| |
| void printFileHeaders() override; |
| void printSectionHeaders() override; |
| void printRelocations() override; |
| void printSymbols() override; |
| void printDynamicSymbols() override; |
| void printUnwindInfo() override; |
| void printStackMap() const override; |
| void printNeededLibraries() override; |
| |
| private: |
| template <typename T> void printSectionHeaders(ArrayRef<T> Sections); |
| 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 |
| |
| void XCOFFDumper::printFileHeaders() { |
| DictScope DS(W, "FileHeader"); |
| W.printHex("Magic", Obj.getMagic()); |
| W.printNumber("NumberOfSections", Obj.getNumberOfSections()); |
| |
| // Negative timestamp values are reserved for future use. |
| int32_t TimeStamp = Obj.getTimeStamp(); |
| if (TimeStamp > 0) { |
| // This handling of the time stamp assumes that the host system's time_t is |
| // compatible with AIX time_t. If a platform is not compatible, the lit |
| // tests will let us know. |
| time_t TimeDate = TimeStamp; |
| |
| char FormattedTime[21] = {}; |
| size_t BytesWritten = |
| strftime(FormattedTime, 21, "%Y-%m-%dT%H:%M:%SZ", gmtime(&TimeDate)); |
| if (BytesWritten) |
| W.printHex("TimeStamp", FormattedTime, TimeStamp); |
| else |
| W.printHex("Timestamp", TimeStamp); |
| } else { |
| W.printHex("TimeStamp", TimeStamp == 0 ? "None" : "Reserved Value", |
| TimeStamp); |
| } |
| |
| // The number of symbol table entries is an unsigned value in 64-bit objects |
| // and a signed value (with negative values being 'reserved') in 32-bit |
| // objects. |
| if (Obj.is64Bit()) { |
| W.printHex("SymbolTableOffset", Obj.getSymbolTableOffset64()); |
| W.printNumber("SymbolTableEntries", Obj.getNumberOfSymbolTableEntries64()); |
| } else { |
| W.printHex("SymbolTableOffset", Obj.getSymbolTableOffset32()); |
| int32_t SymTabEntries = Obj.getRawNumberOfSymbolTableEntries32(); |
| if (SymTabEntries >= 0) |
| W.printNumber("SymbolTableEntries", SymTabEntries); |
| else |
| W.printHex("SymbolTableEntries", "Reserved Value", SymTabEntries); |
| } |
| |
| W.printHex("OptionalHeaderSize", Obj.getOptionalHeaderSize()); |
| W.printHex("Flags", Obj.getFlags()); |
| |
| // TODO FIXME Add support for the auxiliary header (if any) once |
| // XCOFFObjectFile has the necessary support. |
| } |
| |
| void XCOFFDumper::printSectionHeaders() { |
| if (Obj.is64Bit()) |
| printSectionHeaders(Obj.sections64()); |
| else |
| printSectionHeaders(Obj.sections32()); |
| } |
| |
| void XCOFFDumper::printRelocations() { |
| 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() { |
| ListScope Group(W, "Symbols"); |
| for (const SymbolRef &S : Obj.symbols()) |
| printSymbol(S); |
| } |
| |
| void XCOFFDumper::printDynamicSymbols() { |
| llvm_unreachable("Unimplemented functionality for XCOFFDumper"); |
| } |
| |
| void XCOFFDumper::printUnwindInfo() { |
| llvm_unreachable("Unimplemented functionality for XCOFFDumper"); |
| } |
| |
| void XCOFFDumper::printStackMap() const { |
| llvm_unreachable("Unimplemented functionality for XCOFFDumper"); |
| } |
| |
| void XCOFFDumper::printNeededLibraries() { |
| llvm_unreachable("Unimplemented functionality for XCOFFDumper"); |
| } |
| |
| static const EnumEntry<XCOFF::SectionTypeFlags> SectionTypeFlagsNames[] = { |
| #define ECase(X) \ |
| { #X, XCOFF::X } |
| ECase(STYP_PAD), ECase(STYP_DWARF), ECase(STYP_TEXT), |
| ECase(STYP_DATA), ECase(STYP_BSS), ECase(STYP_EXCEPT), |
| ECase(STYP_INFO), ECase(STYP_TDATA), ECase(STYP_TBSS), |
| ECase(STYP_LOADER), ECase(STYP_DEBUG), ECase(STYP_TYPCHK), |
| ECase(STYP_OVRFLO) |
| #undef ECase |
| }; |
| |
| 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"); |
| |
| uint16_t Index = 1; |
| for (const T &Sec : Sections) { |
| DictScope SecDS(W, "Section"); |
| |
| W.printNumber("Index", Index++); |
| |
| 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", SectionType, makeArrayRef(SectionTypeFlagsNames)); |
| } |
| |
| if (opts::SectionRelocations) |
| report_fatal_error("Dumping section relocations is unimplemented"); |
| |
| if (opts::SectionSymbols) |
| report_fatal_error("Dumping symbols is unimplemented"); |
| |
| if (opts::SectionData) |
| report_fatal_error("Dumping section data is unimplemented"); |
| } |
| |
| namespace llvm { |
| std::error_code createXCOFFDumper(const object::ObjectFile *Obj, |
| ScopedPrinter &Writer, |
| std::unique_ptr<ObjDumper> &Result) { |
| const XCOFFObjectFile *XObj = dyn_cast<XCOFFObjectFile>(Obj); |
| if (!XObj) |
| return readobj_error::unsupported_obj_file_format; |
| |
| Result.reset(new XCOFFDumper(*XObj, Writer)); |
| return readobj_error::success; |
| } |
| } // namespace llvm |