1 /* Everything about syscall catchpoints, for GDB.
3 Copyright (C) 2009-2017 Free Software Foundation, Inc.
5 This file is part of GDB.
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.
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.
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/>. */
22 #include "breakpoint.h"
25 #include "cli/cli-utils.h"
27 #include "mi/mi-common.h"
29 #include "arch-utils.h"
31 #include "xml-syscall.h"
33 /* An instance of this type is used to represent a syscall catchpoint.
34 A breakpoint is really of this type iff its ops pointer points to
35 CATCH_SYSCALL_BREAKPOINT_OPS. */
37 struct syscall_catchpoint : public breakpoint
39 ~syscall_catchpoint () override;
41 /* Syscall numbers used for the 'catch syscall' feature. If no
42 syscall has been specified for filtering, its value is NULL.
43 Otherwise, it holds a list of all syscalls to be caught. The
44 list elements are allocated with xmalloc. */
45 VEC(int) *syscalls_to_be_caught;
48 /* catch_syscall destructor. */
50 syscall_catchpoint::~syscall_catchpoint ()
52 VEC_free (int, this->syscalls_to_be_caught);
55 static const struct inferior_data *catch_syscall_inferior_data = NULL;
57 struct catch_syscall_inferior_data
59 /* We keep a count of the number of times the user has requested a
60 particular syscall to be tracked, and pass this information to the
61 target. This lets capable targets implement filtering directly. */
63 /* Number of times that "any" syscall is requested. */
64 int any_syscall_count;
66 /* Count of each system call. */
67 VEC(int) *syscalls_counts;
69 /* This counts all syscall catch requests, so we can readily determine
70 if any catching is necessary. */
71 int total_syscalls_count;
74 static struct catch_syscall_inferior_data*
75 get_catch_syscall_inferior_data (struct inferior *inf)
77 struct catch_syscall_inferior_data *inf_data;
79 inf_data = ((struct catch_syscall_inferior_data *)
80 inferior_data (inf, catch_syscall_inferior_data));
83 inf_data = XCNEW (struct catch_syscall_inferior_data);
84 set_inferior_data (inf, catch_syscall_inferior_data, inf_data);
91 catch_syscall_inferior_data_cleanup (struct inferior *inf, void *arg)
97 /* Implement the "insert" breakpoint_ops method for syscall
101 insert_catch_syscall (struct bp_location *bl)
103 struct syscall_catchpoint *c = (struct syscall_catchpoint *) bl->owner;
104 struct inferior *inf = current_inferior ();
105 struct catch_syscall_inferior_data *inf_data
106 = get_catch_syscall_inferior_data (inf);
108 ++inf_data->total_syscalls_count;
109 if (!c->syscalls_to_be_caught)
110 ++inf_data->any_syscall_count;
116 VEC_iterate (int, c->syscalls_to_be_caught, i, iter);
121 if (iter >= VEC_length (int, inf_data->syscalls_counts))
123 int old_size = VEC_length (int, inf_data->syscalls_counts);
124 uintptr_t vec_addr_offset
125 = old_size * ((uintptr_t) sizeof (int));
127 VEC_safe_grow (int, inf_data->syscalls_counts, iter + 1);
128 vec_addr = ((uintptr_t) VEC_address (int,
129 inf_data->syscalls_counts)
131 memset ((void *) vec_addr, 0,
132 (iter + 1 - old_size) * sizeof (int));
134 elem = VEC_index (int, inf_data->syscalls_counts, iter);
135 VEC_replace (int, inf_data->syscalls_counts, iter, ++elem);
139 return target_set_syscall_catchpoint (ptid_get_pid (inferior_ptid),
140 inf_data->total_syscalls_count != 0,
141 inf_data->any_syscall_count,
143 inf_data->syscalls_counts),
145 inf_data->syscalls_counts));
148 /* Implement the "remove" breakpoint_ops method for syscall
152 remove_catch_syscall (struct bp_location *bl, enum remove_bp_reason reason)
154 struct syscall_catchpoint *c = (struct syscall_catchpoint *) bl->owner;
155 struct inferior *inf = current_inferior ();
156 struct catch_syscall_inferior_data *inf_data
157 = get_catch_syscall_inferior_data (inf);
159 --inf_data->total_syscalls_count;
160 if (!c->syscalls_to_be_caught)
161 --inf_data->any_syscall_count;
167 VEC_iterate (int, c->syscalls_to_be_caught, i, iter);
171 if (iter >= VEC_length (int, inf_data->syscalls_counts))
172 /* Shouldn't happen. */
174 elem = VEC_index (int, inf_data->syscalls_counts, iter);
175 VEC_replace (int, inf_data->syscalls_counts, iter, --elem);
179 return target_set_syscall_catchpoint (ptid_get_pid (inferior_ptid),
180 inf_data->total_syscalls_count != 0,
181 inf_data->any_syscall_count,
183 inf_data->syscalls_counts),
185 inf_data->syscalls_counts));
188 /* Implement the "breakpoint_hit" breakpoint_ops method for syscall
192 breakpoint_hit_catch_syscall (const struct bp_location *bl,
193 struct address_space *aspace, CORE_ADDR bp_addr,
194 const struct target_waitstatus *ws)
196 /* We must check if we are catching specific syscalls in this
197 breakpoint. If we are, then we must guarantee that the called
198 syscall is the same syscall we are catching. */
199 int syscall_number = 0;
200 const struct syscall_catchpoint *c
201 = (const struct syscall_catchpoint *) bl->owner;
203 if (ws->kind != TARGET_WAITKIND_SYSCALL_ENTRY
204 && ws->kind != TARGET_WAITKIND_SYSCALL_RETURN)
207 syscall_number = ws->value.syscall_number;
209 /* Now, checking if the syscall is the same. */
210 if (c->syscalls_to_be_caught)
215 VEC_iterate (int, c->syscalls_to_be_caught, i, iter);
217 if (syscall_number == iter)
226 /* Implement the "print_it" breakpoint_ops method for syscall
229 static enum print_stop_action
230 print_it_catch_syscall (bpstat bs)
232 struct ui_out *uiout = current_uiout;
233 struct breakpoint *b = bs->breakpoint_at;
234 /* These are needed because we want to know in which state a
235 syscall is. It can be in the TARGET_WAITKIND_SYSCALL_ENTRY
236 or TARGET_WAITKIND_SYSCALL_RETURN, and depending on it we
237 must print "called syscall" or "returned from syscall". */
239 struct target_waitstatus last;
241 struct gdbarch *gdbarch = bs->bp_location_at->gdbarch;
243 get_last_target_status (&ptid, &last);
245 get_syscall_by_number (gdbarch, last.value.syscall_number, &s);
247 annotate_catchpoint (b->number);
248 maybe_print_thread_hit_breakpoint (uiout);
250 if (b->disposition == disp_del)
251 uiout->text ("Temporary catchpoint ");
253 uiout->text ("Catchpoint ");
254 if (uiout->is_mi_like_p ())
256 uiout->field_string ("reason",
257 async_reason_lookup (last.kind == TARGET_WAITKIND_SYSCALL_ENTRY
258 ? EXEC_ASYNC_SYSCALL_ENTRY
259 : EXEC_ASYNC_SYSCALL_RETURN));
260 uiout->field_string ("disp", bpdisp_text (b->disposition));
262 uiout->field_int ("bkptno", b->number);
264 if (last.kind == TARGET_WAITKIND_SYSCALL_ENTRY)
265 uiout->text (" (call to syscall ");
267 uiout->text (" (returned from syscall ");
269 if (s.name == NULL || uiout->is_mi_like_p ())
270 uiout->field_int ("syscall-number", last.value.syscall_number);
272 uiout->field_string ("syscall-name", s.name);
276 return PRINT_SRC_AND_LOC;
279 /* Implement the "print_one" breakpoint_ops method for syscall
283 print_one_catch_syscall (struct breakpoint *b,
284 struct bp_location **last_loc)
286 struct syscall_catchpoint *c = (struct syscall_catchpoint *) b;
287 struct value_print_options opts;
288 struct ui_out *uiout = current_uiout;
289 struct gdbarch *gdbarch = b->loc->gdbarch;
291 get_user_print_options (&opts);
292 /* Field 4, the address, is omitted (which makes the columns not
293 line up too nicely with the headers, but the effect is relatively
295 if (opts.addressprint)
296 uiout->field_skip ("addr");
299 if (c->syscalls_to_be_caught
300 && VEC_length (int, c->syscalls_to_be_caught) > 1)
301 uiout->text ("syscalls \"");
303 uiout->text ("syscall \"");
305 if (c->syscalls_to_be_caught)
308 char *text = xstrprintf ("%s", "");
311 VEC_iterate (int, c->syscalls_to_be_caught, i, iter);
316 get_syscall_by_number (gdbarch, iter, &s);
319 text = xstrprintf ("%s%s, ", text, s.name);
321 text = xstrprintf ("%s%d, ", text, iter);
323 /* We have to xfree the last 'text' (now stored at 'x')
324 because xstrprintf dynamically allocates new space for it
328 /* Remove the last comma. */
329 text[strlen (text) - 2] = '\0';
330 uiout->field_string ("what", text);
333 uiout->field_string ("what", "<any syscall>");
336 if (uiout->is_mi_like_p ())
337 uiout->field_string ("catch-type", "syscall");
340 /* Implement the "print_mention" breakpoint_ops method for syscall
344 print_mention_catch_syscall (struct breakpoint *b)
346 struct syscall_catchpoint *c = (struct syscall_catchpoint *) b;
347 struct gdbarch *gdbarch = b->loc->gdbarch;
349 if (c->syscalls_to_be_caught)
353 if (VEC_length (int, c->syscalls_to_be_caught) > 1)
354 printf_filtered (_("Catchpoint %d (syscalls"), b->number);
356 printf_filtered (_("Catchpoint %d (syscall"), b->number);
359 VEC_iterate (int, c->syscalls_to_be_caught, i, iter);
363 get_syscall_by_number (gdbarch, iter, &s);
366 printf_filtered (" '%s' [%d]", s.name, s.number);
368 printf_filtered (" %d", s.number);
370 printf_filtered (")");
373 printf_filtered (_("Catchpoint %d (any syscall)"),
377 /* Implement the "print_recreate" breakpoint_ops method for syscall
381 print_recreate_catch_syscall (struct breakpoint *b, struct ui_file *fp)
383 struct syscall_catchpoint *c = (struct syscall_catchpoint *) b;
384 struct gdbarch *gdbarch = b->loc->gdbarch;
386 fprintf_unfiltered (fp, "catch syscall");
388 if (c->syscalls_to_be_caught)
393 VEC_iterate (int, c->syscalls_to_be_caught, i, iter);
398 get_syscall_by_number (gdbarch, iter, &s);
400 fprintf_unfiltered (fp, " %s", s.name);
402 fprintf_unfiltered (fp, " %d", s.number);
405 print_recreate_thread (b, fp);
408 /* The breakpoint_ops structure to be used in syscall catchpoints. */
410 static struct breakpoint_ops catch_syscall_breakpoint_ops;
412 /* Returns non-zero if 'b' is a syscall catchpoint. */
415 syscall_catchpoint_p (struct breakpoint *b)
417 return (b->ops == &catch_syscall_breakpoint_ops);
421 create_syscall_event_catchpoint (int tempflag, VEC(int) *filter,
422 const struct breakpoint_ops *ops)
424 struct syscall_catchpoint *c;
425 struct gdbarch *gdbarch = get_current_arch ();
427 c = new syscall_catchpoint ();
428 init_catchpoint (c, gdbarch, tempflag, NULL, ops);
429 c->syscalls_to_be_caught = filter;
431 install_breakpoint (0, c, 1);
434 /* Splits the argument using space as delimiter. Returns an xmalloc'd
435 filter list, or NULL if no filtering is required. */
437 catch_syscall_split_args (char *arg)
439 VEC(int) *result = NULL;
440 struct cleanup *cleanup = make_cleanup (VEC_cleanup (int), &result);
441 struct gdbarch *gdbarch = target_gdbarch ();
445 int i, syscall_number;
450 /* Skip whitespace. */
451 arg = skip_spaces (arg);
453 for (i = 0; i < 127 && arg[i] && !isspace (arg[i]); ++i)
454 cur_name[i] = arg[i];
458 /* Check if the user provided a syscall name, group, or a number. */
459 syscall_number = (int) strtol (cur_name, &endptr, 0);
462 get_syscall_by_number (gdbarch, syscall_number, &s);
463 VEC_safe_push (int, result, s.number);
465 else if (startswith (cur_name, "g:")
466 || startswith (cur_name, "group:"))
468 /* We have a syscall group. Let's expand it into a syscall
469 list before inserting. */
470 struct syscall *syscall_list;
471 const char *group_name;
473 /* Skip over "g:" and "group:" prefix strings. */
474 group_name = strchr (cur_name, ':') + 1;
476 syscall_list = get_syscalls_by_group (gdbarch, group_name);
478 if (syscall_list == NULL)
479 error (_("Unknown syscall group '%s'."), group_name);
481 for (i = 0; syscall_list[i].name != NULL; i++)
483 /* Insert each syscall that are part of the group. No
484 need to check if it is valid. */
485 VEC_safe_push (int, result, syscall_list[i].number);
488 xfree (syscall_list);
492 /* We have a name. Let's check if it's valid and convert it
494 get_syscall_by_name (gdbarch, cur_name, &s);
496 if (s.number == UNKNOWN_SYSCALL)
497 /* Here we have to issue an error instead of a warning,
498 because GDB cannot do anything useful if there's no
499 syscall number to be caught. */
500 error (_("Unknown syscall name '%s'."), cur_name);
502 /* Ok, it's valid. */
503 VEC_safe_push (int, result, s.number);
507 discard_cleanups (cleanup);
511 /* Implement the "catch syscall" command. */
514 catch_syscall_command_1 (char *arg, int from_tty,
515 struct cmd_list_element *command)
520 struct gdbarch *gdbarch = get_current_arch ();
522 /* Checking if the feature if supported. */
523 if (gdbarch_get_syscall_number_p (gdbarch) == 0)
524 error (_("The feature 'catch syscall' is not supported on \
525 this architecture yet."));
527 tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
529 arg = skip_spaces (arg);
531 /* We need to do this first "dummy" translation in order
532 to get the syscall XML file loaded or, most important,
533 to display a warning to the user if there's no XML file
534 for his/her architecture. */
535 get_syscall_by_number (gdbarch, 0, &s);
537 /* The allowed syntax is:
539 catch syscall <name | number> [<name | number> ... <name | number>]
541 Let's check if there's a syscall name. */
544 filter = catch_syscall_split_args (arg);
548 create_syscall_event_catchpoint (tempflag, filter,
549 &catch_syscall_breakpoint_ops);
553 /* Returns 0 if 'bp' is NOT a syscall catchpoint,
554 non-zero otherwise. */
556 is_syscall_catchpoint_enabled (struct breakpoint *bp)
558 if (syscall_catchpoint_p (bp)
559 && bp->enable_state != bp_disabled
560 && bp->enable_state != bp_call_disabled)
567 catch_syscall_enabled (void)
569 struct catch_syscall_inferior_data *inf_data
570 = get_catch_syscall_inferior_data (current_inferior ());
572 return inf_data->total_syscalls_count != 0;
575 /* Helper function for catching_syscall_number. If B is a syscall
576 catchpoint for SYSCALL_NUMBER, return 1 (which will make
577 'breakpoint_find_if' return). Otherwise, return 0. */
580 catching_syscall_number_1 (struct breakpoint *b,
583 int syscall_number = (int) (uintptr_t) data;
585 if (is_syscall_catchpoint_enabled (b))
587 struct syscall_catchpoint *c = (struct syscall_catchpoint *) b;
589 if (c->syscalls_to_be_caught)
593 VEC_iterate (int, c->syscalls_to_be_caught, i, iter);
595 if (syscall_number == iter)
606 catching_syscall_number (int syscall_number)
608 struct breakpoint *b = breakpoint_find_if (catching_syscall_number_1,
609 (void *) (uintptr_t) syscall_number);
614 /* Complete syscall names. Used by "catch syscall". */
617 catch_syscall_completer (struct cmd_list_element *cmd,
618 completion_tracker &tracker,
619 const char *text, const char *word)
621 struct gdbarch *gdbarch = get_current_arch ();
622 struct cleanup *cleanups = make_cleanup (null_cleanup, NULL);
623 const char **group_list = NULL;
624 const char **syscall_list = NULL;
628 /* Completion considers ':' to be a word separator, so we use this to
629 verify whether the previous word was a group prefix. If so, we
630 build the completion list using group names only. */
631 for (prefix = word; prefix != text && prefix[-1] != ' '; prefix--)
634 if (startswith (prefix, "g:") || startswith (prefix, "group:"))
636 /* Perform completion inside 'group:' namespace only. */
637 group_list = get_syscall_group_names (gdbarch);
638 if (group_list != NULL)
639 complete_on_enum (tracker, group_list, word, word);
643 /* Complete with both, syscall names and groups. */
644 syscall_list = get_syscall_names (gdbarch);
645 group_list = get_syscall_group_names (gdbarch);
647 /* Append "group:" prefix to syscall groups. */
648 for (i = 0; group_list[i] != NULL; i++)
650 char *prefixed_group = xstrprintf ("group:%s", group_list[i]);
652 group_list[i] = prefixed_group;
653 make_cleanup (xfree, prefixed_group);
656 if (syscall_list != NULL)
657 complete_on_enum (tracker, syscall_list, word, word);
658 if (group_list != NULL)
659 complete_on_enum (tracker, group_list, word, word);
662 xfree (syscall_list);
664 do_cleanups (cleanups);
668 clear_syscall_counts (struct inferior *inf)
670 struct catch_syscall_inferior_data *inf_data
671 = get_catch_syscall_inferior_data (inf);
673 inf_data->total_syscalls_count = 0;
674 inf_data->any_syscall_count = 0;
675 VEC_free (int, inf_data->syscalls_counts);
679 initialize_syscall_catchpoint_ops (void)
681 struct breakpoint_ops *ops;
683 initialize_breakpoint_ops ();
685 /* Syscall catchpoints. */
686 ops = &catch_syscall_breakpoint_ops;
687 *ops = base_breakpoint_ops;
688 ops->insert_location = insert_catch_syscall;
689 ops->remove_location = remove_catch_syscall;
690 ops->breakpoint_hit = breakpoint_hit_catch_syscall;
691 ops->print_it = print_it_catch_syscall;
692 ops->print_one = print_one_catch_syscall;
693 ops->print_mention = print_mention_catch_syscall;
694 ops->print_recreate = print_recreate_catch_syscall;
697 initialize_file_ftype _initialize_break_catch_syscall;
700 _initialize_break_catch_syscall (void)
702 initialize_syscall_catchpoint_ops ();
704 observer_attach_inferior_exit (clear_syscall_counts);
705 catch_syscall_inferior_data
706 = register_inferior_data_with_cleanup (NULL,
707 catch_syscall_inferior_data_cleanup);
709 add_catch_command ("syscall", _("\
710 Catch system calls by their names, groups and/or numbers.\n\
711 Arguments say which system calls to catch. If no arguments are given,\n\
712 every system call will be caught. Arguments, if given, should be one\n\
713 or more system call names (if your system supports that), system call\n\
714 groups or system call numbers."),
715 catch_syscall_command_1,
716 catch_syscall_completer,