[Object] Add {begin,end}_dynamic_symbols stubs and implementation for ELF.
authorMichael J. Spencer <bigcheesegs@gmail.com>
Tue, 28 Feb 2012 00:40:37 +0000 (00:40 +0000)
committerMichael J. Spencer <bigcheesegs@gmail.com>
Tue, 28 Feb 2012 00:40:37 +0000 (00:40 +0000)
Add -D option to llvm-nm to dump dynamic symbols.

Patch by David Meyer.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@151600 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/Object/COFF.h
include/llvm/Object/ELF.h
include/llvm/Object/MachO.h
include/llvm/Object/ObjectFile.h
lib/Object/COFFObjectFile.cpp
lib/Object/MachOObjectFile.cpp
test/Object/Inputs/shared-object-test.elf-i386 [new file with mode: 0644]
test/Object/Inputs/shared-object-test.elf-x86-64 [new file with mode: 0644]
test/Object/Inputs/shared.ll [new file with mode: 0644]
test/Object/nm-shared-object.test [new file with mode: 0644]
tools/llvm-nm/llvm-nm.cpp

index 73bde8ef4125de468d044a59451ac123f784c9f3..714034069095eadabb60e7cef2e0f5deaf58c6c9 100644 (file)
@@ -152,6 +152,8 @@ public:
   COFFObjectFile(MemoryBuffer *Object, error_code &ec);
   virtual symbol_iterator begin_symbols() const;
   virtual symbol_iterator end_symbols() const;
+  virtual symbol_iterator begin_dynamic_symbols() const;
+  virtual symbol_iterator end_dynamic_symbols() const;
   virtual section_iterator begin_sections() const;
   virtual section_iterator end_sections() const;
 
index aaeea1d2bf854950d5a68aa5f30e3204d6a90b0c..2fd10ef6710de8a404ff13ee9af86d8d95636635 100644 (file)
@@ -295,6 +295,7 @@ private:
   const Elf_Shdr *SectionHeaderTable;
   const Elf_Shdr *dot_shstrtab_sec; // Section header string table.
   const Elf_Shdr *dot_strtab_sec;   // Symbol header string table.
+  const Elf_Shdr *dot_dynstr_sec;   // Dynamic symbol string table.
   Sections_t SymbolTableSections;
   IndexMap_t SymbolTableSectionsIndexMap;
   DenseMap<const Elf_Sym*, ELF::Elf64_Word> ExtendedSymbolTable;
@@ -319,7 +320,10 @@ private:
   const Elf_Rela *getRela(DataRefImpl Rela) const;
   const char     *getString(uint32_t section, uint32_t offset) const;
   const char     *getString(const Elf_Shdr *section, uint32_t offset) const;
-  error_code      getSymbolName(const Elf_Sym *Symb, StringRef &Res) const;
+  error_code      getSymbolName(const Elf_Shdr *section,
+                                const Elf_Sym *Symb,
+                                StringRef &Res) const;
+  void VerifyStrTab(const Elf_Shdr *sh) const;
 
 protected:
   const Elf_Sym  *getSymbol(DataRefImpl Symb) const; // FIXME: Should be private?
@@ -375,6 +379,8 @@ public:
   ELFObjectFile(MemoryBuffer *Object, error_code &ec);
   virtual symbol_iterator begin_symbols() const;
   virtual symbol_iterator end_symbols() const;
+  virtual symbol_iterator begin_dynamic_symbols() const;
+  virtual symbol_iterator end_dynamic_symbols() const;
   virtual section_iterator begin_sections() const;
   virtual section_iterator end_sections() const;
 
