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 syscall_catchpoint (struct gdbarch
*gdbarch
, std::vector
<int> &&calls
)
41 : breakpoint (gdbarch
, bp_catchpoint
),
42 syscalls_to_be_caught (std::move (calls
))
46 int insert_location (struct bp_location
*) override
;
47 int remove_location (struct bp_location
*,
48 enum remove_bp_reason reason
) override
;
49 int breakpoint_hit (const struct bp_location
*bl
,
50 const address_space
*aspace
,
52 const target_waitstatus
&ws
) override
;
53 enum print_stop_action
print_it (const bpstat
*bs
) const override
;
54 bool print_one (bp_location
**) const override
;
55 void print_mention () const override
;
56 void print_recreate (struct ui_file
*fp
) const override
;
58 /* Syscall numbers used for the 'catch syscall' feature. If no
59 syscall has been specified for filtering, it is empty.
60 Otherwise, it holds a list of all syscalls to be caught. */
61 std::vector
<int> syscalls_to_be_caught
;
64 struct catch_syscall_inferior_data
66 /* We keep a count of the number of times the user has requested a
67 particular syscall to be tracked, and pass this information to the
68 target. This lets capable targets implement filtering directly. */
70 /* Number of times that "any" syscall is requested. */
71 int any_syscall_count
;
73 /* Count of each system call. */
74 std::vector
<int> syscalls_counts
;
76 /* This counts all syscall catch requests, so we can readily determine
77 if any catching is necessary. */
78 int total_syscalls_count
;
81 static const struct inferior_key
<struct catch_syscall_inferior_data
>
82 catch_syscall_inferior_data
;
84 static struct catch_syscall_inferior_data
*
85 get_catch_syscall_inferior_data (struct inferior
*inf
)
87 struct catch_syscall_inferior_data
*inf_data
;
89 inf_data
= catch_syscall_inferior_data
.get (inf
);
91 inf_data
= catch_syscall_inferior_data
.emplace (inf
);
96 /* Implement the "insert" method for syscall catchpoints. */
99 syscall_catchpoint::insert_location (struct bp_location
*bl
)
101 struct inferior
*inf
= current_inferior ();
102 struct catch_syscall_inferior_data
*inf_data
103 = get_catch_syscall_inferior_data (inf
);
105 ++inf_data
->total_syscalls_count
;
106 if (syscalls_to_be_caught
.empty ())
107 ++inf_data
->any_syscall_count
;
110 for (int iter
: syscalls_to_be_caught
)
112 if (iter
>= inf_data
->syscalls_counts
.size ())
113 inf_data
->syscalls_counts
.resize (iter
+ 1);
114 ++inf_data
->syscalls_counts
[iter
];
118 return target_set_syscall_catchpoint (inferior_ptid
.pid (),
119 inf_data
->total_syscalls_count
!= 0,
120 inf_data
->any_syscall_count
,
121 inf_data
->syscalls_counts
);
124 /* Implement the "remove" method for syscall catchpoints. */
127 syscall_catchpoint::remove_location (struct bp_location
*bl
,
128 enum remove_bp_reason reason
)
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 (syscalls_to_be_caught
.empty ())
136 --inf_data
->any_syscall_count
;
139 for (int iter
: 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" method for syscall catchpoints. */
157 syscall_catchpoint::breakpoint_hit (const struct bp_location
*bl
,
158 const address_space
*aspace
,
160 const 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;
167 if (ws
.kind () != TARGET_WAITKIND_SYSCALL_ENTRY
168 && ws
.kind () != TARGET_WAITKIND_SYSCALL_RETURN
)
171 syscall_number
= ws
.syscall_number ();
173 /* Now, checking if the syscall is the same. */
174 if (!syscalls_to_be_caught
.empty ())
176 for (int iter
: syscalls_to_be_caught
)
177 if (syscall_number
== iter
)
186 /* Implement the "print_it" method for syscall catchpoints. */
188 enum print_stop_action
189 syscall_catchpoint::print_it (const bpstat
*bs
) const
191 struct ui_out
*uiout
= current_uiout
;
192 struct breakpoint
*b
= bs
->breakpoint_at
;
193 /* These are needed because we want to know in which state a
194 syscall is. It can be in the TARGET_WAITKIND_SYSCALL_ENTRY
195 or TARGET_WAITKIND_SYSCALL_RETURN, and depending on it we
196 must print "called syscall" or "returned from syscall". */
197 struct target_waitstatus last
;
199 struct gdbarch
*gdbarch
= bs
->bp_location_at
->gdbarch
;
201 get_last_target_status (nullptr, nullptr, &last
);
203 get_syscall_by_number (gdbarch
, last
.syscall_number (), &s
);
205 annotate_catchpoint (b
->number
);
206 maybe_print_thread_hit_breakpoint (uiout
);
208 if (b
->disposition
== disp_del
)
209 uiout
->text ("Temporary catchpoint ");
211 uiout
->text ("Catchpoint ");
212 if (uiout
->is_mi_like_p ())
214 uiout
->field_string ("reason",
215 async_reason_lookup (last
.kind () == TARGET_WAITKIND_SYSCALL_ENTRY
216 ? EXEC_ASYNC_SYSCALL_ENTRY
217 : EXEC_ASYNC_SYSCALL_RETURN
));
218 uiout
->field_string ("disp", bpdisp_text (b
->disposition
));
220 uiout
->field_signed ("bkptno", b
->number
);
222 if (last
.kind () == TARGET_WAITKIND_SYSCALL_ENTRY
)
223 uiout
->text (" (call to syscall ");
225 uiout
->text (" (returned from syscall ");
227 if (s
.name
== NULL
|| uiout
->is_mi_like_p ())
228 uiout
->field_signed ("syscall-number", last
.syscall_number ());
230 uiout
->field_string ("syscall-name", s
.name
);
234 return PRINT_SRC_AND_LOC
;
237 /* Implement the "print_one" method for syscall catchpoints. */
240 syscall_catchpoint::print_one (bp_location
**last_loc
) const
242 struct value_print_options opts
;
243 struct ui_out
*uiout
= current_uiout
;
244 struct gdbarch
*gdbarch
= loc
->gdbarch
;
246 get_user_print_options (&opts
);
247 /* Field 4, the address, is omitted (which makes the columns not
248 line up too nicely with the headers, but the effect is relatively
250 if (opts
.addressprint
)
251 uiout
->field_skip ("addr");
254 if (syscalls_to_be_caught
.size () > 1)
255 uiout
->text ("syscalls \"");
257 uiout
->text ("syscall \"");
259 if (!syscalls_to_be_caught
.empty ())
264 for (int iter
: syscalls_to_be_caught
)
267 get_syscall_by_number (gdbarch
, iter
, &s
);
276 text
+= std::to_string (iter
);
278 uiout
->field_string ("what", text
.c_str ());
281 uiout
->field_string ("what", "<any syscall>", metadata_style
.style ());
284 if (uiout
->is_mi_like_p ())
285 uiout
->field_string ("catch-type", "syscall");
290 /* Implement the "print_mention" method for syscall catchpoints. */
293 syscall_catchpoint::print_mention () const
295 struct gdbarch
*gdbarch
= loc
->gdbarch
;
297 if (!syscalls_to_be_caught
.empty ())
299 if (syscalls_to_be_caught
.size () > 1)
300 gdb_printf (_("Catchpoint %d (syscalls"), number
);
302 gdb_printf (_("Catchpoint %d (syscall"), number
);
304 for (int iter
: syscalls_to_be_caught
)
307 get_syscall_by_number (gdbarch
, iter
, &s
);
310 gdb_printf (" '%s' [%d]", s
.name
, s
.number
);
312 gdb_printf (" %d", s
.number
);
317 gdb_printf (_("Catchpoint %d (any syscall)"), number
);
320 /* Implement the "print_recreate" method for syscall catchpoints. */
323 syscall_catchpoint::print_recreate (struct ui_file
*fp
) const
325 struct gdbarch
*gdbarch
= loc
->gdbarch
;
327 gdb_printf (fp
, "catch syscall");
329 for (int iter
: syscalls_to_be_caught
)
333 get_syscall_by_number (gdbarch
, iter
, &s
);
335 gdb_printf (fp
, " %s", s
.name
);
337 gdb_printf (fp
, " %d", s
.number
);
340 print_recreate_thread (fp
);
343 /* Returns non-zero if 'b' is a syscall catchpoint. */
346 syscall_catchpoint_p (struct breakpoint
*b
)
348 return dynamic_cast<syscall_catchpoint
*> (b
) != nullptr;
352 create_syscall_event_catchpoint (int tempflag
, std::vector
<int> &&filter
)
354 struct gdbarch
*gdbarch
= get_current_arch ();
356 std::unique_ptr
<syscall_catchpoint
> c
357 (new syscall_catchpoint (gdbarch
, std::move (filter
)));
359 install_breakpoint (0, std::move (c
), 1);
362 /* Splits the argument using space as delimiter. */
364 static std::vector
<int>
365 catch_syscall_split_args (const char *arg
)
367 std::vector
<int> result
;
368 struct gdbarch
*gdbarch
= target_gdbarch ();
372 int i
, syscall_number
;
377 /* Skip whitespace. */
378 arg
= skip_spaces (arg
);
380 for (i
= 0; i
< 127 && arg
[i
] && !isspace (arg
[i
]); ++i
)
381 cur_name
[i
] = arg
[i
];
385 /* Check if the user provided a syscall name, group, or a number. */
386 syscall_number
= (int) strtol (cur_name
, &endptr
, 0);
389 if (syscall_number
< 0)
390 error (_("Unknown syscall number '%d'."), syscall_number
);
391 get_syscall_by_number (gdbarch
, syscall_number
, &s
);
392 result
.push_back (s
.number
);
394 else if (startswith (cur_name
, "g:")
395 || startswith (cur_name
, "group:"))
397 /* We have a syscall group. Let's expand it into a syscall
398 list before inserting. */
399 const char *group_name
;
401 /* Skip over "g:" and "group:" prefix strings. */
402 group_name
= strchr (cur_name
, ':') + 1;
404 if (!get_syscalls_by_group (gdbarch
, group_name
, &result
))
405 error (_("Unknown syscall group '%s'."), group_name
);
409 /* We have a name. Let's check if it's valid and fetch a
410 list of matching numbers. */
411 if (!get_syscalls_by_name (gdbarch
, cur_name
, &result
))
412 /* Here we have to issue an error instead of a warning,
413 because GDB cannot do anything useful if there's no
414 syscall number to be caught. */
415 error (_("Unknown syscall name '%s'."), cur_name
);
422 /* Implement the "catch syscall" command. */
425 catch_syscall_command_1 (const char *arg
, int from_tty
,
426 struct cmd_list_element
*command
)
429 std::vector
<int> filter
;
431 struct gdbarch
*gdbarch
= get_current_arch ();
433 /* Checking if the feature if supported. */
434 if (gdbarch_get_syscall_number_p (gdbarch
) == 0)
435 error (_("The feature 'catch syscall' is not supported on \
436 this architecture yet."));
438 tempflag
= command
->context () == CATCH_TEMPORARY
;
440 arg
= skip_spaces (arg
);
442 /* We need to do this first "dummy" translation in order
443 to get the syscall XML file loaded or, most important,
444 to display a warning to the user if there's no XML file
445 for his/her architecture. */
446 get_syscall_by_number (gdbarch
, 0, &s
);
448 /* The allowed syntax is:
450 catch syscall <name | number> [<name | number> ... <name | number>]
452 Let's check if there's a syscall name. */
455 filter
= catch_syscall_split_args (arg
);
457 create_syscall_event_catchpoint (tempflag
, std::move (filter
));
461 /* Returns 0 if 'bp' is NOT a syscall catchpoint,
462 non-zero otherwise. */
464 is_syscall_catchpoint_enabled (struct breakpoint
*bp
)
466 if (syscall_catchpoint_p (bp
)
467 && bp
->enable_state
!= bp_disabled
468 && bp
->enable_state
!= bp_call_disabled
)
475 catch_syscall_enabled (void)
477 struct catch_syscall_inferior_data
*inf_data
478 = get_catch_syscall_inferior_data (current_inferior ());
480 return inf_data
->total_syscalls_count
!= 0;
483 /* Helper function for catching_syscall_number. return true if B is a syscall
484 catchpoint for SYSCALL_NUMBER, else false. */
487 catching_syscall_number_1 (struct breakpoint
*b
, int syscall_number
)
490 if (is_syscall_catchpoint_enabled (b
))
492 struct syscall_catchpoint
*c
= (struct syscall_catchpoint
*) b
;
494 if (!c
->syscalls_to_be_caught
.empty ())
496 for (int iter
: c
->syscalls_to_be_caught
)
497 if (syscall_number
== iter
)
508 catching_syscall_number (int syscall_number
)
510 for (breakpoint
*b
: all_breakpoints ())
511 if (catching_syscall_number_1 (b
, syscall_number
))
517 /* Complete syscall names. Used by "catch syscall". */
520 catch_syscall_completer (struct cmd_list_element
*cmd
,
521 completion_tracker
&tracker
,
522 const char *text
, const char *word
)
524 struct gdbarch
*gdbarch
= get_current_arch ();
525 gdb::unique_xmalloc_ptr
<const char *> group_list
;
528 /* Completion considers ':' to be a word separator, so we use this to
529 verify whether the previous word was a group prefix. If so, we
530 build the completion list using group names only. */
531 for (prefix
= word
; prefix
!= text
&& prefix
[-1] != ' '; prefix
--)
534 if (startswith (prefix
, "g:") || startswith (prefix
, "group:"))
536 /* Perform completion inside 'group:' namespace only. */
537 group_list
.reset (get_syscall_group_names (gdbarch
));
538 if (group_list
!= NULL
)
539 complete_on_enum (tracker
, group_list
.get (), word
, word
);
543 /* Complete with both, syscall names and groups. */
544 gdb::unique_xmalloc_ptr
<const char *> syscall_list
545 (get_syscall_names (gdbarch
));
546 group_list
.reset (get_syscall_group_names (gdbarch
));
548 const char **group_ptr
= group_list
.get ();
550 /* Hold on to strings while we're using them. */
551 std::vector
<std::string
> holders
;
553 /* Append "group:" prefix to syscall groups. */
554 for (int i
= 0; group_ptr
[i
] != NULL
; i
++)
555 holders
.push_back (string_printf ("group:%s", group_ptr
[i
]));
557 for (int i
= 0; group_ptr
[i
] != NULL
; i
++)
558 group_ptr
[i
] = holders
[i
].c_str ();
560 if (syscall_list
!= NULL
)
561 complete_on_enum (tracker
, syscall_list
.get (), word
, word
);
562 if (group_list
!= NULL
)
563 complete_on_enum (tracker
, group_ptr
, word
, word
);
568 clear_syscall_counts (struct inferior
*inf
)
570 struct catch_syscall_inferior_data
*inf_data
571 = get_catch_syscall_inferior_data (inf
);
573 inf_data
->total_syscalls_count
= 0;
574 inf_data
->any_syscall_count
= 0;
575 inf_data
->syscalls_counts
.clear ();
578 void _initialize_break_catch_syscall ();
580 _initialize_break_catch_syscall ()
582 gdb::observers::inferior_exit
.attach (clear_syscall_counts
,
583 "break-catch-syscall");
585 add_catch_command ("syscall", _("\
586 Catch system calls by their names, groups and/or numbers.\n\
587 Arguments say which system calls to catch. If no arguments are given,\n\
588 every system call will be caught. Arguments, if given, should be one\n\
589 or more system call names (if your system supports that), system call\n\
590 groups or system call numbers."),
591 catch_syscall_command_1
,
592 catch_syscall_completer
,