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