GDB (xrefs)
Loading...
Searching...
No Matches
break-catch-syscall.c
Go to the documentation of this file.
1/* Everything about syscall catchpoints, for GDB.
2
3 Copyright (C) 2009-2023 Free Software Foundation, Inc.
4
5 This file is part of GDB.
6
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.
11
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.
16
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/>. */
19
20#include "defs.h"
21#include <ctype.h>
22#include "breakpoint.h"
23#include "gdbcmd.h"
24#include "inferior.h"
25#include "cli/cli-utils.h"
26#include "annotate.h"
27#include "mi/mi-common.h"
28#include "valprint.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"
34
35/* An instance of this type is used to represent a syscall
36 catchpoint. */
37
39{
40 syscall_catchpoint (struct gdbarch *gdbarch, bool tempflag,
41 std::vector<int> &&calls)
42 : catchpoint (gdbarch, tempflag, nullptr),
43 syscalls_to_be_caught (std::move (calls))
44 {
45 }
46
47 int insert_location (struct bp_location *) override;
48 int remove_location (struct bp_location *,
49 enum remove_bp_reason reason) override;
50 int breakpoint_hit (const struct bp_location *bl,
51 const address_space *aspace,
52 CORE_ADDR bp_addr,
53 const target_waitstatus &ws) override;
54 enum print_stop_action print_it (const bpstat *bs) const override;
55 bool print_one (const bp_location **) const override;
56 void print_mention () const override;
57 void print_recreate (struct ui_file *fp) const override;
58
59 /* Syscall numbers used for the 'catch syscall' feature. If no
60 syscall has been specified for filtering, it is empty.
61 Otherwise, it holds a list of all syscalls to be caught. */
62 std::vector<int> syscalls_to_be_caught;
63};
64
66{
67 /* We keep a count of the number of times the user has requested a
68 particular syscall to be tracked, and pass this information to the
69 target. This lets capable targets implement filtering directly. */
70
71 /* Number of times that "any" syscall is requested. */
73
74 /* Count of each system call. */
75 std::vector<int> syscalls_counts;
76
77 /* This counts all syscall catch requests, so we can readily determine
78 if any catching is necessary. */
80};
81
84
85static struct catch_syscall_inferior_data *
87{
88 struct catch_syscall_inferior_data *inf_data;
89
90 inf_data = catch_syscall_inferior_data.get (inf);
91 if (inf_data == NULL)
92 inf_data = catch_syscall_inferior_data.emplace (inf);
93
94 return inf_data;
95}
96
97/* Implement the "insert" method for syscall catchpoints. */
98
99int
101{
102 struct inferior *inf = current_inferior ();
103 struct catch_syscall_inferior_data *inf_data
105
106 ++inf_data->total_syscalls_count;
107 if (syscalls_to_be_caught.empty ())
108 ++inf_data->any_syscall_count;
109 else
110 {
111 for (int iter : syscalls_to_be_caught)
112 {
113 if (iter >= inf_data->syscalls_counts.size ())
114 inf_data->syscalls_counts.resize (iter + 1);
115 ++inf_data->syscalls_counts[iter];
116 }
117 }
118
120 inf_data->total_syscalls_count != 0,
121 inf_data->any_syscall_count,
122 inf_data->syscalls_counts);
123}
124
125/* Implement the "remove" method for syscall catchpoints. */
126
127int
129 enum remove_bp_reason reason)
130{
131 struct inferior *inf = current_inferior ();
132 struct catch_syscall_inferior_data *inf_data
134
135 --inf_data->total_syscalls_count;
136 if (syscalls_to_be_caught.empty ())
137 --inf_data->any_syscall_count;
138 else
139 {
140 for (int iter : syscalls_to_be_caught)
141 {
142 if (iter >= inf_data->syscalls_counts.size ())
143 /* Shouldn't happen. */
144 continue;
145 --inf_data->syscalls_counts[iter];
146 }
147 }
148
150 inf_data->total_syscalls_count != 0,
151 inf_data->any_syscall_count,
152 inf_data->syscalls_counts);
153}
154
155/* Implement the "breakpoint_hit" method for syscall catchpoints. */
156
157int
159 const address_space *aspace,
160 CORE_ADDR bp_addr,
161 const target_waitstatus &ws)
162{
163 /* We must check if we are catching specific syscalls in this
164 breakpoint. If we are, then we must guarantee that the called
165 syscall is the same syscall we are catching. */
166 int syscall_number = 0;
167
170 return 0;
171
172 syscall_number = ws.syscall_number ();
173
174 /* Now, checking if the syscall is the same. */
175 if (!syscalls_to_be_caught.empty ())
176 {
177 for (int iter : syscalls_to_be_caught)
178 if (syscall_number == iter)
179 return 1;
180
181 return 0;
182 }
183
184 return 1;
185}
186
187/* Implement the "print_it" method for syscall catchpoints. */
188
191{
192 struct ui_out *uiout = current_uiout;
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;
198 struct syscall s;
199
200 get_last_target_status (nullptr, nullptr, &last);
201
203
206
207 if (this->disposition == disp_del)
208 uiout->text ("Temporary catchpoint ");
209 else
210 uiout->text ("Catchpoint ");
211 if (uiout->is_mi_like_p ())
212 {
213 uiout->field_string ("reason",
217 uiout->field_string ("disp", bpdisp_text (this->disposition));
218 }
219 print_num_locno (bs, uiout);
220
221 if (last.kind () == TARGET_WAITKIND_SYSCALL_ENTRY)
222 uiout->text (" (call to syscall ");
223 else
224 uiout->text (" (returned from syscall ");
225
226 if (s.name == NULL || uiout->is_mi_like_p ())
227 uiout->field_signed ("syscall-number", last.syscall_number ());
228 if (s.name != NULL)
229 uiout->field_string ("syscall-name", s.name);
230
231 uiout->text ("), ");
232
233 return PRINT_SRC_AND_LOC;
234}
235
236/* Implement the "print_one" method for syscall catchpoints. */
237
238bool
240{
241 struct value_print_options opts;
242 struct ui_out *uiout = current_uiout;
243
245 /* Field 4, the address, is omitted (which makes the columns not
246 line up too nicely with the headers, but the effect is relatively
247 readable). */
248 if (opts.addressprint)
249 uiout->field_skip ("addr");
250 annotate_field (5);
251
252 if (syscalls_to_be_caught.size () > 1)
253 uiout->text ("syscalls \"");
254 else
255 uiout->text ("syscall \"");
256
257 if (!syscalls_to_be_caught.empty ())
258 {
259 std::string text;
260
261 bool first = true;
262 for (int iter : syscalls_to_be_caught)
263 {
264 struct syscall s;
265 get_syscall_by_number (gdbarch, iter, &s);
266
267 if (!first)
268 text += ", ";
269 first = false;
270
271 if (s.name != NULL)
272 text += s.name;
273 else
274 text += std::to_string (iter);
275 }
276 uiout->field_string ("what", text.c_str ());
277 }
278 else
279 uiout->field_string ("what", "<any syscall>", metadata_style.style ());
280 uiout->text ("\" ");
281
282 if (uiout->is_mi_like_p ())
283 uiout->field_string ("catch-type", "syscall");
284
285 return true;
286}
287
288/* Implement the "print_mention" method for syscall catchpoints. */
289
290void
292{
293 if (!syscalls_to_be_caught.empty ())
294 {
295 if (syscalls_to_be_caught.size () > 1)
296 gdb_printf (_("Catchpoint %d (syscalls"), number);
297 else
298 gdb_printf (_("Catchpoint %d (syscall"), number);
299
300 for (int iter : syscalls_to_be_caught)
301 {
302 struct syscall s;
303 get_syscall_by_number (gdbarch, iter, &s);
304
305 if (s.name != NULL)
306 gdb_printf (" '%s' [%d]", s.name, s.number);
307 else
308 gdb_printf (" %d", s.number);
309 }
310 gdb_printf (")");
311 }
312 else
313 gdb_printf (_("Catchpoint %d (any syscall)"), number);
314}
315
316/* Implement the "print_recreate" method for syscall catchpoints. */
317
318void
320{
321 gdb_printf (fp, "catch syscall");
322
323 for (int iter : syscalls_to_be_caught)
324 {
325 struct syscall s;
326
327 get_syscall_by_number (gdbarch, iter, &s);
328 if (s.name != NULL)
329 gdb_printf (fp, " %s", s.name);
330 else
331 gdb_printf (fp, " %d", s.number);
332 }
333
335}
336
337/* Returns non-zero if 'b' is a syscall catchpoint. */
338
339static int
341{
342 return dynamic_cast<syscall_catchpoint *> (b) != nullptr;
343}
344
345static void
346create_syscall_event_catchpoint (int tempflag, std::vector<int> &&filter)
347{
348 struct gdbarch *gdbarch = get_current_arch ();
349
350 std::unique_ptr<syscall_catchpoint> c
351 (new syscall_catchpoint (gdbarch, tempflag, std::move (filter)));
352
353 install_breakpoint (0, std::move (c), 1);
354}
355
356/* Splits the argument using space as delimiter. */
357
358static std::vector<int>
360{
361 std::vector<int> result;
362 struct gdbarch *gdbarch = target_gdbarch ();
363
364 while (*arg != '\0')
365 {
366 int i, syscall_number;
367 char *endptr;
368 char cur_name[128];
369 struct syscall s;
370
371 /* Skip whitespace. */
372 arg = skip_spaces (arg);
373
374 for (i = 0; i < 127 && arg[i] && !isspace (arg[i]); ++i)
375 cur_name[i] = arg[i];
376 cur_name[i] = '\0';
377 arg += i;
378
379 /* Check if the user provided a syscall name, group, or a number. */
380 syscall_number = (int) strtol (cur_name, &endptr, 0);
381 if (*endptr == '\0')
382 {
383 if (syscall_number < 0)
384 error (_("Unknown syscall number '%d'."), syscall_number);
385 get_syscall_by_number (gdbarch, syscall_number, &s);
386 result.push_back (s.number);
387 }
388 else if (startswith (cur_name, "g:")
389 || startswith (cur_name, "group:"))
390 {
391 /* We have a syscall group. Let's expand it into a syscall
392 list before inserting. */
393 const char *group_name;
394
395 /* Skip over "g:" and "group:" prefix strings. */
396 group_name = strchr (cur_name, ':') + 1;
397
398 if (!get_syscalls_by_group (gdbarch, group_name, &result))
399 error (_("Unknown syscall group '%s'."), group_name);
400 }
401 else
402 {
403 /* We have a name. Let's check if it's valid and fetch a
404 list of matching numbers. */
405 if (!get_syscalls_by_name (gdbarch, cur_name, &result))
406 /* Here we have to issue an error instead of a warning,
407 because GDB cannot do anything useful if there's no
408 syscall number to be caught. */
409 error (_("Unknown syscall name '%s'."), cur_name);
410 }
411 }
412
413 return result;
414}
415
416/* Implement the "catch syscall" command. */
417
418static void
419catch_syscall_command_1 (const char *arg, int from_tty,
420 struct cmd_list_element *command)
421{
422 int tempflag;
423 std::vector<int> filter;
424 struct syscall s;
425 struct gdbarch *gdbarch = get_current_arch ();
426
427 /* Checking if the feature if supported. */
429 error (_("The feature 'catch syscall' is not supported on \
430this architecture yet."));
431
432 tempflag = command->context () == CATCH_TEMPORARY;
433
434 arg = skip_spaces (arg);
435
436 /* We need to do this first "dummy" translation in order
437 to get the syscall XML file loaded or, most important,
438 to display a warning to the user if there's no XML file
439 for his/her architecture. */
441
442 /* The allowed syntax is:
443 catch syscall
444 catch syscall <name | number> [<name | number> ... <name | number>]
445
446 Let's check if there's a syscall name. */
447
448 if (arg != NULL)
449 filter = catch_syscall_split_args (arg);
450
451 create_syscall_event_catchpoint (tempflag, std::move (filter));
452}
453
454
455/* Returns 0 if 'bp' is NOT a syscall catchpoint,
456 non-zero otherwise. */
457static int
459{
461 && bp->enable_state != bp_disabled
462 && bp->enable_state != bp_call_disabled)
463 return 1;
464 else
465 return 0;
466}
467
468int
470{
471 struct catch_syscall_inferior_data *inf_data
473
474 return inf_data->total_syscalls_count != 0;
475}
476
477/* Helper function for catching_syscall_number. return true if B is a syscall
478 catchpoint for SYSCALL_NUMBER, else false. */
479
480static bool
481catching_syscall_number_1 (struct breakpoint *b, int syscall_number)
482{
484 {
486 = gdb::checked_static_cast<syscall_catchpoint *> (b);
487
488 if (!c->syscalls_to_be_caught.empty ())
489 {
490 for (int iter : c->syscalls_to_be_caught)
491 if (syscall_number == iter)
492 return true;
493 }
494 else
495 return true;
496 }
497
498 return false;
499}
500
501bool
502catching_syscall_number (int syscall_number)
503{
504 for (breakpoint &b : all_breakpoints ())
505 if (catching_syscall_number_1 (&b, syscall_number))
506 return true;
507
508 return false;
509}
510
511/* Complete syscall names. Used by "catch syscall". */
512
513static void
515 completion_tracker &tracker,
516 const char *text, const char *word)
517{
518 struct gdbarch *gdbarch = get_current_arch ();
519 gdb::unique_xmalloc_ptr<const char *> group_list;
520 const char *prefix;
521
522 /* Completion considers ':' to be a word separator, so we use this to
523 verify whether the previous word was a group prefix. If so, we
524 build the completion list using group names only. */
525 for (prefix = word; prefix != text && prefix[-1] != ' '; prefix--)
526 ;
527
528 if (startswith (prefix, "g:") || startswith (prefix, "group:"))
529 {
530 /* Perform completion inside 'group:' namespace only. */
531 group_list.reset (get_syscall_group_names (gdbarch));
532 if (group_list != NULL)
533 complete_on_enum (tracker, group_list.get (), word, word);
534 }
535 else
536 {
537 /* Complete with both, syscall names and groups. */
538 gdb::unique_xmalloc_ptr<const char *> syscall_list
540 group_list.reset (get_syscall_group_names (gdbarch));
541
542 const char **group_ptr = group_list.get ();
543
544 /* Hold on to strings while we're using them. */
545 std::vector<std::string> holders;
546
547 /* Append "group:" prefix to syscall groups. */
548 for (int i = 0; group_ptr[i] != NULL; i++)
549 holders.push_back (string_printf ("group:%s", group_ptr[i]));
550
551 for (int i = 0; group_ptr[i] != NULL; i++)
552 group_ptr[i] = holders[i].c_str ();
553
554 if (syscall_list != NULL)
555 complete_on_enum (tracker, syscall_list.get (), word, word);
556 if (group_list != NULL)
557 complete_on_enum (tracker, group_ptr, word, word);
558 }
559}
560
561static void
563{
564 struct catch_syscall_inferior_data *inf_data
566
567 inf_data->total_syscalls_count = 0;
568 inf_data->any_syscall_count = 0;
569 inf_data->syscalls_counts.clear ();
570}
571
573void
575{
577 "break-catch-syscall");
578
579 add_catch_command ("syscall", _("\
580Catch system calls by their names, groups and/or numbers.\n\
581Arguments say which system calls to catch. If no arguments are given,\n\
582every system call will be caught. Arguments, if given, should be one\n\
583or more system call names (if your system supports that), system call\n\
584groups or system call numbers."),
589}
void annotate_field(int num)
Definition annotate.c:172
void annotate_catchpoint(int num)
Definition annotate.c:82
struct gdbarch * get_current_arch(void)
Definition arch-utils.c:846
struct gdbarch * target_gdbarch(void)
static std::vector< int > catch_syscall_split_args(const char *arg)
static bool catching_syscall_number_1(struct breakpoint *b, int syscall_number)
static void catch_syscall_command_1(const char *arg, int from_tty, struct cmd_list_element *command)
static void clear_syscall_counts(struct inferior *inf)
static int syscall_catchpoint_p(struct breakpoint *b)
int catch_syscall_enabled(void)
static void catch_syscall_completer(struct cmd_list_element *cmd, completion_tracker &tracker, const char *text, const char *word)
static int is_syscall_catchpoint_enabled(struct breakpoint *bp)
static const registry< inferior >::key< catch_syscall_inferior_data > catch_syscall_inferior_data
bool catching_syscall_number(int syscall_number)
static struct catch_syscall_inferior_data * get_catch_syscall_inferior_data(struct inferior *inf)
void _initialize_break_catch_syscall()
static void create_syscall_event_catchpoint(int tempflag, std::vector< int > &&filter)
void add_catch_command(const char *name, const char *docstring, cmd_func_ftype *func, completer_ftype *completer, void *user_data_catch, void *user_data_tcatch)
const char * bpdisp_text(enum bpdisp disp)
Definition breakpoint.c:505
breakpoint * install_breakpoint(int internal, std::unique_ptr< breakpoint > &&arg, int update_gll)
void print_num_locno(const bpstat *bs, struct ui_out *uiout)
breakpoint_range all_breakpoints()
Definition breakpoint.c:704
void maybe_print_thread_hit_breakpoint(struct ui_out *uiout)
#define CATCH_PERMANENT
@ disp_del
Definition breakpoint.h:237
#define CATCH_TEMPORARY
print_stop_action
Definition breakpoint.h:542
@ PRINT_SRC_AND_LOC
Definition breakpoint.h:548
@ bp_disabled
Definition breakpoint.h:218
@ bp_call_disabled
Definition breakpoint.h:222
remove_bp_reason
Definition breakpoint.h:64
ui_file_style style() const
Definition cli-style.c:169
void field_string(const char *fldname, const char *string, const ui_file_style &style=ui_file_style())
Definition ui-out.c:511
void field_signed(const char *fldname, LONGEST value)
Definition ui-out.c:437
void field_skip(const char *fldname)
Definition ui-out.c:499
void text(const char *string)
Definition ui-out.c:566
bool is_mi_like_p() const
Definition ui-out.c:810
void complete_on_enum(completion_tracker &tracker, const char *const *enumlist, const char *text, const char *word)
cli_style_option metadata_style
bool gdbarch_get_syscall_number_p(struct gdbarch *gdbarch)
Definition gdbarch.c:4492
ptid_t inferior_ptid
Definition infcmd.c:74
struct inferior * current_inferior(void)
Definition inferior.c:55
void get_last_target_status(process_stratum_target **target, ptid_t *ptid, target_waitstatus *status)
Definition infrun.c:4621
const char * async_reason_lookup(enum async_reply_reason reason)
Definition mi-common.c:50
@ EXEC_ASYNC_SYSCALL_ENTRY
Definition mi-common.h:42
@ EXEC_ASYNC_SYSCALL_RETURN
Definition mi-common.h:43
observable< struct inferior * > inferior_exit
Definition aarch64.h:67
#define prefix(a, b, R, do)
Definition ppc64-tdep.c:52
void print_recreate_thread(struct ui_file *fp) const
bpdisp disposition
Definition breakpoint.h:802
void * context() const
Definition cli-decode.h:109
Definition gnu-nat.c:153
std::vector< int > syscalls_to_be_caught
int insert_location(struct bp_location *) override
int breakpoint_hit(const struct bp_location *bl, const address_space *aspace, CORE_ADDR bp_addr, const target_waitstatus &ws) override
bool print_one(const bp_location **) const override
void print_mention() const override
enum print_stop_action print_it(const bpstat *bs) const override
syscall_catchpoint(struct gdbarch *gdbarch, bool tempflag, std::vector< int > &&calls)
int remove_location(struct bp_location *, enum remove_bp_reason reason) override
void print_recreate(struct ui_file *fp) const override
const char * name
Definition target.h:122
int number
Definition target.h:119
target_waitkind kind() const
Definition waitstatus.h:345
int target_set_syscall_catchpoint(int pid, bool needed, int any_count, gdb::array_view< const int > syscall_counts)
Definition target.c:354
#define current_uiout
Definition ui-out.h:40
void gdb_printf(struct ui_file *stream, const char *format,...)
Definition utils.c:1886
void get_user_print_options(struct value_print_options *opts)
Definition valprint.c:135
@ TARGET_WAITKIND_SYSCALL_RETURN
Definition waitstatus.h:73
@ TARGET_WAITKIND_SYSCALL_ENTRY
Definition waitstatus.h:72
#define nullptr
Definition x86-cpuid.h:28
const char ** get_syscall_group_names(struct gdbarch *gdbarch)
Definition xml-syscall.c:88
bool get_syscalls_by_group(struct gdbarch *gdbarch, const char *group, std::vector< int > *syscall_numbers)
Definition xml-syscall.c:80
const char ** get_syscall_names(struct gdbarch *gdbarch)
Definition xml-syscall.c:73
bool get_syscalls_by_name(struct gdbarch *gdbarch, const char *syscall_name, std::vector< int > *syscall_numbers)
Definition xml-syscall.c:65
void get_syscall_by_number(struct gdbarch *gdbarch, int syscall_number, struct syscall *s)
Definition xml-syscall.c:56