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