Commit | Line | Data |
---|---|---|
ab04a2af TT |
1 | /* Everything about signal catchpoints, for GDB. |
2 | ||
b811d2c2 | 3 | Copyright (C) 2011-2020 Free Software Foundation, Inc. |
ab04a2af TT |
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" | |
d55e5aa6 | 21 | #include "arch-utils.h" |
4de283e4 | 22 | #include <ctype.h> |
ab04a2af TT |
23 | #include "breakpoint.h" |
24 | #include "gdbcmd.h" | |
25 | #include "inferior.h" | |
45741a9c | 26 | #include "infrun.h" |
4de283e4 | 27 | #include "annotate.h" |
ab04a2af | 28 | #include "valprint.h" |
4de283e4 TT |
29 | #include "cli/cli-utils.h" |
30 | #include "completer.h" | |
7f6aba03 | 31 | #include "cli/cli-style.h" |
4de283e4 TT |
32 | |
33 | #include <string> | |
ab04a2af TT |
34 | |
35 | #define INTERNAL_SIGNAL(x) ((x) == GDB_SIGNAL_TRAP || (x) == GDB_SIGNAL_INT) | |
36 | ||
ab04a2af | 37 | /* An instance of this type is used to represent a signal catchpoint. |
c1fc2657 | 38 | A breakpoint is really of this type iff its ops pointer points to |
ab04a2af TT |
39 | SIGNAL_CATCHPOINT_OPS. */ |
40 | ||
c1fc2657 | 41 | struct signal_catchpoint : public breakpoint |
ab04a2af | 42 | { |
ab04a2af | 43 | /* Signal numbers used for the 'catch signal' feature. If no signal |
f746a154 | 44 | has been specified for filtering, it is empty. Otherwise, |
ab04a2af TT |
45 | it holds a list of all signals to be caught. */ |
46 | ||
f746a154 | 47 | std::vector<gdb_signal> signals_to_be_caught; |
ab04a2af | 48 | |
f746a154 TT |
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. */ | |
ab04a2af | 53 | |
f746a154 | 54 | bool catch_all; |
ab04a2af TT |
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 | ||
ab04a2af TT |
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 | { | |
9a3c8263 | 89 | struct signal_catchpoint *c = (struct signal_catchpoint *) bl->owner; |
ab04a2af | 90 | |
f746a154 | 91 | if (!c->signals_to_be_caught.empty ()) |
ab04a2af | 92 | { |
f746a154 | 93 | for (gdb_signal iter : c->signals_to_be_caught) |
ab04a2af TT |
94 | ++signal_catch_counts[iter]; |
95 | } | |
96 | else | |
97 | { | |
f746a154 | 98 | for (int i = 0; i < GDB_SIGNAL_LAST; ++i) |
ab04a2af TT |
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 | |
73971819 PA |
114 | signal_catchpoint_remove_location (struct bp_location *bl, |
115 | enum remove_bp_reason reason) | |
ab04a2af | 116 | { |
9a3c8263 | 117 | struct signal_catchpoint *c = (struct signal_catchpoint *) bl->owner; |
ab04a2af | 118 | |
f746a154 | 119 | if (!c->signals_to_be_caught.empty ()) |
ab04a2af | 120 | { |
f746a154 | 121 | for (gdb_signal iter : c->signals_to_be_caught) |
ab04a2af TT |
122 | { |
123 | gdb_assert (signal_catch_counts[iter] > 0); | |
124 | --signal_catch_counts[iter]; | |
125 | } | |
126 | } | |
127 | else | |
128 | { | |
f746a154 | 129 | for (int i = 0; i < GDB_SIGNAL_LAST; ++i) |
ab04a2af TT |
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, | |
bd522513 | 149 | const address_space *aspace, |
ab04a2af TT |
150 | CORE_ADDR bp_addr, |
151 | const struct target_waitstatus *ws) | |
152 | { | |
9a3c8263 SM |
153 | const struct signal_catchpoint *c |
154 | = (const struct signal_catchpoint *) bl->owner; | |
f746a154 | 155 | gdb_signal signal_number; |
ab04a2af TT |
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. */ | |
f746a154 | 165 | if (!c->signals_to_be_caught.empty ()) |
ab04a2af | 166 | { |
f746a154 | 167 | for (gdb_signal iter : c->signals_to_be_caught) |
ab04a2af | 168 | if (signal_number == iter) |
96f7d3f1 | 169 | return 1; |
ab04a2af | 170 | /* Not the same. */ |
96f7d3f1 | 171 | return 0; |
ab04a2af | 172 | } |
96f7d3f1 PW |
173 | else |
174 | return c->catch_all || !INTERNAL_SIGNAL (signal_number); | |
ab04a2af TT |
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; | |
ab04a2af TT |
184 | struct target_waitstatus last; |
185 | const char *signal_name; | |
f303dbd6 | 186 | struct ui_out *uiout = current_uiout; |
ab04a2af | 187 | |
5b6d1e4f | 188 | get_last_target_status (nullptr, nullptr, &last); |
ab04a2af TT |
189 | |
190 | signal_name = signal_to_name_or_int (last.value.sig); | |
191 | ||
192 | annotate_catchpoint (b->number); | |
f303dbd6 | 193 | maybe_print_thread_hit_breakpoint (uiout); |
ab04a2af | 194 | |
f303dbd6 | 195 | printf_filtered (_("Catchpoint %d (signal %s), "), b->number, signal_name); |
ab04a2af TT |
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 | { | |
9a3c8263 | 207 | struct signal_catchpoint *c = (struct signal_catchpoint *) b; |
ab04a2af TT |
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) | |
112e8700 | 217 | uiout->field_skip ("addr"); |
ab04a2af TT |
218 | annotate_field (5); |
219 | ||
f746a154 | 220 | if (c->signals_to_be_caught.size () > 1) |
112e8700 | 221 | uiout->text ("signals \""); |
ab04a2af | 222 | else |
112e8700 | 223 | uiout->text ("signal \""); |
ab04a2af | 224 | |
f746a154 | 225 | if (!c->signals_to_be_caught.empty ()) |
ab04a2af | 226 | { |
5809899d | 227 | std::string text; |
ab04a2af | 228 | |
f746a154 TT |
229 | bool first = true; |
230 | for (gdb_signal iter : c->signals_to_be_caught) | |
ab04a2af TT |
231 | { |
232 | const char *name = signal_to_name_or_int (iter); | |
233 | ||
f746a154 | 234 | if (!first) |
5809899d | 235 | text += " "; |
f746a154 TT |
236 | first = false; |
237 | ||
5809899d | 238 | text += name; |
ab04a2af | 239 | } |
112e8700 | 240 | uiout->field_string ("what", text.c_str ()); |
ab04a2af TT |
241 | } |
242 | else | |
112e8700 | 243 | uiout->field_string ("what", |
7f6aba03 TT |
244 | c->catch_all ? "<any signal>" : "<standard signals>", |
245 | metadata_style.style ()); | |
112e8700 | 246 | uiout->text ("\" "); |
ab04a2af | 247 | |
112e8700 SM |
248 | if (uiout->is_mi_like_p ()) |
249 | uiout->field_string ("catch-type", "signal"); | |
ab04a2af TT |
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 | { | |
9a3c8263 | 258 | struct signal_catchpoint *c = (struct signal_catchpoint *) b; |
ab04a2af | 259 | |
f746a154 | 260 | if (!c->signals_to_be_caught.empty ()) |
ab04a2af | 261 | { |
f746a154 | 262 | if (c->signals_to_be_caught.size () > 1) |
ab04a2af TT |
263 | printf_filtered (_("Catchpoint %d (signals"), b->number); |
264 | else | |
265 | printf_filtered (_("Catchpoint %d (signal"), b->number); | |
266 | ||
f746a154 | 267 | for (gdb_signal iter : c->signals_to_be_caught) |
ab04a2af TT |
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 | { | |
9a3c8263 | 287 | struct signal_catchpoint *c = (struct signal_catchpoint *) b; |
ab04a2af TT |
288 | |
289 | fprintf_unfiltered (fp, "catch signal"); | |
290 | ||
f746a154 | 291 | if (!c->signals_to_be_caught.empty ()) |
ab04a2af | 292 | { |
f746a154 | 293 | for (gdb_signal iter : c->signals_to_be_caught) |
ab04a2af TT |
294 | fprintf_unfiltered (fp, " %s", signal_to_name_or_int (iter)); |
295 | } | |
296 | else if (c->catch_all) | |
297 | fprintf_unfiltered (fp, " all"); | |
c780cc2f | 298 | fputc_unfiltered ('\n', fp); |
ab04a2af TT |
299 | } |
300 | ||
301 | /* Implement the "explains_signal" breakpoint_ops method for signal | |
302 | catchpoints. */ | |
303 | ||
47591c29 | 304 | static int |
427cd150 | 305 | signal_catchpoint_explains_signal (struct breakpoint *b, enum gdb_signal sig) |
ab04a2af | 306 | { |
47591c29 | 307 | return 1; |
ab04a2af TT |
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 | |
f746a154 | 312 | can be empty, meaning all signals. CATCH_ALL is a flag indicating |
ab04a2af | 313 | whether signals used internally by gdb should be caught; it is only |
f746a154 | 314 | valid if FILTER is NULL. If FILTER is empty and CATCH_ALL is zero, |
ab04a2af TT |
315 | then internal signals like SIGTRAP are not caught. */ |
316 | ||
317 | static void | |
f746a154 TT |
318 | create_signal_catchpoint (int tempflag, std::vector<gdb_signal> &&filter, |
319 | bool catch_all) | |
ab04a2af | 320 | { |
ab04a2af TT |
321 | struct gdbarch *gdbarch = get_current_arch (); |
322 | ||
b270e6f9 TT |
323 | std::unique_ptr<signal_catchpoint> c (new signal_catchpoint ()); |
324 | init_catchpoint (c.get (), gdbarch, tempflag, NULL, &signal_catchpoint_ops); | |
2f5404b3 | 325 | c->signals_to_be_caught = std::move (filter); |
ab04a2af TT |
326 | c->catch_all = catch_all; |
327 | ||
b270e6f9 | 328 | install_breakpoint (0, std::move (c), 1); |
ab04a2af TT |
329 | } |
330 | ||
331 | ||
f746a154 TT |
332 | /* Splits the argument using space as delimiter. Returns a filter |
333 | list, which is empty if no filtering is required. */ | |
ab04a2af | 334 | |
f746a154 | 335 | static std::vector<gdb_signal> |
eb4c3f4a | 336 | catch_signal_split_args (const char *arg, bool *catch_all) |
ab04a2af | 337 | { |
f746a154 TT |
338 | std::vector<gdb_signal> result; |
339 | bool first = true; | |
ab04a2af TT |
340 | |
341 | while (*arg != '\0') | |
342 | { | |
343 | int num; | |
f746a154 TT |
344 | gdb_signal signal_number; |
345 | char *endptr; | |
ab04a2af | 346 | |
cb791d59 TT |
347 | std::string one_arg = extract_arg (&arg); |
348 | if (one_arg.empty ()) | |
ab04a2af | 349 | break; |
ab04a2af TT |
350 | |
351 | /* Check for the special flag "all". */ | |
cb791d59 | 352 | if (one_arg == "all") |
ab04a2af TT |
353 | { |
354 | arg = skip_spaces (arg); | |
355 | if (*arg != '\0' || !first) | |
356 | error (_("'all' cannot be caught with other signals")); | |
f746a154 TT |
357 | *catch_all = true; |
358 | gdb_assert (result.empty ()); | |
359 | return result; | |
ab04a2af TT |
360 | } |
361 | ||
f746a154 | 362 | first = false; |
ab04a2af TT |
363 | |
364 | /* Check if the user provided a signal name or a number. */ | |
cb791d59 | 365 | num = (int) strtol (one_arg.c_str (), &endptr, 0); |
ab04a2af TT |
366 | if (*endptr == '\0') |
367 | signal_number = gdb_signal_from_command (num); | |
368 | else | |
369 | { | |
cb791d59 | 370 | signal_number = gdb_signal_from_name (one_arg.c_str ()); |
ab04a2af | 371 | if (signal_number == GDB_SIGNAL_UNKNOWN) |
cb791d59 | 372 | error (_("Unknown signal name '%s'."), one_arg.c_str ()); |
ab04a2af TT |
373 | } |
374 | ||
f746a154 | 375 | result.push_back (signal_number); |
ab04a2af TT |
376 | } |
377 | ||
f746a154 | 378 | result.shrink_to_fit (); |
ab04a2af TT |
379 | return result; |
380 | } | |
381 | ||
382 | /* Implement the "catch signal" command. */ | |
383 | ||
384 | static void | |
eb4c3f4a | 385 | catch_signal_command (const char *arg, int from_tty, |
ab04a2af TT |
386 | struct cmd_list_element *command) |
387 | { | |
f746a154 TT |
388 | int tempflag; |
389 | bool catch_all = false; | |
390 | std::vector<gdb_signal> filter; | |
ab04a2af TT |
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); | |
ab04a2af | 404 | |
f746a154 | 405 | create_signal_catchpoint (tempflag, std::move (filter), catch_all); |
ab04a2af TT |
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; | |
ab04a2af TT |
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 | ||
6c265988 | 427 | void _initialize_break_catch_sig (); |
ab04a2af | 428 | void |
6c265988 | 429 | _initialize_break_catch_sig () |
ab04a2af TT |
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 | } |