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
38 struct syscall_catchpoint
: public breakpoint
40 int insert_location (struct bp_location
*) override
;
41 int remove_location (struct bp_location
*,
42 enum remove_bp_reason reason
) override
;
43 int breakpoint_hit (const struct bp_location
*bl
,
44 const address_space
*aspace
,
46 const target_waitstatus
&ws
) override
;
47 enum print_stop_action
print_it (struct bpstat
*bs
) override
;
48 bool print_one (struct bp_location
**) override
;
49 void print_mention () override
;
50 void print_recreate (struct ui_file
*fp
) override
;
52 /* Syscall numbers used for the 'catch syscall' feature. If no
53 syscall has been specified for filtering, it is empty.
54 Otherwise, it holds a list of all syscalls to be caught. */
55 std::vector
<int> syscalls_to_be_caught
;
58 struct catch_syscall_inferior_data
60 /* We keep a count of the number of times the user has requested a
61 particular syscall to be tracked, and pass this information to the
62 target. This lets capable targets implement filtering directly. */
64 /* Number of times that "any" syscall is requested. */
65 int any_syscall_count
;
67 /* Count of each system call. */
68 std::vector
<int> syscalls_counts
;
70 /* This counts all syscall catch requests, so we can readily determine
71 if any catching is necessary. */
72 int total_syscalls_count
;
75 static const struct inferior_key
<struct catch_syscall_inferior_data
>
76 catch_syscall_inferior_data
;
78 static struct catch_syscall_inferior_data
*
79 get_catch_syscall_inferior_data (struct inferior
*inf
)
81 struct catch_syscall_inferior_data
*inf_data
;
83 inf_data
= catch_syscall_inferior_data
.get (inf
);
85 inf_data
= catch_syscall_inferior_data
.emplace (inf
);
90 /* Implement the "insert" method for syscall catchpoints. */
93 syscall_catchpoint::insert_location (struct bp_location
*bl
)
95 struct inferior
*inf
= current_inferior ();
96 struct catch_syscall_inferior_data
*inf_data
97 = get_catch_syscall_inferior_data (inf
);
99 ++inf_data
->total_syscalls_count
;
100 if (syscalls_to_be_caught
.empty ())
101 ++inf_data
->any_syscall_count
;
104 for (int iter
: syscalls_to_be_caught
)
106 if (iter
>= inf_data
->syscalls_counts
.size ())
107 inf_data
->syscalls_counts
.resize (iter
+ 1);
108 ++inf_data
->syscalls_counts
[iter
];
112 return target_set_syscall_catchpoint (inferior_ptid
.pid (),
113 inf_data
->total_syscalls_count
!= 0,
114 inf_data
->any_syscall_count
,
115 inf_data
->syscalls_counts
);
118 /* Implement the "remove" method for syscall catchpoints. */
121 syscall_catchpoint::remove_location (struct bp_location
*bl
,
122 enum remove_bp_reason reason
)
124 struct inferior
*inf
= current_inferior ();
125 struct catch_syscall_inferior_data
*inf_data
126 = get_catch_syscall_inferior_data (inf
);
128 --inf_data
->total_syscalls_count
;
129 if (syscalls_to_be_caught
.empty ())
130 --inf_data
->any_syscall_count
;
133 for (int iter
: syscalls_to_be_caught
)
135 if (iter
>= inf_data
->syscalls_counts
.size ())
136 /* Shouldn't happen. */
138 --inf_data
->syscalls_counts
[iter
];
142 return target_set_syscall_catchpoint (inferior_ptid
.pid (),
143 inf_data
->total_syscalls_count
!= 0,
144 inf_data
->any_syscall_count
,
145 inf_data
->syscalls_counts
);
148 /* Implement the "breakpoint_hit" method for syscall catchpoints. */
151 syscall_catchpoint::breakpoint_hit (const struct bp_location
*bl
,
152 const address_space
*aspace
,
154 const target_waitstatus
&ws
)
156 /* We must check if we are catching specific syscalls in this
157 breakpoint. If we are, then we must guarantee that the called
158 syscall is the same syscall we are catching. */
159 int syscall_number
= 0;
161 if (ws
.kind () != TARGET_WAITKIND_SYSCALL_ENTRY
162 && ws
.kind () != TARGET_WAITKIND_SYSCALL_RETURN
)
165 syscall_number
= ws
.syscall_number ();
167 /* Now, checking if the syscall is the same. */
168 if (!syscalls_to_be_caught
.empty ())
170 for (int iter
: syscalls_to_be_caught
)
171 if (syscall_number
== iter
)
180 /* Implement the "print_it" method for syscall catchpoints. */
182 enum print_stop_action
183 syscall_catchpoint::print_it (bpstat
*bs
)
185 struct ui_out
*uiout
= current_uiout
;
186 struct breakpoint
*b
= bs
->breakpoint_at
;
187 /* These are needed because we want to know in which state a
188 syscall is. It can be in the TARGET_WAITKIND_SYSCALL_ENTRY
189 or TARGET_WAITKIND_SYSCALL_RETURN, and depending on it we
190 must print "called syscall" or "returned from syscall". */
191 struct target_waitstatus last
;
193 struct gdbarch
*gdbarch
= bs
->bp_location_at
->gdbarch
;
195 get_last_target_status (nullptr, nullptr, &last
);
197 get_syscall_by_number (gdbarch
, last
.syscall_number (), &s
);
199 annotate_catchpoint (b
->number
);
200 maybe_print_thread_hit_breakpoint (uiout
);
202 if (b
->disposition
== disp_del
)
203 uiout
->text ("Temporary catchpoint ");
205 uiout
->text ("Catchpoint ");
206 if (uiout
->is_mi_like_p ())
208 uiout
->field_string ("reason",
209 async_reason_lookup (last
.kind () == TARGET_WAITKIND_SYSCALL_ENTRY
210 ? EXEC_ASYNC_SYSCALL_ENTRY
211 : EXEC_ASYNC_SYSCALL_RETURN
));
212 uiout
->field_string ("disp", bpdisp_text (b
->disposition
));
214 uiout
->field_signed ("bkptno", b
->number
);
216 if (last
.kind () == TARGET_WAITKIND_SYSCALL_ENTRY
)
217 uiout
->text (" (call to syscall ");
219 uiout
->text (" (returned from syscall ");
221 if (s
.name
== NULL
|| uiout
->is_mi_like_p ())
222 uiout
->field_signed ("syscall-number", last
.syscall_number ());
224 uiout
->field_string ("syscall-name", s
.name
);
228 return PRINT_SRC_AND_LOC
;
231 /* Implement the "print_one" method for syscall catchpoints. */
234 syscall_catchpoint::print_one (struct bp_location
**last_loc
)
236 struct value_print_options opts
;
237 struct ui_out
*uiout
= current_uiout
;
238 struct gdbarch
*gdbarch
= loc
->gdbarch
;
240 get_user_print_options (&opts
);
241 /* Field 4, the address, is omitted (which makes the columns not
242 line up too nicely with the headers, but the effect is relatively
244 if (opts
.addressprint
)
245 uiout
->field_skip ("addr");
248 if (syscalls_to_be_caught
.size () > 1)
249 uiout
->text ("syscalls \"");
251 uiout
->text ("syscall \"");
253 if (!syscalls_to_be_caught
.empty ())
258 for (int iter
: syscalls_to_be_caught
)
261 get_syscall_by_number (gdbarch
, iter
, &s
);
270 text
+= std::to_string (iter
);
272 uiout
->field_string ("what", text
.c_str ());
275 uiout
->field_string ("what", "<any syscall>", metadata_style
.style ());
278 if (uiout
->is_mi_like_p ())
279 uiout
->field_string ("catch-type", "syscall");
284 /* Implement the "print_mention" method for syscall catchpoints. */
287 syscall_catchpoint::print_mention ()
289 struct gdbarch
*gdbarch
= loc
->gdbarch
;
291 if (!syscalls_to_be_caught
.empty ())
293 if (syscalls_to_be_caught
.size () > 1)
294 gdb_printf (_("Catchpoint %d (syscalls"), number
);
296 gdb_printf (_("Catchpoint %d (syscall"), number
);
298 for (int iter
: 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)"), number
);
314 /* Implement the "print_recreate" method for syscall catchpoints. */
317 syscall_catchpoint::print_recreate (struct ui_file
*fp
)
319 struct gdbarch
*gdbarch
= loc
->gdbarch
;
321 gdb_printf (fp
, "catch syscall");
323 for (int iter
: syscalls_to_be_caught
)
327 get_syscall_by_number (gdbarch
, iter
, &s
);
329 gdb_printf (fp
, " %s", s
.name
);
331 gdb_printf (fp
, " %d", s
.number
);
334 print_recreate_thread (fp
);
337 /* Returns non-zero if 'b' is a syscall catchpoint. */
340 syscall_catchpoint_p (struct breakpoint
*b
)
342 return dynamic_cast<syscall_catchpoint
*> (b
) != nullptr;
346 create_syscall_event_catchpoint (int tempflag
, std::vector
<int> &&filter
)
348 struct gdbarch
*gdbarch
= get_current_arch ();
350 std::unique_ptr
<syscall_catchpoint
> c (new syscall_catchpoint ());
351 init_catchpoint (c
.get (), gdbarch
, tempflag
, nullptr);
352 c
->syscalls_to_be_caught
= std::move (filter
);
354 install_breakpoint (0, std::move (c
), 1);
357 /* Splits the argument using space as delimiter. */
359 static std::vector
<int>
360 catch_syscall_split_args (const char *arg
)
362 std::vector
<int> result
;
363 struct gdbarch
*gdbarch
= target_gdbarch ();
367 int i
, syscall_number
;
372 /* Skip whitespace. */
373 arg
= skip_spaces (arg
);
375 for (i
= 0; i
< 127 && arg
[i
] && !isspace (arg
[i
]); ++i
)
376 cur_name
[i
] = arg
[i
];
380 /* Check if the user provided a syscall name, group, or a number. */
381 syscall_number
= (int) strtol (cur_name
, &endptr
, 0);
384 if (syscall_number
< 0)
385 error (_("Unknown syscall number '%d'."), syscall_number
);
386 get_syscall_by_number (gdbarch
, syscall_number
, &s
);
387 result
.push_back (s
.number
);
389 else if (startswith (cur_name
, "g:")
390 || startswith (cur_name
, "group:"))
392 /* We have a syscall group. Let's expand it into a syscall
393 list before inserting. */
394 const char *group_name
;
396 /* Skip over "g:" and "group:" prefix strings. */
397 group_name
= strchr (cur_name
, ':') + 1;
399 if (!get_syscalls_by_group (gdbarch
, group_name
, &result
))
400 error (_("Unknown syscall group '%s'."), group_name
);
404 /* We have a name. Let's check if it's valid and fetch a
405 list of matching numbers. */
406 if (!get_syscalls_by_name (gdbarch
, cur_name
, &result
))
407 /* Here we have to issue an error instead of a warning,
408 because GDB cannot do anything useful if there's no
409 syscall number to be caught. */
410 error (_("Unknown syscall name '%s'."), cur_name
);
417 /* Implement the "catch syscall" command. */
420 catch_syscall_command_1 (const char *arg
, int from_tty
,
421 struct cmd_list_element
*command
)
424 std::vector
<int> filter
;
426 struct gdbarch
*gdbarch
= get_current_arch ();
428 /* Checking if the feature if supported. */
429 if (gdbarch_get_syscall_number_p (gdbarch
) == 0)
430 error (_("The feature 'catch syscall' is not supported on \
431 this architecture yet."));
433 tempflag
= command
->context () == CATCH_TEMPORARY
;
435 arg
= skip_spaces (arg
);
437 /* We need to do this first "dummy" translation in order
438 to get the syscall XML file loaded or, most important,
439 to display a warning to the user if there's no XML file
440 for his/her architecture. */
441 get_syscall_by_number (gdbarch
, 0, &s
);
443 /* The allowed syntax is:
445 catch syscall <name | number> [<name | number> ... <name | number>]
447 Let's check if there's a syscall name. */
450 filter
= catch_syscall_split_args (arg
);
452 create_syscall_event_catchpoint (tempflag
, std::move (filter
));
456 /* Returns 0 if 'bp' is NOT a syscall catchpoint,
457 non-zero otherwise. */
459 is_syscall_catchpoint_enabled (struct breakpoint
*bp
)
461 if (syscall_catchpoint_p (bp
)
462 && bp
->enable_state
!= bp_disabled
463 && bp
->enable_state
!= bp_call_disabled
)
470 catch_syscall_enabled (void)
472 struct catch_syscall_inferior_data
*inf_data
473 = get_catch_syscall_inferior_data (current_inferior ());
475 return inf_data
->total_syscalls_count
!= 0;
478 /* Helper function for catching_syscall_number. return true if B is a syscall
479 catchpoint for SYSCALL_NUMBER, else false. */
482 catching_syscall_number_1 (struct breakpoint
*b
, int syscall_number
)
485 if (is_syscall_catchpoint_enabled (b
))
487 struct syscall_catchpoint
*c
= (struct syscall_catchpoint
*) b
;
489 if (!c
->syscalls_to_be_caught
.empty ())
491 for (int iter
: c
->syscalls_to_be_caught
)
492 if (syscall_number
== iter
)
503 catching_syscall_number (int syscall_number
)
505 for (breakpoint
*b
: all_breakpoints ())
506 if (catching_syscall_number_1 (b
, syscall_number
))
512 /* Complete syscall names. Used by "catch syscall". */
515 catch_syscall_completer (struct cmd_list_element
*cmd
,
516 completion_tracker
&tracker
,
517 const char *text
, const char *word
)
519 struct gdbarch
*gdbarch
= get_current_arch ();
520 gdb::unique_xmalloc_ptr
<const char *> group_list
;
523 /* Completion considers ':' to be a word separator, so we use this to
524 verify whether the previous word was a group prefix. If so, we
525 build the completion list using group names only. */
526 for (prefix
= word
; prefix
!= text
&& prefix
[-1] != ' '; prefix
--)
529 if (startswith (prefix
, "g:") || startswith (prefix
, "group:"))
531 /* Perform completion inside 'group:' namespace only. */
532 group_list
.reset (get_syscall_group_names (gdbarch
));
533 if (group_list
!= NULL
)
534 complete_on_enum (tracker
, group_list
.get (), word
, word
);
538 /* Complete with both, syscall names and groups. */
539 gdb::unique_xmalloc_ptr
<const char *> syscall_list
540 (get_syscall_names (gdbarch
));
541 group_list
.reset (get_syscall_group_names (gdbarch
));
543 const char **group_ptr
= group_list
.get ();
545 /* Hold on to strings while we're using them. */
546 std::vector
<std::string
> holders
;
548 /* Append "group:" prefix to syscall groups. */
549 for (int i
= 0; group_ptr
[i
] != NULL
; i
++)
550 holders
.push_back (string_printf ("group:%s", group_ptr
[i
]));
552 for (int i
= 0; group_ptr
[i
] != NULL
; i
++)
553 group_ptr
[i
] = holders
[i
].c_str ();
555 if (syscall_list
!= NULL
)
556 complete_on_enum (tracker
, syscall_list
.get (), word
, word
);
557 if (group_list
!= NULL
)
558 complete_on_enum (tracker
, group_ptr
, word
, word
);
563 clear_syscall_counts (struct inferior
*inf
)
565 struct catch_syscall_inferior_data
*inf_data
566 = get_catch_syscall_inferior_data (inf
);
568 inf_data
->total_syscalls_count
= 0;
569 inf_data
->any_syscall_count
= 0;
570 inf_data
->syscalls_counts
.clear ();
573 void _initialize_break_catch_syscall ();
575 _initialize_break_catch_syscall ()
577 gdb::observers::inferior_exit
.attach (clear_syscall_counts
,
578 "break-catch-syscall");
580 add_catch_command ("syscall", _("\
581 Catch system calls by their names, groups and/or numbers.\n\
582 Arguments say which system calls to catch. If no arguments are given,\n\
583 every system call will be caught. Arguments, if given, should be one\n\
584 or more system call names (if your system supports that), system call\n\
585 groups or system call numbers."),
586 catch_syscall_command_1
,
587 catch_syscall_completer
,