This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB 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]

[4/4] RFC: implement catch load and catch unload


This patch actually implements catch load and catch unload.  It also
changes 'set stop-on-solib-events' to print information about what
libraries were loaded or unloaded.

This patch has a few oddities.  I would appreciate comment on them.

* If you have a catchpoint and also set stop-on-solib-events, the latter
  will always take precedence.  This is unfortunate but I think it is an
  artifact of the bp_shlib_event breakpoint coming first in the
  breakpoint list.

  I don't think this is a very big deal.  I'd like to consider
  stop-on-solib-events as being essentially deprecated by the new
  commands.

* There is a change in bpstat_stop_status that is somewhat hacky.  We
  have to do a pass here to handle an solib event, because we need to
  load libraries at a point (1) after the catchpoint's breakpoint_hit
  method is invoked, but (2) before the catchpoint's check_status method
  is invoked.  This is needed so that we can properly collect the names
  of added and removed solibs.

* There is a change in internal_bkpt_check_status that is somewhat
  hacky.  This was the simplest way I could find to make it so that
  "catch load" reported the catchpoint; without this, bpstat_print would
  find the internal bp_shlib_event bpstat and print it instead, even if
  stop-on-solib-events was not set.

Oh, I just remembered something else -- I have yet to test this on a
TARGET_WAITKIND_LOADED target.  I will do that and ensure there are no
regressions before checking it in.

Tom

>From 8343621246f42269a485e0f53277ea0b41a398ab Mon Sep 17 00:00:00 2001
From: Tom Tromey <tromey@redhat.com>
Date: Thu, 19 Jan 2012 12:20:36 -0700
Subject: [PATCH 4/4] the patch

gdb
	PR symtab/12406:
	* solib.c (update_solib_list): Update the program space's
	added_solibs and deleted_solibs fields.
	* progspace.h (struct program_space) <added_solibs,
	deleted_solibs>: New fields.
	(clear_program_space_solib_cache): Declare.
	* progspace.c (release_program_space): Call
	clear_program_space_solib_cache.
	(clear_program_space_solib_cache): New function.
	* infrun.c (handle_inferior_event) <TARGET_WAITKIND_LOADED>: Call
	bpstat_stop_status.  Use handle_solib_event.
	* breakpoint.c: Include gdb_regex.h.
	(print_solib_event): New function.
	(bpstat_print): Use print_solib_event.
	(bpstat_stop_status): Add special case for bp_shlib_event.
	(handle_solib_event): New function.
	(bpstat_what): Use handle_solib_event.
	(struct solib_catchpoint): New.
	(dtor_catch_solib, insert_catch_solib, remove_catch_solib)
	(breakpoint_hit_catch_solib, check_status_catch_solib)
	(print_it_catch_solib, print_one_catch_solib)
	(print_mention_catch_solib, print_recreate_catch_solib): New
	functions.
	(catch_solib_breakpoint_ops): New global.
	(catch_load_or_unload, catch_load_command_1)
	(catch_unload_command_1): New functions.
	(internal_bkpt_check_status): Add special case for
	bp_shlib_event.
	(internal_bkpt_print_it): Use print_solib_event.
	(initialize_breakpoint_ops): Initialize
	catch_solib_breakpoint_ops.
	(_initialize_breakpoint): Register "catch load" and "catch
	unload".
	* breakpoint.h (handle_solib_event): Declare.
	* NEWS: Add entry for "catch load" and "catch unload".
gdb/doc
	* gdb.texinfo (Set Catchpoints): Document "catch load" and "catch
	unload".
	(Files): Mention new catch commands.
	(GDB/MI Async Records): Likewise.
gdb/testsuite
	* lib/mi-support.exp (mi_expect_stop): Add special case for
	solib-event.
	* gdb.base/catch-load-so.c: New file.
	* gdb.base/catch-load.exp: New file.
	* gdb.base/catch-load.c: New file.
	* gdb.base/break-interp.exp (reach_1): Update regexp.
---
 gdb/NEWS                                |    5 +
 gdb/breakpoint.c                        |  426 ++++++++++++++++++++++++++++--
 gdb/breakpoint.h                        |    2 +
 gdb/doc/gdb.texinfo                     |   21 ++-
 gdb/infrun.c                            |   41 ++--
 gdb/progspace.c                         |   17 ++
 gdb/progspace.h                         |   17 ++
 gdb/solib.c                             |    4 +
 gdb/testsuite/gdb.base/break-interp.exp |    2 +-
 gdb/testsuite/gdb.base/catch-load-so.c  |   22 ++
 gdb/testsuite/gdb.base/catch-load.c     |   35 +++
 gdb/testsuite/gdb.base/catch-load.exp   |  120 +++++++++
 gdb/testsuite/lib/mi-support.exp        |    2 +
 13 files changed, 660 insertions(+), 54 deletions(-)
 create mode 100644 gdb/testsuite/gdb.base/catch-load-so.c
 create mode 100644 gdb/testsuite/gdb.base/catch-load.c
 create mode 100644 gdb/testsuite/gdb.base/catch-load.exp

