Support reading GNU symbol versions in ELFObjectFile

* Add enums and structures for GNU version information.
* Implement extraction of that information on a per-symbol basis (ELFObjectFile::getSymbolVersion).
* Implement a generic interface, GetELFSymbolVersion(), for getting the symbol version from the ObjectFile (hides the templating).
* Have llvm-readobj print out the version, when available.
* Add a test for the new feature: readobj-elf-versioning.test



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@152436 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/tools/llvm-readobj/llvm-readobj.cpp b/tools/llvm-readobj/llvm-readobj.cpp
index 3f8789d..0c58fb3 100644
--- a/tools/llvm-readobj/llvm-readobj.cpp
+++ b/tools/llvm-readobj/llvm-readobj.cpp
@@ -17,6 +17,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/Object/ObjectFile.h"
+#include "llvm/Object/ELF.h"
 #include "llvm/Analysis/Verifier.h"
 #include "llvm/ADT/Triple.h"
 #include "llvm/Support/Format.h"
@@ -78,22 +79,35 @@
   return result;
 }
 
-void DumpSymbol(const SymbolRef &sym) {
+void DumpSymbol(const SymbolRef &Sym, const ObjectFile *obj, bool IsDynamic) {
     StringRef Name;
     SymbolRef::Type Type;
     uint32_t Flags;
     uint64_t Address;
     uint64_t Size;
     uint64_t FileOffset;
-    sym.getName(Name);
-    sym.getAddress(Address);
-    sym.getSize(Size);
-    sym.getFileOffset(FileOffset);
-    sym.getType(Type);
-    sym.getFlags(Flags);
+    Sym.getName(Name);
+    Sym.getAddress(Address);
+    Sym.getSize(Size);
+    Sym.getFileOffset(FileOffset);
+    Sym.getType(Type);
+    Sym.getFlags(Flags);
+    std::string FullName = Name;
+
+    // If this is a dynamic symbol from an ELF object, append
+    // the symbol's version to the name.
+    if (IsDynamic && obj->isELF()) {
+      StringRef Version;
+      bool IsDefault;
+      GetELFSymbolVersion(obj, Sym, Version, IsDefault);
+      if (!Version.empty()) {
+        FullName += (IsDefault ? "@@" : "@");
+        FullName += Version;
+      }
+    }
 
     // format() can't handle StringRefs
-    outs() << format("  %-32s", Name.str().c_str())
+    outs() << format("  %-32s", FullName.c_str())
            << format("  %-4s", GetTypeStr(Type))
            << format("  %16"PRIx64, Address)
            << format("  %16"PRIx64, Size)
@@ -111,7 +125,7 @@
   symbol_iterator it = obj->begin_symbols();
   symbol_iterator ie = obj->end_symbols();
   while (it != ie) {
-    DumpSymbol(*it);
+    DumpSymbol(*it, obj, false);
     it.increment(ec);
     if (ec)
       report_fatal_error("Symbol iteration failed");
@@ -128,7 +142,7 @@
   symbol_iterator it = obj->begin_dynamic_symbols();
   symbol_iterator ie = obj->end_dynamic_symbols();
   while (it != ie) {
-    DumpSymbol(*it);
+    DumpSymbol(*it, obj, true);
     it.increment(ec);
     if (ec)
       report_fatal_error("Symbol iteration failed");