public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] Handle PIEs in libbacktrace
@ 2013-12-06  7:50 Jakub Jelinek
  2013-12-06  8:20 ` Dmitry Vyukov
  2013-12-06 14:36 ` [PATCH] Handle PIEs in libbacktrace Ian Lance Taylor
  0 siblings, 2 replies; 21+ messages in thread
From: Jakub Jelinek @ 2013-12-06  7:50 UTC (permalink / raw)
  To: Ian Lance Taylor, Konstantin Serebryany, Dmitry Vyukov; +Cc: gcc-patches

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

^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2014-01-29  9:38 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-12-06  7:50 [PATCH] Handle PIEs in libbacktrace Jakub Jelinek
2013-12-06  8:20 ` Dmitry Vyukov
2013-12-06  8:25   ` Jakub Jelinek
2013-12-06  8:52     ` Dmitry Vyukov
2013-12-06  8:53       ` Alexey Samsonov
2013-12-06  9:53         ` Jakub Jelinek
2013-12-06 14:41           ` Ian Lance Taylor
2013-12-10 11:38             ` [PATCH] libsanitizer demangling using cp-demangle.c Jakub Jelinek
2014-01-09 11:41               ` Dodji Seketeli
2014-01-09 13:51               ` Konstantin Serebryany
2014-01-09 13:57                 ` Jakub Jelinek
2014-01-10  3:57                   ` Konstantin Serebryany
2014-01-16 13:58                     ` Alexey Samsonov
2014-01-28 14:36               ` -Og bug? (was: [PATCH] libsanitizer demangling using cp-demangle.c) Thomas Schwinge
2014-01-28 14:52                 ` Ian Lance Taylor
2014-01-28 16:11                   ` -Og bug? Thomas Schwinge
2014-01-28 17:12                     ` Ian Lance Taylor
2014-01-28 21:10                       ` Thomas Schwinge
2014-01-28 21:24                         ` Ian Lance Taylor
2014-01-29  9:38                           ` Richard Biener
2013-12-06 14:36 ` [PATCH] Handle PIEs in libbacktrace Ian Lance Taylor

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).