diff --git a/gdb/NEWS b/gdb/NEWS
index eaf0b9d..6d8f8f7 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -28,6 +28,11 @@
   now set a breakpoint in build/gcc/expr.c, but not
   build/libcpp/expr.c.
 
+* New commands
+
+  ** "catch load" and "catch unload" can be used to stop when a shared
+     library is loaded or unloaded, respectively.
+
 *** Changes in GDB 7.4
 
 * GDB now handles ambiguous linespecs more consistently; the existing
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 1b43b43..f2710ee 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -65,6 +65,7 @@
 #include "stack.h"
 #include "skip.h"
 #include "record.h"
+#include "gdb_regex.h"
 
 /* readline include files */
 #include "readline/readline.h"
@@ -259,6 +260,11 @@ static int is_masked_watchpoint (const struct breakpoint *b);
 
 static int strace_marker_p (struct breakpoint *b);
 
+static void init_catchpoint (struct breakpoint *b,
+			     struct gdbarch *gdbarch, int tempflag,
+			     char *cond_string,
+			     const struct breakpoint_ops *ops);
+
 /* The abstract base class all breakpoint_ops structures inherit
    from.  */
 static struct breakpoint_ops base_breakpoint_ops;
@@ -3489,6 +3495,82 @@ print_bp_stop_message (bpstat bs)
     }
 }
 
+/* A helper function that prints a shared library stopped event.  */
+
+static void
+print_solib_event (int is_catchpoint)
+{
+  int any_deleted
+    = !VEC_empty (char_ptr, current_program_space->deleted_solibs);
+  int any_added
+    = !VEC_empty (so_list_ptr, current_program_space->added_solibs);
+
+  if (!is_catchpoint)
+    {
+      if (any_added || any_deleted)
+	ui_out_text (current_uiout,
+		     _("Stopped due to shared library event:\n"));
+      else
+	ui_out_text (current_uiout,
+		     _("Stopped due to spurious shared library event (no "
+		       "libraries added or removed)\n"));
+    }
+
+  if (ui_out_is_mi_like_p (current_uiout))
+    {
+      ui_out_field_string (current_uiout, "reason",
+			   async_reason_lookup (EXEC_ASYNC_SOLIB_EVENT));
+      if (!any_added && !any_deleted)
+	ui_out_field_int (current_uiout, "spurious", 1);
+    }
+
+  if (any_deleted)
+    {
+      struct cleanup *cleanup;
+      char *name;
+      int ix;
+
+      ui_out_text (current_uiout, _("  Inferior unloaded "));
+      cleanup = make_cleanup_ui_out_list_begin_end (current_uiout,
+						    "removed");
+      for (ix = 0;
+	   VEC_iterate (char_ptr, current_program_space->deleted_solibs,
+			ix, name);
+	   ++ix)
+	{
+	  if (ix > 0)
+	    ui_out_text (current_uiout, "    ");
+	  ui_out_field_string (current_uiout, "library", name);
+	  ui_out_text (current_uiout, "\n");
+	}
+
+      do_cleanups (cleanup);
+    }
+
+  if (any_added)
+    {
+      struct so_list *iter;
+      int ix;
+      struct cleanup *cleanup;
+
+      ui_out_text (current_uiout, _("  Inferior loaded "));
+      cleanup = make_cleanup_ui_out_list_begin_end (current_uiout,
+						    "added");
+      for (ix = 0;
+	   VEC_iterate (so_list_ptr, current_program_space->added_solibs,
+			ix, iter);
+	   ++ix)
+	{
+	  if (ix > 0)
+	    ui_out_text (current_uiout, "    ");
+	  ui_out_field_string (current_uiout, "library", iter->so_name);
+	  ui_out_text (current_uiout, "\n");
+	}
+
+      do_cleanups (cleanup);
+    }
+}
+
 /* Print a message indicating what happened.  This is called from
    normal_stop().  The input to this routine is the head of the bpstat
    list - a list of the eventpoints that caused this stop.  KIND is
@@ -3533,10 +3615,7 @@ bpstat_print (bpstat bs, int kind)
      OS-level shared library event, do the same thing.  */
   if (kind == TARGET_WAITKIND_LOADED)
     {
-      ui_out_text (current_uiout, _("Stopped due to shared library event\n"));
-      if (ui_out_is_mi_like_p (current_uiout))
-	ui_out_field_string (current_uiout, "reason",
-			     async_reason_lookup (EXEC_ASYNC_SOLIB_EVENT));
+      print_solib_event (0);
       return PRINT_NOTHING;
     }
 
