diff --git a/llvm/docs/CommandGuide/llvm-objdump.rst b/llvm/docs/CommandGuide/llvm-objdump.rst --- a/llvm/docs/CommandGuide/llvm-objdump.rst +++ b/llvm/docs/CommandGuide/llvm-objdump.rst @@ -321,6 +321,13 @@ Display weak binding information. +XCOFF ONLY OPTIONS AND COMMANDS +--------------------------------- + +.. option:: --symbol-description + + Add symbol description to disassembly output. + BUGS ---- diff --git a/llvm/include/llvm/MC/MCDisassembler/MCDisassembler.h b/llvm/include/llvm/MC/MCDisassembler/MCDisassembler.h --- a/llvm/include/llvm/MC/MCDisassembler/MCDisassembler.h +++ b/llvm/include/llvm/MC/MCDisassembler/MCDisassembler.h @@ -9,7 +9,9 @@ #ifndef LLVM_MC_MCDISASSEMBLER_MCDISASSEMBLER_H #define LLVM_MC_MCDISASSEMBLER_MCDISASSEMBLER_H +#include "llvm/ADT/Optional.h" #include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/XCOFF.h" #include "llvm/MC/MCDisassembler/MCSymbolizer.h" #include #include @@ -17,23 +19,46 @@ namespace llvm { +struct XCOFFSymbolInfo { + Optional StorageMappingClass; + Optional Index; + bool IsLabel; + XCOFFSymbolInfo(Optional Smc, + Optional Idx, bool Label) + : StorageMappingClass(Smc), Index(Idx), IsLabel(Label){}; +}; + struct SymbolInfoTy { - uint64_t Addr; - StringRef Name; - uint8_t Type; + uint64_t Addr; + StringRef Name; + union { + uint8_t Type; + XCOFFSymbolInfo XCOFFSymInfo; + }; + +private: + bool IsXCOFF; - SymbolInfoTy(uint64_t Addr, StringRef Name, uint8_t Type) - : Addr(Addr), Name(Name), Type(Type){}; +public: + SymbolInfoTy(uint64_t Addr, StringRef Name, + Optional Smc, Optional Idx, + bool Label) + : Addr(Addr), Name(Name), XCOFFSymInfo(Smc, Idx, Label), IsXCOFF(true){}; + SymbolInfoTy(uint64_t Addr, StringRef Name, uint8_t Type) + : Addr(Addr), Name(Name), Type(Type), IsXCOFF(false){}; - friend bool operator<(const SymbolInfoTy &P1, const SymbolInfoTy &P2) { - return std::tie(P1.Addr, P1.Name, P1.Type) < - std::tie(P2.Addr, P2.Name, P2.Type); - } +private: + friend bool operator<(const SymbolInfoTy &P1, const SymbolInfoTy &P2) { + if (P1.IsXCOFF) + return std::tie(P1.Addr, P1.Name) < std::tie(P2.Addr, P2.Name); + else + return std::tie(P1.Addr, P1.Name, P1.Type) < + std::tie(P2.Addr, P2.Name, P2.Type); + } }; using SectionSymbolsTy = std::vector; - template class ArrayRef; class MCContext; class MCInst; diff --git a/llvm/include/llvm/Object/XCOFFObjectFile.h b/llvm/include/llvm/Object/XCOFFObjectFile.h --- a/llvm/include/llvm/Object/XCOFFObjectFile.h +++ b/llvm/include/llvm/Object/XCOFFObjectFile.h @@ -128,6 +128,12 @@ }; struct XCOFFCsectAuxEnt32 { + enum { + SymbolTypeMask = 0x07, + SymbolAlignmentMask = 0xF8, + SymbolAlignmentBitOffset = 3 + }; + support::ubig32_t SectionOrLength; // If the symbol type is XTY_SD or XTY_CM, the csect // length. @@ -140,6 +146,17 @@ XCOFF::StorageMappingClass StorageMappingClass; support::ubig32_t StabInfoIndex; support::ubig16_t StabSectNum; + + uint16_t getAlignmentLog2() const { + return (SymbolAlignmentAndType & SymbolAlignmentMask) >> + SymbolAlignmentBitOffset; + }; + + uint8_t getSymbolType() const { + return SymbolAlignmentAndType & SymbolTypeMask; + }; + + bool isLabel() const { return getSymbolType() == XCOFF::XTY_LD; } }; struct XCOFFFileAuxEnt { diff --git a/llvm/lib/BinaryFormat/XCOFF.cpp b/llvm/lib/BinaryFormat/XCOFF.cpp --- a/llvm/lib/BinaryFormat/XCOFF.cpp +++ b/llvm/lib/BinaryFormat/XCOFF.cpp @@ -10,25 +10,35 @@ using namespace llvm; +#define SMC_CASE(A) \ + case XCOFF::XMC_##A: \ + return #A; StringRef XCOFF::getMappingClassString(XCOFF::StorageMappingClass SMC) { switch (SMC) { - case XCOFF::XMC_DS: - return "DS"; - case XCOFF::XMC_RW: - return "RW"; - case XCOFF::XMC_PR: - return "PR"; - case XCOFF::XMC_TC0: - return "TC0"; - case XCOFF::XMC_BS: - return "BS"; - case XCOFF::XMC_RO: - return "RO"; - case XCOFF::XMC_UA: - return "UA"; - case XCOFF::XMC_TC: - return "TC"; - default: - report_fatal_error("Unhandled storage-mapping class."); + SMC_CASE(PR) + SMC_CASE(RO) + SMC_CASE(DB) + SMC_CASE(GL) + SMC_CASE(XO) + SMC_CASE(SV) + SMC_CASE(SV64) + SMC_CASE(SV3264) + SMC_CASE(TI) + SMC_CASE(TB) + SMC_CASE(RW) + SMC_CASE(TC0) + SMC_CASE(TC) + SMC_CASE(TD) + SMC_CASE(DS) + SMC_CASE(UA) + SMC_CASE(BS) + SMC_CASE(UC) + SMC_CASE(TL) + SMC_CASE(UL) + SMC_CASE(TE) +#undef SMC_CASE } + + // TODO: need to add a test case for "Unknown" and other SMC. + return "Unknown"; } diff --git a/llvm/test/tools/llvm-objdump/xcoff-disassemble-all.test b/llvm/test/tools/llvm-objdump/xcoff-disassemble-all.test --- a/llvm/test/tools/llvm-objdump/xcoff-disassemble-all.test +++ b/llvm/test/tools/llvm-objdump/xcoff-disassemble-all.test @@ -1,8 +1,12 @@ # RUN: llvm-objdump -D %p/Inputs/xcoff-section-headers.o | \ -# RUN: FileCheck %s +# RUN: FileCheck --check-prefixes=COMMON,PLAIN %s + +# RUN: llvm-objdump -D --symbol-description %p/Inputs/xcoff-section-headers.o | \ +# RUN: FileCheck --check-prefixes=COMMON,DESC %s # xcoff-section-headers.o Compiled with IBM XL C/C++ for AIX, V16.1.0 # compiler command: xlc -qtls -o xcoff-section-headers.o -c test.c + # test.c: # int a; # int b = 12345; @@ -12,44 +16,58 @@ # int func(void) { # return a; # } + ; REQUIRES: powerpc-registered-target -CHECK: Inputs/xcoff-section-headers.o: file format aixcoff-rs6000 -CHECK: Disassembly of section .text: -CHECK: 00000000 .text: -CHECK-NEXT: 0: 80 62 00 04 lwz 3, 4(2) -CHECK-NEXT: 4: 80 63 00 00 lwz 3, 0(3) -CHECK-NEXT: 8: 4e 80 00 20 blr -CHECK-NEXT: c: 00 00 00 00 -CHECK-NEXT: 10: 00 00 20 40 -CHECK-NEXT: 14: 00 00 00 01 -CHECK-NEXT: 18: 00 00 00 0c -CHECK-NEXT: 1c: 00 04 66 75 -CHECK-NEXT: 20: 6e 63 00 00 xoris 3, 19, 0 -CHECK-NEXT: ... -CHECK: Disassembly of section .data: -CHECK: 00000080 func: -CHECK-NEXT: 80: 00 00 00 94 -CHECK: 00000084 a: -CHECK-NEXT: 84: 00 00 00 a4 -CHECK: 00000088 b: -CHECK-NEXT: 88: 00 00 00 a0 -CHECK: 0000008c c: -CHECK-NEXT: 8c: 00 00 00 08 -CHECK: 00000090 d: -CHECK-NEXT: 90: 00 00 00 00 -CHECK: 00000094 func: -CHECK-NEXT: 94: 00 00 00 00 -CHECK-NEXT: 98: 00 00 00 80 -CHECK-NEXT: 9c: 00 00 00 00 -CHECK: 000000a0 b: -CHECK-NEXT: a0: 00 00 30 39 -CHECK: Disassembly of section .bss: -CHECK: 000000a4 a: -CHECK-NEXT: ... -CHECK: Disassembly of section .tdata: -CHECK: 00000000 d: -CHECK-NEXT: 0: 40 09 21 f9 bdnzfl 9, .+8696 -CHECK-NEXT: 4: f0 1b 86 6e -CHECK: Disassembly of section .tbss: -CHECK: 00000008 c: -CHECK-NEXT: ... + +COMMON: Inputs/xcoff-section-headers.o: file format aixcoff-rs6000 +COMMON: Disassembly of section .text: +PLAIN: 00000000 .text: +DESC: 00000000 (idx: 4) .text: +COMMON-NEXT: 0: 80 62 00 04 lwz 3, 4(2) +COMMON-NEXT: 4: 80 63 00 00 lwz 3, 0(3) +COMMON-NEXT: 8: 4e 80 00 20 blr +COMMON-NEXT: c: 00 00 00 00 +COMMON-NEXT: 10: 00 00 20 40 +COMMON-NEXT: 14: 00 00 00 01 +COMMON-NEXT: 18: 00 00 00 0c +COMMON-NEXT: 1c: 00 04 66 75 +COMMON-NEXT: 20: 6e 63 00 00 xoris 3, 19, 0 +COMMON-NEXT: ... +COMMON: Disassembly of section .data: +PLAIN: 00000080 func: +DESC: 00000080 (idx: 22) func[TC]: +COMMON-NEXT: 80: 00 00 00 94 +PLAIN: 00000084 a: +DESC: 00000084 (idx: 26) a[TC]: +COMMON-NEXT: 84: 00 00 00 a4 +PLAIN: 00000088 b: +DESC: 00000088 (idx: 30) b[TC]: +COMMON-NEXT: 88: 00 00 00 a0 +PLAIN: 0000008c c: +DESC: 0000008c (idx: 34) c[TC]: +COMMON-NEXT: 8c: 00 00 00 08 +PLAIN: 00000090 d: +DESC: 00000090 (idx: 38) d[TC]: +COMMON-NEXT: 90: 00 00 00 00 +PLAIN: 00000094 func: +DESC: 00000094 (idx: 20) func[DS]: +COMMON-NEXT: 94: 00 00 00 00 +COMMON-NEXT: 98: 00 00 00 80 +COMMON-NEXT: 9c: 00 00 00 00 +PLAIN: 000000a0 b: +DESC: 000000a0 (idx: 28) b[RW]: +COMMON-NEXT: a0: 00 00 30 39 +COMMON: Disassembly of section .bss: +PLAIN: 000000a4 a: +DESC: 000000a4 (idx: 24) a[RW]: +COMMON-NEXT: ... +COMMON: Disassembly of section .tdata: +PLAIN: 00000000 d: +DESC: 00000000 (idx: 36) d[TL]: +COMMON-NEXT: 0: 40 09 21 f9 bdnzfl 9, .+8696 +COMMON-NEXT: 4: f0 1b 86 6e +COMMON: Disassembly of section .tbss: +PLAIN: 00000008 c: +DESC: 00000008 (idx: 32) c[UL]: +COMMON-NEXT: ... + diff --git a/llvm/tools/llvm-objdump/CMakeLists.txt b/llvm/tools/llvm-objdump/CMakeLists.txt --- a/llvm/tools/llvm-objdump/CMakeLists.txt +++ b/llvm/tools/llvm-objdump/CMakeLists.txt @@ -20,6 +20,7 @@ ELFDump.cpp MachODump.cpp WasmDump.cpp + XCOFFDump.cpp ) if(HAVE_LIBXAR) diff --git a/llvm/tools/llvm-objdump/XCOFFDump.cpp b/llvm/tools/llvm-objdump/XCOFFDump.cpp new file mode 100644 --- /dev/null +++ b/llvm/tools/llvm-objdump/XCOFFDump.cpp @@ -0,0 +1,66 @@ +//===-- XCOFFDump.cpp - Object file dumping utility for llvm --------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file implements XCOFF object dump information. +// +//===----------------------------------------------------------------------===// + +#include "llvm-xcoffdump.h" +#include "llvm/Object/XCOFFObjectFile.h" + +namespace llvm { + +using namespace llvm::object; + +Optional +getXCOFFSymbolCsectSMC(const XCOFFObjectFile *Obj, const SymbolRef &Sym) { + DataRefImpl SymbolDRI = Sym.getRawDataRefImpl(); + + XCOFFSymbolRef SymRef(SymbolDRI, Obj); + + if (SymRef.hasCsectAuxEnt()) { + assert(SymRef.getNumberOfAuxEntries() && + "No CSECT Auxiliary Entry is found."); + const XCOFFCsectAuxEnt32 *AuxEntPtr = SymRef.getXCOFFCsectAuxEnt32(); + return Optional(AuxEntPtr->StorageMappingClass); + } + return None; +} + +bool isLabel(const XCOFFObjectFile *Obj, const SymbolRef &Sym) { + + DataRefImpl SymbolDRI = Sym.getRawDataRefImpl(); + + XCOFFSymbolRef SymRef(SymbolDRI, Obj); + + if (SymRef.hasCsectAuxEnt()) { + assert(SymRef.getNumberOfAuxEntries() && + "No CSECT Auxiliary Entry is found."); + const XCOFFCsectAuxEnt32 *AuxEntPtr = SymRef.getXCOFFCsectAuxEnt32(); + return AuxEntPtr->isLabel(); + } + + return false; +} + +void printXCOFFSymbolDescription(const SymbolInfoTy &SymbolInfo, + StringRef SymbolName) { + if (SymbolInfo.XCOFFSymInfo.Index) + outs() << "(idx: " << SymbolInfo.XCOFFSymInfo.Index.getValue() << ") "; + + outs() << SymbolName; + + if (SymbolInfo.XCOFFSymInfo.StorageMappingClass && + !SymbolInfo.XCOFFSymInfo.IsLabel) { + const XCOFF::StorageMappingClass Smc = + SymbolInfo.XCOFFSymInfo.StorageMappingClass.getValue(); + outs() << "[" << XCOFF::getMappingClassString(Smc).str() << "]"; + } +} + +} // namespace llvm diff --git a/llvm/tools/llvm-objdump/llvm-objdump.h b/llvm/tools/llvm-objdump/llvm-objdump.h --- a/llvm/tools/llvm-objdump/llvm-objdump.h +++ b/llvm/tools/llvm-objdump/llvm-objdump.h @@ -9,10 +9,10 @@ #define LLVM_TOOLS_LLVM_OBJDUMP_LLVM_OBJDUMP_H #include "llvm/DebugInfo/DIContext.h" +#include "llvm/Object/Archive.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/DataTypes.h" -#include "llvm/Object/Archive.h" namespace llvm { class StringRef; diff --git a/llvm/tools/llvm-objdump/llvm-objdump.cpp b/llvm/tools/llvm-objdump/llvm-objdump.cpp --- a/llvm/tools/llvm-objdump/llvm-objdump.cpp +++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp @@ -16,6 +16,7 @@ //===----------------------------------------------------------------------===// #include "llvm-objdump.h" +#include "llvm-xcoffdump.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SetOperations.h" @@ -46,6 +47,7 @@ #include "llvm/Object/MachOUniversal.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Object/Wasm.h" +#include "llvm/Object/XCOFFObjectFile.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" @@ -143,6 +145,12 @@ cl::NotHidden, cl::Grouping, cl::aliasopt(DisassembleAll)); +cl::opt + SymbolDescription("symbol-description", + cl::desc("Add symbol description for disassembly. This " + "option is for XCOFF files only"), + cl::init(false), cl::cat(ObjdumpCat)); + static cl::list DisassembleFunctions("disassemble-functions", cl::CommaSeparated, cl::desc("List of functions to disassemble. " @@ -1138,6 +1146,40 @@ } } +SymbolInfoTy createSymbolInfo(const ObjectFile *Obj, const SymbolRef &Symbol) { + const StringRef FileName = Obj->getFileName(); + const uint64_t Addr = unwrapOrError(Symbol.getAddress(), FileName); + const StringRef Name = unwrapOrError(Symbol.getName(), FileName); + + uint8_t SymbolType = ELF::STT_NOTYPE; + + if (Obj->isELF()) { + SymbolType = getElfSymbolType(Obj, Symbol); + } + + if (Obj->isXCOFF() && SymbolDescription) { + const auto *XCOFFObj = dyn_cast(Obj); + DataRefImpl SymbolDRI = Symbol.getRawDataRefImpl(); + + const Optional SymbolIndex = + XCOFFObj->getSymbolIndex(SymbolDRI.p); + const bool IsLabel = isLabel(XCOFFObj, Symbol); + Optional Smc = getXCOFFSymbolCsectSMC( + static_cast(Obj), Symbol); + return SymbolInfoTy(Addr, Name, Smc, SymbolIndex, IsLabel); + } else + return SymbolInfoTy(Addr, Name, SymbolType); +} + +SymbolInfoTy createDummySymbolInfo(const ObjectFile *Obj, const uint64_t Addr, + StringRef &Name, uint8_t Type) { + if (Obj->isXCOFF() && SymbolDescription) + return SymbolInfoTy(Addr, Name, Optional(), + None, false); + else + return SymbolInfoTy(Addr, Name, Type); +} + static void disassembleObject(const Target *TheTarget, const ObjectFile *Obj, MCContext &Ctx, MCDisassembler *PrimaryDisAsm, MCDisassembler *SecondaryDisAsm, @@ -1164,8 +1206,6 @@ const StringRef FileName = Obj->getFileName(); const MachOObjectFile *MachO = dyn_cast(Obj); for (const SymbolRef &Symbol : Obj->symbols()) { - uint64_t Address = unwrapOrError(Symbol.getAddress(), FileName); - StringRef Name = unwrapOrError(Symbol.getName(), FileName); if (Name.empty()) continue; @@ -1177,7 +1217,7 @@ continue; } - // Don't ask a Mach-O STAB symbol for its section unless you know that + // Don't ask a Mach-O STAB symbol for its section unless you know that // STAB symbol's section field refers to a valid section index. Otherwise // the symbol may error trying to load a section that does not exist. if (MachO) { @@ -1191,10 +1231,11 @@ section_iterator SecI = unwrapOrError(Symbol.getSection(), FileName); if (SecI != Obj->section_end()) - AllSymbols[*SecI].emplace_back(Address, Name, SymbolType); + AllSymbols[*SecI].push_back(createSymbolInfo(Obj, Symbol)); else - AbsoluteSymbols.emplace_back(Address, Name, SymbolType); + AbsoluteSymbols.push_back(createSymbolInfo(Obj, Symbol)); } + if (AllSymbols.empty() && Obj->isELF()) addDynamicElfSymbols(Obj, AllSymbols); @@ -1293,10 +1334,10 @@ StringRef SectionName = unwrapOrError(Section.getName(), Obj->getFileName()); // If the section has no symbol at the start, just insert a dummy one. if (Symbols.empty() || Symbols[0].Addr != 0) { - Symbols.insert( - Symbols.begin(), - SymbolInfoTy(SectionAddr, SectionName, - Section.isText() ? ELF::STT_FUNC : ELF::STT_OBJECT)); + Symbols.insert(Symbols.begin(), + createDummySymbolInfo(Obj, SectionAddr, SectionName, + Section.isText() ? ELF::STT_FUNC + : ELF::STT_OBJECT)); } SmallString<40> Comments; @@ -1371,8 +1412,11 @@ if (!NoLeadingAddr) outs() << format(Is64Bits ? "%016" PRIx64 " " : "%08" PRIx64 " ", SectionAddr + Start + VMAAdjustment); - - outs() << SymbolName << ":\n"; + if (Obj->isXCOFF() && SymbolDescription) { + printXCOFFSymbolDescription(Symbols[SI], SymbolName); + outs() << ":\n"; + } else + outs() << SymbolName << ":\n"; // Don't print raw contents of a virtual section. A virtual section // doesn't have any contents in the file. diff --git a/llvm/tools/llvm-objdump/llvm-xcoffdump.h b/llvm/tools/llvm-objdump/llvm-xcoffdump.h new file mode 100644 --- /dev/null +++ b/llvm/tools/llvm-objdump/llvm-xcoffdump.h @@ -0,0 +1,32 @@ +//===-- llvm-xcoffdump.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_OBJDUMP_LLVM_XCOFFDUMP_H +#define LLVM_TOOLS_LLVM_OBJDUMP_LLVM_XCOFFDUMP_H + +#include "llvm/MC/MCDisassembler/MCDisassembler.h" + +namespace llvm { +class StringRef; + +namespace object { +class XCOFFObjectFile; +class SymbolRef; +} // namespace object + +Optional +getXCOFFSymbolCsectSMC(const object::XCOFFObjectFile *Obj, + const object::SymbolRef &Sym); + +bool isLabel(const object::XCOFFObjectFile *Obj, const object::SymbolRef &Sym); + +void printXCOFFSymbolDescription(const SymbolInfoTy &SymbolInfo, + StringRef SymbolName); + +} // namespace llvm +#endif