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 std::vector
<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
= new 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
)
83 struct catch_syscall_inferior_data
*inf_data
84 = (struct catch_syscall_inferior_data
*) arg
;
89 /* Implement the "insert" breakpoint_ops method for syscall
93 insert_catch_syscall (struct bp_location
*bl
)
95 struct syscall_catchpoint
*c
= (struct syscall_catchpoint
*) bl
->owner
;
96 struct inferior
*inf
= current_inferior ();
97 struct catch_syscall_inferior_data
*inf_data
98 = get_catch_syscall_inferior_data (inf
);
100 ++inf_data
->total_syscalls_count
;
101 if (c
->syscalls_to_be_caught
.empty ())
102 ++inf_data
->any_syscall_count
;
105 for (int iter
: c
->syscalls_to_be_caught
)
107 if (iter
>= inf_data
->syscalls_counts
.size ())
108 inf_data
->syscalls_counts
.resize (iter
+ 1);
109 ++inf_data
->syscalls_counts
[iter
];
113 return target_set_syscall_catchpoint (ptid_get_pid (inferior_ptid
),
114 inf_data
->total_syscalls_count
!= 0,
115 inf_data
->any_syscall_count
,
116 inf_data
->syscalls_counts
.size (),
117 inf_data
->syscalls_counts
.data ());
120 /* Implement the "remove" breakpoint_ops method for syscall
124 remove_catch_syscall (struct bp_location
*bl
, enum remove_bp_reason reason
)
126 struct syscall_catchpoint
*c
= (struct syscall_catchpoint
*) bl
->owner
;
127 struct inferior
*inf
= current_inferior ();
128 struct catch_syscall_inferior_data
*inf_data
129 = get_catch_syscall_inferior_data (inf
);
131 --inf_data
->total_syscalls_count
;
132 if (c
->syscalls_to_be_caught
.empty ())
133 --inf_data
->any_syscall_count
;
136 for (int iter
: c
->syscalls_to_be_caught
)
138 if (iter
>= inf_data
->syscalls_counts
.size ())
139 /* Shouldn't happen. */
141 --inf_data
->syscalls_counts
[iter
];
145 return target_set_syscall_catchpoint (ptid_get_pid (inferior_ptid
),
146 inf_data
->total_syscalls_count
!= 0,
147 inf_data
->any_syscall_count
,
148 inf_data
->syscalls_counts
.size (),
149 inf_data
->syscalls_counts
.data ());
152 /* Implement the "breakpoint_hit" breakpoint_ops method for syscall
156 breakpoint_hit_catch_syscall (const struct bp_location
*bl
,
157 const address_space
*aspace
, CORE_ADDR bp_addr
,
158 const struct target_waitstatus
*ws
)
160 /* We must check if we are catching specific syscalls in this
161 breakpoint. If we are, then we must guarantee that the called
162 syscall is the same syscall we are catching. */
163 int syscall_number
= 0;
164 const struct syscall_catchpoint
*c
165 = (const struct syscall_catchpoint
*) bl
->owner
;
167 if (ws
->kind
!= TARGET_WAITKIND_SYSCALL_ENTRY
168 && ws
->kind
!= TARGET_WAITKIND_SYSCALL_RETURN
)
171 syscall_number
= ws
->value
.syscall_number
;
173 /* Now, checking if the syscall is the same. */
174 if (!c
->syscalls_to_be_caught
.empty ())
176 for (int iter
: c
->syscalls_to_be_caught
)
177 if (syscall_number
== iter
)
186 /* Implement the "print_it" breakpoint_ops method for syscall
189 static enum print_stop_action
190 print_it_catch_syscall (bpstat bs
)
192 struct ui_out
*uiout
= current_uiout
;
193 struct breakpoint
*b
= bs
->breakpoint_at
;
194 /* These are needed because we want to know in which state a
195 syscall is. It can be in the TARGET_WAITKIND_SYSCALL_ENTRY
196 or TARGET_WAITKIND_SYSCALL_RETURN, and depending on it we
197 must print "called syscall" or "returned from syscall". */
199 struct target_waitstatus last
;
201 struct gdbarch
*gdbarch
= bs
->bp_location_at
->gdbarch
;
203 get_last_target_status (&ptid
, &last
);
205 get_syscall_by_number (gdbarch
, last
.value
.syscall_number
, &s
);
207 annotate_catchpoint (b
->number
);
208 maybe_print_thread_hit_breakpoint (uiout
);
210 if (b
->disposition
== disp_del
)
211 uiout
->text ("Temporary catchpoint ");
213 uiout
->text ("Catchpoint ");
214 if (uiout
->is_mi_like_p ())
216 uiout
->field_string ("reason",
217 async_reason_lookup (last
.kind
== TARGET_WAITKIND_SYSCALL_ENTRY
218 ? EXEC_ASYNC_SYSCALL_ENTRY
219 : EXEC_ASYNC_SYSCALL_RETURN
));
220 uiout
->field_string ("disp", bpdisp_text (b
->disposition
));
222 uiout
->field_int ("bkptno", b
->number
);
224 if (last
.kind
== TARGET_WAITKIND_SYSCALL_ENTRY
)
225 uiout
->text (" (call to syscall ");
227 uiout
->text (" (returned from syscall ");
229 if (s
.name
== NULL
|| uiout
->is_mi_like_p ())
230 uiout
->field_int ("syscall-number", last
.value
.syscall_number
);
232 uiout
->field_string ("syscall-name", s
.name
);
236 return PRINT_SRC_AND_LOC
;
239 /* Implement the "print_one" breakpoint_ops method for syscall
243 print_one_catch_syscall (struct breakpoint
*b
,
244 struct bp_location
**last_loc
)
246 struct syscall_catchpoint
*c
= (struct syscall_catchpoint
*) b
;
247 struct value_print_options opts
;
248 struct ui_out
*uiout
= current_uiout
;
249 struct gdbarch
*gdbarch
= b
->loc
->gdbarch
;
251 get_user_print_options (&opts
);
252 /* Field 4, the address, is omitted (which makes the columns not
253 line up too nicely with the headers, but the effect is relatively
255 if (opts
.addressprint
)
256 uiout
->field_skip ("addr");
259 if (c
->syscalls_to_be_caught
.size () > 1)
260 uiout
->text ("syscalls \"");
262 uiout
->text ("syscall \"");
264 if (!c
->syscalls_to_be_caught
.empty ())
266 char *text
= xstrprintf ("%s", "");
268 for (int iter
: c
->syscalls_to_be_caught
)
272 get_syscall_by_number (gdbarch
, iter
, &s
);
275 text
= xstrprintf ("%s%s, ", text
, s
.name
);
277 text
= xstrprintf ("%s%d, ", text
, iter
);
279 /* We have to xfree the last 'text' (now stored at 'x')
280 because xstrprintf dynamically allocates new space for it
284 /* Remove the last comma. */
285 text
[strlen (text
) - 2] = '\0';
286 uiout
->field_string ("what", text
);
289 uiout
->field_string ("what", "<any syscall>");
292 if (uiout
->is_mi_like_p ())
293 uiout
->field_string ("catch-type", "syscall");
296 /* Implement the "print_mention" breakpoint_ops method for syscall
300 print_mention_catch_syscall (struct breakpoint
*b
)
302 struct syscall_catchpoint
*c
= (struct syscall_catchpoint
*) b
;
303 struct gdbarch
*gdbarch
= b
->loc
->gdbarch
;
305 if (!c
->syscalls_to_be_caught
.empty ())
307 if (c
->syscalls_to_be_caught
.size () > 1)
308 printf_filtered (_("Catchpoint %d (syscalls"), b
->number
);
310 printf_filtered (_("Catchpoint %d (syscall"), b
->number
);
312 for (int iter
: c
->syscalls_to_be_caught
)
315 get_syscall_by_number (gdbarch
, iter
, &s
);
318 printf_filtered (" '%s' [%d]", s
.name
, s
.number
);
320 printf_filtered (" %d", s
.number
);
322 printf_filtered (")");
325 printf_filtered (_("Catchpoint %d (any syscall)"),
329 /* Implement the "print_recreate" breakpoint_ops method for syscall
333 print_recreate_catch_syscall (struct breakpoint
*b
, struct ui_file
*fp
)
335 struct syscall_catchpoint
*c
= (struct syscall_catchpoint
*) b
;
336 struct gdbarch
*gdbarch
= b
->loc
->gdbarch
;
338 fprintf_unfiltered (fp
, "catch syscall");
340 for (int iter
: c
->syscalls_to_be_caught
)
344 get_syscall_by_number (gdbarch
, iter
, &s
);
346 fprintf_unfiltered (fp
, " %s", s
.name
);
348 fprintf_unfiltered (fp
, " %d", s
.number
);
351 print_recreate_thread (b
, fp
);
354 /* The breakpoint_ops structure to be used in syscall catchpoints. */
356 static struct breakpoint_ops catch_syscall_breakpoint_ops
;
358 /* Returns non-zero if 'b' is a syscall catchpoint. */
361 syscall_catchpoint_p (struct breakpoint
*b
)
363 return (b
->ops
== &catch_syscall_breakpoint_ops
);
367 create_syscall_event_catchpoint (int tempflag
, std::vector
<int> &&filter
,
368 const struct breakpoint_ops
*ops
)
370 struct gdbarch
*gdbarch
= get_current_arch ();
372 std::unique_ptr
<syscall_catchpoint
> c (new syscall_catchpoint ());
373 init_catchpoint (c
.get (), gdbarch
, tempflag
, NULL
, ops
);
374 c
->syscalls_to_be_caught
= std::move (filter
);
376 install_breakpoint (0, std::move (c
), 1);
379 /* Splits the argument using space as delimiter. */
381 static std::vector
<int>
382 catch_syscall_split_args (const char *arg
)
384 std::vector
<int> result
;
385 struct gdbarch
*gdbarch
= target_gdbarch ();
389 int i
, syscall_number
;
394 /* Skip whitespace. */
395 arg
= skip_spaces (arg
);
397 for (i
= 0; i
< 127 && arg
[i
] && !isspace (arg
[i
]); ++i
)
398 cur_name
[i
] = arg
[i
];
402 /* Check if the user provided a syscall name, group, or a number. */
403 syscall_number
= (int) strtol (cur_name
, &endptr
, 0);
406 get_syscall_by_number (gdbarch
, syscall_number
, &s
);
407 result
.push_back (s
.number
);
409 else if (startswith (cur_name
, "g:")
410 || startswith (cur_name
, "group:"))
412 /* We have a syscall group. Let's expand it into a syscall
413 list before inserting. */
414 struct syscall
*syscall_list
;
415 const char *group_name
;
417 /* Skip over "g:" and "group:" prefix strings. */
418 group_name
= strchr (cur_name
, ':') + 1;
420 syscall_list
= get_syscalls_by_group (gdbarch
, group_name
);
422 if (syscall_list
== NULL
)
423 error (_("Unknown syscall group '%s'."), group_name
);
425 for (i
= 0; syscall_list
[i
].name
!= NULL
; i
++)
427 /* Insert each syscall that are part of the group. No
428 need to check if it is valid. */
429 result
.push_back (syscall_list
[i
].number
);
432 xfree (syscall_list
);
436 /* We have a name. Let's check if it's valid and convert it
438 get_syscall_by_name (gdbarch
, cur_name
, &s
);
440 if (s
.number
== UNKNOWN_SYSCALL
)
441 /* Here we have to issue an error instead of a warning,
442 because GDB cannot do anything useful if there's no
443 syscall number to be caught. */
444 error (_("Unknown syscall name '%s'."), cur_name
);
446 /* Ok, it's valid. */
447 result
.push_back (s
.number
);
454 /* Implement the "catch syscall" command. */
457 catch_syscall_command_1 (const char *arg
, int from_tty
,
458 struct cmd_list_element
*command
)
461 std::vector
<int> filter
;
463 struct gdbarch
*gdbarch
= get_current_arch ();
465 /* Checking if the feature if supported. */
466 if (gdbarch_get_syscall_number_p (gdbarch
) == 0)
467 error (_("The feature 'catch syscall' is not supported on \
468 this architecture yet."));
470 tempflag
= get_cmd_context (command
) == CATCH_TEMPORARY
;
472 arg
= skip_spaces (arg
);
474 /* We need to do this first "dummy" translation in order
475 to get the syscall XML file loaded or, most important,
476 to display a warning to the user if there's no XML file
477 for his/her architecture. */
478 get_syscall_by_number (gdbarch
, 0, &s
);
480 /* The allowed syntax is:
482 catch syscall <name | number> [<name | number> ... <name | number>]
484 Let's check if there's a syscall name. */
487 filter
= catch_syscall_split_args (arg
);
489 create_syscall_event_catchpoint (tempflag
, std::move (filter
),
490 &catch_syscall_breakpoint_ops
);
494 /* Returns 0 if 'bp' is NOT a syscall catchpoint,
495 non-zero otherwise. */
497 is_syscall_catchpoint_enabled (struct breakpoint
*bp
)
499 if (syscall_catchpoint_p (bp
)
500 && bp
->enable_state
!= bp_disabled
501 && bp
->enable_state
!= bp_call_disabled
)
508 catch_syscall_enabled (void)
510 struct catch_syscall_inferior_data
*inf_data
511 = get_catch_syscall_inferior_data (current_inferior ());
513 return inf_data
->total_syscalls_count
!= 0;
516 /* Helper function for catching_syscall_number. If B is a syscall
517 catchpoint for SYSCALL_NUMBER, return 1 (which will make
518 'breakpoint_find_if' return). Otherwise, return 0. */
521 catching_syscall_number_1 (struct breakpoint
*b
,
524 int syscall_number
= (int) (uintptr_t) data
;
526 if (is_syscall_catchpoint_enabled (b
))
528 struct syscall_catchpoint
*c
= (struct syscall_catchpoint
*) b
;
530 if (!c
->syscalls_to_be_caught
.empty ())
532 for (int iter
: c
->syscalls_to_be_caught
)
533 if (syscall_number
== iter
)
544 catching_syscall_number (int syscall_number
)
546 struct breakpoint
*b
= breakpoint_find_if (catching_syscall_number_1
,
547 (void *) (uintptr_t) syscall_number
);
552 /* Complete syscall names. Used by "catch syscall". */
555 catch_syscall_completer (struct cmd_list_element
*cmd
,
556 completion_tracker
&tracker
,
557 const char *text
, const char *word
)
559 struct gdbarch
*gdbarch
= get_current_arch ();
560 gdb::unique_xmalloc_ptr
<const char *> group_list
;
564 /* Completion considers ':' to be a word separator, so we use this to
565 verify whether the previous word was a group prefix. If so, we
566 build the completion list using group names only. */
567 for (prefix
= word
; prefix
!= text
&& prefix
[-1] != ' '; prefix
--)
570 if (startswith (prefix
, "g:") || startswith (prefix
, "group:"))
572 /* Perform completion inside 'group:' namespace only. */
573 group_list
.reset (get_syscall_group_names (gdbarch
));
574 if (group_list
!= NULL
)
575 complete_on_enum (tracker
, group_list
.get (), word
, word
);
579 /* Complete with both, syscall names and groups. */
580 gdb::unique_xmalloc_ptr
<const char *> syscall_list
581 (get_syscall_names (gdbarch
));
582 group_list
.reset (get_syscall_group_names (gdbarch
));
584 const char **group_ptr
= group_list
.get ();
586 /* Hold on to strings while we're using them. */
587 std::vector
<std::string
> holders
;
589 /* Append "group:" prefix to syscall groups. */
590 for (i
= 0; group_ptr
[i
] != NULL
; i
++)
592 std::string prefixed_group
= string_printf ("group:%s",
595 group_ptr
[i
] = prefixed_group
.c_str ();
596 holders
.push_back (std::move (prefixed_group
));
599 if (syscall_list
!= NULL
)
600 complete_on_enum (tracker
, syscall_list
.get (), word
, word
);
601 if (group_list
!= NULL
)
602 complete_on_enum (tracker
, group_ptr
, word
, word
);
607 clear_syscall_counts (struct inferior
*inf
)
609 struct catch_syscall_inferior_data
*inf_data
610 = get_catch_syscall_inferior_data (inf
);
612 inf_data
->total_syscalls_count
= 0;
613 inf_data
->any_syscall_count
= 0;
614 inf_data
->syscalls_counts
.clear ();
618 initialize_syscall_catchpoint_ops (void)
620 struct breakpoint_ops
*ops
;
622 initialize_breakpoint_ops ();
624 /* Syscall catchpoints. */
625 ops
= &catch_syscall_breakpoint_ops
;
626 *ops
= base_breakpoint_ops
;
627 ops
->insert_location
= insert_catch_syscall
;
628 ops
->remove_location
= remove_catch_syscall
;
629 ops
->breakpoint_hit
= breakpoint_hit_catch_syscall
;
630 ops
->print_it
= print_it_catch_syscall
;
631 ops
->print_one
= print_one_catch_syscall
;
632 ops
->print_mention
= print_mention_catch_syscall
;
633 ops
->print_recreate
= print_recreate_catch_syscall
;
637 _initialize_break_catch_syscall (void)
639 initialize_syscall_catchpoint_ops ();
641 observer_attach_inferior_exit (clear_syscall_counts
);
642 catch_syscall_inferior_data
643 = register_inferior_data_with_cleanup (NULL
,
644 catch_syscall_inferior_data_cleanup
);
646 add_catch_command ("syscall", _("\
647 Catch system calls by their names, groups and/or numbers.\n\
648 Arguments say which system calls to catch. If no arguments are given,\n\
649 every system call will be caught. Arguments, if given, should be one\n\
650 or more system call names (if your system supports that), system call\n\
651 groups or system call numbers."),
652 catch_syscall_command_1
,
653 catch_syscall_completer
,