Changeset View
Changeset View
Standalone View
Standalone View
llvm/tools/llvm-readobj/ELFDumper.cpp
- This file is larger than 256 KB, so syntax highlighting is disabled by default.
Show First 20 Lines • Show All 678 Lines • ▼ Show 20 Lines | public: | ||||
void printVersionDependencySection(const Elf_Shdr *Sec) override; | void printVersionDependencySection(const Elf_Shdr *Sec) override; | ||||
void printHashHistograms() override; | void printHashHistograms() override; | ||||
void printCGProfile() override; | void printCGProfile() override; | ||||
void printBBAddrMaps() override; | void printBBAddrMaps() override; | ||||
void printAddrsig() override; | void printAddrsig() override; | ||||
void printNotes() override; | void printNotes() override; | ||||
void printELFLinkerOptions() override; | void printELFLinkerOptions() override; | ||||
void printStackSizes() override; | void printStackSizes() override; | ||||
void printSymbolSection(const Elf_Sym &Symbol, unsigned SymIndex, | |||||
DataRegion<Elf_Word> ShndxTable) const; | |||||
private: | private: | ||||
void printRelrReloc(const Elf_Relr &R) override; | void printRelrReloc(const Elf_Relr &R) override; | ||||
void printRelRelaReloc(const Relocation<ELFT> &R, | void printRelRelaReloc(const Relocation<ELFT> &R, | ||||
const RelSymbol<ELFT> &RelSym) override; | const RelSymbol<ELFT> &RelSym) override; | ||||
void printSymbolSection(const Elf_Sym &Symbol, unsigned SymIndex, | |||||
DataRegion<Elf_Word> ShndxTable) const; | |||||
void printSymbol(const Elf_Sym &Symbol, unsigned SymIndex, | void printSymbol(const Elf_Sym &Symbol, unsigned SymIndex, | ||||
DataRegion<Elf_Word> ShndxTable, | DataRegion<Elf_Word> ShndxTable, | ||||
std::optional<StringRef> StrTable, bool IsDynamic, | std::optional<StringRef> StrTable, bool IsDynamic, | ||||
bool /*NonVisibilityBitsUsed*/) const override; | bool /*NonVisibilityBitsUsed*/) const override; | ||||
void printProgramHeaders() override; | void printProgramHeaders() override; | ||||
void printSectionMapping() override {} | void printSectionMapping() override {} | ||||
void printStackSizeEntry(uint64_t Size, | void printStackSizeEntry(uint64_t Size, | ||||
ArrayRef<std::string> FuncNames) override; | ArrayRef<std::string> FuncNames) override; | ||||
void printMipsGOT(const MipsGOTParser<ELFT> &Parser) override; | void printMipsGOT(const MipsGOTParser<ELFT> &Parser) override; | ||||
void printMipsPLT(const MipsGOTParser<ELFT> &Parser) override; | void printMipsPLT(const MipsGOTParser<ELFT> &Parser) override; | ||||
void printMipsABIFlags() override; | void printMipsABIFlags() override; | ||||
virtual void printZeroSymbolOtherField(const Elf_Sym &Symbol) const; | |||||
protected: | protected: | ||||
void printSymbolOtherField(const Elf_Sym &Symbol) const; | |||||
ScopedPrinter &W; | ScopedPrinter &W; | ||||
}; | }; | ||||
// JSONELFDumper shares most of the same implementation as LLVMELFDumper except | // JSONELFDumper shares most of the same implementation as LLVMELFDumper except | ||||
// it uses a JSONScopedPrinter. | // it uses a JSONScopedPrinter. | ||||
template <typename ELFT> class JSONELFDumper : public LLVMELFDumper<ELFT> { | template <typename ELFT> class JSONELFDumper : public LLVMELFDumper<ELFT> { | ||||
public: | public: | ||||
LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) | LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) | ||||
JSONELFDumper(const object::ELFObjectFile<ELFT> &ObjF, ScopedPrinter &Writer) | JSONELFDumper(const object::ELFObjectFile<ELFT> &ObjF, ScopedPrinter &Writer) | ||||
: LLVMELFDumper<ELFT>(ObjF, Writer) {} | : LLVMELFDumper<ELFT>(ObjF, Writer) {} | ||||
void printFileSummary(StringRef FileStr, ObjectFile &Obj, | void printFileSummary(StringRef FileStr, ObjectFile &Obj, | ||||
ArrayRef<std::string> InputFilenames, | ArrayRef<std::string> InputFilenames, | ||||
const Archive *A) override; | const Archive *A) override; | ||||
virtual void printZeroSymbolOtherField(const Elf_Sym &Symbol) const override; | |||||
private: | private: | ||||
std::unique_ptr<DictScope> FileScope; | std::unique_ptr<DictScope> FileScope; | ||||
}; | }; | ||||
} // end anonymous namespace | } // end anonymous namespace | ||||
namespace llvm { | namespace llvm { | ||||
▲ Show 20 Lines • Show All 6,080 Lines • ▼ Show 20 Lines | else | ||||
consumeError(SectionName.takeError()); | consumeError(SectionName.takeError()); | ||||
W.printHex("Section", "<?>", *SectionIndex); | W.printHex("Section", "<?>", *SectionIndex); | ||||
} else { | } else { | ||||
W.printHex("Section", *SectionName, *SectionIndex); | W.printHex("Section", *SectionName, *SectionIndex); | ||||
} | } | ||||
} | } | ||||
template <class ELFT> | template <class ELFT> | ||||
void LLVMELFDumper<ELFT>::printSymbolOtherField(const Elf_Sym &Symbol) const { | |||||
std::vector<EnumEntry<unsigned>> SymOtherFlags = | |||||
this->getOtherFlagsFromSymbol(this->Obj.getHeader(), Symbol); | |||||
W.printFlags("Other", Symbol.st_other, makeArrayRef(SymOtherFlags), 0x3u); | |||||
} | |||||
template <class ELFT> | |||||
void LLVMELFDumper<ELFT>::printZeroSymbolOtherField( | |||||
const Elf_Sym &Symbol) const { | |||||
assert(Symbol.st_other == 0 && "non-zero Other Field"); | |||||
// Usually st_other flag is zero. Do not pollute the output | |||||
// by flags enumeration in that case. | |||||
W.printNumber("Other", 0); | |||||
} | |||||
template <class ELFT> | |||||
void LLVMELFDumper<ELFT>::printSymbol(const Elf_Sym &Symbol, unsigned SymIndex, | void LLVMELFDumper<ELFT>::printSymbol(const Elf_Sym &Symbol, unsigned SymIndex, | ||||
DataRegion<Elf_Word> ShndxTable, | DataRegion<Elf_Word> ShndxTable, | ||||
std::optional<StringRef> StrTable, | std::optional<StringRef> StrTable, | ||||
bool IsDynamic, | bool IsDynamic, | ||||
bool /*NonVisibilityBitsUsed*/) const { | bool /*NonVisibilityBitsUsed*/) const { | ||||
std::string FullSymbolName = this->getFullSymbolName( | std::string FullSymbolName = this->getFullSymbolName( | ||||
Symbol, SymIndex, ShndxTable, StrTable, IsDynamic); | Symbol, SymIndex, ShndxTable, StrTable, IsDynamic); | ||||
unsigned char SymbolType = Symbol.getType(); | unsigned char SymbolType = Symbol.getType(); | ||||
DictScope D(W, "Symbol"); | DictScope D(W, "Symbol"); | ||||
W.printNumber("Name", FullSymbolName, Symbol.st_name); | W.printNumber("Name", FullSymbolName, Symbol.st_name); | ||||
W.printHex("Value", Symbol.st_value); | W.printHex("Value", Symbol.st_value); | ||||
W.printNumber("Size", Symbol.st_size); | W.printNumber("Size", Symbol.st_size); | ||||
W.printEnum("Binding", Symbol.getBinding(), ArrayRef(ElfSymbolBindings)); | W.printEnum("Binding", Symbol.getBinding(), ArrayRef(ElfSymbolBindings)); | ||||
if (this->Obj.getHeader().e_machine == ELF::EM_AMDGPU && | if (this->Obj.getHeader().e_machine == ELF::EM_AMDGPU && | ||||
SymbolType >= ELF::STT_LOOS && SymbolType < ELF::STT_HIOS) | SymbolType >= ELF::STT_LOOS && SymbolType < ELF::STT_HIOS) | ||||
W.printEnum("Type", SymbolType, ArrayRef(AMDGPUSymbolTypes)); | W.printEnum("Type", SymbolType, ArrayRef(AMDGPUSymbolTypes)); | ||||
else | else | ||||
W.printEnum("Type", SymbolType, ArrayRef(ElfSymbolTypes)); | W.printEnum("Type", SymbolType, ArrayRef(ElfSymbolTypes)); | ||||
if (Symbol.st_other == 0) | if (Symbol.st_other == 0) | ||||
// Usually st_other flag is zero. Do not pollute the output | printZeroSymbolOtherField(Symbol); | ||||
// by flags enumeration in that case. | else | ||||
W.printNumber("Other", 0); | printSymbolOtherField(Symbol); | ||||
else { | |||||
std::vector<EnumEntry<unsigned>> SymOtherFlags = | |||||
this->getOtherFlagsFromSymbol(this->Obj.getHeader(), Symbol); | |||||
W.printFlags("Other", Symbol.st_other, makeArrayRef(SymOtherFlags), 0x3u); | |||||
} | |||||
printSymbolSection(Symbol, SymIndex, ShndxTable); | printSymbolSection(Symbol, SymIndex, ShndxTable); | ||||
} | } | ||||
template <class ELFT> | template <class ELFT> | ||||
void LLVMELFDumper<ELFT>::printSymbols(bool PrintSymbols, | void LLVMELFDumper<ELFT>::printSymbols(bool PrintSymbols, | ||||
bool PrintDynamicSymbols) { | bool PrintDynamicSymbols) { | ||||
if (PrintSymbols) { | if (PrintSymbols) { | ||||
ListScope Group(W, "Symbols"); | ListScope Group(W, "Symbols"); | ||||
▲ Show 20 Lines • Show All 704 Lines • ▼ Show 20 Lines | void JSONELFDumper<ELFT>::printFileSummary(StringRef FileStr, ObjectFile &Obj, | ||||
this->W.printString("File", FileStr); | this->W.printString("File", FileStr); | ||||
this->W.printString("Format", Obj.getFileFormatName()); | this->W.printString("Format", Obj.getFileFormatName()); | ||||
this->W.printString("Arch", Triple::getArchTypeName(Obj.getArch())); | this->W.printString("Arch", Triple::getArchTypeName(Obj.getArch())); | ||||
this->W.printString( | this->W.printString( | ||||
"AddressSize", | "AddressSize", | ||||
std::string(formatv("{0}bit", 8 * Obj.getBytesInAddress()))); | std::string(formatv("{0}bit", 8 * Obj.getBytesInAddress()))); | ||||
this->printLoadName(); | this->printLoadName(); | ||||
} | } | ||||
template <class ELFT> | |||||
void JSONELFDumper<ELFT>::printZeroSymbolOtherField( | |||||
jhenderson: Could we avoid the mass code-duplication by just introducing another function… | |||||
It might be worth a comment explaining why for JSON it's desirable to do things differently here. jhenderson: It might be worth a comment explaining why for JSON it's desirable to do things differently… | |||||
const Elf_Sym &Symbol) const { | |||||
this->printSymbolOtherField(Symbol); | |||||
} |
Could we avoid the mass code-duplication by just introducing another function "printSymbolOtherField" (or something like that) that is implemented differently for the two dumper types?
Maybe even "printZeroSymbolOtherField" so that only the very niche bit that needs to differ is distinguished. This function could then just delegate to the regular print symbol st_other code, to avoid needing to duplicate that in any way.
With this change, I think you could minimise the additional testing to just demonstrate basic behaviour difference for zero/non-zero st_other values, without needing to have additional cases for the various other aspects of this field printing.