xref: /netbsd-src/external/gpl3/gdb/dist/gdb/break-catch-sig.c (revision 9fb66d812c00ebfb445c0b47dea128f32aa6fe96)
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 
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 
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 }
448