@@ -4221,6 +4300,19 @@ bpstat_stop_status (struct address_space *aspace,
 	}
     }
 
+  /* A bit of special processing for shlib breakpoints.  We need to
+     process solib loading here, so that the lists of loaded and
+     unloaded libraries are correct before we handle "catch load" and
+     "catch unload".  */
+  for (bs = bs_head; bs != NULL; bs = bs->next)
+    {
+      if (bs->breakpoint_at->type == bp_shlib_event)
+	{
+	  handle_solib_event ();
+	  break;
+	}
+    }
+
   /* Now go through the locations that caused the target to stop, and
      check whether we're interested in reporting this stop to higher
      layers, or whether we should resume the target transparently.  */
@@ -4308,6 +4400,25 @@ handle_jit_event (void)
   target_terminal_inferior ();
 }
 
+/* Handle an solib event by calling solib_add.  */
+
+void
+handle_solib_event (void)
+{
+  clear_program_space_solib_cache (current_inferior ()->pspace);
+
+  /* Check for any newly added shared libraries if we're supposed to
+     be adding them automatically.  Switch terminal for any messages
+     produced by breakpoint_re_set.  */
+  target_terminal_ours_for_output ();
+#ifdef SOLIB_ADD
+  SOLIB_ADD (NULL, 0, &current_target, auto_solib_add);
+#else
+  solib_add (NULL, 0, &current_target, auto_solib_add);
+#endif
+  target_terminal_inferior ();
+}
+
 /* Prepare WHAT final decision for infrun.  */
 
 /* Decide what infrun needs to do with this bpstat.  */
@@ -4485,27 +4596,6 @@ bpstat_what (bpstat bs_head)
   /* These operations may affect the bs->breakpoint_at state so they are
      delayed after MAIN_ACTION is decided above.  */
 
