1 /* Everything about syscall catchpoints, for GDB.
3 Copyright (C) 2009-2022 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"
30 #include "observable.h"
31 #include "xml-syscall.h"
32 #include "cli/cli-style.h"
33 #include "cli/cli-decode.h"
35 /* An instance of this type is used to represent a syscall catchpoint.
36 A breakpoint is really of this type iff its ops pointer points to
37 CATCH_SYSCALL_BREAKPOINT_OPS. */
39 struct syscall_catchpoint
: public breakpoint
41 /* Syscall numbers used for the 'catch syscall' feature. If no
42 syscall has been specified for filtering, it is empty.
43 Otherwise, it holds a list of all syscalls to be caught. */
44 std::vector
<int> syscalls_to_be_caught
;
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 const struct inferior_key
<struct catch_syscall_inferior_data
>
65 catch_syscall_inferior_data
;
67 static struct catch_syscall_inferior_data
*
68 get_catch_syscall_inferior_data (struct inferior
*inf
)
70 struct catch_syscall_inferior_data
*inf_data
;
72 inf_data
= catch_syscall_inferior_data
.get (inf
);
74 inf_data
= catch_syscall_inferior_data
.emplace (inf
);
79 /* Implement the "insert" breakpoint_ops method for syscall
83 insert_catch_syscall (struct bp_location
*bl
)
85 struct syscall_catchpoint
*c
= (struct syscall_catchpoint
*) bl
->owner
;
86 struct inferior
*inf
= current_inferior ();
87 struct catch_syscall_inferior_data
*inf_data
88 = get_catch_syscall_inferior_data (inf
);
90 ++inf_data
->total_syscalls_count
;
91 if (c
->syscalls_to_be_caught
.empty ())
92 ++inf_data
->any_syscall_count
;
95 for (int iter
: c
->syscalls_to_be_caught
)
97 if (iter
>= inf_data
->syscalls_counts
.size ())
98 inf_data
->syscalls_counts
.resize (iter
+ 1);
99 ++inf_data
->syscalls_counts
[iter
];
103 return target_set_syscall_catchpoint (inferior_ptid
.pid (),
104 inf_data
->total_syscalls_count
!= 0,
105 inf_data
->any_syscall_count
,
106 inf_data
->syscalls_counts
);
109 /* Implement the "remove" breakpoint_ops method for syscall
113 remove_catch_syscall (struct bp_location
*bl
, enum remove_bp_reason reason
)
115 struct syscall_catchpoint
*c
= (struct syscall_catchpoint
*) bl
->owner
;
116 struct inferior
*inf
= current_inferior ();
117 struct catch_syscall_inferior_data
*inf_data
118 = get_catch_syscall_inferior_data (inf
);
120 --inf_data
->total_syscalls_count
;
121 if (c
->syscalls_to_be_caught
.empty ())
122 --inf_data
->any_syscall_count
;
125 for (int iter
: c
->syscalls_to_be_caught
)
127 if (iter
>= inf_data
->syscalls_counts
.size ())
128 /* Shouldn't happen. */
130 --inf_data
->syscalls_counts
[iter
];
134 return target_set_syscall_catchpoint (inferior_ptid
.pid (),
135 inf_data
->total_syscalls_count
!= 0,
136 inf_data
->any_syscall_count
,
137 inf_data
->syscalls_counts
);
140 /* Implement the "breakpoint_hit" breakpoint_ops method for syscall
144 breakpoint_hit_catch_syscall (const struct bp_location
*bl
,
145 const address_space
*aspace
, CORE_ADDR bp_addr
,
146 const target_waitstatus
&ws
)
148 /* We must check if we are catching specific syscalls in this
149 breakpoint. If we are, then we must guarantee that the called
150 syscall is the same syscall we are catching. */
151 int syscall_number
= 0;
152 const struct syscall_catchpoint
*c
153 = (const struct syscall_catchpoint
*) bl
->owner
;
155 if (ws
.kind () != TARGET_WAITKIND_SYSCALL_ENTRY
156 && ws
.kind () != TARGET_WAITKIND_SYSCALL_RETURN
)
159 syscall_number
= ws
.syscall_number ();
161 /* Now, checking if the syscall is the same. */
162 if (!c
->syscalls_to_be_caught
.empty ())
164 for (int iter
: c
->syscalls_to_be_caught
)
165 if (syscall_number
== iter
)
174 /* Implement the "print_it" breakpoint_ops method for syscall
177 static enum print_stop_action
178 print_it_catch_syscall (bpstat
*bs
)
180 struct ui_out
*uiout
= current_uiout
;
181 struct breakpoint
*b
= bs
->breakpoint_at
;
182 /* These are needed because we want to know in which state a
183 syscall is. It can be in the TARGET_WAITKIND_SYSCALL_ENTRY
184 or TARGET_WAITKIND_SYSCALL_RETURN, and depending on it we
185 must print "called syscall" or "returned from syscall". */
186 struct target_waitstatus last
;
188 struct gdbarch
*gdbarch
= bs
->bp_location_at
->gdbarch
;
190 get_last_target_status (nullptr, nullptr, &last
);
192 get_syscall_by_number (gdbarch
, last
.syscall_number (), &s
);
194 annotate_catchpoint (b
->number
);
195 maybe_print_thread_hit_breakpoint (uiout
);
197 if (b
->disposition
== disp_del
)
198 uiout
->text ("Temporary catchpoint ");
200 uiout
->text ("Catchpoint ");
201 if (uiout
->is_mi_like_p ())
203 uiout
->field_string ("reason",
204 async_reason_lookup (last
.kind () == TARGET_WAITKIND_SYSCALL_ENTRY
205 ? EXEC_ASYNC_SYSCALL_ENTRY
206 : EXEC_ASYNC_SYSCALL_RETURN
));
207 uiout
->field_string ("disp", bpdisp_text (b
->disposition
));
209 uiout
->field_signed ("bkptno", b
->number
);
211 if (last
.kind () == TARGET_WAITKIND_SYSCALL_ENTRY
)
212 uiout
->text (" (call to syscall ");
214 uiout
->text (" (returned from syscall ");
216 if (s
.name
== NULL
|| uiout
->is_mi_like_p ())
217 uiout
->field_signed ("syscall-number", last
.syscall_number ());
219 uiout
->field_string ("syscall-name", s
.name
);
223 return PRINT_SRC_AND_LOC
;
226 /* Implement the "print_one" breakpoint_ops method for syscall
230 print_one_catch_syscall (struct breakpoint
*b
,
231 struct bp_location
**last_loc
)
233 struct syscall_catchpoint
*c
= (struct syscall_catchpoint
*) b
;
234 struct value_print_options opts
;
235 struct ui_out
*uiout
= current_uiout
;
236 struct gdbarch
*gdbarch
= b
->loc
->gdbarch
;
238 get_user_print_options (&opts
);
239 /* Field 4, the address, is omitted (which makes the columns not
240 line up too nicely with the headers, but the effect is relatively
242 if (opts
.addressprint
)
243 uiout
->field_skip ("addr");
246 if (c
->syscalls_to_be_caught
.size () > 1)
247 uiout
->text ("syscalls \"");
249 uiout
->text ("syscall \"");
251 if (!c
->syscalls_to_be_caught
.empty ())
256 for (int iter
: c
->syscalls_to_be_caught
)
259 get_syscall_by_number (gdbarch
, iter
, &s
);
268 text
+= std::to_string (iter
);
270 uiout
->field_string ("what", text
.c_str ());
273 uiout
->field_string ("what", "<any syscall>", metadata_style
.style ());
276 if (uiout
->is_mi_like_p ())
277 uiout
->field_string ("catch-type", "syscall");
282 /* Implement the "print_mention" breakpoint_ops method for syscall
286 print_mention_catch_syscall (struct breakpoint
*b
)
288 struct syscall_catchpoint
*c
= (struct syscall_catchpoint
*) b
;
289 struct gdbarch
*gdbarch
= b
->loc
->gdbarch
;
291 if (!c
->syscalls_to_be_caught
.empty ())
293 if (c
->syscalls_to_be_caught
.size () > 1)
294 gdb_printf (_("Catchpoint %d (syscalls"), b
->number
);
296 gdb_printf (_("Catchpoint %d (syscall"), b
->number
);
298 for (int iter
: c
->syscalls_to_be_caught
)
301 get_syscall_by_number (gdbarch
, iter
, &s
);
304 gdb_printf (" '%s' [%d]", s
.name
, s
.number
);
306 gdb_printf (" %d", s
.number
);
311 gdb_printf (_("Catchpoint %d (any syscall)"),
315 /* Implement the "print_recreate" breakpoint_ops method for syscall
319 print_recreate_catch_syscall (struct breakpoint
*b
, struct ui_file
*fp
)
321 struct syscall_catchpoint
*c
= (struct syscall_catchpoint
*) b
;
322 struct gdbarch
*gdbarch
= b
->loc
->gdbarch
;
324 gdb_printf (fp
, "catch syscall");
326 for (int iter
: c
->syscalls_to_be_caught
)
330 get_syscall_by_number (gdbarch
, iter
, &s
);
332 gdb_printf (fp
, " %s", s
.name
);
334 gdb_printf (fp
, " %d", s
.number
);
337 print_recreate_thread (b
, fp
);
340 /* The breakpoint_ops structure to be used in syscall catchpoints. */
342 static struct breakpoint_ops catch_syscall_breakpoint_ops
;
344 /* Returns non-zero if 'b' is a syscall catchpoint. */
347 syscall_catchpoint_p (struct breakpoint
*b
)
349 return (b
->ops
== &catch_syscall_breakpoint_ops
);
353 create_syscall_event_catchpoint (int tempflag
, std::vector
<int> &&filter
,
354 const struct breakpoint_ops
*ops
)
356 struct gdbarch
*gdbarch
= get_current_arch ();
358 std::unique_ptr
<syscall_catchpoint
> c (new syscall_catchpoint ());
359 init_catchpoint (c
.get (), gdbarch
, tempflag
, NULL
, ops
);
360 c
->syscalls_to_be_caught
= std::move (filter
);
362 install_breakpoint (0, std::move (c
), 1);
365 /* Splits the argument using space as delimiter. */
367 static std::vector
<int>
368 catch_syscall_split_args (const char *arg
)
370 std::vector
<int> result
;
371 struct gdbarch
*gdbarch
= target_gdbarch ();
375 int i
, syscall_number
;
380 /* Skip whitespace. */
381 arg
= skip_spaces (arg
);
383 for (i
= 0; i
< 127 && arg
[i
] && !isspace (arg
[i
]); ++i
)
384 cur_name
[i
] = arg
[i
];
388 /* Check if the user provided a syscall name, group, or a number. */
389 syscall_number
= (int) strtol (cur_name
, &endptr
, 0);
392 if (syscall_number
< 0)
393 error (_("Unknown syscall number '%d'."), syscall_number
);
394 get_syscall_by_number (gdbarch
, syscall_number
, &s
);
395 result
.push_back (s
.number
);
397 else if (startswith (cur_name
, "g:")
398 || startswith (cur_name
, "group:"))
400 /* We have a syscall group. Let's expand it into a syscall
401 list before inserting. */
402 const char *group_name
;
404 /* Skip over "g:" and "group:" prefix strings. */
405 group_name
= strchr (cur_name
, ':') + 1;
407 if (!get_syscalls_by_group (gdbarch
, group_name
, &result
))
408 error (_("Unknown syscall group '%s'."), group_name
);
412 /* We have a name. Let's check if it's valid and fetch a
413 list of matching numbers. */
414 if (!get_syscalls_by_name (gdbarch
, cur_name
, &result
))
415 /* Here we have to issue an error instead of a warning,
416 because GDB cannot do anything useful if there's no
417 syscall number to be caught. */
418 error (_("Unknown syscall name '%s'."), cur_name
);
425 /* Implement the "catch syscall" command. */
428 catch_syscall_command_1 (const char *arg
, int from_tty
,
429 struct cmd_list_element
*command
)
432 std::vector
<int> filter
;
434 struct gdbarch
*gdbarch
= get_current_arch ();
436 /* Checking if the feature if supported. */
437 if (gdbarch_get_syscall_number_p (gdbarch
) == 0)
438 error (_("The feature 'catch syscall' is not supported on \
439 this architecture yet."));
441 tempflag
= command
->context () == CATCH_TEMPORARY
;
443 arg
= skip_spaces (arg
);
445 /* We need to do this first "dummy" translation in order
446 to get the syscall XML file loaded or, most important,
447 to display a warning to the user if there's no XML file
448 for his/her architecture. */
449 get_syscall_by_number (gdbarch
, 0, &s
);
451 /* The allowed syntax is:
453 catch syscall <name | number> [<name | number> ... <name | number>]
455 Let's check if there's a syscall name. */
458 filter
= catch_syscall_split_args (arg
);
460 create_syscall_event_catchpoint (tempflag
, std::move (filter
),
461 &catch_syscall_breakpoint_ops
);
465 /* Returns 0 if 'bp' is NOT a syscall catchpoint,
466 non-zero otherwise. */
468 is_syscall_catchpoint_enabled (struct breakpoint
*bp
)
470 if (syscall_catchpoint_p (bp
)
471 && bp
->enable_state
!= bp_disabled
472 && bp
->enable_state
!= bp_call_disabled
)
479 catch_syscall_enabled (void)
481 struct catch_syscall_inferior_data
*inf_data
482 = get_catch_syscall_inferior_data (current_inferior ());
484 return inf_data
->total_syscalls_count
!= 0;
487 /* Helper function for catching_syscall_number. return true if B is a syscall
488 catchpoint for SYSCALL_NUMBER, else false. */
491 catching_syscall_number_1 (struct breakpoint
*b
, int syscall_number
)
494 if (is_syscall_catchpoint_enabled (b
))
496 struct syscall_catchpoint
*c
= (struct syscall_catchpoint
*) b
;
498 if (!c
->syscalls_to_be_caught
.empty ())
500 for (int iter
: c
->syscalls_to_be_caught
)
501 if (syscall_number
== iter
)
512 catching_syscall_number (int syscall_number
)
514 for (breakpoint
*b
: all_breakpoints ())
515 if (catching_syscall_number_1 (b
, syscall_number
))
521 /* Complete syscall names. Used by "catch syscall". */
524 catch_syscall_completer (struct cmd_list_element
*cmd
,
525 completion_tracker
&tracker
,
526 const char *text
, const char *word
)
528 struct gdbarch
*gdbarch
= get_current_arch ();
529 gdb::unique_xmalloc_ptr
<const char *> group_list
;
532 /* Completion considers ':' to be a word separator, so we use this to
533 verify whether the previous word was a group prefix. If so, we
534 build the completion list using group names only. */
535 for (prefix
= word
; prefix
!= text
&& prefix
[-1] != ' '; prefix
--)
538 if (startswith (prefix
, "g:") || startswith (prefix
, "group:"))
540 /* Perform completion inside 'group:' namespace only. */
541 group_list
.reset (get_syscall_group_names (gdbarch
));
542 if (group_list
!= NULL
)
543 complete_on_enum (tracker
, group_list
.get (), word
, word
);
547 /* Complete with both, syscall names and groups. */
548 gdb::unique_xmalloc_ptr
<const char *> syscall_list
549 (get_syscall_names (gdbarch
));
550 group_list
.reset (get_syscall_group_names (gdbarch
));
552 const char **group_ptr
= group_list
.get ();
554 /* Hold on to strings while we're using them. */
555 std::vector
<std::string
> holders
;
557 /* Append "group:" prefix to syscall groups. */
558 for (int i
= 0; group_ptr
[i
] != NULL
; i
++)
559 holders
.push_back (string_printf ("group:%s", group_ptr
[i
]));
561 for (int i
= 0; group_ptr
[i
] != NULL
; i
++)
562 group_ptr
[i
] = holders
[i
].c_str ();
564 if (syscall_list
!= NULL
)
565 complete_on_enum (tracker
, syscall_list
.get (), word
, word
);
566 if (group_list
!= NULL
)
567 complete_on_enum (tracker
, group_ptr
, word
, word
);
572 clear_syscall_counts (struct inferior
*inf
)
574 struct catch_syscall_inferior_data
*inf_data
575 = get_catch_syscall_inferior_data (inf
);
577 inf_data
->total_syscalls_count
= 0;
578 inf_data
->any_syscall_count
= 0;
579 inf_data
->syscalls_counts
.clear ();
583 initialize_syscall_catchpoint_ops (void)
585 struct breakpoint_ops
*ops
;
587 initialize_breakpoint_ops ();
589 /* Syscall catchpoints. */
590 ops
= &catch_syscall_breakpoint_ops
;
591 *ops
= base_breakpoint_ops
;
592 ops
->insert_location
= insert_catch_syscall
;
593 ops
->remove_location
= remove_catch_syscall
;
594 ops
->breakpoint_hit
= breakpoint_hit_catch_syscall
;
595 ops
->print_it
= print_it_catch_syscall
;
596 ops
->print_one
= print_one_catch_syscall
;
597 ops
->print_mention
= print_mention_catch_syscall
;
598 ops
->print_recreate
= print_recreate_catch_syscall
;
601 void _initialize_break_catch_syscall ();
603 _initialize_break_catch_syscall ()
605 initialize_syscall_catchpoint_ops ();
607 gdb::observers::inferior_exit
.attach (clear_syscall_counts
,
608 "break-catch-syscall");
610 add_catch_command ("syscall", _("\
611 Catch system calls by their names, groups and/or numbers.\n\
612 Arguments say which system calls to catch. If no arguments are given,\n\
613 every system call will be caught. Arguments, if given, should be one\n\
614 or more system call names (if your system supports that), system call\n\
615 groups or system call numbers."),
616 catch_syscall_command_1
,
617 catch_syscall_completer
,