Index: test/MC/Hexagon/basic.ll =================================================================== --- test/MC/Hexagon/basic.ll +++ test/MC/Hexagon/basic.ll @@ -4,4 +4,4 @@ ; OBJ: Format: ELF32-hexagon ; OBJ: Arch: hexagon ; OBJ: AddressSize: 32bit -; OBJ: Machine: EM_HEXAGON +; OBJ: Machine: Qualcomm Hexagon Index: test/tools/llvm-readobj/gnu-file-headers.test =================================================================== --- /dev/null +++ test/tools/llvm-readobj/gnu-file-headers.test @@ -0,0 +1,46 @@ +RUN: llvm-readobj -h %p/Inputs/trivial.obj.elf-i386 -gnu-style \ +RUN: | FileCheck %s -check-prefix ELF32 +RUN: llvm-readobj -h %p/Inputs/trivial.obj.elf-x86-64 -gnu-style \ +RUN: | FileCheck %s -check-prefix ELF64 + +ELF32: ELF Header: +ELF32-NEXT: Magic: 7f 45 4c 46 01 01 01 03 00 00 00 00 00 00 00 00 +ELF32-NEXT: Class: 32-bit +ELF32-NEXT: Data: LittleEndian +ELF32-NEXT: Version: 1 (current) +ELF32-NEXT: OS/ABI: GNU/Linux +ELF32-NEXT: ABI Version: 0 +ELF32-NEXT: Type: Relocatable +ELF32-NEXT: Machine: EM_386 +ELF32-NEXT: Version: 0x1 +ELF32-NEXT: Entry point address: 0x0 +ELF32-NEXT: Start of program headers: 0 (bytes into file) +ELF32-NEXT: Start of section headers: 200 (bytes into file) +ELF32-NEXT: Flags: 0x0 +ELF32-NEXT: Size of this header: 52 (bytes) +ELF32-NEXT: Size of prgram headers: 0 (bytes) +ELF32-NEXT: Number of prgram headers: 0 +ELF32-NEXT: Size of section headers: 40 (bytes) +ELF32-NEXT: Number of section headers: 10 +ELF32-NEXT: Section header string table index: 7 + +ELF64: ELF Header: +ELF64-NEXT: Magic: 7f 45 4c 46 02 01 01 03 00 00 00 00 00 00 00 00 +ELF64-NEXT: Class: 64-bit +ELF64-NEXT: Data: LittleEndian +ELF64-NEXT: Version: 1 (current) +ELF64-NEXT: OS/ABI: GNU/Linux +ELF64-NEXT: ABI Version: 0 +ELF64-NEXT: Type: Relocatable +ELF64-NEXT: Machine: EM_X86_64 +ELF64-NEXT: Version: 0x1 +ELF64-NEXT: Entry point address: 0x0 +ELF64-NEXT: Start of program headers: 0 (bytes into file) +ELF64-NEXT: Start of section headers: 184 (bytes into file) +ELF64-NEXT: Flags: 0x0 +ELF64-NEXT: Size of this header: 64 (bytes) +ELF64-NEXT: Size of prgram headers: 0 (bytes) +ELF64-NEXT: Number of prgram headers: 0 +ELF64-NEXT: Size of section headers: 64 (bytes) +ELF64-NEXT: Number of section headers: 10 +ELF64-NEXT: Section header string table index: 7 Index: tools/llvm-readobj/ELFDumper.cpp =================================================================== --- tools/llvm-readobj/ELFDumper.cpp +++ tools/llvm-readobj/ELFDumper.cpp @@ -39,10 +39,12 @@ namespace { +template class DumpStyle; + template class ELFDumper : public ObjDumper { public: - ELFDumper(const ELFFile *Obj, StreamWriter &Writer); + ELFDumper(const ELFFile *Obj, StreamWriter &Writer, bool isGNUStyle); void printFileHeaders() override; void printSections() override; @@ -68,6 +70,7 @@ void printStackMap() const override; private: + std::unique_ptr> ELFDumperStyle; typedef ELFFile ELFO; typedef typename ELFO::Elf_Shdr Elf_Shdr; typedef typename ELFO::Elf_Sym Elf_Sym; @@ -181,6 +184,43 @@ ArrayRef getShndxTable() { return ShndxTable; } }; +template class DumpStyle { +public: + virtual void printFileHeaders(const typename ELFFile::Elf_Ehdr *e) = 0; +}; + +template class GNUStyle : public DumpStyle { +public: + typedef std::pair LineEntry; + GNUStyle(raw_ostream &os) : OS(os) {} + + void printFileHeaders(const typename ELFFile::Elf_Ehdr *e) override; + + void printLine(ArrayRef line) { + int position = 0; + for (const auto &entry : line) { + int blanks = position <= entry.second ? entry.second - position : 1; + std::string blankSpace(blanks, ' '); + OS << blankSpace << entry.first; + position = position + blanks + entry.first.size(); + } + OS << "\n"; + } + +private: + raw_ostream &OS; +}; + +template class LLVMStyle : public DumpStyle { +public: + LLVMStyle(StreamWriter &W) : W(W) {} + + void printFileHeaders(const typename ELFFile::Elf_Ehdr *e) override; + +private: + StreamWriter &W; +}; + template T errorOrDefault(ErrorOr Val, T Default = T()) { if (!Val) { error(Val.getError()); @@ -194,31 +234,32 @@ namespace llvm { template -static std::error_code createELFDumper(const ELFFile *Obj, - StreamWriter &Writer, - std::unique_ptr &Result) { - Result.reset(new ELFDumper(Obj, Writer)); +static std::error_code +createELFDumper(const ELFFile *Obj, StreamWriter &Writer, + std::unique_ptr &Result, bool GNUStyle) { + Result.reset(new ELFDumper(Obj, Writer, GNUStyle)); return readobj_error::success; } std::error_code createELFDumper(const object::ObjectFile *Obj, StreamWriter &Writer, - std::unique_ptr &Result) { + std::unique_ptr &Result, + bool GNUStyle) { // Little-endian 32-bit if (const ELF32LEObjectFile *ELFObj = dyn_cast(Obj)) - return createELFDumper(ELFObj->getELFFile(), Writer, Result); + return createELFDumper(ELFObj->getELFFile(), Writer, Result, GNUStyle); // Big-endian 32-bit if (const ELF32BEObjectFile *ELFObj = dyn_cast(Obj)) - return createELFDumper(ELFObj->getELFFile(), Writer, Result); + return createELFDumper(ELFObj->getELFFile(), Writer, Result, GNUStyle); // Little-endian 64-bit if (const ELF64LEObjectFile *ELFObj = dyn_cast(Obj)) - return createELFDumper(ELFObj->getELFFile(), Writer, Result); + return createELFDumper(ELFObj->getELFFile(), Writer, Result, GNUStyle); // Big-endian 64-bit if (const ELF64BEObjectFile *ELFObj = dyn_cast(Obj)) - return createELFDumper(ELFObj->getELFFile(), Writer, Result); + return createELFDumper(ELFObj->getELFFile(), Writer, Result, GNUStyle); return readobj_error::unsupported_obj_file_format; } @@ -679,7 +720,7 @@ LLVM_READOBJ_ENUM_ENT(ELF, EM_CYPRESS_M8C ), LLVM_READOBJ_ENUM_ENT(ELF, EM_R32C ), LLVM_READOBJ_ENUM_ENT(ELF, EM_TRIMEDIA ), - LLVM_READOBJ_ENUM_ENT(ELF, EM_HEXAGON ), + {"Qualcomm Hexagon", ELF::EM_HEXAGON }, LLVM_READOBJ_ENUM_ENT(ELF, EM_8051 ), LLVM_READOBJ_ENUM_ENT(ELF, EM_STXP7X ), LLVM_READOBJ_ENUM_ENT(ELF, EM_NDS32 ), @@ -909,7 +950,8 @@ }; template -ELFDumper::ELFDumper(const ELFFile *Obj, StreamWriter &Writer) +ELFDumper::ELFDumper(const ELFFile *Obj, StreamWriter &Writer, + bool isGNUStyle) : ObjDumper(Writer), Obj(Obj) { SmallVector LoadSegments; @@ -1013,6 +1055,10 @@ } } } + if (isGNUStyle) + ELFDumperStyle.reset(new GNUStyle(Writer.getOStream())); + else + ELFDumperStyle.reset(new LLVMStyle(Writer)); } template @@ -1040,49 +1086,7 @@ template void ELFDumper::printFileHeaders() { const Elf_Ehdr *Header = Obj->getHeader(); - - { - DictScope D(W, "ElfHeader"); - { - DictScope D(W, "Ident"); - W.printBinary("Magic", makeArrayRef(Header->e_ident).slice(ELF::EI_MAG0, - 4)); - W.printEnum ("Class", Header->e_ident[ELF::EI_CLASS], - makeArrayRef(ElfClass)); - W.printEnum ("DataEncoding", Header->e_ident[ELF::EI_DATA], - makeArrayRef(ElfDataEncoding)); - W.printNumber("FileVersion", Header->e_ident[ELF::EI_VERSION]); - - // Handle architecture specific OS/ABI values. - if (Header->e_machine == ELF::EM_AMDGPU && - Header->e_ident[ELF::EI_OSABI] == ELF::ELFOSABI_AMDGPU_HSA) - W.printHex("OS/ABI", "AMDGPU_HSA", ELF::ELFOSABI_AMDGPU_HSA); - else - W.printEnum ("OS/ABI", Header->e_ident[ELF::EI_OSABI], - makeArrayRef(ElfOSABI)); - W.printNumber("ABIVersion", Header->e_ident[ELF::EI_ABIVERSION]); - W.printBinary("Unused", makeArrayRef(Header->e_ident).slice(ELF::EI_PAD)); - } - - W.printEnum ("Type", Header->e_type, makeArrayRef(ElfObjectFileType)); - W.printEnum ("Machine", Header->e_machine, makeArrayRef(ElfMachineType)); - W.printNumber("Version", Header->e_version); - W.printHex ("Entry", Header->e_entry); - W.printHex ("ProgramHeaderOffset", Header->e_phoff); - W.printHex ("SectionHeaderOffset", Header->e_shoff); - if (Header->e_machine == EM_MIPS) - W.printFlags("Flags", Header->e_flags, makeArrayRef(ElfHeaderMipsFlags), - unsigned(ELF::EF_MIPS_ARCH), unsigned(ELF::EF_MIPS_ABI), - unsigned(ELF::EF_MIPS_MACH)); - else - W.printFlags("Flags", Header->e_flags); - W.printNumber("HeaderSize", Header->e_ehsize); - W.printNumber("ProgramHeaderEntrySize", Header->e_phentsize); - W.printNumber("ProgramHeaderCount", Header->e_phnum); - W.printNumber("SectionHeaderEntrySize", Header->e_shentsize); - W.printNumber("SectionHeaderCount", Header->e_shnum); - W.printNumber("StringTableSectionIndex", Header->e_shstrndx); - } + ELFDumperStyle->printFileHeaders(Header); } template @@ -2171,3 +2175,131 @@ llvm::outs(), StackMapV1Parser(*StackMapContentsArray)); } + +template +void +GNUStyle::printFileHeaders(const typename ELFFile::Elf_Ehdr *e) { + LineEntry fields[2]; + OS << "ELF Header:\n"; + OS << " Magic: "; + for (int i = 0; i < ELF::EI_NIDENT; i++) + OS << format(" %02x", static_cast(e->e_ident[i])); + OS << "\n"; + fields[0].first = "Class:"; + fields[0].second = 2; + enumStr(e->e_ident[ELF::EI_CLASS], makeArrayRef(ElfClass), fields[1].first); + fields[1].second = 37; + printLine(makeArrayRef(fields)); + fields[0].first = "Data:"; + enumStr(e->e_ident[ELF::EI_DATA], makeArrayRef(ElfDataEncoding), + fields[1].first); + printLine(makeArrayRef(fields)); + fields[0].first = "Version:"; + std::string tmpstr = to_hexString(e->e_ident[ELF::EI_VERSION]); + if (e->e_version == ELF::EV_CURRENT) + tmpstr += " (current)"; + fields[1].first = tmpstr; + printLine(makeArrayRef(fields)); + fields[0].first = "OS/ABI:"; + enumStr(e->e_ident[ELF::EI_OSABI], makeArrayRef(ElfOSABI), fields[1].first); + printLine(makeArrayRef(fields)); + fields[0].first = "ABI Version:"; + tmpstr = to_hexString(e->e_ident[ELF::EI_ABIVERSION]); + fields[1].first = tmpstr; + printLine(makeArrayRef(fields)); + fields[0].first = "Type:"; + enumStr(e->e_type, makeArrayRef(ElfObjectFileType), fields[1].first); + printLine(makeArrayRef(fields)); + fields[0].first = "Machine:"; + enumStr(e->e_machine, makeArrayRef(ElfMachineType), fields[1].first); + printLine(makeArrayRef(fields)); + fields[0].first = "Version:"; + tmpstr = "0x" + to_hexString(e->e_version); + fields[1].first = tmpstr; + printLine(makeArrayRef(fields)); + fields[0].first = "Entry point address:"; + tmpstr = "0x" + to_hexString(e->e_entry); + fields[1].first = tmpstr; + printLine(makeArrayRef(fields)); + fields[0].first = "Start of program headers:"; + tmpstr = std::to_string(e->e_phoff) + " (bytes into file)"; + fields[1].first = tmpstr; + printLine(makeArrayRef(fields)); + fields[0].first = "Start of section headers:"; + tmpstr = std::to_string(e->e_shoff) + " (bytes into file)"; + fields[1].first = tmpstr; + printLine(makeArrayRef(fields)); + fields[0].first = "Flags:"; + tmpstr = "0x" + to_hexString(e->e_flags); + fields[1].first = tmpstr; + printLine(makeArrayRef(fields)); + fields[0].first = "Size of this header:"; + tmpstr = std::to_string(e->e_ehsize) + " (bytes)"; + fields[1].first = tmpstr; + printLine(makeArrayRef(fields)); + fields[0].first = "Size of prgram headers:"; + tmpstr = std::to_string(e->e_phentsize) + " (bytes)"; + fields[1].first = tmpstr; + printLine(makeArrayRef(fields)); + fields[0].first = "Number of prgram headers:"; + tmpstr = std::to_string(e->e_phnum); + fields[1].first = tmpstr; + printLine(makeArrayRef(fields)); + fields[0].first = "Size of section headers:"; + tmpstr = std::to_string(e->e_shentsize) + " (bytes)"; + fields[1].first = tmpstr; + printLine(makeArrayRef(fields)); + fields[0].first = "Number of section headers:"; + tmpstr = std::to_string(e->e_shnum); + fields[1].first = tmpstr; + printLine(makeArrayRef(fields)); + fields[0].first = "Section header string table index:"; + tmpstr = std::to_string(e->e_shstrndx); + fields[1].first = tmpstr; + printLine(makeArrayRef(fields)); +} + +template +void +LLVMStyle::printFileHeaders(const typename ELFFile::Elf_Ehdr *e) { + { + DictScope D(W, "ElfHeader"); + { + DictScope D(W, "Ident"); + W.printBinary("Magic", makeArrayRef(e->e_ident).slice(ELF::EI_MAG0, 4)); + W.printEnum("Class", e->e_ident[ELF::EI_CLASS], makeArrayRef(ElfClass)); + W.printEnum("DataEncoding", e->e_ident[ELF::EI_DATA], + 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)); + W.printNumber("ABIVersion", e->e_ident[ELF::EI_ABIVERSION]); + W.printBinary("Unused", makeArrayRef(e->e_ident).slice(ELF::EI_PAD)); + } + + W.printEnum("Type", e->e_type, makeArrayRef(ElfObjectFileType)); + W.printEnum("Machine", e->e_machine, makeArrayRef(ElfMachineType)); + W.printNumber("Version", e->e_version); + W.printHex("Entry", e->e_entry); + W.printHex("ProgramHeaderOffset", e->e_phoff); + W.printHex("SectionHeaderOffset", e->e_shoff); + if (e->e_machine == EM_MIPS) + W.printFlags("Flags", e->e_flags, makeArrayRef(ElfHeaderMipsFlags), + unsigned(ELF::EF_MIPS_ARCH), unsigned(ELF::EF_MIPS_ABI), + unsigned(ELF::EF_MIPS_MACH)); + else + W.printFlags("Flags", e->e_flags); + W.printNumber("HeaderSize", e->e_ehsize); + W.printNumber("ProgramHeaderEntrySize", e->e_phentsize); + W.printNumber("ProgramHeaderCount", e->e_phnum); + W.printNumber("SectionHeaderEntrySize", e->e_shentsize); + W.printNumber("SectionHeaderCount", e->e_shnum); + W.printNumber("StringTableSectionIndex", e->e_shstrndx); + } +} Index: tools/llvm-readobj/ObjDumper.h =================================================================== --- tools/llvm-readobj/ObjDumper.h +++ tools/llvm-readobj/ObjDumper.h @@ -77,7 +77,8 @@ std::error_code createELFDumper(const object::ObjectFile *Obj, StreamWriter &Writer, - std::unique_ptr &Result); + std::unique_ptr &Result, + bool GNUStyle = false); std::error_code createMachODumper(const object::ObjectFile *Obj, StreamWriter &Writer, Index: tools/llvm-readobj/StreamWriter.h =================================================================== --- tools/llvm-readobj/StreamWriter.h +++ tools/llvm-readobj/StreamWriter.h @@ -50,6 +50,19 @@ raw_ostream &operator<<(raw_ostream &OS, const HexNumber& Value); +const std::string to_hexString(uint64_t Value, bool UpperCase = true); + +template +bool enumStr(T Value, ArrayRef> EnumValues, StringRef &Name) { + for (const auto &EnumItem : EnumValues) { + if (EnumItem.Value == Value) { + Name = EnumItem.Name; + return true; + } + } + return false; +} + class StreamWriter { public: StreamWriter(raw_ostream &OS) @@ -83,14 +96,7 @@ void printEnum(StringRef Label, T Value, ArrayRef > EnumValues) { StringRef Name; - bool Found = false; - for (const auto &EnumItem : EnumValues) { - if (EnumItem.Value == Value) { - Name = EnumItem.Name; - Found = true; - break; - } - } + bool Found = enumStr(Value, EnumValues, Name); if (Found) { startLine() << Label << ": " << Name << " (" << hex(Value) << ")\n"; Index: tools/llvm-readobj/StreamWriter.cpp =================================================================== --- tools/llvm-readobj/StreamWriter.cpp +++ tools/llvm-readobj/StreamWriter.cpp @@ -8,23 +8,30 @@ namespace llvm { raw_ostream &operator<<(raw_ostream &OS, const HexNumber& Value) { - uint64_t N = Value.Value; + OS << "0x" << to_hexString(Value.Value); + return OS; +} + +const std::string to_hexString(uint64_t Value, bool UpperCase) { // Zero is a special case. - if (N == 0) - return OS << "0x0"; + if (Value == 0) + return "0"; char NumberBuffer[20]; char *EndPtr = NumberBuffer + sizeof(NumberBuffer); char *CurPtr = EndPtr; + char A = 'a'; + int digits = 0; + if (UpperCase) + A = 'A'; - while (N) { - uintptr_t X = N % 16; - *--CurPtr = (X < 10 ? '0' + X : 'A' + X - 10); - N /= 16; + while (Value) { + uintptr_t X = Value % 16; + *--CurPtr = (X < 10 ? '0' + X : A + X - 10); + Value /= 16; + digits++; } - - OS << "0x"; - return OS.write(CurPtr, EndPtr - CurPtr); + return std::string(CurPtr, digits); } void StreamWriter::printBinaryImpl(StringRef Label, StringRef Str, Index: tools/llvm-readobj/llvm-readobj.cpp =================================================================== --- tools/llvm-readobj/llvm-readobj.cpp +++ tools/llvm-readobj/llvm-readobj.cpp @@ -227,6 +227,10 @@ cl::desc("Display ELF version sections (if present)")); cl::alias VersionInfoShort("V", cl::desc("Alias for -version-info"), cl::aliasopt(VersionInfo)); + + cl::opt GNUStyle("gnu-style", cl::init(false), + cl::desc("print ELF dump simialr to readelf tools")); + } // namespace opts namespace llvm { @@ -285,7 +289,7 @@ if (Obj->isCOFF()) return createCOFFDumper(Obj, Writer, Result); if (Obj->isELF()) - return createELFDumper(Obj, Writer, Result); + return createELFDumper(Obj, Writer, Result, opts::GNUStyle); if (Obj->isMachO()) return createMachODumper(Obj, Writer, Result); @@ -301,14 +305,15 @@ return; } - outs() << '\n'; - outs() << "File: " << Obj->getFileName() << "\n"; - outs() << "Format: " << Obj->getFileFormatName() << "\n"; - outs() << "Arch: " - << Triple::getArchTypeName((llvm::Triple::ArchType)Obj->getArch()) - << "\n"; - outs() << "AddressSize: " << (8*Obj->getBytesInAddress()) << "bit\n"; - Dumper->printLoadName(); + if (!opts::GNUStyle) { + outs() << '\n'; + outs() << "File: " << Obj->getFileName() << "\n"; + outs() << "Format: " << Obj->getFileFormatName() << "\n"; + outs() << "Arch: " << Triple::getArchTypeName( + (llvm::Triple::ArchType)Obj->getArch()) << "\n"; + outs() << "AddressSize: " << (8 * Obj->getBytesInAddress()) << "bit\n"; + Dumper->printLoadName(); + } if (opts::FileHeaders) Dumper->printFileHeaders();