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]

[RFC/WIP PATCH v2 08/12] I/T set support for breakpoints - trigger set, and stop set


This adds support for setting a breakpoint that only triggers on a
given set (a superset of the current thread specific breakpoints
support).  In addition, it adds support for specifying the set of
threads that are suspended when the breakpoint is triggered.

Breakpoints need two sets.  The trigger set, which is a generalization
of the "break foo thread N", meaning the set of inferiors/threads
where the breakpoint should fire, and, a suspend/stop set, which is
the set of inferiors/threads that should be suspended when the
breakpoint fires.

The trigger set of breakpoints is set from the current set at the time
the breakpoint is created.  The stop set is passed explicitly as
optional switch.  E.g.,:

 [itfocus TRIGGER-SET] break [-stop STOP-SET] LINESPEC

This leaves LINESPEC last, so that we can keep supporting the current
form, but avoid more hacks in linespecs like the special termination
for "thread/task/if" in the lexers.

So the old:

 (gdb) break LINESPEC

still works just the same.  The breakpoint's trigger set will be
inferred from the current set as set or temporarily overriden by
itfocus.  The stop set, if not specified, is inferred from the "set
non-stop" global option.  If non-stop is on, only the thread that
triggers the breakpoint should be suspended; if non-stop is off, then
all threads in the current focus will be suspended when the breakpoint
fires.  The thread that fired the breakpoint always remains stopped,
nomatter the stop set.

E.g.,

(gdb) info threads
  Id   Target Id         Frame
  3    Thread 0x7ffff7028700 (LWP 2296) "threads" (running)
* 2    Thread 0x7ffff7829700 (LWP 2295) "threads" thread_function0 (arg=0x0) at threads.c:63
  1    Thread 0x7ffff7fcb720 (LWP 2290) "threads" (running)
(gdb) itfocus t2 break -stop t3 63
Breakpoint 4 at 0x40076d: file threads.c, line 63.

Breakpoint 4 triggers on thread 2 (equivalent to break 63 thread 2),
and when the breakpoint fires, thread 3 is suspended.  Like so:

(gdb) c -a&
Continuing.
(gdb)
Breakpoint 4, thread_function0 (arg=0x0) at threads.c:63
63              (*myp) ++;
info threads
  Id   Target Id         Frame
  3    Thread 0x7ffff7028700 (LWP 2296) "threads" 0x00007ffff78d75ad in nanosleep () from /lib/x86_64-linux-gnu/libc.so.6
* 2    Thread 0x7ffff7829700 (LWP 2295) "threads" thread_function0 (arg=0x0) at threads.c:63
  1    Thread 0x7ffff7fcb720 (LWP 2290) "threads" (running)

(gdb) info breakpoints
Num     Type           Disp Enb Address            What
4       breakpoint     keep y   0x000000000040076d in thread_function0 at threads.c:63
        stop only in trigger-set: t2
        suspend all in stop-set: t3
        breakpoint already hit 1 time

We can make a breakpoint that stops the world with (recall I had
non-stop on):

(gdb) del 4
(gdb) itfocus t2 break -stop all 63
Breakpoint 5 at 0x40076d: file threads.c, line 63.
(gdb) c -a&
Continuing.
(gdb)
Breakpoint 5, thread_function0 (arg=0x0) at threads.c:63
63              (*myp) ++;
info threads
  Id   Target Id         Frame
  3    Thread 0x7ffff7028700 (LWP 2296) "threads" 0x00007ffff78d75ad in nanosleep () from /lib/x86_64-linux-gnu/libc.so.6
* 2    Thread 0x7ffff7829700 (LWP 2295) "threads" thread_function0 (arg=0x0) at threads.c:63
  1    Thread 0x7ffff7fcb720 (LWP 2290) "threads" 0x00007ffff7bc606d in pthread_join () from /lib/x86_64-linux-gnu/libpthread.so.0

