943 lines
		
	
	
		
			37 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			943 lines
		
	
	
		
			37 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===-- 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/Object/XCOFFObjectFile.h"
 | |
| #include "llvm/Support/FormattedStream.h"
 | |
| #include "llvm/Support/ScopedPrinter.h"
 | |
| 
 | |
| #include <ctime>
 | |
| 
 | |
| 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() override;
 | |
|   void printDynamicSymbols() override;
 | |
|   void printUnwindInfo() override;
 | |
|   void printStackMap() const override;
 | |
|   void printNeededLibraries() override;
 | |
|   void printStringTable() override;
 | |
| 
 | |
|   ScopedPrinter &getScopedPrinter() const { return W; }
 | |
| 
 | |
| 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;
 | |
|   template <typename T> 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 <typename T> void printSectAuxEntForDWARF(const T *AuxEntPtr);
 | |
|   void printSymbol(const SymbolRef &);
 | |
|   template <typename RelTy> void printRelocation(RelTy Reloc);
 | |
|   template <typename Shdr, typename RelTy>
 | |
|   void printRelocations(ArrayRef<Shdr> Sections);
 | |
|   void printAuxiliaryHeader(const XCOFFAuxiliaryHeader32 *AuxHeader);
 | |
|   void printAuxiliaryHeader(const XCOFFAuxiliaryHeader64 *AuxHeader);
 | |
|   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::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::printRelocations() {
 | |
|   if (Obj.is64Bit())
 | |
|     printRelocations<XCOFFSectionHeader64, XCOFFRelocation64>(Obj.sections64());
 | |
|   else
 | |
|     printRelocations<XCOFFSectionHeader32, XCOFFRelocation32>(Obj.sections32());
 | |
| }
 | |
| 
 | |
| 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
 | |
| };
 | |
| 
 | |
| template <typename RelTy> void XCOFFDumper::printRelocation(RelTy Reloc) {
 | |
|   Expected<StringRef> 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", 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));
 | |
|   } else {
 | |
|     raw_ostream &OS = W.startLine();
 | |
|     OS << W.hex(Reloc.VirtualAddress) << " " << RelocName << " " << SymbolName
 | |
|        << "(" << Reloc.SymbolIndex << ") " << W.hex(Reloc.Info) << "\n";
 | |
|   }
 | |
| }
 | |
| 
 | |
| template <typename Shdr, typename RelTy>
 | |
| void XCOFFDumper::printRelocations(ArrayRef<Shdr> 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<ArrayRef<RelTy>> ErrOrRelocations = Obj.relocations<Shdr, RelTy>(Sec);
 | |
|     if (Error E = ErrOrRelocations.takeError()) {
 | |
|       reportUniqueWarning(std::move(E));
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     const ArrayRef<RelTy> 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<XCOFF::CFileStringType> FileStringType[] = {
 | |
| #define ECase(X)                                                               \
 | |
|   { #X, XCOFF::X }
 | |
|     ECase(XFT_FN), ECase(XFT_CT), ECase(XFT_CV), ECase(XFT_CD)
 | |
| #undef ECase
 | |
| };
 | |
| 
 | |
| const EnumEntry<XCOFF::SymbolAuxType> 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<uintptr_t>(AuxEntPtr)));
 | |
|   W.printString("Name", FileName);
 | |
|   W.printEnum("Type", static_cast<uint8_t>(AuxEntPtr->Type),
 | |
|               makeArrayRef(FileStringType));
 | |
|   if (Obj.is64Bit()) {
 | |
|     W.printEnum("Auxiliary Type", static_cast<uint8_t>(AuxEntPtr->AuxType),
 | |
|                 makeArrayRef(SymAuxType));
 | |
|   }
 | |
| }
 | |
| 
 | |
| 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_UL),
 | |
|         ECase(XMC_TE)
 | |
| #undef ECase
 | |
| };
 | |
| 
 | |
| 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::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(),
 | |
|               makeArrayRef(CsectSymbolTypeClass));
 | |
|   W.printEnum("StorageMappingClass",
 | |
|               static_cast<uint8_t>(AuxEntRef.getStorageMappingClass()),
 | |
|               makeArrayRef(CsectStorageMappingClass));
 | |
| 
 | |
|   if (Obj.is64Bit()) {
 | |
|     W.printEnum("Auxiliary Type", static_cast<uint8_t>(XCOFF::AUX_CSECT),
 | |
|                 makeArrayRef(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<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);
 | |
| }
 | |
| 
 | |
| 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<uintptr_t>(AuxEntPtr)));
 | |
|   W.printHex("OffsetToExceptionTable", AuxEntPtr->OffsetToExceptionTbl);
 | |