@@ -425,10 +431,14 @@ error_code ELFObjectFile<target_endianness, is64Bits>
   // Check to see if we are at the end of this symbol table.
   if (Symb.d.a >= SymbolTableSection->getEntityCount()) {
     // We are at the end. If there are other symbol tables, jump to them.
-    ++Symb.d.b;
-    Symb.d.a = 1; // The 0th symbol in ELF is fake.
+    // If the symbol table is .dynsym, we are iterating dynamic symbols,
+    // and there is only one table of these.
+    if (Symb.d.b != 0) {
+      ++Symb.d.b;
+      Symb.d.a = 1; // The 0th symbol in ELF is fake.
+    }
     // Otherwise return the terminator.
-    if (Symb.d.b >= SymbolTableSections.size()) {
+    if (Symb.d.b == 0 || Symb.d.b >= SymbolTableSections.size()) {
       Symb.d.a = std::numeric_limits<uint32_t>::max();
       Symb.d.b = std::numeric_limits<uint32_t>::max();
     }
@@ -444,7 +454,7 @@ error_code ELFObjectFile<target_endianness, is64Bits>
                                         StringRef &Result) const {
   validateSymbol(Symb);
   const Elf_Sym *symb = getSymbol(Symb);
-  return getSymbolName(symb, Result);
+  return getSymbolName(SymbolTableSections[Symb.d.b], symb, Result);
 }
 
 template<support::endianness target_endianness, bool is64Bits>
@@ -1128,7 +1138,7 @@ error_code ELFObjectFile<target_endianness, is64Bits>
   }
   const Elf_Sym *symb = getEntry<Elf_Sym>(sec->sh_link, symbol_index);
   StringRef symname;
-  if (error_code ec = getSymbolName(symb, symname))
+  if (error_code ec = getSymbolName(getSection(sec->sh_link), symb, symname))
     return ec;
   switch (Header->e_machine) {
   case ELF::EM_X86_64:
@@ -1156,6 +1166,16 @@ error_code ELFObjectFile<target_endianness, is64Bits>
   return object_error::success;
 }
 
+// Verify that the last byte in the string table in a null.
+template<support::endianness target_endianness, bool is64Bits>
+void ELFObjectFile<target_endianness, is64Bits>
+                  ::VerifyStrTab(const Elf_Shdr *sh) const {
+  const char *strtab = (const char*)base() + sh->sh_offset;
+  if (strtab[sh->sh_size - 1] != 0)
+    // FIXME: Proper error handling.
+    report_fatal_error("String table must end with a null terminator!");
+}
+
 template<support::endianness target_endianness, bool is64Bits>
 ELFObjectFile<target_endianness, is64Bits>::ELFObjectFile(MemoryBuffer *Object
                                                           , error_code &ec)
