diff options
Diffstat (limited to 'tools/llvm-readobj')
| -rw-r--r-- | tools/llvm-readobj/ARMEHABIPrinter.h | 141 | ||||
| -rw-r--r-- | tools/llvm-readobj/CMakeLists.txt | 5 | ||||
| -rw-r--r-- | tools/llvm-readobj/COFFDumper.cpp | 46 | ||||
| -rw-r--r-- | tools/llvm-readobj/COFFImportDumper.cpp | 3 | ||||
| -rw-r--r-- | tools/llvm-readobj/ELFDumper.cpp | 476 | ||||
| -rw-r--r-- | tools/llvm-readobj/ObjDumper.h | 16 | ||||
| -rw-r--r-- | tools/llvm-readobj/WasmDumper.cpp | 23 | ||||
| -rw-r--r-- | tools/llvm-readobj/WindowsResourceDumper.cpp | 82 | ||||
| -rw-r--r-- | tools/llvm-readobj/WindowsResourceDumper.h | 37 | ||||
| -rw-r--r-- | tools/llvm-readobj/llvm-readobj.cpp | 34 |
10 files changed, 586 insertions, 277 deletions
diff --git a/tools/llvm-readobj/ARMEHABIPrinter.h b/tools/llvm-readobj/ARMEHABIPrinter.h index 903a246ccfd8f..4417aa60fe903 100644 --- a/tools/llvm-readobj/ARMEHABIPrinter.h +++ b/tools/llvm-readobj/ARMEHABIPrinter.h @@ -35,7 +35,7 @@ class OpcodeDecoder { uint8_t Value; void (OpcodeDecoder::*Routine)(const uint8_t *Opcodes, unsigned &OI); }; - static const RingEntry Ring[]; + static ArrayRef<RingEntry> ring(); void Decode_00xxxxxx(const uint8_t *Opcodes, unsigned &OI); void Decode_01xxxxxx(const uint8_t *Opcodes, unsigned &OI); @@ -68,43 +68,48 @@ public: void Decode(const uint8_t *Opcodes, off_t Offset, size_t Length); }; -const OpcodeDecoder::RingEntry OpcodeDecoder::Ring[] = { - { 0xc0, 0x00, &OpcodeDecoder::Decode_00xxxxxx }, - { 0xc0, 0x40, &OpcodeDecoder::Decode_01xxxxxx }, - { 0xf0, 0x80, &OpcodeDecoder::Decode_1000iiii_iiiiiiii }, - { 0xff, 0x9d, &OpcodeDecoder::Decode_10011101 }, - { 0xff, 0x9f, &OpcodeDecoder::Decode_10011111 }, - { 0xf0, 0x90, &OpcodeDecoder::Decode_1001nnnn }, - { 0xf8, 0xa0, &OpcodeDecoder::Decode_10100nnn }, - { 0xf8, 0xa8, &OpcodeDecoder::Decode_10101nnn }, - { 0xff, 0xb0, &OpcodeDecoder::Decode_10110000 }, - { 0xff, 0xb1, &OpcodeDecoder::Decode_10110001_0000iiii }, - { 0xff, 0xb2, &OpcodeDecoder::Decode_10110010_uleb128 }, - { 0xff, 0xb3, &OpcodeDecoder::Decode_10110011_sssscccc }, - { 0xfc, 0xb4, &OpcodeDecoder::Decode_101101nn }, - { 0xf8, 0xb8, &OpcodeDecoder::Decode_10111nnn }, - { 0xff, 0xc6, &OpcodeDecoder::Decode_11000110_sssscccc }, - { 0xff, 0xc7, &OpcodeDecoder::Decode_11000111_0000iiii }, - { 0xff, 0xc8, &OpcodeDecoder::Decode_11001000_sssscccc }, - { 0xff, 0xc9, &OpcodeDecoder::Decode_11001001_sssscccc }, - { 0xc8, 0xc8, &OpcodeDecoder::Decode_11001yyy }, - { 0xf8, 0xc0, &OpcodeDecoder::Decode_11000nnn }, - { 0xf8, 0xd0, &OpcodeDecoder::Decode_11010nnn }, - { 0xc0, 0xc0, &OpcodeDecoder::Decode_11xxxyyy }, -}; +inline ArrayRef<OpcodeDecoder::RingEntry> OpcodeDecoder::ring() { + static const OpcodeDecoder::RingEntry Ring[] = { + {0xc0, 0x00, &OpcodeDecoder::Decode_00xxxxxx}, + {0xc0, 0x40, &OpcodeDecoder::Decode_01xxxxxx}, + {0xf0, 0x80, &OpcodeDecoder::Decode_1000iiii_iiiiiiii}, + {0xff, 0x9d, &OpcodeDecoder::Decode_10011101}, + {0xff, 0x9f, &OpcodeDecoder::Decode_10011111}, + {0xf0, 0x90, &OpcodeDecoder::Decode_1001nnnn}, + {0xf8, 0xa0, &OpcodeDecoder::Decode_10100nnn}, + {0xf8, 0xa8, &OpcodeDecoder::Decode_10101nnn}, + {0xff, 0xb0, &OpcodeDecoder::Decode_10110000}, + {0xff, 0xb1, &OpcodeDecoder::Decode_10110001_0000iiii}, + {0xff, 0xb2, &OpcodeDecoder::Decode_10110010_uleb128}, + {0xff, 0xb3, &OpcodeDecoder::Decode_10110011_sssscccc}, + {0xfc, 0xb4, &OpcodeDecoder::Decode_101101nn}, + {0xf8, 0xb8, &OpcodeDecoder::Decode_10111nnn}, + {0xff, 0xc6, &OpcodeDecoder::Decode_11000110_sssscccc}, + {0xff, 0xc7, &OpcodeDecoder::Decode_11000111_0000iiii}, + {0xff, 0xc8, &OpcodeDecoder::Decode_11001000_sssscccc}, + {0xff, 0xc9, &OpcodeDecoder::Decode_11001001_sssscccc}, + {0xc8, 0xc8, &OpcodeDecoder::Decode_11001yyy}, + {0xf8, 0xc0, &OpcodeDecoder::Decode_11000nnn}, + {0xf8, 0xd0, &OpcodeDecoder::Decode_11010nnn}, + {0xc0, 0xc0, &OpcodeDecoder::Decode_11xxxyyy}, + }; + return makeArrayRef(Ring); +} -void OpcodeDecoder::Decode_00xxxxxx(const uint8_t *Opcodes, unsigned &OI) { +inline void OpcodeDecoder::Decode_00xxxxxx(const uint8_t *Opcodes, + unsigned &OI) { uint8_t Opcode = Opcodes[OI++ ^ 3]; SW.startLine() << format("0x%02X ; vsp = vsp + %u\n", Opcode, ((Opcode & 0x3f) << 2) + 4); } -void OpcodeDecoder::Decode_01xxxxxx(const uint8_t *Opcodes, unsigned &OI) { +inline void OpcodeDecoder::Decode_01xxxxxx(const uint8_t *Opcodes, + unsigned &OI) { uint8_t Opcode = Opcodes[OI++ ^ 3]; SW.startLine() << format("0x%02X ; vsp = vsp - %u\n", Opcode, ((Opcode & 0x3f) << 2) + 4); } -void OpcodeDecoder::Decode_1000iiii_iiiiiiii(const uint8_t *Opcodes, - unsigned &OI) { +inline void OpcodeDecoder::Decode_1000iiii_iiiiiiii(const uint8_t *Opcodes, + unsigned &OI) { uint8_t Opcode0 = Opcodes[OI++ ^ 3]; uint8_t Opcode1 = Opcodes[OI++ ^ 3]; @@ -116,36 +121,42 @@ void OpcodeDecoder::Decode_1000iiii_iiiiiiii(const uint8_t *Opcodes, PrintGPR(GPRMask); OS << '\n'; } -void OpcodeDecoder::Decode_10011101(const uint8_t *Opcodes, unsigned &OI) { +inline void OpcodeDecoder::Decode_10011101(const uint8_t *Opcodes, + unsigned &OI) { uint8_t Opcode = Opcodes[OI++ ^ 3]; SW.startLine() << format("0x%02X ; reserved (ARM MOVrr)\n", Opcode); } -void OpcodeDecoder::Decode_10011111(const uint8_t *Opcodes, unsigned &OI) { +inline void OpcodeDecoder::Decode_10011111(const uint8_t *Opcodes, + unsigned &OI) { uint8_t Opcode = Opcodes[OI++ ^ 3]; SW.startLine() << format("0x%02X ; reserved (WiMMX MOVrr)\n", Opcode); } -void OpcodeDecoder::Decode_1001nnnn(const uint8_t *Opcodes, unsigned &OI) { +inline void OpcodeDecoder::Decode_1001nnnn(const uint8_t *Opcodes, + unsigned &OI) { uint8_t Opcode = Opcodes[OI++ ^ 3]; SW.startLine() << format("0x%02X ; vsp = r%u\n", Opcode, (Opcode & 0x0f)); } -void OpcodeDecoder::Decode_10100nnn(const uint8_t *Opcodes, unsigned &OI) { +inline void OpcodeDecoder::Decode_10100nnn(const uint8_t *Opcodes, + unsigned &OI) { uint8_t Opcode = Opcodes[OI++ ^ 3]; SW.startLine() << format("0x%02X ; pop ", Opcode); PrintGPR((((1 << ((Opcode & 0x7) + 1)) - 1) << 4)); OS << '\n'; } -void OpcodeDecoder::Decode_10101nnn(const uint8_t *Opcodes, unsigned &OI) { +inline void OpcodeDecoder::Decode_10101nnn(const uint8_t *Opcodes, + unsigned &OI) { uint8_t Opcode = Opcodes[OI++ ^ 3]; SW.startLine() << format("0x%02X ; pop ", Opcode); PrintGPR((((1 << ((Opcode & 0x7) + 1)) - 1) << 4) | (1 << 14)); OS << '\n'; } -void OpcodeDecoder::Decode_10110000(const uint8_t *Opcodes, unsigned &OI) { +inline void OpcodeDecoder::Decode_10110000(const uint8_t *Opcodes, + unsigned &OI) { uint8_t Opcode = Opcodes[OI++ ^ 3]; SW.startLine() << format("0x%02X ; finish\n", Opcode); } -void OpcodeDecoder::Decode_10110001_0000iiii(const uint8_t *Opcodes, - unsigned &OI) { +inline void OpcodeDecoder::Decode_10110001_0000iiii(const uint8_t *Opcodes, + unsigned &OI) { uint8_t Opcode0 = Opcodes[OI++ ^ 3]; uint8_t Opcode1 = Opcodes[OI++ ^ 3]; @@ -156,8 +167,8 @@ void OpcodeDecoder::Decode_10110001_0000iiii(const uint8_t *Opcodes, PrintGPR((Opcode1 & 0x0f)); OS << '\n'; } -void OpcodeDecoder::Decode_10110010_uleb128(const uint8_t *Opcodes, - unsigned &OI) { +inline void OpcodeDecoder::Decode_10110010_uleb128(const uint8_t *Opcodes, + unsigned &OI) { uint8_t Opcode = Opcodes[OI++ ^ 3]; SW.startLine() << format("0x%02X ", Opcode); @@ -173,8 +184,8 @@ void OpcodeDecoder::Decode_10110010_uleb128(const uint8_t *Opcodes, OS << format("; vsp = vsp + %" PRIu64 "\n", 0x204 + (Value << 2)); } -void OpcodeDecoder::Decode_10110011_sssscccc(const uint8_t *Opcodes, - unsigned &OI) { +inline void OpcodeDecoder::Decode_10110011_sssscccc(const uint8_t *Opcodes, + unsigned &OI) { uint8_t Opcode0 = Opcodes[OI++ ^ 3]; uint8_t Opcode1 = Opcodes[OI++ ^ 3]; SW.startLine() << format("0x%02X 0x%02X ; pop ", Opcode0, Opcode1); @@ -183,18 +194,20 @@ void OpcodeDecoder::Decode_10110011_sssscccc(const uint8_t *Opcodes, PrintRegisters((((1 << (Count + 1)) - 1) << Start), "d"); OS << '\n'; } -void OpcodeDecoder::Decode_101101nn(const uint8_t *Opcodes, unsigned &OI) { +inline void OpcodeDecoder::Decode_101101nn(const uint8_t *Opcodes, + unsigned &OI) { uint8_t Opcode = Opcodes[OI++ ^ 3]; SW.startLine() << format("0x%02X ; spare\n", Opcode); } -void OpcodeDecoder::Decode_10111nnn(const uint8_t *Opcodes, unsigned &OI) { +inline void OpcodeDecoder::Decode_10111nnn(const uint8_t *Opcodes, + unsigned &OI) { uint8_t Opcode = Opcodes[OI++ ^ 3]; SW.startLine() << format("0x%02X ; pop ", Opcode); PrintRegisters((((1 << ((Opcode & 0x07) + 1)) - 1) << 8), "d"); OS << '\n'; } -void OpcodeDecoder::Decode_11000110_sssscccc(const uint8_t *Opcodes, - unsigned &OI) { +inline void OpcodeDecoder::Decode_11000110_sssscccc(const uint8_t *Opcodes, + unsigned &OI) { uint8_t Opcode0 = Opcodes[OI++ ^ 3]; uint8_t Opcode1 = Opcodes[OI++ ^ 3]; SW.startLine() << format("0x%02X 0x%02X ; pop ", Opcode0, Opcode1); @@ -203,8 +216,8 @@ void OpcodeDecoder::Decode_11000110_sssscccc(const uint8_t *Opcodes, PrintRegisters((((1 << (Count + 1)) - 1) << Start), "wR"); OS << '\n'; } -void OpcodeDecoder::Decode_11000111_0000iiii(const uint8_t *Opcodes, - unsigned &OI) { +inline void OpcodeDecoder::Decode_11000111_0000iiii(const uint8_t *Opcodes, + unsigned &OI) { uint8_t Opcode0 = Opcodes[OI++ ^ 3]; uint8_t Opcode1 = Opcodes[OI++ ^ 3]; SW.startLine() @@ -214,8 +227,8 @@ void OpcodeDecoder::Decode_11000111_0000iiii(const uint8_t *Opcodes, PrintRegisters(Opcode1 & 0x0f, "wCGR"); OS << '\n'; } -void OpcodeDecoder::Decode_11001000_sssscccc(const uint8_t *Opcodes, - unsigned &OI) { +inline void OpcodeDecoder::Decode_11001000_sssscccc(const uint8_t *Opcodes, + unsigned &OI) { uint8_t Opcode0 = Opcodes[OI++ ^ 3]; uint8_t Opcode1 = Opcodes[OI++ ^ 3]; SW.startLine() << format("0x%02X 0x%02X ; pop ", Opcode0, Opcode1); @@ -224,8 +237,8 @@ void OpcodeDecoder::Decode_11001000_sssscccc(const uint8_t *Opcodes, PrintRegisters((((1 << (Count + 1)) - 1) << Start), "d"); OS << '\n'; } -void OpcodeDecoder::Decode_11001001_sssscccc(const uint8_t *Opcodes, - unsigned &OI) { +inline void OpcodeDecoder::Decode_11001001_sssscccc(const uint8_t *Opcodes, + unsigned &OI) { uint8_t Opcode0 = Opcodes[OI++ ^ 3]; uint8_t Opcode1 = Opcodes[OI++ ^ 3]; SW.startLine() << format("0x%02X 0x%02X ; pop ", Opcode0, Opcode1); @@ -234,28 +247,32 @@ void OpcodeDecoder::Decode_11001001_sssscccc(const uint8_t *Opcodes, PrintRegisters((((1 << (Count + 1)) - 1) << Start), "d"); OS << '\n'; } -void OpcodeDecoder::Decode_11001yyy(const uint8_t *Opcodes, unsigned &OI) { +inline void OpcodeDecoder::Decode_11001yyy(const uint8_t *Opcodes, + unsigned &OI) { uint8_t Opcode = Opcodes[OI++ ^ 3]; SW.startLine() << format("0x%02X ; spare\n", Opcode); } -void OpcodeDecoder::Decode_11000nnn(const uint8_t *Opcodes, unsigned &OI) { +inline void OpcodeDecoder::Decode_11000nnn(const uint8_t *Opcodes, + unsigned &OI) { uint8_t Opcode = Opcodes[OI++ ^ 3]; SW.startLine() << format("0x%02X ; pop ", Opcode); PrintRegisters((((1 << ((Opcode & 0x07) + 1)) - 1) << 10), "wR"); OS << '\n'; } -void OpcodeDecoder::Decode_11010nnn(const uint8_t *Opcodes, unsigned &OI) { +inline void OpcodeDecoder::Decode_11010nnn(const uint8_t *Opcodes, + unsigned &OI) { uint8_t Opcode = Opcodes[OI++ ^ 3]; SW.startLine() << format("0x%02X ; pop ", Opcode); PrintRegisters((((1 << ((Opcode & 0x07) + 1)) - 1) << 8), "d"); OS << '\n'; } -void OpcodeDecoder::Decode_11xxxyyy(const uint8_t *Opcodes, unsigned &OI) { +inline void OpcodeDecoder::Decode_11xxxyyy(const uint8_t *Opcodes, + unsigned &OI) { uint8_t Opcode = Opcodes[OI++ ^ 3]; SW.startLine() << format("0x%02X ; spare\n", Opcode); } -void OpcodeDecoder::PrintGPR(uint16_t GPRMask) { +inline void OpcodeDecoder::PrintGPR(uint16_t GPRMask) { static const char *GPRRegisterNames[16] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "fp", "ip", "sp", "lr", "pc" @@ -274,7 +291,7 @@ void OpcodeDecoder::PrintGPR(uint16_t GPRMask) { OS << '}'; } -void OpcodeDecoder::PrintRegisters(uint32_t VFPMask, StringRef Prefix) { +inline void OpcodeDecoder::PrintRegisters(uint32_t VFPMask, StringRef Prefix) { OS << '{'; bool Comma = false; for (unsigned RI = 0, RE = 32; RI < RE; ++RI) { @@ -288,13 +305,13 @@ void OpcodeDecoder::PrintRegisters(uint32_t VFPMask, StringRef Prefix) { OS << '}'; } -void OpcodeDecoder::Decode(const uint8_t *Opcodes, off_t Offset, size_t Length) { +inline void OpcodeDecoder::Decode(const uint8_t *Opcodes, off_t Offset, + size_t Length) { for (unsigned OCI = Offset; OCI < Length + Offset; ) { bool Decoded = false; - for (unsigned REI = 0, REE = array_lengthof(Ring); - REI != REE && !Decoded; ++REI) { - if ((Opcodes[OCI ^ 3] & Ring[REI].Mask) == Ring[REI].Value) { - (this->*Ring[REI].Routine)(Opcodes, OCI); + for (const auto &RE : ring()) { + if ((Opcodes[OCI ^ 3] & RE.Mask) == RE.Value) { + (this->*RE.Routine)(Opcodes, OCI); Decoded = true; break; } diff --git a/tools/llvm-readobj/CMakeLists.txt b/tools/llvm-readobj/CMakeLists.txt index f5b1a5b256add..dafc9e10cfa12 100644 --- a/tools/llvm-readobj/CMakeLists.txt +++ b/tools/llvm-readobj/CMakeLists.txt @@ -19,6 +19,11 @@ add_llvm_tool(llvm-readobj ObjDumper.cpp WasmDumper.cpp Win64EHDumper.cpp + WindowsResourceDumper.cpp ) add_llvm_tool_symlink(llvm-readelf llvm-readobj) + +if(LLVM_INSTALL_BINUTILS_SYMLINKS) + add_llvm_tool_symlink(readelf llvm-readobj) +endif() diff --git a/tools/llvm-readobj/COFFDumper.cpp b/tools/llvm-readobj/COFFDumper.cpp index 74c44116b1270..8ac9f1a51cc55 100644 --- a/tools/llvm-readobj/COFFDumper.cpp +++ b/tools/llvm-readobj/COFFDumper.cpp @@ -31,16 +31,16 @@ #include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h" #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" #include "llvm/DebugInfo/CodeView/Line.h" +#include "llvm/DebugInfo/CodeView/MergingTypeTableBuilder.h" #include "llvm/DebugInfo/CodeView/RecordSerialization.h" -#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" #include "llvm/DebugInfo/CodeView/SymbolDumpDelegate.h" #include "llvm/DebugInfo/CodeView/SymbolDumper.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h" #include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h" +#include "llvm/DebugInfo/CodeView/TypeHashing.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/CodeView/TypeStreamMerger.h" -#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h" #include "llvm/DebugInfo/CodeView/TypeTableCollection.h" #include "llvm/Object/COFF.h" #include "llvm/Object/ObjectFile.h" @@ -48,17 +48,10 @@ #include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ConvertUTF.h" -#include "llvm/Support/DataExtractor.h" #include "llvm/Support/FormatVariadic.h" -#include "llvm/Support/Path.h" #include "llvm/Support/ScopedPrinter.h" -#include "llvm/Support/SourceMgr.h" #include "llvm/Support/Win64EH.h" #include "llvm/Support/raw_ostream.h" -#include <algorithm> -#include <cstring> -#include <system_error> -#include <time.h> using namespace llvm; using namespace llvm::object; @@ -96,8 +89,9 @@ public: void printCOFFResources() override; void printCOFFLoadConfig() override; void printCodeViewDebugInfo() override; - void mergeCodeViewTypes(llvm::codeview::TypeTableBuilder &CVIDs, - llvm::codeview::TypeTableBuilder &CVTypes) override; + void + mergeCodeViewTypes(llvm::codeview::MergingTypeTableBuilder &CVIDs, + llvm::codeview::MergingTypeTableBuilder &CVTypes) override; void printStackMap() const override; private: void printSymbol(const SymbolRef &Sym); @@ -1194,8 +1188,8 @@ void COFFDumper::printFileNameForOffset(StringRef Label, uint32_t FileOffset) { W.printHex(Label, getFileNameForFileOffset(FileOffset), FileOffset); } -void COFFDumper::mergeCodeViewTypes(TypeTableBuilder &CVIDs, - TypeTableBuilder &CVTypes) { +void COFFDumper::mergeCodeViewTypes(MergingTypeTableBuilder &CVIDs, + MergingTypeTableBuilder &CVTypes) { for (const SectionRef &S : Obj->sections()) { StringRef SectionName; error(S.getName(SectionName)); @@ -1423,9 +1417,9 @@ void COFFDumper::printSymbol(const SymbolRef &Sym) { const coff_aux_weak_external *Aux; error(getSymbolAuxData(Obj, Symbol, I, Aux)); - ErrorOr<COFFSymbolRef> Linked = Obj->getSymbol(Aux->TagIndex); + Expected<COFFSymbolRef> Linked = Obj->getSymbol(Aux->TagIndex); StringRef LinkedName; - std::error_code EC = Linked.getError(); + std::error_code EC = errorToErrorCode(Linked.takeError()); if (EC || (EC = Obj->getSymbolName(*Linked, LinkedName))) { LinkedName = ""; error(EC); @@ -1481,10 +1475,10 @@ void COFFDumper::printSymbol(const SymbolRef &Sym) { const coff_aux_clr_token *Aux; error(getSymbolAuxData(Obj, Symbol, I, Aux)); - ErrorOr<COFFSymbolRef> ReferredSym = + Expected<COFFSymbolRef> ReferredSym = Obj->getSymbol(Aux->SymbolTableIndex); StringRef ReferredName; - std::error_code EC = ReferredSym.getError(); + std::error_code EC = errorToErrorCode(ReferredSym.takeError()); if (EC || (EC = Obj->getSymbolName(*ReferredSym, ReferredName))) { ReferredName = ""; error(EC); @@ -1627,7 +1621,7 @@ void COFFDumper::printCOFFDirectives() { } } -static StringRef getBaseRelocTypeName(uint8_t Type) { +static std::string getBaseRelocTypeName(uint8_t Type) { switch (Type) { case COFF::IMAGE_REL_BASED_ABSOLUTE: return "ABSOLUTE"; case COFF::IMAGE_REL_BASED_HIGH: return "HIGH"; @@ -1636,11 +1630,7 @@ static StringRef getBaseRelocTypeName(uint8_t Type) { case COFF::IMAGE_REL_BASED_HIGHADJ: return "HIGHADJ"; case COFF::IMAGE_REL_BASED_ARM_MOV32T: return "ARM_MOV32(T)"; case COFF::IMAGE_REL_BASED_DIR64: return "DIR64"; - default: { - static std::string Result; - Result = "unknown (" + llvm::utostr(Type) + ")"; - return Result; - } + default: return "unknown (" + llvm::utostr(Type) + ")"; } } @@ -1807,13 +1797,13 @@ void COFFDumper::printStackMap() const { StackMapV2Parser<support::big>(StackMapContentsArray)); } -void llvm::dumpCodeViewMergedTypes(ScopedPrinter &Writer, - llvm::codeview::TypeTableBuilder &IDTable, - llvm::codeview::TypeTableBuilder &CVTypes) { +void llvm::dumpCodeViewMergedTypes( + ScopedPrinter &Writer, llvm::codeview::MergingTypeTableBuilder &IDTable, + llvm::codeview::MergingTypeTableBuilder &CVTypes) { // Flatten it first, then run our dumper on it. SmallString<0> TypeBuf; - CVTypes.ForEachRecord([&](TypeIndex TI, ArrayRef<uint8_t> Record) { - TypeBuf.append(Record.begin(), Record.end()); + CVTypes.ForEachRecord([&](TypeIndex TI, const CVType &Record) { + TypeBuf.append(Record.RecordData.begin(), Record.RecordData.end()); }); TypeTableCollection TpiTypes(CVTypes.records()); diff --git a/tools/llvm-readobj/COFFImportDumper.cpp b/tools/llvm-readobj/COFFImportDumper.cpp index c5b8bf7584627..3b546b3ef508b 100644 --- a/tools/llvm-readobj/COFFImportDumper.cpp +++ b/tools/llvm-readobj/COFFImportDumper.cpp @@ -12,9 +12,6 @@ /// //===----------------------------------------------------------------------===// -#include "Error.h" -#include "ObjDumper.h" -#include "llvm-readobj.h" #include "llvm/BinaryFormat/COFF.h" #include "llvm/Object/COFF.h" #include "llvm/Object/COFFImportFile.h" diff --git a/tools/llvm-readobj/ELFDumper.cpp b/tools/llvm-readobj/ELFDumper.cpp index 5698420bbcc23..9678667abffe8 100644 --- a/tools/llvm-readobj/ELFDumper.cpp +++ b/tools/llvm-readobj/ELFDumper.cpp @@ -18,6 +18,7 @@ #include "StackMapPrinter.h" #include "llvm-readobj.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/SmallString.h" @@ -33,6 +34,7 @@ #include "llvm/Object/Error.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Object/StackMapParser.h" +#include "llvm/Support/AMDGPUMetadata.h" #include "llvm/Support/ARMAttributeParser.h" #include "llvm/Support/ARMBuildAttributes.h" #include "llvm/Support/Casting.h" @@ -155,8 +157,6 @@ public: void printMipsReginfo() override; void printMipsOptions() override; - void printAMDGPUCodeObjectMetadata() override; - void printStackMap() const override; void printHashHistogram() override; @@ -820,12 +820,24 @@ static const EnumEntry<unsigned> ElfOSABI[] = { {"AROS", "AROS", ELF::ELFOSABI_AROS}, {"FenixOS", "FenixOS", ELF::ELFOSABI_FENIXOS}, {"CloudABI", "CloudABI", ELF::ELFOSABI_CLOUDABI}, - {"C6000_ELFABI", "Bare-metal C6000", ELF::ELFOSABI_C6000_ELFABI}, - {"C6000_LINUX", "Linux C6000", ELF::ELFOSABI_C6000_LINUX}, - {"ARM", "ARM", ELF::ELFOSABI_ARM}, {"Standalone", "Standalone App", ELF::ELFOSABI_STANDALONE} }; +static const EnumEntry<unsigned> AMDGPUElfOSABI[] = { + {"AMDGPU_HSA", "AMDGPU - HSA", ELF::ELFOSABI_AMDGPU_HSA}, + {"AMDGPU_PAL", "AMDGPU - PAL", ELF::ELFOSABI_AMDGPU_PAL}, + {"AMDGPU_MESA3D", "AMDGPU - MESA3D", ELF::ELFOSABI_AMDGPU_MESA3D} +}; + +static const EnumEntry<unsigned> ARMElfOSABI[] = { + {"ARM", "ARM", ELF::ELFOSABI_ARM} +}; + +static const EnumEntry<unsigned> C6000ElfOSABI[] = { + {"C6000_ELFABI", "Bare-metal C6000", ELF::ELFOSABI_C6000_ELFABI}, + {"C6000_LINUX", "Linux C6000", ELF::ELFOSABI_C6000_LINUX} +}; + static const EnumEntry<unsigned> ElfMachineType[] = { ENUM_ENT(EM_NONE, "None"), ENUM_ENT(EM_M32, "WE32100"), @@ -967,7 +979,7 @@ static const EnumEntry<unsigned> ElfMachineType[] = { ENUM_ENT(EM_L10M, "EM_L10M"), ENUM_ENT(EM_K10M, "EM_K10M"), ENUM_ENT(EM_AARCH64, "AArch64"), - ENUM_ENT(EM_AVR32, "Atmel AVR 8-bit microcontroller"), + ENUM_ENT(EM_AVR32, "Atmel Corporation 32-bit microprocessor family"), ENUM_ENT(EM_STM8, "STMicroeletronics STM8 8-bit microcontroller"), ENUM_ENT(EM_TILE64, "Tilera TILE64 multicore architecture family"), ENUM_ENT(EM_TILEPRO, "Tilera TILEPro multicore architecture family"), @@ -1231,6 +1243,20 @@ static const EnumEntry<unsigned> ElfHeaderMipsFlags[] = { LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ARCH_64R6) }; +static const EnumEntry<unsigned> ElfHeaderAMDGPUFlags[] = { + LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_ARCH_NONE), + LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_ARCH_R600), + LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_ARCH_GCN) +}; + +static const EnumEntry<unsigned> ElfHeaderRISCVFlags[] = { + LLVM_READOBJ_ENUM_ENT(ELF, EF_RISCV_RVC), + LLVM_READOBJ_ENUM_ENT(ELF, EF_RISCV_FLOAT_ABI_SINGLE), + LLVM_READOBJ_ENUM_ENT(ELF, EF_RISCV_FLOAT_ABI_DOUBLE), + LLVM_READOBJ_ENUM_ENT(ELF, EF_RISCV_FLOAT_ABI_QUAD), + LLVM_READOBJ_ENUM_ENT(ELF, EF_RISCV_RVE) +}; + static const EnumEntry<unsigned> ElfSymOtherFlags[] = { LLVM_READOBJ_ENUM_ENT(ELF, STV_INTERNAL), LLVM_READOBJ_ENUM_ENT(ELF, STV_HIDDEN), @@ -1287,15 +1313,16 @@ ELFDumper<ELFT>::ELFDumper(const ELFFile<ELFT> *Obj, ScopedPrinter &Writer) switch (Sec.sh_type) { case ELF::SHT_SYMTAB: if (DotSymtabSec != nullptr) - reportError("Multilpe SHT_SYMTAB"); + reportError("Multiple SHT_SYMTAB"); DotSymtabSec = &Sec; break; case ELF::SHT_DYNSYM: if (DynSymRegion.Size) - reportError("Multilpe SHT_DYNSYM"); + reportError("Multiple SHT_DYNSYM"); DynSymRegion = createDRIFrom(&Sec); // This is only used (if Elf_Shdr present)for naming section in GNU style DynSymtabName = unwrapOrError(Obj->getSectionName(&Sec)); + DynamicStringTable = unwrapOrError(Obj->getStringTableForSymtab(Sec)); break; case ELF::SHT_SYMTAB_SHNDX: ShndxTable = unwrapOrError(Obj->getSHNDXTable(Sec)); @@ -1312,7 +1339,7 @@ ELFDumper<ELFT>::ELFDumper(const ELFFile<ELFT> *Obj, ScopedPrinter &Writer) break; case ELF::SHT_GNU_verneed: if (dot_gnu_version_r_sec != nullptr) - reportError("Multilpe SHT_GNU_verneed"); + reportError("Multiple SHT_GNU_verneed"); dot_gnu_version_r_sec = &Sec; break; } @@ -1330,8 +1357,11 @@ template <typename ELFT> void ELFDumper<ELFT>::parseDynamicTable( ArrayRef<const Elf_Phdr *> LoadSegments) { auto toMappedAddr = [&](uint64_t VAddr) -> const uint8_t * { - const Elf_Phdr *const *I = std::upper_bound( - LoadSegments.begin(), LoadSegments.end(), VAddr, compareAddr<ELFT>); + const Elf_Phdr *const *I = + std::upper_bound(LoadSegments.begin(), LoadSegments.end(), VAddr, + [](uint64_t VAddr, const Elf_Phdr_Impl<ELFT> *Phdr) { + return VAddr < Phdr->p_vaddr; + }); if (I == LoadSegments.begin()) report_fatal_error("Virtual address is not in any segment"); --I; @@ -1487,6 +1517,10 @@ static const char *getTypeString(unsigned Arch, uint64_t Type) { } } switch (Type) { + LLVM_READOBJ_TYPE_CASE(ANDROID_REL); + LLVM_READOBJ_TYPE_CASE(ANDROID_RELSZ); + LLVM_READOBJ_TYPE_CASE(ANDROID_RELA); + LLVM_READOBJ_TYPE_CASE(ANDROID_RELASZ); LLVM_READOBJ_TYPE_CASE(BIND_NOW); LLVM_READOBJ_TYPE_CASE(DEBUG); LLVM_READOBJ_TYPE_CASE(FINI); @@ -1689,6 +1723,8 @@ void ELFDumper<ELFT>::printValue(uint64_t Type, uint64_t Value) { case DT_INIT_ARRAYSZ: case DT_FINI_ARRAYSZ: case DT_PREINIT_ARRAYSZ: + case DT_ANDROID_RELSZ: + case DT_ANDROID_RELASZ: OS << Value << " (bytes)"; break; case DT_NEEDED: @@ -1874,6 +1910,7 @@ public: MipsGOTParser(ELFDumper<ELFT> *Dumper, const ELFO *Obj, Elf_Dyn_Range DynTable, ScopedPrinter &W); + void parseStaticGOT(); void parseGOT(); void parsePLT(); @@ -1890,11 +1927,12 @@ private: std::size_t getGOTTotal(ArrayRef<uint8_t> GOT) const; const GOTEntry *makeGOTIter(ArrayRef<uint8_t> GOT, std::size_t EntryNum); + void printLocalGOT(const Elf_Shdr *GOTShdr, size_t Num); void printGotEntry(uint64_t GotAddr, const GOTEntry *BeginIt, const GOTEntry *It); void printGlobalGotEntry(uint64_t GotAddr, const GOTEntry *BeginIt, const GOTEntry *It, const Elf_Sym *Sym, - StringRef StrTable, bool IsDynamic); + StringRef StrTable); void printPLTEntry(uint64_t PLTAddr, const GOTEntry *BeginIt, const GOTEntry *It, StringRef Purpose); void printPLTEntry(uint64_t PLTAddr, const GOTEntry *BeginIt, @@ -1929,6 +1967,50 @@ MipsGOTParser<ELFT>::MipsGOTParser(ELFDumper<ELFT> *Dumper, const ELFO *Obj, } } +template <class ELFT> +void MipsGOTParser<ELFT>::printLocalGOT(const Elf_Shdr *GOTShdr, size_t Num) { + ArrayRef<uint8_t> GOT = unwrapOrError(Obj->getSectionContents(GOTShdr)); + + const GOTEntry *GotBegin = makeGOTIter(GOT, 0); + const GOTEntry *GotEnd = makeGOTIter(GOT, Num); + const GOTEntry *It = GotBegin; + + W.printHex("Canonical gp value", GOTShdr->sh_addr + 0x7ff0); + { + ListScope RS(W, "Reserved entries"); + + { + DictScope D(W, "Entry"); + printGotEntry(GOTShdr->sh_addr, GotBegin, It++); + W.printString("Purpose", StringRef("Lazy resolver")); + } + + if (It != GotEnd && (*It >> (sizeof(GOTEntry) * 8 - 1)) != 0) { + DictScope D(W, "Entry"); + printGotEntry(GOTShdr->sh_addr, GotBegin, It++); + W.printString("Purpose", StringRef("Module pointer (GNU extension)")); + } + } + { + ListScope LS(W, "Local entries"); + for (; It != GotEnd; ++It) { + DictScope D(W, "Entry"); + printGotEntry(GOTShdr->sh_addr, GotBegin, It); + } + } +} + +template <class ELFT> void MipsGOTParser<ELFT>::parseStaticGOT() { + const Elf_Shdr *GOTShdr = findSectionByName(*Obj, ".got"); + if (!GOTShdr) { + W.startLine() << "Cannot find .got section.\n"; + return; + } + + DictScope GS(W, "Static GOT"); + printLocalGOT(GOTShdr, GOTShdr->sh_size / sizeof(GOTEntry)); +} + template <class ELFT> void MipsGOTParser<ELFT>::parseGOT() { // See "Global Offset Table" in Chapter 5 in the following document // for detailed GOT description. @@ -1946,10 +2028,7 @@ template <class ELFT> void MipsGOTParser<ELFT>::parseGOT() { return; } - StringRef StrTable = Dumper->getDynamicStringTable(); - const Elf_Sym *DynSymBegin = Dumper->dynamic_symbols().begin(); - const Elf_Sym *DynSymEnd = Dumper->dynamic_symbols().end(); - std::size_t DynSymTotal = std::size_t(std::distance(DynSymBegin, DynSymEnd)); + std::size_t DynSymTotal = Dumper->dynamic_symbols().size(); if (*DtGotSym > DynSymTotal) report_fatal_error("MIPS_GOTSYM exceeds a number of dynamic symbols"); @@ -1971,45 +2050,19 @@ template <class ELFT> void MipsGOTParser<ELFT>::parseGOT() { if (*DtLocalGotNum + GlobalGotNum > getGOTTotal(GOT)) report_fatal_error("Number of GOT entries exceeds the size of GOT section"); - const GOTEntry *GotBegin = makeGOTIter(GOT, 0); - const GOTEntry *GotLocalEnd = makeGOTIter(GOT, *DtLocalGotNum); - const GOTEntry *It = GotBegin; - DictScope GS(W, "Primary GOT"); + printLocalGOT(GOTShdr, *DtLocalGotNum); - W.printHex("Canonical gp value", GOTShdr->sh_addr + 0x7ff0); - { - ListScope RS(W, "Reserved entries"); - - { - DictScope D(W, "Entry"); - printGotEntry(GOTShdr->sh_addr, GotBegin, It++); - W.printString("Purpose", StringRef("Lazy resolver")); - } - - if (It != GotLocalEnd && (*It >> (sizeof(GOTEntry) * 8 - 1)) != 0) { - DictScope D(W, "Entry"); - printGotEntry(GOTShdr->sh_addr, GotBegin, It++); - W.printString("Purpose", StringRef("Module pointer (GNU extension)")); - } - } - { - ListScope LS(W, "Local entries"); - for (; It != GotLocalEnd; ++It) { - DictScope D(W, "Entry"); - printGotEntry(GOTShdr->sh_addr, GotBegin, It); - } - } { ListScope GS(W, "Global entries"); - const GOTEntry *GotGlobalEnd = - makeGOTIter(GOT, *DtLocalGotNum + GlobalGotNum); - const Elf_Sym *GotDynSym = DynSymBegin + *DtGotSym; - for (; It != GotGlobalEnd; ++It) { + const GOTEntry *GotBegin = makeGOTIter(GOT, 0); + const GOTEntry *GotEnd = makeGOTIter(GOT, *DtLocalGotNum + GlobalGotNum); + const Elf_Sym *GotDynSym = Dumper->dynamic_symbols().begin() + *DtGotSym; + for (auto It = makeGOTIter(GOT, *DtLocalGotNum); It != GotEnd; ++It) { DictScope D(W, "Entry"); - printGlobalGotEntry(GOTShdr->sh_addr, GotBegin, It, GotDynSym++, StrTable, - true); + printGlobalGotEntry(GOTShdr->sh_addr, GotBegin, It, GotDynSym++, + Dumper->getDynamicStringTable()); } } @@ -2101,9 +2154,11 @@ void MipsGOTParser<ELFT>::printGotEntry(uint64_t GotAddr, } template <class ELFT> -void MipsGOTParser<ELFT>::printGlobalGotEntry( - uint64_t GotAddr, const GOTEntry *BeginIt, const GOTEntry *It, - const Elf_Sym *Sym, StringRef StrTable, bool IsDynamic) { +void MipsGOTParser<ELFT>::printGlobalGotEntry(uint64_t GotAddr, + const GOTEntry *BeginIt, + const GOTEntry *It, + const Elf_Sym *Sym, + StringRef StrTable) { printGotEntry(GotAddr, BeginIt, It); W.printHex("Value", Sym->st_value); @@ -2115,8 +2170,7 @@ void MipsGOTParser<ELFT>::printGlobalGotEntry( Dumper->getShndxTable(), SectionName, SectionIndex); W.printHex("Section", SectionName, SectionIndex); - std::string FullSymbolName = - Dumper->getFullSymbolName(Sym, StrTable, IsDynamic); + std::string FullSymbolName = Dumper->getFullSymbolName(Sym, StrTable, true); W.printNumber("Name", FullSymbolName, Sym->st_name); } @@ -2160,8 +2214,12 @@ template <class ELFT> void ELFDumper<ELFT>::printMipsPLTGOT() { } MipsGOTParser<ELFT> GOTParser(this, Obj, dynamic_table(), W); - GOTParser.parseGOT(); - GOTParser.parsePLT(); + if (dynamic_table().empty()) + GOTParser.parseStaticGOT(); + else { + GOTParser.parseGOT(); + GOTParser.parsePLT(); + } } static const EnumEntry<unsigned> ElfMipsISAExtType[] = { @@ -2326,36 +2384,6 @@ template <class ELFT> void ELFDumper<ELFT>::printMipsOptions() { } } -template <class ELFT> void ELFDumper<ELFT>::printAMDGPUCodeObjectMetadata() { - const Elf_Shdr *Shdr = findSectionByName(*Obj, ".note"); - if (!Shdr) { - W.startLine() << "There is no .note section in the file.\n"; - return; - } - ArrayRef<uint8_t> Sec = unwrapOrError(Obj->getSectionContents(Shdr)); - - const uint32_t CodeObjectMetadataNoteType = 10; - for (auto I = reinterpret_cast<const Elf_Word *>(&Sec[0]), - E = I + Sec.size()/4; I != E;) { - uint32_t NameSZ = I[0]; - uint32_t DescSZ = I[1]; - uint32_t Type = I[2]; - I += 3; - - StringRef Name; - if (NameSZ) { - Name = StringRef(reinterpret_cast<const char *>(I), NameSZ - 1); - I += alignTo<4>(NameSZ)/4; - } - - if (Name == "AMD" && Type == CodeObjectMetadataNoteType) { - StringRef Desc(reinterpret_cast<const char *>(I), DescSZ); - W.printString(Desc); - } - I += alignTo<4>(DescSZ)/4; - } -} - template <class ELFT> void ELFDumper<ELFT>::printStackMap() const { const Elf_Shdr *StackMapSection = nullptr; for (const auto &Sec : unwrapOrError(Obj->sections())) { @@ -2369,7 +2397,6 @@ template <class ELFT> void ELFDumper<ELFT>::printStackMap() const { if (!StackMapSection) return; - StringRef StackMapContents; ArrayRef<uint8_t> StackMapContentsArray = unwrapOrError(Obj->getSectionContents(StackMapSection)); @@ -2441,34 +2468,91 @@ template <class ELFT> void GNUStyle<ELFT>::printFileHeaders(const ELFO *Obj) { printFields(OS, "Section header string table index:", Str); } -template <class ELFT> void GNUStyle<ELFT>::printGroupSections(const ELFO *Obj) { - uint32_t SectionIndex = 0; - bool HasGroups = false; +namespace { +struct GroupMember { + StringRef Name; + uint64_t Index; +}; + +struct GroupSection { + StringRef Name; + StringRef Signature; + uint64_t ShName; + uint64_t Index; + uint32_t Type; + std::vector<GroupMember> Members; +}; + +template <class ELFT> +std::vector<GroupSection> getGroups(const ELFFile<ELFT> *Obj) { + using Elf_Shdr = typename ELFFile<ELFT>::Elf_Shdr; + using Elf_Sym = typename ELFFile<ELFT>::Elf_Sym; + using Elf_Word = typename ELFFile<ELFT>::Elf_Word; + + std::vector<GroupSection> Ret; + uint64_t I = 0; for (const Elf_Shdr &Sec : unwrapOrError(Obj->sections())) { - if (Sec.sh_type == ELF::SHT_GROUP) { - HasGroups = true; - const Elf_Shdr *Symtab = unwrapOrError(Obj->getSection(Sec.sh_link)); - StringRef StrTable = unwrapOrError(Obj->getStringTableForSymtab(*Symtab)); - const Elf_Sym *Signature = - unwrapOrError(Obj->template getEntry<Elf_Sym>(Symtab, Sec.sh_info)); - ArrayRef<Elf_Word> Data = unwrapOrError( - Obj->template getSectionContentsAsArray<Elf_Word>(&Sec)); - StringRef Name = unwrapOrError(Obj->getSectionName(&Sec)); - OS << "\n" << getGroupType(Data[0]) << " group section [" - << format_decimal(SectionIndex, 5) << "] `" << Name << "' [" - << StrTable.data() + Signature->st_name << "] contains " - << (Data.size() - 1) << " sections:\n" - << " [Index] Name\n"; - for (auto &Ndx : Data.slice(1)) { - auto Sec = unwrapOrError(Obj->getSection(Ndx)); - const StringRef Name = unwrapOrError(Obj->getSectionName(Sec)); - OS << " [" << format_decimal(Ndx, 5) << "] " << Name - << "\n"; + ++I; + if (Sec.sh_type != ELF::SHT_GROUP) + continue; + + const Elf_Shdr *Symtab = unwrapOrError(Obj->getSection(Sec.sh_link)); + StringRef StrTable = unwrapOrError(Obj->getStringTableForSymtab(*Symtab)); + const Elf_Sym *Sym = + unwrapOrError(Obj->template getEntry<Elf_Sym>(Symtab, Sec.sh_info)); + auto Data = + unwrapOrError(Obj->template getSectionContentsAsArray<Elf_Word>(&Sec)); + + StringRef Name = unwrapOrError(Obj->getSectionName(&Sec)); + StringRef Signature = StrTable.data() + Sym->st_name; + Ret.push_back({Name, Signature, Sec.sh_name, I - 1, Data[0], {}}); + + std::vector<GroupMember> &GM = Ret.back().Members; + for (uint32_t Ndx : Data.slice(1)) { + auto Sec = unwrapOrError(Obj->getSection(Ndx)); + const StringRef Name = unwrapOrError(Obj->getSectionName(Sec)); + GM.push_back({Name, Ndx}); + } + } + return Ret; +} + +DenseMap<uint64_t, const GroupSection *> +mapSectionsToGroups(ArrayRef<GroupSection> Groups) { + DenseMap<uint64_t, const GroupSection *> Ret; + for (const GroupSection &G : Groups) + for (const GroupMember &GM : G.Members) + Ret.insert({GM.Index, &G}); + return Ret; +} + +} // namespace + +template <class ELFT> void GNUStyle<ELFT>::printGroupSections(const ELFO *Obj) { + std::vector<GroupSection> V = getGroups<ELFT>(Obj); + DenseMap<uint64_t, const GroupSection *> Map = mapSectionsToGroups(V); + for (const GroupSection &G : V) { + OS << "\n" + << getGroupType(G.Type) << " group section [" + << format_decimal(G.Index, 5) << "] `" << G.Name << "' [" << G.Signature + << "] contains " << G.Members.size() << " sections:\n" + << " [Index] Name\n"; + for (const GroupMember &GM : G.Members) { + const GroupSection *MainGroup = Map[GM.Index]; + if (MainGroup != &G) { + OS.flush(); + errs() << "Error: section [" << format_decimal(GM.Index, 5) + << "] in group section [" << format_decimal(G.Index, 5) + << "] already in group section [" + << format_decimal(MainGroup->Index, 5) << "]"; + errs().flush(); + continue; } + OS << " [" << format_decimal(GM.Index, 5) << "] " << GM.Name << "\n"; } - ++SectionIndex; } - if (!HasGroups) + + if (V.empty()) OS << "There are no section groups in this file.\n"; } @@ -2539,7 +2623,9 @@ static inline void printRelocHeader(raw_ostream &OS, bool Is64, bool IsRela) { template <class ELFT> void GNUStyle<ELFT>::printRelocations(const ELFO *Obj) { bool HasRelocSections = false; for (const Elf_Shdr &Sec : unwrapOrError(Obj->sections())) { - if (Sec.sh_type != ELF::SHT_REL && Sec.sh_type != ELF::SHT_RELA) + if (Sec.sh_type != ELF::SHT_REL && Sec.sh_type != ELF::SHT_RELA && + Sec.sh_type != ELF::SHT_ANDROID_REL && + Sec.sh_type != ELF::SHT_ANDROID_RELA) continue; HasRelocSections = true; StringRef Name = unwrapOrError(Obj->getSectionName(&Sec)); @@ -2548,9 +2634,12 @@ template <class ELFT> void GNUStyle<ELFT>::printRelocations(const ELFO *Obj) { OS << "\nRelocation section '" << Name << "' at offset 0x" << to_hexString(Offset, false) << " contains " << Entries << " entries:\n"; - printRelocHeader(OS, ELFT::Is64Bits, (Sec.sh_type == ELF::SHT_RELA)); + printRelocHeader(OS, ELFT::Is64Bits, + Sec.sh_type == ELF::SHT_RELA || + Sec.sh_type == ELF::SHT_ANDROID_RELA); const Elf_Shdr *SymTab = unwrapOrError(Obj->getSection(Sec.sh_link)); - if (Sec.sh_type == ELF::SHT_REL) { + switch (Sec.sh_type) { + case ELF::SHT_REL: for (const auto &R : unwrapOrError(Obj->rels(&Sec))) { Elf_Rela Rela; Rela.r_offset = R.r_offset; @@ -2558,9 +2647,16 @@ template <class ELFT> void GNUStyle<ELFT>::printRelocations(const ELFO *Obj) { Rela.r_addend = 0; printRelocation(Obj, SymTab, Rela, false); } - } else { + break; + case ELF::SHT_RELA: for (const auto &R : unwrapOrError(Obj->relas(&Sec))) printRelocation(Obj, SymTab, R, true); + break; + case ELF::SHT_ANDROID_REL: + case ELF::SHT_ANDROID_RELA: + for (const auto &R : unwrapOrError(Obj->android_relas(&Sec))) + printRelocation(Obj, SymTab, R, Sec.sh_type == ELF::SHT_ANDROID_RELA); + break; } } if (!HasRelocSections) @@ -3310,7 +3406,7 @@ static std::string getGNUNoteTypeName(const uint32_t NT) { std::string string; raw_string_ostream OS(string); OS << format("Unknown note type (0x%08x)", NT); - return string; + return OS.str(); } static std::string getFreeBSDNoteTypeName(const uint32_t NT) { @@ -3338,7 +3434,30 @@ static std::string getFreeBSDNoteTypeName(const uint32_t NT) { std::string string; raw_string_ostream OS(string); OS << format("Unknown note type (0x%08x)", NT); - return string; + return OS.str(); +} + +static std::string getAMDGPUNoteTypeName(const uint32_t NT) { + static const struct { + uint32_t ID; + const char *Name; + } Notes[] = { + {ELF::NT_AMD_AMDGPU_HSA_METADATA, + "NT_AMD_AMDGPU_HSA_METADATA (HSA Metadata)"}, + {ELF::NT_AMD_AMDGPU_ISA, + "NT_AMD_AMDGPU_ISA (ISA Version)"}, + {ELF::NT_AMD_AMDGPU_PAL_METADATA, + "NT_AMD_AMDGPU_PAL_METADATA (PAL Metadata)"} + }; + + for (const auto &Note : Notes) + if (Note.ID == NT) + return std::string(Note.Name); + + std::string string; + raw_string_ostream OS(string); + OS << format("Unknown note type (0x%08x)", NT); + return OS.str(); } template <typename ELFT> @@ -3381,6 +3500,39 @@ static void printGNUNote(raw_ostream &OS, uint32_t NoteType, OS << '\n'; } +template <typename ELFT> +static void printAMDGPUNote(raw_ostream &OS, uint32_t NoteType, + ArrayRef<typename ELFFile<ELFT>::Elf_Word> Words, + size_t Size) { + switch (NoteType) { + default: + return; + case ELF::NT_AMD_AMDGPU_HSA_METADATA: + OS << " HSA Metadata:\n" + << StringRef(reinterpret_cast<const char *>(Words.data()), Size); + break; + case ELF::NT_AMD_AMDGPU_ISA: + OS << " ISA Version:\n" + << " " + << StringRef(reinterpret_cast<const char *>(Words.data()), Size); + break; + case ELF::NT_AMD_AMDGPU_PAL_METADATA: + const uint32_t *PALMetadataBegin = reinterpret_cast<const uint32_t *>(Words.data()); + const uint32_t *PALMetadataEnd = PALMetadataBegin + Size; + std::vector<uint32_t> PALMetadata(PALMetadataBegin, PALMetadataEnd); + std::string PALMetadataString; + auto Error = AMDGPU::PALMD::toString(PALMetadata, PALMetadataString); + OS << " PAL Metadata:\n"; + if (Error) { + OS << " Invalid"; + return; + } + OS << PALMetadataString; + break; + } + OS.flush(); +} + template <class ELFT> void GNUStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) { const Elf_Ehdr *e = Obj->getHeader(); @@ -3421,6 +3573,9 @@ void GNUStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) { printGNUNote<ELFT>(OS, Type, Descriptor, DescriptorSize); } else if (Name == "FreeBSD") { OS << getFreeBSDNoteTypeName(Type) << '\n'; + } else if (Name == "AMD") { + OS << getAMDGPUNoteTypeName(Type) << '\n'; + printAMDGPUNote<ELFT>(OS, Type, Descriptor, DescriptorSize); } else { OS << "Unknown note type: (" << format_hex(Type, 10) << ')'; } @@ -3454,13 +3609,22 @@ template <class ELFT> void LLVMStyle<ELFT>::printFileHeaders(const ELFO *Obj) { makeArrayRef(ElfDataEncoding)); W.printNumber("FileVersion", e->e_ident[ELF::EI_VERSION]); - // Handle architecture specific OS/ABI values. - if (e->e_machine == ELF::EM_AMDGPU && - e->e_ident[ELF::EI_OSABI] == ELF::ELFOSABI_AMDGPU_HSA) - W.printHex("OS/ABI", "AMDGPU_HSA", ELF::ELFOSABI_AMDGPU_HSA); - else - W.printEnum("OS/ABI", e->e_ident[ELF::EI_OSABI], - makeArrayRef(ElfOSABI)); + auto OSABI = makeArrayRef(ElfOSABI); + if (e->e_ident[ELF::EI_OSABI] >= ELF::ELFOSABI_FIRST_ARCH && + e->e_ident[ELF::EI_OSABI] <= ELF::ELFOSABI_LAST_ARCH) { + switch (e->e_machine) { + case ELF::EM_AMDGPU: + OSABI = makeArrayRef(AMDGPUElfOSABI); + break; + case ELF::EM_ARM: + OSABI = makeArrayRef(ARMElfOSABI); + break; + case ELF::EM_TI_C6000: + OSABI = makeArrayRef(C6000ElfOSABI); + break; + } + } + W.printEnum("OS/ABI", e->e_ident[ELF::EI_OSABI], OSABI); W.printNumber("ABIVersion", e->e_ident[ELF::EI_ABIVERSION]); W.printBinary("Unused", makeArrayRef(e->e_ident).slice(ELF::EI_PAD)); } @@ -3475,6 +3639,11 @@ template <class ELFT> void LLVMStyle<ELFT>::printFileHeaders(const ELFO *Obj) { W.printFlags("Flags", e->e_flags, makeArrayRef(ElfHeaderMipsFlags), unsigned(ELF::EF_MIPS_ARCH), unsigned(ELF::EF_MIPS_ABI), unsigned(ELF::EF_MIPS_MACH)); + else if (e->e_machine == EM_AMDGPU) + W.printFlags("Flags", e->e_flags, makeArrayRef(ElfHeaderAMDGPUFlags), + unsigned(ELF::EF_AMDGPU_ARCH)); + else if (e->e_machine == EM_RISCV) + W.printFlags("Flags", e->e_flags, makeArrayRef(ElfHeaderRISCVFlags)); else W.printFlags("Flags", e->e_flags); W.printNumber("HeaderSize", e->e_ehsize); @@ -3489,36 +3658,32 @@ template <class ELFT> void LLVMStyle<ELFT>::printFileHeaders(const ELFO *Obj) { template <class ELFT> void LLVMStyle<ELFT>::printGroupSections(const ELFO *Obj) { DictScope Lists(W, "Groups"); - uint32_t SectionIndex = 0; - bool HasGroups = false; - for (const Elf_Shdr &Sec : unwrapOrError(Obj->sections())) { - if (Sec.sh_type == ELF::SHT_GROUP) { - HasGroups = true; - const Elf_Shdr *Symtab = unwrapOrError(Obj->getSection(Sec.sh_link)); - StringRef StrTable = unwrapOrError(Obj->getStringTableForSymtab(*Symtab)); - const Elf_Sym *Sym = - unwrapOrError(Obj->template getEntry<Elf_Sym>(Symtab, Sec.sh_info)); - auto Data = unwrapOrError( - Obj->template getSectionContentsAsArray<Elf_Word>(&Sec)); - DictScope D(W, "Group"); - StringRef Name = unwrapOrError(Obj->getSectionName(&Sec)); - W.printNumber("Name", Name, Sec.sh_name); - W.printNumber("Index", SectionIndex); - W.printHex("Type", getGroupType(Data[0]), Data[0]); - W.startLine() << "Signature: " << StrTable.data() + Sym->st_name << "\n"; - { - ListScope L(W, "Section(s) in group"); - size_t Member = 1; - while (Member < Data.size()) { - auto Sec = unwrapOrError(Obj->getSection(Data[Member])); - const StringRef Name = unwrapOrError(Obj->getSectionName(Sec)); - W.startLine() << Name << " (" << Data[Member++] << ")\n"; - } + std::vector<GroupSection> V = getGroups<ELFT>(Obj); + DenseMap<uint64_t, const GroupSection *> Map = mapSectionsToGroups(V); + for (const GroupSection &G : V) { + DictScope D(W, "Group"); + W.printNumber("Name", G.Name, G.ShName); + W.printNumber("Index", G.Index); + W.printHex("Type", getGroupType(G.Type), G.Type); + W.startLine() << "Signature: " << G.Signature << "\n"; + + ListScope L(W, "Section(s) in group"); + for (const GroupMember &GM : G.Members) { + const GroupSection *MainGroup = Map[GM.Index]; + if (MainGroup != &G) { + W.flush(); + errs() << "Error: " << GM.Name << " (" << GM.Index + << ") in a group " + G.Name + " (" << G.Index + << ") is already in a group " + MainGroup->Name + " (" + << MainGroup->Index << ")\n"; + errs().flush(); + continue; } + W.startLine() << GM.Name << " (" << GM.Index << ")\n"; } - ++SectionIndex; } - if (!HasGroups) + + if (V.empty()) W.startLine() << "There are no group sections in the file.\n"; } @@ -3529,7 +3694,9 @@ template <class ELFT> void LLVMStyle<ELFT>::printRelocations(const ELFO *Obj) { for (const Elf_Shdr &Sec : unwrapOrError(Obj->sections())) { ++SectionNumber; - if (Sec.sh_type != ELF::SHT_REL && Sec.sh_type != ELF::SHT_RELA) + if (Sec.sh_type != ELF::SHT_REL && Sec.sh_type != ELF::SHT_RELA && + Sec.sh_type != ELF::SHT_ANDROID_REL && + Sec.sh_type != ELF::SHT_ANDROID_RELA) continue; StringRef Name = unwrapOrError(Obj->getSectionName(&Sec)); @@ -3562,6 +3729,11 @@ void LLVMStyle<ELFT>::printRelocations(const Elf_Shdr *Sec, const ELFO *Obj) { for (const Elf_Rela &R : unwrapOrError(Obj->relas(Sec))) printRelocation(Obj, R, SymTab); break; + case ELF::SHT_ANDROID_REL: + case ELF::SHT_ANDROID_RELA: + for (const Elf_Rela &R : unwrapOrError(Obj->android_relas(Sec))) + printRelocation(Obj, R, SymTab); + break; } } diff --git a/tools/llvm-readobj/ObjDumper.h b/tools/llvm-readobj/ObjDumper.h index 43883c2d21766..c5b331d944a20 100644 --- a/tools/llvm-readobj/ObjDumper.h +++ b/tools/llvm-readobj/ObjDumper.h @@ -19,7 +19,7 @@ class COFFImportFile; class ObjectFile; } namespace codeview { -class TypeTableBuilder; +class MergingTypeTableBuilder; } class ScopedPrinter; @@ -58,9 +58,6 @@ public: virtual void printMipsReginfo() { } virtual void printMipsOptions() { } - // Only implemented for AMDGPU ELF at this time. - virtual void printAMDGPUCodeObjectMetadata() {} - // Only implemented for PE/COFF. virtual void printCOFFImports() { } virtual void printCOFFExports() { } @@ -70,8 +67,9 @@ public: virtual void printCOFFResources() {} virtual void printCOFFLoadConfig() { } virtual void printCodeViewDebugInfo() { } - virtual void mergeCodeViewTypes(llvm::codeview::TypeTableBuilder &CVIDs, - llvm::codeview::TypeTableBuilder &CVTypes) {} + virtual void + mergeCodeViewTypes(llvm::codeview::MergingTypeTableBuilder &CVIDs, + llvm::codeview::MergingTypeTableBuilder &CVTypes) {} // Only implemented for MachO. virtual void printMachODataInCode() { } @@ -105,9 +103,9 @@ std::error_code createWasmDumper(const object::ObjectFile *Obj, void dumpCOFFImportFile(const object::COFFImportFile *File); -void dumpCodeViewMergedTypes(ScopedPrinter &Writer, - llvm::codeview::TypeTableBuilder &IDTable, - llvm::codeview::TypeTableBuilder &TypeTable); +void dumpCodeViewMergedTypes( + ScopedPrinter &Writer, llvm::codeview::MergingTypeTableBuilder &IDTable, + llvm::codeview::MergingTypeTableBuilder &TypeTable); } // namespace llvm diff --git a/tools/llvm-readobj/WasmDumper.cpp b/tools/llvm-readobj/WasmDumper.cpp index 266226d59ee87..77711e749aa09 100644 --- a/tools/llvm-readobj/WasmDumper.cpp +++ b/tools/llvm-readobj/WasmDumper.cpp @@ -83,9 +83,9 @@ void WasmDumper::printRelocation(const SectionRef &Section, bool HasAddend = false; switch (RelocType) { - case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_LEB: - case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_SLEB: - case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_I32: + case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB: + case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB: + case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32: HasAddend = true; break; default: @@ -148,7 +148,7 @@ void WasmDumper::printSections() { const WasmSection &WasmSec = Obj->getWasmSection(Section); DictScope SectionD(W, "Section"); W.printEnum("Type", WasmSec.Type, makeArrayRef(WasmSectionTypes)); - W.printNumber("Size", (uint64_t)WasmSec.Content.size()); + W.printNumber("Size", static_cast<uint64_t>(WasmSec.Content.size())); W.printNumber("Offset", WasmSec.Offset); switch (WasmSec.Type) { case wasm::WASM_SEC_CUSTOM: @@ -156,10 +156,21 @@ void WasmDumper::printSections() { if (WasmSec.Name == "linking") { const wasm::WasmLinkingData &LinkingData = Obj->linkingData(); W.printNumber("DataSize", LinkingData.DataSize); - if (LinkingData.DataAlignment) - W.printNumber("DataAlignment", LinkingData.DataAlignment); } break; + case wasm::WASM_SEC_DATA: { + ListScope Group(W, "Segments"); + for (const WasmSegment &Segment : Obj->dataSegments()) { + const wasm::WasmDataSegment& Seg = Segment.Data; + DictScope Group(W, "Segment"); + if (!Seg.Name.empty()) + W.printString("Name", Seg.Name); + W.printNumber("Size", static_cast<uint64_t>(Seg.Content.size())); + if (Seg.Offset.Opcode == wasm::WASM_OPCODE_I32_CONST) + W.printNumber("Offset", Seg.Offset.Value.Int32); + } + break; + } case wasm::WASM_SEC_MEMORY: ListScope Group(W, "Memories"); for (const wasm::WasmLimits &Memory : Obj->memories()) { diff --git a/tools/llvm-readobj/WindowsResourceDumper.cpp b/tools/llvm-readobj/WindowsResourceDumper.cpp new file mode 100644 index 0000000000000..1f568a9636712 --- /dev/null +++ b/tools/llvm-readobj/WindowsResourceDumper.cpp @@ -0,0 +1,82 @@ +//===-- WindowsResourceDumper.cpp - Windows Resource printer --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Windows resource (.res) dumper for llvm-readobj. +// +//===----------------------------------------------------------------------===// + +#include "WindowsResourceDumper.h" +#include "Error.h" +#include "llvm/Object/WindowsResource.h" +#include "llvm/Support/ConvertUTF.h" +#include "llvm/Support/ScopedPrinter.h" + +namespace llvm { +namespace object { +namespace WindowsRes { + +std::string stripUTF16(const ArrayRef<UTF16> &UTF16Str) { + std::string Result; + Result.reserve(UTF16Str.size()); + + for (UTF16 Ch : UTF16Str) { + // UTF16Str will have swapped byte order in case of big-endian machines. + // Swap it back in such a case. + uint16_t ChValue = support::endian::byte_swap(Ch, support::little); + if (ChValue <= 0xFF) + Result += ChValue; + else + Result += '?'; + } + return Result; +} + +Error Dumper::printData() { + auto EntryPtrOrErr = WinRes->getHeadEntry(); + if (!EntryPtrOrErr) + return EntryPtrOrErr.takeError(); + auto EntryPtr = *EntryPtrOrErr; + + bool IsEnd = false; + while (!IsEnd) { + printEntry(EntryPtr); + + if (auto Err = EntryPtr.moveNext(IsEnd)) + return Err; + } + return Error::success(); +} + +void Dumper::printEntry(const ResourceEntryRef &Ref) { + if (Ref.checkTypeString()) { + auto NarrowStr = stripUTF16(Ref.getTypeString()); + SW.printString("Resource type (string)", NarrowStr); + } else + SW.printNumber("Resource type (int)", Ref.getTypeID()); + + if (Ref.checkNameString()) { + auto NarrowStr = stripUTF16(Ref.getNameString()); + SW.printString("Resource name (string)", NarrowStr); + } else + SW.printNumber("Resource name (int)", Ref.getNameID()); + + SW.printNumber("Data version", Ref.getDataVersion()); + SW.printHex("Memory flags", Ref.getMemoryFlags()); + SW.printNumber("Language ID", Ref.getLanguage()); + SW.printNumber("Version (major)", Ref.getMajorVersion()); + SW.printNumber("Version (minor)", Ref.getMinorVersion()); + SW.printNumber("Characteristics", Ref.getCharacteristics()); + SW.printNumber("Data size", (uint64_t)Ref.getData().size()); + SW.printBinary("Data:", Ref.getData()); + SW.startLine() << "\n"; +} + +} // namespace WindowsRes +} // namespace object +} // namespace llvm diff --git a/tools/llvm-readobj/WindowsResourceDumper.h b/tools/llvm-readobj/WindowsResourceDumper.h new file mode 100644 index 0000000000000..ca6da40466052 --- /dev/null +++ b/tools/llvm-readobj/WindowsResourceDumper.h @@ -0,0 +1,37 @@ +//===- WindowsResourceDumper.h - Windows Resource printer -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVM_READOBJ_WINDOWSRESOURCEDUMPER_H +#define LLVM_TOOLS_LLVM_READOBJ_WINDOWSRESOURCEDUMPER_H + +#include "llvm/Object/WindowsResource.h" +#include "llvm/Support/ScopedPrinter.h" + +namespace llvm { +namespace object { +namespace WindowsRes { + +class Dumper { +public: + Dumper(WindowsResource *Res, ScopedPrinter &SW) : SW(SW), WinRes(Res) {} + + Error printData(); + +private: + ScopedPrinter &SW; + WindowsResource *WinRes; + + void printEntry(const ResourceEntryRef &Ref); +}; + +} // namespace WindowsRes +} // namespace object +} // namespace llvm + +#endif diff --git a/tools/llvm-readobj/llvm-readobj.cpp b/tools/llvm-readobj/llvm-readobj.cpp index 7bfb18fab12b6..c076582794fe4 100644 --- a/tools/llvm-readobj/llvm-readobj.cpp +++ b/tools/llvm-readobj/llvm-readobj.cpp @@ -22,12 +22,13 @@ #include "llvm-readobj.h" #include "Error.h" #include "ObjDumper.h" -#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h" +#include "WindowsResourceDumper.h" +#include "llvm/DebugInfo/CodeView/MergingTypeTableBuilder.h" #include "llvm/Object/Archive.h" #include "llvm/Object/COFFImportFile.h" -#include "llvm/Object/ELFObjectFile.h" #include "llvm/Object/MachOUniversal.h" #include "llvm/Object/ObjectFile.h" +#include "llvm/Object/WindowsResource.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/DataTypes.h" @@ -39,9 +40,6 @@ #include "llvm/Support/ScopedPrinter.h" #include "llvm/Support/Signals.h" #include "llvm/Support/TargetRegistry.h" -#include "llvm/Support/TargetSelect.h" -#include <string> -#include <system_error> using namespace llvm; using namespace llvm::object; @@ -198,11 +196,6 @@ namespace opts { cl::opt<bool> MipsOptions("mips-options", cl::desc("Display the MIPS .MIPS.options section")); - // -amdgpu-code-object-metadata - cl::opt<bool> AMDGPUCodeObjectMetadata( - "amdgpu-code-object-metadata", - cl::desc("Display AMDGPU code object metadata")); - // -coff-imports cl::opt<bool> COFFImports("coff-imports", cl::desc("Display the PE/COFF import table")); @@ -356,8 +349,8 @@ struct ReadObjTypeTableBuilder { : Allocator(), IDTable(Allocator), TypeTable(Allocator) {} llvm::BumpPtrAllocator Allocator; - llvm::codeview::TypeTableBuilder IDTable; - llvm::codeview::TypeTableBuilder TypeTable; + llvm::codeview::MergingTypeTableBuilder IDTable; + llvm::codeview::MergingTypeTableBuilder TypeTable; }; } static ReadObjTypeTableBuilder CVTypes; @@ -438,9 +431,6 @@ static void dumpObject(const ObjectFile *Obj) { if (opts::MipsOptions) Dumper->printMipsOptions(); } - if (Obj->getArch() == llvm::Triple::amdgcn) - if (opts::AMDGPUCodeObjectMetadata) - Dumper->printAMDGPUCodeObjectMetadata(); if (opts::SectionGroups) Dumper->printGroupSections(); if (opts::HashHistogram) @@ -522,6 +512,15 @@ static void dumpMachOUniversalBinary(const MachOUniversalBinary *UBinary) { } } +/// @brief Dumps \a WinRes, Windows Resource (.res) file; +static void dumpWindowsResourceFile(WindowsResource *WinRes) { + ScopedPrinter Printer{outs()}; + WindowsRes::Dumper Dumper(WinRes, Printer); + if (auto Err = Dumper.printData()) + reportError(WinRes->getFileName(), std::move(Err)); +} + + /// @brief Opens \a File and dumps it. static void dumpInput(StringRef File) { @@ -540,6 +539,8 @@ static void dumpInput(StringRef File) { dumpObject(Obj); else if (COFFImportFile *Import = dyn_cast<COFFImportFile>(&Binary)) dumpCOFFImportFile(Import); + else if (WindowsResource *WinRes = dyn_cast<WindowsResource>(&Binary)) + dumpWindowsResourceFile(WinRes); else reportError(File, readobj_error::unrecognized_file_format); } @@ -564,8 +565,7 @@ int main(int argc, const char *argv[]) { if (opts::InputFilenames.size() == 0) opts::InputFilenames.push_back("-"); - std::for_each(opts::InputFilenames.begin(), opts::InputFilenames.end(), - dumpInput); + llvm::for_each(opts::InputFilenames, dumpInput); if (opts::CodeViewMergedTypes) { ScopedPrinter W(outs()); |