-  if (shlib_event)
-    {
-      if (debug_infrun)
-	fprintf_unfiltered (gdb_stdlog, "bpstat_what: bp_shlib_event\n");
-
-      /* Check for any newly added shared libraries if we're supposed
-	 to be adding them automatically.  */
-
-      /* Switch terminal for any messages produced by
-	 breakpoint_re_set.  */
-      target_terminal_ours_for_output ();
-
-#ifdef SOLIB_ADD
-      SOLIB_ADD (NULL, 0, &current_target, auto_solib_add);
-#else
-      solib_add (NULL, 0, &current_target, auto_solib_add);
-#endif
-
-      target_terminal_inferior ();
-    }
-
   if (jit_event)
     {
       if (debug_infrun)
@@ -6436,6 +6526,257 @@ print_recreate_catch_vfork (struct breakpoint *b, struct ui_file *fp)
 
 static struct breakpoint_ops catch_vfork_breakpoint_ops;
 
+struct solib_catchpoint
+{
+  /* The base class.  */
+  struct breakpoint base;
+
+  /* True for "catch load".  */
+  unsigned char is_load;
+
+  /* Regular expression to match, if any.  */
+  char *regex;
+  regex_t compiled;
+};
+
+static void
+dtor_catch_solib (struct breakpoint *b)
+{
+  struct solib_catchpoint *self = (struct solib_catchpoint *) b;
+
+  if (self->regex)
+    regfree (&self->compiled);
+  xfree (self->regex);
+
+  base_breakpoint_ops.dtor (b);
+}
+
+static int
+insert_catch_solib (struct bp_location *ignore)
+{
+  return 0;
+}
+
+static int
+remove_catch_solib (struct bp_location *ignore)
+{
+  return 0;
+}
+
+static int
+breakpoint_hit_catch_solib (const struct bp_location *bl,
+			    struct address_space *aspace,
+			    CORE_ADDR bp_addr,
+			    const struct target_waitstatus *ws)
+{
+  struct solib_catchpoint *self = (struct solib_catchpoint *) bl->owner;
+  struct breakpoint *other;
+
+  if (ws->kind == TARGET_WAITKIND_LOADED)
+    return 1;
+
+  ALL_BREAKPOINTS (other)
+  {
+    struct bp_location *other_bl;
+
+    if (other == bl->owner)
+      continue;
+
+    if (other->type != bp_shlib_event)
+      continue;
+
+    if (self->base.pspace != NULL && other->pspace != self->base.pspace)
+      continue;
+
+    for (other_bl = other->loc; other_bl != NULL; other_bl = other_bl->next)
+      {
+	if (other->ops->breakpoint_hit (other_bl, aspace, bp_addr, ws))
+	  return 1;
+      }
+  }
+
+  return 0;
+}
+
+static void
+check_status_catch_solib (struct bpstats *bs)
+{
+  struct solib_catchpoint *self
+    = (struct solib_catchpoint *) bs->breakpoint_at;
+  int ix;
+
+  if (self->is_load)
+    {
+      struct so_list *iter;
+
+      for (ix = 0;
+	   VEC_iterate (so_list_ptr, current_program_space->added_solibs,
+			ix, iter);
+	   ++ix)
+	{
+	  if (!self->regex
+	      || regexec (&self->compiled, iter->so_name, 0, NULL, 0) == 0)
+	    return;
+	}
+    }
+  else
+    {
+      char *iter;
+
+      for (ix = 0;
+	   VEC_iterate (char_ptr, current_program_space->deleted_solibs,
+			ix, iter);
+	   ++ix)
+	{
+	  if (!self->regex
+	      || regexec (&self->compiled, iter, 0, NULL, 0) == 0)
+	    return;
+	}
+    }
+
+  bs->stop = 0;
+  bs->print_it = print_it_noop;
+}
+
+static enum print_stop_action
+print_it_catch_solib (bpstat bs)
+{
+  struct breakpoint *b = bs->breakpoint_at;
+  struct ui_out *uiout = current_uiout;
+
+  annotate_catchpoint (b->number);
+  if (b->disposition == disp_del)
+    ui_out_text (uiout, "\nTemporary catchpoint ");
+  else
+    ui_out_text (uiout, "\nCatchpoint ");
+  ui_out_field_int (uiout, "bkptno", b->number);
+  ui_out_text (uiout, "\n");
+  if (ui_out_is_mi_like_p (uiout))
+    ui_out_field_string (uiout, "disp", bpdisp_text (b->disposition));
+  print_solib_event (1);
+  return PRINT_SRC_AND_LOC;
+}
+
+static void
+print_one_catch_solib (struct breakpoint *b, struct bp_location **locs)
+{
+  struct solib_catchpoint *self = (struct solib_catchpoint *) b;
+  struct value_print_options opts;
+  struct ui_out *uiout = current_uiout;
+  char *msg;
+
+  get_user_print_options (&opts);
+  /* Field 4, the address, is omitted (which makes the columns not
+     line up too nicely with the headers, but the effect is relatively
+     readable).  */
+  if (opts.addressprint)
+    {
+      annotate_field (4);
+      ui_out_field_skip (uiout, "addr");
+    }
+
+  annotate_field (5);
+  if (self->is_load)
+    {
+      if (self->regex)
+	msg = xstrprintf (_("load of library matching %s"), self->regex);
+      else
+	msg = xstrdup (_("load of library"));
+    }
+  else
+    {
+      if (self->regex)
+	msg = xstrprintf (_("unload of library matching %s"), self->regex);
+      else
+	msg = xstrdup (_("unload of library"));
+    }
+  ui_out_field_string (uiout, "what", msg);
+  xfree (msg);
+}
+
+static void
+print_mention_catch_solib (struct breakpoint *b)
+{
+  struct solib_catchpoint *self = (struct solib_catchpoint *) b;
+
+  printf_filtered (_("Catchpoint %d (%s)"), b->number,
+		   self->is_load ? "load" : "unload");
+}
+
+static void
+print_recreate_catch_solib (struct breakpoint *b, struct ui_file *fp)
+{
+  struct solib_catchpoint *self = (struct solib_catchpoint *) b;
+
+  fprintf_unfiltered (fp, "%s %s",
+		      b->disposition == disp_del ? "tcatch" : "catch",
+		      self->is_load ? "load" : "unload");
+  if (self->regex)
+    fprintf_unfiltered (fp, " %s", self->regex);
+  fprintf_unfiltered (fp, "\n");
+}
+
+static struct breakpoint_ops catch_solib_breakpoint_ops;
+
+/* A helper function that does all the work for "catch load" and
+   "catch unload".  */
+
+static void
+catch_load_or_unload (char *arg, int from_tty, int is_load,
+		      struct cmd_list_element *command)
+{
+  struct solib_catchpoint *c;
+  struct gdbarch *gdbarch = get_current_arch ();
+  int tempflag;
+  regex_t compiled;
+  struct cleanup *cleanup;
+
+  tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
+
+  if (!arg)
+    arg = "";
+  arg = skip_spaces (arg);
+
+  c = XCNEW (struct solib_catchpoint);
+  cleanup = make_cleanup (xfree, c);
+
+  if (*arg != '\0')
+    {
+      int errcode;
+
+      errcode = regcomp (&c->compiled, arg, REG_NOSUB);
+      if (errcode != 0)
+	{
+	  char *err = get_regcomp_error (errcode, &c->compiled);
+
+	  make_cleanup (xfree, err);
+	  error (_("Invalid regexp (%s): %s"), err, arg);
+	}
+      c->regex = xstrdup (arg);
+    }
+
+  c->is_load = is_load;
+  init_catchpoint (&c->base, gdbarch, tempflag, NULL,
+		   &catch_solib_breakpoint_ops);
+
+  install_breakpoint (0, &c->base, 1);
+  discard_cleanups (cleanup);
+}
+
+static void
+catch_load_command_1 (char *arg, int from_tty,
+		      struct cmd_list_element *command)
+{
+  catch_load_or_unload (arg, from_tty, 1, command);
+}
+
+static void
+catch_unload_command_1 (char *arg, int from_tty,
+			struct cmd_list_element *command)
+{
+  catch_load_or_unload (arg, from_tty, 0, command);
+}
+
 /* An instance of this type is used to represent a syscall catchpoint.
    It includes a "struct breakpoint" as a kind of base class; users
    downcast to "struct breakpoint *" when needed.  A breakpoint is
@@ -11179,6 +11520,9 @@ internal_bkpt_check_status (bpstat bs)
 {
   /* We do not stop for these.  */
   bs->stop = 0;
+
+  if (bs->breakpoint_at->type == bp_shlib_event && !stop_on_solib_events)
+    bs->print_it = print_it_noop;
 }
 
 static enum print_stop_action
