diff --git a/llvm/docs/CommandGuide/llvm-readobj.rst b/llvm/docs/CommandGuide/llvm-readobj.rst --- a/llvm/docs/CommandGuide/llvm-readobj.rst +++ b/llvm/docs/CommandGuide/llvm-readobj.rst @@ -334,6 +334,10 @@ Display XCOFF exception section entries. +.. option:: --loader-section-symbol + + Display symbol table of loader section. + EXIT STATUS ----------- diff --git a/llvm/include/llvm/Object/XCOFFObjectFile.h b/llvm/include/llvm/Object/XCOFFObjectFile.h --- a/llvm/include/llvm/Object/XCOFFObjectFile.h +++ b/llvm/include/llvm/Object/XCOFFObjectFile.h @@ -229,6 +229,9 @@ support::big32_t OffsetToImpid; support::ubig32_t LengthOfStrTbl; support::big32_t OffsetToStrTbl; + uint64_t getOffsetToSymTbl() const { + return NumberOfSymTabEnt == 0 ? 0 : sizeof(LoaderSectionHeader32); + } }; struct LoaderSectionHeader64 : LoaderSectionHeader { @@ -247,6 +250,60 @@ uint64_t getOffsetToRelEnt() const { return OffsetToRelEnt; } }; +template struct LoaderSectionSymbolEntry { + uint32_t getValue() const { return static_cast(this)->Value; } + uint16_t getSectionNum() const { + return static_cast(this)->SectionNumber; + } + uint16_t getSymbolType() const { + return static_cast(this)->SymbolType; + } + XCOFF::StorageClass getStorageClass() const { + return static_cast(this)->StorageClass; + } + uint32_t getImportFileID() const { + return static_cast(this)->ImportFileID; + } + uint32_t getParameterTypeCheck() const { + return static_cast(this)->ParameterTypeCheck; + } +}; + +struct LoaderSectionSymbolEntry32 + : LoaderSectionSymbolEntry { + typedef struct { + support::big32_t Magic; // Zero indicates name in string table. + support::ubig32_t Offset; + } NameInStrTblType; + + union { + char SymbolName[XCOFF::NameSize]; + NameInStrTblType NameInStrTbl; + }; + + 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 + getSymbolName(const LoaderSectionHeader32 *LDHeader) const; +}; + +struct LoaderSectionSymbolEntry64 + : LoaderSectionSymbolEntry { + 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 + getSymbolName(const LoaderSectionHeader64 *LDHeader) const; +}; + template struct ExceptionSectionEntry { union { support::ubig32_t SymbolIdx; diff --git a/llvm/lib/Object/XCOFFObjectFile.cpp b/llvm/lib/Object/XCOFFObjectFile.cpp --- a/llvm/lib/Object/XCOFFObjectFile.cpp +++ b/llvm/lib/Object/XCOFFObjectFile.cpp @@ -89,6 +89,31 @@ template struct ExceptionSectionEntry; template struct ExceptionSectionEntry; +template +Expected getLoadSectionSymName(const T *LDHeader, uint64_t Offset) { + if (LDHeader->getLengthOfStrTbl() > Offset) + return (reinterpret_cast(LDHeader) + + LDHeader->getOffsetToStrTbl() + Offset); + + return createError("entry with offset 0x" + Twine::utohexstr(Offset) + + " in the loader section's string table with size 0x" + + Twine::utohexstr(LDHeader->getLengthOfStrTbl()) + + " is invalid"); +} + +Expected LoaderSectionSymbolEntry32::getSymbolName( + const LoaderSectionHeader32 *LDHeader32) const { + if (NameInStrTbl.Magic != XCOFFSymbolRef::NAME_IN_STR_TBL_MAGIC) + return generateXCOFFFixedNameStringRef(SymbolName); + + return getLoadSectionSymName(LDHeader32, NameInStrTbl.Offset); +} + +Expected LoaderSectionSymbolEntry64::getSymbolName( + const LoaderSectionHeader64 *LDHeader64) const { + return getLoadSectionSymName(LDHeader64, Offset); +} + uintptr_t XCOFFObjectFile::getAdvancedSymbolEntryAddress(uintptr_t CurrentAddress, uint32_t Distance) { diff --git a/llvm/test/tools/llvm-readobj/XCOFF/loader-section-symbol-invalid.test b/llvm/test/tools/llvm-readobj/XCOFF/loader-section-symbol-invalid.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/XCOFF/loader-section-symbol-invalid.test @@ -0,0 +1,39 @@ +## Test the --loader-section-header option. + +# RUN: yaml2obj %s -o %t_xcoff.o +# RUN: llvm-readobj --loader-section-symbol %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 +## ^-------OffsetToSymTbl=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 diff --git a/llvm/test/tools/llvm-readobj/XCOFF/loader-section-symbol.test b/llvm/test/tools/llvm-readobj/XCOFF/loader-section-symbol.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/XCOFF/loader-section-symbol.test @@ -0,0 +1,120 @@ +## Test the --loader-section-header option. + +# RUN: yaml2obj --docnum=1 %s -o %t_xcoff32.o +# RUN: yaml2obj --docnum=2 %s -o %t_xcoff64.o +# RUN: llvm-readobj --loader-section-symbol %t_xcoff32.o |\ +# RUN: FileCheck %s --check-prefixes=CHECK32 +# RUN: llvm-readobj --loader-section-symbol %t_xcoff64.o |\ +# RUN: FileCheck %s --check-prefixes=CHECK64 + +--- !XCOFF +FileHeader: + MagicNumber: 0x1DF +Sections: + - Name: .loader + Flags: [ STYP_LOADER ] + SectionData: "0000000100000002000000050000016D00000001000000A40000000c000000506d79696e74766172200002800002110500000000000000000000000000000002200002840002110a0000000000000000000a66756e63305f5f467600" +## ^------- -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=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=0x000000011000030 +#### ^------- Offset=2 +#### ^--- sectionNumber = 2 +#### ^- SymbolType=0x11 +#### ^- StorageClass=0x05 +#### ^------- ImportFileID=0 +#### ^-------ParameterCheckType=0 +#### ^--------------- Value=0x000000011000030 +#### ^------- 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: } +# CHECK32-NEXT: } +# CHECK32-NEXT: } + +# CHECK64: Loader Section { +# CHECK64-NEXT: Loader Section Symbols { +# CHECK64-NEXT: Symbol { +# CHECK64-NEXT: Name: myintvar +# CHECK64-NEXT: Virtual Address: 0x10000300 +# 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: 0x10000308 +# 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: } diff --git a/llvm/tools/llvm-readobj/ObjDumper.h b/llvm/tools/llvm-readobj/ObjDumper.h --- a/llvm/tools/llvm-readobj/ObjDumper.h +++ b/llvm/tools/llvm-readobj/ObjDumper.h @@ -160,6 +160,7 @@ virtual void printExceptionSection() {} virtual void printLoaderSection() {} virtual void setPrintLoaderSectionHeader() {} + virtual void setPrintLoaderSectionSymbol() {} // Only implemented for MachO. virtual void printMachODataInCode() { } diff --git a/llvm/tools/llvm-readobj/Opts.td b/llvm/tools/llvm-readobj/Opts.td --- a/llvm/tools/llvm-readobj/Opts.td +++ b/llvm/tools/llvm-readobj/Opts.td @@ -90,6 +90,7 @@ def auxiliary_header : FF<"auxiliary-header" , "Display the auxiliary header">, Group; def exception_section : FF<"exception-section" , "Display the exception section entries">, Group; def loader_section_header : FF<"loader-section-header" , "Display the loader section header">, Group; +def loader_section_symbol : FF<"loader-section-symbol" , "Display the loader section symbol table">, Group; def help : FF<"help", "Display this help">; def version : FF<"version", "Display the version">; diff --git a/llvm/tools/llvm-readobj/XCOFFDumper.cpp b/llvm/tools/llvm-readobj/XCOFFDumper.cpp --- a/llvm/tools/llvm-readobj/XCOFFDumper.cpp +++ b/llvm/tools/llvm-readobj/XCOFFDumper.cpp @@ -46,6 +46,10 @@ PrintLoaderSectionHeader = true; } + void setPrintLoaderSectionSymbol() override { + PrintLoaderSectionSymbol = true; + } + ScopedPrinter &getScopedPrinter() const { return W; } private: @@ -72,8 +76,10 @@ void printAuxiliaryHeader(const XCOFFAuxiliaryHeader32 *AuxHeader); void printAuxiliaryHeader(const XCOFFAuxiliaryHeader64 *AuxHeader); void printLoaderSectionHeader(uintptr_t LoaderSectAddr); + void printLoaderSectionSymbols(uintptr_t LoaderSectAddr); const XCOFFObjectFile &Obj; bool PrintLoaderSectionHeader = false; + bool PrintLoaderSectionSymbol = false; }; } // anonymous namespace @@ -150,12 +156,19 @@ } uintptr_t LoaderSectionAddr = LoaderSectionAddrOrError.get(); + if (LoaderSectionAddr == 0) + return; + W.indent(); if (PrintLoaderSectionHeader) XCOFFDumper::printLoaderSectionHeader(LoaderSectionAddr); + + if (PrintLoaderSectionSymbol) + XCOFFDumper::printLoaderSectionSymbols(LoaderSectionAddr); + // TODO: Need to print symbol table, relocation entry of loader section later. // For example: - // if (PrintLoaderSectionSymbolTable) + // if (PrintLoaderSectionSymbol) // XCOFFDumper::printLoaderSectionSymbolTable(); // if (PrintLoaderSectionRelocationEntry) // XCOFFDumper::printLoaderSectionRelocationEntry(); @@ -191,6 +204,70 @@ } } +const EnumEntry SymStorageClass[] = { +#define ECase(X) \ + { #X, XCOFF::X } + ECase(C_NULL), ECase(C_AUTO), ECase(C_EXT), ECase(C_STAT), + ECase(C_REG), ECase(C_EXTDEF), ECase(C_LABEL), ECase(C_ULABEL), + ECase(C_MOS), ECase(C_ARG), ECase(C_STRTAG), ECase(C_MOU), + ECase(C_UNTAG), ECase(C_TPDEF), ECase(C_USTATIC), ECase(C_ENTAG), + ECase(C_MOE), ECase(C_REGPARM), ECase(C_FIELD), ECase(C_BLOCK), + ECase(C_FCN), ECase(C_EOS), ECase(C_FILE), ECase(C_LINE), + ECase(C_ALIAS), ECase(C_HIDDEN), ECase(C_HIDEXT), ECase(C_BINCL), + ECase(C_EINCL), ECase(C_INFO), ECase(C_WEAKEXT), ECase(C_DWARF), + ECase(C_GSYM), ECase(C_LSYM), ECase(C_PSYM), ECase(C_RSYM), + ECase(C_RPSYM), ECase(C_STSYM), ECase(C_TCSYM), ECase(C_BCOMM), + ECase(C_ECOML), ECase(C_ECOMM), ECase(C_DECL), ECase(C_ENTRY), + ECase(C_FUN), ECase(C_BSTAT), ECase(C_ESTAT), ECase(C_GTLS), + ECase(C_STTLS), ECase(C_EFCN) +#undef ECase +}; + +void XCOFFDumper::printLoaderSectionSymbols(uintptr_t LoaderSectionAddr) { + + DictScope DS(W, "Loader Section Symbols"); + + auto printLoadSecSymbolCommon = [&](auto *LDSymbol, auto *LDheader) { + Expected SymbolNameOrErr = LDSymbol->getSymbolName(LDheader); + + if (!SymbolNameOrErr) { + reportUniqueWarning(SymbolNameOrErr.takeError()); + return; + } + DictScope DS(W, "Symbol"); + W.printString("Name", SymbolNameOrErr.get()); + W.printHex("Virtual Address", LDSymbol->getValue()); + W.printNumber("SectionNum", LDSymbol->getSectionNum()); + W.printHex("SymbolType", LDSymbol->getSymbolType()); + W.printEnum("StorageClass", + static_cast(LDSymbol->getStorageClass()), + makeArrayRef(SymStorageClass)); + W.printHex("ImportFileID", LDSymbol->getImportFileID()); + W.printNumber("ParameterTypeCheck", LDSymbol->getParameterTypeCheck()); + }; + + if (Obj.is64Bit()) { + const LoaderSectionHeader64 *LoaderSec64 = + reinterpret_cast(LoaderSectionAddr); + const LoaderSectionSymbolEntry64 *LDSymEntPtr64 = + reinterpret_cast( + LoaderSectionAddr + uintptr_t(LoaderSec64->getOffsetToSymTbl())); + for (uint32_t i = 0; i < LoaderSec64->getNumOfSymTblEnt(); + i++, LDSymEntPtr64++) + printLoadSecSymbolCommon(LDSymEntPtr64, LoaderSec64); + + } else { + const LoaderSectionHeader32 *LoaderSec32 = + reinterpret_cast(LoaderSectionAddr); + const LoaderSectionSymbolEntry32 *LDSymEntPtr32 = + reinterpret_cast( + LoaderSectionAddr + uintptr_t(LoaderSec32->getOffsetToSymTbl())); + for (uint32_t i = 0; i < LoaderSec32->getNumOfSymTblEnt(); + i++, LDSymEntPtr32++) + printLoadSecSymbolCommon(LDSymEntPtr32, LoaderSec32); + } +} + template void XCOFFDumper::printExceptionSectionEntry(const T &ExceptionSectEnt) const { if (ExceptionSectEnt.getReason()) @@ -474,25 +551,6 @@ makeArrayRef(SymAuxType)); } -const EnumEntry SymStorageClass[] = { -#define ECase(X) \ - { #X, XCOFF::X } - ECase(C_NULL), ECase(C_AUTO), ECase(C_EXT), ECase(C_STAT), - ECase(C_REG), ECase(C_EXTDEF), ECase(C_LABEL), ECase(C_ULABEL), - ECase(C_MOS), ECase(C_ARG), ECase(C_STRTAG), ECase(C_MOU), - ECase(C_UNTAG), ECase(C_TPDEF), ECase(C_USTATIC), ECase(C_ENTAG), - ECase(C_MOE), ECase(C_REGPARM), ECase(C_FIELD), ECase(C_BLOCK), - ECase(C_FCN), ECase(C_EOS), ECase(C_FILE), ECase(C_LINE), - ECase(C_ALIAS), ECase(C_HIDDEN), ECase(C_HIDEXT), ECase(C_BINCL), - ECase(C_EINCL), ECase(C_INFO), ECase(C_WEAKEXT), ECase(C_DWARF), - ECase(C_GSYM), ECase(C_LSYM), ECase(C_PSYM), ECase(C_RSYM), - ECase(C_RPSYM), ECase(C_STSYM), ECase(C_TCSYM), ECase(C_BCOMM), - ECase(C_ECOML), ECase(C_ECOMM), ECase(C_DECL), ECase(C_ENTRY), - ECase(C_FUN), ECase(C_BSTAT), ECase(C_ESTAT), ECase(C_GTLS), - ECase(C_STTLS), ECase(C_EFCN) -#undef ECase -}; - static StringRef GetSymbolValueName(XCOFF::StorageClass SC) { switch (SC) { case XCOFF::C_EXT: diff --git a/llvm/tools/llvm-readobj/llvm-readobj.cpp b/llvm/tools/llvm-readobj/llvm-readobj.cpp --- a/llvm/tools/llvm-readobj/llvm-readobj.cpp +++ b/llvm/tools/llvm-readobj/llvm-readobj.cpp @@ -163,6 +163,7 @@ // XCOFF specific options. static bool XCOFFAuxiliaryHeader; static bool XCOFFLoaderSectionHeader; +static bool XCOFFLoaderSectionSymbol; static bool XCOFFExceptionSection; OutputStyleTy Output = OutputStyleTy::LLVM; @@ -305,6 +306,7 @@ // 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_symbol); opts::XCOFFExceptionSection = Args.hasArg(OPT_exception_section); opts::InputFilenames = Args.getAllArgValues(OPT_INPUT); @@ -510,10 +512,15 @@ } if (Obj.isXCOFF()) { - if (opts::XCOFFLoaderSectionHeader) { + if (opts::XCOFFLoaderSectionHeader) Dumper->setPrintLoaderSectionHeader(); + + if (opts::XCOFFLoaderSectionSymbol) + Dumper->setPrintLoaderSectionSymbol(); + + if (opts::XCOFFLoaderSectionHeader || opts::XCOFFLoaderSectionSymbol) Dumper->printLoaderSection(); - } + if (opts::XCOFFExceptionSection) Dumper->printExceptionSection(); }