//===-- 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 "ObjDumper.h" #include "llvm-readobj.h" #include "llvm/Demangle/Demangle.h" #include "llvm/Object/XCOFFObjectFile.h" #include "llvm/Support/FormattedStream.h" #include "llvm/Support/ScopedPrinter.h" #include using namespace llvm; using namespace object; namespace { class XCOFFDumper : public ObjDumper { public: XCOFFDumper(const XCOFFObjectFile &Obj, ScopedPrinter &Writer) : ObjDumper(Writer, Obj.getFileName()), Obj(Obj) {} void printFileHeaders() override; void printAuxiliaryHeader() override; void printSectionHeaders() override; void printRelocations() override; void printSymbols(bool ExtraSymInfo) override; void printDynamicSymbols() override; void printUnwindInfo() override; void printStackMap() const override; void printNeededLibraries() override; void printStringTable() override; void printExceptionSection() override; void printLoaderSection(bool PrintHeader, bool PrintSymbols, bool PrintRelocations) override; ScopedPrinter &getScopedPrinter() const { return W; } private: template void printSectionHeaders(ArrayRef Sections); template void printGenericSectionHeader(T &Sec) const; template void printOverflowSectionHeader(T &Sec) const; template void printExceptionSectionEntry(const T &ExceptionSectEnt) const; template void printExceptionSectionEntries() const; template const T *getAuxEntPtr(uintptr_t AuxAddress); void printFileAuxEnt(const XCOFFFileAuxEnt *AuxEntPtr); void printCsectAuxEnt(XCOFFCsectAuxRef AuxEntRef); void printSectAuxEntForStat(const XCOFFSectAuxEntForStat *AuxEntPtr); void printExceptionAuxEnt(const XCOFFExceptionAuxEnt *AuxEntPtr); void printFunctionAuxEnt(const XCOFFFunctionAuxEnt32 *AuxEntPtr); void printFunctionAuxEnt(const XCOFFFunctionAuxEnt64 *AuxEntPtr); void printBlockAuxEnt(const XCOFFBlockAuxEnt32 *AuxEntPtr); void printBlockAuxEnt(const XCOFFBlockAuxEnt64 *AuxEntPtr); template void printSectAuxEntForDWARF(const T *AuxEntPtr); void printSymbol(const SymbolRef &); template void printRelocation(RelTy Reloc); template void printRelocations(ArrayRef Sections); void printAuxiliaryHeader(const XCOFFAuxiliaryHeader32 *AuxHeader); void printAuxiliaryHeader(const XCOFFAuxiliaryHeader64 *AuxHeader); void printLoaderSectionHeader(uintptr_t LoaderSectAddr); void printLoaderSectionSymbols(uintptr_t LoaderSectAddr); template void printLoaderSectionSymbolsHelper(uintptr_t LoaderSectAddr); template void printLoaderSectionRelocationEntry(LoadSectionRelocTy *LoaderSecRelEntPtr, StringRef SymbolName); void printLoaderSectionRelocationEntries(uintptr_t LoaderSectAddr); template void printLoaderSectionRelocationEntriesHelper(uintptr_t LoaderSectAddr); const XCOFFObjectFile &Obj; const static int32_t FirstSymIdxOfLoaderSec = 3; }; } // 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[80] = {}; size_t BytesFormatted = strftime(FormattedTime, sizeof(FormattedTime), "%F %T", gmtime(&TimeDate)); if (BytesFormatted) 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::printAuxiliaryHeader() { DictScope DS(W, "AuxiliaryHeader"); if (Obj.is64Bit()) printAuxiliaryHeader(Obj.auxiliaryHeader64()); else printAuxiliaryHeader(Obj.auxiliaryHeader32()); } void XCOFFDumper::printSectionHeaders() { if (Obj.is64Bit()) printSectionHeaders(Obj.sections64()); else printSectionHeaders(Obj.sections32()); } void XCOFFDumper::printLoaderSection(bool PrintHeader, bool PrintSymbols, bool PrintRelocations) { DictScope DS(W, "Loader Section"); Expected LoaderSectionAddrOrError = Obj.getSectionFileOffsetToRawData(XCOFF::STYP_LOADER); if (!LoaderSectionAddrOrError) { reportUniqueWarning(LoaderSectionAddrOrError.takeError()); return; } uintptr_t LoaderSectionAddr = LoaderSectionAddrOrError.get(); if (LoaderSectionAddr == 0) return; W.indent(); if (PrintHeader) printLoaderSectionHeader(LoaderSectionAddr); if (PrintSymbols) printLoaderSectionSymbols(LoaderSectionAddr); if (PrintRelocations) printLoaderSectionRelocationEntries(LoaderSectionAddr); W.unindent(); } void XCOFFDumper::printLoaderSectionHeader(uintptr_t LoaderSectionAddr) { DictScope DS(W, "Loader Section Header"); auto PrintLoadSecHeaderCommon = [&](const auto *LDHeader) { W.printNumber("Version", LDHeader->Version); W.printNumber("NumberOfSymbolEntries", LDHeader->NumberOfSymTabEnt); W.printNumber("NumberOfRelocationEntries", LDHeader->NumberOfRelTabEnt); W.printNumber("LengthOfImportFileIDStringTable", LDHeader->LengthOfImpidStrTbl); W.printNumber("NumberOfImportFileIDs", LDHeader->NumberOfImpid); W.printHex("OffsetToImportFileIDs", LDHeader->OffsetToImpid); W.printNumber("LengthOfStringTable", LDHeader->LengthOfStrTbl); W.printHex("OffsetToStringTable", LDHeader->OffsetToStrTbl); }; if (Obj.is64Bit()) { const LoaderSectionHeader64 *LoaderSec64 = reinterpret_cast(LoaderSectionAddr); PrintLoadSecHeaderCommon(LoaderSec64); W.printHex("OffsetToSymbolTable", LoaderSec64->OffsetToSymTbl); W.printHex("OffsetToRelocationEntries", LoaderSec64->OffsetToRelEnt); } else { const LoaderSectionHeader32 *LoaderSec32 = reinterpret_cast(LoaderSectionAddr); PrintLoadSecHeaderCommon(LoaderSec32); } } const EnumEntry 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 }; template void XCOFFDumper::printLoaderSectionSymbolsHelper(uintptr_t LoaderSectionAddr) { const LoaderSectionHeader *LoadSecHeader = reinterpret_cast(LoaderSectionAddr); const LoaderSectionSymbolEntry *LoadSecSymEntPtr = reinterpret_cast( LoaderSectionAddr + uintptr_t(LoadSecHeader->getOffsetToSymTbl())); for (uint32_t i = 0; i < LoadSecHeader->NumberOfSymTabEnt; ++i, ++LoadSecSymEntPtr) { if (Error E = Binary::checkOffset( Obj.getMemoryBufferRef(), LoaderSectionAddr + uintptr_t(LoadSecHeader->getOffsetToSymTbl()) + (i * sizeof(LoaderSectionSymbolEntry)), sizeof(LoaderSectionSymbolEntry))) { reportUniqueWarning(std::move(E)); return; } Expected SymbolNameOrErr = LoadSecSymEntPtr->getSymbolName(LoadSecHeader); if (!SymbolNameOrErr) { reportUniqueWarning(SymbolNameOrErr.takeError()); return; } DictScope DS(W, "Symbol"); StringRef SymbolName = SymbolNameOrErr.get(); W.printString("Name", opts::Demangle ? demangle(SymbolName) : SymbolName); W.printHex("Virtual Address", LoadSecSymEntPtr->Value); W.printNumber("SectionNum", LoadSecSymEntPtr->SectionNumber); W.printHex("SymbolType", LoadSecSymEntPtr->SymbolType); W.printEnum("StorageClass", static_cast(LoadSecSymEntPtr->StorageClass), ArrayRef(SymStorageClass)); W.printHex("ImportFileID", LoadSecSymEntPtr->ImportFileID); W.printNumber("ParameterTypeCheck", LoadSecSymEntPtr->ParameterTypeCheck); } } void XCOFFDumper::printLoaderSectionSymbols(uintptr_t LoaderSectionAddr) { DictScope DS(W, "Loader Section Symbols"); if (Obj.is64Bit()) printLoaderSectionSymbolsHelper(LoaderSectionAddr); else printLoaderSectionSymbolsHelper(LoaderSectionAddr); } const EnumEntry 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 }; // From the XCOFF specification: there are five implicit external symbols, one // each for the .text, .data, .bss, .tdata, and .tbss sections. These symbols // are referenced from the relocation table entries using symbol table index // values 0, 1, 2, -1, and -2, respectively. static const char *getImplicitLoaderSectionSymName(int SymIndx) { switch (SymIndx) { default: return "Unkown Symbol Name"; case -2: return ".tbss"; case -1: return ".tdata"; case 0: return ".text"; case 1: return ".data"; case 2: return ".bss"; } } template void XCOFFDumper::printLoaderSectionRelocationEntry( LoadSectionRelocTy *LoaderSecRelEntPtr, StringRef SymbolName) { uint16_t Type = LoaderSecRelEntPtr->Type; if (opts::ExpandRelocs) { DictScope DS(W, "Relocation"); auto IsRelocationSigned = [](uint8_t Info) { return Info & XCOFF::XR_SIGN_INDICATOR_MASK; }; auto IsFixupIndicated = [](uint8_t Info) { return Info & XCOFF::XR_FIXUP_INDICATOR_MASK; }; auto GetRelocatedLength = [](uint8_t Info) { // The relocation encodes the bit length being relocated minus 1. Add // back // the 1 to get the actual length being relocated. return (Info & XCOFF::XR_BIASED_LENGTH_MASK) + 1; }; uint8_t Info = Type >> 8; W.printHex("Virtual Address", LoaderSecRelEntPtr->VirtualAddr); W.printNumber("Symbol", opts::Demangle ? demangle(SymbolName) : SymbolName, LoaderSecRelEntPtr->SymbolIndex); W.printString("IsSigned", IsRelocationSigned(Info) ? "Yes" : "No"); W.printNumber("FixupBitValue", IsFixupIndicated(Info) ? 1 : 0); W.printNumber("Length", GetRelocatedLength(Info)); W.printEnum("Type", static_cast(Type), ArrayRef(RelocationTypeNameclass)); W.printNumber("SectionNumber", LoaderSecRelEntPtr->SectionNum); } else { W.startLine() << format_hex(LoaderSecRelEntPtr->VirtualAddr, Obj.is64Bit() ? 18 : 10) << " " << format_hex(Type, 6) << " (" << XCOFF::getRelocationTypeString( static_cast(Type)) << ")" << format_decimal(LoaderSecRelEntPtr->SectionNum, 8) << " " << (opts::Demangle ? demangle(SymbolName) : SymbolName) << " (" << LoaderSecRelEntPtr->SymbolIndex << ")\n"; } } template void XCOFFDumper::printLoaderSectionRelocationEntriesHelper( uintptr_t LoaderSectionAddr) { const LoaderSectionHeader *LoaderSec = reinterpret_cast(LoaderSectionAddr); const LoaderSectionRelocationEntry *LoaderSecRelEntPtr = reinterpret_cast( LoaderSectionAddr + uintptr_t(LoaderSec->getOffsetToRelEnt())); if (!opts::ExpandRelocs) W.startLine() << center_justify("Vaddr", Obj.is64Bit() ? 18 : 10) << center_justify("Type", 15) << right_justify("SecNum", 8) << center_justify("SymbolName (Index) ", 24) << "\n"; for (uint32_t i = 0; i < LoaderSec->NumberOfRelTabEnt; ++i, ++LoaderSecRelEntPtr) { StringRef SymbolName; if (LoaderSecRelEntPtr->SymbolIndex >= FirstSymIdxOfLoaderSec) { // Because there are implicit symbol index values (-2, -1, 0, 1, 2), // LoaderSecRelEnt.SymbolIndex - FirstSymIdxOfLoaderSec will get the // real symbol from the symbol table. const uint64_t SymOffset = (LoaderSecRelEntPtr->SymbolIndex - FirstSymIdxOfLoaderSec) * sizeof(LoaderSectionSymbolEntry); const LoaderSectionSymbolEntry *LoaderSecRelSymEntPtr = reinterpret_cast( LoaderSectionAddr + uintptr_t(LoaderSec->getOffsetToSymTbl()) + SymOffset); Expected SymbolNameOrErr = LoaderSecRelSymEntPtr->getSymbolName(LoaderSec); if (!SymbolNameOrErr) { reportUniqueWarning(SymbolNameOrErr.takeError()); return; } SymbolName = SymbolNameOrErr.get(); } else SymbolName = getImplicitLoaderSectionSymName(LoaderSecRelEntPtr->SymbolIndex); printLoaderSectionRelocationEntry(LoaderSecRelEntPtr, SymbolName); } } void XCOFFDumper::printLoaderSectionRelocationEntries( uintptr_t LoaderSectionAddr) { DictScope DS(W, "Loader Section Relocations"); if (Obj.is64Bit()) printLoaderSectionRelocationEntriesHelper( LoaderSectionAddr); else printLoaderSectionRelocationEntriesHelper( LoaderSectionAddr); } template void XCOFFDumper::printExceptionSectionEntry(const T &ExceptionSectEnt) const { if (ExceptionSectEnt.getReason()) W.printHex("Trap Instr Addr", ExceptionSectEnt.getTrapInstAddr()); else { uint32_t SymIdx = ExceptionSectEnt.getSymbolIndex(); Expected ErrOrSymbolName = Obj.getSymbolNameByIndex(SymIdx); if (Error E = ErrOrSymbolName.takeError()) { reportUniqueWarning(std::move(E)); return; } StringRef SymName = *ErrOrSymbolName; W.printNumber("Symbol", SymName, SymIdx); } W.printNumber("LangID", ExceptionSectEnt.getLangID()); W.printNumber("Reason", ExceptionSectEnt.getReason()); } template void XCOFFDumper::printExceptionSectionEntries() const { Expected> ExceptSectEntsOrErr = Obj.getExceptionEntries(); if (Error E = ExceptSectEntsOrErr.takeError()) { reportUniqueWarning(std::move(E)); return; } ArrayRef ExceptSectEnts = *ExceptSectEntsOrErr; DictScope DS(W, "Exception section"); if (ExceptSectEnts.empty()) return; for (auto &Ent : ExceptSectEnts) printExceptionSectionEntry(Ent); } void XCOFFDumper::printExceptionSection() { if (Obj.is64Bit()) printExceptionSectionEntries(); else printExceptionSectionEntries(); } void XCOFFDumper::printRelocations() { if (Obj.is64Bit()) printRelocations(Obj.sections64()); else printRelocations(Obj.sections32()); } template void XCOFFDumper::printRelocation(RelTy Reloc) { Expected ErrOrSymbolName = Obj.getSymbolNameByIndex(Reloc.SymbolIndex); if (Error E = ErrOrSymbolName.takeError()) { reportUniqueWarning(std::move(E)); return; } StringRef SymbolName = *ErrOrSymbolName; StringRef RelocName = XCOFF::getRelocationTypeString(Reloc.Type); if (opts::ExpandRelocs) { DictScope Group(W, "Relocation"); W.printHex("Virtual Address", Reloc.VirtualAddress); W.printNumber("Symbol", opts::Demangle ? demangle(SymbolName) : 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, ArrayRef(RelocationTypeNameclass)); } else { raw_ostream &OS = W.startLine(); OS << W.hex(Reloc.VirtualAddress) << " " << RelocName << " " << (opts::Demangle ? demangle(SymbolName) : SymbolName) << "(" << Reloc.SymbolIndex << ") " << W.hex(Reloc.Info) << "\n"; } } template void XCOFFDumper::printRelocations(ArrayRef Sections) { ListScope LS(W, "Relocations"); uint16_t Index = 0; for (const Shdr &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; Expected> ErrOrRelocations = Obj.relocations(Sec); if (Error E = ErrOrRelocations.takeError()) { reportUniqueWarning(std::move(E)); continue; } const ArrayRef Relocations = *ErrOrRelocations; if (Relocations.empty()) continue; W.startLine() << "Section (index: " << Index << ") " << Sec.getName() << " {\n"; W.indent(); for (const RelTy Reloc : Relocations) printRelocation(Reloc); W.unindent(); W.startLine() << "}\n"; } } const EnumEntry FileStringType[] = { #define ECase(X) \ { #X, XCOFF::X } ECase(XFT_FN), ECase(XFT_CT), ECase(XFT_CV), ECase(XFT_CD) #undef ECase }; const EnumEntry SymAuxType[] = { #define ECase(X) \ { #X, XCOFF::X } ECase(AUX_EXCEPT), ECase(AUX_FCN), ECase(AUX_SYM), ECase(AUX_FILE), ECase(AUX_CSECT), ECase(AUX_SECT) #undef ECase }; void XCOFFDumper::printFileAuxEnt(const XCOFFFileAuxEnt *AuxEntPtr) { assert((!Obj.is64Bit() || AuxEntPtr->AuxType == XCOFF::AUX_FILE) && "Mismatched auxiliary type!"); StringRef FileName = unwrapOrError(Obj.getFileName(), Obj.getCFileName(AuxEntPtr)); DictScope SymDs(W, "File Auxiliary Entry"); W.printNumber("Index", Obj.getSymbolIndex(reinterpret_cast(AuxEntPtr))); W.printString("Name", FileName); W.printEnum("Type", static_cast(AuxEntPtr->Type), ArrayRef(FileStringType)); if (Obj.is64Bit()) { W.printEnum("Auxiliary Type", static_cast(AuxEntPtr->AuxType), ArrayRef(SymAuxType)); } } static const EnumEntry 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_UL), ECase(XMC_TE) #undef ECase }; const EnumEntry CsectSymbolTypeClass[] = { #define ECase(X) \ { #X, XCOFF::X } ECase(XTY_ER), ECase(XTY_SD), ECase(XTY_LD), ECase(XTY_CM) #undef ECase }; void XCOFFDumper::printCsectAuxEnt(XCOFFCsectAuxRef AuxEntRef) { assert((!Obj.is64Bit() || AuxEntRef.getAuxType64() == XCOFF::AUX_CSECT) && "Mismatched auxiliary type!"); DictScope SymDs(W, "CSECT Auxiliary Entry"); W.printNumber("Index", Obj.getSymbolIndex(AuxEntRef.getEntryAddress())); W.printNumber(AuxEntRef.isLabel() ? "ContainingCsectSymbolIndex" : "SectionLen", AuxEntRef.getSectionOrLength()); W.printHex("ParameterHashIndex", AuxEntRef.getParameterHashIndex()); W.printHex("TypeChkSectNum", AuxEntRef.getTypeChkSectNum()); // Print out symbol alignment and type. W.printNumber("SymbolAlignmentLog2", AuxEntRef.getAlignmentLog2()); W.printEnum("SymbolType", AuxEntRef.getSymbolType(), ArrayRef(CsectSymbolTypeClass)); W.printEnum("StorageMappingClass", static_cast(AuxEntRef.getStorageMappingClass()), ArrayRef(CsectStorageMappingClass)); if (Obj.is64Bit()) { W.printEnum("Auxiliary Type", static_cast(XCOFF::AUX_CSECT), ArrayRef(SymAuxType)); } else { W.printHex("StabInfoIndex", AuxEntRef.getStabInfoIndex32()); W.printHex("StabSectNum", AuxEntRef.getStabSectNum32()); } } 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(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); } void XCOFFDumper::printExceptionAuxEnt(const XCOFFExceptionAuxEnt *AuxEntPtr) { assert(Obj.is64Bit() && "64-bit interface called on 32-bit object file."); DictScope SymDs(W, "Exception Auxiliary Entry"); W.printNumber("Index", Obj.getSymbolIndex(reinterpret_cast(AuxEntPtr))); W.printHex("OffsetToExceptionTable", AuxEntPtr->OffsetToExceptionTbl); W.printHex("SizeOfFunction", AuxEntPtr->SizeOfFunction); W.printNumber("SymbolIndexOfNextBeyond", AuxEntPtr->SymIdxOfNextBeyond); W.printEnum("Auxiliary Type", static_cast(AuxEntPtr->AuxType), ArrayRef(SymAuxType)); } void XCOFFDumper::printFunctionAuxEnt(const XCOFFFunctionAuxEnt32 *AuxEntPtr) { assert(!Obj.is64Bit() && "32-bit interface called on 64-bit object file."); DictScope SymDs(W, "Function Auxiliary Entry"); W.printNumber("Index", Obj.getSymbolIndex(reinterpret_cast(AuxEntPtr))); W.printHex("OffsetToExceptionTable", AuxEntPtr->OffsetToExceptionTbl); W.printHex("SizeOfFunction", AuxEntPtr->SizeOfFunction); W.printHex("PointerToLineNum", AuxEntPtr->PtrToLineNum); W.printNumber("SymbolIndexOfNextBeyond", AuxEntPtr->SymIdxOfNextBeyond); } void XCOFFDumper::printFunctionAuxEnt(const XCOFFFunctionAuxEnt64 *AuxEntPtr) { assert(Obj.is64Bit() && "64-bit interface called on 32-bit object file."); DictScope SymDs(W, "Function Auxiliary Entry"); W.printNumber("Index", Obj.getSymbolIndex(reinterpret_cast(AuxEntPtr))); W.printHex("SizeOfFunction", AuxEntPtr->SizeOfFunction); W.printHex("PointerToLineNum", AuxEntPtr->PtrToLineNum); W.printNumber("SymbolIndexOfNextBeyond", AuxEntPtr->SymIdxOfNextBeyond); W.printEnum("Auxiliary Type", static_cast(AuxEntPtr->AuxType), ArrayRef(SymAuxType)); } void XCOFFDumper::printBlockAuxEnt(const XCOFFBlockAuxEnt32 *AuxEntPtr) { assert(!Obj.is64Bit() && "32-bit interface called on 64-bit object file."); DictScope SymDs(W, "Block Auxiliary Entry"); W.printNumber("Index", Obj.getSymbolIndex(reinterpret_cast(AuxEntPtr))); W.printHex("LineNumber (High 2 Bytes)", AuxEntPtr->LineNumHi); W.printHex("LineNumber (Low 2 Bytes)", AuxEntPtr->LineNumLo); } void XCOFFDumper::printBlockAuxEnt(const XCOFFBlockAuxEnt64 *AuxEntPtr) { assert(Obj.is64Bit() && "64-bit interface called on 32-bit object file."); DictScope SymDs(W, "Block Auxiliary Entry"); W.printNumber("Index", Obj.getSymbolIndex(reinterpret_cast(AuxEntPtr))); W.printHex("LineNumber", AuxEntPtr->LineNum); W.printEnum("Auxiliary Type", static_cast(AuxEntPtr->AuxType), ArrayRef(SymAuxType)); } template void XCOFFDumper::printSectAuxEntForDWARF(const T *AuxEntPtr) { DictScope SymDs(W, "Sect Auxiliary Entry For DWARF"); W.printNumber("Index", Obj.getSymbolIndex(reinterpret_cast(AuxEntPtr))); W.printHex("LengthOfSectionPortion", AuxEntPtr->LengthOfSectionPortion); W.printNumber("NumberOfRelocEntries", AuxEntPtr->NumberOfRelocEnt); if (Obj.is64Bit()) W.printEnum("Auxiliary Type", static_cast(XCOFF::AUX_SECT), ArrayRef(SymAuxType)); } static StringRef GetSymbolValueName(XCOFF::StorageClass SC) { switch (SC) { case XCOFF::C_EXT: case XCOFF::C_WEAKEXT: case XCOFF::C_HIDEXT: case XCOFF::C_STAT: case XCOFF::C_FCN: case XCOFF::C_BLOCK: return "Value (RelocatableAddress)"; case XCOFF::C_FILE: return "Value (SymbolTableIndex)"; case XCOFF::C_DWARF: return "Value (OffsetInDWARF)"; 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: assert(false && "This StorageClass for the symbol is not yet implemented."); return ""; default: return "Value"; } } const EnumEntry CFileLangIdClass[] = { #define ECase(X) \ { #X, XCOFF::X } ECase(TB_C), ECase(TB_Fortran), ECase(TB_CPLUSPLUS) #undef ECase }; const EnumEntry CFileCpuIdClass[] = { #define ECase(X) \ { #X, XCOFF::X } ECase(TCPU_PPC64), ECase(TCPU_COM), ECase(TCPU_970) #undef ECase }; template const T *XCOFFDumper::getAuxEntPtr(uintptr_t AuxAddress) { const T *AuxEntPtr = reinterpret_cast(AuxAddress); Obj.checkSymbolEntryPointer(reinterpret_cast(AuxEntPtr)); return AuxEntPtr; } static void printUnexpectedRawAuxEnt(ScopedPrinter &W, uintptr_t AuxAddress) { W.startLine() << "!Unexpected raw auxiliary entry data:\n"; W.startLine() << format_bytes( ArrayRef( reinterpret_cast(AuxAddress), XCOFF::SymbolTableEntrySize), std::nullopt, XCOFF::SymbolTableEntrySize) << "\n"; } void XCOFFDumper::printSymbol(const SymbolRef &S) { DataRefImpl SymbolDRI = S.getRawDataRefImpl(); XCOFFSymbolRef SymbolEntRef = Obj.toSymbolRef(SymbolDRI); uint8_t NumberOfAuxEntries = SymbolEntRef.getNumberOfAuxEntries(); DictScope SymDs(W, "Symbol"); StringRef SymbolName = unwrapOrError(Obj.getFileName(), SymbolEntRef.getName()); uint32_t SymbolIdx = Obj.getSymbolIndex(SymbolEntRef.getEntryAddress()); XCOFF::StorageClass SymbolClass = SymbolEntRef.getStorageClass(); W.printNumber("Index", SymbolIdx); W.printString("Name", opts::Demangle ? demangle(SymbolName) : SymbolName); W.printHex(GetSymbolValueName(SymbolClass), SymbolEntRef.getValue()); StringRef SectionName = unwrapOrError(Obj.getFileName(), Obj.getSymbolSectionName(SymbolEntRef)); W.printString("Section", SectionName); if (SymbolClass == XCOFF::C_FILE) { W.printEnum("Source Language ID", SymbolEntRef.getLanguageIdForCFile(), ArrayRef(CFileLangIdClass)); W.printEnum("CPU Version ID", SymbolEntRef.getCPUTypeIddForCFile(), ArrayRef(CFileCpuIdClass)); } else W.printHex("Type", SymbolEntRef.getSymbolType()); W.printEnum("StorageClass", static_cast(SymbolClass), ArrayRef(SymStorageClass)); W.printNumber("NumberOfAuxEntries", NumberOfAuxEntries); if (NumberOfAuxEntries == 0) return; auto checkNumOfAux = [=] { if (NumberOfAuxEntries > 1) reportUniqueWarning("the " + enumToString(static_cast(SymbolClass), ArrayRef(SymStorageClass)) + " symbol at index " + Twine(SymbolIdx) + " should not have more than 1 " "auxiliary entry"); }; switch (SymbolClass) { case XCOFF::C_FILE: // If the symbol is C_FILE and has auxiliary entries... for (int I = 1; I <= NumberOfAuxEntries; I++) { uintptr_t AuxAddress = XCOFFObjectFile::getAdvancedSymbolEntryAddress( SymbolEntRef.getEntryAddress(), I); if (Obj.is64Bit() && *Obj.getSymbolAuxType(AuxAddress) != XCOFF::SymbolAuxType::AUX_FILE) { printUnexpectedRawAuxEnt(W, AuxAddress); continue; } const XCOFFFileAuxEnt *FileAuxEntPtr = getAuxEntPtr(AuxAddress); printFileAuxEnt(FileAuxEntPtr); } break; case XCOFF::C_EXT: case XCOFF::C_WEAKEXT: case XCOFF::C_HIDEXT: { // For 32-bit objects, print the function auxiliary symbol table entry. The // last one must be a CSECT auxiliary entry. // For 64-bit objects, both a function auxiliary entry and an exception // auxiliary entry may appear, print them in the loop and skip printing the // CSECT auxiliary entry, which will be printed outside the loop. for (int I = 1; I <= NumberOfAuxEntries; I++) { if (I == NumberOfAuxEntries && !Obj.is64Bit()) break; uintptr_t AuxAddress = XCOFFObjectFile::getAdvancedSymbolEntryAddress( SymbolEntRef.getEntryAddress(), I); if (Obj.is64Bit()) { XCOFF::SymbolAuxType Type = *Obj.getSymbolAuxType(AuxAddress); if (Type == XCOFF::SymbolAuxType::AUX_CSECT) continue; if (Type == XCOFF::SymbolAuxType::AUX_FCN) { const XCOFFFunctionAuxEnt64 *AuxEntPtr = getAuxEntPtr(AuxAddress); printFunctionAuxEnt(AuxEntPtr); } else if (Type == XCOFF::SymbolAuxType::AUX_EXCEPT) { const XCOFFExceptionAuxEnt *AuxEntPtr = getAuxEntPtr(AuxAddress); printExceptionAuxEnt(AuxEntPtr); } else { printUnexpectedRawAuxEnt(W, AuxAddress); } } else { const XCOFFFunctionAuxEnt32 *AuxEntPtr = getAuxEntPtr(AuxAddress); printFunctionAuxEnt(AuxEntPtr); } } // Print the CSECT auxiliary entry. auto ErrOrCsectAuxRef = SymbolEntRef.getXCOFFCsectAuxRef(); if (!ErrOrCsectAuxRef) reportUniqueWarning(ErrOrCsectAuxRef.takeError()); else printCsectAuxEnt(*ErrOrCsectAuxRef); break; } case XCOFF::C_STAT: { checkNumOfAux(); const XCOFFSectAuxEntForStat *StatAuxEntPtr = getAuxEntPtr( XCOFFObjectFile::getAdvancedSymbolEntryAddress( SymbolEntRef.getEntryAddress(), 1)); printSectAuxEntForStat(StatAuxEntPtr); break; } case XCOFF::C_DWARF: { checkNumOfAux(); uintptr_t AuxAddress = XCOFFObjectFile::getAdvancedSymbolEntryAddress( SymbolEntRef.getEntryAddress(), 1); if (Obj.is64Bit()) { const XCOFFSectAuxEntForDWARF64 *AuxEntPtr = getAuxEntPtr(AuxAddress); printSectAuxEntForDWARF(AuxEntPtr); } else { const XCOFFSectAuxEntForDWARF32 *AuxEntPtr = getAuxEntPtr(AuxAddress); printSectAuxEntForDWARF(AuxEntPtr); } break; } case XCOFF::C_BLOCK: case XCOFF::C_FCN: { checkNumOfAux(); uintptr_t AuxAddress = XCOFFObjectFile::getAdvancedSymbolEntryAddress( SymbolEntRef.getEntryAddress(), 1); if (Obj.is64Bit()) { const XCOFFBlockAuxEnt64 *AuxEntPtr = getAuxEntPtr(AuxAddress); printBlockAuxEnt(AuxEntPtr); } else { const XCOFFBlockAuxEnt32 *AuxEntPtr = getAuxEntPtr(AuxAddress); printBlockAuxEnt(AuxEntPtr); } break; } default: for (int i = 1; i <= NumberOfAuxEntries; i++) { printUnexpectedRawAuxEnt(W, XCOFFObjectFile::getAdvancedSymbolEntryAddress( SymbolEntRef.getEntryAddress(), i)); } break; } } void XCOFFDumper::printSymbols(bool /*ExtraSymInfo*/) { ListScope Group(W, "Symbols"); for (const SymbolRef &S : Obj.symbols()) printSymbol(S); } void XCOFFDumper::printStringTable() { DictScope DS(W, "StringTable"); StringRef StrTable = Obj.getStringTable(); uint32_t StrTabSize = StrTable.size(); W.printNumber("Length", StrTabSize); // Print strings from the fifth byte, since the first four bytes contain the // length (in bytes) of the string table (including the length field). if (StrTabSize > 4) printAsStringList(StrTable, 4); } 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() { ListScope D(W, "NeededLibraries"); auto ImportFilesOrError = Obj.getImportFileTable(); if (!ImportFilesOrError) { reportUniqueWarning(ImportFilesOrError.takeError()); return; } StringRef ImportFileTable = ImportFilesOrError.get(); const char *CurrentStr = ImportFileTable.data(); const char *TableEnd = ImportFileTable.end(); // Default column width for names is 13 even if no names are that long. size_t BaseWidth = 13; // Get the max width of BASE columns. for (size_t StrIndex = 0; CurrentStr < TableEnd; ++StrIndex) { size_t CurrentLen = strlen(CurrentStr); CurrentStr += strlen(CurrentStr) + 1; if (StrIndex % 3 == 1) BaseWidth = std::max(BaseWidth, CurrentLen); } auto &OS = static_cast(W.startLine()); // Each entry consists of 3 strings: the path_name, base_name and // archive_member_name. The first entry is a default LIBPATH value and other // entries have no path_name. We just dump the base_name and // archive_member_name here. OS << left_justify("BASE", BaseWidth) << " MEMBER\n"; CurrentStr = ImportFileTable.data(); for (size_t StrIndex = 0; CurrentStr < TableEnd; ++StrIndex, CurrentStr += strlen(CurrentStr) + 1) { if (StrIndex >= 3 && StrIndex % 3 != 0) { if (StrIndex % 3 == 1) OS << " " << left_justify(CurrentStr, BaseWidth) << " "; else OS << CurrentStr << "\n"; } } } const EnumEntry 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 }; const EnumEntry DWARFSectionSubtypeFlagsNames[] = { #define ECase(X) \ { #X, XCOFF::X } ECase(SSUBTYP_DWINFO), ECase(SSUBTYP_DWLINE), ECase(SSUBTYP_DWPBNMS), ECase(SSUBTYP_DWPBTYP), ECase(SSUBTYP_DWARNGE), ECase(SSUBTYP_DWABREV), ECase(SSUBTYP_DWSTR), ECase(SSUBTYP_DWRNGES), ECase(SSUBTYP_DWLOC), ECase(SSUBTYP_DWFRAME), ECase(SSUBTYP_DWMAC) #undef ECase }; template void XCOFFDumper::printOverflowSectionHeader(T &Sec) const { if (Obj.is64Bit()) { reportWarning(make_error("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 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); } enum PrintStyle { Hex, Number }; template static void printAuxMemberHelper(PrintStyle Style, const char *MemberName, const T &Member, const V *AuxHeader, uint16_t AuxSize, uint16_t &PartialFieldOffset, const char *&PartialFieldName, ScopedPrinter &W) { ptrdiff_t Offset = reinterpret_cast(&Member) - reinterpret_cast(AuxHeader); if (Offset + sizeof(Member) <= AuxSize) Style == Hex ? W.printHex(MemberName, Member) : W.printNumber(MemberName, Member); else if (Offset < AuxSize) { PartialFieldOffset = Offset; PartialFieldName = MemberName; } } template void checkAndPrintAuxHeaderParseError(const char *PartialFieldName, uint16_t PartialFieldOffset, uint16_t AuxSize, T &AuxHeader, XCOFFDumper *Dumper) { if (PartialFieldOffset < AuxSize) { Dumper->reportUniqueWarning(Twine("only partial field for ") + PartialFieldName + " at offset (" + Twine(PartialFieldOffset) + ")"); Dumper->getScopedPrinter().printBinary( "Raw data", "", ArrayRef(reinterpret_cast(&AuxHeader) + PartialFieldOffset, AuxSize - PartialFieldOffset)); } else if (sizeof(AuxHeader) < AuxSize) Dumper->getScopedPrinter().printBinary( "Extra raw data", "", ArrayRef(reinterpret_cast(&AuxHeader) + sizeof(AuxHeader), AuxSize - sizeof(AuxHeader))); } void XCOFFDumper::printAuxiliaryHeader( const XCOFFAuxiliaryHeader32 *AuxHeader) { if (AuxHeader == nullptr) return; uint16_t AuxSize = Obj.getOptionalHeaderSize(); uint16_t PartialFieldOffset = AuxSize; const char *PartialFieldName = nullptr; auto PrintAuxMember = [&](PrintStyle Style, const char *MemberName, auto &Member) { printAuxMemberHelper(Style, MemberName, Member, AuxHeader, AuxSize, PartialFieldOffset, PartialFieldName, W); }; PrintAuxMember(Hex, "Magic", AuxHeader->AuxMagic); PrintAuxMember(Hex, "Version", AuxHeader->Version); PrintAuxMember(Hex, "Size of .text section", AuxHeader->TextSize); PrintAuxMember(Hex, "Size of .data section", AuxHeader->InitDataSize); PrintAuxMember(Hex, "Size of .bss section", AuxHeader->BssDataSize); PrintAuxMember(Hex, "Entry point address", AuxHeader->EntryPointAddr); PrintAuxMember(Hex, ".text section start address", AuxHeader->TextStartAddr); PrintAuxMember(Hex, ".data section start address", AuxHeader->DataStartAddr); PrintAuxMember(Hex, "TOC anchor address", AuxHeader->TOCAnchorAddr); PrintAuxMember(Number, "Section number of entryPoint", AuxHeader->SecNumOfEntryPoint); PrintAuxMember(Number, "Section number of .text", AuxHeader->SecNumOfText); PrintAuxMember(Number, "Section number of .data", AuxHeader->SecNumOfData); PrintAuxMember(Number, "Section number of TOC", AuxHeader->SecNumOfTOC); PrintAuxMember(Number, "Section number of loader data", AuxHeader->SecNumOfLoader); PrintAuxMember(Number, "Section number of .bss", AuxHeader->SecNumOfBSS); PrintAuxMember(Hex, "Maxium alignment of .text", AuxHeader->MaxAlignOfText); PrintAuxMember(Hex, "Maxium alignment of .data", AuxHeader->MaxAlignOfData); PrintAuxMember(Hex, "Module type", AuxHeader->ModuleType); PrintAuxMember(Hex, "CPU type of objects", AuxHeader->CpuFlag); PrintAuxMember(Hex, "(Reserved)", AuxHeader->CpuType); PrintAuxMember(Hex, "Maximum stack size", AuxHeader->MaxStackSize); PrintAuxMember(Hex, "Maximum data size", AuxHeader->MaxDataSize); PrintAuxMember(Hex, "Reserved for debugger", AuxHeader->ReservedForDebugger); PrintAuxMember(Hex, "Text page size", AuxHeader->TextPageSize); PrintAuxMember(Hex, "Data page size", AuxHeader->DataPageSize); PrintAuxMember(Hex, "Stack page size", AuxHeader->StackPageSize); if (offsetof(XCOFFAuxiliaryHeader32, FlagAndTDataAlignment) + sizeof(XCOFFAuxiliaryHeader32::FlagAndTDataAlignment) <= AuxSize) { W.printHex("Flag", AuxHeader->getFlag()); W.printHex("Alignment of thread-local storage", AuxHeader->getTDataAlignment()); } PrintAuxMember(Number, "Section number for .tdata", AuxHeader->SecNumOfTData); PrintAuxMember(Number, "Section number for .tbss", AuxHeader->SecNumOfTBSS); checkAndPrintAuxHeaderParseError(PartialFieldName, PartialFieldOffset, AuxSize, *AuxHeader, this); } void XCOFFDumper::printAuxiliaryHeader( const XCOFFAuxiliaryHeader64 *AuxHeader) { if (AuxHeader == nullptr) return; uint16_t AuxSize = Obj.getOptionalHeaderSize(); uint16_t PartialFieldOffset = AuxSize; const char *PartialFieldName = nullptr; auto PrintAuxMember = [&](PrintStyle Style, const char *MemberName, auto &Member) { printAuxMemberHelper(Style, MemberName, Member, AuxHeader, AuxSize, PartialFieldOffset, PartialFieldName, W); }; PrintAuxMember(Hex, "Magic", AuxHeader->AuxMagic); PrintAuxMember(Hex, "Version", AuxHeader->Version); PrintAuxMember(Hex, "Reserved for debugger", AuxHeader->ReservedForDebugger); PrintAuxMember(Hex, ".text section start address", AuxHeader->TextStartAddr); PrintAuxMember(Hex, ".data section start address", AuxHeader->DataStartAddr); PrintAuxMember(Hex, "TOC anchor address", AuxHeader->TOCAnchorAddr); PrintAuxMember(Number, "Section number of entryPoint", AuxHeader->SecNumOfEntryPoint); PrintAuxMember(Number, "Section number of .text", AuxHeader->SecNumOfText); PrintAuxMember(Number, "Section number of .data", AuxHeader->SecNumOfData); PrintAuxMember(Number, "Section number of TOC", AuxHeader->SecNumOfTOC); PrintAuxMember(Number, "Section number of loader data", AuxHeader->SecNumOfLoader); PrintAuxMember(Number, "Section number of .bss", AuxHeader->SecNumOfBSS); PrintAuxMember(Hex, "Maxium alignment of .text", AuxHeader->MaxAlignOfText); PrintAuxMember(Hex, "Maxium alignment of .data", AuxHeader->MaxAlignOfData); PrintAuxMember(Hex, "Module type", AuxHeader->ModuleType); PrintAuxMember(Hex, "CPU type of objects", AuxHeader->CpuFlag); PrintAuxMember(Hex, "(Reserved)", AuxHeader->CpuType); PrintAuxMember(Hex, "Text page size", AuxHeader->TextPageSize); PrintAuxMember(Hex, "Data page size", AuxHeader->DataPageSize); PrintAuxMember(Hex, "Stack page size", AuxHeader->StackPageSize); if (offsetof(XCOFFAuxiliaryHeader64, FlagAndTDataAlignment) + sizeof(XCOFFAuxiliaryHeader64::FlagAndTDataAlignment) <= AuxSize) { W.printHex("Flag", AuxHeader->getFlag()); W.printHex("Alignment of thread-local storage", AuxHeader->getTDataAlignment()); } PrintAuxMember(Hex, "Size of .text section", AuxHeader->TextSize); PrintAuxMember(Hex, "Size of .data section", AuxHeader->InitDataSize); PrintAuxMember(Hex, "Size of .bss section", AuxHeader->BssDataSize); PrintAuxMember(Hex, "Entry point address", AuxHeader->EntryPointAddr); PrintAuxMember(Hex, "Maximum stack size", AuxHeader->MaxStackSize); PrintAuxMember(Hex, "Maximum data size", AuxHeader->MaxDataSize); PrintAuxMember(Number, "Section number for .tdata", AuxHeader->SecNumOfTData); PrintAuxMember(Number, "Section number for .tbss", AuxHeader->SecNumOfTBSS); PrintAuxMember(Hex, "Additional flags 64-bit XCOFF", AuxHeader->XCOFF64Flag); checkAndPrintAuxHeaderParseError(PartialFieldName, PartialFieldOffset, AuxSize, *AuxHeader, this); } template void XCOFFDumper::printSectionHeaders(ArrayRef 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.getSectionType(); int32_t SectionSubtype = Sec.getSectionSubtype(); 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; } if (Sec.isReservedSectionType()) W.printHex("Flags", "Reserved", SectionType); else { W.printEnum("Type", SectionType, ArrayRef(SectionTypeFlagsNames)); if (SectionType == XCOFF::STYP_DWARF) { W.printEnum("DWARFSubType", SectionSubtype, ArrayRef(DWARFSectionSubtypeFlagsNames)); } } } 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::unique_ptr createXCOFFDumper(const object::XCOFFObjectFile &XObj, ScopedPrinter &Writer) { return std::make_unique(XObj, Writer); } } // namespace llvm