Correctly resolve symbol names containing linker annotations

Summary:
Symbols in ELF files can be versioned, but LLDB currently does not understand these. This problem
becomes apparent once one loads glibc with debug info. Here (in the .symtab section) the versions
are embedded in the name (name@VERSION), which causes issues when evaluating expressions
referencing memcpy for example (current glibc contains memcpy@@GLIBC_2.14 and
memcpy@GLIBC_2.2.5).

This problem was not evident without debug symbols as the .dynsym section
stores the bare names and the actual versions are present in a separate section (.gnu.version_d),
which LLDB ignores. This resulted in two definitions of memcpy in the symbol table.

This patch adds support for storing annotated names to the Symbol class. If
Symbol.m_contains_linker_annotations is true then this symbol is annotated. Unannotated name can
be obtained by calling StripLinkerAnnotations on the corresponding ObjectFile. ObjectFileELF
implements this to strip @VERSION suffixes when requested. Symtab uses this function to add the
bare name as well as the annotated name to the name lookup table.

To preserve the size of the Symbol class, I had to steal one bit from the m_type field.

Test Plan:
This fixes TestExprHelpExamples.py when run with a glibc with debug symbols. Writing
an environment agnostic test case would require building a custom shared library with symbol
versions and testing symbol resolution against that, which is somewhat challenging.

Reviewers: clayborg, jingham

Subscribers: lldb-commits

Differential Revision: http://reviews.llvm.org/D8036

llvm-svn: 231228
diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
index 1b49aab..1a2ef87 100644
--- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
+++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
@@ -1504,6 +1504,13 @@
     return DataExtractor(m_data, segment_header->p_offset, segment_header->p_filesz);
 }
 
+std::string
+ObjectFileELF::StripLinkerSymbolAnnotations(llvm::StringRef symbol_name) const
+{
+    size_t pos = symbol_name.find("@");
+    return symbol_name.substr(0, pos).str();
+}
+
 //----------------------------------------------------------------------
 // ParseSectionHeaders
 //----------------------------------------------------------------------
@@ -1897,23 +1904,46 @@
         uint32_t flags = symbol.st_other << 8 | symbol.st_info | additional_flags;
         bool is_mangled = symbol_name ? (symbol_name[0] == '_' && symbol_name[1] == 'Z') : false;
 
+        llvm::StringRef symbol_ref(symbol_name);
+
+        // Symbol names may contain @VERSION suffixes. Find those and strip them temporarily.
+        size_t version_pos = symbol_ref.find('@');
+        bool has_suffix = version_pos != llvm::StringRef::npos;
+        llvm::StringRef symbol_bare = symbol_ref.substr(0, version_pos);
+        Mangled mangled(ConstString(symbol_bare), is_mangled);
+
+        // Now append the suffix back to mangled and unmangled names. Only do it if the
+        // demangling was sucessful (string is not empty).
+        if (has_suffix)
+        {
+            llvm::StringRef suffix = symbol_ref.substr(version_pos);
+
+            llvm::StringRef mangled_name = mangled.GetMangledName().GetStringRef();
+            if (! mangled_name.empty())
+                mangled.SetMangledName( ConstString((mangled_name + suffix).str()) );
+
+            llvm::StringRef demangled_name = mangled.GetDemangledName().GetStringRef();
+            if (! demangled_name.empty())
+                mangled.SetDemangledName( ConstString((demangled_name + suffix).str()) );
+        }
+
         Symbol dc_symbol(
             i + start_id,       // ID is the original symbol table index.
-            symbol_name,        // Symbol name.
-            is_mangled,         // Is the symbol name mangled?
+            mangled,
             symbol_type,        // Type of this symbol
             is_global,          // Is this globally visible?
             false,              // Is this symbol debug info?
             false,              // Is this symbol a trampoline?
             false,              // Is this symbol artificial?
-            symbol_section_sp,  // Section in which this symbol is defined or null.
-            symbol_value,       // Offset in section or symbol value.
-            symbol.st_size,     // Size in bytes of this symbol.
+            AddressRange(
+                symbol_section_sp,  // Section in which this symbol is defined or null.
+                symbol_value,       // Offset in section or symbol value.
+                symbol.st_size),    // Size in bytes of this symbol.
             true,               // Size is valid
+            has_suffix,         // Contains linker annotations?
             flags);             // Symbol flags.
         symtab->AddSymbol(dc_symbol);
     }
-
     return i;
 }
 
@@ -2102,6 +2132,7 @@
             plt_index,       // Offset in section or symbol value.
             plt_entsize,     // Size in bytes of this symbol.
             true,            // Size is valid
+            false,           // Contains linker annotations?
             0);              // Symbol flags.
 
         symbol_table->AddSymbol(jump_symbol);
@@ -2443,6 +2474,7 @@
                         offset,               // Offset in section or symbol value.
                         range.GetByteSize(),  // Size in bytes of this symbol.
                         true,                 // Size is valid.
+                        false,                // Contains linker annotations?
                         0);                   // Symbol flags.
                 if (symbol_id == m_symtab_ap->AddSymbol(eh_symbol))
                     return m_symtab_ap->SymbolAtIndex(symbol_id);
diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
index b10dfb5..f264478 100644
--- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
+++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
@@ -187,6 +187,9 @@
     lldb_private::DataExtractor
     GetSegmentDataByIndex(lldb::user_id_t id);
 
+    std::string
+    StripLinkerSymbolAnnotations(llvm::StringRef symbol_name) const override;
+
 private:
     ObjectFileELF(const lldb::ModuleSP &module_sp,
                   lldb::DataBufferSP& data_sp,