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 @@ -330,6 +330,10 @@ Display XCOFF Auxiliary header. +.. option:: --exception-section + + Display exception section entries of XCOFF object file. + 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 @@ -220,6 +220,35 @@ support::big32_t OffsetToRelEnt; }; +template struct ExceptionSectionEntry { + union { + support::ubig32_t SymbolIdx; + AddressType TrapInstAddr; + }; + uint8_t LangId; + uint8_t Reason; + +public: + uint32_t getSymbolIndex() const { + assert(Reason == 0 && "Get symbol table index of the function only when " + "the e_reason field is 0."); + return SymbolIdx; + } + uint64_t getTrapInstAddr() const { + assert(Reason && " Zero is not a valid trap exception reason code."); + return TrapInstAddr; + } + uint8_t getLangID() const { return LangId; } + uint8_t getReason() const { return Reason; } +}; + +typedef ExceptionSectionEntry ExceptionSectionEntry32; +typedef ExceptionSectionEntry ExceptionSectionEntry64; + +// Explicit extern template declarations. +extern template struct ExceptionSectionEntry; +extern template struct ExceptionSectionEntry; + struct XCOFFStringTable { uint32_t Size; const char *Data; @@ -462,7 +491,11 @@ const XCOFFSectionHeader64 *toSection64(DataRefImpl Ref) const; uintptr_t getSectionHeaderTableAddress() const; uintptr_t getEndOfSymbolTableAddress() const; - Expected getLoaderSectionAddress() const; + + DataRefImpl getSectionByType(XCOFF::SectionTypeFlags SectType) const; + uint64_t getSectionFileOffsetToRawData(DataRefImpl Sec) const; + Expected + getSectionFileOffsetToRawData(XCOFF::SectionTypeFlags SectType) const; // This returns a pointer to the start of the storage for the name field of // the 32-bit or 64-bit SectionHeader struct. This string is *not* necessarily @@ -618,6 +651,10 @@ // Loader section related interfaces. Expected getImportFileTable() const; + // Exception-related interface. + template + Expected> getExceptionEntries() const; + // This function returns string table entry. Expected getStringTableEntry(uint32_t Offset) const; 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 @@ -86,6 +86,15 @@ return (Info & XR_BIASED_LENGTH_MASK) + 1; } +template uint32_t ExceptionSectionEntry::getSymbolIndex() const; +template uint64_t ExceptionSectionEntry::getTrapInstAddr() const; +template uint8_t ExceptionSectionEntry::getLangID() const; +template uint8_t ExceptionSectionEntry::getReason() const ; +template uint32_t ExceptionSectionEntry::getSymbolIndex() const ; +template uint64_t ExceptionSectionEntry::getTrapInstAddr()const; +template uint8_t ExceptionSectionEntry::getLangID() const; +template uint8_t ExceptionSectionEntry::getReason() const; + uintptr_t XCOFFObjectFile::getAdvancedSymbolEntryAddress(uintptr_t CurrentAddress, uint32_t Distance) { @@ -392,41 +401,44 @@ return Result; } -Expected XCOFFObjectFile::getLoaderSectionAddress() const { - uint64_t OffsetToLoaderSection = 0; - uint64_t SizeOfLoaderSection = 0; +uint64_t XCOFFObjectFile::getSectionFileOffsetToRawData(DataRefImpl Sec) const { + if (is64Bit()) + return toSection64(Sec)->FileOffsetToRawData; - if (is64Bit()) { - for (const auto &Sec64 : sections64()) - if (Sec64.getSectionType() == XCOFF::STYP_LOADER) { - OffsetToLoaderSection = Sec64.FileOffsetToRawData; - SizeOfLoaderSection = Sec64.SectionSize; - break; - } - } else { - for (const auto &Sec32 : sections32()) - if (Sec32.getSectionType() == XCOFF::STYP_LOADER) { - OffsetToLoaderSection = Sec32.FileOffsetToRawData; - SizeOfLoaderSection = Sec32.SectionSize; - break; - } - } + return toSection32(Sec)->FileOffsetToRawData; +} + +Expected XCOFFObjectFile::getSectionFileOffsetToRawData( + XCOFF::SectionTypeFlags SectType) const { + DataRefImpl DRI = getSectionByType(SectType); - // No loader section is not an error. - if (!SizeOfLoaderSection) + if (DRI.p == 0) // No section is not error. return 0; - uintptr_t LoderSectionStart = - reinterpret_cast(base() + OffsetToLoaderSection); - if (Error E = - Binary::checkOffset(Data, LoderSectionStart, SizeOfLoaderSection)) - return createError(toString(std::move(E)) + - ": loader section with offset 0x" + - Twine::utohexstr(OffsetToLoaderSection) + - " and size 0x" + Twine::utohexstr(SizeOfLoaderSection) + + uint64_t OffsetToSection = getSectionFileOffsetToRawData(DRI); + uint64_t SizeOfSection = getSectionSize(DRI); + + uintptr_t SectionStart = + reinterpret_cast(base() + OffsetToSection); + if (Error E = Binary::checkOffset(Data, SectionStart, SizeOfSection)) { + + const char *SectNameMap[] = {"pad", "text", "data", "bss", + "expect", "info", "tdata", "tbss", + "loader", "debug", "typchk", "ovrflo"}; + auto getSectName = [&]() { + for (int I = 3; I < 16; I++) + if (SectType & (1 << I)) + return SectNameMap[I]; + return ""; + }; + + return createError(toString(std::move(E)) + ": " + getSectName() + + " section with offset 0x" + + Twine::utohexstr(OffsetToSection) + " and size 0x" + + Twine::utohexstr(SizeOfSection) + " goes past the end of the file"); - - return LoderSectionStart; + } + return SectionStart; } bool XCOFFObjectFile::isSectionCompressed(DataRefImpl Sec) const { @@ -738,6 +750,25 @@ return DRI; } +DataRefImpl +XCOFFObjectFile::getSectionByType(XCOFF::SectionTypeFlags SectType) const { + DataRefImpl DRI; + if (is64Bit()) { + for (const auto &Sec64 : sections64()) + if (Sec64.getSectionType() == SectType) { + DRI.p = reinterpret_cast(&Sec64); + break; + } + } else { + for (const auto &Sec32 : sections32()) + if (Sec32.getSectionType() == SectType) { + DRI.p = reinterpret_cast(&Sec32); + break; + } + } + return DRI; +} + Expected XCOFFObjectFile::getSymbolSectionName(XCOFFSymbolRef SymEntPtr) const { const int16_t SectionNum = SymEntPtr.getSectionNumber(); @@ -960,6 +991,36 @@ return ArrayRef(StartReloc, StartReloc + NumRelocEntries); } +template +Expected> XCOFFObjectFile::getExceptionEntries() const { + Expected ExceptionSectOrErr = + getSectionFileOffsetToRawData(XCOFF::STYP_EXCEPT); + if (!ExceptionSectOrErr) + return ExceptionSectOrErr.takeError(); + + DataRefImpl DRI = getSectionByType(XCOFF::STYP_EXCEPT); + + if (DRI.p == 0) + return ArrayRef(); + + uint64_t SizeOfSection = getSectionSize(DRI); + + if (is64Bit()) + assert(sizeof(ExceptEnt) == sizeof(ExceptionSectionEntry64)); + else + assert(sizeof(ExceptEnt) == sizeof(ExceptionSectionEntry32)); + + ExceptEnt *ExceptEntStart = + reinterpret_cast(*ExceptionSectOrErr); + return ArrayRef( + ExceptEntStart, ExceptEntStart + SizeOfSection / sizeof(ExceptEnt)); +} + +template Expected> +XCOFFObjectFile::getExceptionEntries() const; +template Expected> +XCOFFObjectFile::getExceptionEntries() const; + Expected XCOFFObjectFile::parseStringTable(const XCOFFObjectFile *Obj, uint64_t Offset) { // If there is a string table, then the buffer must contain at least 4 bytes @@ -997,7 +1058,8 @@ // This function returns the import file table. Each entry in the import file // table consists of: "path_name\0base_name\0archive_member_name\0". Expected XCOFFObjectFile::getImportFileTable() const { - Expected LoaderSectionAddrOrError = getLoaderSectionAddress(); + Expected LoaderSectionAddrOrError = + getSectionFileOffsetToRawData(XCOFF::STYP_LOADER); if (!LoaderSectionAddrOrError) return LoaderSectionAddrOrError.takeError(); diff --git a/llvm/test/tools/llvm-readobj/XCOFF/Inputs/exception-section.o b/llvm/test/tools/llvm-readobj/XCOFF/Inputs/exception-section.o new file mode 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@, HelpText<"OPTIONS (XCOFF specific)">; def auxiliary_header : FF<"auxiliary-header" , "Display the auxiliary header">, Group; +def exception_section : FF<"exception-section" , "Display the exception section entries">, 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 @@ -39,6 +39,7 @@ void printStackMap() const override; void printNeededLibraries() override; void printStringTable() override; + void printExceptionSection() override; ScopedPrinter &getScopedPrinter() const { return W; } @@ -46,6 +47,9 @@ template void printSectionHeaders(ArrayRef Sections); template void printGenericSectionHeader(T &Sec) const; template void printOverflowSectionHeader(T &Sec) const; + template + void printExceptionSectionEntry(const T &ExceptionSectEnt) const; + template void printExceptionSectionEntries() const; template const T *getAuxEntPtr(uintptr_t AuxAddress); void printFileAuxEnt(const XCOFFFileAuxEnt *AuxEntPtr); void printCsectAuxEnt(XCOFFCsectAuxRef AuxEntRef); @@ -129,6 +133,39 @@ printSectionHeaders(Obj.sections32()); } +template +void XCOFFDumper::printExceptionSectionEntry(const T &ExceptionSectEnt) const { + if (ExceptionSectEnt.getReason()) + W.printHex("Trap Instr Addr", ExceptionSectEnt.getTrapInstAddr()); + else { + uint32_t SymIdx = ExceptionSectEnt.getSymbolIndex(); + StringRef SymName = + unwrapOrError(Obj.getFileName(), Obj.getSymbolNameByIndex(SymIdx)); + Twine SymInfo = Twine(SymIdx) + " (" + SymName + ")"; + W.printString("Symbol Index", SymInfo.str()); + } + W.printNumber("LangID", ExceptionSectEnt.getLangID()); + W.printNumber("Reason", ExceptionSectEnt.getReason()); +} + +template void XCOFFDumper::printExceptionSectionEntries() const { + ArrayRef ExceptSectEnts = + unwrapOrError(Obj.getFileName(), Obj.getExceptionEntries()); + + DictScope DS(W, "Exception section"); + if (ExceptSectEnts.empty()) + return; + for (auto &Ent : ExceptSectEnts) + printExceptionSectionEntry(Ent); +} + +void XCOFFDumper::printExceptionSection() { + if (Obj.is64Bit()) + printExceptionSectionEntries(); + else + printExceptionSectionEntries(); +} + void XCOFFDumper::printRelocations() { if (Obj.is64Bit()) printRelocations(Obj.sections64()); 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 @@ -162,6 +162,7 @@ // XCOFF specific options. static bool XCOFFAuxiliaryHeader; +static bool XCOFFExceptionSection; OutputStyleTy Output = OutputStyleTy::LLVM; static std::vector InputFilenames; @@ -302,6 +303,7 @@ // XCOFF specific options. opts::XCOFFAuxiliaryHeader = Args.hasArg(OPT_auxiliary_header); + opts::XCOFFExceptionSection = Args.hasArg(OPT_exception_section); opts::InputFilenames = Args.getAllArgValues(OPT_INPUT); } @@ -502,6 +504,10 @@ if (opts::CGProfile) Dumper->printCGProfile(); } + + if (Obj.isXCOFF() && opts::XCOFFExceptionSection) + Dumper->printExceptionSection(); + if (opts::PrintStackMap) Dumper->printStackMap(); if (opts::PrintStackSizes)