diff --git a/llvm/test/tools/llvm-objdump/ELF/elf-dynamic-symbol.test b/llvm/test/tools/llvm-objdump/ELF/elf-dynamic-symbol.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/ELF/elf-dynamic-symbol.test @@ -0,0 +1,67 @@ +## Test that llvm-objdump can dump dynamic symbols. + +# RUN: yaml2obj --docnum=1 %s -o %t1 +# RUN: llvm-objdump --dynamic-syms %t1 | FileCheck %s --check-prefix=DYNSYM +# RUN: llvm-objdump -T %t1 | FileCheck %s --check-prefix=DYNSYM + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_X86_64 +Sections: + - Name: .data + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_WRITE ] +DynamicSymbols: + - Name: localsym + Type: STT_OBJECT + Section: .data + Binding: STB_LOCAL + - Name: globalsym + Type: STT_OBJECT + Section: .data + Binding: STB_GLOBAL + - Name: uniqueglobalsym + Type: STT_OBJECT + Section: .data + Binding: STB_GNU_UNIQUE + - Name: weaksym + Type: STT_OBJECT + Section: .data + Binding: STB_WEAK + - Name: filesym + Type: STT_FILE + Section: .data + Binding: STB_GLOBAL + - Name: funcsym + Type: STT_FUNC + Section: .data + Binding: STB_GLOBAL + +# DYNSYM: DYNAMIC SYMBOL TABLE: +# DYNSYM-NEXT: 0000000000000000 l DO .data 0000000000000000 localsym +# DYNSYM-NEXT: 0000000000000000 g DO .data 0000000000000000 globalsym +# DYNSYM-NEXT: 0000000000000000 g DO .data 0000000000000000 uniqueglobalsym +# DYNSYM-NEXT: 0000000000000000 w DO .data 0000000000000000 weaksym +# DYNSYM-NEXT: 0000000000000000 g Df .data 0000000000000000 filesym +# DYNSYM-NEXT: 0000000000000000 g DF .data 0000000000000000 funcsym + +## Test dumping ELF files with no dynamic symbol. +# RUN: yaml2obj --docnum=2 %s -o %t2 +# RUN: llvm-objdump --dynamic-syms %t2 | FileCheck %s --check-prefix=NODYNSYM +# RUN: llvm-objdump -T %t2 | FileCheck %s --check-prefix=NODYNSYM +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_X86_64 +Sections: + - Name: .data + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_WRITE ] + +# NODYNSYM: DYNAMIC SYMBOL TABLE: +# NODYNSYM-NEXT: no symbols 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 @@ -138,7 +138,8 @@ void printSectionHeaders(const object::ObjectFile *O); void printSectionContents(const object::ObjectFile *O); void printSymbolTable(const object::ObjectFile *O, StringRef ArchiveName, - StringRef ArchitectureName = StringRef()); + StringRef ArchitectureName = StringRef(), + bool DumpDynamicSymbol = false); LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, Twine Message); LLVM_ATTRIBUTE_NORETURN void reportError(Error E, StringRef FileName, StringRef ArchiveName = "", 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 @@ -318,6 +318,15 @@ cl::NotHidden, cl::Grouping, cl::aliasopt(SymbolTable)); +cl::opt DynamicSymbolTable( + "dynamic-syms", + cl::desc("Display the contents of the dynamic symbol table"), + cl::cat(ObjdumpCat)); +static cl::alias DynamicSymbolTableShort("T", + cl::desc("Alias for --dynamic-syms"), + cl::NotHidden, cl::Grouping, + cl::aliasopt(DynamicSymbolTable)); + cl::opt TripleName("triple", cl::desc("Target triple to disassemble for, " "see -version for available targets"), @@ -1843,8 +1852,31 @@ } void printSymbolTable(const ObjectFile *O, StringRef ArchiveName, - StringRef ArchitectureName) { - outs() << "SYMBOL TABLE:\n"; + StringRef ArchitectureName, bool DumpDynamicSymbol) { + auto I = O->symbol_begin(); + auto E = O->symbol_end(); + + if (!DumpDynamicSymbol) + outs() << "SYMBOL TABLE:\n"; + else { + outs() << "DYNAMIC SYMBOL TABLE:\n"; + if (!O->isELF()) { + WithColor::error( + errs(), ToolName, + "This operation is only currently supported for ELF object files.\n"); + return; + } + + const ELFObjectFileBase *ELF = dyn_cast(O); + I = ELF->getDynamicSymbolIterators().begin(); + E = ELF->getDynamicSymbolIterators().end(); + if (I != E) + ++I; // Skip first meaningless symbol. + else { + outs() << "no symbols\n"; + return; + } + } if (const COFFObjectFile *Coff = dyn_cast(O)) { printCOFFSymbolTable(Coff); @@ -1853,7 +1885,8 @@ const StringRef FileName = O->getFileName(); const MachOObjectFile *MachO = dyn_cast(O); - for (auto I = O->symbol_begin(), E = O->symbol_end(); I != E; ++I) { + + for (; I != E; ++I) { const SymbolRef &Symbol = *I; uint64_t Address = unwrapOrError(Symbol.getAddress(), FileName, ArchiveName, ArchitectureName); @@ -1900,8 +1933,11 @@ char GlobLoc = ' '; if ((Section != O->section_end() || Absolute) && !Weak) GlobLoc = Global ? 'g' : 'l'; - char Debug = (Type == SymbolRef::ST_Debug || Type == SymbolRef::ST_File) - ? 'd' : ' '; + char Debug = + DumpDynamicSymbol + ? 'D' + : (Type == SymbolRef::ST_Debug || Type == SymbolRef::ST_File) ? 'd' + : ' '; char FileFunc = ' '; if (Type == SymbolRef::ST_File) FileFunc = 'f'; @@ -2216,6 +2252,8 @@ printSectionHeaders(O); if (SymbolTable) printSymbolTable(O, ArchiveName); + if (DynamicSymbolTable) + printSymbolTable(O, ArchiveName, StringRef(), /*DumpDynamicSymbol=*/true); if (DwarfDumpType != DIDT_Null) { std::unique_ptr DICtx = DWARFContext::create(*O); // Dump the complete DWARF structure. @@ -2355,7 +2393,7 @@ if (!ArchiveHeaders && !Disassemble && DwarfDumpType == DIDT_Null && !DynamicRelocations && !FileHeaders && !PrivateHeaders && !RawClangAST && !Relocations && !SectionHeaders && !SectionContents && !SymbolTable && - !UnwindInfo && !FaultMapSection && + !DynamicSymbolTable && !UnwindInfo && !FaultMapSection && !(MachOOpt && (Bind || DataInCode || DylibId || DylibsUsed || ExportsTrie || FirstPrivateHeader || IndirectSymbols || InfoPlist || LazyBind ||