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 numbers used for the 'catch syscall' feature. If no
40 syscall has been specified for filtering, it is empty.
41 Otherwise, it holds a list of all syscalls to be caught. */
42 std::vector
<int> syscalls_to_be_caught
;
45 static const struct inferior_data
*catch_syscall_inferior_data
= NULL
;
47 struct catch_syscall_inferior_data
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. */
53 /* Number of times that "any" syscall is requested. */
54 int any_syscall_count
;
56 /* Count of each system call. */
57 VEC(int) *syscalls_counts
;
59 /* This counts all syscall catch requests, so we can readily determine
60 if any catching is necessary. */
61 int total_syscalls_count
;
64 static struct catch_syscall_inferior_data
*
65 get_catch_syscall_inferior_data (struct inferior
*inf
)
67 struct catch_syscall_inferior_data
*inf_data
;
69 inf_data
= ((struct catch_syscall_inferior_data
*)
70 inferior_data (inf
, catch_syscall_inferior_data
));
73 inf_data
= XCNEW (struct catch_syscall_inferior_data
);
74 set_inferior_data (inf
, catch_syscall_inferior_data
, inf_data
);
81 catch_syscall_inferior_data_cleanup (struct inferior
*inf
, void *arg
)
87 /* Implement the "insert" breakpoint_ops method for syscall
91 insert_catch_syscall (struct bp_location
*bl
)
93 struct syscall_catchpoint
*c
= (struct syscall_catchpoint
*) bl
->owner
;
94 struct inferior
*inf
= current_inferior ();
95 struct catch_syscall_inferior_data
*inf_data
96 = get_catch_syscall_inferior_data (inf
);
98 ++inf_data
->total_syscalls_count
;
99 if (c
->syscalls_to_be_caught
.empty ())
100 ++inf_data
->any_syscall_count
;
103 for (int iter
: c
->syscalls_to_be_caught
)
107 if (iter
>= VEC_length (int, inf_data
->syscalls_counts
))
109 int old_size
= VEC_length (int, inf_data
->syscalls_counts
);
110 uintptr_t vec_addr_offset
111 = old_size
* ((uintptr_t) sizeof (int));
113 VEC_safe_grow (int, inf_data
->syscalls_counts
, iter
+ 1);
114 vec_addr
= ((uintptr_t) VEC_address (int,
115 inf_data
->syscalls_counts
)
117 memset ((void *) vec_addr
, 0,
118 (iter
+ 1 - old_size
) * sizeof (int));
120 elem
= VEC_index (int, inf_data
->syscalls_counts
, iter
);
121 VEC_replace (int, inf_data
->syscalls_counts
, iter
, ++elem
);
125 return target_set_syscall_catchpoint (ptid_get_pid (inferior_ptid
),
126 inf_data
->total_syscalls_count
!= 0,
127 inf_data
->any_syscall_count
,
129 inf_data
->syscalls_counts
),
131 inf_data
->syscalls_counts
));
134 /* Implement the "remove" breakpoint_ops method for syscall
138 remove_catch_syscall (struct bp_location
*bl
, enum remove_bp_reason reason
)
140 struct syscall_catchpoint
*c
= (struct syscall_catchpoint
*) bl
->owner
;
141 struct inferior
*inf
= current_inferior ();
142 struct catch_syscall_inferior_data
*inf_data
143 = get_catch_syscall_inferior_data (inf
);
145 --inf_data
->total_syscalls_count
;
146 if (c
->syscalls_to_be_caught
.empty ())
147 --inf_data
->any_syscall_count
;
150 for (int iter
: c
->syscalls_to_be_caught
)
153 if (iter
>= VEC_length (int, inf_data
->syscalls_counts
))
154 /* Shouldn't happen. */
156 elem
= VEC_index (int, inf_data
->syscalls_counts
, iter
);
157 VEC_replace (int, inf_data
->syscalls_counts
, iter
, --elem
);
161 return target_set_syscall_catchpoint (ptid_get_pid (inferior_ptid
),
162 inf_data
->total_syscalls_count
!= 0,
163 inf_data
->any_syscall_count
,
165 inf_data
->syscalls_counts
),
167 inf_data
->syscalls_counts
));
170 /* Implement the "breakpoint_hit" breakpoint_ops method for syscall
174 breakpoint_hit_catch_syscall (const struct bp_location
*bl
,
175 struct address_space
*aspace
, CORE_ADDR bp_addr
,
176 const struct target_waitstatus
*ws
)
178 /* We must check if we are catching specific syscalls in this
179 breakpoint. If we are, then we must guarantee that the called
180 syscall is the same syscall we are catching. */
181 int syscall_number
= 0;
182 const struct syscall_catchpoint
*c
183 = (const struct syscall_catchpoint
*) bl
->owner
;
185 if (ws
->kind
!= TARGET_WAITKIND_SYSCALL_ENTRY
186 && ws
->kind
!= TARGET_WAITKIND_SYSCALL_RETURN
)
189 syscall_number
= ws
->value
.syscall_number
;
191 /* Now, checking if the syscall is the same. */
192 if (!c
->syscalls_to_be_caught
.empty ())
194 for (int iter
: c
->syscalls_to_be_caught
)
195 if (syscall_number
== iter
)
204 /* Implement the "print_it" breakpoint_ops method for syscall
207 static enum print_stop_action
208 print_it_catch_syscall (bpstat bs
)
210 struct ui_out
*uiout
= current_uiout
;
211 struct breakpoint
*b
= bs
->breakpoint_at
;
212 /* These are needed because we want to know in which state a
213 syscall is. It can be in the TARGET_WAITKIND_SYSCALL_ENTRY
214 or TARGET_WAITKIND_SYSCALL_RETURN, and depending on it we
215 must print "called syscall" or "returned from syscall". */
217 struct target_waitstatus last
;
219 struct gdbarch
*gdbarch
= bs
->bp_location_at
->gdbarch
;
221 get_last_target_status (&ptid
, &last
);
223 get_syscall_by_number (gdbarch
, last
.value
.syscall_number
, &s
);
225 annotate_catchpoint (b
->number
);
226 maybe_print_thread_hit_breakpoint (uiout
);
228 if (b
->disposition
== disp_del
)
229 uiout
->text ("Temporary catchpoint ");
231 uiout
->text ("Catchpoint ");
232 if (uiout
->is_mi_like_p ())
234 uiout
->field_string ("reason",
235 async_reason_lookup (last
.kind
== TARGET_WAITKIND_SYSCALL_ENTRY
236 ? EXEC_ASYNC_SYSCALL_ENTRY
237 : EXEC_ASYNC_SYSCALL_RETURN
));
238 uiout
->field_string ("disp", bpdisp_text (b
->disposition
));
240 uiout
->field_int ("bkptno", b
->number
);
242 if (last
.kind
== TARGET_WAITKIND_SYSCALL_ENTRY
)
243 uiout
->text (" (call to syscall ");
245 uiout
->text (" (returned from syscall ");
247 if (s
.name
== NULL
|| uiout
->is_mi_like_p ())
248 uiout
->field_int ("syscall-number", last
.value
.syscall_number
);
250 uiout
->field_string ("syscall-name", s
.name
);
254 return PRINT_SRC_AND_LOC
;
257 /* Implement the "print_one" breakpoint_ops method for syscall
261 print_one_catch_syscall (struct breakpoint
*b
,
262 struct bp_location
**last_loc
)
264 struct syscall_catchpoint
*c
= (struct syscall_catchpoint
*) b
;
265 struct value_print_options opts
;
266 struct ui_out
*uiout
= current_uiout
;
267 struct gdbarch
*gdbarch
= b
->loc
->gdbarch
;
269 get_user_print_options (&opts
);
270 /* Field 4, the address, is omitted (which makes the columns not
271 line up too nicely with the headers, but the effect is relatively
273 if (opts
.addressprint
)
274 uiout
->field_skip ("addr");
277 if (c
->syscalls_to_be_caught
.size () > 1)
278 uiout
->text ("syscalls \"");
280 uiout
->text ("syscall \"");
282 if (!c
->syscalls_to_be_caught
.empty ())
284 char *text
= xstrprintf ("%s", "");
286 for (int iter
: c
->syscalls_to_be_caught
)
290 get_syscall_by_number (gdbarch
, iter
, &s
);
293 text
= xstrprintf ("%s%s, ", text
, s
.name
);
295 text
= xstrprintf ("%s%d, ", text
, iter
);
297 /* We have to xfree the last 'text' (now stored at 'x')
298 because xstrprintf dynamically allocates new space for it
302 /* Remove the last comma. */
303 text
[strlen (text
) - 2] = '\0';
304 uiout
->field_string ("what", text
);
307 uiout
->field_string ("what", "<any syscall>");
310 if (uiout
->is_mi_like_p ())
311 uiout
->field_string ("catch-type", "syscall");
314 /* Implement the "print_mention" breakpoint_ops method for syscall
318 print_mention_catch_syscall (struct breakpoint
*b
)
320 struct syscall_catchpoint
*c
= (struct syscall_catchpoint
*) b
;
321 struct gdbarch
*gdbarch
= b
->loc
->gdbarch
;
323 if (!c
->syscalls_to_be_caught
.empty ())
325 if (c
->syscalls_to_be_caught
.size () > 1)
326 printf_filtered (_("Catchpoint %d (syscalls"), b
->number
);
328 printf_filtered (_("Catchpoint %d (syscall"), b
->number
);
330 for (int iter
: c
->syscalls_to_be_caught
)
333 get_syscall_by_number (gdbarch
, iter
, &s
);
336 printf_filtered (" '%s' [%d]", s
.name
, s
.number
);
338 printf_filtered (" %d", s
.number
);
340 printf_filtered (")");
343 printf_filtered (_("Catchpoint %d (any syscall)"),
347 /* Implement the "print_recreate" breakpoint_ops method for syscall
351 print_recreate_catch_syscall (struct breakpoint
*b
, struct ui_file
*fp
)
353 struct syscall_catchpoint
*c
= (struct syscall_catchpoint
*) b
;
354 struct gdbarch
*gdbarch
= b
->loc
->gdbarch
;
356 fprintf_unfiltered (fp
, "catch syscall");
358 for (int iter
: c
->syscalls_to_be_caught
)
362 get_syscall_by_number (gdbarch
, iter
, &s
);
364 fprintf_unfiltered (fp
, " %s", s
.name
);
366 fprintf_unfiltered (fp
, " %d", s
.number
);
369 print_recreate_thread (b
, fp
);
372 /* The breakpoint_ops structure to be used in syscall catchpoints. */
374 static struct breakpoint_ops catch_syscall_breakpoint_ops
;
376 /* Returns non-zero if 'b' is a syscall catchpoint. */
379 syscall_catchpoint_p (struct breakpoint
*b
)
381 return (b
->ops
== &catch_syscall_breakpoint_ops
);
385 create_syscall_event_catchpoint (int tempflag
, std::vector
<int> &&filter
,
386 const struct breakpoint_ops
*ops
)
388 struct syscall_catchpoint
*c
;
389 struct gdbarch
*gdbarch
= get_current_arch ();
391 c
= new syscall_catchpoint ();
392 init_catchpoint (c
, gdbarch
, tempflag
, NULL
, ops
);
393 c
->syscalls_to_be_caught
= filter
;
395 install_breakpoint (0, c
, 1);
398 /* Splits the argument using space as delimiter. */
400 static std::vector
<int>
401 catch_syscall_split_args (char *arg
)
403 std::vector
<int> result
;
404 struct gdbarch
*gdbarch
= target_gdbarch ();
408 int i
, syscall_number
;
413 /* Skip whitespace. */
414 arg
= skip_spaces (arg
);
416 for (i
= 0; i
< 127 && arg
[i
] && !isspace (arg
[i
]); ++i
)
417 cur_name
[i
] = arg
[i
];
421 /* Check if the user provided a syscall name, group, or a number. */
422 syscall_number
= (int) strtol (cur_name
, &endptr
, 0);
425 get_syscall_by_number (gdbarch
, syscall_number
, &s
);
426 result
.push_back (s
.number
);
428 else if (startswith (cur_name
, "g:")
429 || startswith (cur_name
, "group:"))
431 /* We have a syscall group. Let's expand it into a syscall
432 list before inserting. */
433 struct syscall
*syscall_list
;
434 const char *group_name
;
436 /* Skip over "g:" and "group:" prefix strings. */
437 group_name
= strchr (cur_name
, ':') + 1;
439 syscall_list
= get_syscalls_by_group (gdbarch
, group_name
);
441 if (syscall_list
== NULL
)
442 error (_("Unknown syscall group '%s'."), group_name
);
444 for (i
= 0; syscall_list
[i
].name
!= NULL
; i
++)
446 /* Insert each syscall that are part of the group. No
447 need to check if it is valid. */
448 result
.push_back (syscall_list
[i
].number
);
451 xfree (syscall_list
);
455 /* We have a name. Let's check if it's valid and convert it
457 get_syscall_by_name (gdbarch
, cur_name
, &s
);
459 if (s
.number
== UNKNOWN_SYSCALL
)
460 /* Here we have to issue an error instead of a warning,
461 because GDB cannot do anything useful if there's no
462 syscall number to be caught. */
463 error (_("Unknown syscall name '%s'."), cur_name
);
465 /* Ok, it's valid. */
466 result
.push_back (s
.number
);
473 /* Implement the "catch syscall" command. */
476 catch_syscall_command_1 (char *arg
, int from_tty
,
477 struct cmd_list_element
*command
)
480 std::vector
<int> filter
;
482 struct gdbarch
*gdbarch
= get_current_arch ();
484 /* Checking if the feature if supported. */
485 if (gdbarch_get_syscall_number_p (gdbarch
) == 0)
486 error (_("The feature 'catch syscall' is not supported on \
487 this architecture yet."));
489 tempflag
= get_cmd_context (command
) == CATCH_TEMPORARY
;
491 arg
= skip_spaces (arg
);
493 /* We need to do this first "dummy" translation in order
494 to get the syscall XML file loaded or, most important,
495 to display a warning to the user if there's no XML file
496 for his/her architecture. */
497 get_syscall_by_number (gdbarch
, 0, &s
);
499 /* The allowed syntax is:
501 catch syscall <name | number> [<name | number> ... <name | number>]
503 Let's check if there's a syscall name. */
506 filter
= catch_syscall_split_args (arg
);
508 create_syscall_event_catchpoint (tempflag
, std::move (filter
),
509 &catch_syscall_breakpoint_ops
);
513 /* Returns 0 if 'bp' is NOT a syscall catchpoint,
514 non-zero otherwise. */
516 is_syscall_catchpoint_enabled (struct breakpoint
*bp
)
518 if (syscall_catchpoint_p (bp
)
519 && bp
->enable_state
!= bp_disabled
520 && bp
->enable_state
!= bp_call_disabled
)
527 catch_syscall_enabled (void)
529 struct catch_syscall_inferior_data
*inf_data
530 = get_catch_syscall_inferior_data (current_inferior ());
532 return inf_data
->total_syscalls_count
!= 0;
535 /* Helper function for catching_syscall_number. If B is a syscall
536 catchpoint for SYSCALL_NUMBER, return 1 (which will make
537 'breakpoint_find_if' return). Otherwise, return 0. */
540 catching_syscall_number_1 (struct breakpoint
*b
,
543 int syscall_number
= (int) (uintptr_t) data
;
545 if (is_syscall_catchpoint_enabled (b
))
547 struct syscall_catchpoint
*c
= (struct syscall_catchpoint
*) b
;
549 if (!c
->syscalls_to_be_caught
.empty ())
551 for (int iter
: c
->syscalls_to_be_caught
)
552 if (syscall_number
== iter
)
563 catching_syscall_number (int syscall_number
)
565 struct breakpoint
*b
= breakpoint_find_if (catching_syscall_number_1
,
566 (void *) (uintptr_t) syscall_number
);
571 /* Complete syscall names. Used by "catch syscall". */
574 catch_syscall_completer (struct cmd_list_element
*cmd
,
575 completion_tracker
&tracker
,
576 const char *text
, const char *word
)
578 struct gdbarch
*gdbarch
= get_current_arch ();
579 struct cleanup
*cleanups
= make_cleanup (null_cleanup
, NULL
);
580 const char **group_list
= NULL
;
581 const char **syscall_list
= NULL
;
585 /* Completion considers ':' to be a word separator, so we use this to
586 verify whether the previous word was a group prefix. If so, we
587 build the completion list using group names only. */
588 for (prefix
= word
; prefix
!= text
&& prefix
[-1] != ' '; prefix
--)
591 if (startswith (prefix
, "g:") || startswith (prefix
, "group:"))
593 /* Perform completion inside 'group:' namespace only. */
594 group_list
= get_syscall_group_names (gdbarch
);
595 if (group_list
!= NULL
)
596 complete_on_enum (tracker
, group_list
, word
, word
);
600 /* Complete with both, syscall names and groups. */
601 syscall_list
= get_syscall_names (gdbarch
);
602 group_list
= get_syscall_group_names (gdbarch
);
604 /* Append "group:" prefix to syscall groups. */
605 for (i
= 0; group_list
[i
] != NULL
; i
++)
607 char *prefixed_group
= xstrprintf ("group:%s", group_list
[i
]);
609 group_list
[i
] = prefixed_group
;
610 make_cleanup (xfree
, prefixed_group
);
613 if (syscall_list
!= NULL
)
614 complete_on_enum (tracker
, syscall_list
, word
, word
);
615 if (group_list
!= NULL
)
616 complete_on_enum (tracker
, group_list
, word
, word
);
619 xfree (syscall_list
);
621 do_cleanups (cleanups
);
625 clear_syscall_counts (struct inferior
*inf
)
627 struct catch_syscall_inferior_data
*inf_data
628 = get_catch_syscall_inferior_data (inf
);
630 inf_data
->total_syscalls_count
= 0;
631 inf_data
->any_syscall_count
= 0;
632 VEC_free (int, inf_data
->syscalls_counts
);
636 initialize_syscall_catchpoint_ops (void)
638 struct breakpoint_ops
*ops
;
640 initialize_breakpoint_ops ();
642 /* Syscall catchpoints. */
643 ops
= &catch_syscall_breakpoint_ops
;
644 *ops
= base_breakpoint_ops
;
645 ops
->insert_location
= insert_catch_syscall
;
646 ops
->remove_location
= remove_catch_syscall
;
647 ops
->breakpoint_hit
= breakpoint_hit_catch_syscall
;
648 ops
->print_it
= print_it_catch_syscall
;
649 ops
->print_one
= print_one_catch_syscall
;
650 ops
->print_mention
= print_mention_catch_syscall
;
651 ops
->print_recreate
= print_recreate_catch_syscall
;
654 initialize_file_ftype _initialize_break_catch_syscall
;
657 _initialize_break_catch_syscall (void)
659 initialize_syscall_catchpoint_ops ();
661 observer_attach_inferior_exit (clear_syscall_counts
);
662 catch_syscall_inferior_data
663 = register_inferior_data_with_cleanup (NULL
,
664 catch_syscall_inferior_data_cleanup
);
666 add_catch_command ("syscall", _("\
667 Catch system calls by their names, groups and/or numbers.\n\
668 Arguments say which system calls to catch. If no arguments are given,\n\
669 every system call will be caught. Arguments, if given, should be one\n\
670 or more system call names (if your system supports that), system call\n\
671 groups or system call numbers."),
672 catch_syscall_command_1
,
673 catch_syscall_completer
,