[ELF] Implement demangle.
authorShankar Easwaran <shankarke@gmail.com>
Mon, 20 Oct 2014 05:04:53 +0000 (05:04 +0000)
committerShankar Easwaran <shankarke@gmail.com>
Mon, 20 Oct 2014 05:04:53 +0000 (05:04 +0000)
This adds functionality in the GNU flavor to demangle symbols when
undefined symbols are displayed to the user.

llvm-svn: 220184

lld/include/lld/ReaderWriter/ELFLinkingContext.h
lld/lib/Driver/GnuLdDriver.cpp
lld/lib/Driver/GnuLdOptions.td
lld/lib/ReaderWriter/ELF/ELFLinkingContext.cpp
lld/test/elf/X86_64/Inputs/undefcpp.c [new file with mode: 0644]
lld/test/elf/X86_64/Inputs/undefcpp.o [new file with mode: 0644]
lld/test/elf/X86_64/demangle.test [new file with mode: 0644]

index eda445b..225d3ca 100644 (file)
@@ -275,6 +275,11 @@ public:
     return _dynamicallyExportedSymbols.count(name) != 0;
   }
 
+  /// \brief Demangle symbols.
+  std::string demangle(StringRef symbolName) const override;
+  bool demangleSymbols() const { return _demangle; }
+  void setDemangleSymbols(bool d) { _demangle = d; }
+
 private:
   ELFLinkingContext() LLVM_DELETED_FUNCTION;
 
@@ -299,6 +304,7 @@ protected:
   bool _dynamicLinkerArg;
   bool _noAllowDynamicLibraries;
   bool _mergeRODataToTextSegment;
+  bool _demangle;
   OutputMagic _outputMagic;
   StringRefVector _inputSearchPaths;
   std::unique_ptr<Writer> _writer;