|   W.printHex("SizeOfFunction", AuxEntPtr->SizeOfFunction);
 | |
|   W.printNumber("SymbolIndexOfNextBeyond", AuxEntPtr->SymIdxOfNextBeyond);
 | |
|   W.printEnum("Auxiliary Type", static_cast<uint8_t>(AuxEntPtr->AuxType),
 | |
|               makeArrayRef(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<uintptr_t>(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<uintptr_t>(AuxEntPtr)));
 | |
|   W.printHex("SizeOfFunction", AuxEntPtr->SizeOfFunction);
 | |
|   W.printHex("PointerToLineNum", AuxEntPtr->PtrToLineNum);
 | |
|   W.printNumber("SymbolIndexOfNextBeyond", AuxEntPtr->SymIdxOfNextBeyond);
 | |
|   W.printEnum("Auxiliary Type", static_cast<uint8_t>(AuxEntPtr->AuxType),
 | |
|               makeArrayRef(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<uintptr_t>(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<uintptr_t>(AuxEntPtr)));
 | |
|   W.printHex("LineNumber", AuxEntPtr->LineNum);
 | |
|   W.printEnum("Auxiliary Type", static_cast<uint8_t>(AuxEntPtr->AuxType),
 | |
|               makeArrayRef(SymAuxType));
 | |
| }
 | |
| 
 | |
| template <typename T>
 | |
| void XCOFFDumper::printSectAuxEntForDWARF(const T *AuxEntPtr) {
 | |
|   DictScope SymDs(W, "Sect Auxiliary Entry For DWARF");
 | |
|   W.printNumber("Index",
 | |
|                 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr)));
 | |
|   W.printHex("LengthOfSectionPortion", AuxEntPtr->LengthOfSectionPortion);
 | |
|   W.printNumber("NumberOfRelocEntries", AuxEntPtr->NumberOfRelocEnt);
 | |
|   if (Obj.is64Bit())
 | |
|     W.printEnum("Auxiliary Type", static_cast<uint8_t>(XCOFF::AUX_SECT),
 | |
|                 makeArrayRef(SymAuxType));
 | |
| }
 | |
| 
 | |
| 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:
 | |
