diff --git a/llvm/tools/llvm-readobj/ELFDumper.h b/llvm/tools/llvm-readobj/ELFDumper.h new file mode 100644 --- /dev/null +++ b/llvm/tools/llvm-readobj/ELFDumper.h @@ -0,0 +1,215 @@ +//===-- ELFDumper.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_TOOLS_LLVM_READOBJ_ELFDUMPER_H +#define LLVM_TOOLS_LLVM_READOBJ_ELFDUMPER_H + +#include "llvm/Object/ELF.h" +#include "llvm/Support/FormattedStream.h" +#include "llvm/Support/ScopedPrinter.h" + +namespace llvm { +namespace ELF { +#define LLVM_READOBJ_ENUM_CASE(ns, enum) \ + case ns::enum: \ + return #enum; + +#define ENUM_ENT(enum, altName) \ + { #enum, altName, ELF::enum } + +#define ENUM_ENT_1(enum) \ + { #enum, #enum, ELF::enum } + +const EnumEntry ElfSectionFlags[] = { + ENUM_ENT(SHF_WRITE, "W"), ENUM_ENT(SHF_ALLOC, "A"), + ENUM_ENT(SHF_EXECINSTR, "X"), ENUM_ENT(SHF_MERGE, "M"), + ENUM_ENT(SHF_STRINGS, "S"), ENUM_ENT(SHF_INFO_LINK, "I"), + ENUM_ENT(SHF_LINK_ORDER, "L"), ENUM_ENT(SHF_OS_NONCONFORMING, "O"), + ENUM_ENT(SHF_GROUP, "G"), ENUM_ENT(SHF_TLS, "T"), + ENUM_ENT(SHF_COMPRESSED, "C"), ENUM_ENT(SHF_GNU_RETAIN, "R"), + ENUM_ENT(SHF_EXCLUDE, "E"), +}; + +const EnumEntry ElfXCoreSectionFlags[] = { + ENUM_ENT(XCORE_SHF_CP_SECTION, ""), ENUM_ENT(XCORE_SHF_DP_SECTION, "")}; + +const EnumEntry ElfARMSectionFlags[] = { + ENUM_ENT(SHF_ARM_PURECODE, "y")}; + +const EnumEntry ElfHexagonSectionFlags[] = { + ENUM_ENT(SHF_HEX_GPREL, "")}; + +const EnumEntry ElfMipsSectionFlags[] = { + ENUM_ENT(SHF_MIPS_NODUPES, ""), ENUM_ENT(SHF_MIPS_NAMES, ""), + ENUM_ENT(SHF_MIPS_LOCAL, ""), ENUM_ENT(SHF_MIPS_NOSTRIP, ""), + ENUM_ENT(SHF_MIPS_GPREL, ""), ENUM_ENT(SHF_MIPS_MERGE, ""), + ENUM_ENT(SHF_MIPS_ADDR, ""), ENUM_ENT(SHF_MIPS_STRING, "")}; + +const EnumEntry ElfX86_64SectionFlags[] = { + ENUM_ENT(SHF_X86_64_LARGE, "l")}; + +struct Field { + std::string Str; + unsigned Column; + + Field(StringRef S, unsigned Col) : Str(std::string(S)), Column(Col) {} + Field(unsigned Col) : Column(Col) {} +}; + +inline void printFields(formatted_raw_ostream &OS, StringRef Str1, + StringRef Str2) { + OS.PadToColumn(2u); + OS << Str1; + OS.PadToColumn(37u); + OS << Str2 << "\n"; + OS.flush(); +} + +inline void printField(formatted_raw_ostream &OS, struct Field F) { + if (F.Column != 0) + OS.PadToColumn(F.Column); + OS << F.Str; + OS.flush(); +} + +inline std::vector> +getSectionFlagsForTarget(unsigned EMachine) { + std::vector> Ret(std::begin(ElfSectionFlags), + std::end(ElfSectionFlags)); + switch (EMachine) { + case EM_ARM: + Ret.insert(Ret.end(), std::begin(ElfARMSectionFlags), + std::end(ElfARMSectionFlags)); + break; + case EM_HEXAGON: + Ret.insert(Ret.end(), std::begin(ElfHexagonSectionFlags), + std::end(ElfHexagonSectionFlags)); + break; + case EM_MIPS: + Ret.insert(Ret.end(), std::begin(ElfMipsSectionFlags), + std::end(ElfMipsSectionFlags)); + break; + case EM_X86_64: + Ret.insert(Ret.end(), std::begin(ElfX86_64SectionFlags), + std::end(ElfX86_64SectionFlags)); + break; + case EM_XCORE: + Ret.insert(Ret.end(), std::begin(ElfXCoreSectionFlags), + std::end(ElfXCoreSectionFlags)); + break; + default: + break; + } + return Ret; +} + +inline std::string getGNUFlags(unsigned EMachine, uint64_t Flags) { + // Here we are trying to build the flags string in the same way as GNU does. + // It is not that straightforward. Imagine we have sh_flags == 0x90000000. + // SHF_EXCLUDE ("E") has a value of 0x80000000 and SHF_MASKPROC is 0xf0000000. + // GNU readelf will not print "E" or "Ep" in this case, but will print just + // "p". It only will print "E" when no other processor flag is set. + std::string Str; + bool HasUnknownFlag = false; + bool HasOSFlag = false; + bool HasProcFlag = false; + std::vector> FlagsList = + getSectionFlagsForTarget(EMachine); + while (Flags) { + // Take the least significant bit as a flag. + uint64_t Flag = Flags & -Flags; + Flags -= Flag; + + // Find the flag in the known flags list. + auto I = llvm::find_if(FlagsList, [=](const EnumEntry &E) { + // Flags with empty names are not printed in GNU style output. + return E.Value == Flag && !E.AltName.empty(); + }); + if (I != FlagsList.end()) { + Str += I->AltName; + continue; + } + + // If we did not find a matching regular flag, then we deal with an OS + // specific flag, processor specific flag or an unknown flag. + if (Flag & ELF::SHF_MASKOS) { + HasOSFlag = true; + Flags &= ~ELF::SHF_MASKOS; + } else if (Flag & ELF::SHF_MASKPROC) { + HasProcFlag = true; + // Mask off all the processor-specific bits. This removes the SHF_EXCLUDE + // bit if set so that it doesn't also get printed. + Flags &= ~ELF::SHF_MASKPROC; + } else { + HasUnknownFlag = true; + } + } + + // "o", "p" and "x" are printed last. + if (HasOSFlag) + Str += "o"; + if (HasProcFlag) + Str += "p"; + if (HasUnknownFlag) + Str += "x"; + return Str; +} + +// Print the offset of a particular section from anyone of the ranges: +// [SHT_LOOS, SHT_HIOS], [SHT_LOPROC, SHT_HIPROC], [SHT_LOUSER, SHT_HIUSER]. +// If 'Type' does not fall within any of those ranges, then a string is +// returned as '' followed by the type value. +inline std::string getSectionTypeOffsetString(unsigned Type) { + if (Type >= SHT_LOOS && Type <= SHT_HIOS) + return "LOOS+0x" + to_hexString(Type - SHT_LOOS); + else if (Type >= SHT_LOPROC && Type <= SHT_HIPROC) + return "LOPROC+0x" + to_hexString(Type - SHT_LOPROC); + else if (Type >= SHT_LOUSER && Type <= SHT_HIUSER) + return "LOUSER+0x" + to_hexString(Type - SHT_LOUSER); + return "0x" + to_hexString(Type) + ": "; +} + +std::string getSectionTypeString(unsigned Machine, unsigned Type) { + StringRef Name = object::getELFSectionTypeName(Machine, Type); + + // Handle SHT_GNU_* type names. + if (Name.startswith("SHT_GNU_")) { + if (Name == "SHT_GNU_HASH") + return "GNU_HASH"; + // E.g. SHT_GNU_verneed -> VERNEED. + return Name.drop_front(8).upper(); + } + + if (Name == "SHT_SYMTAB_SHNDX") + return "SYMTAB SECTION INDICES"; + + if (Name.startswith("SHT_")) + return Name.drop_front(4).str(); + return getSectionTypeOffsetString(Type); +} + +void printSectionDescription(formatted_raw_ostream &OS, unsigned EMachine) { + OS << "Key to Flags:\n"; + OS << " W (write), A (alloc), X (execute), M (merge), S (strings), I " + "(info),\n"; + OS << " L (link order), O (extra OS processing required), G (group), T " + "(TLS),\n"; + OS << " C (compressed), x (unknown), o (OS specific), E (exclude),\n"; + OS << " R (retain)"; + + if (EMachine == EM_X86_64) + OS << ", l (large)"; + else if (EMachine == EM_ARM) + OS << ", y (purecode)"; + + OS << ", p (processor specific)\n"; +} +} // namespace ELF +} // namespace llvm + +#endif diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -11,6 +11,7 @@ /// //===----------------------------------------------------------------------===// +#include "ELFDumper.h" #include "ARMEHABIPrinter.h" #include "DwarfCFIEHPrinter.h" #include "ObjDumper.h" @@ -31,7 +32,6 @@ #include "llvm/BinaryFormat/AMDGPUMetadataVerifier.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/Demangle/Demangle.h" -#include "llvm/Object/ELF.h" #include "llvm/Object/ELFObjectFile.h" #include "llvm/Object/ELFTypes.h" #include "llvm/Object/Error.h" @@ -47,13 +47,11 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Format.h" #include "llvm/Support/FormatVariadic.h" -#include "llvm/Support/FormattedStream.h" #include "llvm/Support/LEB128.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/MipsABIFlags.h" #include "llvm/Support/RISCVAttributeParser.h" #include "llvm/Support/RISCVAttributes.h" -#include "llvm/Support/ScopedPrinter.h" #include "llvm/Support/raw_ostream.h" #include #include @@ -70,16 +68,6 @@ using namespace llvm::object; using namespace ELF; -#define LLVM_READOBJ_ENUM_CASE(ns, enum) \ - case ns::enum: \ - return #enum; - -#define ENUM_ENT(enum, altName) \ - { #enum, altName, ELF::enum } - -#define ENUM_ENT_1(enum) \ - { #enum, #enum, ELF::enum } - namespace { template struct RelSymbol { @@ -576,14 +564,6 @@ void printHashTableSymbols(const Elf_Hash &HashTable); void printGnuHashTableSymbols(const Elf_GnuHash &GnuHashTable); - struct Field { - std::string Str; - unsigned Column; - - Field(StringRef S, unsigned Col) : Str(std::string(S)), Column(Col) {} - Field(unsigned Col) : Column(Col) {} - }; - template std::string printEnum(T Value, ArrayRef> EnumValues) const { for (const EnumEntry &EnumItem : EnumValues) @@ -619,13 +599,6 @@ return Str; } - formatted_raw_ostream &printField(struct Field F) const { - if (F.Column != 0) - OS.PadToColumn(F.Column); - OS << F.Str; - OS.flush(); - return OS; - } void printHashedSymbol(const Elf_Sym *Sym, unsigned SymIndex, DataRegion ShndxTable, StringRef StrTable, uint32_t Bucket); @@ -1208,133 +1181,6 @@ return "(unknown)"; } -static const EnumEntry ElfSectionFlags[] = { - ENUM_ENT(SHF_WRITE, "W"), - ENUM_ENT(SHF_ALLOC, "A"), - ENUM_ENT(SHF_EXECINSTR, "X"), - ENUM_ENT(SHF_MERGE, "M"), - ENUM_ENT(SHF_STRINGS, "S"), - ENUM_ENT(SHF_INFO_LINK, "I"), - ENUM_ENT(SHF_LINK_ORDER, "L"), - ENUM_ENT(SHF_OS_NONCONFORMING, "O"), - ENUM_ENT(SHF_GROUP, "G"), - ENUM_ENT(SHF_TLS, "T"), - ENUM_ENT(SHF_COMPRESSED, "C"), - ENUM_ENT(SHF_GNU_RETAIN, "R"), - ENUM_ENT(SHF_EXCLUDE, "E"), -}; - -static const EnumEntry ElfXCoreSectionFlags[] = { - ENUM_ENT(XCORE_SHF_CP_SECTION, ""), - ENUM_ENT(XCORE_SHF_DP_SECTION, "") -}; - -static const EnumEntry ElfARMSectionFlags[] = { - ENUM_ENT(SHF_ARM_PURECODE, "y") -}; - -static const EnumEntry ElfHexagonSectionFlags[] = { - ENUM_ENT(SHF_HEX_GPREL, "") -}; - -static const EnumEntry ElfMipsSectionFlags[] = { - ENUM_ENT(SHF_MIPS_NODUPES, ""), - ENUM_ENT(SHF_MIPS_NAMES, ""), - ENUM_ENT(SHF_MIPS_LOCAL, ""), - ENUM_ENT(SHF_MIPS_NOSTRIP, ""), - ENUM_ENT(SHF_MIPS_GPREL, ""), - ENUM_ENT(SHF_MIPS_MERGE, ""), - ENUM_ENT(SHF_MIPS_ADDR, ""), - ENUM_ENT(SHF_MIPS_STRING, "") -}; - -static const EnumEntry ElfX86_64SectionFlags[] = { - ENUM_ENT(SHF_X86_64_LARGE, "l") -}; - -static std::vector> -getSectionFlagsForTarget(unsigned EMachine) { - std::vector> Ret(std::begin(ElfSectionFlags), - std::end(ElfSectionFlags)); - switch (EMachine) { - case EM_ARM: - Ret.insert(Ret.end(), std::begin(ElfARMSectionFlags), - std::end(ElfARMSectionFlags)); - break; - case EM_HEXAGON: - Ret.insert(Ret.end(), std::begin(ElfHexagonSectionFlags), - std::end(ElfHexagonSectionFlags)); - break; - case EM_MIPS: - Ret.insert(Ret.end(), std::begin(ElfMipsSectionFlags), - std::end(ElfMipsSectionFlags)); - break; - case EM_X86_64: - Ret.insert(Ret.end(), std::begin(ElfX86_64SectionFlags), - std::end(ElfX86_64SectionFlags)); - break; - case EM_XCORE: - Ret.insert(Ret.end(), std::begin(ElfXCoreSectionFlags), - std::end(ElfXCoreSectionFlags)); - break; - default: - break; - } - return Ret; -} - -static std::string getGNUFlags(unsigned EMachine, uint64_t Flags) { - // Here we are trying to build the flags string in the same way as GNU does. - // It is not that straightforward. Imagine we have sh_flags == 0x90000000. - // SHF_EXCLUDE ("E") has a value of 0x80000000 and SHF_MASKPROC is 0xf0000000. - // GNU readelf will not print "E" or "Ep" in this case, but will print just - // "p". It only will print "E" when no other processor flag is set. - std::string Str; - bool HasUnknownFlag = false; - bool HasOSFlag = false; - bool HasProcFlag = false; - std::vector> FlagsList = - getSectionFlagsForTarget(EMachine); - while (Flags) { - // Take the least significant bit as a flag. - uint64_t Flag = Flags & -Flags; - Flags -= Flag; - - // Find the flag in the known flags list. - auto I = llvm::find_if(FlagsList, [=](const EnumEntry &E) { - // Flags with empty names are not printed in GNU style output. - return E.Value == Flag && !E.AltName.empty(); - }); - if (I != FlagsList.end()) { - Str += I->AltName; - continue; - } - - // If we did not find a matching regular flag, then we deal with an OS - // specific flag, processor specific flag or an unknown flag. - if (Flag & ELF::SHF_MASKOS) { - HasOSFlag = true; - Flags &= ~ELF::SHF_MASKOS; - } else if (Flag & ELF::SHF_MASKPROC) { - HasProcFlag = true; - // Mask off all the processor-specific bits. This removes the SHF_EXCLUDE - // bit if set so that it doesn't also get printed. - Flags &= ~ELF::SHF_MASKPROC; - } else { - HasUnknownFlag = true; - } - } - - // "o", "p" and "x" are printed last. - if (HasOSFlag) - Str += "o"; - if (HasProcFlag) - Str += "p"; - if (HasUnknownFlag) - Str += "x"; - return Str; -} - static StringRef segmentTypeToString(unsigned Arch, unsigned Type) { // Check potentially overlapped processor-specific program header type. switch (Arch) { @@ -3158,15 +3004,6 @@ printRelRelaReloc(R, *Target); } -static inline void printFields(formatted_raw_ostream &OS, StringRef Str1, - StringRef Str2) { - OS.PadToColumn(2u); - OS << Str1; - OS.PadToColumn(37u); - OS << Str2 << "\n"; - OS.flush(); -} - template static std::string getSectionHeadersNumString(const ELFFile &Obj, StringRef FileName) { @@ -3439,7 +3276,7 @@ Fields[4].Str = std::string(RelSym.Name); for (const Field &F : Fields) - printField(F); + printField(OS, F); std::string Addend; if (Optional A = R.Addend) { @@ -3546,57 +3383,6 @@ OS << "\nThere are no relocations in this file.\n"; } -// Print the offset of a particular section from anyone of the ranges: -// [SHT_LOOS, SHT_HIOS], [SHT_LOPROC, SHT_HIPROC], [SHT_LOUSER, SHT_HIUSER]. -// If 'Type' does not fall within any of those ranges, then a string is -// returned as '' followed by the type value. -static std::string getSectionTypeOffsetString(unsigned Type) { - if (Type >= SHT_LOOS && Type <= SHT_HIOS) - return "LOOS+0x" + to_hexString(Type - SHT_LOOS); - else if (Type >= SHT_LOPROC && Type <= SHT_HIPROC) - return "LOPROC+0x" + to_hexString(Type - SHT_LOPROC); - else if (Type >= SHT_LOUSER && Type <= SHT_HIUSER) - return "LOUSER+0x" + to_hexString(Type - SHT_LOUSER); - return "0x" + to_hexString(Type) + ": "; -} - -static std::string getSectionTypeString(unsigned Machine, unsigned Type) { - StringRef Name = getELFSectionTypeName(Machine, Type); - - // Handle SHT_GNU_* type names. - if (Name.startswith("SHT_GNU_")) { - if (Name == "SHT_GNU_HASH") - return "GNU_HASH"; - // E.g. SHT_GNU_verneed -> VERNEED. - return Name.drop_front(8).upper(); - } - - if (Name == "SHT_SYMTAB_SHNDX") - return "SYMTAB SECTION INDICES"; - - if (Name.startswith("SHT_")) - return Name.drop_front(4).str(); - return getSectionTypeOffsetString(Type); -} - -static void printSectionDescription(formatted_raw_ostream &OS, - unsigned EMachine) { - OS << "Key to Flags:\n"; - OS << " W (write), A (alloc), X (execute), M (merge), S (strings), I " - "(info),\n"; - OS << " L (link order), O (extra OS processing required), G (group), T " - "(TLS),\n"; - OS << " C (compressed), x (unknown), o (OS specific), E (exclude),\n"; - OS << " R (retain)"; - - if (EMachine == EM_X86_64) - OS << ", l (large)"; - else if (EMachine == EM_ARM) - OS << ", y (purecode)"; - - OS << ", p (processor specific)\n"; -} - template void GNUELFDumper::printSectionHeaders() { unsigned Bias = ELFT::Is64Bits ? 0 : 8; ArrayRef Sections = cantFail(this->Obj.sections()); @@ -3610,7 +3396,7 @@ {"ES", 72 - Bias}, {"Flg", 75 - Bias}, {"Lk", 79 - Bias}, {"Inf", 82 - Bias}, {"Al", 86 - Bias}}; for (const Field &F : Fields) - printField(F); + printField(OS, F); OS << "\n"; StringRef SecStrTable; @@ -3643,7 +3429,7 @@ OS.PadToColumn(Fields[0].Column); OS << "[" << right_justify(Fields[0].Str, 2) << "]"; for (int i = 1; i < 7; i++) - printField(Fields[i]); + printField(OS, Fields[i]); OS.PadToColumn(Fields[7].Column); OS << right_justify(Fields[7].Str, 3); OS.PadToColumn(Fields[8].Column); @@ -3774,7 +3560,7 @@ Fields[7].Str = this->getFullSymbolName(Symbol, SymIndex, ShndxTable, StrTable, IsDynamic); for (const Field &Entry : Fields) - printField(Entry); + printField(OS, Entry); OS << "\n"; } @@ -3810,7 +3596,7 @@ this->getFullSymbolName(*Symbol, SymIndex, ShndxTable, StrTable, true); for (const Field &Entry : Fields) - printField(Entry); + printField(OS, Entry); OS << "\n"; } @@ -3977,7 +3763,7 @@ auto PrintFields = [&](ArrayRef V) { for (const Field &F : V) - printField(F); + printField(OS, F); OS << "\n"; }; @@ -4199,7 +3985,7 @@ Fields[6].Str = printPhdrFlags(Phdr.p_flags); Fields[7].Str = to_string(format_hex(Phdr.p_align, 1)); for (const Field &F : Fields) - printField(F); + printField(OS, F); if (Phdr.p_type == ELF::PT_INTERP) { OS << "\n"; auto ReportBadInterp = [&](const Twine &Msg) { @@ -4775,7 +4561,7 @@ Fields[0].Str = to_string(format_decimal(++SymIndex, 6)) + ":"; Fields[1].Str = this->getStaticSymbolName(Sym); for (const Field &Entry : Fields) - printField(Entry); + printField(OS, Entry); OS << "\n"; } } diff --git a/llvm/tools/llvm-readobj/ObjDumper.h b/llvm/tools/llvm-readobj/ObjDumper.h --- a/llvm/tools/llvm-readobj/ObjDumper.h +++ b/llvm/tools/llvm-readobj/ObjDumper.h @@ -15,6 +15,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/FormattedStream.h" #include