diff --git a/llvm/include/llvm/BinaryFormat/SFrame.h b/llvm/include/llvm/BinaryFormat/SFrame.h index 16d3b16c6c2d3..98dbe38fb2bc4 100644 --- a/llvm/include/llvm/BinaryFormat/SFrame.h +++ b/llvm/include/llvm/BinaryFormat/SFrame.h @@ -15,33 +15,36 @@ #ifndef LLVM_BINARYFORMAT_SFRAME_H #define LLVM_BINARYFORMAT_SFRAME_H +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/BitmaskEnum.h" #include "llvm/Support/DataTypes.h" #include "llvm/Support/Endian.h" -namespace llvm::sframe { +namespace llvm { + +template struct EnumEntry; + +namespace sframe { LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); constexpr uint16_t Magic = 0xdee2; enum class Version : uint8_t { - V1 = 1, - V2 = 2, +#define HANDLE_SFRAME_VERSION(CODE, NAME) NAME = CODE, +#include "llvm/BinaryFormat/SFrameConstants.def" }; enum class Flags : uint8_t { - FDESorted = 0x01, - FramePointer = 0x02, - FDEFuncStartPCRel = 0x04, +#define HANDLE_SFRAME_FLAG(CODE, NAME) NAME = CODE, +#include "llvm/BinaryFormat/SFrameConstants.def" V2AllFlags = FDESorted | FramePointer | FDEFuncStartPCRel, LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/0xff), }; enum class ABI : uint8_t { - AArch64EndianBig = 1, - AArch64EndianLittle = 2, - AMD64EndianLittle = 3, +#define HANDLE_SFRAME_ABI(CODE, NAME) NAME = CODE, +#include "llvm/BinaryFormat/SFrameConstants.def" }; /// SFrame FRE Types. Bits 0-3 of FuncDescEntry.Info. @@ -160,6 +163,11 @@ template using FrameRowEntryAddr1 = FrameRowEntry; template using FrameRowEntryAddr2 = FrameRowEntry; template using FrameRowEntryAddr4 = FrameRowEntry; -} // namespace llvm::sframe +ArrayRef> getVersions(); +ArrayRef> getFlags(); +ArrayRef> getABIs(); + +} // namespace sframe +} // namespace llvm #endif // LLVM_BINARYFORMAT_SFRAME_H diff --git a/llvm/include/llvm/BinaryFormat/SFrameConstants.def b/llvm/include/llvm/BinaryFormat/SFrameConstants.def new file mode 100644 index 0000000000000..643b15f438c86 --- /dev/null +++ b/llvm/include/llvm/BinaryFormat/SFrameConstants.def @@ -0,0 +1,39 @@ +//===- SFrameConstants.def --------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#if !(defined(HANDLE_SFRAME_VERSION) || defined(HANDLE_SFRAME_FLAG) || \ + defined(HANDLE_SFRAME_ABI)) +#error "Missing HANDLE_SFRAME definition" +#endif + +#ifndef HANDLE_SFRAME_VERSION +#define HANDLE_SFRAME_VERSION(CODE, NAME) +#endif + +#ifndef HANDLE_SFRAME_FLAG +#define HANDLE_SFRAME_FLAG(CODE, NAME) +#endif + +#ifndef HANDLE_SFRAME_ABI +#define HANDLE_SFRAME_ABI(CODE, NAME) +#endif + +HANDLE_SFRAME_VERSION(0x01, V1) +HANDLE_SFRAME_VERSION(0x02, V2) + +HANDLE_SFRAME_FLAG(0x01, FDESorted) +HANDLE_SFRAME_FLAG(0x02, FramePointer) +HANDLE_SFRAME_FLAG(0x04, FDEFuncStartPCRel) + +HANDLE_SFRAME_ABI(0x01, AArch64EndianBig) +HANDLE_SFRAME_ABI(0x02, AArch64EndianLittle) +HANDLE_SFRAME_ABI(0x03, AMD64EndianLittle) + +#undef HANDLE_SFRAME_VERSION +#undef HANDLE_SFRAME_FLAG +#undef HANDLE_SFRAME_ABI diff --git a/llvm/include/llvm/Object/SFrameParser.h b/llvm/include/llvm/Object/SFrameParser.h new file mode 100644 index 0000000000000..cf4fe20e84431 --- /dev/null +++ b/llvm/include/llvm/Object/SFrameParser.h @@ -0,0 +1,48 @@ +//===- SFrameParser.h -------------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECT_SFRAME_H +#define LLVM_OBJECT_SFRAME_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/BinaryFormat/SFrame.h" +#include "llvm/Support/Error.h" +#include + +namespace llvm { +namespace object { + +template class SFrameParser { +public: + static Expected create(ArrayRef Contents); + + const sframe::Preamble &getPreamble() const { return Header.Preamble; } + const sframe::Header &getHeader() const { return Header; } + + bool usesFixedRAOffset() const { + return getHeader().ABIArch == sframe::ABI::AMD64EndianLittle; + } + bool usesFixedFPOffset() const { + return false; // Not used in any currently defined ABI. + } + +private: + ArrayRef Data; + const sframe::Header &Header; + + SFrameParser(ArrayRef Data, const sframe::Header &Header) + : Data(Data), Header(Header) {} +}; + +extern template class SFrameParser; +extern template class SFrameParser; + +} // end namespace object +} // end namespace llvm + +#endif // LLVM_OBJECT_SFRAME_H diff --git a/llvm/lib/BinaryFormat/CMakeLists.txt b/llvm/lib/BinaryFormat/CMakeLists.txt index 38ba2d9e85a06..4b2debb7ae236 100644 --- a/llvm/lib/BinaryFormat/CMakeLists.txt +++ b/llvm/lib/BinaryFormat/CMakeLists.txt @@ -11,6 +11,7 @@ add_llvm_component_library(LLVMBinaryFormat MsgPackDocumentYAML.cpp MsgPackReader.cpp MsgPackWriter.cpp + SFrame.cpp Wasm.cpp XCOFF.cpp diff --git a/llvm/lib/BinaryFormat/SFrame.cpp b/llvm/lib/BinaryFormat/SFrame.cpp new file mode 100644 index 0000000000000..3b436afd32083 --- /dev/null +++ b/llvm/lib/BinaryFormat/SFrame.cpp @@ -0,0 +1,37 @@ +//===-- SFrame.cpp -----------------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#include "llvm/BinaryFormat/SFrame.h" +#include "llvm/Support/ScopedPrinter.h" + +using namespace llvm; + +ArrayRef> sframe::getVersions() { + static constexpr EnumEntry Versions[] = { +#define HANDLE_SFRAME_VERSION(CODE, NAME) {#NAME, sframe::Version::NAME}, +#include "llvm/BinaryFormat/SFrameConstants.def" + }; + + return ArrayRef(Versions); +} + +ArrayRef> sframe::getFlags() { + static constexpr EnumEntry Flags[] = { +#define HANDLE_SFRAME_FLAG(CODE, NAME) {#NAME, sframe::Flags::NAME}, +#include "llvm/BinaryFormat/SFrameConstants.def" + }; + return ArrayRef(Flags); +} + +ArrayRef> sframe::getABIs() { + static constexpr EnumEntry ABIs[] = { +#define HANDLE_SFRAME_ABI(CODE, NAME) {#NAME, sframe::ABI::NAME}, +#include "llvm/BinaryFormat/SFrameConstants.def" + }; + return ArrayRef(ABIs); +} diff --git a/llvm/lib/Object/CMakeLists.txt b/llvm/lib/Object/CMakeLists.txt index 870169a83174f..0f6d2f7c59a5c 100644 --- a/llvm/lib/Object/CMakeLists.txt +++ b/llvm/lib/Object/CMakeLists.txt @@ -25,6 +25,7 @@ add_llvm_component_library(LLVMObject OffloadBundle.cpp RecordStreamer.cpp RelocationResolver.cpp + SFrameParser.cpp SymbolicFile.cpp SymbolSize.cpp TapiFile.cpp diff --git a/llvm/lib/Object/SFrameParser.cpp b/llvm/lib/Object/SFrameParser.cpp new file mode 100644 index 0000000000000..2d74d1d6b3827 --- /dev/null +++ b/llvm/lib/Object/SFrameParser.cpp @@ -0,0 +1,55 @@ +//===- SFrameParser.cpp ---------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "llvm/Object/SFrameParser.h" +#include "llvm/BinaryFormat/SFrame.h" +#include "llvm/Object/Error.h" +#include "llvm/Support/FormatVariadic.h" + +using namespace llvm; +using namespace llvm::object; + +template +static Expected getDataSliceAs(ArrayRef Data, + uint64_t Offset) { + static_assert(std::is_trivial_v); + if (Data.size() < Offset + sizeof(T)) { + return createStringError( + formatv("unexpected end of data at offset {0:x} while reading [{1:x}, " + "{2:x})", + Data.size(), Offset, Offset + sizeof(T)) + .str(), + object_error::unexpected_eof); + } + return *reinterpret_cast(Data.data() + Offset); +} + +template +Expected> SFrameParser::create(ArrayRef Contents) { + Expected &> Preamble = + getDataSliceAs>(Contents, 0); + if (!Preamble) + return Preamble.takeError(); + + if (Preamble->Magic != sframe::Magic) + return createError( + formatv("invalid magic number ({0:x+4})", Preamble->Magic.value())); + if (Preamble->Version != sframe::Version::V2) + return createError( + formatv("invalid/unsupported version number ({0})", + static_cast(Preamble->Version.value()))); + + Expected &> Header = + getDataSliceAs>(Contents, 0); + if (!Header) + return Header.takeError(); + return SFrameParser(Contents, *Header); +} + +template class llvm::object::SFrameParser; +template class llvm::object::SFrameParser; diff --git a/llvm/test/tools/llvm-readobj/ELF/sframe-header.test b/llvm/test/tools/llvm-readobj/ELF/sframe-header.test new file mode 100644 index 0000000000000..f827296b1c399 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/ELF/sframe-header.test @@ -0,0 +1,148 @@ +## Check parsing and dumping of the SFrame header. +# RUN: yaml2obj --docnum=1 %s -o %t.1 +# RUN: llvm-readobj --sframe=.sframe_bad_sh_size --sframe=.sframe_1b \ +# RUN: --sframe=.sframe_bad_magic --sframe=.sframe_bad_version \ +# RUN: --sframe=.sframe_6b --sframe=.sframe_header %t.1 2>&1 | \ +# RUN: FileCheck %s --strict-whitespace --match-full-lines \ +# RUN: -DFILE=%t.1 --check-prefix=CASE1 + +## Check big-endian support and the handling of --sframe argument default. +# RUN: yaml2obj --docnum=2 %s -o %t.2 +# RUN: llvm-readobj --sframe %t.2 2>&1 | \ +# RUN: FileCheck %s --strict-whitespace --match-full-lines \ +# RUN: -DFILE=%t.2 --check-prefix=CASE2 + +## Check handling of corrupted elf files (bad sh_name) +# RUN: yaml2obj --docnum=3 %s -o %t.3 +# RUN: not llvm-readobj --sframe %t.3 2>&1 | \ +# RUN: FileCheck %s --strict-whitespace --match-full-lines \ +# RUN: -DFILE=%t.3 --check-prefix=CASE3 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC +Sections: + - Name: .sframe_bad_sh_size + Type: SHT_GNU_SFRAME + Flags: [ SHF_ALLOC ] + ShSize: 0xfffff +# CASE1-LABEL:SFrame section '.sframe_bad_sh_size' { +# CASE1:{{.*}}: warning: '[[FILE]]': The end of the file was unexpectedly encountered + - Name: .sframe_1b + Type: SHT_GNU_SFRAME + Flags: [ SHF_ALLOC ] + ContentArray: [ 0x00 ] +# CASE1-LABEL:SFrame section '.sframe_1b' { +# CASE1:{{.*}}: warning: '[[FILE]]': invalid sframe section: unexpected end of data at offset 0x1 while reading [0x0, 0x4) + + - Name: .sframe_bad_magic + Type: SHT_GNU_SFRAME + Flags: [ SHF_ALLOC ] + ContentArray: [ 0xde, 0xad, 0xbe, 0xef] +# CASE1-LABEL:SFrame section '.sframe_bad_magic' { +# CASE1:{{.*}}: warning: '[[FILE]]': invalid sframe section: invalid magic number (0xadde) + + - Name: .sframe_bad_version + Type: SHT_GNU_SFRAME + Flags: [ SHF_ALLOC ] + ContentArray: [ + 0xe2, 0xde, 0x01, 0x00 # Preamble (magic, version, flags) + ] +# CASE1-LABEL:SFrame section '.sframe_bad_version' { +# CASE1:{{.*}}: warning: '[[FILE]]': invalid sframe section: invalid/unsupported version number (1) + + - Name: .sframe_6b + Type: SHT_GNU_SFRAME + Flags: [ SHF_ALLOC ] + ContentArray: [ + 0xe2, 0xde, 0x02, 0x00, # Preamble (magic, version, flags) + 0x01, 0x02 + ] + +# CASE1-LABEL:SFrame section '.sframe_6b' { +# CASE1:{{.*}}: warning: '[[FILE]]': invalid sframe section: unexpected end of data at offset 0x6 while reading [0x0, 0x1c) + + - Name: .sframe_header + Type: SHT_GNU_SFRAME + Flags: [ SHF_ALLOC ] + ContentArray: [ + 0xe2, 0xde, 0x02, 0x06, # Preamble (magic, version, flags) + # Header: + 0x03, 0x42, 0x47, 0x00, # ABI, Fixed FP offset, Fixed RA Offset, AUX header length + 0x01, 0x00, 0x00, 0x00, # Number of FDEs + 0x10, 0x00, 0x00, 0x00, # Number of FREs + 0x00, 0x10, 0x00, 0x00, # FRE length + 0x04, 0x00, 0x00, 0x00, # FDE offset + 0x00, 0x01, 0x00, 0x00, # FRE offset + ] +# CASE1-LABEL:SFrame section '.sframe_header' { +# CASE1: Header { +# CASE1-NEXT: Magic: 0xDEE2 +# CASE1-NEXT: Version: V2 (0x2) +# CASE1-NEXT: Flags [ (0x6) +# CASE1-NEXT: FDEFuncStartPCRel (0x4){{ *}} +# CASE1-NEXT: FramePointer (0x2){{ *}} +# CASE1-NEXT: ] +# CASE1-NEXT: ABI: AMD64EndianLittle (0x3) +# CASE1-NEXT: CFA fixed FP offset (unused): 66 +# CASE1-NEXT: CFA fixed RA offset: 71 +# CASE1-NEXT: Auxiliary header length: 0 +# CASE1-NEXT: Num FDEs: 1 +# CASE1-NEXT: Num FREs: 16 +# CASE1-NEXT: FRE subsection length: 4096 +# CASE1-NEXT: FDE subsection offset: 4 +# CASE1-NEXT: FRE subsection offset: 256 +# CASE1-NEXT: } +# CASE1-NEXT:} + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2MSB + Type: ET_EXEC +Sections: + - Name: .sframe + Type: SHT_GNU_SFRAME + Flags: [ SHF_ALLOC ] + ContentArray: [ + 0xde, 0xe2, 0x02, 0x01, # Preamble (magic, version, flags) + # Header: + 0x01, 0x42, 0x47, 0x00, # ABI, Fixed FP offset, Fixed RA Offset, AUX header length + 0x00, 0x00, 0x00, 0x01, # Number of FDEs + 0x00, 0x00, 0x00, 0x10, # Number of FREs + 0x00, 0x00, 0x10, 0x00, # FRE length + 0x00, 0x00, 0x00, 0x04, # FDE offset + 0x00, 0x00, 0x01, 0x00, # FRE offset + ] +# CASE2-LABEL:SFrame section '.sframe' { +# CASE2: Header { +# CASE2-NEXT: Magic: 0xDEE2 +# CASE2-NEXT: Version: V2 (0x2) +# CASE2-NEXT: Flags [ (0x1) +# CASE2-NEXT: FDESorted (0x1){{ *}} +# CASE2-NEXT: ] +# CASE2-NEXT: ABI: AArch64EndianBig (0x1) +# CASE2-NEXT: CFA fixed FP offset (unused): 66 +# CASE2-NEXT: CFA fixed RA offset (unused): 71 +# CASE2-NEXT: Auxiliary header length: 0 +# CASE2-NEXT: Num FDEs: 1 +# CASE2-NEXT: Num FREs: 16 +# CASE2-NEXT: FRE subsection length: 4096 +# CASE2-NEXT: FDE subsection offset: 4 +# CASE2-NEXT: FRE subsection offset: 256 +# CASE2-NEXT: } +# CASE2-NEXT:} + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2MSB + Type: ET_EXEC +Sections: + - Name: .corrupted + Type: SHT_GNU_SFRAME + Flags: [ SHF_ALLOC ] + ShName: 0x10000 +# CASE3:{{.*}}: error: '[[FILE]]': a section [index 1] has an invalid sh_name (0x10000) offset which goes past the end of the section name string table diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp index 465c189680cae..5caa1935ae2ef 100644 --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -30,6 +30,7 @@ #include "llvm/BinaryFormat/AMDGPUMetadataVerifier.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/BinaryFormat/MsgPackDocument.h" +#include "llvm/BinaryFormat/SFrame.h" #include "llvm/Demangle/Demangle.h" #include "llvm/Object/Archive.h" #include "llvm/Object/ELF.h" @@ -38,6 +39,7 @@ #include "llvm/Object/Error.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Object/RelocationResolver.h" +#include "llvm/Object/SFrameParser.h" #include "llvm/Object/StackMapParser.h" #include "llvm/Support/AArch64AttributeParser.h" #include "llvm/Support/AMDGPUMetadata.h" @@ -225,6 +227,8 @@ template class ELFDumper : public ObjDumper { void printArchSpecificInfo() override; void printStackMap() const override; void printMemtag() override; + void printSectionsAsSFrame(ArrayRef Sections) override; + ArrayRef getMemtagGlobalsSectionContents(uint64_t ExpectedAddr); // Hash histogram shows statistics of how efficient the hash was for the @@ -6429,6 +6433,61 @@ template void ELFDumper::printMemtag() { printMemtag(DynamicEntries, AndroidNoteDesc, GlobalDescriptors); } +template +void ELFDumper::printSectionsAsSFrame(ArrayRef Sections) { + constexpr endianness E = ELFT::Endianness; + for (object::SectionRef Section : + getSectionRefsByNameOrIndex(ObjF, Sections)) { + // Validity of sections names checked in getSectionRefsByNameOrIndex. + StringRef SectionName = cantFail(Section.getName()); + + DictScope SectionScope(W, + formatv("SFrame section '{0}'", SectionName).str()); + + StringRef SectionContent; + if (Error Err = Section.getContents().moveInto(SectionContent)) { + reportWarning(std::move(Err), FileName); + continue; + } + + Expected> Parser = + object::SFrameParser::create(arrayRefFromStringRef(SectionContent)); + if (!Parser) { + reportWarning(createError("invalid sframe section: " + + toString(Parser.takeError())), + FileName); + continue; + } + + DictScope HeaderScope(W, "Header"); + + const sframe::Preamble &Preamble = Parser->getPreamble(); + W.printHex("Magic", Preamble.Magic.value()); + W.printEnum("Version", Preamble.Version.value(), sframe::getVersions()); + W.printFlags("Flags", Preamble.Flags.value(), sframe::getFlags()); + + const sframe::Header &Header = Parser->getHeader(); + W.printEnum("ABI", Header.ABIArch.value(), sframe::getABIs()); + + W.printNumber(("CFA fixed FP offset" + + Twine(Parser->usesFixedFPOffset() ? "" : " (unused)")) + .str(), + Header.CFAFixedFPOffset.value()); + + W.printNumber(("CFA fixed RA offset" + + Twine(Parser->usesFixedRAOffset() ? "" : " (unused)")) + .str(), + Header.CFAFixedRAOffset.value()); + + W.printNumber("Auxiliary header length", Header.AuxHdrLen.value()); + W.printNumber("Num FDEs", Header.NumFDEs.value()); + W.printNumber("Num FREs", Header.NumFREs.value()); + W.printNumber("FRE subsection length", Header.FRELen.value()); + W.printNumber("FDE subsection offset", Header.FDEOff.value()); + W.printNumber("FRE subsection offset", Header.FREOff.value()); + } +} + template void GNUELFDumper::printELFLinkerOptions() { OS << "printELFLinkerOptions not implemented!\n"; } diff --git a/llvm/tools/llvm-readobj/ObjDumper.cpp b/llvm/tools/llvm-readobj/ObjDumper.cpp index 1a535ede07096..bd670aeab9ed8 100644 --- a/llvm/tools/llvm-readobj/ObjDumper.cpp +++ b/llvm/tools/llvm-readobj/ObjDumper.cpp @@ -102,9 +102,9 @@ void ObjDumper::printFileSummary(StringRef FileStr, object::ObjectFile &Obj, this->printLoadName(); } -static std::vector -getSectionRefsByNameOrIndex(const object::ObjectFile &Obj, - ArrayRef Sections) { +std::vector +ObjDumper::getSectionRefsByNameOrIndex(const object::ObjectFile &Obj, + ArrayRef Sections) { std::vector Ret; std::map> SecNames; std::map SecIndices; diff --git a/llvm/tools/llvm-readobj/ObjDumper.h b/llvm/tools/llvm-readobj/ObjDumper.h index a76afbe9c88c7..1dc29661f7178 100644 --- a/llvm/tools/llvm-readobj/ObjDumper.h +++ b/llvm/tools/llvm-readobj/ObjDumper.h @@ -139,6 +139,7 @@ class ObjDumper { virtual void printSectionDetails() {} virtual void printArchSpecificInfo() {} virtual void printMemtag() {} + virtual void printSectionsAsSFrame(ArrayRef Sections) {} // Only implemented for PE/COFF. virtual void printCOFFImports() { } @@ -190,6 +191,10 @@ class ObjDumper { protected: ScopedPrinter &W; + static std::vector + getSectionRefsByNameOrIndex(const object::ObjectFile &Obj, + ArrayRef Sections); + private: virtual void printSymbols(bool ExtraSymInfo) {} virtual void printSymbols(std::optional Comp) {} diff --git a/llvm/tools/llvm-readobj/Opts.td b/llvm/tools/llvm-readobj/Opts.td index f95461aaca1a7..48d43cc635a4f 100644 --- a/llvm/tools/llvm-readobj/Opts.td +++ b/llvm/tools/llvm-readobj/Opts.td @@ -62,6 +62,8 @@ def memtag : FF<"memtag", "Display memory tagging metadata (modes, Android notes def needed_libs : FF<"needed-libs", "Display the needed libraries">, Group; def notes : FF<"notes", "Display notes">, Group; def program_headers : FF<"program-headers", "Display program headers">, Group; +def sframe_EQ : Joined<["--"], "sframe=">, HelpText<"Display SFrame section ">, MetaVarName<"">, Group; +def sframe: FF<"sframe", "Alias for --sframe=.sframe">, Alias, AliasArgs<[".sframe"]>, Group; def version_info : FF<"version-info", "Display version sections">, Group; // Mach-O specific options. diff --git a/llvm/tools/llvm-readobj/llvm-readobj.cpp b/llvm/tools/llvm-readobj/llvm-readobj.cpp index 1231c02035d1f..4c84ed701bb9a 100644 --- a/llvm/tools/llvm-readobj/llvm-readobj.cpp +++ b/llvm/tools/llvm-readobj/llvm-readobj.cpp @@ -137,6 +137,7 @@ static bool NeededLibraries; static bool Notes; static bool ProgramHeaders; static bool SectionGroups; +static std::vector SFrame; static bool VersionInfo; // Mach-O specific options. @@ -275,6 +276,7 @@ static void parseOptions(const opt::InputArgList &Args) { opts::PrettyPrint = Args.hasArg(OPT_pretty_print); opts::ProgramHeaders = Args.hasArg(OPT_program_headers); opts::SectionGroups = Args.hasArg(OPT_section_groups); + opts::SFrame = Args.getAllArgValues(OPT_sframe_EQ); if (Arg *A = Args.getLastArg(OPT_sort_symbols_EQ)) { for (StringRef KeyStr : llvm::split(A->getValue(), ",")) { SortSymbolKeyTy KeyType = StringSwitch(KeyStr) @@ -478,6 +480,8 @@ static void dumpObject(ObjectFile &Obj, ScopedPrinter &Writer, Dumper->printNotes(); if (opts::Memtag) Dumper->printMemtag(); + if (!opts::SFrame.empty()) + Dumper->printSectionsAsSFrame(opts::SFrame); } if (Obj.isCOFF()) { if (opts::COFFImports)