mirror of
https://github.com/llvm/llvm-project.git
synced 2025-05-07 21:26:05 +00:00

Summary: llvm-readobj decide whether to decode the external symbol's function auxiliary entry based on whether symbol is function or not currently. But the XCOFFSymbolRef::isFunction() do not work properly when -ffunction-sections is enabled. we will not decode the function auxiliary entry based on the XCOFFSymbolRef::isFunction() we will decode the function auxiliary entry based on following: According to the https://www.ibm.com/docs/en/aix/7.2?topic=formats-xcoff-object-file-format#XCOFF__c0f91ad419jbau In XCOFF32, there are only "one csect Auxiliary Entry" and "a function auxiliary symbol table entry" for the C_EXT, C_WEAKEXT, and C_HIDEXT Symbols. and By convention, the csect auxiliary entry in an XCOFF32 file must be the last auxiliary entry for any external symbol that has more than one auxiliary entry( that means for the C_EXT, C_WEAKEXT, and C_HIDEXT Symbols. if there more than one auxiliary Entries. we look the last one as csect auxiliary entry. and others auxiliary entries as function entries). Reviewers: Hubert Tong, James Henderson Differential Revision: https://reviews.llvm.org/D136950
1031 lines
40 KiB
C++
1031 lines
40 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;
|
|
void printExceptionSection() override;
|
|
void printLoaderSection(bool PrintHeader) 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>
|
|
void printExceptionSectionEntry(const T &ExceptionSectEnt) const;
|
|
template <typename T> void printExceptionSectionEntries() 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);
|
|
void printLoaderSectionHeader(uintptr_t LoaderSectAddr);
|
|
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::printLoaderSection(bool PrintHeader) {
|
|
DictScope DS(W, "Loader Section");
|
|
Expected<uintptr_t> LoaderSectionAddrOrError =
|
|
Obj.getSectionFileOffsetToRawData(XCOFF::STYP_LOADER);
|
|
if (!LoaderSectionAddrOrError) {
|
|
reportUniqueWarning(LoaderSectionAddrOrError.takeError());
|
|
return;
|
|
}
|
|
uintptr_t LoaderSectionAddr = LoaderSectionAddrOrError.get();
|
|
|
|
W.indent();
|
|
if (PrintHeader)
|
|
printLoaderSectionHeader(LoaderSectionAddr);
|
|
// TODO: Need to print symbol table, relocation entry of loader section later.
|
|
// For example:
|
|
// if (PrintSymbolTable)
|
|
// printLoaderSectionSymbolTable();
|
|
// if (PrintRelocation)
|
|
// printLoaderSectionRelocationEntry();
|
|
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<const LoaderSectionHeader64 *>(LoaderSectionAddr);
|
|
PrintLoadSecHeaderCommon(LoaderSec64);
|
|
W.printHex("OffsetToSymbolTable", LoaderSec64->OffsetToSymTbl);
|
|
W.printHex("OffsetToRelocationEntries", LoaderSec64->OffsetToRelEnt);
|
|
} else {
|
|
const LoaderSectionHeader32 *LoaderSec32 =
|
|
reinterpret_cast<const LoaderSectionHeader32 *>(LoaderSectionAddr);
|
|
PrintLoadSecHeaderCommon(LoaderSec32);
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
void XCOFFDumper::printExceptionSectionEntry(const T &ExceptionSectEnt) const {
|
|
if (ExceptionSectEnt.getReason())
|
|
W.printHex("Trap Instr Addr", ExceptionSectEnt.getTrapInstAddr());
|
|
else {
|
|
uint32_t SymIdx = ExceptionSectEnt.getSymbolIndex();
|
|
Expected<StringRef> 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 <typename T> void XCOFFDumper::printExceptionSectionEntries() const {
|
|
Expected<ArrayRef<T>> ExceptSectEntsOrErr = Obj.getExceptionEntries<T>();
|
|
if (Error E = ExceptSectEntsOrErr.takeError()) {
|
|
reportUniqueWarning(std::move(E));
|
|
return;
|
|
}
|
|
ArrayRef<T> ExceptSectEnts = *ExceptSectEntsOrErr;
|
|
|
|
DictScope DS(W, "Exception section");
|
|
if (ExceptSectEnts.empty())
|
|
return;
|
|
for (auto &Ent : ExceptSectEnts)
|
|
printExceptionSectionEntry(Ent);
|
|
}
|
|
|
|
void XCOFFDumper::printExceptionSection() {
|
|
if (Obj.is64Bit())
|
|
printExceptionSectionEntries<ExceptionSectionEntry64>();
|
|
else
|
|
printExceptionSectionEntries<ExceptionSectionEntry32>();
|
|
}
|
|
|
|
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: {
|
|
// 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<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
|