This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Handle PIEs in libbacktrace


Hi!

With the new tsan tests, I've noticed that libbacktrace symbolization
doesn't work when the binary is a PIE.
The problem is that in that case we obviously can't use base_address
of 0, the PIE typically will not have 0 bias, that is actually the sole
point of PIEs that their base address is randomized.  So, in that case
we need to wait until dl_iterate_phdr to determine the proper bias.
The executable is always the first in the search scope and/or list of
loaded modules, so we just check if the first callback gives us a dlpi_name
== NULL entry and assume it is the PIE.

Regtested on x86_64-linux, ok for trunk?

The rest of this mail except the libbacktrace patch is for the sanitizer
folks.

With this patch check-gcc tsan.exp passes fully again, but check-g++ does
not, there seems to be important differences between tsan symbolization
and say asan symbolization.  First of all, if symbolizer fails (as without
this patch for tsan because the executables are PIEs), we get something
like:
WARNING: ThreadSanitizer: data race (pid=18998)
  Write of size 4 at 0x7f4a88f0a08c by thread T1:
    #0 <null> <null>:0 (tiny_race+0x000000000b19)

  Previous write of size 4 at 0x7f4a88f0a08c by main thread:
    #0 <null> <null>:0 (tiny_race+0x000000000b7a)
    #1 __libc_start_main <null>:0 (libc.so.6+0x003c08c21b74)

  As if synchronized via sleep:
    #0 sleep ../../../../libsanitizer/tsan/tsan_interceptors.cc:239 (libtsan.so.0+0x000000048c65)
    #1 <null> <null>:0 (tiny_race+0x000000000b0a)

  Location is global '<null>' of size 0 at 0x000000000000 (tiny_race+0x00000020208c)

  Thread T1 (tid=19000, running) created by main thread at:
    #0 pthread_create ../../../../libsanitizer/tsan/tsan_interceptors.cc:877 (libtsan.so.0+0x0000000461b3)
    #1 <null> <null>:0 (tiny_race+0x000000000b6b)
    #2 __libc_start_main <null>:0 (libc.so.6+0x003c08c21b74)

The <null> <null>:0 or <null>:0 look very ugly, e.g. asan
I think just prints the exe/dso name + offset in that case.

And the reason why check-g++ tsan.exp fails even with this patch is
that apparently tsan doesn't try to demangle the symbol names, so we get
e.g.:
FAIL: c-c++-common/tsan/atomic_stack.c  -O0  output pattern test, is ==================
WARNING: ThreadSanitizer: data race (pid=22075)
  Atomic write of size 4 at 0x7fe8c9b630ac by thread T1:
    #0 __tsan_atomic32_fetch_add ../../../../libsanitizer/tsan/tsan_interface_atomic.cc:468 (libtsan.so.0+0x00000001ec7e)
    #1 _Z7Thread1Pv /usr/src/gcc/gcc/testsuite/c-c++-common/tsan/atomic_stack.c:11 (atomic_stack.exe+0x000000000d90)

  Previous write of size 4 at 0x7fe8c9b630ac by thread T2:
    #0 _Z7Thread2Pv /usr/src/gcc/gcc/testsuite/c-c++-common/tsan/atomic_stack.c:16 (atomic_stack.exe+0x000000000dde)

  As if synchronized via sleep:
    #0 sleep ../../../../libsanitizer/tsan/tsan_interceptors.cc:239 (libtsan.so.0+0x000000048c65)
    #1 _Z7Thread1Pv /usr/src/gcc/gcc/testsuite/c-c++-common/tsan/atomic_stack.c:10 (atomic_stack.exe+0x000000000d7a)

  Location is global 'Global' of size 4 at 0x7fe8c9b630ac (atomic_stack.exe+0x0000002020ac)

  Thread T1 (tid=22080, running) created by main thread at:
    #0 pthread_create ../../../../libsanitizer/tsan/tsan_interceptors.cc:877 (libtsan.so.0+0x0000000461b3)
    #1 main /usr/src/gcc/gcc/testsuite/c-c++-common/tsan/atomic_stack.c:22 (atomic_stack.exe+0x000000000e2a)

  Thread T2 (tid=22081, finished) created by main thread at:
    #0 pthread_create ../../../../libsanitizer/tsan/tsan_interceptors.cc:877 (libtsan.so.0+0x0000000461b3)
    #1 main /usr/src/gcc/gcc/testsuite/c-c++-common/tsan/atomic_stack.c:23 (atomic_stack.exe+0x000000000e4b)

Is the non-demangling intentional?  If yes, I guess we'd need to adjust
the testcases to cope with both mangled and non-mangled names, otherwise
please change tsan to demangle, the symbolizer has functions for it.

2013-12-06  Jakub Jelinek  <jakub@redhat.com>

	* elf.c (ET_DYN): Undefine and define again.
	(elf_add): Add exe argument, if true and ehdr.e_type is ET_DYN,
	return early -1 without closing the descriptor.
	(struct phdr_data): Add exe_descriptor.
	(phdr_callback): If pd->exe_descriptor is not -1, for very first
	call if dlpi_name is NULL just call elf_add with the exe_descriptor,
	otherwise backtrace_close the exe_descriptor if not -1.  Adjust
	call to elf_add.
	(backtrace_initialize): Adjust call to elf_add.  If it returns
	-1, set pd.exe_descriptor to descriptor, otherwise set it to -1.

