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]

Re: About catching signal


On Friday 09 September 2011 16:11:09, Pedro Alves wrote:
> On Friday 09 September 2011 16:03:43, Abhijit Halder wrote:
> > Hi,
> > 
> > I was browsing through the internet and found that a bug (Bug 7221) is
> > already filed for this feature. I am interested to know whether this
> > is already implemented or somebody is working on this feature. If not,
> > I am planning to start with this.
> 
> I've got a 90% done patch for that.  Let me look for it...

Here is is.  3 patches actually.  The first two lay the path to
be able to pass down the current event's waitstatus down through 
bpstat_stop_status to the catchpoint's breakpoint_hit callbacks.
The third actually implements the feature.  It looks like:

(top-gdb) catch signal 5
Catchpoint 6 (signal 5)
(top-gdb) commands 
Type commands for breakpoint(s) 6, one per line.
End with a line saying just "end".
>echo caught!\n
>end
(top-gdb) n

Catchpoint 6 (signal 5), 0x0000000000451431 in main (argc=1, argv=0x7fffffffe068) at ../../src/gdb/gdb.c:30
30        memset (&args, 0, sizeof args);
caught!
(top-gdb) 

You'll notice the catch signal code looks a lot like the catch
syscalls code.  That's because I started out with mostly
copy&pasting the syscalls code.  There's certainly cruft
in there.  :-)

This is missing being able to specify signals by name, and,
there's no integration with "handle" presently.  E.g, if
the user says "handle FOO pass nostop noprint", then the
linux target backend will report stops for FOO signal
to the core.  We'll need to make infrun.c:signal_pass
(for target_pass_signals) consider FOO due to "catch signal FOO"
somehow.  It also lacks documentation, of course.  :-)

(I wrote this as a proof of concept for some special
catchpoints for an unsubmitted target support, and it
was catchpoints like these that mostly drove the recent
breakpoint changes that made catchpoints implementable
outside of breakpoint.c.)