Since all-stop was reimplemented on top of the target running in
non-stop mode, when "set non-stop" is off, not specifying a stop set
(or specifying it as empty, like -stop empty) means that all threads
stop by default, e.g., `itfocus t2 break 63', but you can still
override that explicitly by specifying "-stop SET", so the breakpoint
only forces suspension of a given itset, with:

(gdb) itfocus t2 break -stop t3 63
Breakpoint 5 at 0x40076d: file threads.c, line 63.
(gdb) c &
Continuing.
(gdb)
Breakpoint 5, thread_function0 (arg=0x0) at threads.c:63
63              (*myp) ++;
info threads
  Id   Target Id         Frame
  3    Thread 0x7ffff7028700 (LWP 2645) "threads" 0x00007ffff78d75ad in nanosleep () from /lib/x86_64-linux-gnu/libc.so.6
* 2    Thread 0x7ffff7829700 (LWP 2644) "threads" thread_function0 (arg=0x0) at threads.c:63
  1    Thread 0x7ffff7fcb720 (LWP 2610) "threads" (running)


v2:

 - Adjusted to new itset spec syntax.
 - All breakpoint-ish commands adjusted to accept "-stop", and handle
   the trigger and stop sets.
 - The stop set when multiple breakpoints are hit is the union of the
   stop sets of all the breakpoints that caused the stop.
 - Some cleanup, some bugfixes, some hacks removed.


2011-12-16  Pedro Alves  <pedro@codesourcery.com>

	* ada-lang.c: Include itset.h.
	(create_ada_exception_catchpoint): Add trigger_set and stop_set
	parameters.  Adjust.
	(catch_ada_exception_command, catch_assert_command): Parse
	`-stop', and pass down trigger and stop sets.
	* breakpoint.c: Include itset.h.
	(bpstat_check_trigger_set): New.
	(breakpoint_thread_match): Handle the trigger set.
	(bpstat_check_breakpoint_conditions): Handle the trigger set.
	(bpstat_stop_set): New.
	(print_one_breakpoint_location): Print the trigger and stop sets.
	(init_raw_breakpoint_without_location): Initialize new fields.
	(init_catchpoint, create_fork_vfork_event_catchpoint)
	(create_syscall_event_catchpoint, init_breakpoint_sal)
	(create_breakpoint_sal): Add trigger_set and stop_set parameters.
	Adjust.
	(parse_breakpoint_sals): Handle pointer to pointer to empty string
	as no arg.
	(parse_breakpoint_args): New.
	(create_breakpoint, watch_command_1, catch_fork_command_1)
	(catch_exec_command_1): Parse `-stop', and pass down trigger and
	stop sets.
	(init_ada_exception_breakpoint): Add trigger_set and stop_set
	parameters.  Adjust.
	(catch_syscall_command_1): Parse `-stop', and pass down trigger
	and stop sets.
	(base_breakpoint_dtor): Free the trigger and stop sets.
	* breakpoint.h (struct itset): Forward declare.
	(struct breakpoint) <trigger_set, stop_set>: New fields.
	(bpstat_stop_set): Declare.
	(init_ada_exception_breakpoint): Adjust.
	* infcall.c (call_function_by_hand): Set the breakpoint's trigger
	and stop sets.
	* infrun.c: Include itset.h.
	(struct execution_control_state) <stop_set>: New field.
	(ecs_destroy, ecs_destroy_cleanup): New.
	(infrun_thread_stop_requested_callback): Destroy ecs.
	(select_event_thread): Adjust.
	(wait_for_inferior, fetch_inferior_event): Destroy ecs.
	(stop_set_match): New.
	(stop_all_threads): New parameter `stop_set'.  Stop only stops in
	the specified stop set.
	(handle_inferior_event): Set the stop set from the bpstat's stop
	set.
	(stop_stepping): If there's no stop set in the ecs, infer from
	non_stop setting.  Only clear the resumed flag of threads in the
	stop set.
	(keep_going): Adjust.
---
 gdb/ada-lang.c   |   38 ++++++++
 gdb/breakpoint.c |  243 ++++++++++++++++++++++++++++++++++++++++++++++++++----
 gdb/breakpoint.h |   15 +++
 gdb/infcall.c    |    7 ++
 gdb/infrun.c     |   96 ++++++++++++++++++---
 5 files changed, 362 insertions(+), 37 deletions(-)

diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 1befc43..c018bfe 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -63,6 +63,7 @@
 #include "mi/mi-common.h"
 #include "arch-utils.h"
 #include "exceptions.h"
+#include "itset.h"
 
 /* Define whether or not the C operator '/' truncates towards zero for
    differently signed operands (truncation direction is undefined in C).
@@ -11752,7 +11753,9 @@ ada_decode_exception_location (char *args, char **addr_string,
 /* Create an Ada exception catchpoint.  */
 
 static void
-create_ada_exception_catchpoint (struct gdbarch *gdbarch,
+create_ada_exception_catchpoint (struct itset *trigger_set,
+				 struct itset *stop_set,
+				 struct gdbarch *gdbarch,
 				 struct symtab_and_line sal,
 				 char *addr_string,
 				 char *excep_string,
@@ -11763,7 +11766,8 @@ create_ada_exception_catchpoint (struct gdbarch *gdbarch,
   struct ada_catchpoint *c;
 
   c = XNEW (struct ada_catchpoint);
-  init_ada_exception_breakpoint (&c->base, gdbarch, sal, addr_string,
+  init_ada_exception_breakpoint (&c->base, trigger_set, stop_set,
+				 gdbarch, sal, addr_string,
 				 ops, tempflag, from_tty);
   c->excep_string = excep_string;
   create_excep_cond_exprs (c);
@@ -11772,6 +11776,10 @@ create_ada_exception_catchpoint (struct gdbarch *gdbarch,
 
 /* Implement the "catch exception" command.  */
 
+void parse_breakpoint_args (char **args,
+			    struct itset **trigger_set,
+			    struct itset **stop_set);
+
 static void
 catch_ada_exception_command (char *arg, int from_tty,
 			     struct cmd_list_element *command)
@@ -11782,14 +11790,25 @@ catch_ada_exception_command (char *arg, int from_tty,
   char *addr_string = NULL;
   char *excep_string = NULL;
   const struct breakpoint_ops *ops = NULL;
+  struct itset *trigger_set;
+  struct itset *stop_set;
+  struct cleanup *old_chain;
 
   tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
 
+  parse_breakpoint_args (&arg, &trigger_set, &stop_set);
+
+  old_chain = make_cleanup_itset_free (trigger_set);
+  make_cleanup_itset_free (stop_set);
+
   if (!arg)
     arg = "";
   sal = ada_decode_exception_location (arg, &addr_string, &excep_string, &ops);
-  create_ada_exception_catchpoint (gdbarch, sal, addr_string,
+  create_ada_exception_catchpoint (trigger_set, stop_set,
+				   gdbarch, sal, addr_string,
 				   excep_string, ops, tempflag, from_tty);
+
+  discard_cleanups (old_chain);
 }
 
 static struct symtab_and_line
@@ -11820,14 +11839,25 @@ catch_assert_command (char *arg, int from_tty,
   struct symtab_and_line sal;
   char *addr_string = NULL;
   const struct breakpoint_ops *ops = NULL;
+  struct itset *trigger_set;
+  struct itset *stop_set;
+  struct cleanup *old_chain;
 
   tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
 
+  parse_breakpoint_args (&arg, &trigger_set, &stop_set);
+
+  old_chain = make_cleanup_itset_free (trigger_set);
+  make_cleanup_itset_free (stop_set);
+
   if (!arg)
     arg = "";
   sal = ada_decode_assert_location (arg, &addr_string, &ops);
-  create_ada_exception_catchpoint (gdbarch, sal, addr_string,
+  create_ada_exception_catchpoint (trigger_set, stop_set,
+				   gdbarch, sal, addr_string,
 				   NULL, ops, tempflag, from_tty);
+
+  discard_cleanups (old_chain);
 }
                                 /* Operators */
 /* Information about operators given special treatment in functions
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index ec1565d..effb53b 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -34,6 +34,7 @@
 #include "value.h"
 #include "command.h"
 #include "inferior.h"
+#include "itset.h"
 #include "gdbthread.h"
 #include "target.h"
 #include "language.h"
@@ -3049,6 +3050,21 @@ hardware_watchpoint_inserted_in_range (struct address_space *aspace,
   return 0;
 }
 
+/* Test whether this stopping thread is in the I/T set for this
+   breakpoint.  */
+
+static int
+bpstat_check_trigger_set (const struct breakpoint *b, struct thread_info *thread)
+{
+  if (b->trigger_set == NULL)
+    return 1;
+
+  if (itset_contains_thread (b->trigger_set, thread))
+    return 1;
+
+  return 0;
+}
+
 /* breakpoint_thread_match (PC, PTID) returns true if the breakpoint at
    PC is valid for process/thread PTID.  */
 
@@ -3058,7 +3074,7 @@ breakpoint_thread_match (struct address_space *aspace, CORE_ADDR pc,
 {
   struct bp_location *bl, **blp_tmp;
   /* The thread and task IDs associated to PTID, computed lazily.  */
-  int thread = -1;
+  struct thread_info *thread = NULL;
   int task = 0;
   
   ALL_BP_LOCATIONS (bl, blp_tmp)
@@ -3080,9 +3096,9 @@ breakpoint_thread_match (struct address_space *aspace, CORE_ADDR pc,
 	  /* This is a thread-specific breakpoint.  Check that ptid
 	     matches that thread.  If thread hasn't been computed yet,
 	     it is now time to do so.  */
-	  if (thread == -1)
-	    thread = pid_to_thread_id (ptid);
-	  if (bl->owner->thread != thread)
+	  if (thread == NULL)
+	    thread = find_thread_ptid (ptid);
+	  if (bl->owner->thread != thread->num)
 	    continue;
 	}
 
@@ -3097,6 +3113,16 @@ breakpoint_thread_match (struct address_space *aspace, CORE_ADDR pc,
 	    continue;
         }
 
+      if (bl->owner->trigger_set != NULL)
+	{
+	  /* A breakpoint with a trigger itset.  Check that ptid
+	     matches that set.  */
+	  if (thread == NULL)
+	    thread = find_thread_ptid (ptid);
+	  if (!bpstat_check_trigger_set (bl->owner, thread))
+	    continue;
+	}
+
       if (overlay_debugging 
 	  && section_is_overlay (bl->section)
 	  && !section_is_mapped (bl->section))
@@ -3988,7 +4014,7 @@ bpstat_check_watchpoint (bpstat bs)
 static void
 bpstat_check_breakpoint_conditions (bpstat bs, ptid_t ptid)
 {
-  int thread_id = pid_to_thread_id (ptid);
+  struct thread_info *thread = find_thread_ptid (ptid);
   const struct bp_location *bl;
   struct breakpoint *b;
 
@@ -4090,7 +4116,12 @@ bpstat_check_breakpoint_conditions (bpstat bs, ptid_t ptid)
 	{
 	  bs->stop = 0;
 	}
-      else if (b->thread != -1 && b->thread != thread_id)
+      else if (b->thread != -1 && b->thread != thread->num)
+	{
+	  bs->stop = 0;
+	}
+      else if (b->trigger_set != NULL
+	       && !bpstat_check_trigger_set (b, thread))
 	{
 	  bs->stop = 0;
 	}
@@ -4518,6 +4549,34 @@ bpstat_what (bpstat bs_head)
   return retval;
 }
 
+/* Tell us what we should suspend.  Returns a union of the stop sets
+   of all breakpoints that caused the stop.  */
+
+struct itset *
+bpstat_stop_set (bpstat bs_head)
+{
+  bpstat bs;
+  struct itset *stop_set = itset_create_empty ();
+
+  for (bs = bs_head; bs != NULL; bs = bs->next)
+    {
+      if (bs->breakpoint_at == NULL)
+	{
+	  /* I suspect this can happen if it was a momentary
+	     breakpoint which has since been deleted.  */
+	  continue;
+	}
+
+      if (!bs->stop)
+	continue;
+
+      if (bs->breakpoint_at->stop_set != NULL)
+	itset_add_set (stop_set, bs->breakpoint_at->stop_set);
+    }
+
+  return stop_set;
+}
+
 /* Nonzero if we should step constantly (e.g. watchpoints on machines
    without hardware support).  This isn't related to a specific bpstat,
    just to things like whether watchpoints are set.  */
@@ -4917,7 +4976,27 @@ print_one_breakpoint_location (struct breakpoint *b,
       ui_out_field_int (uiout, "thread", b->thread);
       ui_out_text (uiout, "\n");
     }
-  
+
+  if (!part_of_multiple && b->trigger_set != NULL)
+    {
+      ui_out_text (uiout, "\tstop only in trigger-set: [");
+      if (itset_name (b->trigger_set) != NULL)
+	ui_out_field_string (uiout, "trigger-set", itset_name (b->trigger_set));
+      else
+	ui_out_field_string (uiout, "trigger-set", itset_spec (b->trigger_set));
+      ui_out_text (uiout, "]\n");
+    }
+
+  if (!part_of_multiple && b->stop_set != NULL)
+    {
+      ui_out_text (uiout, "\tsuspend all in stop-set: [");
+      if (itset_name (b->stop_set) != NULL)
+	ui_out_field_string (uiout, "stop-set", itset_name (b->stop_set));
+      else
+	ui_out_field_string (uiout, "stop-set", itset_spec (b->stop_set));
+      ui_out_text (uiout, "]\n");
+    }
+
   if (!part_of_multiple && b->hit_count)
     {
       /* FIXME should make an annotation for this.  */
@@ -5744,6 +5823,8 @@ init_raw_breakpoint_without_location (struct breakpoint *b,
   b->language = current_language->la_language;
   b->input_radix = input_radix;
   b->thread = -1;
+  b->trigger_set = NULL;
+  b->stop_set = NULL;
   b->enable_state = bp_enabled;
   b->next = 0;
   b->silent = 0;
@@ -6753,6 +6834,8 @@ syscall_catchpoint_p (struct breakpoint *b)
 
 static void
 init_catchpoint (struct breakpoint *b,
+		 struct itset *trigger_set,
+		 struct itset *stop_set,
 		 struct gdbarch *gdbarch, int tempflag,
 		 char *cond_string,
 		 const struct breakpoint_ops *ops)
@@ -6764,6 +6847,9 @@ init_catchpoint (struct breakpoint *b,
 
   init_raw_breakpoint (b, gdbarch, sal, bp_catchpoint, ops);
 
+  b->trigger_set = trigger_set;
+  b->stop_set = stop_set;
+
   b->cond_string = (cond_string == NULL) ? NULL : xstrdup (cond_string);
   b->disposition = tempflag ? disp_del : disp_donttouch;
 }
@@ -6782,13 +6868,16 @@ install_breakpoint (int internal, struct breakpoint *b, int update_gll)
 }
 
 static void
-create_fork_vfork_event_catchpoint (struct gdbarch *gdbarch,
+create_fork_vfork_event_catchpoint (struct itset *trigger_set,
+				    struct itset *stop_set,
+				    struct gdbarch *gdbarch,
 				    int tempflag, char *cond_string,
                                     const struct breakpoint_ops *ops)
 {
   struct fork_catchpoint *c = XNEW (struct fork_catchpoint);
 
-  init_catchpoint (&c->base, gdbarch, tempflag, cond_string, ops);
+  init_catchpoint (&c->base, trigger_set, stop_set,
+		   gdbarch, tempflag, cond_string, ops);
 
   c->forked_inferior_pid = null_ptid;
 
@@ -6917,14 +7006,17 @@ print_recreate_catch_exec (struct breakpoint *b, struct ui_file *fp)
 static struct breakpoint_ops catch_exec_breakpoint_ops;
 
 static void
-create_syscall_event_catchpoint (int tempflag, VEC(int) *filter,
-                                 const struct breakpoint_ops *ops)
+create_syscall_event_catchpoint (struct itset *trigger_set,
+				 struct itset *stop_set,
+				 int tempflag, VEC(int) *filter,
+				 const struct breakpoint_ops *ops)
 {
   struct syscall_catchpoint *c;
   struct gdbarch *gdbarch = get_current_arch ();
 
   c = XNEW (struct syscall_catchpoint);
-  init_catchpoint (&c->base, gdbarch, tempflag, NULL, ops);
+  init_catchpoint (&c->base, trigger_set, stop_set,
+		   gdbarch, tempflag, NULL, ops);
   c->syscalls_to_be_caught = filter;
 
   install_breakpoint (0, &c->base, 1);
@@ -7248,6 +7340,7 @@ init_breakpoint_sal (struct breakpoint *b, struct gdbarch *gdbarch,
 		     struct symtabs_and_lines sals, char *addr_string,
 		     char *filter, char *cond_string,
 		     enum bptype type, enum bpdisp disposition,
+		     struct itset *trigger_set, struct itset *stop_set,
 		     int thread, int task, int ignore_count,
 		     const struct breakpoint_ops *ops, int from_tty,
 		     int enabled, int internal, int display_canonical)
@@ -7290,6 +7383,8 @@ init_breakpoint_sal (struct breakpoint *b, struct gdbarch *gdbarch,
 	  init_raw_breakpoint (b, gdbarch, sal, type, ops);
 	  b->thread = thread;
 	  b->task = task;
+	  b->trigger_set = trigger_set;
+	  b->stop_set = stop_set;
   
 	  b->cond_string = cond_string;
 	  b->ignore_count = ignore_count;
@@ -7369,6 +7464,7 @@ create_breakpoint_sal (struct gdbarch *gdbarch,
 		       struct symtabs_and_lines sals, char *addr_string,
 		       char *filter, char *cond_string,
 		       enum bptype type, enum bpdisp disposition,
+		       struct itset *trigger_set, struct itset *stop_set,
 		       int thread, int task, int ignore_count,
 		       const struct breakpoint_ops *ops, int from_tty,
 		       int enabled, int internal, int display_canonical)
@@ -7392,6 +7488,7 @@ create_breakpoint_sal (struct gdbarch *gdbarch,
 		       sals, addr_string,
 		       filter, cond_string,
 		       type, disposition,
+		       trigger_set, stop_set,
 		       thread, task, ignore_count,
 		       ops, from_tty,
 		       enabled, internal, display_canonical);
@@ -7420,6 +7517,7 @@ create_breakpoints_sal (struct gdbarch *gdbarch,
 			struct linespec_result *canonical,
 			char *cond_string,
 			enum bptype type, enum bpdisp disposition,
+			struct itset *trigger_set, struct itset *stop_set,
 			int thread, int task, int ignore_count,
 			const struct breakpoint_ops *ops, int from_tty,
 			int enabled, int internal)
@@ -7445,6 +7543,7 @@ create_breakpoints_sal (struct gdbarch *gdbarch,
 			     addr_string,
 			     filter_string,
 			     cond_string, type, disposition,
+			     trigger_set, stop_set,
 			     thread, task, ignore_count, ops,
 			     from_tty, enabled, internal,
 			     canonical->special_display);
@@ -7468,7 +7567,8 @@ parse_breakpoint_sals (char **address,
 
   /* If no arg given, or if first arg is 'if ', use the default
      breakpoint.  */
-  if ((*address) == NULL
+  if (*address == NULL
+      || **address == '\0'
       || (strncmp ((*address), "if", 2) == 0 && isspace ((*address)[2])))
     {
       /* The last displayed codepoint, if it's valid, is our default breakpoint
@@ -7687,6 +7787,48 @@ decode_static_tracepoint_spec (char **arg_p)
   return sals;
 }
 
+void
+parse_breakpoint_args (char **args,
+		       struct itset **trigger_set,
+		       struct itset **stop_set)
+{
+  *trigger_set = itset_reference (current_itset);
+  if (non_stop)
+    *stop_set = itset_create_empty ();
+  else
+    *stop_set = itset_reference (*trigger_set);
+
+  if (*args != NULL)
+    {
+      char *arg = *args;
+
+      while (*arg)
+	{
+	  char *p;
+
+	  arg = skip_spaces (arg);
+	  p = skip_to_space (arg);
+
+	  if (strncmp (arg, "-stop", p - arg) == 0)
+	    {
+	      p = skip_spaces (p);
+	      itset_free (*stop_set);
+	      *stop_set = itset_create (&p);
+	      arg = p;
+	    }
+	  else if (strcmp (arg, "--") == 0)
+	    {
+	      arg += 2;
+	      break;
+	    }
+	  else
+	    break;
+	}
+
+      *args = arg;
+    }
+}
+
 /* Set a breakpoint.  This function is shared between CLI and MI
    functions for setting a breakpoint.  This function has two major
    modes of operations, selected by the PARSE_CONDITION_AND_THREAD
@@ -7714,15 +7856,24 @@ create_breakpoint (struct gdbarch *gdbarch,
   struct linespec_result canonical;
   struct cleanup *old_chain;
   struct cleanup *bkpt_chain = NULL;
+  struct cleanup *args_cleanup;
   int i;
   int pending = 0;
   int task = 0;
   int prev_bkpt_count = breakpoint_count;
+  char *p;
+  struct itset *trigger_set;
+  struct itset *stop_set;
 
   gdb_assert (ops != NULL);
 
   init_linespec_result (&canonical);
 
+  parse_breakpoint_args (&arg, &trigger_set, &stop_set);
+
+  args_cleanup = make_cleanup_itset_free (trigger_set);
+  make_cleanup_itset_free (stop_set);
+
   if (type_wanted == bp_static_tracepoint && is_marker_spec (arg))
     {
       int i;
@@ -7796,6 +7947,8 @@ create_breakpoint (struct gdbarch *gdbarch,
 
   done:
 
+  discard_cleanups (args_cleanup);
+
   /* Create a chain of things that always need to be cleaned up.  */
   old_chain = make_cleanup_destroy_linespec_result (&canonical);
 
@@ -7805,6 +7958,9 @@ create_breakpoint (struct gdbarch *gdbarch,
      then the memory is not reclaimed.  */
   bkpt_chain = make_cleanup (null_cleanup, 0);
 
+  make_cleanup_itset_free (trigger_set);
+  make_cleanup_itset_free (stop_set);
+
   /* Resolve all line numbers to PC's and verify that the addresses
      are ok for the target.  */
   if (!pending)
@@ -7887,7 +8043,7 @@ create_breakpoint (struct gdbarch *gdbarch,
 				   addr_string, NULL,
 				   cond_string, type_wanted,
 				   tempflag ? disp_del : disp_donttouch,
-				   thread, task, ignore_count, ops,
+				   NULL, NULL, thread, task, ignore_count, ops,
 				   from_tty, enabled, internal,
 				   canonical.special_display);
 	      /* Given that its possible to have multiple markers with
@@ -7907,6 +8063,7 @@ create_breakpoint (struct gdbarch *gdbarch,
 	create_breakpoints_sal (gdbarch, &canonical, cond_string,
 				type_wanted,
 				tempflag ? disp_del : disp_donttouch,
+				trigger_set, stop_set,
 				thread, task, ignore_count, ops, from_tty,
 				enabled, internal);
     }
@@ -9043,6 +9200,14 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
   int use_mask = 0;
   CORE_ADDR mask = 0;
   struct watchpoint *w;
+  struct itset *trigger_set;
+  struct itset *stop_set;
+  struct cleanup *old_chain;
+
+  parse_breakpoint_args (&arg, &trigger_set, &stop_set);
+
+  old_chain = make_cleanup_itset_free (trigger_set);
+  make_cleanup_itset_free (stop_set);
 
   /* Make sure that we actually have parameters to parse.  */
   if (arg != NULL && arg[0] != '\0')
@@ -9248,6 +9413,8 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
   else
     init_raw_breakpoint_without_location (b, NULL, bp_type,
 					  &watchpoint_breakpoint_ops);
+  b->trigger_set = trigger_set;
+  b->stop_set = stop_set;
   b->thread = thread;
   b->disposition = disp_donttouch;
   b->pspace = current_program_space;
@@ -9325,6 +9492,7 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
       throw_exception (e);
     }
 
+  discard_cleanups (old_chain);
   install_breakpoint (internal, b, 1);
 }
 
@@ -9654,6 +9822,9 @@ catch_fork_command_1 (char *arg, int from_tty,
   char *cond_string = NULL;
   catch_fork_kind fork_kind;
   int tempflag;
+  struct itset *trigger_set;
+  struct itset *stop_set;
+  struct cleanup *old_chain;
 
   fork_kind = (catch_fork_kind) (uintptr_t) get_cmd_context (command);
   tempflag = (fork_kind == catch_fork_temporary
@@ -9663,6 +9834,11 @@ catch_fork_command_1 (char *arg, int from_tty,
     arg = "";
   arg = skip_spaces (arg);
 
+  parse_breakpoint_args (&arg, &trigger_set, &stop_set);
+
+  old_chain = make_cleanup_itset_free (trigger_set);
+  make_cleanup_itset_free (stop_set);
+
   /* The allowed syntax is:
      catch [v]fork
      catch [v]fork if <cond>
@@ -9679,18 +9855,22 @@ catch_fork_command_1 (char *arg, int from_tty,
     {
     case catch_fork_temporary:
     case catch_fork_permanent:
-      create_fork_vfork_event_catchpoint (gdbarch, tempflag, cond_string,
+      create_fork_vfork_event_catchpoint (trigger_set, stop_set,
+					  gdbarch, tempflag, cond_string,
                                           &catch_fork_breakpoint_ops);
       break;
     case catch_vfork_temporary:
     case catch_vfork_permanent:
-      create_fork_vfork_event_catchpoint (gdbarch, tempflag, cond_string,
+      create_fork_vfork_event_catchpoint (trigger_set, stop_set,
+					  gdbarch, tempflag, cond_string,
                                           &catch_vfork_breakpoint_ops);
       break;
     default:
       error (_("unsupported or unknown fork kind; cannot catch it"));
       break;
     }
+
+  discard_cleanups (old_chain);
 }
 
 static void
@@ -9701,6 +9881,9 @@ catch_exec_command_1 (char *arg, int from_tty,
   struct gdbarch *gdbarch = get_current_arch ();
   int tempflag;
   char *cond_string = NULL;
+  struct itset *trigger_set;
+  struct itset *stop_set;
+  struct cleanup *old_chain;
 
   tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
 
@@ -9708,6 +9891,11 @@ catch_exec_command_1 (char *arg, int from_tty,
     arg = "";
   arg = skip_spaces (arg);
 
+  parse_breakpoint_args (&arg, &trigger_set, &stop_set);
+
+  old_chain = make_cleanup_itset_free (trigger_set);
+  make_cleanup_itset_free (stop_set);
+
   /* The allowed syntax is:
      catch exec
      catch exec if <cond>
@@ -9719,10 +9907,13 @@ catch_exec_command_1 (char *arg, int from_tty,
     error (_("Junk at end of arguments."));
 
   c = XNEW (struct exec_catchpoint);
-  init_catchpoint (&c->base, gdbarch, tempflag, cond_string,
+  init_catchpoint (&c->base, trigger_set, stop_set,
+		   gdbarch, tempflag, cond_string,
 		   &catch_exec_breakpoint_ops);
   c->exec_pathname = NULL;
 
+  discard_cleanups (old_chain);
+
   install_breakpoint (0, &c->base, 1);
 }
 
@@ -9893,6 +10084,8 @@ catch_throw_command (char *arg, int from_tty, struct cmd_list_element *command)
 
 void
 init_ada_exception_breakpoint (struct breakpoint *b,
+			       struct itset *trigger_set,
+			       struct itset *stop_set,
 			       struct gdbarch *gdbarch,
 			       struct symtab_and_line sal,
 			       char *addr_string,
@@ -9920,6 +10113,8 @@ init_ada_exception_breakpoint (struct breakpoint *b,
 
   init_raw_breakpoint (b, gdbarch, sal, bp_breakpoint, ops);
 
+  b->trigger_set = trigger_set;
+  b->stop_set = stop_set;
   b->enable_state = bp_enabled;
   b->disposition = tempflag ? disp_del : disp_donttouch;
   b->addr_string = addr_string;
@@ -9985,6 +10180,9 @@ catch_syscall_command_1 (char *arg, int from_tty,
   VEC(int) *filter;
   struct syscall s;
   struct gdbarch *gdbarch = get_current_arch ();
+  struct cleanup *old_chain;
+  struct itset *trigger_set;
+  struct itset *stop_set;
 
   /* Checking if the feature if supported.  */
   if (gdbarch_get_syscall_number_p (gdbarch) == 0)
@@ -9993,8 +10191,12 @@ this architecture yet."));
 
   tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
 
+  parse_breakpoint_args (&arg, &trigger_set, &stop_set);
   arg = skip_spaces (arg);
 
+  old_chain = make_cleanup_itset_free (trigger_set);
+  make_cleanup_itset_free (stop_set);
+
   /* We need to do this first "dummy" translation in order
      to get the syscall XML file loaded or, most important,
      to display a warning to the user if there's no XML file
@@ -10012,8 +10214,11 @@ this architecture yet."));
   else
     filter = NULL;
 
-  create_syscall_event_catchpoint (tempflag, filter,
+  create_syscall_event_catchpoint (trigger_set, stop_set,
+				   tempflag, filter,
 				   &catch_syscall_breakpoint_ops);
+
+  discard_cleanups (old_chain);
 }
 
 static void
@@ -10822,6 +11027,8 @@ base_breakpoint_dtor (struct breakpoint *self)
   xfree (self->addr_string);
   xfree (self->filter);
   xfree (self->addr_string_range_end);
+  itset_free (self->trigger_set);
+  itset_free (self->stop_set);
 }
 
 static struct bp_location *
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index ddf1881..22e7f0d 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -32,6 +32,7 @@ struct get_number_or_range_state;
 struct thread_info;
 struct bpstats;
 struct bp_location;
+struct itset;
 
 /* This is the maximum number of bytes a breakpoint instruction can
    take.  Feel free to increase it.  It's just used in a few places to
@@ -611,6 +612,15 @@ struct breakpoint
        or 0 if don't care.  */
     int task;
 
+    /* I/T set controlling where this breakpoint will stop.  */
+    struct itset *trigger_set;
+
+    /* The set that should be suspended once the breakpoint has
+       triggered.  If empty, defaults to consulting the "non-stop"
+       setting: if that is on, just the triggering thread should stop;
+       otherwise, all threads in the TRIGGER_SET set stop.  */
+    struct itset *stop_set;
+
     /* Count of the number of times this breakpoint was taken, dumped
        with the info, but not used for anything else.  Useful for
        seeing how many times you hit a break prior to the program
@@ -862,6 +872,9 @@ enum print_stop_action
 
 /* Tell what to do about this bpstat.  */
 struct bpstat_what bpstat_what (bpstat);
+
+/* Tell us what we should suspend.  */
+extern struct itset *bpstat_stop_set (bpstat);
 
 /* Find the bpstat associated with a breakpoint.  NULL otherwise.  */
 bpstat bpstat_find_breakpoint (bpstat, struct breakpoint *);
@@ -1091,6 +1104,8 @@ extern void
 
 extern void
   init_ada_exception_breakpoint (struct breakpoint *b,
+				 struct itset *trigger_set,
+				 struct itset *stop_set,
 				 struct gdbarch *gdbarch,
 				 struct symtab_and_line sal,
 				 char *addr_string,
diff --git a/gdb/infcall.c b/gdb/infcall.c
index 50f1289..19e72a7 100644
--- a/gdb/infcall.c
+++ b/gdb/infcall.c
@@ -38,6 +38,7 @@
 #include "ada-lang.h"
 #include "gdbthread.h"
 #include "exceptions.h"
+#include "itset.h"
 
 /* If we can't find a function's name from its address,
    we print this instead.  */
@@ -796,6 +797,12 @@ call_function_by_hand (struct value *function, int nargs, struct value **args)
        dummy_id to form the frame ID's stack address.  */
     bpt = set_momentary_breakpoint (gdbarch, sal, dummy_id, bp_call_dummy);
     bpt->disposition = disp_del;
+
+    bpt->trigger_set = itset_reference (current_itset);
+    if (non_stop)
+      bpt->stop_set = itset_create_empty ();
+    else
+      bpt->stop_set = itset_reference (bpt->trigger_set);
   }
 
   /* Create a breakpoint in std::terminate.
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 324329f..7f6d643 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -26,6 +26,7 @@
 #include "symtab.h"
 #include "frame.h"
 #include "inferior.h"
+#include "itset.h"
 #include "exceptions.h"
 #include "breakpoint.h"
 #include "gdb_wait.h"
@@ -2640,6 +2641,8 @@ struct execution_control_state
   char *stop_func_name;
   int new_thread_event;
   int wait_some_more;
+
+  struct itset *stop_set;
 };
 
 static void handle_inferior_event (struct execution_control_state *ecs);
@@ -2655,6 +2658,20 @@ static void stop_stepping (struct execution_control_state *ecs);
 static void prepare_to_wait (struct execution_control_state *ecs);
 static void keep_going (struct execution_control_state *ecs);
 
+static void
+ecs_destroy (struct execution_control_state *ecs)
+{
+  itset_free (ecs->stop_set);
+}
+
+static void
+ecs_destroy_cleanup (void *arg)
+{
+  struct execution_control_state *ecs = arg;
+
+  ecs_destroy (ecs);
+}
+
 /* Callback for iterate over threads.  If the thread is stopped, but
    the user/frontend doesn't know about that yet, go through
    normal_stop, as if the thread had just stopped now.  ARG points at
@@ -2685,6 +2702,8 @@ infrun_thread_stop_requested_callback (struct thread_info *info, void *arg)
 
       switch_to_thread (info->ptid);
 
+      make_cleanup (ecs_destroy_cleanup, ecs);
+
       /* Go through handle_inferior_event/normal_stop, so we always
 	 have consistent output as if the stop event had been
 	 reported.  */
@@ -2966,6 +2985,7 @@ prepare_for_detach (void)
 
   while (!ptid_equal (displaced->step_ptid, null_ptid))
     {
+      struct cleanup *ecs_chain;
       struct cleanup *old_chain_2;
       struct execution_control_state ecss;
       struct execution_control_state *ecs;
@@ -2973,6 +2993,8 @@ prepare_for_detach (void)
       ecs = &ecss;
       memset (ecs, 0, sizeof (*ecs));
 
+      ecs_chain = make_cleanup (ecs_destroy_cleanup, ecs);
+
       overlay_cache_invalid = 1;
 
       ecs->ptid = do_target_wait (pid_ptid, &ecs->ws, 0);
@@ -3008,12 +3030,14 @@ prepare_for_detach (void)
 	  discard_cleanups (old_chain_1);
 	  error (_("Program exited while detaching"));
 	}
+
+      do_cleanups (ecs_chain);
     }
 
   discard_cleanups (old_chain_1);
 }
 
-static void stop_all_threads (void);
+static void stop_all_threads (struct itset *stop_set);
 static int adjust_pc_after_break (struct thread_info *thread,
 				  struct target_waitstatus *ws);
 
@@ -3087,7 +3111,7 @@ select_event_thread (struct execution_control_state *ecs)
 {
   if (!non_stop && target_is_non_stop_p () && !stop_only_if_needed)
     {
-      stop_all_threads ();
+      stop_all_threads (NULL);
 
       if (ecs->ws.kind != TARGET_WAITKIND_NO_RESUMED
 	  && ecs->ws.kind != TARGET_WAITKIND_EXITED
@@ -3207,8 +3231,6 @@ void
 wait_for_inferior (void)
 {
   struct cleanup *old_cleanups;
-  struct execution_control_state ecss;
-  struct execution_control_state *ecs;
 
   if (debug_infrun)
     fprintf_unfiltered
@@ -3217,12 +3239,18 @@ wait_for_inferior (void)
   old_cleanups =
     make_cleanup (delete_step_thread_step_resume_breakpoint_cleanup, NULL);
 
-  ecs = &ecss;
-  memset (ecs, 0, sizeof (*ecs));
-
   while (1)
     {
+      struct execution_control_state ecss;
+      struct execution_control_state *ecs;
+      struct cleanup *ecs_chain;
       struct cleanup *old_chain;
+      int wait_some_more;
+
+      ecs = &ecss;
+      memset (ecs, 0, sizeof (*ecs));
+
+      ecs_chain = make_cleanup (ecs_destroy_cleanup, ecs);
 
       overlay_cache_invalid = 1;
 
@@ -3256,7 +3284,10 @@ wait_for_inferior (void)
       /* No error, don't finish the state yet.  */
       discard_cleanups (old_chain);
 
-      if (!ecs->wait_some_more)
+      wait_some_more = ecs->wait_some_more;
+      do_cleanups (ecs_chain);
+
+      if (!wait_some_more)
 	break;
     }
 
@@ -3284,6 +3315,8 @@ fetch_inferior_event (void *client_data)
 
   memset (ecs, 0, sizeof (*ecs));
 
+  make_cleanup (ecs_destroy_cleanup, ecs);
+
   /* We're handling a live event, so make sure we're doing live
      debugging.  If we're looking at traceframes while the target is
      running, we're going to need to get back to that mode after
@@ -3725,8 +3758,20 @@ wait_one (ptid_t wait_ptid, struct target_waitstatus *ws)
   return event_ptid;
 }
 
+static int
+stop_set_match (struct itset *stop_set, struct thread_info *t)
+{
+  if (stop_set == NULL || itset_is_empty_set (stop_set))
+    return !non_stop;
+
+  if (itset_contains_thread (stop_set, t))
+    return 1;
+
+  return 0;
+}
+
 static void
-stop_all_threads (void)
+stop_all_threads (struct itset *stop_set)
 {
   /* We may need multiple passes to discover all threads.  */
   int pass;
@@ -3756,6 +3801,7 @@ stop_all_threads (void)
 	  /* Go through all threads looking for threads that we need
 	     to tell the target to stop.  */
 	  ALL_LIVE_THREADS (t)
+	    if (stop_set_match (stop_set, t))
 	    {
 	      if (t->executing)
 		{
@@ -3800,6 +3846,11 @@ stop_all_threads (void)
 	    pass = -1;
 
 	  event_ptid = wait_one (minus_one_ptid, &ws);
+
+	  /* FIXME: if EVENT_PTID isn't in the trigger or stop sets,
+	     we'll need to re-resume or handle the event
+	     afterwards.  */
+
 	  if (ws.kind == TARGET_WAITKIND_NO_RESUMED)
 	    /* All resumed threads exited.  */
 	    ;
@@ -5276,7 +5327,11 @@ process_event_stop_test:
 	/* We are about to nuke the step_resume_breakpointt via the
 	   cleanup chain, so no need to worry about it here.  */
 
+	ecs->stop_set
+	  = bpstat_stop_set (ecs->event_thread->control.stop_bpstat);
 	stop_stepping (ecs);
+	itset_free (ecs->stop_set);
+	ecs->stop_set = NULL;
 	return;
 
       case BPSTAT_WHAT_STOP_SILENT:
@@ -5287,7 +5342,11 @@ process_event_stop_test:
 	/* We are about to nuke the step_resume_breakpoin via the
 	   cleanup chain, so no need to worry about it here.  */
 
+	ecs->stop_set
+	  = bpstat_stop_set (ecs->event_thread->control.stop_bpstat);
 	stop_stepping (ecs);
+	itset_free (ecs->stop_set);
+	ecs->stop_set = NULL;
 	return;
 
       case BPSTAT_WHAT_HP_STEP_RESUME:
@@ -6304,13 +6363,19 @@ stop_stepping (struct execution_control_state *ecs)
   /* Let callers know we don't want to wait for the inferior anymore.  */
   ecs->wait_some_more = 0;
 
-  if (!non_stop
-      && target_is_non_stop_p ()
-      && stop_only_if_needed)
+  if (target_is_non_stop_p () && stop_only_if_needed)
     {
       struct thread_info *t;
 
-      stop_all_threads ();
+      if (ecs->stop_set == NULL)
+	{
+	  if (non_stop)
+	    ecs->stop_set = itset_create_empty ();
+	  else
+	    ecs->stop_set = itset_reference (current_itset);
+	}
+
+      stop_all_threads (ecs->stop_set);
 
       cancel_breakpoints ();
 
@@ -6318,7 +6383,8 @@ stop_stepping (struct execution_control_state *ecs)
 	 are now stopped until a new resume action is sent
 	 over.  */
       ALL_LIVE_THREADS (t)
-	t->control.resumed = 0;
+	if (stop_set_match (ecs->stop_set, t))
+	  t->control.resumed = 0;
     }
 }
 
@@ -6377,7 +6443,7 @@ keep_going (struct execution_control_state *ecs)
 	      /* Since we can't do a displaced step, we have to remove
 		 the breakpoint while we step it.  To keep things
 		 simple, we remove them all.  */
-	      stop_all_threads ();
+	      stop_all_threads (NULL);
 
 	      cancel_breakpoints ();
 	      /* In all-stop, from the core's perspective, all threads


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