Return bool from breakpoint_ops::print_one
[binutils-gdb.git] / gdb / break-catch-syscall.c
1 /* Everything about syscall catchpoints, for GDB.
2
3 Copyright (C) 2009-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 <ctype.h>
22 #include "breakpoint.h"
23 #include "gdbcmd.h"
24 #include "inferior.h"
25 #include "cli/cli-utils.h"
26 #include "annotate.h"
27 #include "mi/mi-common.h"
28 #include "valprint.h"
29 #include "arch-utils.h"
30 #include "observable.h"
31 #include "xml-syscall.h"
32 #include "cli/cli-style.h"
33 #include "cli/cli-decode.h"
34
35 /* An instance of this type is used to represent a syscall catchpoint.
36 A breakpoint is really of this type iff its ops pointer points to
37 CATCH_SYSCALL_BREAKPOINT_OPS. */
38
39 struct syscall_catchpoint : public breakpoint
40 {
41 /* Syscall numbers used for the 'catch syscall' feature. If no
42 syscall has been specified for filtering, it is empty.
43 Otherwise, it holds a list of all syscalls to be caught. */
44 std::vector<int> syscalls_to_be_caught;
45 };
46
47 struct catch_syscall_inferior_data
48 {
49 /* We keep a count of the number of times the user has requested a
50 particular syscall to be tracked, and pass this information to the
51 target. This lets capable targets implement filtering directly. */
52
53 /* Number of times that "any" syscall is requested. */
54 int any_syscall_count;
55
56 /* Count of each system call. */
57 std::vector<int> syscalls_counts;
58
59 /* This counts all syscall catch requests, so we can readily determine
60 if any catching is necessary. */
61 int total_syscalls_count;
62 };
63
64 static const struct inferior_key<struct catch_syscall_inferior_data>
65 catch_syscall_inferior_data;
66
67 static struct catch_syscall_inferior_data *
68 get_catch_syscall_inferior_data (struct inferior *inf)
69 {
70 struct catch_syscall_inferior_data *inf_data;
71
72 inf_data = catch_syscall_inferior_data.get (inf);
73 if (inf_data == NULL)
74 inf_data = catch_syscall_inferior_data.emplace (inf);
75
76 return inf_data;
77 }
78
79 /* Implement the "insert" breakpoint_ops method for syscall
80 catchpoints. */
81
82 static int
83 insert_catch_syscall (struct bp_location *bl)
84 {
85 struct syscall_catchpoint *c = (struct syscall_catchpoint *) bl->owner;
86 struct inferior *inf = current_inferior ();
87 struct catch_syscall_inferior_data *inf_data
88 = get_catch_syscall_inferior_data (inf);
89
90 ++inf_data->total_syscalls_count;
91 if (c->syscalls_to_be_caught.empty ())
92 ++inf_data->any_syscall_count;
93 else
94 {
95 for (int iter : c->syscalls_to_be_caught)
96 {
97 if (iter >= inf_data->syscalls_counts.size ())
98 inf_data->syscalls_counts.resize (iter + 1);
99 ++inf_data->syscalls_counts[iter];
100 }
101 }
102
103 return target_set_syscall_catchpoint (inferior_ptid.pid (),
104 inf_data->total_syscalls_count != 0,
105 inf_data->any_syscall_count,
106 inf_data->syscalls_counts);
107 }
108
109 /* Implement the "remove" breakpoint_ops method for syscall
110 catchpoints. */
111
112 static int
113 remove_catch_syscall (struct bp_location *bl, enum remove_bp_reason reason)
114 {
115 struct syscall_catchpoint *c = (struct syscall_catchpoint *) bl->owner;
116 struct inferior *inf = current_inferior ();
117 struct catch_syscall_inferior_data *inf_data
118 = get_catch_syscall_inferior_data (inf);
119
120 --inf_data->total_syscalls_count;
121 if (c->syscalls_to_be_caught.empty ())
122 --inf_data->any_syscall_count;
123 else
124 {
125 for (int iter : c->syscalls_to_be_caught)
126 {
127 if (iter >= inf_data->syscalls_counts.size ())
128 /* Shouldn't happen. */
129 continue;
130 --inf_data->syscalls_counts[iter];
131 }
132 }
133
134 return target_set_syscall_catchpoint (inferior_ptid.pid (),
135 inf_data->total_syscalls_count != 0,
136 inf_data->any_syscall_count,
137 inf_data->syscalls_counts);
138 }
139
140 /* Implement the "breakpoint_hit" breakpoint_ops method for syscall
141 catchpoints. */
142
143 static int
144 breakpoint_hit_catch_syscall (const struct bp_location *bl,
145 const address_space *aspace, CORE_ADDR bp_addr,
146 const target_waitstatus &ws)
147 {
148 /* We must check if we are catching specific syscalls in this
149 breakpoint. If we are, then we must guarantee that the called
150 syscall is the same syscall we are catching. */
151 int syscall_number = 0;
152 const struct syscall_catchpoint *c
153 = (const struct syscall_catchpoint *) bl->owner;
154
155 if (ws.kind () != TARGET_WAITKIND_SYSCALL_ENTRY
156 && ws.kind () != TARGET_WAITKIND_SYSCALL_RETURN)
157 return 0;
158
159 syscall_number = ws.syscall_number ();
160
161 /* Now, checking if the syscall is the same. */
162 if (!c->syscalls_to_be_caught.empty ())
163 {
164 for (int iter : c->syscalls_to_be_caught)
165 if (syscall_number == iter)
166 return 1;
167
168 return 0;
169 }
170
171 return 1;
172 }
173
174 /* Implement the "print_it" breakpoint_ops method for syscall
175 catchpoints. */
176
177 static enum print_stop_action
178 print_it_catch_syscall (bpstat *bs)
179 {
180 struct ui_out *uiout = current_uiout;
181 struct breakpoint *b = bs->breakpoint_at;
182 /* These are needed because we want to know in which state a
183 syscall is. It can be in the TARGET_WAITKIND_SYSCALL_ENTRY
184 or TARGET_WAITKIND_SYSCALL_RETURN, and depending on it we
185 must print "called syscall" or "returned from syscall". */
186 struct target_waitstatus last;
187 struct syscall s;
188 struct gdbarch *gdbarch = bs->bp_location_at->gdbarch;
189
190 get_last_target_status (nullptr, nullptr, &last);
191
192 get_syscall_by_number (gdbarch, last.syscall_number (), &s);
193
194 annotate_catchpoint (b->number);
195 maybe_print_thread_hit_breakpoint (uiout);
196
197 if (b->disposition == disp_del)
198 uiout->text ("Temporary catchpoint ");
199 else
200 uiout->text ("Catchpoint ");
201 if (uiout->is_mi_like_p ())
202 {
203 uiout->field_string ("reason",
204 async_reason_lookup (last.kind () == TARGET_WAITKIND_SYSCALL_ENTRY
205 ? EXEC_ASYNC_SYSCALL_ENTRY
206 : EXEC_ASYNC_SYSCALL_RETURN));
207 uiout->field_string ("disp", bpdisp_text (b->disposition));
208 }
209 uiout->field_signed ("bkptno", b->number);
210
211 if (last.kind () == TARGET_WAITKIND_SYSCALL_ENTRY)
212 uiout->text (" (call to syscall ");
213 else
214 uiout->text (" (returned from syscall ");
215
216 if (s.name == NULL || uiout->is_mi_like_p ())
217 uiout->field_signed ("syscall-number", last.syscall_number ());
218 if (s.name != NULL)
219 uiout->field_string ("syscall-name", s.name);
220
221 uiout->text ("), ");
222
223 return PRINT_SRC_AND_LOC;
224 }
225
226 /* Implement the "print_one" breakpoint_ops method for syscall
227 catchpoints. */
228
229 static bool
230 print_one_catch_syscall (struct breakpoint *b,
231 struct bp_location **last_loc)
232 {
233 struct syscall_catchpoint *c = (struct syscall_catchpoint *) b;
234 struct value_print_options opts;
235 struct ui_out *uiout = current_uiout;
236 struct gdbarch *gdbarch = b->loc->gdbarch;
237
238 get_user_print_options (&opts);
239 /* Field 4, the address, is omitted (which makes the columns not
240 line up too nicely with the headers, but the effect is relatively
241 readable). */
242 if (opts.addressprint)
243 uiout->field_skip ("addr");
244 annotate_field (5);
245
246 if (c->syscalls_to_be_caught.size () > 1)
247 uiout->text ("syscalls \"");
248 else
249 uiout->text ("syscall \"");
250
251 if (!c->syscalls_to_be_caught.empty ())
252 {
253 std::string text;
254
255 bool first = true;
256 for (int iter : c->syscalls_to_be_caught)
257 {
258 struct syscall s;
259 get_syscall_by_number (gdbarch, iter, &s);
260
261 if (!first)
262 text += ", ";
263 first = false;
264
265 if (s.name != NULL)
266 text += s.name;
267 else
268 text += std::to_string (iter);
269 }
270 uiout->field_string ("what", text.c_str ());
271 }
272 else
273 uiout->field_string ("what", "<any syscall>", metadata_style.style ());
274 uiout->text ("\" ");
275
276 if (uiout->is_mi_like_p ())
277 uiout->field_string ("catch-type", "syscall");
278
279 return true;
280 }
281
282 /* Implement the "print_mention" breakpoint_ops method for syscall
283 catchpoints. */
284
285 static void
286 print_mention_catch_syscall (struct breakpoint *b)
287 {
288 struct syscall_catchpoint *c = (struct syscall_catchpoint *) b;
289 struct gdbarch *gdbarch = b->loc->gdbarch;
290
291 if (!c->syscalls_to_be_caught.empty ())
292 {
293 if (c->syscalls_to_be_caught.size () > 1)
294 gdb_printf (_("Catchpoint %d (syscalls"), b->number);
295 else
296 gdb_printf (_("Catchpoint %d (syscall"), b->number);
297
298 for (int iter : c->syscalls_to_be_caught)
299 {
300 struct syscall s;
301 get_syscall_by_number (gdbarch, iter, &s);
302
303 if (s.name != NULL)
304 gdb_printf (" '%s' [%d]", s.name, s.number);
305 else
306 gdb_printf (" %d", s.number);
307 }
308 gdb_printf (")");
309 }
310 else
311 gdb_printf (_("Catchpoint %d (any syscall)"),
312 b->number);
313 }
314
315 /* Implement the "print_recreate" breakpoint_ops method for syscall
316 catchpoints. */
317
318 static void
319 print_recreate_catch_syscall (struct breakpoint *b, struct ui_file *fp)
320 {
321 struct syscall_catchpoint *c = (struct syscall_catchpoint *) b;
322 struct gdbarch *gdbarch = b->loc->gdbarch;
323
324 gdb_printf (fp, "catch syscall");
325
326 for (int iter : c->syscalls_to_be_caught)
327 {
328 struct syscall s;
329
330 get_syscall_by_number (gdbarch, iter, &s);
331 if (s.name != NULL)
332 gdb_printf (fp, " %s", s.name);
333 else
334 gdb_printf (fp, " %d", s.number);
335 }
336
337 print_recreate_thread (b, fp);
338 }
339
340 /* The breakpoint_ops structure to be used in syscall catchpoints. */
341
342 static struct breakpoint_ops catch_syscall_breakpoint_ops;
343
344 /* Returns non-zero if 'b' is a syscall catchpoint. */
345
346 static int
347 syscall_catchpoint_p (struct breakpoint *b)
348 {
349 return (b->ops == &catch_syscall_breakpoint_ops);
350 }
351
352 static void
353 create_syscall_event_catchpoint (int tempflag, std::vector<int> &&filter,
354 const struct breakpoint_ops *ops)
355 {
356 struct gdbarch *gdbarch = get_current_arch ();
357
358 std::unique_ptr<syscall_catchpoint> c (new syscall_catchpoint ());
359 init_catchpoint (c.get (), gdbarch, tempflag, NULL, ops);
360 c->syscalls_to_be_caught = std::move (filter);
361
362 install_breakpoint (0, std::move (c), 1);
363 }
364
365 /* Splits the argument using space as delimiter. */
366
367 static std::vector<int>
368 catch_syscall_split_args (const char *arg)
369 {
370 std::vector<int> result;
371 struct gdbarch *gdbarch = target_gdbarch ();
372
373 while (*arg != '\0')
374 {
375 int i, syscall_number;
376 char *endptr;
377 char cur_name[128];
378 struct syscall s;
379
380 /* Skip whitespace. */
381 arg = skip_spaces (arg);
382
383 for (i = 0; i < 127 && arg[i] && !isspace (arg[i]); ++i)
384 cur_name[i] = arg[i];
385 cur_name[i] = '\0';
386 arg += i;
387
388 /* Check if the user provided a syscall name, group, or a number. */
389 syscall_number = (int) strtol (cur_name, &endptr, 0);
390 if (*endptr == '\0')
391 {
392 if (syscall_number < 0)
393 error (_("Unknown syscall number '%d'."), syscall_number);
394 get_syscall_by_number (gdbarch, syscall_number, &s);
395 result.push_back (s.number);
396 }
397 else if (startswith (cur_name, "g:")
398 || startswith (cur_name, "group:"))
399 {
400 /* We have a syscall group. Let's expand it into a syscall
401 list before inserting. */
402 const char *group_name;
403
404 /* Skip over "g:" and "group:" prefix strings. */
405 group_name = strchr (cur_name, ':') + 1;
406
407 if (!get_syscalls_by_group (gdbarch, group_name, &result))
408 error (_("Unknown syscall group '%s'."), group_name);
409 }
410 else
411 {
412 /* We have a name. Let's check if it's valid and fetch a
413 list of matching numbers. */
414 if (!get_syscalls_by_name (gdbarch, cur_name, &result))
415 /* Here we have to issue an error instead of a warning,
416 because GDB cannot do anything useful if there's no
417 syscall number to be caught. */
418 error (_("Unknown syscall name '%s'."), cur_name);
419 }
420 }
421
422 return result;
423 }
424
425 /* Implement the "catch syscall" command. */
426
427 static void
428 catch_syscall_command_1 (const char *arg, int from_tty,
429 struct cmd_list_element *command)
430 {
431 int tempflag;
432 std::vector<int> filter;
433 struct syscall s;
434 struct gdbarch *gdbarch = get_current_arch ();
435
436 /* Checking if the feature if supported. */
437 if (gdbarch_get_syscall_number_p (gdbarch) == 0)
438 error (_("The feature 'catch syscall' is not supported on \
439 this architecture yet."));
440
441 tempflag = command->context () == CATCH_TEMPORARY;
442
443 arg = skip_spaces (arg);
444
445 /* We need to do this first "dummy" translation in order
446 to get the syscall XML file loaded or, most important,
447 to display a warning to the user if there's no XML file
448 for his/her architecture. */
449 get_syscall_by_number (gdbarch, 0, &s);
450
451 /* The allowed syntax is:
452 catch syscall
453 catch syscall <name | number> [<name | number> ... <name | number>]
454
455 Let's check if there's a syscall name. */
456
457 if (arg != NULL)
458 filter = catch_syscall_split_args (arg);
459
460 create_syscall_event_catchpoint (tempflag, std::move (filter),
461 &catch_syscall_breakpoint_ops);
462 }
463
464
465 /* Returns 0 if 'bp' is NOT a syscall catchpoint,
466 non-zero otherwise. */
467 static int
468 is_syscall_catchpoint_enabled (struct breakpoint *bp)
469 {
470 if (syscall_catchpoint_p (bp)
471 && bp->enable_state != bp_disabled
472 && bp->enable_state != bp_call_disabled)
473 return 1;
474 else
475 return 0;
476 }
477
478 int
479 catch_syscall_enabled (void)
480 {
481 struct catch_syscall_inferior_data *inf_data
482 = get_catch_syscall_inferior_data (current_inferior ());
483
484 return inf_data->total_syscalls_count != 0;
485 }
486
487 /* Helper function for catching_syscall_number. return true if B is a syscall
488 catchpoint for SYSCALL_NUMBER, else false. */
489
490 static bool
491 catching_syscall_number_1 (struct breakpoint *b, int syscall_number)
492 {
493
494 if (is_syscall_catchpoint_enabled (b))
495 {
496 struct syscall_catchpoint *c = (struct syscall_catchpoint *) b;
497
498 if (!c->syscalls_to_be_caught.empty ())
499 {
500 for (int iter : c->syscalls_to_be_caught)
501 if (syscall_number == iter)
502 return true;
503 }
504 else
505 return true;
506 }
507
508 return false;
509 }
510
511 bool
512 catching_syscall_number (int syscall_number)
513 {
514 for (breakpoint *b : all_breakpoints ())
515 if (catching_syscall_number_1 (b, syscall_number))
516 return true;
517
518 return false;
519 }
520
521 /* Complete syscall names. Used by "catch syscall". */
522
523 static void
524 catch_syscall_completer (struct cmd_list_element *cmd,
525 completion_tracker &tracker,
526 const char *text, const char *word)
527 {
528 struct gdbarch *gdbarch = get_current_arch ();
529 gdb::unique_xmalloc_ptr<const char *> group_list;
530 const char *prefix;
531
532 /* Completion considers ':' to be a word separator, so we use this to
533 verify whether the previous word was a group prefix. If so, we
534 build the completion list using group names only. */
535 for (prefix = word; prefix != text && prefix[-1] != ' '; prefix--)
536 ;
537
538 if (startswith (prefix, "g:") || startswith (prefix, "group:"))
539 {
540 /* Perform completion inside 'group:' namespace only. */
541 group_list.reset (get_syscall_group_names (gdbarch));
542 if (group_list != NULL)
543 complete_on_enum (tracker, group_list.get (), word, word);
544 }
545 else
546 {
547 /* Complete with both, syscall names and groups. */
548 gdb::unique_xmalloc_ptr<const char *> syscall_list
549 (get_syscall_names (gdbarch));
550 group_list.reset (get_syscall_group_names (gdbarch));
551
552 const char **group_ptr = group_list.get ();
553
554 /* Hold on to strings while we're using them. */
555 std::vector<std::string> holders;
556
557 /* Append "group:" prefix to syscall groups. */
558 for (int i = 0; group_ptr[i] != NULL; i++)
559 holders.push_back (string_printf ("group:%s", group_ptr[i]));
560
561 for (int i = 0; group_ptr[i] != NULL; i++)
562 group_ptr[i] = holders[i].c_str ();
563
564 if (syscall_list != NULL)
565 complete_on_enum (tracker, syscall_list.get (), word, word);
566 if (group_list != NULL)
567 complete_on_enum (tracker, group_ptr, word, word);
568 }
569 }
570
571 static void
572 clear_syscall_counts (struct inferior *inf)
573 {
574 struct catch_syscall_inferior_data *inf_data
575 = get_catch_syscall_inferior_data (inf);
576
577 inf_data->total_syscalls_count = 0;
578 inf_data->any_syscall_count = 0;
579 inf_data->syscalls_counts.clear ();
580 }
581
582 static void
583 initialize_syscall_catchpoint_ops (void)
584 {
585 struct breakpoint_ops *ops;
586
587 initialize_breakpoint_ops ();
588
589 /* Syscall catchpoints. */
590 ops = &catch_syscall_breakpoint_ops;
591 *ops = base_breakpoint_ops;
592 ops->insert_location = insert_catch_syscall;
593 ops->remove_location = remove_catch_syscall;
594 ops->breakpoint_hit = breakpoint_hit_catch_syscall;
595 ops->print_it = print_it_catch_syscall;
596 ops->print_one = print_one_catch_syscall;
597 ops->print_mention = print_mention_catch_syscall;
598 ops->print_recreate = print_recreate_catch_syscall;
599 }
600
601 void _initialize_break_catch_syscall ();
602 void
603 _initialize_break_catch_syscall ()
604 {
605 initialize_syscall_catchpoint_ops ();
606
607 gdb::observers::inferior_exit.attach (clear_syscall_counts,
608 "break-catch-syscall");
609
610 add_catch_command ("syscall", _("\
611 Catch system calls by their names, groups and/or numbers.\n\
612 Arguments say which system calls to catch. If no arguments are given,\n\
613 every system call will be caught. Arguments, if given, should be one\n\
614 or more system call names (if your system supports that), system call\n\
615 groups or system call numbers."),
616 catch_syscall_command_1,
617 catch_syscall_completer,
618 CATCH_PERMANENT,
619 CATCH_TEMPORARY);
620 }