diff --git a/llvm/test/tools/llvm-readobj/ELF/llvm-vs-json-format.test b/llvm/test/tools/llvm-readobj/ELF/llvm-vs-json-format.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/ELF/llvm-vs-json-format.test @@ -0,0 +1,46 @@ +# Check that the LLVM and JSON formats differ when their implementations diverge. + +# When the Other field is 0, the LLVM format prints the output differently, +# JSON formatting should always be consistent. + +# RUN: yaml2obj %s -o %t.o +# RUN: llvm-readobj --symbols %t.o | FileCheck %s --check-prefix=LLVM +# RUN: llvm-readobj --symbols --pretty-print --elf-output-style=JSON %t.o | FileCheck %s --check-prefix=JSON + +# LLVM: Name: foo +# LLVM: Other [ (0x80) +# LLVM-NEXT: STO_AARCH64_VARIANT_PCS (0x80) +# LLVM-NEXT: ] +# LLVM: Name: bar +# LLVM: Other: 0 + +# JSON: "Value": "foo", +# JSON: "Other": { +# JSON-NEXT: "RawFlags": 128, +# JSON-NEXT: "Flags": [ +# JSON-NEXT: { +# JSON-NEXT: "Name": "STO_AARCH64_VARIANT_PCS", +# JSON-NEXT: "Value": 128 +# JSON-NEXT: } +# JSON-NEXT: ] +# JSON-NEXT: }, + +# JSON: "Name": { +# JSON-NEXT: "Value": "bar", +# JSON: "Other": { +# JSON-NEXT: "RawFlags": 0, +# JSON-NEXT: "Flags": [] +# JSON-NEXT: }, + + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_AARCH64 +Symbols: + - Name: foo + Other: [ STO_AARCH64_VARIANT_PCS ] + - Name: bar + Other: [ ] 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 @@ -684,14 +684,14 @@ void printNotes() override; void printELFLinkerOptions() override; void printStackSizes() override; + void printSymbolSection(const Elf_Sym &Symbol, unsigned SymIndex, + DataRegion ShndxTable) const; private: void printRelrReloc(const Elf_Relr &R) override; void printRelRelaReloc(const Relocation &R, const RelSymbol &RelSym) override; - void printSymbolSection(const Elf_Sym &Symbol, unsigned SymIndex, - DataRegion ShndxTable) const; void printSymbol(const Elf_Sym &Symbol, unsigned SymIndex, DataRegion ShndxTable, std::optional StrTable, bool IsDynamic, @@ -704,8 +704,10 @@ void printMipsGOT(const MipsGOTParser &Parser) override; void printMipsPLT(const MipsGOTParser &Parser) override; void printMipsABIFlags() override; + virtual void printZeroSymbolOtherField(const Elf_Sym &Symbol) const; protected: + void printSymbolOtherField(const Elf_Sym &Symbol) const; ScopedPrinter &W; }; @@ -721,6 +723,7 @@ void printFileSummary(StringRef FileStr, ObjectFile &Obj, ArrayRef InputFilenames, const Archive *A) override; + virtual void printZeroSymbolOtherField(const Elf_Sym &Symbol) const override; private: std::unique_ptr FileScope; @@ -6804,6 +6807,22 @@ } } +template +void LLVMELFDumper::printSymbolOtherField(const Elf_Sym &Symbol) const { + std::vector> SymOtherFlags = + this->getOtherFlagsFromSymbol(this->Obj.getHeader(), Symbol); + W.printFlags("Other", Symbol.st_other, makeArrayRef(SymOtherFlags), 0x3u); +} + +template +void LLVMELFDumper::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 void LLVMELFDumper::printSymbol(const Elf_Sym &Symbol, unsigned SymIndex, DataRegion ShndxTable, @@ -6825,14 +6844,9 @@ else W.printEnum("Type", SymbolType, makeArrayRef(ElfSymbolTypes)); if (Symbol.st_other == 0) - // Usually st_other flag is zero. Do not pollute the output - // by flags enumeration in that case. - W.printNumber("Other", 0); - else { - std::vector> SymOtherFlags = - this->getOtherFlagsFromSymbol(this->Obj.getHeader(), Symbol); - W.printFlags("Other", Symbol.st_other, makeArrayRef(SymOtherFlags), 0x3u); - } + printZeroSymbolOtherField(Symbol); + else + printSymbolOtherField(Symbol); printSymbolSection(Symbol, SymIndex, ShndxTable); } @@ -7552,3 +7566,9 @@ std::string(formatv("{0}bit", 8 * Obj.getBytesInAddress()))); this->printLoadName(); } + +template +void JSONELFDumper::printZeroSymbolOtherField( + const Elf_Sym &Symbol) const { + this->printSymbolOtherField(Symbol); +}