index 0d2dea3..542b1bd 100644 (file)
@@ -305,6 +305,14 @@ bool GnuLdDriver::parse(int argc, const char *argv[],
   if (!parsedArgs->hasArg(OPT_nostdlib))
     addPlatformSearchDirs(*ctx, triple, baseTriple);
 
+  // Handle --demangle option(For compatibility)
+  if (parsedArgs->getLastArg(OPT_demangle))
+    ctx->setDemangleSymbols(true);
+
+  // Handle --no-demangle option.
+  if (parsedArgs->getLastArg(OPT_no_demangle))
+    ctx->setDemangleSymbols(false);
+
   // Figure out output kind ( -r, -static, -shared)
   if (llvm::opt::Arg *kind =
           parsedArgs->getLastArg(OPT_relocatable, OPT_static, OPT_shared,
index 590ce95..0abb7e5 100644 (file)
@@ -215,6 +215,18 @@ def z : Separate<["-"], "z">,
      Group<grp_customopts>;
 
 //===----------------------------------------------------------------------===//
+/// Symbol options
+//===----------------------------------------------------------------------===//
+def grp_symbolopts : OptionGroup<"opts">,
+     HelpText<"SYMBOL OPTIONS">;
+def demangle : Flag<["--"], "demangle">,
+     HelpText<"Demangle C++ symbols">,
+     Group<grp_symbolopts>;
+def no_demangle : Flag<["--"], "no-demangle">,
+     HelpText<"Dont demangle C++ symbols">,
+     Group<grp_symbolopts>;
+
+//===----------------------------------------------------------------------===//
 /// Optimization Options
 //===----------------------------------------------------------------------===//
 def grp_opts : OptionGroup<"opts">,
index e3428fb..9dba86a 100644 (file)
 #include "lld/Passes/LayoutPass.h"
 #include "lld/Passes/RoundTripYAMLPass.h"
 #include "llvm/ADT/Triple.h"
+#include "llvm/Config/config.h"
 #include "llvm/Support/ELF.h"
 #include "llvm/Support/Errc.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/Path.h"
 
+#if HAVE_CXXABI_H
+#include <cxxabi.h>
+#endif
+
 namespace lld {
 
 class CommandLineAbsoluteAtom : public AbsoluteAtom {
@@ -53,12 +58,11 @@ ELFLinkingContext::ELFLinkingContext(
     llvm::Triple triple, std::unique_ptr<TargetHandlerBase> targetHandler)
     : _outputELFType(elf::ET_EXEC), _triple(triple),
       _targetHandler(std::move(targetHandler)), _baseAddress(0),
-      _isStaticExecutable(false), _noInhibitExec(false),
-      _exportDynamic(false), _mergeCommonStrings(false),
-      _runLayoutPass(true), _useShlibUndefines(true),
-      _dynamicLinkerArg(false), _noAllowDynamicLibraries(false),
-      _mergeRODataToTextSegment(true), _outputMagic(OutputMagic::DEFAULT),
-      _sysrootPath("") {}
+      _isStaticExecutable(false), _noInhibitExec(false), _exportDynamic(false),
+      _mergeCommonStrings(false), _runLayoutPass(true),
+      _useShlibUndefines(true), _dynamicLinkerArg(false),
+      _noAllowDynamicLibraries(false), _mergeRODataToTextSegment(true),
+      _demangle(true), _outputMagic(OutputMagic::DEFAULT), _sysrootPath("") {}
 
 bool ELFLinkingContext::is64Bits() const { return getTriple().isArch64Bit(); }
 
@@ -260,4 +264,29 @@ void ELFLinkingContext::notifySymbolTableCoalesce(const Atom *existingAtom,
     _dynamicallyExportedSymbols.insert(ua->name());
 }
 
+std::string ELFLinkingContext::demangle(StringRef symbolName) const {
+  if (!_demangle)
+    return symbolName;
+
+  // Only try to demangle symbols that look like C++ symbols
+  if (!symbolName.startswith("_Z"))
+    return symbolName;
+
+#if HAVE_CXXABI_H
+  SmallString<256> symBuff;
+  StringRef nullTermSym = Twine(symbolName).toNullTerminatedStringRef(symBuff);
+  const char *cstr = nullTermSym.data();
+  int status;
+  char *demangled = abi::__cxa_demangle(cstr, nullptr, nullptr, &status);
+  if (demangled != NULL) {
+    std::string result(demangled);
+    // __cxa_demangle() always uses a malloc'ed buffer to return the result.
+    free(demangled);
+    return result;
+  }
+#endif
+
+  return symbolName;
+}
+
 } // end namespace lld
diff --git a/lld/test/elf/X86_64/Inputs/undefcpp.c b/lld/test/elf/X86_64/Inputs/undefcpp.c
new file mode 100644 (file)
index 0000000..ce84c2a
--- /dev/null
@@ -0,0 +1 @@
+int foo() { return _Z3fooPKc(); }
diff --git a/lld/test/elf/X86_64/Inputs/undefcpp.o b/lld/test/elf/X86_64/Inputs/undefcpp.o
new file mode 100644 (file)
index 0000000..6b8ebf5
Binary files /dev/null and b/lld/test/elf/X86_64/Inputs/undefcpp.o differ
diff --git a/lld/test/elf/X86_64/demangle.test b/lld/test/elf/X86_64/demangle.test
new file mode 100644 (file)
index 0000000..820e6be
--- /dev/null
@@ -0,0 +1,10 @@
+# Check that the linker is able to demangle strings properly.
+# Once there is a way to add undefined symbols using yaml2obj, the test will be
+# changed.
+#
+RUN: lld -flavor gnu -target x86_64 %p/Inputs/undefcpp.o --noinhibit-exec 2>&1 | FileCheck -check-prefix=DEMANGLE %s
+RUN: lld -flavor gnu -target x86_64 %p/Inputs/undefcpp.o --noinhibit-exec --no-demangle 2>&1 | FileCheck -check-prefix=NODEMANGLE %s
+RUN: lld -flavor gnu -target x86_64 %p/Inputs/undefcpp.o --noinhibit-exec --demangle 2>&1 | FileCheck -check-prefix=DEMANGLE %s
+
+#DEMANGLE: undefcpp.o: foo(char const*)
+#NODEMANGLE: undefcpp.o: _Z3fooPKc