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