-- 
Pedro Alves
2011-09-09  Pedro Alves  <pedro@codesourcery.com>

	gdb/
	* breakpoint.c (bpstat_check_location, bpstat_stop_status) : Add
	`ws' parameter, and pass it down.
	(breakpoint_hit_catch_fork, breakpoint_hit_catch_vfork)
	(breakpoint_hit_catch_syscall, breakpoint_hit_catch_exec): Add
	`ws' parameter.
	(breakpoint_hit_ranged_breakpoint): Add `ws' parameter.  Return
	false for events other than TARGET_SIGNAL_TRAP.
	(breakpoint_hit_watchpoint, base_breakpoint_breakpoint_hit):
	Add `ws' parameter.
	(bkpt_breakpoint_hit): Add `ws' parameter.  Return false for
	events other than TARGET_SIGNAL_TRAP.
	(tracepoint_breakpoint_hit): Add `ws' parameter.
	* breakpoint.h (struct breakpoint_ops) <breakpoint_hit>: Add `ws'
	parameter.
	(bpstat_stop_status): Same.
	* infrun.c (handle_syscall_event, handle_inferior_event): Adjust
	to pass the current event's waitstatus to bpstat_stop_status.

---
 gdb/breakpoint.c |   45 ++++++++++++++++++++++++++++++++-------------
 gdb/breakpoint.h |    5 +++--
 gdb/infrun.c     |   11 ++++++-----
 3 files changed, 41 insertions(+), 20 deletions(-)

Index: src/gdb/breakpoint.c
===================================================================
--- src.orig/gdb/breakpoint.c	2011-09-09 16:17:32.000000000 +0100
+++ src/gdb/breakpoint.c	2011-09-09 16:33:26.509763222 +0100
@@ -3749,14 +3749,15 @@ which its expression is valid.\n");
 
 static int
 bpstat_check_location (const struct bp_location *bl,
-		       struct address_space *aspace, CORE_ADDR bp_addr)
+		       struct address_space *aspace, CORE_ADDR bp_addr,
+		       struct target_waitstatus *ws)
 {
   struct breakpoint *b = bl->owner;
 
   /* BL is from an existing breakpoint.  */
   gdb_assert (b != NULL);
 
-  return b->ops->breakpoint_hit (bl, aspace, bp_addr);
+  return b->ops->breakpoint_hit (bl, aspace, bp_addr, ws);
 }
 
 /* Determine if the watched values have actually changed, and we
@@ -4066,7 +4067,8 @@ bpstat_check_breakpoint_conditions (bpst
 
 bpstat
 bpstat_stop_status (struct address_space *aspace,
-		    CORE_ADDR bp_addr, ptid_t ptid)
+		    CORE_ADDR bp_addr, ptid_t ptid,
+		    struct target_waitstatus *ws)
 {
   struct breakpoint *b = NULL;
   struct bp_location *bl;
@@ -4104,7 +4106,7 @@ bpstat_stop_status (struct address_space
 	  if (bl->shlib_disabled)
 	    continue;
 
-	  if (!bpstat_check_location (bl, aspace, bp_addr))
+	  if (!bpstat_check_location (bl, aspace, bp_addr, ws))
 	    continue;
 
 	  /* Come here if it's a watchpoint, or if the break address
@@ -6163,7 +6165,8 @@ remove_catch_fork (struct bp_location *b
 
 static int
 breakpoint_hit_catch_fork (const struct bp_location *bl,
-			   struct address_space *aspace, CORE_ADDR bp_addr)
+			   struct address_space *aspace, CORE_ADDR bp_addr,
+			   struct target_waitstatus *ws)
 {
   struct fork_catchpoint *c = (struct fork_catchpoint *) bl->owner;
 
@@ -6259,7 +6262,8 @@ remove_catch_vfork (struct bp_location *
 
 static int
 breakpoint_hit_catch_vfork (const struct bp_location *bl,
-			    struct address_space *aspace, CORE_ADDR bp_addr)
+			    struct address_space *aspace, CORE_ADDR bp_addr,
+			    struct target_waitstatus *ws)
 {
   struct fork_catchpoint *c = (struct fork_catchpoint *) bl->owner;
 
@@ -6450,7 +6454,8 @@ remove_catch_syscall (struct bp_location
 
 static int
 breakpoint_hit_catch_syscall (const struct bp_location *bl,
-			      struct address_space *aspace, CORE_ADDR bp_addr)
+			      struct address_space *aspace, CORE_ADDR bp_addr,
+			      struct target_waitstatus *ws)
 {
   /* We must check if we are catching specific syscalls in this
      breakpoint.  If we are, then we must guarantee that the called
@@ -6750,7 +6755,8 @@ remove_catch_exec (struct bp_location *b
 
 static int
 breakpoint_hit_catch_exec (const struct bp_location *bl,
-			   struct address_space *aspace, CORE_ADDR bp_addr)
+			   struct address_space *aspace, CORE_ADDR bp_addr,
+			   struct target_waitstatus *ws)
 {
   struct exec_catchpoint *c = (struct exec_catchpoint *) bl->owner;
 
@@ -8169,8 +8175,13 @@ stopat_command (char *arg, int from_tty)
 static int
 breakpoint_hit_ranged_breakpoint (const struct bp_location *bl,
 				  struct address_space *aspace,
-				  CORE_ADDR bp_addr)
+				  CORE_ADDR bp_addr,
+				  struct target_waitstatus *ws)
 {
+  if (ws->kind != TARGET_WAITKIND_STOPPED
+      || ws->value.sig != TARGET_SIGNAL_TRAP)
+    return 0;
+
   return breakpoint_address_match_range (bl->pspace->aspace, bl->address,
 					 bl->length, aspace, bp_addr);
 }
@@ -8646,7 +8657,8 @@ remove_watchpoint (struct bp_location *b
 
 static int
 breakpoint_hit_watchpoint (const struct bp_location *bl,
-			   struct address_space *aspace, CORE_ADDR bp_addr)
+			   struct address_space *aspace, CORE_ADDR bp_addr,
+			   struct target_waitstatus *ws)
 {
   struct breakpoint *b = bl->owner;
   struct watchpoint *w = (struct watchpoint *) b;
@@ -10779,7 +10791,8 @@ base_breakpoint_remove_location (struct
 static int
 base_breakpoint_breakpoint_hit (const struct bp_location *bl,
 				struct address_space *aspace,
-				CORE_ADDR bp_addr)
+				CORE_ADDR bp_addr,
+				struct target_waitstatus *ws)
 {
   internal_error_pure_virtual_called ();
 }
@@ -10893,10 +10906,15 @@ bkpt_remove_location (struct bp_location
 
 static int
 bkpt_breakpoint_hit (const struct bp_location *bl,
-		     struct address_space *aspace, CORE_ADDR bp_addr)
+		     struct address_space *aspace, CORE_ADDR bp_addr,
+		     struct target_waitstatus *ws)
 {
   struct breakpoint *b = bl->owner;
 
+  if (ws->kind != TARGET_WAITKIND_STOPPED
+      || ws->value.sig != TARGET_SIGNAL_TRAP)
+    return 0;
+
   if (!breakpoint_address_match (bl->pspace->aspace, bl->address,
 				 aspace, bp_addr))
     return 0;
@@ -11146,7 +11164,8 @@ tracepoint_re_set (struct breakpoint *b)
 
 static int
 tracepoint_breakpoint_hit (const struct bp_location *bl,
-			   struct address_space *aspace, CORE_ADDR bp_addr)
+			   struct address_space *aspace, CORE_ADDR bp_addr,
+			   struct target_waitstatus *ws)
 {
   /* By definition, the inferior does not report stops at
      tracepoints.  */
Index: src/gdb/breakpoint.h
===================================================================
--- src.orig/gdb/breakpoint.h	2011-09-09 16:17:33.139763056 +0100
+++ src/gdb/breakpoint.h	2011-09-09 16:33:26.519763222 +0100
@@ -436,7 +436,7 @@ struct breakpoint_ops
      breakpoint location BL.  This function does not check if we
      should stop, only if BL explains the stop.  */
   int (*breakpoint_hit) (const struct bp_location *bl, struct address_space *,
-			 CORE_ADDR);
+			 CORE_ADDR, struct target_waitstatus *);
 
   /* Check internal conditions of the breakpoint referred to by BS.
      If we should not stop for this breakpoint, set BS->stop to 0.  */
@@ -736,7 +736,8 @@ extern void bpstat_clear (bpstat *);
 extern bpstat bpstat_copy (bpstat);
 
 extern bpstat bpstat_stop_status (struct address_space *aspace,
-				  CORE_ADDR pc, ptid_t ptid);
+				  CORE_ADDR pc, ptid_t ptid,
+				  struct target_waitstatus *ws);
 
 /* This bpstat_what stuff tells wait_for_inferior what to do with a
    breakpoint (a challenging task).
Index: src/gdb/infrun.c
===================================================================
--- src.orig/gdb/infrun.c	2011-09-09 16:17:43.379763058 +0100
+++ src/gdb/infrun.c	2011-09-09 16:33:26.519763222 +0100
@@ -3080,7 +3080,7 @@ handle_syscall_event (struct execution_c
 
       ecs->event_thread->control.stop_bpstat
 	= bpstat_stop_status (get_regcache_aspace (regcache),
-			      stop_pc, ecs->ptid);
+			      stop_pc, ecs->ptid, &ecs->ws);
       ecs->random_signal
 	= !bpstat_explains_signal (ecs->event_thread->control.stop_bpstat);
 
@@ -3449,7 +3449,7 @@ handle_inferior_event (struct execution_
 
       ecs->event_thread->control.stop_bpstat
 	= bpstat_stop_status (get_regcache_aspace (get_current_regcache ()),
-			      stop_pc, ecs->ptid);
+			      stop_pc, ecs->ptid, &ecs->ws);
 
       /* Note that we're interested in knowing the bpstat actually
 	 causes a stop, not just if it may explain the signal.
@@ -3547,7 +3547,7 @@ handle_inferior_event (struct execution_
 
       ecs->event_thread->control.stop_bpstat
 	= bpstat_stop_status (get_regcache_aspace (get_current_regcache ()),
-			      stop_pc, ecs->ptid);
+			      stop_pc, ecs->ptid, &ecs->ws);
       ecs->random_signal
 	= !bpstat_explains_signal (ecs->event_thread->control.stop_bpstat);
 
@@ -4085,10 +4085,11 @@ handle_inferior_event (struct execution_
 	  return;
 	}
 
-      /* See if there is a breakpoint at the current PC.  */
+      /* See if there is a breakpoint/watchpoint/catchpoint/etc. that
+	 handles this signal.  */
       ecs->event_thread->control.stop_bpstat
 	= bpstat_stop_status (get_regcache_aspace (get_current_regcache ()),
-			      stop_pc, ecs->ptid);
+			      stop_pc, ecs->ptid, &ecs->ws);
 
       /* Following in case break condition called a
 	 function.  */
2011-09-09  Pedro Alves  <pedro@codesourcery.com>

	gdb/
	* breakpoint.c (breakpoint_hit_catch_fork)
	(breakpoint_hit_catch_vfork, breakpoint_hit_catch_syscall)
	(breakpoint_hit_catch_exec): Make use of the `ws' argument.
	* infrun.c (inferior_has_forked, inferior_has_vforked)
	(inferior_has_execd, inferior_has_called_syscall): Delete.

