Index: include/llvm/Object/COFF.h =================================================================== --- include/llvm/Object/COFF.h +++ include/llvm/Object/COFF.h @@ -964,6 +964,8 @@ std::error_code getDataDirectory(uint32_t index, const data_directory *&Res) const; std::error_code getSection(int32_t index, const coff_section *&Res) const; + std::error_code getSection(StringRef SectionName, + const coff_section *&Res) const; template std::error_code getSymbol(uint32_t Index, Index: include/llvm/Object/MachO.h =================================================================== --- include/llvm/Object/MachO.h +++ include/llvm/Object/MachO.h @@ -304,6 +304,9 @@ std::error_code getSectionContents(DataRefImpl Sec, StringRef &Res) const override; uint64_t getSectionAlignment(DataRefImpl Sec) const override; + Expected getSection(unsigned SectionIndex) const; + std::error_code getSection(StringRef SectionName, + const SectionRef *&Result) const; bool isSectionCompressed(DataRefImpl Sec) const override; bool isSectionText(DataRefImpl Sec) const override; bool isSectionData(DataRefImpl Sec) const override; Index: lib/Object/COFFObjectFile.cpp =================================================================== --- lib/Object/COFFObjectFile.cpp +++ lib/Object/COFFObjectFile.cpp @@ -973,6 +973,21 @@ return object_error::parse_failed; } +std::error_code COFFObjectFile::getSection(StringRef SectionName, + const coff_section *&Result) const { + Result = nullptr; + StringRef SecName; + for (const SectionRef &Section : sections()) { + if (std::error_code E = Section.getName(SecName)) + return E; + if (SecName == SectionName) { + Result = getCOFFSection(Section); + return std::error_code(); + } + } + return object_error::parse_failed; +} + std::error_code COFFObjectFile::getString(uint32_t Offset, StringRef &Result) const { if (StringTableSize <= 4) Index: lib/Object/MachOObjectFile.cpp =================================================================== --- lib/Object/MachOObjectFile.cpp +++ lib/Object/MachOObjectFile.cpp @@ -1939,6 +1939,29 @@ return uint64_t(1) << Align; } +Expected MachOObjectFile::getSection(unsigned SectionIndex) const { + if (SectionIndex < 1 || SectionIndex > Sections.size()) + return malformedError("bad section index: " + Twine((int)SectionIndex)); + + DataRefImpl DRI; + DRI.d.a = SectionIndex - 1; + return SectionRef(DRI, this); +} + +std::error_code MachOObjectFile::getSection(StringRef SectionName, + const SectionRef *&Result) const { + StringRef SecName; + for (const SectionRef &Section : sections()) { + if (std::error_code E = Section.getName(SecName)) + return E; + if (SecName == SectionName) { + Result = &Section; + return std::error_code(); + } + } + return object_error::parse_failed; +} + bool MachOObjectFile::isSectionCompressed(DataRefImpl Sec) const { return false; } Index: test/tools/llvm-readobj/print-hex.test =================================================================== --- /dev/null +++ test/tools/llvm-readobj/print-hex.test @@ -0,0 +1,20 @@ +RUN: llvm-readobj -x .strtab %p/Inputs/trivial.obj.elf-x86-64 \ +RUN: | FileCheck %s --check-prefix ELF + +ELF: 0x00000000 00747269 7669616c 2e6c6c00 6d61696e .trivial.ll.main +ELF: 0x00000010 002e4c2e 73747200 70757473 00536f6d ..L.str.puts.Som +ELF: 0x00000020 654f7468 65724675 6e637469 6f6e005f eOtherFunction._ +ELF: 0x00000030 474c4f42 414c5f4f 46465345 545f5441 GLOBAL_OFFSET_TA +ELF: 0x00000040 424c455f 00 BLE_. + +RUN: llvm-readobj -x 1 %p/Inputs/trivial.obj.coff-x86-64 \ +RUN: | FileCheck %s --check-prefix COFF + +COFF: 0x00000000 4883ec28 488d0d00 000000e8 00000000 H..(H........... +COFF: 0x00000010 e8000000 0031c048 83c428c3 .....1.H..(. + +RUN: llvm-readobj -x 1 %p/Inputs/trivial.obj.macho-x86-64 \ +RUN: | FileCheck %s --check-prefix MACHO + +MACHO: 0x00000000 50488d3d 00000000 e8000000 00e80000 PH.=............ +MACHO: 0x00000010 000031c0 5ac3 ..1.Z. Index: tools/llvm-readobj/COFFDumper.cpp =================================================================== --- tools/llvm-readobj/COFFDumper.cpp +++ tools/llvm-readobj/COFFDumper.cpp @@ -83,6 +83,7 @@ void printSymbols() override; void printDynamicSymbols() override; void printUnwindInfo() override; + void printSectionAsHex(StringRef StringName) override; void printNeededLibraries() override; @@ -654,6 +655,63 @@ printDOSHeader(DH); } +void COFFDumper::printSectionAsHex(StringRef SectionName) { + char *StrPtr; + long SectionIndex = strtol(SectionName.data(), &StrPtr, 10); + const coff_section *Sec; + if (*StrPtr) + error(Obj->getSection(SectionName, Sec)); + else { + error(Obj->getSection((int)SectionIndex, Sec)); + if (!Sec) + return error(object_error::parse_failed); + } + + StringRef SecName; + error(Obj->getSectionName(Sec, SecName)); + + W.printString("Hex dump of section", SecName); + ArrayRef Content; + error(Obj->getSectionContents(Sec, Content)); + const uint8_t *SecContent = Content.data(); + const uint8_t *SecEnd = SecContent + Content.size(); + + for (const uint8_t *SecPtr = SecContent; SecPtr < SecEnd; SecPtr += 16) { + const uint8_t *TmpSecPtr = SecPtr; + uint8_t i; + uint8_t k; + + W.startLine() << format_hex(SecPtr - SecContent, 10); + W.startLine() << ' '; + for (i = 0; TmpSecPtr < SecEnd && i < 4; ++i) { + for (k = 0; TmpSecPtr < SecEnd && k < 4; k++, TmpSecPtr++) { + uint8_t Val = *(reinterpret_cast(TmpSecPtr)); + W.startLine() << format_hex_no_prefix(Val, 2); + } + W.startLine() << ' '; + } + + // We need to print the correct amount of spaces to match the format. + // We are adding the (4 - i) last rows that are 8 characters each. + // Then, the (4 - i) spaces that are in between the rows. + // Least, if we cut in a middle of a row, we add the remaining characters, + // which is (8 - (k * 2)) + if (i < 4) + W.startLine() << format("%*c", (4 - i) * 8 + (4 - i) + (8 - (k * 2)), + ' '); + + TmpSecPtr = SecPtr; + for (i = 0; TmpSecPtr + i < SecEnd && i < 16; ++i) { + if (isprint(TmpSecPtr[i])) + W.startLine() << TmpSecPtr[i]; + else + W.startLine() << '.'; + } + + W.startLine() << '\n'; + } +} + void COFFDumper::printDOSHeader(const dos_header *DH) { DictScope D(W, "DOSHeader"); W.printString("Magic", StringRef(DH->Magic, sizeof(DH->Magic))); Index: tools/llvm-readobj/ELFDumper.cpp =================================================================== --- tools/llvm-readobj/ELFDumper.cpp +++ tools/llvm-readobj/ELFDumper.cpp @@ -150,6 +150,7 @@ void printNeededLibraries() override; void printProgramHeaders() override; void printSectionAsString(StringRef StringName) override; + void printSectionAsHex(StringRef StringName) override; void printHashTable() override; void printGnuHashTable() override; void printLoadName() override; @@ -327,6 +328,8 @@ virtual void printProgramHeaders(const ELFFile *Obj) = 0; virtual void printSectionAsString(const ELFFile *Obj, StringRef SectionName) = 0; + virtual void printSectionAsHex(const ELFFile *Obj, + StringRef SectionName) = 0; virtual void printHashHistogram(const ELFFile *Obj) = 0; virtual void printCGProfile(const ELFFile *Obj) = 0; virtual void printNotes(const ELFFile *Obj) = 0; @@ -359,6 +362,7 @@ size_t Offset) override; void printProgramHeaders(const ELFO *Obj) override; void printSectionAsString(const ELFO *Obj, StringRef SectionName) override; + void printSectionAsHex(const ELFO *Obj, StringRef SectionName) override; void printHashHistogram(const ELFFile *Obj) override; void printCGProfile(const ELFFile *Obj) override; void printNotes(const ELFFile *Obj) override; @@ -422,6 +426,7 @@ void printDynamicRelocations(const ELFO *Obj) override; void printProgramHeaders(const ELFO *Obj) override; void printSectionAsString(const ELFO *Obj, StringRef SectionName) override; + void printSectionAsHex(const ELFO *Obj, StringRef SectionName) override; void printHashHistogram(const ELFFile *Obj) override; void printCGProfile(const ELFFile *Obj) override; void printNotes(const ELFFile *Obj) override; @@ -1549,6 +1554,11 @@ ELFDumperStyle->printSectionAsString(Obj, SectionName); } +template +void ELFDumper::printSectionAsHex(StringRef SectionName) { + ELFDumperStyle->printSectionAsHex(Obj, SectionName); +} + template void ELFDumper::printDynamicRelocations() { ELFDumperStyle->printDynamicRelocations(Obj); } @@ -3250,6 +3260,58 @@ OS.flush(); } +template +void GNUStyle::printSectionAsHex(const ELFO *Obj, StringRef SectionName) { + char *StrPtr; + long SectionIndex = strtol(SectionName.data(), &StrPtr, 10); + const Elf_Shdr *Sec; + if (*StrPtr) + Sec = unwrapOrError(Obj->getSection(SectionName)); + else + Sec = unwrapOrError(Obj->getSection((unsigned int)SectionIndex)); + + StringRef SecName = unwrapOrError(Obj->getSectionName(Sec)); + OS << "Hex dump of section '" << SecName << "':\n"; + const uint8_t *SecContent = + reinterpret_cast(Obj->base() + Sec->sh_offset); + const uint8_t *SecEnd = SecContent + Sec->sh_size; + + for (const uint8_t *SecPtr = SecContent; SecPtr < SecEnd; SecPtr += 16) { + const uint8_t *TmpSecPtr = SecPtr; + uint8_t i; + uint8_t k; + + OS << format_hex(SecPtr - SecContent, 10); + OS << ' '; + for (i = 0; TmpSecPtr < SecEnd && i < 4; ++i) { + for (k = 0; TmpSecPtr < SecEnd && k < 4; k++, TmpSecPtr++) { + uint8_t Val = *(reinterpret_cast(TmpSecPtr)); + OS << format_hex_no_prefix(Val, 2); + } + OS << ' '; + } + + // We need to print the correct amount of spaces to match the format. + // We are adding the (4 - i) last rows that are 8 characters each. + // Then, the (4 - i) spaces that are in between the rows. + // Least, if we cut in a middle of a row, we add the remaining characters, + // which is (8 - (k * 2)) + if (i < 4) + OS << format("%*c", (4 - i) * 8 + (4 - i) + (8 - (k * 2)), ' '); + + TmpSecPtr = SecPtr; + for (i = 0; TmpSecPtr + i < SecEnd && i < 16; ++i) { + if (isprint(TmpSecPtr[i])) + OS << TmpSecPtr[i]; + else + OS << '.'; + } + + OS << '\n'; + } + OS.flush(); +} + template void GNUStyle::printDynamicRelocation(const ELFO *Obj, Elf_Rela R, bool IsRela) { @@ -4276,6 +4338,59 @@ } } +template +void LLVMStyle::printSectionAsHex(const ELFO *Obj, + StringRef SectionName) { + char *StrPtr; + long SectionIndex = strtol(SectionName.data(), &StrPtr, 10); + const Elf_Shdr *Sec; + if (*StrPtr) + Sec = unwrapOrError(Obj->getSection(SectionName)); + else + Sec = unwrapOrError(Obj->getSection((unsigned int)SectionIndex)); + + StringRef SecName = unwrapOrError(Obj->getSectionName(Sec)); + W.startLine() << "Hex dump of section '" << SecName << "':\n"; + const uint8_t *SecContent = + reinterpret_cast(Obj->base() + Sec->sh_offset); + const uint8_t *SecEnd = SecContent + Sec->sh_size; + + for (const uint8_t *SecPtr = SecContent; SecPtr < SecEnd; SecPtr += 16) { + const uint8_t *TmpSecPtr = SecPtr; + uint8_t i; + uint8_t k; + + W.startLine() << format_hex(SecPtr - SecContent, 10); + W.startLine() << ' '; + for (i = 0; TmpSecPtr < SecEnd && i < 4; ++i) { + for (k = 0; TmpSecPtr < SecEnd && k < 4; k++, TmpSecPtr++) { + uint8_t Val = *(reinterpret_cast(TmpSecPtr)); + W.startLine() << format_hex_no_prefix(Val, 2); + } + W.startLine() << ' '; + } + + // We need to print the correct amount of spaces to match the format. + // We are adding the (4 - i) last rows that are 8 characters each. + // Then, the (4 - i) spaces that are in between the rows. + // Least, if we cut in a middle of a row, we add the remaining characters, + // which is (8 - (k * 2)) + if (i < 4) + W.startLine() << format("%*c", (4 - i) * 8 + (4 - i) + (8 - (k * 2)), + ' '); + + TmpSecPtr = SecPtr; + for (i = 0; TmpSecPtr + i < SecEnd && i < 16; ++i) { + if (isprint(TmpSecPtr[i])) + W.startLine() << TmpSecPtr[i]; + else + W.startLine() << '.'; + } + + W.startLine() << '\n'; + } +} + template void LLVMStyle::printHashHistogram(const ELFFile *Obj) { W.startLine() << "Hash Histogram not implemented!\n"; Index: tools/llvm-readobj/MachODumper.cpp =================================================================== --- tools/llvm-readobj/MachODumper.cpp +++ tools/llvm-readobj/MachODumper.cpp @@ -38,6 +38,7 @@ void printDynamicSymbols() override; void printUnwindInfo() override; void printStackMap() const override; + void printSectionAsHex(StringRef SectionName) override; void printNeededLibraries() override; @@ -676,6 +677,63 @@ StackMapV2Parser(StackMapContentsArray)); } +void MachODumper::printSectionAsHex(StringRef SectionName) { + char *StrPtr; + long SectionIndex = strtol(SectionName.data(), &StrPtr, 10); + SectionRef SecTmp; + const SectionRef *Sec = &SecTmp; + if (*StrPtr) + error(Obj->getSection(SectionName, Sec)); + else + SecTmp = unwrapOrError(Obj->getSection((unsigned int)SectionIndex)); + + StringRef SecName; + error(Sec->getName(SecName)); + + W.startLine() << "Hex dump of section '" << SecName << "':\n"; + + StringRef Data; + error(Sec->getContents(Data)); + const uint8_t *SecContent = reinterpret_cast(Data.data()); + const uint8_t *SecEnd = + reinterpret_cast(Data.data() + Data.size()); + + for (const uint8_t *SecPtr = SecContent; SecPtr < SecEnd; SecPtr += 16) { + const uint8_t *TmpSecPtr = SecPtr; + uint8_t i; + uint8_t k; + + W.startLine() << format_hex(SecPtr - SecContent, 10); + W.startLine() << ' '; + for (i = 0; TmpSecPtr < SecEnd && i < 4; ++i) { + for (k = 0; TmpSecPtr < SecEnd && k < 4; k++, TmpSecPtr++) { + uint8_t Val = *(reinterpret_cast(TmpSecPtr)); + W.startLine() << format_hex_no_prefix(Val, 2); + } + W.startLine() << ' '; + } + + // We need to print the correct amount of spaces to match the format. + // We are adding the (4 - i) last rows that are 8 characters each. + // Then, the (4 - i) spaces that are in between the rows. + // Least, if we cut in a middle of a row, we add the remaining characters, + // which is (8 - (k * 2)) + if (i < 4) + W.startLine() << format("%*c", (4 - i) * 8 + (4 - i) + (8 - (k * 2)), + ' '); + + TmpSecPtr = SecPtr; + for (i = 0; TmpSecPtr + i < SecEnd && i < 16; ++i) { + if (isprint(TmpSecPtr[i])) + W.startLine() << TmpSecPtr[i]; + else + W.startLine() << '.'; + } + + W.startLine() << '\n'; + } +} + void MachODumper::printNeededLibraries() { ListScope D(W, "NeededLibraries"); Index: tools/llvm-readobj/ObjDumper.h =================================================================== --- tools/llvm-readobj/ObjDumper.h +++ tools/llvm-readobj/ObjDumper.h @@ -44,6 +44,7 @@ virtual void printNeededLibraries() { } virtual void printProgramHeaders() { } virtual void printSectionAsString(StringRef SectionName) {} + virtual void printSectionAsHex(StringRef SectionName) {} virtual void printHashTable() { } virtual void printGnuHashTable() { } virtual void printLoadName() {} Index: tools/llvm-readobj/llvm-readobj.cpp =================================================================== --- tools/llvm-readobj/llvm-readobj.cpp +++ tools/llvm-readobj/llvm-readobj.cpp @@ -152,6 +152,12 @@ cl::alias StringDumpShort("p", cl::desc("Alias for --string-dump"), cl::aliasopt(StringDump)); + // -hex-dump + cl::list HexDump("hex-dump", cl::desc(""), + cl::ZeroOrMore); + cl::alias HexDumpShort("x", cl::desc("Alias for --hex-dump"), + cl::aliasopt(HexDump)); + // -hash-table cl::opt HashTable("hash-table", cl::desc("Display ELF hash table")); @@ -427,6 +433,10 @@ llvm::for_each(opts::StringDump, [&Dumper](StringRef SectionName) { Dumper->printSectionAsString(SectionName); }); + if (!opts::HexDump.empty()) + llvm::for_each(opts::HexDump, [&Dumper](StringRef SectionName) { + Dumper->printSectionAsHex(SectionName); + }); if (opts::HashTable) Dumper->printHashTable(); if (opts::GnuHashTable)