[XCOFF] llvm-readobj support display symbol table of loader section of xcoff object file.

Reviewers: James Henderson, Esme Yi

Differential Revision: https://reviews.llvm.org/D135887
This commit is contained in:
zhijian 2022-11-21 10:11:12 -05:00
parent c7a53421cd
commit a56d0e84da
9 changed files with 319 additions and 27 deletions

View File

@ -338,6 +338,10 @@ The following options are implemented only for the XCOFF file format.
Display XCOFF loader section header.
.. option:: --loader-section-symbols
Display symbol table of loader section.
EXIT STATUS
-----------

View File

@ -204,6 +204,10 @@ struct LoaderSectionHeader32 {
support::big32_t OffsetToImpid;
support::ubig32_t LengthOfStrTbl;
support::big32_t OffsetToStrTbl;
uint64_t getOffsetToSymTbl() const {
return NumberOfSymTabEnt == 0 ? 0 : sizeof(LoaderSectionHeader32);
}
};
struct LoaderSectionHeader64 {
@ -217,6 +221,39 @@ struct LoaderSectionHeader64 {
support::big64_t OffsetToStrTbl;
support::big64_t OffsetToSymTbl;
support::big64_t OffsetToRelEnt;
uint64_t getOffsetToSymTbl() const { return OffsetToSymTbl; }
};
struct LoaderSectionSymbolEntry32 {
struct NameOffsetInStrTbl {
support::big32_t IsNameInStrTbl; // Zero indicates name in string table.
support::ubig32_t Offset;
};
char SymbolName[XCOFF::NameSize];
support::ubig32_t Value; // The virtual address of the symbol.
support::big16_t SectionNumber;
uint8_t SymbolType;
XCOFF::StorageClass StorageClass;
support::ubig32_t ImportFileID;
support::ubig32_t ParameterTypeCheck;
Expected<StringRef>
getSymbolName(const LoaderSectionHeader32 *LoaderSecHeader) const;
};
struct LoaderSectionSymbolEntry64 {
support::ubig64_t Value; // The virtual address of the symbol.
support::ubig32_t Offset;
support::big16_t SectionNumber;
uint8_t SymbolType;
XCOFF::StorageClass StorageClass;
support::ubig32_t ImportFileID;
support::ubig32_t ParameterTypeCheck;
Expected<StringRef>
getSymbolName(const LoaderSectionHeader64 *LoaderSecHeader) const;
};
template <typename AddressType> struct ExceptionSectionEntry {

View File

@ -89,6 +89,34 @@ uint8_t XCOFFRelocation<AddressType>::getRelocatedLength() const {
template struct ExceptionSectionEntry<support::ubig32_t>;
template struct ExceptionSectionEntry<support::ubig64_t>;
template <typename T>
Expected<StringRef> getLoaderSecSymNameInStrTbl(const T *LoaderSecHeader,
uint64_t Offset) {
if (LoaderSecHeader->LengthOfStrTbl > Offset)
return (reinterpret_cast<const char *>(LoaderSecHeader) +
LoaderSecHeader->OffsetToStrTbl + Offset);
return createError("entry with offset 0x" + Twine::utohexstr(Offset) +
" in the loader section's string table with size 0x" +
Twine::utohexstr(LoaderSecHeader->LengthOfStrTbl) +
" is invalid");
}
Expected<StringRef> LoaderSectionSymbolEntry32::getSymbolName(
const LoaderSectionHeader32 *LoaderSecHeader32) const {
const NameOffsetInStrTbl *NameInStrTbl =
reinterpret_cast<const NameOffsetInStrTbl *>(SymbolName);
if (NameInStrTbl->IsNameInStrTbl != XCOFFSymbolRef::NAME_IN_STR_TBL_MAGIC)
return generateXCOFFFixedNameStringRef(SymbolName);
return getLoaderSecSymNameInStrTbl(LoaderSecHeader32, NameInStrTbl->Offset);
}
Expected<StringRef> LoaderSectionSymbolEntry64::getSymbolName(
const LoaderSectionHeader64 *LoaderSecHeader64) const {
return getLoaderSecSymNameInStrTbl(LoaderSecHeader64, Offset);
}
uintptr_t
XCOFFObjectFile::getAdvancedSymbolEntryAddress(uintptr_t CurrentAddress,
uint32_t Distance) {

View File

@ -0,0 +1,38 @@
## Test invalid offset to symbol string table of loader section for --loader-section-symbols option.
# RUN: yaml2obj %s -o %t_xcoff.o
# RUN: llvm-readobj --loader-section-symbols %t_xcoff.o 2>&1 | FileCheck -DFILE=%t_xcoff.o %s
--- !XCOFF
FileHeader:
MagicNumber: 0x1DF
Sections:
- Name: .loader
Flags: [ STYP_LOADER ]
SectionData: "0000000100000002000000050000016D00000001000000A40000000c000000506d79696e747661722000028000021105000000000000000000000000000000A2200002840002110a0000000000000000000a66756e63305f5f467600"
## ^------- -Version=1
## ^------- -NumberOfSymbolEntries=2
## ^------- -NumberOfRelocationEntries=5
## ^------- -LengthOfImportFileIDStringTable=365
## ^------- -NumberOfImportFileIDs=1
## ^------- -OffsetToImportFileIDs=0xA4
## ^------- -LengthOfStringTable=12
## ^------- -OffsetToStringTable=0x050
## ^--------------- SymbolName=myintvar
## ^------- Value=0x20000280
## ^--- sectionNumber = 2
## ^- SymbolType=0x11
## ^- StorageClass=0x0a
## ^------- ImportFileID=0
## ^-------ParameterCheckType=0
## ^-------SymbolZero=0
## ^-------OffsetToStringTbl=0xA2 (Invalid)
## ^------- Value=20000284
## ^--- sectionNumber = 2
## ^- SymbolType=0x11
## ^- StorageClass=0x0a
## ^------- ImportFileID=0
## ^-------ParameterCheckType=0
## ^StringTable
# CHECK: warning: '[[FILE]]': entry with offset 0xa2 in the loader section's string table with size 0xc is invalid

View File

@ -0,0 +1,124 @@
## Test the --loader-section-symbols option.
# RUN: yaml2obj --docnum=1 -DSYMNUM=2 %s -o %t_xcoff32.o
# RUN: yaml2obj --docnum=1 -DSYMNUM=4 %s -o %t_xcoff32_invalid.o
# RUN: yaml2obj --docnum=2 %s -o %t_xcoff64.o
# RUN: llvm-readobj --loader-section-symbols %t_xcoff32.o |\
# RUN: FileCheck %s --check-prefixes=CHECK32
# RUN: llvm-readobj --loader-section-symbols %t_xcoff32_invalid.o 2>&1 |\
# RUN: FileCheck -DFILE=%t_xcoff32_invalid.o %s --check-prefixes=CHECK32,WARN
# RUN: llvm-readobj --loader-section-symbols %t_xcoff64.o |\
# RUN: FileCheck %s --check-prefixes=CHECK64
--- !XCOFF
FileHeader:
MagicNumber: 0x1DF
Sections:
- Name: .loader
Flags: [ STYP_LOADER ]
SectionData: "000000010000000[[SYMNUM]]000000050000016D00000001000000A40000000c000000506d79696e74766172200002800002110500000000000000000000000000000002200002840002110a0000000000000000000a66756e63305f5f467600"
## ^------- -Version=1
## ^---------------- -NumberOfSymbolEntries=SYMNUM
## ^------- -NumberOfRelocationEntries=5
## ^------- -LengthOfImportFileIDStringTable=365
## ^------- -NumberOfImportFileIDs=1
## ^------- -OffsetToImportFileIDs=0xA4
## ^------- -LengthOfStringTable=12
## ^------- -OffsetToStringTable=0x050
## ^--------------- SymbolName=myintvar
## ^------- Value=0x20000280
## ^--- sectionNumber = 2
## ^- SymbolType=0x11
## ^- StorageClass=0x05
## ^------- ImportFileID=0
## ^-------ParameterCheckType=0
## ^-------SymbolZero=0
## ^-------OffsetToSymTbl=2
## ^------- Value=20000284
## ^--- sectionNumber = 2
## ^- SymbolType=0x11
## ^- StorageClass=0x0a
## ^------- ImportFileID=0
## ^-------ParameterCheckType=0
## ^StringTable
--- !XCOFF
FileHeader:
MagicNumber: 0x1F7
Sections:
- Name: .loader
Flags: [ STYP_LOADER ]
SectionData: "0000000200000002000000050000016D000000010000001200000000000000D000000000000000680000000000000038000000000000008000000001100003000000000200021105000000000000000000000001100003080000000d0002110a000000000000000000096d79696e7476617200000a5f5a3566756e6330760000"
## ^------- -Version=2
## ^------- -NumberOfSymbolEntries=2
## ^------- -NumberOfRelocationEntries=5
## ^------- -LengthOfImportFileIDStringTable=365
## ^------- -NumberOfImportFileIDs=1
## ^------- --LengthOfStringTable=0x12
## ^--------------- -OffsetToImportFileIDs=0xD0
## ^--------------- -OffsetToStringTable=0x68
## ^--------------- -OffsetToSymbolTable=0x38
## ^--------------- -OffsetToRelocationEntries=0x80
## ^--------------- Value=0x0000000110000300
## ^------- OffsetToStringTbl=2
## ^--- sectionNumber = 2
## ^- SymbolType=0x11
## ^- StorageClass=0x05
## ^------- ImportFileID=0
## ^-------ParameterCheckType=0
## ^--------------- Value=0x0000000110000308
## ^------- OffsetToStringTbl= 0x0d
## ^--- sectionNumber = 2
## ^- SymbolType=0x11
## ^- StorageClass=0x0a
## ^------- ImportFileID=0
## ^-------ParameterCheckType=0
## ^StringTable
# CHECK32: Loader Section {
# CHECK32-NEXT: Loader Section Symbols {
# CHECK32-NEXT: Symbol {
# CHECK32-NEXT: Name: myintvar
# CHECK32-NEXT: Virtual Address: 0x20000280
# CHECK32-NEXT: SectionNum: 2
# CHECK32-NEXT: SymbolType: 0x11
# CHECK32-NEXT: StorageClass: C_EXTDEF (0x5)
# CHECK32-NEXT: ImportFileID: 0x0
# CHECK32-NEXT: ParameterTypeCheck: 0
# CHECK32-NEXT: }
# CHECK32-NEXT: Symbol {
# CHECK32-NEXT: Name: func0__Fv
# CHECK32-NEXT: Virtual Address: 0x20000284
# CHECK32-NEXT: SectionNum: 2
# CHECK32-NEXT: SymbolType: 0x11
# CHECK32-NEXT: StorageClass: C_STRTAG (0xA)
# CHECK32-NEXT: ImportFileID: 0x0
# CHECK32-NEXT: ParameterTypeCheck: 0
# CHECK32-NEXT: }
# WARN: warning: '[[FILE]]': The end of the file was unexpectedly encountered
# CHECK32-NEXT: }
# CHECK32-NEXT: }
# CHECK64: Loader Section {
# CHECK64-NEXT: Loader Section Symbols {
# CHECK64-NEXT: Symbol {
# CHECK64-NEXT: Name: myintvar
# CHECK64-NEXT: Virtual Address: 0x110000300
# CHECK64-NEXT: SectionNum: 2
# CHECK64-NEXT: SymbolType: 0x11
# CHECK64-NEXT: StorageClass: C_EXTDEF (0x5)
# CHECK64-NEXT: ImportFileID: 0x0
# CHECK64-NEXT: ParameterTypeCheck: 0
# CHECK64-NEXT: }
# CHECK64-NEXT: Symbol {
# CHECK64-NEXT: Name: _Z5func0v
# CHECK64-NEXT: Virtual Address: 0x110000308
# CHECK64-NEXT: SectionNum: 2
# CHECK64-NEXT: SymbolType: 0x11
# CHECK64-NEXT: StorageClass: C_STRTAG (0xA)
# CHECK64-NEXT: ImportFileID: 0x0
# CHECK64-NEXT: ParameterTypeCheck: 0
# CHECK64-NEXT: }
# CHECK64-NEXT: }
# CHECK64-NEXT: }

View File

@ -158,7 +158,7 @@ public:
// Only implement for XCOFF
virtual void printAuxiliaryHeader() {}
virtual void printExceptionSection() {}
virtual void printLoaderSection(bool PrintHeader) {}
virtual void printLoaderSection(bool PrintHeader, bool PrintSymbolTable) {}
// Only implemented for MachO.
virtual void printMachODataInCode() { }

View File

@ -90,6 +90,7 @@ def grp_xcoff : OptionGroup<"kind">, HelpText<"OPTIONS (XCOFF specific)">;
def auxiliary_header : FF<"auxiliary-header" , "Display the auxiliary header">, Group<grp_xcoff>;
def exception_section : FF<"exception-section" , "Display the exception section entries">, Group<grp_xcoff>;
def loader_section_header : FF<"loader-section-header" , "Display the loader section header">, Group<grp_xcoff>;
def loader_section_symbols : FF<"loader-section-symbols" , "Display the loader section symbol table">, Group<grp_xcoff>;
def help : FF<"help", "Display this help">;
def version : FF<"version", "Display the version">;

View File

@ -40,7 +40,7 @@ public:
void printNeededLibraries() override;
void printStringTable() override;
void printExceptionSection() override;
void printLoaderSection(bool PrintHeader) override;
void printLoaderSection(bool PrintHeader, bool PrintSymbolTable) override;
ScopedPrinter &getScopedPrinter() const { return W; }
@ -68,6 +68,9 @@ private:
void printAuxiliaryHeader(const XCOFFAuxiliaryHeader32 *AuxHeader);
void printAuxiliaryHeader(const XCOFFAuxiliaryHeader64 *AuxHeader);
void printLoaderSectionHeader(uintptr_t LoaderSectAddr);
void printLoaderSectionSymbols(uintptr_t LoaderSectAddr);
template <typename LoaderSectionSymbolEntry, typename LoaderSectionHeader>
void printLoaderSectionSymbolsHelper(uintptr_t LoaderSectAddr);
const XCOFFObjectFile &Obj;
};
} // anonymous namespace
@ -135,7 +138,7 @@ void XCOFFDumper::printSectionHeaders() {
printSectionHeaders(Obj.sections32());
}
void XCOFFDumper::printLoaderSection(bool PrintHeader) {
void XCOFFDumper::printLoaderSection(bool PrintHeader, bool PrintSymbolTable) {
DictScope DS(W, "Loader Section");
Expected<uintptr_t> LoaderSectionAddrOrError =
Obj.getSectionFileOffsetToRawData(XCOFF::STYP_LOADER);
@ -145,13 +148,18 @@ void XCOFFDumper::printLoaderSection(bool PrintHeader) {
}
uintptr_t LoaderSectionAddr = LoaderSectionAddrOrError.get();
if (LoaderSectionAddr == 0)
return;
W.indent();
if (PrintHeader)
printLoaderSectionHeader(LoaderSectionAddr);
// TODO: Need to print symbol table, relocation entry of loader section later.
if (PrintSymbolTable)
printLoaderSectionSymbols(LoaderSectionAddr);
// TODO: Need to add printing of relocation entry of loader section later.
// For example:
// if (PrintSymbolTable)
// printLoaderSectionSymbolTable();
// if (PrintRelocation)
// printLoaderSectionRelocationEntry();
W.unindent();
@ -185,6 +193,74 @@ void XCOFFDumper::printLoaderSectionHeader(uintptr_t LoaderSectionAddr) {
}
}
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
};
template <typename LoaderSectionSymbolEntry, typename LoaderSectionHeader>
void XCOFFDumper::printLoaderSectionSymbolsHelper(uintptr_t LoaderSectionAddr) {
const LoaderSectionHeader *LoadSecHeader =
reinterpret_cast<const LoaderSectionHeader *>(LoaderSectionAddr);
const LoaderSectionSymbolEntry *LoadSecSymEntPtr =
reinterpret_cast<LoaderSectionSymbolEntry *>(
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<StringRef> SymbolNameOrErr =
LoadSecSymEntPtr->getSymbolName(LoadSecHeader);
if (!SymbolNameOrErr) {
reportUniqueWarning(SymbolNameOrErr.takeError());
return;
}
DictScope DS(W, "Symbol");
W.printString("Name", SymbolNameOrErr.get());
W.printHex("Virtual Address", LoadSecSymEntPtr->Value);
W.printNumber("SectionNum", LoadSecSymEntPtr->SectionNumber);
W.printHex("SymbolType", LoadSecSymEntPtr->SymbolType);
W.printEnum("StorageClass",
static_cast<uint8_t>(LoadSecSymEntPtr->StorageClass),
makeArrayRef(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<LoaderSectionSymbolEntry64,
LoaderSectionHeader64>(LoaderSectionAddr);
else
printLoaderSectionSymbolsHelper<LoaderSectionSymbolEntry32,
LoaderSectionHeader32>(LoaderSectionAddr);
}
template <typename T>
void XCOFFDumper::printExceptionSectionEntry(const T &ExceptionSectEnt) const {
if (ExceptionSectEnt.getReason())
@ -468,25 +544,6 @@ void XCOFFDumper::printSectAuxEntForDWARF(const T *AuxEntPtr) {
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:

View File

@ -163,6 +163,7 @@ static bool COFFTLSDirectory;
// XCOFF specific options.
static bool XCOFFAuxiliaryHeader;
static bool XCOFFLoaderSectionHeader;
static bool XCOFFLoaderSectionSymbol;
static bool XCOFFExceptionSection;
OutputStyleTy Output = OutputStyleTy::LLVM;
@ -305,6 +306,7 @@ static void parseOptions(const opt::InputArgList &Args) {
// XCOFF specific options.
opts::XCOFFAuxiliaryHeader = Args.hasArg(OPT_auxiliary_header);
opts::XCOFFLoaderSectionHeader = Args.hasArg(OPT_loader_section_header);
opts::XCOFFLoaderSectionSymbol = Args.hasArg(OPT_loader_section_symbols);
opts::XCOFFExceptionSection = Args.hasArg(OPT_exception_section);
opts::InputFilenames = Args.getAllArgValues(OPT_INPUT);
@ -510,8 +512,9 @@ static void dumpObject(ObjectFile &Obj, ScopedPrinter &Writer,
}
if (Obj.isXCOFF()) {
if (opts::XCOFFLoaderSectionHeader)
Dumper->printLoaderSection(opts::XCOFFLoaderSectionHeader);
if (opts::XCOFFLoaderSectionHeader || opts::XCOFFLoaderSectionSymbol)
Dumper->printLoaderSection(opts::XCOFFLoaderSectionHeader,
opts::XCOFFLoaderSectionSymbol);
if (opts::XCOFFExceptionSection)
Dumper->printExceptionSection();