--- libbacktrace/elf.c.jj	2013-11-19 08:47:37.000000000 +0100
+++ libbacktrace/elf.c	2013-12-06 08:26:53.273602062 +0100
@@ -96,6 +96,7 @@ dl_iterate_phdr (int (*callback) (struct
 #undef ELFDATA2LSB
 #undef ELFDATA2MSB
 #undef EV_CURRENT
+#undef ET_DYN
 #undef SHN_LORESERVE
 #undef SHN_XINDEX
 #undef SHN_UNDEF
@@ -171,6 +172,8 @@ typedef struct {
 
 #define EV_CURRENT 1
 
+#define ET_DYN 3
+
 typedef struct {
   b_elf_word	sh_name;		/* Section name, index in string tbl */
   b_elf_word	sh_type;		/* Type of section */
@@ -512,7 +515,7 @@ elf_syminfo (struct backtrace_state *sta
 static int
 elf_add (struct backtrace_state *state, int descriptor, uintptr_t base_address,
 	 backtrace_error_callback error_callback, void *data,
-	 fileline *fileline_fn, int *found_sym, int *found_dwarf)
+	 fileline *fileline_fn, int *found_sym, int *found_dwarf, int exe)
 {
   struct backtrace_view ehdr_view;
   b_elf_ehdr ehdr;
@@ -591,6 +594,12 @@ elf_add (struct backtrace_state *state,
       goto fail;
     }
 
+  /* If the executable is ET_DYN, it is either a PIE, or we are running
+     directly a shared library with .interp.  We need to wait for
+     dl_iterate_phdr in that case to determine the actual base_address.  */
+  if (exe && ehdr.e_type == ET_DYN)
+    return -1;
+
   shoff = ehdr.e_shoff;
   shnum = ehdr.e_shnum;
   shstrndx = ehdr.e_shstrndx;
@@ -847,6 +856,7 @@ struct phdr_data
   fileline *fileline_fn;
   int *found_sym;
   int *found_dwarf;
+  int exe_descriptor;
 };
 
 /* Callback passed to dl_iterate_phdr.  Load debug info from shared
@@ -862,17 +872,32 @@ phdr_callback (struct dl_phdr_info *info
   fileline elf_fileline_fn;
   int found_dwarf;
 
-  /* There is not much we can do if we don't have the module name.  */
+  /* There is not much we can do if we don't have the module name,
+     unless executable is ET_DYN, where we expect the very first
+     phdr_callback to be for the PIE.  */
   if (info->dlpi_name == NULL || info->dlpi_name[0] == '\0')
-    return 0;
+    {
+      if (pd->exe_descriptor == -1)
+	return 0;
+      descriptor = pd->exe_descriptor;
+      pd->exe_descriptor = -1;
+    }
+  else
+    {
+      if (pd->exe_descriptor != -1)
+	{
+	  backtrace_close (pd->exe_descriptor, pd->error_callback, pd->data);
+	  pd->exe_descriptor = -1;
+	}
 
-  descriptor = backtrace_open (info->dlpi_name, pd->error_callback, pd->data,
-			       &does_not_exist);
-  if (descriptor < 0)
-    return 0;
+      descriptor = backtrace_open (info->dlpi_name, pd->error_callback,
+				   pd->data, &does_not_exist);
+      if (descriptor < 0)
+	return 0;
+    }
 
   if (elf_add (pd->state, descriptor, info->dlpi_addr, pd->error_callback,
-	       pd->data, &elf_fileline_fn, pd->found_sym, &found_dwarf))
+	       pd->data, &elf_fileline_fn, pd->found_sym, &found_dwarf, 0))
     {
       if (found_dwarf)
 	{
@@ -893,13 +918,15 @@ backtrace_initialize (struct backtrace_s
 		      backtrace_error_callback error_callback,
 		      void *data, fileline *fileline_fn)
 {
+  int ret;
   int found_sym;
   int found_dwarf;
   fileline elf_fileline_fn;
   struct phdr_data pd;
 
-  if (!elf_add (state, descriptor, 0, error_callback, data, &elf_fileline_fn,
-		&found_sym, &found_dwarf))
+  ret = elf_add (state, descriptor, 0, error_callback, data, &elf_fileline_fn,
+		 &found_sym, &found_dwarf, 1);
+  if (!ret)
     return 0;
 
   pd.state = state;
@@ -908,6 +935,7 @@ backtrace_initialize (struct backtrace_s
   pd.fileline_fn = &elf_fileline_fn;
   pd.found_sym = &found_sym;
   pd.found_dwarf = &found_dwarf;
+  pd.exe_descriptor = ret < 0 ? descriptor : -1;
 
   dl_iterate_phdr (phdr_callback, (void *) &pd);
 

	Jakub


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]