@@ -11195,10 +11539,7 @@ internal_bkpt_print_it (bpstat bs)
       /* Did we stop because the user set the stop_on_solib_events
 	 variable?  (If so, we report this as a generic, "Stopped due
 	 to shlib event" message.) */
-      ui_out_text (uiout, _("Stopped due to shared library event\n"));
-      if (ui_out_is_mi_like_p (uiout))
-	ui_out_field_string (uiout, "reason",
-			     async_reason_lookup (EXEC_ASYNC_SOLIB_EVENT));
+      print_solib_event (0);
       break;
 
     case bp_thread_event:
@@ -13837,6 +14178,19 @@ initialize_breakpoint_ops (void)
   ops->print_one = print_one_catch_syscall;
   ops->print_mention = print_mention_catch_syscall;
   ops->print_recreate = print_recreate_catch_syscall;
+
+  /* Solib-related catchpoints.  */
+  ops = &catch_solib_breakpoint_ops;
+  *ops = base_breakpoint_ops;
+  ops->dtor = dtor_catch_solib;
+  ops->insert_location = insert_catch_solib;
+  ops->remove_location = remove_catch_solib;
+  ops->breakpoint_hit = breakpoint_hit_catch_solib;
+  ops->check_status = check_status_catch_solib;
+  ops->print_it = print_it_catch_solib;
+  ops->print_one = print_one_catch_solib;
+  ops->print_mention = print_mention_catch_solib;
+  ops->print_recreate = print_recreate_catch_solib;
 }
 
 void
@@ -14140,6 +14494,20 @@ Catch an exception, when thrown."),
                      NULL,
 		     CATCH_PERMANENT,
 		     CATCH_TEMPORARY);
