GDB (xrefs)
Loading...
Searching...
No Matches
/tmp/gdb-13.1/gdb/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 (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 struct breakpoint *b = bs->breakpoint_at;
194 /* These are needed because we want to know in which state a
195 syscall is. It can be in the TARGET_WAITKIND_SYSCALL_ENTRY
196 or TARGET_WAITKIND_SYSCALL_RETURN, and depending on it we
197 must print "called syscall" or "returned from syscall". */
198 struct target_waitstatus last;
199 struct syscall s;
200 struct gdbarch *gdbarch = b->gdbarch;
201
202 get_last_target_status (nullptr, nullptr, &last);
203
205
208
209 if (b->disposition == disp_del)
210 uiout->text ("Temporary catchpoint ");
211 else
212 uiout->text ("Catchpoint ");
213 if (uiout->is_mi_like_p ())
214 {
215 uiout->field_string ("reason",
219 uiout->field_string ("disp", bpdisp_text (b->disposition));
220 }
221 print_num_locno (bs, uiout);
222
223 if (last.kind () == TARGET_WAITKIND_SYSCALL_ENTRY)
224 uiout->text (" (call to syscall ");
225 else
226 uiout->text (" (returned from syscall ");
227
228 if (s.name == NULL || uiout->is_mi_like_p ())
229 uiout->field_signed ("syscall-number", last.syscall_number ());
230 if (s.name != NULL)
231 uiout->field_string ("syscall-name", s.name);
232
233 uiout->text ("), ");
234
235 return PRINT_SRC_AND_LOC;
236}
237
238/* Implement the "print_one" method for syscall catchpoints. */
239
240bool
242{
243 struct value_print_options opts;
244 struct ui_out *uiout = current_uiout;
245 struct gdbarch *gdbarch = loc->owner->gdbarch;
246
248 /* Field 4, the address, is omitted (which makes the columns not
249 line up too nicely with the headers, but the effect is relatively
250 readable). */
251 if (opts.addressprint)
252 uiout->field_skip ("addr");
253 annotate_field (5);
254
255 if (syscalls_to_be_caught.size () > 1)
256 uiout->text ("syscalls \"");
257 else
258 uiout->text ("syscall \"");
259
260 if (!syscalls_to_be_caught.empty ())
261 {
262 std::string text;
263
264 bool first = true;
265 for (int iter : syscalls_to_be_caught)
266 {
267 struct syscall s;
268 get_syscall_by_number (gdbarch, iter, &s);
269
270 if (!first)
271 text += ", ";
272 first = false;
273
274 if (s.name != NULL)
275 text += s.name;
276 else
277 text += std::to_string (iter);
278 }
279 uiout->field_string ("what", text.c_str ());
280 }
281 else
282 uiout->field_string ("what", "<any syscall>", metadata_style.style ());
283 uiout->text ("\" ");
284
285 if (uiout->is_mi_like_p ())
286 uiout->field_string ("catch-type", "syscall");
287
288 return true;
289}
290
291/* Implement the "print_mention" method for syscall catchpoints. */
292
293void
295{
296 struct gdbarch *gdbarch = loc->owner->gdbarch;
297
298 if (!syscalls_to_be_caught.empty ())
299 {
300 if (syscalls_to_be_caught.size () > 1)
301 gdb_printf (_("Catchpoint %d (syscalls"), number);
302 else
303 gdb_printf (_("Catchpoint %d (syscall"), number);
304
305 for (int iter : syscalls_to_be_caught)
306 {
307 struct syscall s;
308 get_syscall_by_number (gdbarch, iter, &s);
309
310 if (s.name != NULL)
311 gdb_printf (" '%s' [%d]", s.name, s.number);
312 else
313 gdb_printf (" %d", s.number);
314 }
315 gdb_printf (")");
316 }
317 else
318 gdb_printf (_("Catchpoint %d (any syscall)"), number);
319}
320
321/* Implement the "print_recreate" method for syscall catchpoints. */
322
323void
325{
326 struct gdbarch *gdbarch = loc->gdbarch;
327
328 gdb_printf (fp, "catch syscall");
329
330 for (int iter : syscalls_to_be_caught)
331 {
332 struct syscall s;
333
334 get_syscall_by_number (gdbarch, iter, &s);
335 if (s.name != NULL)
336 gdb_printf (fp, " %s", s.name);
337 else
338 gdb_printf (fp, " %d", s.number);
339 }
340
342}
343
344/* Returns non-zero if 'b' is a syscall catchpoint. */
345
346static int
348{
349 return dynamic_cast<syscall_catchpoint *> (b) != nullptr;
350}
351
352static void
353create_syscall_event_catchpoint (int tempflag, std::vector<int> &&filter)
354{
355 struct gdbarch *gdbarch = get_current_arch ();
356
357 std::unique_ptr<syscall_catchpoint> c
358 (new syscall_catchpoint (gdbarch, tempflag, std::move (filter)));
359
360 install_breakpoint (0, std::move (c), 1);
361}
362
363/* Splits the argument using space as delimiter. */
364
365static std::vector<int>
367{
368 std::vector<int> result;
369 struct gdbarch *gdbarch = target_gdbarch ();
370
371 while (*arg != '\0')
372 {
373 int i, syscall_number;
374 char *endptr;
375 char cur_name[128];
376 struct syscall s;
377
378 /* Skip whitespace. */
379 arg = skip_spaces (arg);
380
381 for (i = 0; i < 127 && arg[i] && !isspace (arg[i]); ++i)
382 cur_name[i] = arg[i];
383 cur_name[i] = '\0';
384 arg += i;
385
386 /* Check if the user provided a syscall name, group, or a number. */
387 syscall_number = (int) strtol (cur_name, &endptr, 0);
388 if (*endptr == '\0')
389 {
390 if (syscall_number < 0)
391 error (_("Unknown syscall number '%d'."), syscall_number);
392 get_syscall_by_number (gdbarch, syscall_number, &s);
393 result.push_back (s.number);
394 }
395 else if (startswith (cur_name, "g:")
396 || startswith (cur_name, "group:"))
397 {
398 /* We have a syscall group. Let's expand it into a syscall
399 list before inserting. */
400 const char *group_name;
401
402 /* Skip over "g:" and "group:" prefix strings. */
403 group_name = strchr (cur_name, ':') + 1;
404
405 if (!get_syscalls_by_group (gdbarch, group_name, &result))
406 error (_("Unknown syscall group '%s'."), group_name);
407 }
408 else
409 {
410 /* We have a name. Let's check if it's valid and fetch a
411 list of matching numbers. */
412 if (!get_syscalls_by_name (gdbarch, cur_name, &result))
413 /* Here we have to issue an error instead of a warning,
414 because GDB cannot do anything useful if there's no
415 syscall number to be caught. */
416 error (_("Unknown syscall name '%s'."), cur_name);
417 }
418 }
419
420 return result;
421}
422
423/* Implement the "catch syscall" command. */
424
425static void
426catch_syscall_command_1 (const char *arg, int from_tty,
427 struct cmd_list_element *command)
428{
429 int tempflag;
430 std::vector<int> filter;
431 struct syscall s;
432 struct gdbarch *gdbarch = get_current_arch ();
433
434 /* Checking if the feature if supported. */
436 error (_("The feature 'catch syscall' is not supported on \
437this architecture yet."));
438
439 tempflag = command->context () == CATCH_TEMPORARY;
440
441 arg = skip_spaces (arg);
442
443 /* We need to do this first "dummy" translation in order
444 to get the syscall XML file loaded or, most important,
445 to display a warning to the user if there's no XML file
446 for his/her architecture. */
448
449 /* The allowed syntax is:
450 catch syscall
451 catch syscall <name | number> [<name | number> ... <name | number>]
452
453 Let's check if there's a syscall name. */
454
455 if (arg != NULL)
456 filter = catch_syscall_split_args (arg);
457
458 create_syscall_event_catchpoint (tempflag, std::move (filter));
459}
460
461
462/* Returns 0 if 'bp' is NOT a syscall catchpoint,
463 non-zero otherwise. */
464static int
466{
468 && bp->enable_state != bp_disabled
469 && bp->enable_state != bp_call_disabled)
470 return 1;
471 else
472 return 0;
473}
474
475int
477{
478 struct catch_syscall_inferior_data *inf_data
480
481 return inf_data->total_syscalls_count != 0;
482}
483
484/* Helper function for catching_syscall_number. return true if B is a syscall
485 catchpoint for SYSCALL_NUMBER, else false. */
486
487static bool
488catching_syscall_number_1 (struct breakpoint *b, int syscall_number)
489{
490
492 {
493 struct syscall_catchpoint *c = (struct syscall_catchpoint *) b;
494
495 if (!c->syscalls_to_be_caught.empty ())
496 {
497 for (int iter : c->syscalls_to_be_caught)
498 if (syscall_number == iter)
499 return true;
500 }
501 else
502 return true;
503 }
504
505 return false;
506}
507
508bool
509catching_syscall_number (int syscall_number)
510{
511 for (breakpoint *b : all_breakpoints ())
512 if (catching_syscall_number_1 (b, syscall_number))
513 return true;
514
515 return false;
516}
517
518/* Complete syscall names. Used by "catch syscall". */
519
520static void
522 completion_tracker &tracker,
523 const char *text, const char *word)
524{
525 struct gdbarch *gdbarch = get_current_arch ();
526 gdb::unique_xmalloc_ptr<const char *> group_list;
527 const char *prefix;
528
529 /* Completion considers ':' to be a word separator, so we use this to
530 verify whether the previous word was a group prefix. If so, we
531 build the completion list using group names only. */
532 for (prefix = word; prefix != text && prefix[-1] != ' '; prefix--)
533 ;
534
535 if (startswith (prefix, "g:") || startswith (prefix, "group:"))
536 {
537 /* Perform completion inside 'group:' namespace only. */
538 group_list.reset (get_syscall_group_names (gdbarch));
539 if (group_list != NULL)
540 complete_on_enum (tracker, group_list.get (), word, word);
541 }
542 else
543 {
544 /* Complete with both, syscall names and groups. */
545 gdb::unique_xmalloc_ptr<const char *> syscall_list
547 group_list.reset (get_syscall_group_names (gdbarch));
548
549 const char **group_ptr = group_list.get ();
550
551 /* Hold on to strings while we're using them. */
552 std::vector<std::string> holders;
553
554 /* Append "group:" prefix to syscall groups. */
555 for (int i = 0; group_ptr[i] != NULL; i++)
556 holders.push_back (string_printf ("group:%s", group_ptr[i]));
557
558 for (int i = 0; group_ptr[i] != NULL; i++)
559 group_ptr[i] = holders[i].c_str ();
560
561 if (syscall_list != NULL)
562 complete_on_enum (tracker, syscall_list.get (), word, word);
563 if (group_list != NULL)
564 complete_on_enum (tracker, group_ptr, word, word);
565 }
566}
567
568static void
570{
571 struct catch_syscall_inferior_data *inf_data
573
574 inf_data->total_syscalls_count = 0;
575 inf_data->any_syscall_count = 0;
576 inf_data->syscalls_counts.clear ();
577}
578
580void
582{
584 "break-catch-syscall");
585
586 add_catch_command ("syscall", _("\
587Catch system calls by their names, groups and/or numbers.\n\
588Arguments say which system calls to catch. If no arguments are given,\n\
589every system call will be caught. Arguments, if given, should be one\n\
590or more system call names (if your system supports that), system call\n\
591groups or system call numbers."),
596}
void annotate_field(int num)
Definition: annotate.c:173
void annotate_catchpoint(int num)
Definition: annotate.c:83
struct gdbarch * get_current_arch(void)
Definition: arch-utils.c:846
struct gdbarch * target_gdbarch(void)
Definition: arch-utils.c:1453
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)
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)
Definition: breakpoint.c:14303
const char * bpdisp_text(enum bpdisp disp)
Definition: breakpoint.c:437
void print_num_locno(const bpstat *bs, struct ui_out *uiout)
Definition: breakpoint.c:4539
void install_breakpoint(int internal, std::unique_ptr< breakpoint > &&arg, int update_gll)
Definition: breakpoint.c:7960
breakpoint_range all_breakpoints()
Definition: breakpoint.c:629
void maybe_print_thread_hit_breakpoint(struct ui_out *uiout)
Definition: breakpoint.c:4792
#define CATCH_PERMANENT
Definition: breakpoint.h:1464
@ disp_del
Definition: breakpoint.h:237
#define CATCH_TEMPORARY
Definition: breakpoint.h:1465
print_stop_action
Definition: breakpoint.h:543
@ PRINT_SRC_AND_LOC
Definition: breakpoint.h:549
@ bp_disabled
Definition: breakpoint.h:218
@ bp_call_disabled
Definition: breakpoint.h:222
remove_bp_reason
Definition: breakpoint.h:64
breakpoint * owner
Definition: breakpoint.h:350
struct gdbarch * gdbarch
Definition: breakpoint.h:428
ui_file_style style() const
Definition: cli-style.c:169
Definition: ui-out.h:160
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)
Definition: cli-decode.c:2519
cli_style_option metadata_style
bool gdbarch_get_syscall_number_p(struct gdbarch *gdbarch)
Definition: gdbarch.c:4392
ptid_t inferior_ptid
Definition: infcmd.c:91
struct inferior * current_inferior(void)
Definition: inferior.c:54
void get_last_target_status(process_stratum_target **target, ptid_t *ptid, target_waitstatus *status)
Definition: infrun.c:4345
const char * async_reason_lookup(enum async_reply_reason reason)
Definition: mi-common.c:49
@ 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:50
#define prefix(a, b, R, do)
Definition: ppc64-tdep.c:52
struct breakpoint * breakpoint_at
Definition: breakpoint.h:1321
void print_recreate_thread(struct ui_file *fp) const
Definition: breakpoint.c:14099
struct gdbarch * gdbarch
Definition: breakpoint.h:781
bp_location * loc
Definition: breakpoint.h:742
bpdisp disposition
Definition: breakpoint.h:737
std::vector< int > syscalls_counts
void * context() const
Definition: cli-decode.h:109
Definition: gnu-nat.c:154
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(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:117
int number
Definition: target.h:114
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:355
#define current_uiout
Definition: ui-out.h:40
void gdb_printf(struct ui_file *stream, const char *format,...)
Definition: utils.c:1865
void get_user_print_options(struct value_print_options *opts)
Definition: valprint.c:128
@ TARGET_WAITKIND_SYSCALL_RETURN
Definition: waitstatus.h:73
@ TARGET_WAITKIND_SYSCALL_ENTRY
Definition: waitstatus.h:72
const char ** get_syscall_group_names(struct gdbarch *gdbarch)
Definition: xml-syscall.c:558
bool get_syscalls_by_group(struct gdbarch *gdbarch, const char *group, std::vector< int > *syscall_numbers)
Definition: xml-syscall.c:547
const char ** get_syscall_names(struct gdbarch *gdbarch)
Definition: xml-syscall.c:537
bool get_syscalls_by_name(struct gdbarch *gdbarch, const char *syscall_name, std::vector< int > *syscall_numbers)
Definition: xml-syscall.c:528
void get_syscall_by_number(struct gdbarch *gdbarch, int syscall_number, struct syscall *s)
Definition: xml-syscall.c:518