1 /* Everything about syscall catchpoints, for GDB.
3 Copyright (C) 2009-2019 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 /* Standard C includes. */
25 /* Local non-gdb includes. */
27 #include "arch-utils.h"
28 #include "breakpoint.h"
29 #include "cli/cli-utils.h"
32 #include "mi/mi-common.h"
33 #include "observable.h"
35 #include "xml-syscall.h"
37 /* An instance of this type is used to represent a syscall catchpoint.
38 A breakpoint is really of this type iff its ops pointer points to
39 CATCH_SYSCALL_BREAKPOINT_OPS. */
41 struct syscall_catchpoint
: public breakpoint
43 /* Syscall numbers used for the 'catch syscall' feature. If no
44 syscall has been specified for filtering, it is empty.
45 Otherwise, it holds a list of all syscalls to be caught. */
46 std::vector
<int> syscalls_to_be_caught
;
49 static const struct inferior_data
*catch_syscall_inferior_data
= NULL
;
51 struct catch_syscall_inferior_data
53 /* We keep a count of the number of times the user has requested a
54 particular syscall to be tracked, and pass this information to the
55 target. This lets capable targets implement filtering directly. */
57 /* Number of times that "any" syscall is requested. */
58 int any_syscall_count
;
60 /* Count of each system call. */
61 std::vector
<int> syscalls_counts
;
63 /* This counts all syscall catch requests, so we can readily determine
64 if any catching is necessary. */
65 int total_syscalls_count
;
68 static struct catch_syscall_inferior_data
*
69 get_catch_syscall_inferior_data (struct inferior
*inf
)
71 struct catch_syscall_inferior_data
*inf_data
;
73 inf_data
= ((struct catch_syscall_inferior_data
*)
74 inferior_data (inf
, catch_syscall_inferior_data
));
77 inf_data
= new struct catch_syscall_inferior_data ();
78 set_inferior_data (inf
, catch_syscall_inferior_data
, inf_data
);
85 catch_syscall_inferior_data_cleanup (struct inferior
*inf
, void *arg
)
87 struct catch_syscall_inferior_data
*inf_data
88 = (struct catch_syscall_inferior_data
*) arg
;
93 /* Implement the "insert" breakpoint_ops method for syscall
97 insert_catch_syscall (struct bp_location
*bl
)
99 struct syscall_catchpoint
*c
= (struct syscall_catchpoint
*) bl
->owner
;
100 struct inferior
*inf
= current_inferior ();
101 struct catch_syscall_inferior_data
*inf_data
102 = get_catch_syscall_inferior_data (inf
);
104 ++inf_data
->total_syscalls_count
;
105 if (c
->syscalls_to_be_caught
.empty ())
106 ++inf_data
->any_syscall_count
;
109 for (int iter
: c
->syscalls_to_be_caught
)
111 if (iter
>= inf_data
->syscalls_counts
.size ())
112 inf_data
->syscalls_counts
.resize (iter
+ 1);
113 ++inf_data
->syscalls_counts
[iter
];
117 return target_set_syscall_catchpoint (inferior_ptid
.pid (),
118 inf_data
->total_syscalls_count
!= 0,
119 inf_data
->any_syscall_count
,
120 inf_data
->syscalls_counts
);
123 /* Implement the "remove" breakpoint_ops method for syscall
127 remove_catch_syscall (struct bp_location
*bl
, enum remove_bp_reason reason
)
129 struct syscall_catchpoint
*c
= (struct syscall_catchpoint
*) bl
->owner
;
130 struct inferior
*inf
= current_inferior ();
131 struct catch_syscall_inferior_data
*inf_data
132 = get_catch_syscall_inferior_data (inf
);
134 --inf_data
->total_syscalls_count
;
135 if (c
->syscalls_to_be_caught
.empty ())
136 --inf_data
->any_syscall_count
;
139 for (int iter
: c
->syscalls_to_be_caught
)
141 if (iter
>= inf_data
->syscalls_counts
.size ())
142 /* Shouldn't happen. */
144 --inf_data
->syscalls_counts
[iter
];
148 return target_set_syscall_catchpoint (inferior_ptid
.pid (),
149 inf_data
->total_syscalls_count
!= 0,
150 inf_data
->any_syscall_count
,
151 inf_data
->syscalls_counts
);
154 /* Implement the "breakpoint_hit" breakpoint_ops method for syscall
158 breakpoint_hit_catch_syscall (const struct bp_location
*bl
,
159 const address_space
*aspace
, CORE_ADDR bp_addr
,
160 const struct target_waitstatus
*ws
)
162 /* We must check if we are catching specific syscalls in this
163 breakpoint. If we are, then we must guarantee that the called
164 syscall is the same syscall we are catching. */
165 int syscall_number
= 0;
166 const struct syscall_catchpoint
*c
167 = (const struct syscall_catchpoint
*) bl
->owner
;
169 if (ws
->kind
!= TARGET_WAITKIND_SYSCALL_ENTRY
170 && ws
->kind
!= TARGET_WAITKIND_SYSCALL_RETURN
)
173 syscall_number
= ws
->value
.syscall_number
;
175 /* Now, checking if the syscall is the same. */
176 if (!c
->syscalls_to_be_caught
.empty ())
178 for (int iter
: c
->syscalls_to_be_caught
)
179 if (syscall_number
== iter
)
188 /* Implement the "print_it" breakpoint_ops method for syscall
191 static enum print_stop_action
192 print_it_catch_syscall (bpstat bs
)
194 struct ui_out
*uiout
= current_uiout
;
195 struct breakpoint
*b
= bs
->breakpoint_at
;
196 /* These are needed because we want to know in which state a
197 syscall is. It can be in the TARGET_WAITKIND_SYSCALL_ENTRY
198 or TARGET_WAITKIND_SYSCALL_RETURN, and depending on it we
199 must print "called syscall" or "returned from syscall". */
201 struct target_waitstatus last
;
203 struct gdbarch
*gdbarch
= bs
->bp_location_at
->gdbarch
;
205 get_last_target_status (&ptid
, &last
);
207 get_syscall_by_number (gdbarch
, last
.value
.syscall_number
, &s
);
209 annotate_catchpoint (b
->number
);
210 maybe_print_thread_hit_breakpoint (uiout
);
212 if (b
->disposition
== disp_del
)
213 uiout
->text ("Temporary catchpoint ");
215 uiout
->text ("Catchpoint ");
216 if (uiout
->is_mi_like_p ())
218 uiout
->field_string ("reason",
219 async_reason_lookup (last
.kind
== TARGET_WAITKIND_SYSCALL_ENTRY
220 ? EXEC_ASYNC_SYSCALL_ENTRY
221 : EXEC_ASYNC_SYSCALL_RETURN
));
222 uiout
->field_string ("disp", bpdisp_text (b
->disposition
));
224 uiout
->field_int ("bkptno", b
->number
);
226 if (last
.kind
== TARGET_WAITKIND_SYSCALL_ENTRY
)
227 uiout
->text (" (call to syscall ");
229 uiout
->text (" (returned from syscall ");
231 if (s
.name
== NULL
|| uiout
->is_mi_like_p ())
232 uiout
->field_int ("syscall-number", last
.value
.syscall_number
);
234 uiout
->field_string ("syscall-name", s
.name
);
238 return PRINT_SRC_AND_LOC
;
241 /* Implement the "print_one" breakpoint_ops method for syscall
245 print_one_catch_syscall (struct breakpoint
*b
,
246 struct bp_location
**last_loc
)
248 struct syscall_catchpoint
*c
= (struct syscall_catchpoint
*) b
;
249 struct value_print_options opts
;
250 struct ui_out
*uiout
= current_uiout
;
251 struct gdbarch
*gdbarch
= b
->loc
->gdbarch
;
253 get_user_print_options (&opts
);
254 /* Field 4, the address, is omitted (which makes the columns not
255 line up too nicely with the headers, but the effect is relatively
257 if (opts
.addressprint
)
258 uiout
->field_skip ("addr");
261 if (c
->syscalls_to_be_caught
.size () > 1)
262 uiout
->text ("syscalls \"");
264 uiout
->text ("syscall \"");
266 if (!c
->syscalls_to_be_caught
.empty ())
268 char *text
= xstrprintf ("%s", "");
270 for (int iter
: c
->syscalls_to_be_caught
)
272 char *previous_text
= text
;
274 get_syscall_by_number (gdbarch
, iter
, &s
);
277 text
= xstrprintf ("%s%s, ", text
, s
.name
);
279 text
= xstrprintf ("%s%d, ", text
, iter
);
281 /* We have to xfree previous_text because xstrprintf dynamically
282 allocates new space for text on every call. */
283 xfree (previous_text
);
285 /* Remove the last comma. */
286 text
[strlen (text
) - 2] = '\0';
287 uiout
->field_string ("what", text
);
288 /* xfree last text. */
292 uiout
->field_string ("what", "<any syscall>");
295 if (uiout
->is_mi_like_p ())
296 uiout
->field_string ("catch-type", "syscall");
299 /* Implement the "print_mention" breakpoint_ops method for syscall
303 print_mention_catch_syscall (struct breakpoint
*b
)
305 struct syscall_catchpoint
*c
= (struct syscall_catchpoint
*) b
;
306 struct gdbarch
*gdbarch
= b
->loc
->gdbarch
;
308 if (!c
->syscalls_to_be_caught
.empty ())
310 if (c
->syscalls_to_be_caught
.size () > 1)
311 printf_filtered (_("Catchpoint %d (syscalls"), b
->number
);
313 printf_filtered (_("Catchpoint %d (syscall"), b
->number
);
315 for (int iter
: c
->syscalls_to_be_caught
)
318 get_syscall_by_number (gdbarch
, iter
, &s
);
321 printf_filtered (" '%s' [%d]", s
.name
, s
.number
);
323 printf_filtered (" %d", s
.number
);
325 printf_filtered (")");
328 printf_filtered (_("Catchpoint %d (any syscall)"),
332 /* Implement the "print_recreate" breakpoint_ops method for syscall
336 print_recreate_catch_syscall (struct breakpoint
*b
, struct ui_file
*fp
)
338 struct syscall_catchpoint
*c
= (struct syscall_catchpoint
*) b
;
339 struct gdbarch
*gdbarch
= b
->loc
->gdbarch
;
341 fprintf_unfiltered (fp
, "catch syscall");
343 for (int iter
: c
->syscalls_to_be_caught
)
347 get_syscall_by_number (gdbarch
, iter
, &s
);
349 fprintf_unfiltered (fp
, " %s", s
.name
);
351 fprintf_unfiltered (fp
, " %d", s
.number
);
354 print_recreate_thread (b
, fp
);
357 /* The breakpoint_ops structure to be used in syscall catchpoints. */
359 static struct breakpoint_ops catch_syscall_breakpoint_ops
;
361 /* Returns non-zero if 'b' is a syscall catchpoint. */
364 syscall_catchpoint_p (struct breakpoint
*b
)
366 return (b
->ops
== &catch_syscall_breakpoint_ops
);
370 create_syscall_event_catchpoint (int tempflag
, std::vector
<int> &&filter
,
371 const struct breakpoint_ops
*ops
)
373 struct gdbarch
*gdbarch
= get_current_arch ();
375 std::unique_ptr
<syscall_catchpoint
> c (new syscall_catchpoint ());
376 init_catchpoint (c
.get (), gdbarch
, tempflag
, NULL
, ops
);
377 c
->syscalls_to_be_caught
= std::move (filter
);
379 install_breakpoint (0, std::move (c
), 1);
382 /* Splits the argument using space as delimiter. */
384 static std::vector
<int>
385 catch_syscall_split_args (const char *arg
)
387 std::vector
<int> result
;
388 struct gdbarch
*gdbarch
= target_gdbarch ();
392 int i
, syscall_number
;
397 /* Skip whitespace. */
398 arg
= skip_spaces (arg
);
400 for (i
= 0; i
< 127 && arg
[i
] && !isspace (arg
[i
]); ++i
)
401 cur_name
[i
] = arg
[i
];
405 /* Check if the user provided a syscall name, group, or a number. */
406 syscall_number
= (int) strtol (cur_name
, &endptr
, 0);
409 get_syscall_by_number (gdbarch
, syscall_number
, &s
);
410 result
.push_back (s
.number
);
412 else if (startswith (cur_name
, "g:")
413 || startswith (cur_name
, "group:"))
415 /* We have a syscall group. Let's expand it into a syscall
416 list before inserting. */
417 const char *group_name
;
419 /* Skip over "g:" and "group:" prefix strings. */
420 group_name
= strchr (cur_name
, ':') + 1;
422 if (!get_syscalls_by_group (gdbarch
, group_name
, &result
))
423 error (_("Unknown syscall group '%s'."), group_name
);
427 /* We have a name. Let's check if it's valid and fetch a
428 list of matching numbers. */
429 if (!get_syscalls_by_name (gdbarch
, cur_name
, &result
))
430 /* Here we have to issue an error instead of a warning,
431 because GDB cannot do anything useful if there's no
432 syscall number to be caught. */
433 error (_("Unknown syscall name '%s'."), cur_name
);
440 /* Implement the "catch syscall" command. */
443 catch_syscall_command_1 (const char *arg
, int from_tty
,
444 struct cmd_list_element
*command
)
447 std::vector
<int> filter
;
449 struct gdbarch
*gdbarch
= get_current_arch ();
451 /* Checking if the feature if supported. */
452 if (gdbarch_get_syscall_number_p (gdbarch
) == 0)
453 error (_("The feature 'catch syscall' is not supported on \
454 this architecture yet."));
456 tempflag
= get_cmd_context (command
) == CATCH_TEMPORARY
;
458 arg
= skip_spaces (arg
);
460 /* We need to do this first "dummy" translation in order
461 to get the syscall XML file loaded or, most important,
462 to display a warning to the user if there's no XML file
463 for his/her architecture. */
464 get_syscall_by_number (gdbarch
, 0, &s
);
466 /* The allowed syntax is:
468 catch syscall <name | number> [<name | number> ... <name | number>]
470 Let's check if there's a syscall name. */
473 filter
= catch_syscall_split_args (arg
);
475 create_syscall_event_catchpoint (tempflag
, std::move (filter
),
476 &catch_syscall_breakpoint_ops
);
480 /* Returns 0 if 'bp' is NOT a syscall catchpoint,
481 non-zero otherwise. */
483 is_syscall_catchpoint_enabled (struct breakpoint
*bp
)
485 if (syscall_catchpoint_p (bp
)
486 && bp
->enable_state
!= bp_disabled
487 && bp
->enable_state
!= bp_call_disabled
)
494 catch_syscall_enabled (void)
496 struct catch_syscall_inferior_data
*inf_data
497 = get_catch_syscall_inferior_data (current_inferior ());
499 return inf_data
->total_syscalls_count
!= 0;
502 /* Helper function for catching_syscall_number. If B is a syscall
503 catchpoint for SYSCALL_NUMBER, return 1 (which will make
504 'breakpoint_find_if' return). Otherwise, return 0. */
507 catching_syscall_number_1 (struct breakpoint
*b
,
510 int syscall_number
= (int) (uintptr_t) data
;
512 if (is_syscall_catchpoint_enabled (b
))
514 struct syscall_catchpoint
*c
= (struct syscall_catchpoint
*) b
;
516 if (!c
->syscalls_to_be_caught
.empty ())
518 for (int iter
: c
->syscalls_to_be_caught
)
519 if (syscall_number
== iter
)
530 catching_syscall_number (int syscall_number
)
532 struct breakpoint
*b
= breakpoint_find_if (catching_syscall_number_1
,
533 (void *) (uintptr_t) syscall_number
);
538 /* Complete syscall names. Used by "catch syscall". */
541 catch_syscall_completer (struct cmd_list_element
*cmd
,
542 completion_tracker
&tracker
,
543 const char *text
, const char *word
)
545 struct gdbarch
*gdbarch
= get_current_arch ();
546 gdb::unique_xmalloc_ptr
<const char *> group_list
;
549 /* Completion considers ':' to be a word separator, so we use this to
550 verify whether the previous word was a group prefix. If so, we
551 build the completion list using group names only. */
552 for (prefix
= word
; prefix
!= text
&& prefix
[-1] != ' '; prefix
--)
555 if (startswith (prefix
, "g:") || startswith (prefix
, "group:"))
557 /* Perform completion inside 'group:' namespace only. */
558 group_list
.reset (get_syscall_group_names (gdbarch
));
559 if (group_list
!= NULL
)
560 complete_on_enum (tracker
, group_list
.get (), word
, word
);
564 /* Complete with both, syscall names and groups. */
565 gdb::unique_xmalloc_ptr
<const char *> syscall_list
566 (get_syscall_names (gdbarch
));
567 group_list
.reset (get_syscall_group_names (gdbarch
));
569 const char **group_ptr
= group_list
.get ();
571 /* Hold on to strings while we're using them. */
572 std::vector
<std::string
> holders
;
574 /* Append "group:" prefix to syscall groups. */
575 for (int i
= 0; group_ptr
[i
] != NULL
; i
++)
576 holders
.push_back (string_printf ("group:%s", group_ptr
[i
]));
578 for (int i
= 0; group_ptr
[i
] != NULL
; i
++)
579 group_ptr
[i
] = holders
[i
].c_str ();
581 if (syscall_list
!= NULL
)
582 complete_on_enum (tracker
, syscall_list
.get (), word
, word
);
583 if (group_list
!= NULL
)
584 complete_on_enum (tracker
, group_ptr
, word
, word
);
589 clear_syscall_counts (struct inferior
*inf
)
591 struct catch_syscall_inferior_data
*inf_data
592 = get_catch_syscall_inferior_data (inf
);
594 inf_data
->total_syscalls_count
= 0;
595 inf_data
->any_syscall_count
= 0;
596 inf_data
->syscalls_counts
.clear ();
600 initialize_syscall_catchpoint_ops (void)
602 struct breakpoint_ops
*ops
;
604 initialize_breakpoint_ops ();
606 /* Syscall catchpoints. */
607 ops
= &catch_syscall_breakpoint_ops
;
608 *ops
= base_breakpoint_ops
;
609 ops
->insert_location
= insert_catch_syscall
;
610 ops
->remove_location
= remove_catch_syscall
;
611 ops
->breakpoint_hit
= breakpoint_hit_catch_syscall
;
612 ops
->print_it
= print_it_catch_syscall
;
613 ops
->print_one
= print_one_catch_syscall
;
614 ops
->print_mention
= print_mention_catch_syscall
;
615 ops
->print_recreate
= print_recreate_catch_syscall
;
619 _initialize_break_catch_syscall (void)
621 initialize_syscall_catchpoint_ops ();
623 gdb::observers::inferior_exit
.attach (clear_syscall_counts
);
624 catch_syscall_inferior_data
625 = register_inferior_data_with_cleanup (NULL
,
626 catch_syscall_inferior_data_cleanup
);
628 add_catch_command ("syscall", _("\
629 Catch system calls by their names, groups and/or numbers.\n\
630 Arguments say which system calls to catch. If no arguments are given,\n\
631 every system call will be caught. Arguments, if given, should be one\n\
632 or more system call names (if your system supports that), system call\n\
633 groups or system call numbers."),
634 catch_syscall_command_1
,
635 catch_syscall_completer
,