+  add_catch_command ("load", _("Catch loads of shared libraries.\n\
+Usage: catch load [REGEX]\n\
+If REGEX is given, only stop for libraries matching the regular expression."),
+		     catch_load_command_1,
+		     NULL,
+		     CATCH_PERMANENT,
+		     CATCH_TEMPORARY);
+  add_catch_command ("unload", _("Catch unloads of shared libraries.\n\
+Usage: catch unload [REGEX]\n\
+If REGEX is given, only stop for libraries matching the regular expression."),
+		     catch_unload_command_1,
+		     NULL,
+		     CATCH_PERMANENT,
+		     CATCH_TEMPORARY);
   add_catch_command ("syscall", _("\
 Catch system calls by their names and/or numbers.\n\
 Arguments say which system calls to catch.  If no arguments\n\
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index f1c2c52..0fc2e09 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -1414,4 +1414,6 @@ extern int user_breakpoint_p (struct breakpoint *);
 /* Attempt to determine architecture of location identified by SAL.  */
 extern struct gdbarch *get_sal_arch (struct symtab_and_line sal);
 
+extern void handle_solib_event (void);
+
 #endif /* !defined (BREAKPOINT_H) */
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 49db189..a850968 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -4113,6 +4113,12 @@ and @sc{gnu}/Linux.
 A call to @code{vfork}.  This is currently only available for HP-UX
 and @sc{gnu}/Linux.
 
+@item load @r{[}regexp@r{]}
+@itemx unload @r{[}regexp@r{]}
+The loading or unloading of a shared library.  If @var{regexp} is
+given, then the catchpoint will stop only if it matches one of the
+affected libraries.
+
 @end table
 
 @item tcatch @var{event}
@@ -15598,8 +15604,14 @@ discarded.
 @end table
 
 Sometimes you may wish that @value{GDBN} stops and gives you control
-when any of shared library events happen.  Use the @code{set
-stop-on-solib-events} command for this:
+when any of shared library events happen.  The best way to do this is
+to use @code{catch load} and @code{catch unload} (@pxref{Set
+Catchpoints}).
+
+@value{GDBN} also supports the the @code{set stop-on-solib-events}
+command for this.  This command exists for historical reasons.  It is
+less useful than setting a catchpoint, because it does not allow for
+conditions or commands as a catchpoint does.
 
 @table @code
 @item set stop-on-solib-events
@@ -26299,8 +26311,9 @@ The inferior exited normally.
 A signal was received by the inferior.
 @item solib-event
 The inferior has stopped due to a library being loaded or unloaded.
-This can only happen when @code{stop-on-solib-events} (@pxref{Files})
-is set.
+This can happen when @code{stop-on-solib-events} (@pxref{Files}) is
+set or when a @code{catch load} or @code{catch unload} catchpoint is
+in use (@pxref{Set Catchpoints}).
 @item fork
 The inferior has forked.  This is reported when @code{catch fork}
 (@pxref{Set Catchpoints}) has been used.
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 53065c8..68ab851 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -3323,28 +3323,32 @@ handle_inferior_event (struct execution_control_state *ecs)
          established.  */
       if (stop_soon == NO_STOP_QUIETLY)
 	{
-	  /* Check for any newly added shared libraries if we're
-	     supposed to be adding them automatically.  Switch
-	     terminal for any messages produced by
-	     breakpoint_re_set.  */
-	  target_terminal_ours_for_output ();
-	  /* NOTE: cagney/2003-11-25: Make certain that the target
-	     stack's section table is kept up-to-date.  Architectures,
-	     (e.g., PPC64), use the section table to perform
-	     operations such as address => section name and hence
-	     require the table to contain all sections (including
-	     those found in shared libraries).  */
-#ifdef SOLIB_ADD
-	  SOLIB_ADD (NULL, 0, &current_target, auto_solib_add);
-#else
-	  solib_add (NULL, 0, &current_target, auto_solib_add);
-#endif
-	  target_terminal_inferior ();
+	  struct regcache *regcache;
+
+	  if (!ptid_equal (ecs->ptid, inferior_ptid))
+	    context_switch (ecs->ptid);
+	  regcache = get_thread_regcache (ecs->ptid);
+
+	  handle_solib_event ();
+
+	  ecs->event_thread->control.stop_bpstat
+	    = bpstat_stop_status (get_regcache_aspace (regcache),
+				  stop_pc, ecs->ptid, &ecs->ws);
+	  ecs->random_signal
+	    = !bpstat_explains_signal (ecs->event_thread->control.stop_bpstat);
+
+	  if (!ecs->random_signal)
+	    {
+	      /* A catchpoint triggered.  */
+	      ecs->event_thread->suspend.stop_signal = TARGET_SIGNAL_TRAP;
+	      goto process_event_stop_test;
+	    }
 
 	  /* If requested, stop when the dynamic linker notifies
 	     gdb of events.  This allows the user to get control
 	     and place breakpoints in initializer routines for
 	     dynamically loaded objects (among other things).  */
+	  ecs->event_thread->suspend.stop_signal = TARGET_SIGNAL_0;
 	  if (stop_on_solib_events)
 	    {
 	      /* Make sure we print "Stopped due to solib-event" in
@@ -3354,9 +3358,6 @@ handle_inferior_event (struct execution_control_state *ecs)
 	      stop_stepping (ecs);
 	      return;
 	    }
-
-	  /* NOTE drow/2007-05-11: This might be a good place to check
-	     for "catch load".  */
 	}
 
       /* If we are skipping through a shell, or through shared library
diff --git a/gdb/progspace.c b/gdb/progspace.c
index 7175fa6..54531d9 100644
--- a/gdb/progspace.c
+++ b/gdb/progspace.c
@@ -149,6 +149,7 @@ release_program_space (struct program_space *pspace)
     free_address_space (pspace->aspace);
   resize_section_table (&pspace->target_sections,
 			-resize_section_table (&pspace->target_sections, 0));
+  clear_program_space_solib_cache (pspace);
     /* Discard any data modules have associated with the PSPACE.  */
   program_space_free_data (pspace);
   xfree (pspace);
@@ -503,6 +504,22 @@ switch_to_program_space_and_thread (struct program_space *pspace)
 
 
 
+/* See progspace.h.  */
+
+void
+clear_program_space_solib_cache (struct program_space *pspace)
+{
+  int ix;
+  char *name;
+
+  VEC_free (so_list_ptr, pspace->added_solibs);
+  for (ix = 0; VEC_iterate (char_ptr, pspace->deleted_solibs, ix, name); ++ix)
+    xfree (name);
+  VEC_free (char_ptr, pspace->deleted_solibs);
+}
+
+
+
 /* Keep a registry of per-program_space data-pointers required by other GDB
    modules.  */
 
diff --git a/gdb/progspace.h b/gdb/progspace.h
index 9822f70..3db3938 100644
--- a/gdb/progspace.h
+++ b/gdb/progspace.h
@@ -23,6 +23,7 @@
 
 #include "target.h"
 #include "vec.h"
+#include "gdb_vecs.h"
 
 struct target_ops;
 struct bfd;
@@ -32,6 +33,9 @@ struct exec;
 struct address_space;
 struct program_space_data;
 
+typedef struct so_list *so_list_ptr;
+DEF_VEC_P (so_list_ptr);
+
 /* A program space represents a symbolic view of an address space.
    Roughly speaking, it holds all the data associated with a
    non-running-yet program (main executable, main symbols), and when
@@ -188,6 +192,14 @@ struct program_space
     /* Number of calls to solib_add.  */
     unsigned solib_add_generation;
 
+    /* When an solib is added, it is also added to this vector.  This
+       is so we can properly report solib changes to the user.  */
+    VEC (so_list_ptr) *added_solibs;
+
+    /* When an solib is removed, its name is added to this vector.
+       This is so we can properly report solib changes to the user.  */
+    VEC (char_ptr) *deleted_solibs;
+
     /* Per pspace data-pointers required by other GDB modules.  */
     void **data;
     unsigned num_data;
@@ -278,6 +290,11 @@ extern void update_address_spaces (void);
    anymore.  */
 extern void prune_program_spaces (void);
 
+/* Reset saved solib data at the start of an solib event.  This lets
+   us properly collect the data when calling solib_add, so it can then
+   later be printed.  */
+extern void clear_program_space_solib_cache (struct program_space *);
+
 /* Keep a registry of per-pspace data-pointers required by other GDB
    modules.  */
 
diff --git a/gdb/solib.c b/gdb/solib.c
index f591785..84b9019 100644
--- a/gdb/solib.c
+++ b/gdb/solib.c
@@ -758,6 +758,9 @@ update_solib_list (int from_tty, struct target_ops *target)
 	     unloaded before we remove it from GDB's tables.  */
 	  observer_notify_solib_unloaded (gdb);
 
+	  VEC_safe_push (char_ptr, current_program_space->deleted_solibs,
+			 xstrdup (gdb->so_name));
+
 	  *gdb_link = gdb->next;
 
 	  /* Unless the user loaded it explicitly, free SO's objfile.  */
@@ -793,6 +796,7 @@ update_solib_list (int from_tty, struct target_ops *target)
 	  volatile struct gdb_exception e;
 
 	  i->pspace = current_program_space;
+	  VEC_safe_push (so_list_ptr, current_program_space->added_solibs, i);
 
 	  TRY_CATCH (e, RETURN_MASK_ERROR)
 	    {
diff --git a/gdb/testsuite/gdb.base/break-interp.exp b/gdb/testsuite/gdb.base/break-interp.exp
index 5882cfe..04b5eab 100644
--- a/gdb/testsuite/gdb.base/break-interp.exp
+++ b/gdb/testsuite/gdb.base/break-interp.exp
@@ -155,7 +155,7 @@ proc reach_1 {func command displacement} {
 		pass $test
 	    }
 	}
-	-re "Stopped due to shared library event\r\n$gdb_prompt $" {
+	-re "Stopped due to (spurious )?shared library event.*\r\n$gdb_prompt $" {
 	    if {$func == "_dl_debug_state"} {
 		if {$debug_state_count == 0} {
 		    # First stop does not yet relocate the _start function
diff --git a/gdb/testsuite/gdb.base/catch-load-so.c b/gdb/testsuite/gdb.base/catch-load-so.c
new file mode 100644
index 0000000..9676479
--- /dev/null
+++ b/gdb/testsuite/gdb.base/catch-load-so.c
@@ -0,0 +1,22 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2012 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+int
+f(void)
+{
+  return 23;
+}
diff --git a/gdb/testsuite/gdb.base/catch-load.c b/gdb/testsuite/gdb.base/catch-load.c
new file mode 100644
index 0000000..170f581
--- /dev/null
+++ b/gdb/testsuite/gdb.base/catch-load.c
@@ -0,0 +1,35 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2012 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <dlfcn.h>
+#include <stdio.h>
+
+/* This is updated by the .exp file.  */
+char *libname = "catch-load-so.so";
+
+int
+main ()
+{
+  void *h;
+
+  h = dlopen (libname, RTLD_LAZY);
+
+  dlclose (h);
+
+  h = NULL;			/* final breakpoint here */
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.base/catch-load.exp b/gdb/testsuite/gdb.base/catch-load.exp
new file mode 100644
index 0000000..2a7c910
--- /dev/null
+++ b/gdb/testsuite/gdb.base/catch-load.exp
@@ -0,0 +1,120 @@
+# Copyright 2012 Free Software Foundation, Inc.
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+if {[skip_shlib_tests]} {
+    untested catch-load.exp
+    return -1
+}
+
+if {[get_compiler_info not-used]} {
+    warning "Could not get compiler info"
+    untested catch-load.exp
+    return -1
+}
+
+set testfile catch-load
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+if  { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug shlib_load}] != "" } {
+    untested catch-load.exp
+    return -1
+}
+
+set testfile2 catch-load-so
+set srcfile2 ${testfile2}.c
+set binfile2 ${objdir}/${subdir}/${testfile2}.so
+set binfile2_dlopen [shlib_target_file ${testfile2}.so]
+if { [gdb_compile_shlib "${srcdir}/${subdir}/${srcfile2}" ${binfile2} {debug}] != "" } {
+    untested catch-load.exp
+    return -1
+}
+
+# Run one set of tests.
+# SCENARIO is the name of the test scenario, it is just used in test
+# names.
+# KIND is is passed to the "catch" command.
+# MATCH is a boolean saying whether we expect the catchpoint to be hit.
+proc one_catch_load_test {scenario kind match sostop} {
+    global verbose testfile testfile2 binfile2_dlopen
+    global pf_prefix srcfile
+    global decimal gdb_prompt
+
+    set saved_prefix $pf_prefix
+    append pf_prefix "${scenario}:"
+
+    clean_restart $testfile
+    gdb_load_shlibs $binfile2_dlopen
+
+    if {![runto_main]} {
+	fail "can't run to main"
+	set pf_prefix $saved_prefix
+	return
+    }
+
+    gdb_breakpoint [gdb_get_line_number "final breakpoint here"]
+    gdb_test_no_output "set var libname = \"$binfile2_dlopen\""
+    gdb_test_no_output "set stop-on-solib-events $sostop"
+    gdb_test "catch $kind" "Catchpoint $decimal \\(.*\\)"
+
+    send_gdb "continue\n"
+    gdb_expect {
+	-re "Catchpoint $decimal\r\n.*loaded .*/$testfile2.*\r\n.*$gdb_prompt $" {
+	    if {$match} {
+		pass "continue"
+	    } else {
+		fail "continue"
+	    }
+	}
+
+	-re "Stopped due to spurious shared library event .no libraries added or removed.\r\n$gdb_prompt $" {
+	    if {$sostop} {
+		pass "continue"
+	    } else {
+		fail "continue"
+	    }
+	}
+
+	-re "Breakpoint $decimal, .*\r\n$gdb_prompt $" {
+	    if {!$match} {
+		pass "continue"
+	    } else {
+		fail "continue"
+	    }
+	}
+
+	-re ".*$gdb_prompt $" {
+	    fail "continue"
+	}
+    }
+
+    set pf_prefix $saved_prefix
+}
+
+one_catch_load_test "plain load" "load" 1 0
+one_catch_load_test "plain load with stop-on-solib-events" "load" 1 1
+one_catch_load_test "rx load" "load $testfile2" 1 0
+one_catch_load_test "rx load with stop-on-solib-events" "load $testfile2" 1 1
+one_catch_load_test "non-matching load" "load zardoz" 0 0
+one_catch_load_test "non-matching load with stop-on-solib-events" \
+    "load zardoz" 0 1
+
+one_catch_load_test "plain unload" "unload" 1 0
+one_catch_load_test "plain unload with stop-on-solib-events" "unload" 1 1
+one_catch_load_test "rx unload" "unload $testfile2" 1 0
+one_catch_load_test "rx unload with stop-on-solib-events" \
+    "unload $testfile2" 1 1
+one_catch_load_test "non-matching unload" "unload zardoz" 0 0
+one_catch_load_test "non-matching unload with stop-on-solib-events" \
+    "unload zardoz" 0 1
diff --git a/gdb/testsuite/lib/mi-support.exp b/gdb/testsuite/lib/mi-support.exp
index 4d40a1e..b013311 100644
--- a/gdb/testsuite/lib/mi-support.exp
+++ b/gdb/testsuite/lib/mi-support.exp
@@ -1060,6 +1060,8 @@ proc mi_expect_stop { reason func args file line extra test } {
     set bn ""
     if { $reason == "breakpoint-hit" } {
         set bn {bkptno="[0-9]+",}
+    } elseif { $reason == "solib-event" } {
+	set bn ".*,"
     }
 
     set r ""
-- 
1.7.6.5


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