Blob Blame History Raw
From: Gary Benson <gbenson@redhat.com>
To: Jan Kratochvil <jan.kratochvil@redhat.com>
Message-ID: <20110810133605.GB7294@redhat.com>

Index: gdb-7.4.50.20120602/gdb/infrun.c
===================================================================
--- gdb-7.4.50.20120602.orig/gdb/infrun.c	2012-06-02 21:38:07.236442883 +0200
+++ gdb-7.4.50.20120602/gdb/infrun.c	2012-06-02 21:38:13.450440507 +0200
@@ -361,6 +361,13 @@ static struct symbol *step_start_functio
 /* 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)
@@ -7267,7 +7274,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);
 
Index: gdb-7.4.50.20120602/gdb/solib-svr4.c
===================================================================
--- gdb-7.4.50.20120602.orig/gdb/solib-svr4.c	2012-06-02 21:38:07.236442883 +0200
+++ gdb-7.4.50.20120602/gdb/solib-svr4.c	2012-06-02 21:44:23.973298737 +0200
@@ -47,6 +47,8 @@
 #include "auxv.h"
 #include "exceptions.h"
 
+#include "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);
@@ -92,6 +94,32 @@ static const char * const solib_break_na
   NULL
 };
 
+/* A list of SystemTap probes which, if present in the dynamic linker,
+   allow more fine-grained breakpoints to be placed on shared library
+   events.  */
+
+struct probe_info
+  {
+    /* The name of the probe.  */
+    const char *name;
+
+    /* Nonzero if this probe must be stopped at even when
+       stop-on-solib-events is off.  */
+    int mandatory;
+  };
+
+static const struct probe_info probe_info[] =
+{
+  {"rtld_init_start", 0},
+  {"rtld_init_complete", 1},
+  {"rtld_map_start", 0},
+  {"rtld_reloc_complete", 1},
+  {"rtld_unmap_start", 0},
+  {"rtld_unmap_complete", 1},
+};
+
+#define NUM_PROBES (sizeof(probe_info) / sizeof(probe_info[0]))
+
 static const char * const bkpt_names[] =
 {
   "_start",
@@ -313,6 +341,12 @@ struct svr4_info
   CORE_ADDR interp_text_sect_high;
   CORE_ADDR interp_plt_sect_low;
   CORE_ADDR interp_plt_sect_high;
+
+  /* SystemTap probes.  */
+  VEC (probe_p) *probes[NUM_PROBES];
+
+  /* Nonzero if we are using the SystemTap interface.  */
+  int using_probes;
 };
 
 /* Per-program-space data key.  */
@@ -322,8 +356,15 @@ static void
 svr4_pspace_data_cleanup (struct program_space *pspace, void *arg)
 {
   struct svr4_info *info;
+  int i;
 
   info = program_space_data (pspace, solib_svr4_pspace_data);
+  if (info == NULL)
+    return;
+
+  for (i = 0; i < NUM_PROBES; i++)
+    VEC_free (probe_p, info->probes[i]);
+
   xfree (info);
 }
 
