From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 32403 invoked by alias); 9 Sep 2011 16:06:51 -0000 Received: (qmail 32380 invoked by uid 22791); 9 Sep 2011 16:06:45 -0000 X-SWARE-Spam-Status: No, hits=-0.5 required=5.0 tests=AWL,BAYES_50,TO_NO_BRKTS_PCNT X-Spam-Check-By: sourceware.org Received: from relay1.mentorg.com (HELO relay1.mentorg.com) (192.94.38.131) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Fri, 09 Sep 2011 16:06:24 +0000 Received: from nat-dem.mentorg.com ([195.212.93.2] helo=eu2-mail.mgc.mentorg.com) by relay1.mentorg.com with esmtp id 1R23ax-00035W-I1 from pedro_alves@mentor.com ; Fri, 09 Sep 2011 09:06:24 -0700 Received: from scottsdale.localnet ([172.16.63.104]) by eu2-mail.mgc.mentorg.com with Microsoft SMTPSVC(6.0.3790.4675); Fri, 9 Sep 2011 18:06:21 +0200 From: Pedro Alves To: gdb-patches@sourceware.org Subject: Re: About catching signal Date: Fri, 09 Sep 2011 18:36:00 -0000 User-Agent: KMail/1.13.6 (Linux/2.6.38-11-generic; KDE/4.7.0; x86_64; ; ) Cc: Abhijit Halder References: <201109091611.09373.pedro@codesourcery.com> In-Reply-To: <201109091611.09373.pedro@codesourcery.com> MIME-Version: 1.0 Content-Type: Multipart/Mixed; boundary="Boundary-00=_6ljaOtFiDrkXOYx" Message-Id: <201109091706.18869.pedro@codesourcery.com> X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2011-09/txt/msg00165.txt.bz2 --Boundary-00=_6ljaOtFiDrkXOYx Content-Type: Text/Plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit Content-length: 1927 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 --Boundary-00=_6ljaOtFiDrkXOYx Content-Type: text/x-patch; charset="UTF-8"; name="1-ws.diff" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="1-ws.diff" Content-length: 8919 2011-09-09 Pedro Alves 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) : 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. */ --Boundary-00=_6ljaOtFiDrkXOYx Content-Type: text/x-patch; charset="UTF-8"; name="2-cleanup_others.diff" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="2-cleanup_others.diff" Content-length: 4210 2011-09-09 Pedro Alves 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) --Boundary-00=_6ljaOtFiDrkXOYx Content-Type: text/x-patch; charset="UTF-8"; name="3-catch_signals.diff" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="3-catch_signals.diff" Content-length: 20161 2011-09-09 Pedro Alves 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 . */ + +#include "defs.h" +#include "arch-utils.h" +#include +#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", ""); + 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 [ ... ] + + 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 --Boundary-00=_6ljaOtFiDrkXOYx--