Handle PIEs in libbacktrace

Submitted by Jakub Jelinek on Dec. 6, 2013, 9:53 a.m.

Details

Message ID 20131206095337.GH892@tucnak.redhat.com
State New
Headers show

Commit Message

Jakub Jelinek Dec. 6, 2013, 9:53 a.m.
On Fri, Dec 06, 2013 at 12:53:02PM +0400, Alexey Samsonov wrote:
> ASan calls this function only for global variables (not functions). It
> is needed because
> we use a different machinery to pass global names to ASan runtime - we
> register globals
> by a call from instrumented code, which also tells runtime the
> (mangled) global name.

Well, given that it demangled just fine even function names, I guess it
calls it always and just it would do nothing for function names demangled
already by llvm-symbolizer if using the external symbolizer.

> OTOH, in TSan we rely on symbolization to demangle names of global variables.

Then we need something like following, with which all tests pass.  I'm not
using Demangle method from the symbolizer, because getting it requires a
mutex that is already held.

The alternative would be to just (perhaps under #ifdef SANITIZER_CP_DEMANGLE)
compile in libiberty/cp-demangle.c (similarly how libstdc++ compiles it in)
as part of libsanitizer/libiberty/ or even libsanitizer/libbacktrace/,
and tweak it, so that like libsanitizer/libbacktrace it uses internal_memcpy
etc. and uses InternalAlloc/InternalFree.  The problem is that cp-demangle.c
uses only realloc and free, and doesn't provide any hint on how large the
previously allocated memory chunk is.  So, either there is some easy way
how to query the size of InternalAlloc returned allocation, or we would need
to allocate uptr extra and store there number of bytes allocated
and emulate realloc/free that way.



	Jakub

Comments

Ian Taylor Dec. 6, 2013, 2:40 p.m.
On Fri, Dec 6, 2013 at 1:53 AM, Jakub Jelinek <jakub@redhat.com> wrote:
>
> The alternative would be to just (perhaps under #ifdef SANITIZER_CP_DEMANGLE)
> compile in libiberty/cp-demangle.c (similarly how libstdc++ compiles it in)
> as part of libsanitizer/libiberty/ or even libsanitizer/libbacktrace/,
> and tweak it, so that like libsanitizer/libbacktrace it uses internal_memcpy
> etc. and uses InternalAlloc/InternalFree.  The problem is that cp-demangle.c
> uses only realloc and free, and doesn't provide any hint on how large the
> previously allocated memory chunk is.  So, either there is some easy way
> how to query the size of InternalAlloc returned allocation, or we would need
> to allocate uptr extra and store there number of bytes allocated
> and emulate realloc/free that way.

There was a recent buggy patch to the demangler that added calls to
malloc and realloc (2013-10-25 Gary Benson <gbenson@redhat.com>).
That patch must be fixed or reverted before the 4.9 release.  The main
code in the demangler must not call malloc/realloc.

When that patch is fixed, you can use the cplus_demangle_v3_callback
function to get a demangler that never calls malloc.

Ian

Patch hide | download patch | download mbox

--- libsanitizer/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc.jj	2013-12-05 12:04:28.000000000 +0100
+++ libsanitizer/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc	2013-12-06 10:36:02.285059188 +0100
@@ -25,6 +25,15 @@ 
 # endif
 #endif
 
+// C++ demangling function, as required by Itanium C++ ABI. This is weak,
+// because we do not require a C++ ABI library to be linked to a program
+// using sanitizers; if it's not present, we'll just use the mangled name.
+namespace __cxxabiv1 {
+  extern "C" SANITIZER_WEAK_ATTRIBUTE
+  char *__cxa_demangle(const char *mangled, char *buffer,
+		       size_t *length, int *status);
+}
+
 namespace __sanitizer {
 
 #if SANITIZER_LIBBACKTRACE
@@ -39,6 +48,19 @@  struct SymbolizeCodeData {
   uptr module_offset;
 };
 
+char *MaybeDemangleAndDup(const char *symname) {
+  const char *demangled = symname;
+  if (symname[0] == '_' && symname[1] == 'Z' && __cxxabiv1::__cxa_demangle) {
+    demangled = __cxxabiv1::__cxa_demangle(symname, 0, 0, 0);
+    if (demangled == NULL)
+      demangled = symname;
+  }                      
+  char *ret = internal_strdup(demangled);
+  if (demangled != symname)
+    __builtin_free ((void *) demangled);
+  return ret;
+}
+
 extern "C" {
 static int SymbolizeCodePCInfoCallback(void *vdata, uintptr_t addr,
                                        const char *filename, int lineno,
@@ -49,7 +71,7 @@  static int SymbolizeCodePCInfoCallback(v
     info->Clear();
     info->FillAddressAndModuleInfo(addr, cdata->module_name,
                                    cdata->module_offset);
-    info->function = internal_strdup(function);
+    info->function = MaybeDemangleAndDup(function);
     if (filename)
       info->file = internal_strdup(filename);
     info->line = lineno;
@@ -67,7 +89,7 @@  static void SymbolizeCodeCallback(void *
     info->Clear();
     info->FillAddressAndModuleInfo(addr, cdata->module_name,
                                    cdata->module_offset);
-    info->function = internal_strdup(symname);
+    info->function = MaybeDemangleAndDup(symname);
     cdata->n_frames = 1;
   }
 }
@@ -76,7 +98,7 @@  static void SymbolizeDataCallback(void *
                                   uintptr_t symval, uintptr_t symsize) {
   DataInfo *info = (DataInfo *)vdata;
   if (symname && symval) {
-    info->name = internal_strdup(symname);
+    info->name = MaybeDemangleAndDup(symname);
     info->start = symval;
     info->size = symsize;
   }