@@ -1449,6 +1490,126 @@ exec_entry_point (struct bfd *abfd, stru
 					     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;
+
+  if (b->type != bp_shlib_event)
+    return 0;
+
+  for (loc = b->loc; loc; loc = loc->next)
+    {
+      int i;
+
+      for (i = 0; i < NUM_PROBES; i++)
+	{
+	  if (!probe_info[i].mandatory)
+	    {
+	      struct probe *probe;
+	      int ix;
+
+	      for (ix = 0;
+		   VEC_iterate (probe_p, info->probes[i], ix, probe);
+		   ++ix)
+		{
+		  if (loc->pspace == current_program_space
+		      && loc->address == probe->address)
+		    {
+		      b->enable_state =
+			stop_on_solib_events ? bp_enabled : bp_disabled;
+		      return 0;
+		    }
+		}
+	    }
+	}
+    }
+
+  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->using_probes)
+    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 svr4_info *info = get_svr4_info ();
+  struct obj_section *os;
+
+  os = find_pc_section (address);
+  if (os != NULL)
+    {
+      int all_probes_found = 1;
+      int i;
+
+      for (i = 0; i < NUM_PROBES; i++)
+	{
+	  info->probes[i] = find_probes_in_objfile (os->objfile, "rtld",
+						    probe_info[i].name);
+
+	  if (!VEC_length(probe_p, info->probes[i]))
+	    {
+	      int j;
+
+	      for (j = i - 1; j >= 0; j--)
+		{
+		  VEC_free (probe_p, info->probes[j]);
+		  info->probes[j] = NULL;
+		}
+
+	      all_probes_found = 0;
+	      break;
+	    }
+	}
+
+      if (all_probes_found)
+	{
+	  info->using_probes = 1;
+
+	  for (i = 0; i < NUM_PROBES; i++)
+	    {
+	      struct probe *probe;
+	      int ix;
+
+	      for (ix = 0;
+		   VEC_iterate (probe_p, info->probes[i], ix, probe);
+		   ++ix)
+		create_solib_event_breakpoint (gdbarch, probe->address);
+	    }
+
+	  svr4_update_solib_event_breakpoints ();
+	  return;
+	}
+    }
+
+  create_solib_event_breakpoint (gdbarch, address);
+}
+
 /* Helper function for gdb_bfd_lookup_symbol.  */
 
 static int
@@ -1497,10 +1658,18 @@ enable_break (struct svr4_info *info, in
   asection *interp_sect;
   gdb_byte *interp_name;
   CORE_ADDR sym_addr;
+  int i;
 
   info->interp_text_sect_low = info->interp_text_sect_high = 0;
   info->interp_plt_sect_low = info->interp_plt_sect_high = 0;
 
+  for (i = 0; i < NUM_PROBES; i++)
+    {
+      VEC_free (probe_p, info->probes[i]);
+      info->probes[i] = NULL;
+    }
+  info->using_probes = 0;
+
   /* 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
@@ -1532,7 +1701,7 @@ enable_break (struct svr4_info *info, in
 	 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
@@ -1570,7 +1739,7 @@ enable_break (struct svr4_info *info, in
 		+ 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;
 	}
     }
@@ -1725,7 +1894,8 @@ enable_break (struct svr4_info *info, in
 
       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;
 	}
@@ -1751,7 +1921,7 @@ enable_break (struct svr4_info *info, in
 	  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;
 	}
     }
@@ -1767,7 +1937,7 @@ enable_break (struct svr4_info *info, in
 	      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;
 	    }
 	}
@@ -2543,4 +2713,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;
 }
Index: gdb-7.4.50.20120602/gdb/solib.c
===================================================================
--- gdb-7.4.50.20120602.orig/gdb/solib.c	2012-06-02 21:38:07.236442883 +0200
+++ gdb-7.4.50.20120602/gdb/solib.c	2012-06-02 21:38:13.455440507 +0200
@@ -1216,6 +1216,18 @@ no_shared_libraries (char *ignored, int
   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.  */
 
Index: gdb-7.4.50.20120602/gdb/solib.h
===================================================================
--- gdb-7.4.50.20120602.orig/gdb/solib.h	2012-06-02 21:38:07.236442883 +0200
+++ gdb-7.4.50.20120602/gdb/solib.h	2012-06-02 21:38:13.464440503 +0200
@@ -91,4 +91,8 @@ extern CORE_ADDR gdb_bfd_lookup_symbol_f
 								      void *),
 						    void *data);
 
+/* Enable or disable optional solib event breakpoints as appropriate.  */
+
+extern void update_solib_breakpoints (void);
+
 #endif /* SOLIB_H */
Index: gdb-7.4.50.20120602/gdb/solist.h
===================================================================
--- gdb-7.4.50.20120602.orig/gdb/solist.h	2012-06-02 21:38:07.236442883 +0200
+++ gdb-7.4.50.20120602/gdb/solist.h	2012-06-02 21:38:13.465440503 +0200
@@ -149,6 +149,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 *).  */