public inbox for archer@sourceware.org
 help / color / mirror / Atom feed
* gdb side of improved linker-debugger interface
@ 2011-06-07  9:48 Gary Benson
  2011-06-07 16:29 ` Tom Tromey
  2011-06-07 17:20 ` Jan Kratochvil
  0 siblings, 2 replies; 10+ messages in thread
From: Gary Benson @ 2011-06-07  9:48 UTC (permalink / raw)
  To: archer

[-- Attachment #1: Type: text/plain, Size: 2235 bytes --]

Hi all,

A week or so ago I mailed this list a description of a new linker-
debugger interface based on SystemTap probes, along with a patch
containing the glibc side:

  http://www.cygwin.com/ml/archer/2011-q2/msg00000.html

In the meantime I've been working on the gdb side of this, which is
available in the archer-gbenson-stap-rtld branch.  I've also attached
a patch (which applies to archer-sergiodj-stap-patch-split) in case
you just want to have a look.

The deal is basically that gdb would normally set one solib event
breakpoint, on _dl_debug_state.  This patch makes it look for the two
SystemTap probes described in my previous mail, and if it finds them,
set a pair of breakpoints on those instead.  When stop-on-solib-events
is set, gdb will stop on both breakpoints, mimicing the old behaviour.
When stop-on-solib-events is not set, gdb will only stop on the post-
modification breakpoint.  This allows solib mapping and unmapping to
be tracked as before while almost halving the time taken (I did some
basic tests, eg loading 1000 simple libraries took 14s as opposed to
26s).  This helps https://bugzilla.redhat.com/show_bug.cgi?id=698001.
The post-modification breakpoint is called later than previously, to
match where Solaris libc calls _dl_debug_state, which addresses
https://bugzilla.redhat.com/show_bug.cgi?id=658851.

I've not implemented anything to do with dlmopen, but the information
required for gdb to discover the libraries' namespaces can be obtained
from the SystemTap probes.  I've also not done anything special about
STT_GNU_IFUNC functions, since if one of these is causing problems you
could simply set gdb to break on its relocator without needing any
special support in stop-on-solib-events.

I've seen mention that the RT_CONSISTENT called too early bug was the
cause of another issue where libthread_db would not be loaded if
libpthread was loaded with dlopen rather than being linked in, but I
haven't been able to discover if this really was ever the case.  If
anybody knows (or has a testcase) could you fill me in on it please.

I'm still waiting for a reply to my mail about in-process debuggers,
so I haven't changed anything on that regard yet.

Cheers,
Gary

-- 
http://gbenson.net/

[-- Attachment #2: patch --]
[-- Type: text/plain, Size: 9753 bytes --]

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 6a130b6..2490967 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,18 @@
+2011-06-06  Gary Benson  <gbenson@redhat.com>
+
+	* infrun.c (set_stop_on_solib_events): New function.
+	(_initialize_infrun): Call the above when stop_on_solib_events is set.
+	* solib.h (update_solib_breakpoints): New method declaration.
+	* solib.c (update_solib_breakpoints): New method.
+	* solist.h (target_so_ops): New field update_breakpoints.
+	* solib-svr4.c (svr4_info): New fields pre_mod_probe and post_mod_probe.
+	(svr4_update_solib_event_breakpoint): New function.
+	(svr4_update_solib_event_breakpoints): Likewise.
+	(svr4_create_solib_event_breakpoints): Likewise.
+	(enable_break): Use svr4_create_solib_event_breakpoints instead of
+	create_solib_event_breakpoint to create solib event breakpoints.
+	(_initialize_svr4_solib): Initialize svr4_so_ops.update_breakpoints.
+
 2011-05-09  Doug Evans  <dje@google.com>
 
 	* NEWS: Mention --with-iconv-bin.
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 4f1fbd9..425a7b0 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -324,6 +324,13 @@ static struct symbol *step_start_function;
 /* Nonzero if we want to give control to the user when we're notified
    of shared library events by the dynamic linker.  */
 int stop_on_solib_events;
+
+static void
+set_stop_on_solib_events (char *args, int from_tty, struct cmd_list_element *c)
+{
+  update_solib_breakpoints ();
+} 
+
 static void
 show_stop_on_solib_events (struct ui_file *file, int from_tty,
 			   struct cmd_list_element *c, const char *value)
@@ -7122,7 +7129,7 @@ Show stopping for shared library events."), _("\
 If nonzero, gdb will give control to the user when the dynamic linker\n\
 notifies gdb of shared library events.  The most common event of interest\n\
 to the user would be loading/unloading of a new library."),
-			    NULL,
+			    set_stop_on_solib_events,
 			    show_stop_on_solib_events,
 			    &setlist, &showlist);
 
diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c
index bcb94e7..41b3344 100644
--- a/gdb/solib-svr4.c
+++ b/gdb/solib-svr4.c
@@ -48,6 +48,8 @@
 #include "auxv.h"
 #include "exceptions.h"
 
+#include "stap-probe.h"
+
 static struct link_map_offsets *svr4_fetch_link_map_offsets (void);
 static int svr4_have_link_map_offsets (void);
 static void svr4_relocate_main_executable (void);
@@ -335,6 +337,10 @@ struct svr4_info
   CORE_ADDR interp_text_sect_high;
   CORE_ADDR interp_plt_sect_low;
   CORE_ADDR interp_plt_sect_high;
+
+  /* SystemTap probes.  */
+  const struct stap_probe *pre_mod_probe;
+  const struct stap_probe *post_mod_probe;
 };
 
 /* Per-program-space data key.  */