---
 gdb/breakpoint.c |   23 ++++++++++++++---
 gdb/infrun.c     |   72 -------------------------------------------------------
 2 files changed, 19 insertions(+), 76 deletions(-)

Index: src/gdb/breakpoint.c
===================================================================
--- src.orig/gdb/breakpoint.c	2011-09-09 16:33:26.509763222 +0100
+++ src/gdb/breakpoint.c	2011-09-09 16:33:44.299763226 +0100
@@ -6170,7 +6170,11 @@ breakpoint_hit_catch_fork (const struct
 {
   struct fork_catchpoint *c = (struct fork_catchpoint *) bl->owner;
 
-  return inferior_has_forked (inferior_ptid, &c->forked_inferior_pid);
+  if (ws->kind != TARGET_WAITKIND_FORKED)
+    return 0;
+
+  c->forked_inferior_pid = ws->value.related_pid;
+  return 1;
 }
 
 /* Implement the "print_it" breakpoint_ops method for fork
@@ -6267,7 +6271,11 @@ breakpoint_hit_catch_vfork (const struct
 {
   struct fork_catchpoint *c = (struct fork_catchpoint *) bl->owner;
 
-  return inferior_has_vforked (inferior_ptid, &c->forked_inferior_pid);
+  if (ws->kind != TARGET_WAITKIND_VFORKED)
+    return 0;
+
+  c->forked_inferior_pid = ws->value.related_pid;
+  return 1;
 }
 
 /* Implement the "print_it" breakpoint_ops method for vfork
@@ -6464,9 +6472,12 @@ breakpoint_hit_catch_syscall (const stru
   const struct syscall_catchpoint *c
     = (const struct syscall_catchpoint *) bl->owner;
 
-  if (!inferior_has_called_syscall (inferior_ptid, &syscall_number))
+  if (ws->kind != TARGET_WAITKIND_SYSCALL_ENTRY
+      && ws->kind != TARGET_WAITKIND_SYSCALL_RETURN)
     return 0;
 
+  syscall_number = ws->value.syscall_number;
+
   /* Now, checking if the syscall is the same.  */
   if (c->syscalls_to_be_caught)
     {
@@ -6760,7 +6771,11 @@ breakpoint_hit_catch_exec (const struct
 {
   struct exec_catchpoint *c = (struct exec_catchpoint *) bl->owner;
 
-  return inferior_has_execd (inferior_ptid, &c->exec_pathname);
+  if (ws->kind != TARGET_WAITKIND_EXECD)
+    return 0;
+
+  c->exec_pathname = xstrdup (ws->value.execd_pathname);
+  return 1;
 }
 
 static enum print_stop_action
Index: src/gdb/infrun.c
===================================================================
--- src.orig/gdb/infrun.c	2011-09-09 16:33:26.519763222 +0100
+++ src/gdb/infrun.c	2011-09-09 16:33:44.299763226 +0100
@@ -6744,78 +6744,6 @@ discard_infcall_control_state (struct in
   xfree (inf_status);
 }
 
-int
-inferior_has_forked (ptid_t pid, ptid_t *child_pid)
-{
-  struct target_waitstatus last;
-  ptid_t last_ptid;
-
-  get_last_target_status (&last_ptid, &last);
-
-  if (last.kind != TARGET_WAITKIND_FORKED)
-    return 0;
-
-  if (!ptid_equal (last_ptid, pid))
-    return 0;
-
-  *child_pid = last.value.related_pid;
-  return 1;
-}
-
-int
-inferior_has_vforked (ptid_t pid, ptid_t *child_pid)
-{
-  struct target_waitstatus last;
-  ptid_t last_ptid;
-
-  get_last_target_status (&last_ptid, &last);
-
-  if (last.kind != TARGET_WAITKIND_VFORKED)
-    return 0;
-
-  if (!ptid_equal (last_ptid, pid))
-    return 0;
-
-  *child_pid = last.value.related_pid;
-  return 1;
-}
-
-int
-inferior_has_execd (ptid_t pid, char **execd_pathname)
-{
-  struct target_waitstatus last;
-  ptid_t last_ptid;
-
-  get_last_target_status (&last_ptid, &last);
-
-  if (last.kind != TARGET_WAITKIND_EXECD)
-    return 0;
-
-  if (!ptid_equal (last_ptid, pid))
-    return 0;
-
-  *execd_pathname = xstrdup (last.value.execd_pathname);
-  return 1;
-}
-
-int
-inferior_has_called_syscall (ptid_t pid, int *syscall_number)
-{
-  struct target_waitstatus last;
-  ptid_t last_ptid;
-
-  get_last_target_status (&last_ptid, &last);
-
-  if (last.kind != TARGET_WAITKIND_SYSCALL_ENTRY &&
-      last.kind != TARGET_WAITKIND_SYSCALL_RETURN)
-    return 0;
-
-  if (!ptid_equal (last_ptid, pid))
-    return 0;
-
-  *syscall_number = last.value.syscall_number;
-  return 1;
-}
 
 int
 ptid_match (ptid_t ptid, ptid_t filter)
2011-09-09  Pedro Alves  <pedro@codesourcery.com>

	gdb/
	* breakpoint.c (base_breakpoint_ops, init_catchpoint)
	(base_breakpoint_ops): Make extern.
	* infrun.c (handle_inferior_event): Always run all signals through
	bpstat_stop_status.  If a random signal is explained by a
	breakpoint, clear stop_signal to TARGET_SIGNAL_0, not
	TARGET_SIGNAL_TRAP.
	* break-catch-sig.c: New file.
	* Makefile.in (COMMON_OBS): Add break-catch-sig.o.
	* breakpoint.h (base_breakpoint_ops, init_catchpoint): Declare.

---
 gdb/Makefile.in       |    2 
 gdb/break-catch-sig.c |  541 ++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/breakpoint.c      |    6 
 gdb/breakpoint.h      |    6 
 gdb/infrun.c          |   13 -
 5 files changed, 553 insertions(+), 15 deletions(-)

Index: src/gdb/breakpoint.c
===================================================================
--- src.orig/gdb/breakpoint.c	2011-09-09 16:46:34.529763360 +0100
+++ src/gdb/breakpoint.c	2011-09-09 16:49:42.569763393 +0100
@@ -237,7 +237,7 @@ static int is_masked_watchpoint (const s
 
 /* The abstract base class all breakpoint_ops structures inherit
    from.  */
-static struct breakpoint_ops base_breakpoint_ops;
+struct breakpoint_ops base_breakpoint_ops;
 
 /* The breakpoint_ops structure to be inherited by all breakpoint_ops
    that are implemented on top of software or hardware breakpoints
@@ -6678,7 +6678,7 @@ syscall_catchpoint_p (struct breakpoint
    not NULL, then store it in the breakpoint.  OPS, if not NULL, is
    the breakpoint_ops structure associated to the catchpoint.  */
 
-static void
+void
 init_catchpoint (struct breakpoint *b,
 		 struct gdbarch *gdbarch, int tempflag,
 		 char *cond_string,
@@ -10861,7 +10861,7 @@ base_breakpoint_print_recreate (struct b
   internal_error_pure_virtual_called ();
 }
 
-static struct breakpoint_ops base_breakpoint_ops =
+struct breakpoint_ops base_breakpoint_ops =
 {
   base_breakpoint_dtor,
   base_breakpoint_allocate_location,
Index: src/gdb/infrun.c
===================================================================
--- src.orig/gdb/infrun.c	2011-09-09 16:46:34.539763360 +0100
+++ src/gdb/infrun.c	2011-09-09 16:49:42.569763393 +0100
@@ -4031,9 +4031,7 @@ handle_inferior_event (struct execution_
      3) set ecs->random_signal to 1, and the decision between 1 and 2
      will be made according to the signal handling tables.  */
 
-  if (ecs->event_thread->suspend.stop_signal == TARGET_SIGNAL_TRAP
-      || stop_soon == STOP_QUIETLY || stop_soon == STOP_QUIETLY_NO_SIGSTOP
-      || stop_soon == STOP_QUIETLY_REMOTE)
+  if (1)
     {
       if (ecs->event_thread->suspend.stop_signal == TARGET_SIGNAL_TRAP
 	  && stop_after_trap)
@@ -4144,17 +4142,10 @@ handle_inferior_event (struct execution_
 	  ecs->random_signal = !bpstat_explains_signal
 				     (ecs->event_thread->control.stop_bpstat);
 	  if (!ecs->random_signal)
-	    ecs->event_thread->suspend.stop_signal = TARGET_SIGNAL_TRAP;
+	    ecs->event_thread->suspend.stop_signal = TARGET_SIGNAL_0;
 	}
     }
 
-  /* When we reach this point, we've pretty much decided
-     that the reason for stopping must've been a random
-     (unexpected) signal.  */
-
-  else
-    ecs->random_signal = 1;
-
 process_event_stop_test:
 
   /* Re-fetch current thread's frame in case we did a
Index: src/gdb/break-catch-sig.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ src/gdb/break-catch-sig.c	2011-09-09 16:49:42.569763393 +0100
@@ -0,0 +1,541 @@
+/* Everything about signal catchpoints, for GDB.
+
+   Copyright (C) 2011 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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 "defs.h"
+#include "arch-utils.h"
+#include <ctype.h>
+#include "breakpoint.h"
+#include "gdbcmd.h"
+#include "inferior.h"
+#include "annotate.h"
+#include "valprint.h"
+#include "cli/cli-utils.h"
+
+/* An instance of this type is used to represent a signal catchpoint.
+   It includes a "struct breakpoint" as a kind of base class; users
+   downcast to "struct breakpoint *" when needed.  A breakpoint is
+   really of this type iff its ops pointer points to
+   SIGNAL_CATCHPOINT_OPS.  */
+
+struct signal_catchpoint
+{
+  /* The base class.  */
+  struct breakpoint base;
+
+  /* Signal numbers used for the 'catch signal' feature.  If no signal
+     has been specified for filtering, its value is NULL.  Otherwise,
+     it holds a list of all signals to be caught.  The list elements
+     are allocated with xmalloc.  */
+  VEC(int) *signals_to_be_caught;
+};
+
+/* The breakpoint_ops structure to be used in signal catchpoints.  */
+
+static struct breakpoint_ops signal_catchpoint_ops;
+
+struct signal_catch_info
+{
+  /* We keep a count of the number of times the user has requested a
+     particular signal to be tracked, and pass this information to the
+     target.  This lets capable targets implement filtering
+     directly.  */
+
+  /* Number of times that "any" signal is requested.  */
+  int any_signal_count;
+
+  /* Count of each signal.  */
+  VEC(int) *signals_counts;
+
+  /* This counts all signal catch requests, so we can readily
+     determine if any catching is necessary.  */
+  int total_signals_count;
+};
+
+static struct signal_catch_info signal_catch_info;
+
+/* Implement the "dtor" breakpoint_ops method for signal
+   catchpoints.  */
+
+static void
+signal_catchpoint_dtor (struct breakpoint *b)
+{
+  struct signal_catchpoint *c = (struct signal_catchpoint *) b;
+
+  VEC_free (int, c->signals_to_be_caught);
+
+  base_breakpoint_ops.dtor (b);
+}
+
+/* Implement the "insert_location" breakpoint_ops method for signal
+   catchpoints.  */
+
+static int
+signal_catchpoint_insert_location (struct bp_location *bl)
+{
+  struct signal_catchpoint *c = (void *) bl->owner;
+  struct signal_catch_info *info = &signal_catch_info;
+
+  ++info->total_signals_count;
+  if (!c->signals_to_be_caught)
+    ++info->any_signal_count;
+  else
+    {
+      int i, iter;
+
+      for (i = 0;
+           VEC_iterate (int, c->signals_to_be_caught, i, iter);
+           i++)
+	{
+          int elem;
+
+	  if (iter >= VEC_length (int, info->signals_counts))
+	    {
+              int old_size = VEC_length (int, info->signals_counts);
+              uintptr_t vec_addr_offset = old_size * ((uintptr_t) sizeof (int));
+              uintptr_t vec_addr;
+              VEC_safe_grow (int, info->signals_counts, iter + 1);
+              vec_addr = (uintptr_t) VEC_address (int, info->signals_counts) +
+		vec_addr_offset;
+              memset ((void *) vec_addr, 0,
+                      (iter + 1 - old_size) * sizeof (int));
+	    }
+          elem = VEC_index (int, info->signals_counts, iter);
+          VEC_replace (int, info->signals_counts, iter, ++elem);
+	}
+    }
+
+  /* ???: How does this interact with "handle" ?  */
+
+#if 0
+  target_set_signal_catchpoint (PIDGET (inferior_ptid),
+				 inf->total_signals_count != 0,
+				 inf->any_signal_count,
+				 VEC_length (int, inf->signals_counts),
+				 VEC_address (int, inf->signals_counts));
+#endif
+  return 0;
+}
+
+/* Implement the "remove_location" breakpoint_ops method for signal
+   catchpoints.  */
+
+static int
+signal_catchpoint_remove_location (struct bp_location *bl)
+{
+  struct signal_catchpoint *c = (void *) bl->owner;
+  struct signal_catch_info *info = &signal_catch_info;
+
+  --info->total_signals_count;
+  if (!c->signals_to_be_caught)
+    --info->any_signal_count;
+  else
+    {
+      int i, iter;
+
+      for (i = 0;
+           VEC_iterate (int, c->signals_to_be_caught, i, iter);
+           i++)
+	{
+          int elem;
+	  if (iter >= VEC_length (int, info->signals_counts))
+	    /* Shouldn't happen.  */
+	    continue;
+          elem = VEC_index (int, info->signals_counts, iter);
+          VEC_replace (int, info->signals_counts, iter, --elem);
+        }
+    }
+
+  /* ???: How does this interact with "handle" ?  */
+
+  return 0;
+
+#if 0
+  return target_set_signal_catchpoint (PIDGET (inferior_ptid),
+					inf->total_signals_count != 0,
+					inf->any_signal_count,
+					VEC_length (int, inf->signals_counts),
+					VEC_address (int, inf->signals_counts));
+#endif
+}
+
+/* Implement the "breakpoint_hit" breakpoint_ops method for signal
+   catchpoints.  */
+
+static int
+signal_catchpoint_breakpoint_hit (const struct bp_location *bl,
+				  struct address_space *aspace,
+				  CORE_ADDR bp_addr,
+				  struct target_waitstatus *ws)
+{
+  const struct signal_catchpoint *c = (void *) bl->owner;
+  int signal_number;
+
+  if (ws->kind != TARGET_WAITKIND_STOPPED)
+    return 0;
+
+  /* FIXME: host vs target mixup.  */
+  signal_number = ws->value.sig;
+
+  /* If we are catching specific signals in this breakpoint, then we
+     must guarantee that the called signal is the same signal we are
+     catching.  */
+  if (c->signals_to_be_caught)
+    {
+      int i, iter;
+
+      for (i = 0;
+           VEC_iterate (int, c->signals_to_be_caught, i, iter);
+           i++)
+	if (signal_number == iter)
+	  break;
+      /* Not the same.  */
+      if (!iter)
+	return 0;
+    }
+
+  return 1;
+}
+
+struct signal
+{
+  /* The signal number.  */
+  int number;
+
+  /* The signal name.  */
+  const char *name;
+};
+
+void
+get_signal_by_number (int signal_number,
+		      struct signal *s)
+{
+  s->number = signal_number;
+  s->name = NULL;
+}
+
+/* Implement the "print_it" breakpoint_ops method for signal
+   catchpoints.  */
+
+static enum print_stop_action
+signal_catchpoint_print_it (bpstat bs)
+{
+  struct breakpoint *b = bs->breakpoint_at;
+  ptid_t ptid;
+  struct target_waitstatus last;
+  struct signal s;
+  struct cleanup *old_chain;
+  char *signal_id;
+
+  get_last_target_status (&ptid, &last);
+
+  get_signal_by_number (last.value.sig, &s);
+
+  annotate_catchpoint (b->number);
+
+  if (s.name == NULL)
+    signal_id = xstrprintf ("%d", last.value.sig);
+  else
+    signal_id = xstrprintf ("'%s'", s.name);
+
+  old_chain = make_cleanup (xfree, signal_id);
+  printf_filtered (_("\nCatchpoint %d (signal %s), "), b->number, signal_id);
+
+  do_cleanups (old_chain);
+
+  return PRINT_SRC_AND_LOC;
+}
+
+/* Implement the "print_one" breakpoint_ops method for signal
+   catchpoints.  */
+
+static void
+signal_catchpoint_print_one (struct breakpoint *b,
+			     struct bp_location **last_loc)
+{
+  struct signal_catchpoint *c = (void *) b;
+  struct value_print_options opts;
+  struct ui_out *uiout = current_uiout;
+
+  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)
+    ui_out_field_skip (uiout, "addr");
+  annotate_field (5);
+
+  if (c->signals_to_be_caught
+      && VEC_length (int, c->signals_to_be_caught) > 1)
+    ui_out_text (uiout, "signals \"");
+  else
+    ui_out_text (uiout, "signal \"");
+
+  if (c->signals_to_be_caught)
+    {
+      int i, iter;
+      char *text = xstrprintf ("%s", "");
+
+      for (i = 0;
+           VEC_iterate (int, c->signals_to_be_caught, i, iter);
+           i++)
+        {
+          char *x = text;
+          struct signal s;
+
+          get_signal_by_number (iter, &s);
+
+          if (s.name != NULL)
+            text = xstrprintf ("%s%s, ", text, s.name);
+          else
+            text = xstrprintf ("%s%d, ", text, iter);
+
+          /* We have to xfree the last 'text' (now stored at 'x')
+             because xstrprintf dinamically allocates new space for it
+             on every call.  */
+	  xfree (x);
+        }
+      /* Remove the last comma.  */
+      text[strlen (text) - 2] = '\0';
+      ui_out_field_string (uiout, "what", text);
+    }
+  else
+    ui_out_field_string (uiout, "what", "<any signal>");
+  ui_out_text (uiout, "\" ");
+}
+
+/* Implement the "print_mention" breakpoint_ops method for signal
+   catchpoints.  */
+
+static void
+signal_catchpoint_print_mention (struct breakpoint *b)
+{
+  struct signal_catchpoint *c = (void *) b;
+
+  if (c->signals_to_be_caught)
+    {
+      int i, iter;
+
+      if (VEC_length (int, c->signals_to_be_caught) > 1)
+        printf_filtered (_("Catchpoint %d (signals"), b->number);
+      else
+        printf_filtered (_("Catchpoint %d (signal"), b->number);
+
+      for (i = 0;
+           VEC_iterate (int, c->signals_to_be_caught, i, iter);
+           i++)
+        {
+          struct signal s;
+
+          get_signal_by_number (iter, &s);
+
+          if (s.name)
+            printf_filtered (" '%s' [%d]", s.name, s.number);
+          else
+            printf_filtered (" %d", s.number);
+        }
+      printf_filtered (")");
+    }
+  else
+    printf_filtered (_("Catchpoint %d (any signal)"),
+                     b->number);
+}
+
+/* Implement the "print_recreate" breakpoint_ops method for signal
+   catchpoints.  */
+
+static void
+signal_catchpoint_print_recreate (struct breakpoint *b, struct ui_file *fp)
+{
+  struct signal_catchpoint *c = (void *) b;
+
+  fprintf_unfiltered (fp, "catch signal");
+
+  if (c->signals_to_be_caught)
+    {
+      int i, iter;
+
+      for (i = 0;
+           VEC_iterate (int, c->signals_to_be_caught, i, iter);
+           i++)
+        {
+          struct signal s;
+
+          get_signal_by_number (iter, &s);
+          if (s.name)
+            fprintf_unfiltered (fp, " %s", s.name);
+          else
+            fprintf_unfiltered (fp, " %d", s.number);
+        }
+    }
+}
+
+static void
+create_signal_catchpoint (int tempflag, VEC(int) *filter)
+{
+  struct signal_catchpoint *c;
+  struct gdbarch *gdbarch = get_current_arch ();
+
+  c = XNEW (struct signal_catchpoint);
+  init_catchpoint (&c->base, gdbarch, tempflag, NULL, &signal_catchpoint_ops);
+  c->signals_to_be_caught = filter;
+
+  install_breakpoint (0, &c->base);
+}
+
+
+/* Splits the argument using space as delimiter.  Returns an xmalloc'd
+   filter list, or NULL if no filtering is required.  */
+static VEC(int) *
+catch_signal_split_args (char *arg)
+{
+  VEC(int) *result = NULL;
+  struct cleanup *cleanup = make_cleanup (VEC_cleanup (int), &result);
+
+  while (*arg != '\0')
+    {
+      int i, signal_number;
+      char *endptr;
+      char cur_name[128];
+      struct signal s;
+
+      /* Skip whitespace.  */
+      while (isspace (*arg))
+	arg++;
+
+      for (i = 0; i < 127 && arg[i] && !isspace (arg[i]); ++i)
+	cur_name[i] = arg[i];
+      cur_name[i] = '\0';
+      arg += i;
+
+      /* Check if the user provided a signal name or a number.  */
+      signal_number = (int) strtol (cur_name, &endptr, 0);
+      if (*endptr == '\0')
+	get_signal_by_number (signal_number, &s);
+      else
+	{
+	  /* We have a name.  Let's check if it's valid and convert it
+	     to a number.  */
+#if 0
+	  get_signal_by_name (cur_name, &s);
+	  if (s.number == UNKNOWN_SIGNAL)
+	    /* Here we have to issue an error instead of a warning,
+	       because GDB cannot do anything useful if there's no
+	       signal number to be caught.  */
+#endif
+	    error (_("Unknown signal name '%s'."), cur_name);
+	}
+
+     /* Ok, it's valid.  */
+      VEC_safe_push (int, result, s.number);
+   }
+
+  discard_cleanups (cleanup);
+  return result;
+}
+
+/* Complete signal names.  Used by "catch signal".  */
+static char **
+catch_signal_completer (struct cmd_list_element *cmd,
+			char *text, char *word)
+{
+#if 0
+  const char **list = get_signal_names ();
+#else
+  const char **list = NULL;
+#endif
+
+  return (list == NULL) ? NULL : complete_on_enum (list, text, word);
+}
+
+/* Implement the "catch signal" command.  */
+
+static void
+catch_signal_command (char *arg, int from_tty,
+		      struct cmd_list_element *command)
+{
+  int tempflag;
+  VEC(int) *filter;
+  struct signal s;
+  struct gdbarch *gdbarch = get_current_arch ();
+
+#if 0
+  /* Checking if the feature if supported.  */
+  if (gdbarch_get_signal_number_p (gdbarch) == 0)
+    error (_("The feature 'catch signal' is not supported on \
+this architeture yet."));
+#endif
+
+  tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
+
+  arg = skip_spaces (arg);
+
+  /* We need to do this first "dummy" translation in order to get the
+     signal XML file loaded or, most important, to display a warning
+     to the user if there's no XML file for his/her architecture.  */
+  get_signal_by_number (0, &s);
+
+  /* The allowed syntax is:
+     catch signal
+     catch signal <name | number> [<name | number> ... <name | number>]
+
+     Let's check if there's a signal name.  */
+
+  if (arg != NULL)
+    filter = catch_signal_split_args (arg);
+  else
+    filter = NULL;
+
+  create_signal_catchpoint (tempflag, filter);
+}
+
+static void
+initialize_signal_catchpoint_ops (void)
+{
+  struct breakpoint_ops *ops;
+
+  initialize_breakpoint_ops ();
+
+  ops = &signal_catchpoint_ops;
+  *ops = base_breakpoint_ops;
+  ops->dtor = signal_catchpoint_dtor;
+  ops->insert_location = signal_catchpoint_insert_location;
+  ops->remove_location = signal_catchpoint_remove_location;
+  ops->breakpoint_hit = signal_catchpoint_breakpoint_hit;
+  ops->print_it = signal_catchpoint_print_it;
+  ops->print_one = signal_catchpoint_print_one;
+  ops->print_mention = signal_catchpoint_print_mention;
+  ops->print_recreate = signal_catchpoint_print_recreate;
+}
+
+void
+_initialize_break_catch_sig (void)
+{
+  initialize_signal_catchpoint_ops ();
+
+  add_catch_command ("signal", _("\
+Catch signals by their names and/or numbers.\n\
+Arguments say which signals to catch.  If no arguments\n\
+are given, every signal will be caught.\n\
+Arguments, if given, should be one or more signal names\n\
+(if your system supports that), or signal numbers."),
+		     catch_signal_command,
+		     catch_signal_completer,
+		     CATCH_PERMANENT,
+		     CATCH_TEMPORARY);
+}
Index: src/gdb/Makefile.in
===================================================================
--- src.orig/gdb/Makefile.in	2011-09-09 16:41:07.479763303 +0100
+++ src/gdb/Makefile.in	2011-09-09 16:49:42.569763393 +0100
@@ -855,7 +855,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $
 	addrmap.o \
 	auxv.o \
 	bfd-target.o \
-	blockframe.o breakpoint.o findvar.o regcache.o \
+	blockframe.o break-catch-sig.o breakpoint.o findvar.o regcache.o \
 	charset.o continuations.o disasm.o dummy-frame.o dfp.o \
 	source.o value.o eval.o valops.o valarith.o valprint.o printcmd.o \
 	block.o symtab.o psymtab.o symfile.o symmisc.o linespec.o dictionary.o \
Index: src/gdb/breakpoint.h
===================================================================
--- src.orig/gdb/breakpoint.h	2011-09-09 16:41:08.819763303 +0100
+++ src/gdb/breakpoint.h	2011-09-09 16:49:42.579763393 +0100
@@ -1063,6 +1063,7 @@ extern void awatch_command_wrapper (char
 extern void rwatch_command_wrapper (char *, int, int);
 extern void tbreak_command (char *, int);
 
+extern struct breakpoint_ops base_breakpoint_ops;
 extern struct breakpoint_ops bkpt_breakpoint_ops;
 
 extern void initialize_breakpoint_ops (void);
@@ -1095,6 +1096,11 @@ extern void
 				 int tempflag,
 				 int from_tty);
 
+extern void init_catchpoint (struct breakpoint *b,
+			     struct gdbarch *gdbarch, int tempflag,
+			     char *cond_string,
+			     const struct breakpoint_ops *ops);
+
 /* Add breakpoint B on the breakpoint list, and notify the user, the
    target and breakpoint_created observers of its existence.  If
    INTERNAL is non-zero, the breakpoint number will be allocated from

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