1 /* Everything about syscall catchpoints, for GDB.
3 Copyright (C) 2009-2016 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 It includes a "struct breakpoint" as a kind of base class; users
35 downcast to "struct breakpoint *" when needed. A breakpoint is
36 really of this type iff its ops pointer points to
37 CATCH_SYSCALL_BREAKPOINT_OPS. */
39 struct syscall_catchpoint
42 struct breakpoint base;
44 /* Syscall numbers used for the 'catch syscall' feature. If no
45 syscall has been specified for filtering, its value is NULL.
46 Otherwise, it holds a list of all syscalls to be caught. The
47 list elements are allocated with xmalloc. */
48 VEC(int) *syscalls_to_be_caught;
51 /* Implement the "dtor" breakpoint_ops method for syscall
55 dtor_catch_syscall (struct breakpoint *b)
57 struct syscall_catchpoint *c = (struct syscall_catchpoint *) b;
59 VEC_free (int, c->syscalls_to_be_caught);
61 base_breakpoint_ops.dtor (b);
64 static const struct inferior_data *catch_syscall_inferior_data = NULL;
66 struct catch_syscall_inferior_data
68 /* We keep a count of the number of times the user has requested a
69 particular syscall to be tracked, and pass this information to the
70 target. This lets capable targets implement filtering directly. */
72 /* Number of times that "any" syscall is requested. */
73 int any_syscall_count;
75 /* Count of each system call. */
76 VEC(int) *syscalls_counts;
78 /* This counts all syscall catch requests, so we can readily determine
79 if any catching is necessary. */
80 int total_syscalls_count;
83 static struct catch_syscall_inferior_data*
84 get_catch_syscall_inferior_data (struct inferior *inf)
86 struct catch_syscall_inferior_data *inf_data;
88 inf_data = ((struct catch_syscall_inferior_data *)
89 inferior_data (inf, catch_syscall_inferior_data));
92 inf_data = XCNEW (struct catch_syscall_inferior_data);
93 set_inferior_data (inf, catch_syscall_inferior_data, inf_data);
100 catch_syscall_inferior_data_cleanup (struct inferior *inf, void *arg)
106 /* Implement the "insert" breakpoint_ops method for syscall
110 insert_catch_syscall (struct bp_location *bl)
112 struct syscall_catchpoint *c = (struct syscall_catchpoint *) bl->owner;
113 struct inferior *inf = current_inferior ();
114 struct catch_syscall_inferior_data *inf_data
115 = get_catch_syscall_inferior_data (inf);
117 ++inf_data->total_syscalls_count;
118 if (!c->syscalls_to_be_caught)
119 ++inf_data->any_syscall_count;
125 VEC_iterate (int, c->syscalls_to_be_caught, i, iter);
130 if (iter >= VEC_length (int, inf_data->syscalls_counts))
132 int old_size = VEC_length (int, inf_data->syscalls_counts);
133 uintptr_t vec_addr_offset
134 = old_size * ((uintptr_t) sizeof (int));
136 VEC_safe_grow (int, inf_data->syscalls_counts, iter + 1);
137 vec_addr = ((uintptr_t) VEC_address (int,
138 inf_data->syscalls_counts)
140 memset ((void *) vec_addr, 0,
141 (iter + 1 - old_size) * sizeof (int));
143 elem = VEC_index (int, inf_data->syscalls_counts, iter);
144 VEC_replace (int, inf_data->syscalls_counts, iter, ++elem);
148 return target_set_syscall_catchpoint (ptid_get_pid (inferior_ptid),
149 inf_data->total_syscalls_count != 0,
150 inf_data->any_syscall_count,
152 inf_data->syscalls_counts),
154 inf_data->syscalls_counts));
157 /* Implement the "remove" breakpoint_ops method for syscall
161 remove_catch_syscall (struct bp_location *bl)
163 struct syscall_catchpoint *c = (struct syscall_catchpoint *) bl->owner;
164 struct inferior *inf = current_inferior ();
165 struct catch_syscall_inferior_data *inf_data
166 = get_catch_syscall_inferior_data (inf);
168 --inf_data->total_syscalls_count;
169 if (!c->syscalls_to_be_caught)
170 --inf_data->any_syscall_count;
176 VEC_iterate (int, c->syscalls_to_be_caught, i, iter);
180 if (iter >= VEC_length (int, inf_data->syscalls_counts))
181 /* Shouldn't happen. */
183 elem = VEC_index (int, inf_data->syscalls_counts, iter);
184 VEC_replace (int, inf_data->syscalls_counts, iter, --elem);
188 return target_set_syscall_catchpoint (ptid_get_pid (inferior_ptid),
189 inf_data->total_syscalls_count != 0,
190 inf_data->any_syscall_count,
192 inf_data->syscalls_counts),
194 inf_data->syscalls_counts));
197 /* Implement the "breakpoint_hit" breakpoint_ops method for syscall
201 breakpoint_hit_catch_syscall (const struct bp_location *bl,
202 struct address_space *aspace, CORE_ADDR bp_addr,
203 const struct target_waitstatus *ws)
205 /* We must check if we are catching specific syscalls in this
206 breakpoint. If we are, then we must guarantee that the called
207 syscall is the same syscall we are catching. */
208 int syscall_number = 0;
209 const struct syscall_catchpoint *c
210 = (const struct syscall_catchpoint *) bl->owner;
212 if (ws->kind != TARGET_WAITKIND_SYSCALL_ENTRY
213 && ws->kind != TARGET_WAITKIND_SYSCALL_RETURN)
216 syscall_number = ws->value.syscall_number;
218 /* Now, checking if the syscall is the same. */
219 if (c->syscalls_to_be_caught)
224 VEC_iterate (int, c->syscalls_to_be_caught, i, iter);
226 if (syscall_number == iter)
235 /* Implement the "print_it" breakpoint_ops method for syscall
238 static enum print_stop_action
239 print_it_catch_syscall (bpstat bs)
241 struct ui_out *uiout = current_uiout;
242 struct breakpoint *b = bs->breakpoint_at;
243 /* These are needed because we want to know in which state a
244 syscall is. It can be in the TARGET_WAITKIND_SYSCALL_ENTRY
245 or TARGET_WAITKIND_SYSCALL_RETURN, and depending on it we
246 must print "called syscall" or "returned from syscall". */
248 struct target_waitstatus last;
250 struct gdbarch *gdbarch = bs->bp_location_at->gdbarch;
252 get_last_target_status (&ptid, &last);
254 get_syscall_by_number (gdbarch, last.value.syscall_number, &s);
256 annotate_catchpoint (b->number);
257 maybe_print_thread_hit_breakpoint (uiout);
259 if (b->disposition == disp_del)
260 ui_out_text (uiout, "Temporary catchpoint ");
262 ui_out_text (uiout, "Catchpoint ");
263 if (ui_out_is_mi_like_p (uiout))
265 ui_out_field_string (uiout, "reason",
266 async_reason_lookup (last.kind == TARGET_WAITKIND_SYSCALL_ENTRY
267 ? EXEC_ASYNC_SYSCALL_ENTRY
268 : EXEC_ASYNC_SYSCALL_RETURN));
269 ui_out_field_string (uiout, "disp", bpdisp_text (b->disposition));
271 ui_out_field_int (uiout, "bkptno", b->number);
273 if (last.kind == TARGET_WAITKIND_SYSCALL_ENTRY)
274 ui_out_text (uiout, " (call to syscall ");
276 ui_out_text (uiout, " (returned from syscall ");
278 if (s.name == NULL || ui_out_is_mi_like_p (uiout))
279 ui_out_field_int (uiout, "syscall-number", last.value.syscall_number);
281 ui_out_field_string (uiout, "syscall-name", s.name);
283 ui_out_text (uiout, "), ");
285 return PRINT_SRC_AND_LOC;
288 /* Implement the "print_one" breakpoint_ops method for syscall
292 print_one_catch_syscall (struct breakpoint *b,
293 struct bp_location **last_loc)
295 struct syscall_catchpoint *c = (struct syscall_catchpoint *) b;
296 struct value_print_options opts;
297 struct ui_out *uiout = current_uiout;
298 struct gdbarch *gdbarch = b->loc->gdbarch;
300 get_user_print_options (&opts);
301 /* Field 4, the address, is omitted (which makes the columns not
302 line up too nicely with the headers, but the effect is relatively
304 if (opts.addressprint)
305 ui_out_field_skip (uiout, "addr");
308 if (c->syscalls_to_be_caught
309 && VEC_length (int, c->syscalls_to_be_caught) > 1)
310 ui_out_text (uiout, "syscalls \"");
312 ui_out_text (uiout, "syscall \"");
314 if (c->syscalls_to_be_caught)
317 char *text = xstrprintf ("%s", "");
320 VEC_iterate (int, c->syscalls_to_be_caught, i, iter);
325 get_syscall_by_number (gdbarch, iter, &s);
328 text = xstrprintf ("%s%s, ", text, s.name);
330 text = xstrprintf ("%s%d, ", text, iter);
332 /* We have to xfree the last 'text' (now stored at 'x')
333 because xstrprintf dynamically allocates new space for it
337 /* Remove the last comma. */
338 text[strlen (text) - 2] = '\0';
339 ui_out_field_string (uiout, "what", text);
342 ui_out_field_string (uiout, "what", "<any syscall>");
343 ui_out_text (uiout, "\" ");
345 if (ui_out_is_mi_like_p (uiout))
346 ui_out_field_string (uiout, "catch-type", "syscall");
349 /* Implement the "print_mention" breakpoint_ops method for syscall
353 print_mention_catch_syscall (struct breakpoint *b)
355 struct syscall_catchpoint *c = (struct syscall_catchpoint *) b;
356 struct gdbarch *gdbarch = b->loc->gdbarch;
358 if (c->syscalls_to_be_caught)
362 if (VEC_length (int, c->syscalls_to_be_caught) > 1)
363 printf_filtered (_("Catchpoint %d (syscalls"), b->number);
365 printf_filtered (_("Catchpoint %d (syscall"), b->number);
368 VEC_iterate (int, c->syscalls_to_be_caught, i, iter);
372 get_syscall_by_number (gdbarch, iter, &s);
375 printf_filtered (" '%s' [%d]", s.name, s.number);
377 printf_filtered (" %d", s.number);
379 printf_filtered (")");
382 printf_filtered (_("Catchpoint %d (any syscall)"),
386 /* Implement the "print_recreate" breakpoint_ops method for syscall
390 print_recreate_catch_syscall (struct breakpoint *b, struct ui_file *fp)
392 struct syscall_catchpoint *c = (struct syscall_catchpoint *) b;
393 struct gdbarch *gdbarch = b->loc->gdbarch;
395 fprintf_unfiltered (fp, "catch syscall");
397 if (c->syscalls_to_be_caught)
402 VEC_iterate (int, c->syscalls_to_be_caught, i, iter);
407 get_syscall_by_number (gdbarch, iter, &s);
409 fprintf_unfiltered (fp, " %s", s.name);
411 fprintf_unfiltered (fp, " %d", s.number);
414 print_recreate_thread (b, fp);
417 /* The breakpoint_ops structure to be used in syscall catchpoints. */
419 static struct breakpoint_ops catch_syscall_breakpoint_ops;
421 /* Returns non-zero if 'b' is a syscall catchpoint. */
424 syscall_catchpoint_p (struct breakpoint *b)
426 return (b->ops == &catch_syscall_breakpoint_ops);
430 create_syscall_event_catchpoint (int tempflag, VEC(int) *filter,
431 const struct breakpoint_ops *ops)
433 struct syscall_catchpoint *c;
434 struct gdbarch *gdbarch = get_current_arch ();
436 c = XNEW (struct syscall_catchpoint);
437 init_catchpoint (&c->base, gdbarch, tempflag, NULL, ops);
438 c->syscalls_to_be_caught = filter;
440 install_breakpoint (0, &c->base, 1);
443 /* Splits the argument using space as delimiter. Returns an xmalloc'd
444 filter list, or NULL if no filtering is required. */
446 catch_syscall_split_args (char *arg)
448 VEC(int) *result = NULL;
449 struct cleanup *cleanup = make_cleanup (VEC_cleanup (int), &result);
450 struct gdbarch *gdbarch = target_gdbarch ();
454 int i, syscall_number;
459 /* Skip whitespace. */
460 arg = skip_spaces (arg);
462 for (i = 0; i < 127 && arg[i] && !isspace (arg[i]); ++i)
463 cur_name[i] = arg[i];
467 /* Check if the user provided a syscall name or a number. */
468 syscall_number = (int) strtol (cur_name, &endptr, 0);
470 get_syscall_by_number (gdbarch, syscall_number, &s);
473 /* We have a name. Let's check if it's valid and convert it
475 get_syscall_by_name (gdbarch, cur_name, &s);
477 if (s.number == UNKNOWN_SYSCALL)
478 /* Here we have to issue an error instead of a warning,
479 because GDB cannot do anything useful if there's no
480 syscall number to be caught. */
481 error (_("Unknown syscall name '%s'."), cur_name);
484 /* Ok, it's valid. */
485 VEC_safe_push (int, result, s.number);
488 discard_cleanups (cleanup);
492 /* Implement the "catch syscall" command. */
495 catch_syscall_command_1 (char *arg, int from_tty,
496 struct cmd_list_element *command)
501 struct gdbarch *gdbarch = get_current_arch ();
503 /* Checking if the feature if supported. */
504 if (gdbarch_get_syscall_number_p (gdbarch) == 0)
505 error (_("The feature 'catch syscall' is not supported on \
506 this architecture yet."));
508 tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
510 arg = skip_spaces (arg);
512 /* We need to do this first "dummy" translation in order
513 to get the syscall XML file loaded or, most important,
514 to display a warning to the user if there's no XML file
515 for his/her architecture. */
516 get_syscall_by_number (gdbarch, 0, &s);
518 /* The allowed syntax is:
520 catch syscall <name | number> [<name | number> ... <name | number>]
522 Let's check if there's a syscall name. */
525 filter = catch_syscall_split_args (arg);
529 create_syscall_event_catchpoint (tempflag, filter,
530 &catch_syscall_breakpoint_ops);
534 /* Returns 0 if 'bp' is NOT a syscall catchpoint,
535 non-zero otherwise. */
537 is_syscall_catchpoint_enabled (struct breakpoint *bp)
539 if (syscall_catchpoint_p (bp)
540 && bp->enable_state != bp_disabled
541 && bp->enable_state != bp_call_disabled)
548 catch_syscall_enabled (void)
550 struct catch_syscall_inferior_data *inf_data
551 = get_catch_syscall_inferior_data (current_inferior ());
553 return inf_data->total_syscalls_count != 0;
556 /* Helper function for catching_syscall_number. If B is a syscall
557 catchpoint for SYSCALL_NUMBER, return 1 (which will make
558 'breakpoint_find_if' return). Otherwise, return 0. */
561 catching_syscall_number_1 (struct breakpoint *b,
564 int syscall_number = (int) (uintptr_t) data;
566 if (is_syscall_catchpoint_enabled (b))
568 struct syscall_catchpoint *c = (struct syscall_catchpoint *) b;
570 if (c->syscalls_to_be_caught)
574 VEC_iterate (int, c->syscalls_to_be_caught, i, iter);
576 if (syscall_number == iter)
587 catching_syscall_number (int syscall_number)
589 struct breakpoint *b = breakpoint_find_if (catching_syscall_number_1,
590 (void *) (uintptr_t) syscall_number);
595 /* Complete syscall names. Used by "catch syscall". */
596 static VEC (char_ptr) *
597 catch_syscall_completer (struct cmd_list_element *cmd,
598 const char *text, const char *word)
600 const char **list = get_syscall_names (get_current_arch ());
601 VEC (char_ptr) *retlist
602 = (list == NULL) ? NULL : complete_on_enum (list, word, word);
609 clear_syscall_counts (struct inferior *inf)
611 struct catch_syscall_inferior_data *inf_data
612 = get_catch_syscall_inferior_data (inf);
614 inf_data->total_syscalls_count = 0;
615 inf_data->any_syscall_count = 0;
616 VEC_free (int, inf_data->syscalls_counts);
620 initialize_syscall_catchpoint_ops (void)
622 struct breakpoint_ops *ops;
624 initialize_breakpoint_ops ();
626 /* Syscall catchpoints. */
627 ops = &catch_syscall_breakpoint_ops;
628 *ops = base_breakpoint_ops;
629 ops->dtor = dtor_catch_syscall;
630 ops->insert_location = insert_catch_syscall;
631 ops->remove_location = remove_catch_syscall;
632 ops->breakpoint_hit = breakpoint_hit_catch_syscall;
633 ops->print_it = print_it_catch_syscall;
634 ops->print_one = print_one_catch_syscall;
635 ops->print_mention = print_mention_catch_syscall;
636 ops->print_recreate = print_recreate_catch_syscall;
639 initialize_file_ftype _initialize_break_catch_syscall;
642 _initialize_break_catch_syscall (void)
644 initialize_syscall_catchpoint_ops ();
646 observer_attach_inferior_exit (clear_syscall_counts);
647 catch_syscall_inferior_data
648 = register_inferior_data_with_cleanup (NULL,
649 catch_syscall_inferior_data_cleanup);
651 add_catch_command ("syscall", _("\
652 Catch system calls by their names and/or numbers.\n\
653 Arguments say which system calls to catch. If no arguments\n\
654 are given, every system call will be caught.\n\
655 Arguments, if given, should be one or more system call names\n\
656 (if your system supports that), or system call numbers."),
657 catch_syscall_command_1,
658 catch_syscall_completer,