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". */
615 static VEC (char_ptr
) *
616 catch_syscall_completer (struct cmd_list_element
*cmd
,
617 const char *text
, const char *word
)
619 struct gdbarch
*gdbarch
= get_current_arch ();
620 struct cleanup
*cleanups
= make_cleanup (null_cleanup
, NULL
);
621 VEC (char_ptr
) *group_retlist
= NULL
;
622 VEC (char_ptr
) *syscall_retlist
= NULL
;
623 VEC (char_ptr
) *retlist
= NULL
;
624 const char **group_list
= NULL
;
625 const char **syscall_list
= NULL
;
629 /* Completion considers ':' to be a word separator, so we use this to
630 verify whether the previous word was a group prefix. If so, we
631 build the completion list using group names only. */
632 for (prefix
= word
; prefix
!= text
&& prefix
[-1] != ' '; prefix
--)
635 if (startswith (prefix
, "g:") || startswith (prefix
, "group:"))
637 /* Perform completion inside 'group:' namespace only. */
638 group_list
= get_syscall_group_names (gdbarch
);
639 retlist
= (group_list
== NULL
640 ? NULL
: complete_on_enum (group_list
, word
, word
));
644 /* Complete with both, syscall names and groups. */
645 syscall_list
= get_syscall_names (gdbarch
);
646 group_list
= get_syscall_group_names (gdbarch
);
648 /* Append "group:" prefix to syscall groups. */
649 for (i
= 0; group_list
[i
] != NULL
; i
++)
651 char *prefixed_group
= xstrprintf ("group:%s", group_list
[i
]);
653 group_list
[i
] = prefixed_group
;
654 make_cleanup (xfree
, prefixed_group
);
657 syscall_retlist
= ((syscall_list
== NULL
)
658 ? NULL
: complete_on_enum (syscall_list
, word
, word
));
659 group_retlist
= ((group_list
== NULL
)
660 ? NULL
: complete_on_enum (group_list
, word
, word
));
662 retlist
= VEC_merge (char_ptr
, syscall_retlist
, group_retlist
);
665 VEC_free (char_ptr
, syscall_retlist
);
666 VEC_free (char_ptr
, group_retlist
);
667 xfree (syscall_list
);
669 do_cleanups (cleanups
);
675 clear_syscall_counts (struct inferior
*inf
)
677 struct catch_syscall_inferior_data
*inf_data
678 = get_catch_syscall_inferior_data (inf
);
680 inf_data
->total_syscalls_count
= 0;
681 inf_data
->any_syscall_count
= 0;
682 VEC_free (int, inf_data
->syscalls_counts
);
686 initialize_syscall_catchpoint_ops (void)
688 struct breakpoint_ops
*ops
;
690 initialize_breakpoint_ops ();
692 /* Syscall catchpoints. */
693 ops
= &catch_syscall_breakpoint_ops
;
694 *ops
= base_breakpoint_ops
;
695 ops
->insert_location
= insert_catch_syscall
;
696 ops
->remove_location
= remove_catch_syscall
;
697 ops
->breakpoint_hit
= breakpoint_hit_catch_syscall
;
698 ops
->print_it
= print_it_catch_syscall
;
699 ops
->print_one
= print_one_catch_syscall
;
700 ops
->print_mention
= print_mention_catch_syscall
;
701 ops
->print_recreate
= print_recreate_catch_syscall
;
704 initialize_file_ftype _initialize_break_catch_syscall
;
707 _initialize_break_catch_syscall (void)
709 initialize_syscall_catchpoint_ops ();
711 observer_attach_inferior_exit (clear_syscall_counts
);
712 catch_syscall_inferior_data
713 = register_inferior_data_with_cleanup (NULL
,
714 catch_syscall_inferior_data_cleanup
);
716 add_catch_command ("syscall", _("\
717 Catch system calls by their names, groups and/or numbers.\n\
718 Arguments say which system calls to catch. If no arguments are given,\n\
719 every system call will be caught. Arguments, if given, should be one\n\
720 or more system call names (if your system supports that), system call\n\
721 groups or system call numbers."),
722 catch_syscall_command_1
,
723 catch_syscall_completer
,