diff --git a/llvm/include/llvm/Object/ELFObjectFile.h b/llvm/include/llvm/Object/ELFObjectFile.h index aab7340a9e89..a5d3c15809de 100644 --- a/llvm/include/llvm/Object/ELFObjectFile.h +++ b/llvm/include/llvm/Object/ELFObjectFile.h @@ -41,6 +41,9 @@ namespace llvm { namespace object { +constexpr int NumElfSymbolTypes = 8; +extern const llvm::EnumEntry ElfSymbolTypes[NumElfSymbolTypes]; + class elf_symbol_iterator; class ELFObjectFileBase : public ObjectFile { @@ -148,6 +151,16 @@ public: uint8_t getELFType() const { return getObject()->getSymbolELFType(getRawDataRefImpl()); } + + StringRef getELFTypeName() const { + uint8_t Type = getELFType(); + for (auto &EE : ElfSymbolTypes) { + if (EE.Value == Type) { + return EE.AltName; + } + } + return ""; + } }; class elf_symbol_iterator : public symbol_iterator { diff --git a/llvm/lib/Object/ELFObjectFile.cpp b/llvm/lib/Object/ELFObjectFile.cpp index 15e09f8116b0..07851411fe6b 100644 --- a/llvm/lib/Object/ELFObjectFile.cpp +++ b/llvm/lib/Object/ELFObjectFile.cpp @@ -35,6 +35,16 @@ using namespace llvm; using namespace object; +const EnumEntry llvm::object::ElfSymbolTypes[NumElfSymbolTypes] = { + {"None", "NOTYPE", ELF::STT_NOTYPE}, + {"Object", "OBJECT", ELF::STT_OBJECT}, + {"Function", "FUNC", ELF::STT_FUNC}, + {"Section", "SECTION", ELF::STT_SECTION}, + {"File", "FILE", ELF::STT_FILE}, + {"Common", "COMMON", ELF::STT_COMMON}, + {"TLS", "TLS", ELF::STT_TLS}, + {"GNU_IFunc", "IFUNC", ELF::STT_GNU_IFUNC}}; + ELFObjectFileBase::ELFObjectFileBase(unsigned int Type, MemoryBufferRef Source) : ObjectFile(Type, Source) {} diff --git a/llvm/test/Object/X86/nm-print-size.s b/llvm/test/Object/X86/nm-print-size.s index a755ffa3ded6..da67f1fcba23 100644 --- a/llvm/test/Object/X86/nm-print-size.s +++ b/llvm/test/Object/X86/nm-print-size.s @@ -1,11 +1,17 @@ // RUN: llvm-mc %s -o %t -filetype=obj -triple=x86_64-pc-linux // RUN: llvm-nm --print-size %t | FileCheck %s +// RUN: llvm-nm -f sysv %t | FileCheck -check-prefix=SYSV %s // CHECK: 0000000000000000 ffffffffffffffff n a // CHECK: 0000000000000000 0000000000000000 N b // CHECK: 0000000000000004 0000000000000004 C c // CHECK: ffffffffffffffff 0000000000000000 a d +// SYSV: a |0000000000000000| n | NOTYPE|ffffffffffffffff| |foo +// SYSV: b |0000000000000000| N | NOTYPE|0000000000000000| |foo +// SYSV: c |0000000000000004| C | OBJECT|0000000000000004| |*COM* +// SYSV: d |ffffffffffffffff| a | NOTYPE|0000000000000000| |*ABS* + .section foo a: .size a, 0xffffffffffffffff diff --git a/llvm/test/tools/llvm-nm/X86/sysv-i386.test b/llvm/test/tools/llvm-nm/X86/sysv-i386.test index b9b1f6024b1f..ea0dcab5bb3a 100644 --- a/llvm/test/tools/llvm-nm/X86/sysv-i386.test +++ b/llvm/test/tools/llvm-nm/X86/sysv-i386.test @@ -1,6 +1,7 @@ +RUN: llvm-nm -f sysv %p/Inputs/hello.obj.elf-i386 RUN: llvm-nm -f sysv %p/Inputs/hello.obj.elf-i386 | FileCheck %s --strict-whitespace CHECK: Name Value Class Type Size Line Section -CHECK: .L.str |00000000| r | |0000000f| | -CHECK: main |00000000| T | |00000015| | -CHECK: puts | | U | | | | +CHECK: .L.str |00000000| r | OBJECT|0000000f| |.rodata.str1.1 +CHECK: main |00000000| T | FUNC|00000015| |.text +CHECK: puts | | U | NOTYPE| | |*UND* diff --git a/llvm/test/tools/llvm-nm/X86/sysv-x86_64.test b/llvm/test/tools/llvm-nm/X86/sysv-x86_64.test index bf041b202f77..c517af97ad88 100644 --- a/llvm/test/tools/llvm-nm/X86/sysv-x86_64.test +++ b/llvm/test/tools/llvm-nm/X86/sysv-x86_64.test @@ -2,8 +2,8 @@ RUN: llvm-nm -f sysv %p/Inputs/hello.obj.elf-x86_64 | FileCheck %s --check-prefi RUN: llvm-nm -f sysv %p/Inputs/hello.obj.macho-x86_64 2>&1 | FileCheck %s --check-prefix=MACHO --strict-whitespace ELF: Name Value Class Type Size Line Section -ELF: main |0000000000000000| T | |0000000000000015| | -ELF: puts | | U | | | | +ELF: main |0000000000000000| T | FUNC|0000000000000015| |.text +ELF: puts | | U | NOTYPE| | |*UND* MACHO: Name Value Class Type Size Line Section MACHO: EH_frame0 |0000000000000068| s | |0000000000000000| | diff --git a/llvm/tools/llvm-nm/llvm-nm.cpp b/llvm/tools/llvm-nm/llvm-nm.cpp index a7346d56f329..53f07d191c8b 100644 --- a/llvm/tools/llvm-nm/llvm-nm.cpp +++ b/llvm/tools/llvm-nm/llvm-nm.cpp @@ -262,6 +262,8 @@ struct NMSymbol { uint64_t Size; char TypeChar; StringRef Name; + StringRef SectionName; + StringRef TypeName; BasicSymbolRef Sym; // The Sym field above points to the native symbol in the object file, // for Mach-O when we are creating symbols from the dyld info the above @@ -882,8 +884,12 @@ static void sortAndPrintSymbolList(SymbolicFile &Obj, bool printName, std::string PaddedName(Name); while (PaddedName.length() < 20) PaddedName += " "; + std::string TypeName = I->TypeName; + if (TypeName.size() < 18) + TypeName = std::string(18-TypeName.size(), ' ') + TypeName; outs() << PaddedName << "|" << SymbolAddrStr << "| " << I->TypeChar - << " | |" << SymbolSizeStr << "| |\n"; + << " |" << TypeName << "|" << SymbolSizeStr << "| |" + << I->SectionName << "\n"; } } @@ -1078,8 +1084,40 @@ static bool isObject(SymbolicFile &Obj, basic_symbol_iterator I) { : elf_symbol_iterator(I)->getELFType() == ELF::STT_OBJECT; } -static char getNMTypeChar(SymbolicFile &Obj, basic_symbol_iterator I) { +// For ELF object files, Set TypeName to the symbol typename, to be printed +// in the 'Type' column of the SYSV format output. +static StringRef getNMTypeName(SymbolicFile &Obj, basic_symbol_iterator I) { + if (isa(&Obj)) { + elf_symbol_iterator SymI(I); + return SymI->getELFTypeName(); + } + return ""; +} + +// Return Posix nm class type tag (single letter), but also set SecName and +// section and name, to be used in format=sysv output. +static char getNMSectionTagAndName(SymbolicFile &Obj, basic_symbol_iterator I, + StringRef &SecName) { uint32_t Symflags = I->getFlags(); + if (isa(&Obj)) { + if (Symflags & object::SymbolRef::SF_Absolute) + SecName = "*ABS*"; + else if (Symflags & object::SymbolRef::SF_Common) + SecName = "*COM*"; + else if (Symflags & object::SymbolRef::SF_Undefined) + SecName = "*UND*"; + else { + elf_symbol_iterator SymI(I); + Expected SecIOrErr = SymI->getSection(); + if (!SecIOrErr) { + consumeError(SecIOrErr.takeError()); + return '?'; + } + elf_section_iterator secT = *SecIOrErr; + secT->getName(SecName); + } + } + if ((Symflags & object::SymbolRef::SF_Weak) && !isa(Obj)) { char Ret = isObject(Obj, I) ? 'v' : 'w'; return (!(Symflags & object::SymbolRef::SF_Undefined)) ? toupper(Ret) : Ret; @@ -1201,7 +1239,8 @@ dumpSymbolNamesFromObject(SymbolicFile &Obj, bool printName, } S.Address = *AddressOrErr; } - S.TypeChar = getNMTypeChar(Obj, Sym); + S.TypeName = getNMTypeName(Obj, Sym); + S.TypeChar = getNMSectionTagAndName(Obj, Sym, S.SectionName); std::error_code EC = Sym.printName(OS); if (EC && MachO) OS << "bad string index"; diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp index 793bbf06ed08..8566f09772bf 100644 --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -1114,16 +1114,6 @@ static const EnumEntry ElfSymbolVisibilities[] = { {"HIDDEN", "HIDDEN", ELF::STV_HIDDEN}, {"PROTECTED", "PROTECTED", ELF::STV_PROTECTED}}; -static const EnumEntry ElfSymbolTypes[] = { - {"None", "NOTYPE", ELF::STT_NOTYPE}, - {"Object", "OBJECT", ELF::STT_OBJECT}, - {"Function", "FUNC", ELF::STT_FUNC}, - {"Section", "SECTION", ELF::STT_SECTION}, - {"File", "FILE", ELF::STT_FILE}, - {"Common", "COMMON", ELF::STT_COMMON}, - {"TLS", "TLS", ELF::STT_TLS}, - {"GNU_IFunc", "IFUNC", ELF::STT_GNU_IFUNC}}; - static const EnumEntry AMDGPUSymbolTypes[] = { { "AMDGPU_HSA_KERNEL", ELF::STT_AMDGPU_HSA_KERNEL } };