@@ -1310,6 +1316,91 @@ exec_entry_point (struct bfd *abfd, struct target_ops *targ)
 					     targ);
 }
 
+/* Helper function for svr4_update_solib_event_breakpoints.  */
+
+static int
+svr4_update_solib_event_breakpoint (struct breakpoint *b, void *arg)
+{
+  struct svr4_info *info = get_svr4_info ();
+  struct bp_location *loc;
+
+  for (loc = b->loc; loc; loc = loc->next)
+    {
+      if (loc->pspace == current_program_space
+	  && loc->address == info->pre_mod_probe->address)
+	{
+	  b->enable_state = stop_on_solib_events;
+	  return 1;
+	}
+    }
+
+  return 0;
+}
+
+/* Enable or disable optional solib event breakpoints as appropriate.
+   Called whenever stop_on_solib_events is changed.  */
+
+static void
+svr4_update_solib_event_breakpoints (void)
+{
+  struct svr4_info *info = get_svr4_info ();
+
+  if (info->pre_mod_probe)
+    iterate_over_breakpoints (svr4_update_solib_event_breakpoint, NULL);
+}
+
+/* Both the SunOS and the SVR4 dynamic linkers call a marker function
+   before and after mapping and unmapping shared libraries.  The sole
+   purpose of this method is to allow debuggers to set a breakpoint so
+   they can track these changes.
+
+   Some versions of the glibc dynamic linker contain SystemTap probes
+   to allow more fine grained stopping.  Given the address of the
+   original marker function, this function attempts to find these
+   probes, and if found, sets breakpoints on those instead.  If the
+   probes aren't found, a single breakpoint is set on the original
+   SVR4 marker function.  */
+
+static void
+svr4_create_solib_event_breakpoints (struct gdbarch *gdbarch, CORE_ADDR address)
+{
+  struct obj_section *os;
+
+  os = find_pc_section (address);
+  if (os != NULL)
+    {
+      struct svr4_info *info = get_svr4_info ();
+
+      info->pre_mod_probe = find_probe_in_objfile (os->objfile, "rtld",
+						   "r_debug_mod_starting");
+
+      info->post_mod_probe = find_probe_in_objfile (os->objfile, "rtld",
+						    "r_debug_mod_complete");
+
+      if (info->pre_mod_probe && info->post_mod_probe)
+	{
+	  /* The pre-modification probe is triggered before a link map
+	     is changed.  This probe isn't used internally, so we only
+	     break on it when stop-on-solib-events is on.  */
+	  create_solib_event_breakpoint (gdbarch,
+					 info->pre_mod_probe->address);
+
+	  /* The post-modification probe is triggered whenever a link
+	     map has been changed.  We always need to break on this
+	     one so we can track libraries being loaded and
+	     unloaded.  */
+	  create_solib_event_breakpoint (gdbarch,
+					 info->post_mod_probe->address);
+	  
+	  
+	  svr4_update_solib_event_breakpoints ();
+	  return;
+	}
+    }
+
+  create_solib_event_breakpoint (gdbarch, address);
+}
+
 /*
 
    LOCAL FUNCTION
@@ -1365,6 +1456,8 @@ enable_break (struct svr4_info *info, int from_tty)
   info->interp_text_sect_low = info->interp_text_sect_high = 0;
   info->interp_plt_sect_low = info->interp_plt_sect_high = 0;
 
+  info->pre_mod_probe = info->post_mod_probe = NULL;
+
   /* If we already have a shared library list in the target, and
      r_debug contains r_brk, set the breakpoint there - this should
      mean r_brk has already been relocated.  Assume the dynamic linker
@@ -1396,7 +1489,7 @@ enable_break (struct svr4_info *info, int from_tty)
 	 That knowledge is encoded in the address, if it's Thumb the low bit
 	 is 1.  However, we've stripped that info above and it's not clear
 	 what all the consequences are of passing a non-addr_bits_remove'd
-	 address to create_solib_event_breakpoint.  The call to
+	 address to svr4_create_solib_event_breakpoints.  The call to
 	 find_pc_section verifies we know about the address and have some
 	 hope of computing the right kind of breakpoint to use (via
 	 symbol info).  It does mean that GDB needs to be pointed at a
@@ -1434,7 +1527,7 @@ enable_break (struct svr4_info *info, int from_tty)
 		+ bfd_section_size (tmp_bfd, interp_sect);
 	    }
 
-	  create_solib_event_breakpoint (target_gdbarch, sym_addr);
+	  svr4_create_solib_event_breakpoints (target_gdbarch, sym_addr);
 	  return 1;
 	}
     }
@@ -1588,7 +1681,8 @@ enable_break (struct svr4_info *info, int from_tty)
 
       if (sym_addr != 0)
 	{
-	  create_solib_event_breakpoint (target_gdbarch, load_addr + sym_addr);
+	  svr4_create_solib_event_breakpoints (target_gdbarch,
+					       load_addr + sym_addr);
 	  xfree (interp_name);
 	  return 1;
 	}
@@ -1614,7 +1708,7 @@ enable_break (struct svr4_info *info, int from_tty)
 	  sym_addr = gdbarch_convert_from_func_ptr_addr (target_gdbarch,
 							 sym_addr,
 							 &current_target);
-	  create_solib_event_breakpoint (target_gdbarch, sym_addr);
+	  svr4_create_solib_event_breakpoints (target_gdbarch, sym_addr);
 	  return 1;
 	}
     }
@@ -1630,7 +1724,7 @@ enable_break (struct svr4_info *info, int from_tty)
 	      sym_addr = gdbarch_convert_from_func_ptr_addr (target_gdbarch,
 							     sym_addr,
 							     &current_target);
-	      create_solib_event_breakpoint (target_gdbarch, sym_addr);
+	      svr4_create_solib_event_breakpoints (target_gdbarch, sym_addr);
 	      return 1;
 	    }
 	}
@@ -2454,4 +2548,5 @@ _initialize_svr4_solib (void)
   svr4_so_ops.lookup_lib_global_symbol = elf_lookup_lib_symbol;
   svr4_so_ops.same = svr4_same;
   svr4_so_ops.keep_data_in_core = svr4_keep_data_in_core;
+  svr4_so_ops.update_breakpoints = svr4_update_solib_event_breakpoints;
 }
diff --git a/gdb/solib.c b/gdb/solib.c
index a9f46e0..129724d 100644
--- a/gdb/solib.c
+++ b/gdb/solib.c
@@ -1309,6 +1309,18 @@ no_shared_libraries (char *ignored, int from_tty)
   objfile_purge_solibs ();
 }
 
+/* Enable or disable optional solib event breakpoints as appropriate.  */
+
+void
+update_solib_breakpoints (void)
+{
+  struct target_so_ops *ops = solib_ops (target_gdbarch);
+
+  if (ops->update_breakpoints != NULL)
+    ops->update_breakpoints ();
+}
+  
+
 /* Reload shared libraries, but avoid reloading the same symbol file
    we already have loaded.  */
 
