--- /dev/null
+## Show that llvm-readelf + llvm-readobj demangle symbol names in symbol tables
+## (including dynamic symbols), relocations (including dynamic relocations), and groups.
+
+# RUN: yaml2obj %s > %t.so
+
+## Check LLVM output style.
+# RUN: llvm-readobj --symbols --relocations --dyn-symbols --dyn-relocations \
+# RUN: --elf-section-groups --elf-cg-profile --addrsig \
+# RUN: --demangle %t.so > %t.llvm.long
+# RUN: llvm-readobj --symbols --relocations --dyn-symbols --dyn-relocations \
+# RUN: --elf-section-groups --elf-cg-profile --addrsig \
+# RUN: -C %t.so > %t.llvm.short
+# RUN: FileCheck %s --input-file %t.llvm.long --check-prefixes=LLVM-COMMON,LLVM-DEMANGLE
+# RUN: diff %t.llvm.long %t.llvm.short
+
+## Check that default is no demangling.
+# RUN: llvm-readobj --symbols --relocations --dyn-symbols --dyn-relocations \
+# RUN: --elf-section-groups --elf-cg-profile --addrsig \
+# RUN: %t.so > %t.llvm.default
+# RUN: llvm-readobj --symbols --relocations --dyn-symbols --dyn-relocations \
+# RUN: --elf-section-groups --elf-cg-profile --addrsig \
+# RUN: --demangle=false %t.so > %t.llvm.nodemangle
+# RUN: FileCheck %s --input-file %t.llvm.default --check-prefixes=LLVM-COMMON,LLVM-MANGLED
+# RUN: diff %t.llvm.default %t.llvm.nodemangle
+
+# LLVM-COMMON: Relocations [
+# LLVM-COMMON: Section {{.*}} .rela.text.foo {
+# LLVM-DEMANGLE-NEXT: {{ }}foo(char){{ }}
+# LLVM-MANGLED-NEXT: {{ }}_Z3fooc{{ }}
+# LLVM-COMMON-NEXT: }
+# LLVM-COMMON: ]
+
+# LLVM-COMMON: Dynamic Relocations {
+# LLVM-DEMANGLE-NEXT: {{ }}foo(int){{ }}
+# LLVM-MANGLED-NEXT: {{ }}_Z3fooi{{ }}
+# LLVM-COMMON-NEXT: }
+
+# LLVM-COMMON: Symbols [
+# LLVM-DEMANGLE: Name: foo(char){{ }}
+# LLVM-DEMANGLE: Name: blah(float){{ }}
+# LLVM-MANGLED: Name: _Z3fooc{{ }}
+# LLVM-MANGLED: Name: _Z4blahf{{ }}
+# LLVM-COMMON: ]
+
+# LLVM-COMMON: DynamicSymbols [
+# LLVM-DEMANGLE: Name: foo(int){{ }}
+# LLVM-MANGLED: Name: _Z3fooi{{ }}
+# LLVM-COMMON: ]
+
+# LLVM-COMMON: Groups {
+# LLVM-DEMANGLE: Signature: foo(char){{$}}
+# LLVM-MANGLED: Signature: _Z3fooc{{$}}
+# LLVM-COMMON: }
+
+# LLVM-COMMON: CGProfile [
+# LLVM-DEMANGLE: From: foo(char){{ }}
+# LLVM-DEMANGLE: To: blah(float){{ }}
+# LLVM-MANGLED: From: _Z3fooc{{ }}
+# LLVM-MANGLED: To: _Z4blahf{{ }}
+# LLVM-COMMON: ]
+
+# LLVM-COMMON: Addrsig [
+# LLVM-DEMANGLE-NEXT: Sym: foo(char){{ }}
+# LLVM-DEMANGLE-NEXT: Sym: blah(float){{ }}
+# LLVM-MANGLED-NEXT: Sym: _Z3fooc{{ }}
+# LLVM-MANGLED-NEXT: Sym: _Z4blahf{{ }}
+# LLVM-COMMON-NEXT: ]
+
+## Check GNU output style.
+## FIXME: The extra run for --symbols is because GNU mode only prints the dynamic symbols,
+## if --dyn-symbols is specified, even if --symbols is specified.
+# RUN: llvm-readelf --relocations --dyn-symbols --dyn-relocations \
+# RUN: --elf-section-groups --demangle %t.so > %t.gnu.long
+# RUN: llvm-readelf --symbols --demangle %t.so >> %t.gnu.long
+# RUN: llvm-readelf --relocations --dyn-symbols --dyn-relocations \
+# RUN: --elf-section-groups -C %t.so > %t.gnu.short
+# RUN: llvm-readelf --symbols -C %t.so >> %t.gnu.short
+# RUN: FileCheck %s --input-file %t.gnu.long --check-prefixes=GNU-COMMON,GNU-DEMANGLE
+# RUN: diff %t.gnu.long %t.gnu.short
+
+## Check that default is no demangling.
+# RUN: llvm-readelf --relocations --dyn-symbols --dyn-relocations \
+# RUN: --elf-section-groups %t.so > %t.gnu.default
+# RUN: llvm-readelf --symbols %t.so >> %t.gnu.default
+# RUN: llvm-readelf --relocations --dyn-symbols --dyn-relocations \
+# RUN: --elf-section-groups --demangle=false %t.so > %t.gnu.nodemangle
+# RUN: llvm-readelf --symbols --demangle=false %t.so >> %t.gnu.nodemangle
+# RUN: FileCheck %s --input-file %t.gnu.default --check-prefixes=GNU-COMMON,GNU-MANGLED
+# RUN: diff %t.gnu.default %t.gnu.nodemangle
+
+# GNU-COMMON: Relocation section '.rela.text.foo' at offset {{.*}} contains 1 entries:
+# GNU-COMMON-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend
+# GNU-DEMANGLE-NEXT: foo(char){{ }}
+# GNU-MANGLED-NEXT: _Z3fooc{{ }}
+
+# GNU-COMMON: 'RELA' relocation section at offset {{.*}} contains 24 bytes:
+# GNU-COMMON-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend
+# GNU-DEMANGLE-NEXT: foo(int){{ }}
+# GNU-MANGLED-NEXT: _Z3fooi{{ }}
+
+# GNU-COMMON: Symbol table '.dynsym' contains 2 entries:
+# GNU-COMMON-NEXT: Num: Value Size Type Bind Vis Ndx Name
+# GNU-COMMON-NEXT: 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
+# GNU-DEMANGLE-NEXT: foo(int){{$}}
+# GNU-MANGLED-NEXT: _Z3fooi{{$}}
+
+# GNU-COMMON: COMDAT group section [{{.*}}] `.group'
+# GNU-DEMANGLE-SAME: [foo(char)]
+# GNU-MANGLED-SAME: [_Z3fooc]
+
+# GNU-COMMON: Symbol table '.symtab' contains 3 entries:
+# GNU-COMMON-NEXT: Num: Value Size Type Bind Vis Ndx Name
+# GNU-COMMON-NEXT: 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
+# GNU-DEMANGLE-NEXT: foo(char){{$}}
+# GNU-DEMANGLE-NEXT: blah(float){{$}}
+# GNU-MANGLED-NEXT: _Z3fooc{{$}}
+# GNU-MANGLED-NEXT: _Z4blahf{{$}}
+
+!ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_DYN
+ Machine: EM_X86_64
+Sections:
+ ## TODO: Replace the raw section contents with more meaningful dynamic
+ ## tags/symbols/etc, once yaml2obj supports it.
+ ## FIXME: yaml2obj does not currently allow custom addresses for .dynstr and
+ ## .dynsym if DynamicSymbols are specified.
+ ## See https://bugs.llvm.org/show_bug.cgi?id=40339
+ - Name: .dynstr
+ Type: SHT_STRTAB
+ Flags: [ SHF_ALLOC ]
+ AddressAlign: 0x100
+ EntSize: 0x1
+ ## "\0_Z3fooi\0"
+ Content: "005f5a33666f6f6900"
+ - Name: .dynsym
+ Type: SHT_DYNSYM
+ Flags: [ SHF_ALLOC ]
+ Link: .dynstr
+ Info: 1
+ Address: 0x100
+ AddressAlign: 0x100
+ EntSize: 0x18
+ ## Null symbol;
+ ## st_name: 1; st_info: Global | Func; st_other: 0;
+ ## st_shndx: .text.foo; st_value: 0x2000; st_size: 0
+ Content: "000000000000000000000000000000000000000000000000010000001200050000200000000000000000000000000000"
+ - Name: .rela.dyn
+ Type: SHT_RELA
+ Flags: [ SHF_ALLOC ]
+ Link: .dynsym
+ Info: .text.foo
+ Address: 0x200
+ AddressAlign: 0x100
+ EntSize: 0x18
+ Relocations:
+ - Offset: 0x10
+ ## FIXME: This should be a lookup in the corresponding symbol table, not necessarily the static symbol table.
+ ## See https://bugs.llvm.org/show_bug.cgi?id=40337.
+ Symbol: _Z3fooc
+ Type: R_X86_64_PC32
+ Addend: 0x4
+ - Name: .dynamic
+ Type: SHT_DYNAMIC
+ Flags: [ SHF_ALLOC ]
+ Link: .dynstr
+ Address: 0x1000
+ AddressAlign: 0x1000
+ ## DT_STRTAB - 0x0
+ ## DT_STRSZ - 0x9
+ ## DT_SYMTAB - 0x100
+ ## DT_SYMENT - 0x18
+ ## DT_RELA - 0x200
+ ## DT_RELASZ - 0x18
+ ## DT_RELAENT - 0x18
+ ## DT_NULL - 0x0
+ Content: "050000000000000000000000000000000a000000000000000900000000000000060000000000000000010000000000000b00000000000000180000000000000007000000000000000002000000000000080000000000000018000000000000000900000000000000180000000000000000000000000000000000000000000000"
+ - Name: .text.foo
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR, SHF_GROUP ]
+ Size: 0x40
+ Address: 0x2000
+ AddressAlign: 0x2000
+ - Name: .group
+ Type: SHT_GROUP
+ Link: .symtab
+ Info: _Z3fooc
+ Members:
+ - SectionOrType: GRP_COMDAT
+ - SectionOrType: .text.foo
+ - Name: .rela.text.foo
+ Type: SHT_RELA
+ Link: .symtab
+ Info: .text.foo
+ Relocations:
+ - Offset: 0x10
+ Symbol: _Z3fooc
+ Type: R_X86_64_PC32
+ - Name: .llvm.call-graph-profile
+ Type: SHT_LLVM_CALL_GRAPH_PROFILE
+ Link: .symtab
+ EntSize: 16
+ Content: "01000000020000002000000000000000"
+ - Name: .llvm_addrsig
+ Type: SHT_LLVM_ADDRSIG
+ Link: .symtab
+ Content: "0102"
+Symbols:
+ Global:
+ - Name: _Z3fooc
+ Type: STT_FUNC
+ Section: .text.foo
+ - Name: _Z4blahf
+ Type: STT_FUNC
+ Section: .text.foo
+ProgramHeaders:
+ - Type: PT_LOAD
+ Flags: [ PF_R, PF_X ]
+ VAddr: 0x0
+ PAddr: 0x0
+ Sections:
+ - Section: .dynsym
+ - Section: .dynstr
+ - Section: .rela.dyn
+ - Section: .dynamic
+ - Section: .text.foo
+ - Type: PT_DYNAMIC
+ Flags: [ PF_R ]
+ VAddr: 0x1000
+ PAddr: 0x1000
+ Sections:
+ - Section: .dynamic
#include "llvm/ADT/Twine.h"
#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"
void getSectionNameIndex(const Elf_Sym *Symbol, const Elf_Sym *FirstSym,
StringRef &SectionName,
unsigned &SectionIndex) const;
- StringRef getStaticSymbolName(uint32_t Index) const;
+ std::string getStaticSymbolName(uint32_t Index) const;
void printSymbolsHelper(bool IsDynamic) const;
const Elf_Shdr *getDotSymtabSec() const { return DotSymtabSec; }
return StringRef(StrTab.data() + name_offset);
}
+static std::string maybeDemangle(StringRef Name) {
+ return opts::Demangle ? demangle(Name) : Name.str();
+}
+
template <typename ELFT>
-StringRef ELFDumper<ELFT>::getStaticSymbolName(uint32_t Index) const {
+std::string ELFDumper<ELFT>::getStaticSymbolName(uint32_t Index) const {
const ELFFile<ELFT> *Obj = ObjF->getELFFile();
StringRef StrTable = unwrapOrError(Obj->getStringTableForSymtab(*DotSymtabSec));
Elf_Sym_Range Syms = unwrapOrError(Obj->symbols(DotSymtabSec));
if (Index >= Syms.size())
reportError("Invalid symbol index");
const Elf_Sym *Sym = &Syms[Index];
- return unwrapOrError(Sym->getName(StrTable));
+ return maybeDemangle(unwrapOrError(Sym->getName(StrTable)));
}
template <typename ELFT>
std::string ELFDumper<ELFT>::getFullSymbolName(const Elf_Sym *Symbol,
StringRef StrTable,
bool IsDynamic) const {
- StringRef SymbolName = unwrapOrError(Symbol->getName(StrTable));
+ std::string SymbolName =
+ maybeDemangle(unwrapOrError(Symbol->getName(StrTable)));
if (!IsDynamic)
return SymbolName;
- std::string FullSymbolName(SymbolName);
-
bool IsDefault;
StringRef Version = getSymbolVersion(StrTable, &*Symbol, IsDefault);
if (!Version.empty()) {
- FullSymbolName += (IsDefault ? "@@" : "@");
- FullSymbolName += Version;
+ SymbolName += (IsDefault ? "@@" : "@");
+ SymbolName += Version;
}
- return FullSymbolName;
+ return SymbolName;
}
template <typename ELFT>
struct GroupSection {
StringRef Name;
- StringRef Signature;
+ std::string Signature;
uint64_t ShName;
uint64_t Index;
uint32_t Link;
StringRef Name = unwrapOrError(Obj->getSectionName(&Sec));
StringRef Signature = StrTable.data() + Sym->st_name;
- Ret.push_back({Name,
- Signature,
- Sec.sh_name,
+ Ret.push_back({Name,
+ maybeDemangle(Signature),
+ Sec.sh_name,
I - 1,
Sec.sh_link,
Sec.sh_info,
- Data[0],
+ Data[0],
{}});
std::vector<GroupMember> &GM = Ret.back().Members;
const Elf_Rela &R, bool IsRela) {
std::string Offset, Info, Addend, Value;
SmallString<32> RelocName;
- StringRef TargetName;
+ std::string TargetName;
const Elf_Sym *Sym = nullptr;
unsigned Width = ELFT::Is64Bits ? 16 : 8;
unsigned Bias = ELFT::Is64Bits ? 8 : 0;
TargetName = unwrapOrError(Obj->getSectionName(Sec));
} else if (Sym) {
StringRef StrTable = unwrapOrError(Obj->getStringTableForSymtab(*SymTab));
- TargetName = unwrapOrError(Sym->getName(StrTable));
+ TargetName = maybeDemangle(unwrapOrError(Sym->getName(StrTable)));
}
if (Sym && IsRela) {
void GNUStyle<ELFT>::printDynamicRelocation(const ELFO *Obj, Elf_Rela R,
bool IsRela) {
SmallString<32> RelocName;
- StringRef SymbolName;
+ std::string SymbolName;
unsigned Width = ELFT::Is64Bits ? 16 : 8;
unsigned Bias = ELFT::Is64Bits ? 8 : 0;
// First two fields are bit width dependent. The rest of them are after are
uint32_t SymIndex = R.getSymbol(Obj->isMips64EL());
const Elf_Sym *Sym = this->dumper()->dynamic_symbols().begin() + SymIndex;
Obj->getRelocationTypeName(R.getType(Obj->isMips64EL()), RelocName);
- SymbolName =
- unwrapOrError(Sym->getName(this->dumper()->getDynamicStringTable()));
+ SymbolName = maybeDemangle(
+ unwrapOrError(Sym->getName(this->dumper()->getDynamicStringTable())));
std::string Addend, Info, Offset, Value;
Offset = to_string(format_hex_no_prefix(R.r_offset, Width));
Info = to_string(format_hex_no_prefix(R.r_info, Width));
const Elf_Shdr *SymTab) {
SmallString<32> RelocName;
Obj->getRelocationTypeName(Rel.getType(Obj->isMips64EL()), RelocName);
- StringRef TargetName;
+ std::string TargetName;
const Elf_Sym *Sym = unwrapOrError(Obj->getRelocationSymbol(&Rel, SymTab));
if (Sym && Sym->getType() == ELF::STT_SECTION) {
const Elf_Shdr *Sec = unwrapOrError(
TargetName = unwrapOrError(Obj->getSectionName(Sec));
} else if (Sym) {
StringRef StrTable = unwrapOrError(Obj->getStringTableForSymtab(*SymTab));
- TargetName = unwrapOrError(Sym->getName(StrTable));
+ TargetName = maybeDemangle(unwrapOrError(Sym->getName(StrTable)));
}
if (opts::ExpandRelocs) {
void LLVMStyle<ELFT>::printDynamicRelocation(const ELFO *Obj, Elf_Rela Rel) {
SmallString<32> RelocName;
Obj->getRelocationTypeName(Rel.getType(Obj->isMips64EL()), RelocName);
- StringRef SymbolName;
+ std::string SymbolName;
uint32_t SymIndex = Rel.getSymbol(Obj->isMips64EL());
const Elf_Sym *Sym = this->dumper()->dynamic_symbols().begin() + SymIndex;
- SymbolName =
- unwrapOrError(Sym->getName(this->dumper()->getDynamicStringTable()));
+ SymbolName = maybeDemangle(
+ unwrapOrError(Sym->getName(this->dumper()->getDynamicStringTable())));
if (opts::ExpandRelocs) {
DictScope Group(W, "Relocation");
W.printHex("Offset", Rel.r_offset);