]> Git Repo - binutils.git/blob - gdb/break-catch-sig.c
gdb: remove COMPUNIT_BLOCKVECTOR macro, add getter/setter
[binutils.git] / gdb / break-catch-sig.c
1 /* Everything about signal catchpoints, for GDB.
2
3    Copyright (C) 2011-2022 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 catchpoint.
39    A breakpoint is really of this type iff its ops pointer points to
40    SIGNAL_CATCHPOINT_OPS.  */
41
42 struct signal_catchpoint : public breakpoint
43 {
44   /* Signal numbers used for the 'catch signal' feature.  If no signal
45      has been specified for filtering, it is empty.  Otherwise,
46      it holds a list of all signals to be caught.  */
47
48   std::vector<gdb_signal> signals_to_be_caught;
49
50   /* If SIGNALS_TO_BE_CAUGHT is empty, then all "ordinary" signals are
51      caught.  If CATCH_ALL is true, then internal signals are caught
52      as well.  If SIGNALS_TO_BE_CAUGHT is not empty, then this field
53      is ignored.  */
54
55   bool catch_all;
56 };
57
58 /* The breakpoint_ops structure to be used in signal catchpoints.  */
59
60 static struct breakpoint_ops signal_catchpoint_ops;
61
62 /* Count of each signal.  */
63
64 static unsigned int signal_catch_counts[GDB_SIGNAL_LAST];
65
66 \f
67
68 /* A convenience wrapper for gdb_signal_to_name that returns the
69    integer value if the name is not known.  */
70
71 static const char *
72 signal_to_name_or_int (enum gdb_signal sig)
73 {
74   const char *result = gdb_signal_to_name (sig);
75
76   if (strcmp (result, "?") == 0)
77     result = plongest (sig);
78
79   return result;
80 }
81
82 \f
83
84 /* Implement the "insert_location" breakpoint_ops method for signal
85    catchpoints.  */
86
87 static int
88 signal_catchpoint_insert_location (struct bp_location *bl)
89 {
90   struct signal_catchpoint *c = (struct signal_catchpoint *) bl->owner;
91
92   if (!c->signals_to_be_caught.empty ())
93     {
94       for (gdb_signal iter : c->signals_to_be_caught)
95         ++signal_catch_counts[iter];
96     }
97   else
98     {
99       for (int i = 0; i < GDB_SIGNAL_LAST; ++i)
100         {
101           if (c->catch_all || !INTERNAL_SIGNAL (i))
102             ++signal_catch_counts[i];
103         }
104     }
105
106   signal_catch_update (signal_catch_counts);
107
108   return 0;
109 }
110
111 /* Implement the "remove_location" breakpoint_ops method for signal
112    catchpoints.  */
113
114 static int
115 signal_catchpoint_remove_location (struct bp_location *bl,
116                                    enum remove_bp_reason reason)
117 {
118   struct signal_catchpoint *c = (struct signal_catchpoint *) bl->owner;
119
120   if (!c->signals_to_be_caught.empty ())
121     {
122       for (gdb_signal iter : c->signals_to_be_caught)
123         {
124           gdb_assert (signal_catch_counts[iter] > 0);
125           --signal_catch_counts[iter];
126         }
127     }
128   else
129     {
130       for (int i = 0; i < GDB_SIGNAL_LAST; ++i)
131         {
132           if (c->catch_all || !INTERNAL_SIGNAL (i))
133             {
134               gdb_assert (signal_catch_counts[i] > 0);
135               --signal_catch_counts[i];
136             }
137         }
138     }
139
140   signal_catch_update (signal_catch_counts);
141
142   return 0;
143 }
144
145 /* Implement the "breakpoint_hit" breakpoint_ops method for signal
146    catchpoints.  */
147
148 static int
149 signal_catchpoint_breakpoint_hit (const struct bp_location *bl,
150                                   const address_space *aspace,
151                                   CORE_ADDR bp_addr,
152                                   const target_waitstatus &ws)
153 {
154   const struct signal_catchpoint *c
155     = (const struct signal_catchpoint *) bl->owner;
156   gdb_signal signal_number;
157
158   if (ws.kind () != TARGET_WAITKIND_STOPPED)
159     return 0;
160
161   signal_number = ws.sig ();
162
163   /* If we are catching specific signals in this breakpoint, then we
164      must guarantee that the called signal is the same signal we are
165      catching.  */
166   if (!c->signals_to_be_caught.empty ())
167     {
168       for (gdb_signal iter : c->signals_to_be_caught)
169         if (signal_number == iter)
170           return 1;
171       /* Not the same.  */
172       return 0;
173     }
174   else
175     return c->catch_all || !INTERNAL_SIGNAL (signal_number);
176 }
177
178 /* Implement the "print_it" breakpoint_ops method for signal
179    catchpoints.  */
180
181 static enum print_stop_action
182 signal_catchpoint_print_it (bpstat *bs)
183 {
184   struct breakpoint *b = bs->breakpoint_at;
185   struct target_waitstatus last;
186   const char *signal_name;
187   struct ui_out *uiout = current_uiout;
188
189   get_last_target_status (nullptr, nullptr, &last);
190
191   signal_name = signal_to_name_or_int (last.sig ());
192
193   annotate_catchpoint (b->number);
194   maybe_print_thread_hit_breakpoint (uiout);
195
196   printf_filtered (_("Catchpoint %d (signal %s), "), b->number, signal_name);
197
198   return PRINT_SRC_AND_LOC;
199 }
200
201 /* Implement the "print_one" breakpoint_ops method for signal
202    catchpoints.  */
203
204 static void
205 signal_catchpoint_print_one (struct breakpoint *b,
206                              struct bp_location **last_loc)
207 {
208   struct signal_catchpoint *c = (struct signal_catchpoint *) b;
209   struct value_print_options opts;
210   struct ui_out *uiout = current_uiout;
211
212   get_user_print_options (&opts);
213
214   /* Field 4, the address, is omitted (which makes the columns
215      not line up too nicely with the headers, but the effect
216      is relatively readable).  */
217   if (opts.addressprint)
218     uiout->field_skip ("addr");
219   annotate_field (5);
220
221   if (c->signals_to_be_caught.size () > 1)
222     uiout->text ("signals \"");
223   else
224     uiout->text ("signal \"");
225
226   if (!c->signals_to_be_caught.empty ())
227     {
228       std::string text;
229
230       bool first = true;
231       for (gdb_signal iter : c->signals_to_be_caught)
232         {
233           const char *name = signal_to_name_or_int (iter);
234
235           if (!first)
236             text += " ";
237           first = false;
238
239           text += name;
240         }
241       uiout->field_string ("what", text);
242     }
243   else
244     uiout->field_string ("what",
245                          c->catch_all ? "<any signal>" : "<standard signals>",
246                          metadata_style.style ());
247   uiout->text ("\" ");
248
249   if (uiout->is_mi_like_p ())
250     uiout->field_string ("catch-type", "signal");
251 }
252
253 /* Implement the "print_mention" breakpoint_ops method for signal
254    catchpoints.  */
255
256 static void
257 signal_catchpoint_print_mention (struct breakpoint *b)
258 {
259   struct signal_catchpoint *c = (struct signal_catchpoint *) b;
260
261   if (!c->signals_to_be_caught.empty ())
262     {
263       if (c->signals_to_be_caught.size () > 1)
264         printf_filtered (_("Catchpoint %d (signals"), b->number);
265       else
266         printf_filtered (_("Catchpoint %d (signal"), b->number);
267
268       for (gdb_signal iter : c->signals_to_be_caught)
269         {
270           const char *name = signal_to_name_or_int (iter);
271
272           printf_filtered (" %s", name);
273         }
274       printf_filtered (")");
275     }
276   else if (c->catch_all)
277     printf_filtered (_("Catchpoint %d (any signal)"), b->number);
278   else
279     printf_filtered (_("Catchpoint %d (standard signals)"), b->number);
280 }
281
282 /* Implement the "print_recreate" breakpoint_ops method for signal
283    catchpoints.  */
284
285 static void
286 signal_catchpoint_print_recreate (struct breakpoint *b, struct ui_file *fp)
287 {
288   struct signal_catchpoint *c = (struct signal_catchpoint *) b;
289
290   fprintf_unfiltered (fp, "catch signal");
291
292   if (!c->signals_to_be_caught.empty ())
293     {
294       for (gdb_signal iter : c->signals_to_be_caught)
295         fprintf_unfiltered (fp, " %s", signal_to_name_or_int (iter));
296     }
297   else if (c->catch_all)
298     fprintf_unfiltered (fp, " all");
299   fputc_unfiltered ('\n', fp);
300 }
301
302 /* Implement the "explains_signal" breakpoint_ops method for signal
303    catchpoints.  */
304
305 static int
306 signal_catchpoint_explains_signal (struct breakpoint *b, enum gdb_signal sig)
307 {
308   return 1;
309 }
310
311 /* Create a new signal catchpoint.  TEMPFLAG is true if this should be
312    a temporary catchpoint.  FILTER is the list of signals to catch; it
313    can be empty, meaning all signals.  CATCH_ALL is a flag indicating
314    whether signals used internally by gdb should be caught; it is only
315    valid if FILTER is NULL.  If FILTER is empty and CATCH_ALL is zero,
316    then internal signals like SIGTRAP are not caught.  */
317
318 static void
319 create_signal_catchpoint (int tempflag, std::vector<gdb_signal> &&filter,
320                           bool catch_all)
321 {
322   struct gdbarch *gdbarch = get_current_arch ();
323
324   std::unique_ptr<signal_catchpoint> c (new signal_catchpoint ());
325   init_catchpoint (c.get (), gdbarch, tempflag, NULL, &signal_catchpoint_ops);
326   c->signals_to_be_caught = std::move (filter);
327   c->catch_all = catch_all;
328
329   install_breakpoint (0, std::move (c), 1);
330 }
331
332
333 /* Splits the argument using space as delimiter.  Returns a filter
334    list, which is empty if no filtering is required.  */
335
336 static std::vector<gdb_signal>
337 catch_signal_split_args (const char *arg, bool *catch_all)
338 {
339   std::vector<gdb_signal> result;
340   bool first = true;
341
342   while (*arg != '\0')
343     {
344       int num;
345       gdb_signal signal_number;
346       char *endptr;
347
348       std::string one_arg = extract_arg (&arg);
349       if (one_arg.empty ())
350         break;
351
352       /* Check for the special flag "all".  */
353       if (one_arg == "all")
354         {
355           arg = skip_spaces (arg);
356           if (*arg != '\0' || !first)
357             error (_("'all' cannot be caught with other signals"));
358           *catch_all = true;
359           gdb_assert (result.empty ());
360           return result;
361         }
362
363       first = false;
364
365       /* Check if the user provided a signal name or a number.  */
366       num = (int) strtol (one_arg.c_str (), &endptr, 0);
367       if (*endptr == '\0')
368         signal_number = gdb_signal_from_command (num);
369       else
370         {
371           signal_number = gdb_signal_from_name (one_arg.c_str ());
372           if (signal_number == GDB_SIGNAL_UNKNOWN)
373             error (_("Unknown signal name '%s'."), one_arg.c_str ());
374         }
375
376       result.push_back (signal_number);
377     }
378
379   result.shrink_to_fit ();
380   return result;
381 }
382
383 /* Implement the "catch signal" command.  */
384
385 static void
386 catch_signal_command (const char *arg, int from_tty,
387                       struct cmd_list_element *command)
388 {
389   int tempflag;
390   bool catch_all = false;
391   std::vector<gdb_signal> filter;
392
393   tempflag = command->context () == CATCH_TEMPORARY;
394
395   arg = skip_spaces (arg);
396
397   /* The allowed syntax is:
398      catch signal
399      catch signal <name | number> [<name | number> ... <name | number>]
400
401      Let's check if there's a signal name.  */
402
403   if (arg != NULL)
404     filter = catch_signal_split_args (arg, &catch_all);
405
406   create_signal_catchpoint (tempflag, std::move (filter), catch_all);
407 }
408
409 static void
410 initialize_signal_catchpoint_ops (void)
411 {
412   struct breakpoint_ops *ops;
413
414   initialize_breakpoint_ops ();
415
416   ops = &signal_catchpoint_ops;
417   *ops = base_breakpoint_ops;
418   ops->insert_location = signal_catchpoint_insert_location;
419   ops->remove_location = signal_catchpoint_remove_location;
420   ops->breakpoint_hit = signal_catchpoint_breakpoint_hit;
421   ops->print_it = signal_catchpoint_print_it;
422   ops->print_one = signal_catchpoint_print_one;
423   ops->print_mention = signal_catchpoint_print_mention;
424   ops->print_recreate = signal_catchpoint_print_recreate;
425   ops->explains_signal = signal_catchpoint_explains_signal;
426 }
427
428 void _initialize_break_catch_sig ();
429 void
430 _initialize_break_catch_sig ()
431 {
432   initialize_signal_catchpoint_ops ();
433
434   add_catch_command ("signal", _("\
435 Catch signals by their names and/or numbers.\n\
436 Usage: catch signal [[NAME|NUMBER] [NAME|NUMBER]...|all]\n\
437 Arguments say which signals to catch.  If no arguments\n\
438 are given, every \"normal\" signal will be caught.\n\
439 The argument \"all\" means to also catch signals used by GDB.\n\
440 Arguments, if given, should be one or more signal names\n\
441 (if your system supports that), or signal numbers."),
442                      catch_signal_command,
443                      signal_completer,
444                      CATCH_PERMANENT,
445                      CATCH_TEMPORARY);
446 }
This page took 0.09176 seconds and 4 git commands to generate.