@@ -1163,7 +1183,8 @@ ELFObjectFile<target_endianness, is64Bits>::ELFObjectFile(MemoryBuffer *Object
   , isDyldELFObject(false)
   , SectionHeaderTable(0)
   , dot_shstrtab_sec(0)
-  , dot_strtab_sec(0) {
+  , dot_strtab_sec(0)
+  , dot_dynstr_sec(0) {
 
   const uint64_t FileSize = Data->getBufferSize();
 
@@ -1194,6 +1215,10 @@ ELFObjectFile<target_endianness, is64Bits>::ELFObjectFile(MemoryBuffer *Object
   // To find the symbol tables we walk the section table to find SHT_SYMTAB.
   const Elf_Shdr* SymbolTableSectionHeaderIndex = 0;
   const Elf_Shdr* sh = SectionHeaderTable;
+
+  // Reserve SymbolTableSections[0] for .dynsym
+  SymbolTableSections.push_back(NULL);
+
   for (uint64_t i = 0, e = getNumSections(); i != e; ++i) {
     if (sh->sh_type == ELF::SHT_SYMTAB_SHNDX) {
       if (SymbolTableSectionHeaderIndex)
@@ -1205,6 +1230,13 @@ ELFObjectFile<target_endianness, is64Bits>::ELFObjectFile(MemoryBuffer *Object
       SymbolTableSectionsIndexMap[i] = SymbolTableSections.size();
       SymbolTableSections.push_back(sh);
     }
+    if (sh->sh_type == ELF::SHT_DYNSYM) {
+      if (SymbolTableSections[0] != NULL)
+        // FIXME: Proper error handling.
+        report_fatal_error("More than one .dynsym!");
+      SymbolTableSectionsIndexMap[i] = 0;
+      SymbolTableSections[0] = sh;
+    }
     if (sh->sh_type == ELF::SHT_REL || sh->sh_type == ELF::SHT_RELA) {
       SectionRelocMap[getSection(sh->sh_info)].push_back(i);
     }
@@ -1221,10 +1253,7 @@ ELFObjectFile<target_endianness, is64Bits>::ELFObjectFile(MemoryBuffer *Object
   dot_shstrtab_sec = getSection(getStringTableIndex());
   if (dot_shstrtab_sec) {
     // Verify that the last byte in the string table in a null.
-    if (((const char*)base() + dot_shstrtab_sec->sh_offset)
-        [dot_shstrtab_sec->sh_size - 1] != 0)
-      // FIXME: Proper error handling.
-      report_fatal_error("String table must end with a null terminator!");
+    VerifyStrTab(dot_shstrtab_sec);
   }
 
   // Merge this into the above loop.
@@ -1239,10 +1268,13 @@ ELFObjectFile<target_endianness, is64Bits>::ELFObjectFile(MemoryBuffer *Object
           // FIXME: Proper error handling.
           report_fatal_error("Already found section named .strtab!");
         dot_strtab_sec = sh;
-        const char *dot_strtab = (const char*)base() + sh->sh_offset;
-          if (dot_strtab[sh->sh_size - 1] != 0)
-            // FIXME: Proper error handling.
-            report_fatal_error("String table must end with a null terminator!");
+        VerifyStrTab(dot_strtab_sec);
+      } else if (SectionName == ".dynstr") {
+        if (dot_dynstr_sec != 0)
+          // FIXME: Proper error handling.
+          report_fatal_error("Already found section named .dynstr!");
+        dot_dynstr_sec = sh;
+        VerifyStrTab(dot_dynstr_sec);
       }
     }
   }
@@ -1268,12 +1300,12 @@ symbol_iterator ELFObjectFile<target_endianness, is64Bits>
                              ::begin_symbols() const {
   DataRefImpl SymbolData;
   memset(&SymbolData, 0, sizeof(SymbolData));
-  if (SymbolTableSections.size() == 0) {
+  if (SymbolTableSections.size() <= 1) {
     SymbolData.d.a = std::numeric_limits<uint32_t>::max();
     SymbolData.d.b = std::numeric_limits<uint32_t>::max();
   } else {
     SymbolData.d.a = 1; // The 0th symbol in ELF is fake.
-    SymbolData.d.b = 0;
+    SymbolData.d.b = 1; // The 0th table is .dynsym
   }
   return symbol_iterator(SymbolRef(SymbolData, this));
 }
@@ -1288,6 +1320,31 @@ symbol_iterator ELFObjectFile<target_endianness, is64Bits>
   return symbol_iterator(SymbolRef(SymbolData, this));
 }
 
+template<support::endianness target_endianness, bool is64Bits>
+symbol_iterator ELFObjectFile<target_endianness, is64Bits>
+                             ::begin_dynamic_symbols() const {
+  DataRefImpl SymbolData;
+  memset(&SymbolData, 0, sizeof(SymbolData));
+  if (SymbolTableSections[0] == NULL) {
+    SymbolData.d.a = std::numeric_limits<uint32_t>::max();
+    SymbolData.d.b = std::numeric_limits<uint32_t>::max();
+  } else {
+    SymbolData.d.a = 1; // The 0th symbol in ELF is fake.
+    SymbolData.d.b = 0; // The 0th table is .dynsym
+  }
+  return symbol_iterator(SymbolRef(SymbolData, this));
+}
+
+template<support::endianness target_endianness, bool is64Bits>
+symbol_iterator ELFObjectFile<target_endianness, is64Bits>
+                             ::end_dynamic_symbols() const {
+  DataRefImpl SymbolData;
+  memset(&SymbolData, 0, sizeof(SymbolData));
+  SymbolData.d.a = std::numeric_limits<uint32_t>::max();
+  SymbolData.d.b = std::numeric_limits<uint32_t>::max();
+  return symbol_iterator(SymbolRef(SymbolData, this));
+}
+
 template<support::endianness target_endianness, bool is64Bits>
 section_iterator ELFObjectFile<target_endianness, is64Bits>
                               ::begin_sections() const {
@@ -1461,7 +1518,8 @@ const char *ELFObjectFile<target_endianness, is64Bits>
 
 template<support::endianness target_endianness, bool is64Bits>
 error_code ELFObjectFile<target_endianness, is64Bits>
-                        ::getSymbolName(const Elf_Sym *symb,
+                        ::getSymbolName(const Elf_Shdr *section,
+                                        const Elf_Sym *symb,
                                         StringRef &Result) const {
   if (symb->st_name == 0) {
     const Elf_Shdr *section = getSection(symb);
@@ -1472,8 +1530,13 @@ error_code ELFObjectFile<target_endianness, is64Bits>
     return object_error::success;
   }
 
-  // Use the default symbol table name section.
-  Result = getString(dot_strtab_sec, symb->st_name);
+  if (section == SymbolTableSections[0]) {
+    // Symbol is in .dynsym, use .dynstr string table
+    Result = getString(dot_dynstr_sec, symb->st_name);
+  } else {
+    // Use the default symbol table name section.
+    Result = getString(dot_strtab_sec, symb->st_name);
+  }
   return object_error::success;
 }
 
index 7e3a90dab1a8439cdc159cf70448910481834544..b6e583f6f37d855daaf95414f235c9b60c113f3c 100644 (file)
@@ -32,6 +32,8 @@ public:
 
   virtual symbol_iterator begin_symbols() const;
   virtual symbol_iterator end_symbols() const;
+  virtual symbol_iterator begin_dynamic_symbols() const;
+  virtual symbol_iterator end_dynamic_symbols() const;
   virtual section_iterator begin_sections() const;
   virtual section_iterator end_sections() const;
 
index 3a4052abdb32b238ecbd0fc14917a1f8c5426810..4aa05e234fefbbecb9f92052fa6227a80c02c17d 100644 (file)
@@ -313,6 +313,9 @@ public:
   virtual symbol_iterator begin_symbols() const = 0;
   virtual symbol_iterator end_symbols() const = 0;
 
+  virtual symbol_iterator begin_dynamic_symbols() const = 0;
+  virtual symbol_iterator end_dynamic_symbols() const = 0;
+
   virtual section_iterator begin_sections() const = 0;
   virtual section_iterator end_sections() const = 0;
 
index bdf54314458b58cf4f6b2f625151a7ca51a1407f..a2dad41818e1971c6dd5bd5b999c7a6e68f85ee7 100644 (file)
@@ -508,6 +508,16 @@ symbol_iterator COFFObjectFile::end_symbols() const {
   return symbol_iterator(SymbolRef(ret, this));
 }
 
+symbol_iterator COFFObjectFile::begin_dynamic_symbols() const {
+  // TODO: implement
+  report_fatal_error("Dynamic symbols unimplemented in COFFObjectFile");
+}
+
+symbol_iterator COFFObjectFile::end_dynamic_symbols() const {
+  // TODO: implement
+  report_fatal_error("Dynamic symbols unimplemented in COFFObjectFile");
+}
+
 section_iterator COFFObjectFile::begin_sections() const {
   DataRefImpl ret;
   std::memset(&ret, 0, sizeof(DataRefImpl));
index 4fa621ba9e5a2790fab238639de8c9d8b5de379a..b1416eae89ded54c3bb2388fb9d5f881ef22f6b2 100644 (file)
@@ -388,6 +388,15 @@ symbol_iterator MachOObjectFile::end_symbols() const {
   return symbol_iterator(SymbolRef(DRI, this));
 }
 
+symbol_iterator MachOObjectFile::begin_dynamic_symbols() const {
+  // TODO: implement
+  report_fatal_error("Dynamic symbols unimplemented in MachOObjectFile");
+}
+
+symbol_iterator MachOObjectFile::end_dynamic_symbols() const {
+  // TODO: implement
+  report_fatal_error("Dynamic symbols unimplemented in MachOObjectFile");
+}
 
 /*===-- Sections ----------------------------------------------------------===*/
 
diff --git a/test/Object/Inputs/shared-object-test.elf-i386 b/test/Object/Inputs/shared-object-test.elf-i386
new file mode 100644 (file)
index 0000000..5129cc4
Binary files /dev/null and b/test/Object/Inputs/shared-object-test.elf-i386 differ
diff --git a/test/Object/Inputs/shared-object-test.elf-x86-64 b/test/Object/Inputs/shared-object-test.elf-x86-64
new file mode 100644 (file)
index 0000000..71081eb
Binary files /dev/null and b/test/Object/Inputs/shared-object-test.elf-x86-64 differ
diff --git a/test/Object/Inputs/shared.ll b/test/Object/Inputs/shared.ll
new file mode 100644 (file)
index 0000000..3db0f82
--- /dev/null
@@ -0,0 +1,31 @@
+; How to make the shared objects from this file:
+;
+; X86-32 ELF:
+;   llc -mtriple=i386-linux-gnu shared.ll -filetype=obj -o tmp32.o -relocation-model=pic
+;   ld -melf_i386 -shared tmp32.o -o shared-object-test.elf-i386 --unresolved-symbols=ignore-all
+;
+; X86-64 ELF:
+;   llc -mtriple=x86_64-linux-gnu shared.ll -filetype=obj -o tmp64.o -relocation-model=pic
+;   ld -melf_x86_64 -shared tmp64.o -o shared-object-test.elf-x86-64 --unresolved-symbols=ignore-all
+
+@defined_sym = global i32 1, align 4
+
+@tls_sym = thread_local global i32 2, align 4
+
+@undef_sym = external global i32
+
+@undef_tls_sym = external thread_local global i32
+
+@common_sym = common global i32 0, align 4
+
+define i32 @global_func() nounwind uwtable {
+entry:
+  ret i32 0
+}
+
+declare i32 @undef_func(...)
+
+define internal i32 @local_func() nounwind uwtable {
+entry:
+  ret i32 0
+}
diff --git a/test/Object/nm-shared-object.test b/test/Object/nm-shared-object.test
new file mode 100644 (file)
index 0000000..b361df5
--- /dev/null
@@ -0,0 +1,15 @@
+RUN: llvm-nm -D %p/Inputs/shared-object-test.elf-i386 \
+RUN:         | FileCheck %s -check-prefix ELF
+RUN: llvm-nm -D %p/Inputs/shared-object-test.elf-x86-64 \
+RUN:         | FileCheck %s -check-prefix ELF
+
+; Note: tls_sym should be 'D' (not '?'), but TLS is not
+; yet recognized by ObjectFile.
+
+ELF: {{[0-9a-f]+}} A __bss_start
+ELF: {{[0-9a-f]+}} A _edata
+ELF: {{[0-9a-f]+}} A _end
+ELF: {{[0-9a-f]+}} B common_sym
+ELF: {{[0-9a-f]+}} D defined_sym
+ELF: {{[0-9a-f]+}} T global_func
+ELF:               ? tls_sym
index 13356f81b80e96c4ac7d64ca240d1de053ec354c..8688d4af6597993c9afc7100b6d381dff8faeb77 100644 (file)
@@ -61,6 +61,12 @@ namespace {
   cl::alias UndefinedOnly2("u", cl::desc("Alias for --undefined-only"),
                            cl::aliasopt(UndefinedOnly));
 
+  cl::opt<bool> DynamicSyms("dynamic",
+                             cl::desc("Display the dynamic symbols instead "
+                                      "of normal symbols."));
+  cl::alias DynamicSyms2("D", cl::desc("Alias for --dynamic"),
+                         cl::aliasopt(DynamicSyms));
+
   cl::opt<bool> DefinedOnly("defined-only",
                             cl::desc("Show only defined symbols"));
 
@@ -277,9 +283,13 @@ static void DumpSymbolNamesFromModule(Module *M) {
 
 static void DumpSymbolNamesFromObject(ObjectFile *obj) {
   error_code ec;
-  for (symbol_iterator i = obj->begin_symbols(),
-                       e = obj->end_symbols();
-                       i != e; i.increment(ec)) {
+  symbol_iterator ibegin = obj->begin_symbols();
+  symbol_iterator iend = obj->end_symbols();
+  if (DynamicSyms) {
+    ibegin = obj->begin_dynamic_symbols();
+    iend = obj->end_dynamic_symbols();
+  }
+  for (symbol_iterator i = ibegin; i != iend; i.increment(ec)) {
     if (error(ec)) break;
     bool internal;
     if (error(i->isInternal(internal))) break;