diff --git a/gdb/solib.h b/gdb/solib.h
index c473d85..7b3881c 100644
--- a/gdb/solib.h
+++ b/gdb/solib.h
@@ -78,4 +78,8 @@ extern void set_solib_ops (struct gdbarch *gdbarch,
 
 extern int libpthread_name_p (const char *name);
 
+/* Enable or disable optional solib event breakpoints as appropriate.  */
+
+extern void update_solib_breakpoints (void);
+
 #endif /* SOLIB_H */
diff --git a/gdb/solist.h b/gdb/solist.h
index dad11be..14ede10 100644
--- a/gdb/solist.h
+++ b/gdb/solist.h
@@ -137,6 +137,13 @@ struct target_so_ops
        core file (in particular, for readonly sections).  */
     int (*keep_data_in_core) (CORE_ADDR vaddr,
 			      unsigned long size);
+
+    /* Enable or disable optional solib event breakpoints as
+       appropriate.  This should be called whenever
+       stop_on_solib_events is changed.  This pointer can be
+       NULL, in which case no enabling or disabling is necessary
+       for this target.  */
+    void (*update_breakpoints) (void);
   };
 
 /* Free the memory associated with a (so_list *).  */

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

end of thread, other threads:[~2011-06-09 14:43 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-06-07  9:48 gdb side of improved linker-debugger interface Gary Benson
2011-06-07 16:29 ` Tom Tromey
2011-06-09 14:26   ` Gary Benson
2011-06-08 16:27     ` Tom Tromey
2011-06-09 14:09       ` Gary Benson
2011-06-09 14:43         ` Tom Tromey
2011-06-07 17:20 ` Jan Kratochvil
2011-06-08 11:01   ` Gary Benson
2011-06-08 11:48     ` Jan Kratochvil
2011-06-08 12:29       ` Gary Benson

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).