|   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<XCOFF::CFileLangId> CFileLangIdClass[] = {
 | |
| #define ECase(X)                                                               \
 | |
|   { #X, XCOFF::X }
 | |
|     ECase(TB_C), ECase(TB_CPLUSPLUS)
 | |
| #undef ECase
 | |
| };
 | |
| 
 | |
| const EnumEntry<XCOFF::CFileCpuId> CFileCpuIdClass[] = {
 | |
| #define ECase(X)                                                               \
 | |
|   { #X, XCOFF::X }
 | |
|     ECase(TCPU_PPC64), ECase(TCPU_COM), ECase(TCPU_970)
 | |
| #undef ECase
 | |
| };
 | |
| 
 | |
| template <typename T> const T *XCOFFDumper::getAuxEntPtr(uintptr_t AuxAddress) {
 | |
|   const T *AuxEntPtr = reinterpret_cast<const T *>(AuxAddress);
 | |
|   Obj.checkSymbolEntryPointer(reinterpret_cast<uintptr_t>(AuxEntPtr));
 | |
|   return AuxEntPtr;
 | |
| }
 | |
| 
 | |
| static void printUnexpectedRawAuxEnt(ScopedPrinter &W, uintptr_t AuxAddress) {
 | |
|   W.startLine() << "!Unexpected raw auxiliary entry data:\n";
 | |
|   W.startLine() << format_bytes(
 | |
|                        ArrayRef<uint8_t>(
 | |
|                            reinterpret_cast<const uint8_t *>(AuxAddress),
 | |
|                            XCOFF::SymbolTableEntrySize),
 | |
|                        None, 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", 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(),
 | |
|                 makeArrayRef(CFileLangIdClass));
 | |
|     W.printEnum("CPU Version ID", SymbolEntRef.getCPUTypeIddForCFile(),
 | |
|                 makeArrayRef(CFileCpuIdClass));
 | |
|   } else
 | |
|     W.printHex("Type", SymbolEntRef.getSymbolType());
 | |
| 
 | |
|   W.printEnum("StorageClass", static_cast<uint8_t>(SymbolClass),
 | |
|               makeArrayRef(SymStorageClass));
 | |
|   W.printNumber("NumberOfAuxEntries", NumberOfAuxEntries);
 | |
| 
 | |
|   if (NumberOfAuxEntries == 0)
 | |
|     return;
 | |
| 
 | |
|   auto checkNumOfAux = [=] {
 | |
|     if (NumberOfAuxEntries > 1)
 | |
|       reportUniqueWarning("the " +
 | |
|                           enumToString(static_cast<uint8_t>(SymbolClass),
 | |
|                                        makeArrayRef(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<XCOFFFileAuxEnt>(AuxAddress);
 | |
|       printFileAuxEnt(FileAuxEntPtr);
 | |
|     }
 | |
|     break;
 | |
|   case XCOFF::C_EXT:
 | |
|   case XCOFF::C_WEAKEXT:
 | |
|   case XCOFF::C_HIDEXT: {
 | |
|     if (!SymbolEntRef.isFunction() && NumberOfAuxEntries > 1)
 | |
|       reportUniqueWarning("the non-function " +
 | |
|                           enumToString(static_cast<uint8_t>(SymbolClass),
 | |
|                                        makeArrayRef(SymStorageClass)) +
 | |
|                           " symbol at index " + Twine(SymbolIdx) +
 | |
|                           " should have only 1 auxiliary entry, i.e. the CSECT "
 | |
|                           "auxiliary entry");
 | |
| 
 | |
|     // 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()) ||
 | |
|           !SymbolEntRef.isFunction())
 | |
|         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<XCOFFFunctionAuxEnt64>(AuxAddress);
 | |
|           printFunctionAuxEnt(AuxEntPtr);
 | |
|         } else if (Type == XCOFF::SymbolAuxType::AUX_EXCEPT) {
 | |
|           const XCOFFExceptionAuxEnt *AuxEntPtr =
 | |
|               getAuxEntPtr<XCOFFExceptionAuxEnt>(AuxAddress);
 | |
|           printExceptionAuxEnt(AuxEntPtr);
 | |
|         } else {
 | |
|           printUnexpectedRawAuxEnt(W, AuxAddress);
 | |
|         }
 | |
|       } else {
 | |
|         const XCOFFFunctionAuxEnt32 *AuxEntPtr =
 | |
|             getAuxEntPtr<XCOFFFunctionAuxEnt32>(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<XCOFFSectAuxEntForStat>(
 | |
|             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<XCOFFSectAuxEntForDWARF64>(AuxAddress);
 | |
|       printSectAuxEntForDWARF<XCOFFSectAuxEntForDWARF64>(AuxEntPtr);
 | |
|     } else {
 | |
|       const XCOFFSectAuxEntForDWARF32 *AuxEntPtr =
 | |
|           getAuxEntPtr<XCOFFSectAuxEntForDWARF32>(AuxAddress);
 | |
|       printSectAuxEntForDWARF<XCOFFSectAuxEntForDWARF32>(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<XCOFFBlockAuxEnt64>(AuxAddress);
 | |
|       printBlockAuxEnt(AuxEntPtr);
 | |
|     } else {
 | |
|       const XCOFFBlockAuxEnt32 *AuxEntPtr =
 | |
|           getAuxEntPtr<XCOFFBlockAuxEnt32>(AuxAddress);
 | |
|       printBlockAuxEnt(AuxEntPtr);
 | |
|     }
 | |
|     break;
 | |
|   }
 | |
|   default:
 | |
|     for (int i = 1; i <= NumberOfAuxEntries; i++) {
 | |
|       printUnexpectedRawAuxEnt(W,
 | |
|                                XCOFFObjectFile::getAdvancedSymbolEntryAddress(
 | |
|                                    SymbolEntRef.getEntryAddress(), i));
 | |
|     }
 | |
|     break;
 | |
|   }
 | |
| }
 | |
| 
 | |
| void XCOFFDumper::printSymbols() {
 | |
|   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<formatted_raw_ostream &>(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<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);
 | |
| }
 | |
| 
 | |
| enum PrintStyle { Hex, Number };
 | |
| template <typename T, typename V>
 | |
| 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<const char *>(&Member) -
 | |
|                      reinterpret_cast<const char *>(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 <class T>
 | |
| 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<uint8_t>(reinterpret_cast<const uint8_t *>(&AuxHeader) +
 | |
|                               PartialFieldOffset,
 | |
|                           AuxSize - PartialFieldOffset));
 | |
|   } else if (sizeof(AuxHeader) < AuxSize)
 | |
|     Dumper->getScopedPrinter().printBinary(
 | |
|         "Extra raw data", "",
 | |
|         ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(&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 <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.getSectionType();
 | |
|     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, 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::unique_ptr<ObjDumper>
 | |
| createXCOFFDumper(const object::XCOFFObjectFile &XObj, ScopedPrinter &Writer) {
 | |
|   return std::make_unique<XCOFFDumper>(XObj, Writer);
 | |
| }
 | |
| } // namespace llvm
 |