GDB (xrefs)
Loading...
Searching...
No Matches
break-catch-sig.c
Go to the documentation of this file.
1/* Everything about signal catchpoints, for GDB.
2
3 Copyright (C) 2011-2023 Free Software Foundation, Inc.
4
5 This file is part of GDB.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19
20#include "defs.h"
21#include "arch-utils.h"
22#include <ctype.h>
23#include "breakpoint.h"
24#include "gdbcmd.h"
25#include "inferior.h"
26#include "infrun.h"
27#include "annotate.h"
28#include "valprint.h"
29#include "cli/cli-utils.h"
30#include "completer.h"
31#include "cli/cli-style.h"
32#include "cli/cli-decode.h"
33
34#include <string>
35
36#define INTERNAL_SIGNAL(x) ((x) == GDB_SIGNAL_TRAP || (x) == GDB_SIGNAL_INT)
37
38/* An instance of this type is used to represent a signal
39 catchpoint. */
40
42{
43 signal_catchpoint (struct gdbarch *gdbarch, bool temp,
44 std::vector<gdb_signal> &&sigs,
45 bool catch_all_)
46 : catchpoint (gdbarch, temp, nullptr),
47 signals_to_be_caught (std::move (sigs)),
48 catch_all (catch_all_)
49 {
50 }
51
52 int insert_location (struct bp_location *) override;
53 int remove_location (struct bp_location *,
54 enum remove_bp_reason reason) override;
55 int breakpoint_hit (const struct bp_location *bl,
56 const address_space *aspace,
57 CORE_ADDR bp_addr,
58 const target_waitstatus &ws) override;
59 enum print_stop_action print_it (const bpstat *bs) const override;
60 bool print_one (bp_location **) const override;
61 void print_mention () const override;
62 void print_recreate (struct ui_file *fp) const override;
63 bool explains_signal (enum gdb_signal) override;
64
65 /* Signal numbers used for the 'catch signal' feature. If no signal
66 has been specified for filtering, it is empty. Otherwise,
67 it holds a list of all signals to be caught. */
68
69 std::vector<gdb_signal> signals_to_be_caught;
70
71 /* If SIGNALS_TO_BE_CAUGHT is empty, then all "ordinary" signals are
72 caught. If CATCH_ALL is true, then internal signals are caught
73 as well. If SIGNALS_TO_BE_CAUGHT is not empty, then this field
74 is ignored. */
75
77};
78
79/* Count of each signal. */
80
81static unsigned int signal_catch_counts[GDB_SIGNAL_LAST];
82
83
84
85/* A convenience wrapper for gdb_signal_to_name that returns the
86 integer value if the name is not known. */
87
88static const char *
89signal_to_name_or_int (enum gdb_signal sig)
90{
91 const char *result = gdb_signal_to_name (sig);
92
93 if (strcmp (result, "?") == 0)
94 result = plongest (sig);
95
96 return result;
97}
98
99
100
101/* Implement the "insert_location" method for signal catchpoints. */
102
103int
105{
106 struct signal_catchpoint *c = (struct signal_catchpoint *) bl->owner;
107
108 if (!c->signals_to_be_caught.empty ())
109 {
110 for (gdb_signal iter : c->signals_to_be_caught)
111 ++signal_catch_counts[iter];
112 }
113 else
114 {
115 for (int i = 0; i < GDB_SIGNAL_LAST; ++i)
116 {
117 if (c->catch_all || !INTERNAL_SIGNAL (i))
119 }
120 }
121
123
124 return 0;
125}
126
127/* Implement the "remove_location" method for signal catchpoints. */
128
129int
131 enum remove_bp_reason reason)
132{
133 struct signal_catchpoint *c = (struct signal_catchpoint *) bl->owner;
134
135 if (!c->signals_to_be_caught.empty ())
136 {
137 for (gdb_signal iter : c->signals_to_be_caught)
138 {
139 gdb_assert (signal_catch_counts[iter] > 0);
140 --signal_catch_counts[iter];
141 }
142 }
143 else
144 {
145 for (int i = 0; i < GDB_SIGNAL_LAST; ++i)
146 {
147 if (c->catch_all || !INTERNAL_SIGNAL (i))
148 {
149 gdb_assert (signal_catch_counts[i] > 0);
151 }
152 }
153 }
154
156
157 return 0;
158}
159
160/* Implement the "breakpoint_hit" method for signal catchpoints. */
161
162int
164 const address_space *aspace,
165 CORE_ADDR bp_addr,
166 const target_waitstatus &ws)
167{
168 const struct signal_catchpoint *c
169 = (const struct signal_catchpoint *) bl->owner;
170 gdb_signal signal_number;
171
172 if (ws.kind () != TARGET_WAITKIND_STOPPED)
173 return 0;
174
175 signal_number = ws.sig ();
176
177 /* If we are catching specific signals in this breakpoint, then we
178 must guarantee that the called signal is the same signal we are
179 catching. */
180 if (!c->signals_to_be_caught.empty ())
181 {
182 for (gdb_signal iter : c->signals_to_be_caught)
183 if (signal_number == iter)
184 return 1;
185 /* Not the same. */
186 return 0;
187 }
188 else
189 return c->catch_all || !INTERNAL_SIGNAL (signal_number);
190}
191
192/* Implement the "print_it" method for signal catchpoints. */
193
196{
197 struct target_waitstatus last;
198 const char *signal_name;
199 struct ui_out *uiout = current_uiout;
200
201 get_last_target_status (nullptr, nullptr, &last);
202
203 signal_name = signal_to_name_or_int (last.sig ());
204
207
208 gdb_printf (_("Catchpoint %d (signal %s), "), number, signal_name);
209
210 return PRINT_SRC_AND_LOC;
211}
212
213/* Implement the "print_one" method for signal catchpoints. */
214
215bool
217{
218 struct value_print_options opts;
219 struct ui_out *uiout = current_uiout;
220
222
223 /* Field 4, the address, is omitted (which makes the columns
224 not line up too nicely with the headers, but the effect
225 is relatively readable). */
226 if (opts.addressprint)
227 uiout->field_skip ("addr");
228 annotate_field (5);
229
230 if (signals_to_be_caught.size () > 1)
231 uiout->text ("signals \"");
232 else
233 uiout->text ("signal \"");
234
235 if (!signals_to_be_caught.empty ())
236 {
237 std::string text;
238
239 bool first = true;
240 for (gdb_signal iter : signals_to_be_caught)
241 {
242 const char *name = signal_to_name_or_int (iter);
243
244 if (!first)
245 text += " ";
246 first = false;
247
248 text += name;
249 }
250 uiout->field_string ("what", text);
251 }
252 else
253 uiout->field_string ("what",
254 catch_all ? "<any signal>" : "<standard signals>",
256 uiout->text ("\" ");
257
258 if (uiout->is_mi_like_p ())
259 uiout->field_string ("catch-type", "signal");
260
261 return true;
262}
263
264/* Implement the "print_mention" method for signal catchpoints. */
265
266void
268{
269 if (!signals_to_be_caught.empty ())
270 {
271 if (signals_to_be_caught.size () > 1)
272 gdb_printf (_("Catchpoint %d (signals"), number);
273 else
274 gdb_printf (_("Catchpoint %d (signal"), number);
275
276 for (gdb_signal iter : signals_to_be_caught)
277 {
278 const char *name = signal_to_name_or_int (iter);
279
280 gdb_printf (" %s", name);
281 }
282 gdb_printf (")");
283 }
284 else if (catch_all)
285 gdb_printf (_("Catchpoint %d (any signal)"), number);
286 else
287 gdb_printf (_("Catchpoint %d (standard signals)"), number);
288}
289
290/* Implement the "print_recreate" method for signal catchpoints. */
291
292void
294{
295 gdb_printf (fp, "catch signal");
296
297 if (!signals_to_be_caught.empty ())
298 {
299 for (gdb_signal iter : signals_to_be_caught)
300 gdb_printf (fp, " %s", signal_to_name_or_int (iter));
301 }
302 else if (catch_all)
303 gdb_printf (fp, " all");
304 gdb_putc ('\n', fp);
305}
306
307/* Implement the "explains_signal" method for signal catchpoints. */
308
309bool
311{
312 return true;
313}
314
315/* Create a new signal catchpoint. TEMPFLAG is true if this should be
316 a temporary catchpoint. FILTER is the list of signals to catch; it
317 can be empty, meaning all signals. CATCH_ALL is a flag indicating
318 whether signals used internally by gdb should be caught; it is only
319 valid if FILTER is NULL. If FILTER is empty and CATCH_ALL is zero,
320 then internal signals like SIGTRAP are not caught. */
321
322static void
323create_signal_catchpoint (int tempflag, std::vector<gdb_signal> &&filter,
324 bool catch_all)
325{
326 struct gdbarch *gdbarch = get_current_arch ();
327
328 std::unique_ptr<signal_catchpoint> c
329 (new signal_catchpoint (gdbarch, tempflag, std::move (filter), catch_all));
330
331 install_breakpoint (0, std::move (c), 1);
332}
333
334
335/* Splits the argument using space as delimiter. Returns a filter
336 list, which is empty if no filtering is required. */
337
338static std::vector<gdb_signal>
339catch_signal_split_args (const char *arg, bool *catch_all)
340{
341 std::vector<gdb_signal> result;
342 bool first = true;
343
344 while (*arg != '\0')
345 {
346 int num;
347 gdb_signal signal_number;
348 char *endptr;
349
350 std::string one_arg = extract_arg (&arg);
351 if (one_arg.empty ())
352 break;
353
354 /* Check for the special flag "all". */
355 if (one_arg == "all")
356 {
357 arg = skip_spaces (arg);
358 if (*arg != '\0' || !first)
359 error (_("'all' cannot be caught with other signals"));
360 *catch_all = true;
361 gdb_assert (result.empty ());
362 return result;
363 }
364
365 first = false;
366
367 /* Check if the user provided a signal name or a number. */
368 num = (int) strtol (one_arg.c_str (), &endptr, 0);
369 if (*endptr == '\0')
370 signal_number = gdb_signal_from_command (num);
371 else
372 {
373 signal_number = gdb_signal_from_name (one_arg.c_str ());
374 if (signal_number == GDB_SIGNAL_UNKNOWN)
375 error (_("Unknown signal name '%s'."), one_arg.c_str ());
376 }
377
378 result.push_back (signal_number);
379 }
380
381 result.shrink_to_fit ();
382 return result;
383}
384
385/* Implement the "catch signal" command. */
386
387static void
388catch_signal_command (const char *arg, int from_tty,
389 struct cmd_list_element *command)
390{
391 int tempflag;
392 bool catch_all = false;
393 std::vector<gdb_signal> filter;
394
395 tempflag = command->context () == CATCH_TEMPORARY;
396
397 arg = skip_spaces (arg);
398
399 /* The allowed syntax is:
400 catch signal
401 catch signal <name | number> [<name | number> ... <name | number>]
402
403 Let's check if there's a signal name. */
404
405 if (arg != NULL)
406 filter = catch_signal_split_args (arg, &catch_all);
407
408 create_signal_catchpoint (tempflag, std::move (filter), catch_all);
409}
410
412void
414{
415 add_catch_command ("signal", _("\
416Catch signals by their names and/or numbers.\n\
417Usage: catch signal [[NAME|NUMBER] [NAME|NUMBER]...|all]\n\
418Arguments say which signals to catch. If no arguments\n\
419are given, every \"normal\" signal will be caught.\n\
420The argument \"all\" means to also catch signals used by GDB.\n\
421Arguments, if given, should be one or more signal names\n\
422(if your system supports that), or signal numbers."),
427}
const char *const name
void annotate_field(int num)
Definition annotate.c:173
void annotate_catchpoint(int num)
Definition annotate.c:83
struct gdbarch * get_current_arch(void)
Definition arch-utils.c:846
static void create_signal_catchpoint(int tempflag, std::vector< gdb_signal > &&filter, bool catch_all)
static void catch_signal_command(const char *arg, int from_tty, struct cmd_list_element *command)
static std::vector< gdb_signal > catch_signal_split_args(const char *arg, bool *catch_all)
static unsigned int signal_catch_counts[GDB_SIGNAL_LAST]
#define INTERNAL_SIGNAL(x)
static const char * signal_to_name_or_int(enum gdb_signal sig)
void _initialize_break_catch_sig()
void add_catch_command(const char *name, const char *docstring, cmd_func_ftype *func, completer_ftype *completer, void *user_data_catch, void *user_data_tcatch)
void install_breakpoint(int internal, std::unique_ptr< breakpoint > &&arg, int update_gll)
void maybe_print_thread_hit_breakpoint(struct ui_out *uiout)
#define CATCH_PERMANENT
#define CATCH_TEMPORARY
print_stop_action
Definition breakpoint.h:543
@ PRINT_SRC_AND_LOC
Definition breakpoint.h:549
remove_bp_reason
Definition breakpoint.h:64
breakpoint * owner
Definition breakpoint.h:350
ui_file_style style() const
Definition cli-style.c:169
void field_string(const char *fldname, const char *string, const ui_file_style &style=ui_file_style())
Definition ui-out.c:511
void field_skip(const char *fldname)
Definition ui-out.c:499
void text(const char *string)
Definition ui-out.c:566
bool is_mi_like_p() const
Definition ui-out.c:810
cli_style_option metadata_style
std::string extract_arg(const char **arg)
Definition cli-utils.c:383
void signal_completer(struct cmd_list_element *ignore, completion_tracker &tracker, const char *text, const char *word)
Definition completer.c:1756
enum gdb_signal gdb_signal_from_command(int num)
Definition infrun.c:9064
void get_last_target_status(process_stratum_target **target, ptid_t *ptid, target_waitstatus *status)
Definition infrun.c:4345
void signal_catch_update(const unsigned int *info)
Definition infrun.c:8836
Definition aarch64.h:50
void * context() const
Definition cli-decode.h:109
int breakpoint_hit(const struct bp_location *bl, const address_space *aspace, CORE_ADDR bp_addr, const target_waitstatus &ws) override
int remove_location(struct bp_location *, enum remove_bp_reason reason) override
enum print_stop_action print_it(const bpstat *bs) const override
int insert_location(struct bp_location *) override
void print_mention() const override
signal_catchpoint(struct gdbarch *gdbarch, bool temp, std::vector< gdb_signal > &&sigs, bool catch_all_)
std::vector< gdb_signal > signals_to_be_caught
void print_recreate(struct ui_file *fp) const override
bool explains_signal(enum gdb_signal) override
bool print_one(bp_location **) const override
enum gdb_signal sig
Definition waitstatus.h:414
target_waitkind kind() const
Definition waitstatus.h:345
#define current_uiout
Definition ui-out.h:40
void gdb_putc(int c)
Definition utils.c:1841
void gdb_printf(struct ui_file *stream, const char *format,...)
Definition utils.c:1865
void get_user_print_options(struct value_print_options *opts)
Definition valprint.c:128
@ TARGET_WAITKIND_STOPPED
Definition waitstatus.h:36