1 /* Everything about syscall catchpoints, for GDB.
3 Copyright (C) 2009-2018 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"
33 /* An instance of this type is used to represent a syscall catchpoint.
34 A breakpoint is really of this type iff its ops pointer points to
35 CATCH_SYSCALL_BREAKPOINT_OPS. */
37 struct syscall_catchpoint
: public breakpoint
39 /* Syscall numbers used for the 'catch syscall' feature. If no
40 syscall has been specified for filtering, it is empty.
41 Otherwise, it holds a list of all syscalls to be caught. */
42 std::vector
<int> syscalls_to_be_caught
;
45 static const struct inferior_data
*catch_syscall_inferior_data
= NULL
;
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 struct catch_syscall_inferior_data
*
65 get_catch_syscall_inferior_data (struct inferior
*inf
)
67 struct catch_syscall_inferior_data
*inf_data
;
69 inf_data
= ((struct catch_syscall_inferior_data
*)
70 inferior_data (inf
, catch_syscall_inferior_data
));
73 inf_data
= new struct catch_syscall_inferior_data ();
74 set_inferior_data (inf
, catch_syscall_inferior_data
, inf_data
);
81 catch_syscall_inferior_data_cleanup (struct inferior
*inf
, void *arg
)
83 struct catch_syscall_inferior_data
*inf_data
84 = (struct catch_syscall_inferior_data
*) arg
;
89 /* Implement the "insert" breakpoint_ops method for syscall
93 insert_catch_syscall (struct bp_location
*bl
)
95 struct syscall_catchpoint
*c
= (struct syscall_catchpoint
*) bl
->owner
;
96 struct inferior
*inf
= current_inferior ();
97 struct catch_syscall_inferior_data
*inf_data
98 = get_catch_syscall_inferior_data (inf
);
100 ++inf_data
->total_syscalls_count
;
101 if (c
->syscalls_to_be_caught
.empty ())
102 ++inf_data
->any_syscall_count
;
105 for (int iter
: c
->syscalls_to_be_caught
)
107 if (iter
>= inf_data
->syscalls_counts
.size ())
108 inf_data
->syscalls_counts
.resize (iter
+ 1);
109 ++inf_data
->syscalls_counts
[iter
];
113 return target_set_syscall_catchpoint (inferior_ptid
.pid (),
114 inf_data
->total_syscalls_count
!= 0,
115 inf_data
->any_syscall_count
,
116 inf_data
->syscalls_counts
);
119 /* Implement the "remove" breakpoint_ops method for syscall
123 remove_catch_syscall (struct bp_location
*bl
, enum remove_bp_reason reason
)
125 struct syscall_catchpoint
*c
= (struct syscall_catchpoint
*) bl
->owner
;
126 struct inferior
*inf
= current_inferior ();
127 struct catch_syscall_inferior_data
*inf_data
128 = get_catch_syscall_inferior_data (inf
);
130 --inf_data
->total_syscalls_count
;
131 if (c
->syscalls_to_be_caught
.empty ())
132 --inf_data
->any_syscall_count
;
135 for (int iter
: c
->syscalls_to_be_caught
)
137 if (iter
>= inf_data
->syscalls_counts
.size ())
138 /* Shouldn't happen. */
140 --inf_data
->syscalls_counts
[iter
];
144 return target_set_syscall_catchpoint (inferior_ptid
.pid (),
145 inf_data
->total_syscalls_count
!= 0,
146 inf_data
->any_syscall_count
,
147 inf_data
->syscalls_counts
);
150 /* Implement the "breakpoint_hit" breakpoint_ops method for syscall
154 breakpoint_hit_catch_syscall (const struct bp_location
*bl
,
155 const address_space
*aspace
, CORE_ADDR bp_addr
,
156 const struct target_waitstatus
*ws
)
158 /* We must check if we are catching specific syscalls in this
159 breakpoint. If we are, then we must guarantee that the called
160 syscall is the same syscall we are catching. */
161 int syscall_number
= 0;
162 const struct syscall_catchpoint
*c
163 = (const struct syscall_catchpoint
*) bl
->owner
;
165 if (ws
->kind
!= TARGET_WAITKIND_SYSCALL_ENTRY
166 && ws
->kind
!= TARGET_WAITKIND_SYSCALL_RETURN
)
169 syscall_number
= ws
->value
.syscall_number
;
171 /* Now, checking if the syscall is the same. */
172 if (!c
->syscalls_to_be_caught
.empty ())
174 for (int iter
: c
->syscalls_to_be_caught
)
175 if (syscall_number
== iter
)
184 /* Implement the "print_it" breakpoint_ops method for syscall
187 static enum print_stop_action
188 print_it_catch_syscall (bpstat bs
)
190 struct ui_out
*uiout
= current_uiout
;
191 struct breakpoint
*b
= bs
->breakpoint_at
;
192 /* These are needed because we want to know in which state a
193 syscall is. It can be in the TARGET_WAITKIND_SYSCALL_ENTRY
194 or TARGET_WAITKIND_SYSCALL_RETURN, and depending on it we
195 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 (&ptid
, &last
);
203 get_syscall_by_number (gdbarch
, last
.value
.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_int ("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_int ("syscall-number", last
.value
.syscall_number
);
230 uiout
->field_string ("syscall-name", s
.name
);
234 return PRINT_SRC_AND_LOC
;
237 /* Implement the "print_one" breakpoint_ops method for syscall
241 print_one_catch_syscall (struct breakpoint
*b
,
242 struct bp_location
**last_loc
)
244 struct syscall_catchpoint
*c
= (struct syscall_catchpoint
*) b
;
245 struct value_print_options opts
;
246 struct ui_out
*uiout
= current_uiout
;
247 struct gdbarch
*gdbarch
= b
->loc
->gdbarch
;
249 get_user_print_options (&opts
);
250 /* Field 4, the address, is omitted (which makes the columns not
251 line up too nicely with the headers, but the effect is relatively
253 if (opts
.addressprint
)
254 uiout
->field_skip ("addr");
257 if (c
->syscalls_to_be_caught
.size () > 1)
258 uiout
->text ("syscalls \"");
260 uiout
->text ("syscall \"");
262 if (!c
->syscalls_to_be_caught
.empty ())
264 char *text
= xstrprintf ("%s", "");
266 for (int iter
: c
->syscalls_to_be_caught
)
270 get_syscall_by_number (gdbarch
, iter
, &s
);
273 text
= xstrprintf ("%s%s, ", text
, s
.name
);
275 text
= xstrprintf ("%s%d, ", text
, iter
);
277 /* We have to xfree the last 'text' (now stored at 'x')
278 because xstrprintf dynamically allocates new space for it
282 /* Remove the last comma. */
283 text
[strlen (text
) - 2] = '\0';
284 uiout
->field_string ("what", text
);
287 uiout
->field_string ("what", "<any syscall>");
290 if (uiout
->is_mi_like_p ())
291 uiout
->field_string ("catch-type", "syscall");
294 /* Implement the "print_mention" breakpoint_ops method for syscall
298 print_mention_catch_syscall (struct breakpoint
*b
)
300 struct syscall_catchpoint
*c
= (struct syscall_catchpoint
*) b
;
301 struct gdbarch
*gdbarch
= b
->loc
->gdbarch
;
303 if (!c
->syscalls_to_be_caught
.empty ())
305 if (c
->syscalls_to_be_caught
.size () > 1)
306 printf_filtered (_("Catchpoint %d (syscalls"), b
->number
);
308 printf_filtered (_("Catchpoint %d (syscall"), b
->number
);
310 for (int iter
: c
->syscalls_to_be_caught
)
313 get_syscall_by_number (gdbarch
, iter
, &s
);
316 printf_filtered (" '%s' [%d]", s
.name
, s
.number
);
318 printf_filtered (" %d", s
.number
);
320 printf_filtered (")");
323 printf_filtered (_("Catchpoint %d (any syscall)"),
327 /* Implement the "print_recreate" breakpoint_ops method for syscall
331 print_recreate_catch_syscall (struct breakpoint
*b
, struct ui_file
*fp
)
333 struct syscall_catchpoint
*c
= (struct syscall_catchpoint
*) b
;
334 struct gdbarch
*gdbarch
= b
->loc
->gdbarch
;
336 fprintf_unfiltered (fp
, "catch syscall");
338 for (int iter
: c
->syscalls_to_be_caught
)
342 get_syscall_by_number (gdbarch
, iter
, &s
);
344 fprintf_unfiltered (fp
, " %s", s
.name
);
346 fprintf_unfiltered (fp
, " %d", s
.number
);
349 print_recreate_thread (b
, fp
);
352 /* The breakpoint_ops structure to be used in syscall catchpoints. */
354 static struct breakpoint_ops catch_syscall_breakpoint_ops
;
356 /* Returns non-zero if 'b' is a syscall catchpoint. */
359 syscall_catchpoint_p (struct breakpoint
*b
)
361 return (b
->ops
== &catch_syscall_breakpoint_ops
);
365 create_syscall_event_catchpoint (int tempflag
, std::vector
<int> &&filter
,
366 const struct breakpoint_ops
*ops
)
368 struct gdbarch
*gdbarch
= get_current_arch ();
370 std::unique_ptr
<syscall_catchpoint
> c (new syscall_catchpoint ());
371 init_catchpoint (c
.get (), gdbarch
, tempflag
, NULL
, ops
);
372 c
->syscalls_to_be_caught
= std::move (filter
);
374 install_breakpoint (0, std::move (c
), 1);
377 /* Splits the argument using space as delimiter. */
379 static std::vector
<int>
380 catch_syscall_split_args (const char *arg
)
382 std::vector
<int> result
;
383 struct gdbarch
*gdbarch
= target_gdbarch ();
387 int i
, syscall_number
;
392 /* Skip whitespace. */
393 arg
= skip_spaces (arg
);
395 for (i
= 0; i
< 127 && arg
[i
] && !isspace (arg
[i
]); ++i
)
396 cur_name
[i
] = arg
[i
];
400 /* Check if the user provided a syscall name, group, or a number. */
401 syscall_number
= (int) strtol (cur_name
, &endptr
, 0);
404 get_syscall_by_number (gdbarch
, syscall_number
, &s
);
405 result
.push_back (s
.number
);
407 else if (startswith (cur_name
, "g:")
408 || startswith (cur_name
, "group:"))
410 /* We have a syscall group. Let's expand it into a syscall
411 list before inserting. */
412 const char *group_name
;
414 /* Skip over "g:" and "group:" prefix strings. */
415 group_name
= strchr (cur_name
, ':') + 1;
417 if (!get_syscalls_by_group (gdbarch
, group_name
, &result
))
418 error (_("Unknown syscall group '%s'."), group_name
);
422 /* We have a name. Let's check if it's valid and fetch a
423 list of matching numbers. */
424 if (!get_syscalls_by_name (gdbarch
, cur_name
, &result
))
425 /* Here we have to issue an error instead of a warning,
426 because GDB cannot do anything useful if there's no
427 syscall number to be caught. */
428 error (_("Unknown syscall name '%s'."), cur_name
);
435 /* Implement the "catch syscall" command. */
438 catch_syscall_command_1 (const char *arg
, int from_tty
,
439 struct cmd_list_element
*command
)
442 std::vector
<int> filter
;
444 struct gdbarch
*gdbarch
= get_current_arch ();
446 /* Checking if the feature if supported. */
447 if (gdbarch_get_syscall_number_p (gdbarch
) == 0)
448 error (_("The feature 'catch syscall' is not supported on \
449 this architecture yet."));
451 tempflag
= get_cmd_context (command
) == CATCH_TEMPORARY
;
453 arg
= skip_spaces (arg
);
455 /* We need to do this first "dummy" translation in order
456 to get the syscall XML file loaded or, most important,
457 to display a warning to the user if there's no XML file
458 for his/her architecture. */
459 get_syscall_by_number (gdbarch
, 0, &s
);
461 /* The allowed syntax is:
463 catch syscall <name | number> [<name | number> ... <name | number>]
465 Let's check if there's a syscall name. */
468 filter
= catch_syscall_split_args (arg
);
470 create_syscall_event_catchpoint (tempflag
, std::move (filter
),
471 &catch_syscall_breakpoint_ops
);
475 /* Returns 0 if 'bp' is NOT a syscall catchpoint,
476 non-zero otherwise. */
478 is_syscall_catchpoint_enabled (struct breakpoint
*bp
)
480 if (syscall_catchpoint_p (bp
)
481 && bp
->enable_state
!= bp_disabled
482 && bp
->enable_state
!= bp_call_disabled
)
489 catch_syscall_enabled (void)
491 struct catch_syscall_inferior_data
*inf_data
492 = get_catch_syscall_inferior_data (current_inferior ());
494 return inf_data
->total_syscalls_count
!= 0;
497 /* Helper function for catching_syscall_number. If B is a syscall
498 catchpoint for SYSCALL_NUMBER, return 1 (which will make
499 'breakpoint_find_if' return). Otherwise, return 0. */
502 catching_syscall_number_1 (struct breakpoint
*b
,
505 int syscall_number
= (int) (uintptr_t) data
;
507 if (is_syscall_catchpoint_enabled (b
))
509 struct syscall_catchpoint
*c
= (struct syscall_catchpoint
*) b
;
511 if (!c
->syscalls_to_be_caught
.empty ())
513 for (int iter
: c
->syscalls_to_be_caught
)
514 if (syscall_number
== iter
)
525 catching_syscall_number (int syscall_number
)
527 struct breakpoint
*b
= breakpoint_find_if (catching_syscall_number_1
,
528 (void *) (uintptr_t) syscall_number
);
533 /* Complete syscall names. Used by "catch syscall". */
536 catch_syscall_completer (struct cmd_list_element
*cmd
,
537 completion_tracker
&tracker
,
538 const char *text
, const char *word
)
540 struct gdbarch
*gdbarch
= get_current_arch ();
541 gdb::unique_xmalloc_ptr
<const char *> group_list
;
544 /* Completion considers ':' to be a word separator, so we use this to
545 verify whether the previous word was a group prefix. If so, we
546 build the completion list using group names only. */
547 for (prefix
= word
; prefix
!= text
&& prefix
[-1] != ' '; prefix
--)
550 if (startswith (prefix
, "g:") || startswith (prefix
, "group:"))
552 /* Perform completion inside 'group:' namespace only. */
553 group_list
.reset (get_syscall_group_names (gdbarch
));
554 if (group_list
!= NULL
)
555 complete_on_enum (tracker
, group_list
.get (), word
, word
);
559 /* Complete with both, syscall names and groups. */
560 gdb::unique_xmalloc_ptr
<const char *> syscall_list
561 (get_syscall_names (gdbarch
));
562 group_list
.reset (get_syscall_group_names (gdbarch
));
564 const char **group_ptr
= group_list
.get ();
566 /* Hold on to strings while we're using them. */
567 std::vector
<std::string
> holders
;
569 /* Append "group:" prefix to syscall groups. */
570 for (int i
= 0; group_ptr
[i
] != NULL
; i
++)
571 holders
.push_back (string_printf ("group:%s", group_ptr
[i
]));
573 for (int i
= 0; group_ptr
[i
] != NULL
; i
++)
574 group_ptr
[i
] = holders
[i
].c_str ();
576 if (syscall_list
!= NULL
)
577 complete_on_enum (tracker
, syscall_list
.get (), word
, word
);
578 if (group_list
!= NULL
)
579 complete_on_enum (tracker
, group_ptr
, word
, word
);
584 clear_syscall_counts (struct inferior
*inf
)
586 struct catch_syscall_inferior_data
*inf_data
587 = get_catch_syscall_inferior_data (inf
);
589 inf_data
->total_syscalls_count
= 0;
590 inf_data
->any_syscall_count
= 0;
591 inf_data
->syscalls_counts
.clear ();
595 initialize_syscall_catchpoint_ops (void)
597 struct breakpoint_ops
*ops
;
599 initialize_breakpoint_ops ();
601 /* Syscall catchpoints. */
602 ops
= &catch_syscall_breakpoint_ops
;
603 *ops
= base_breakpoint_ops
;
604 ops
->insert_location
= insert_catch_syscall
;
605 ops
->remove_location
= remove_catch_syscall
;
606 ops
->breakpoint_hit
= breakpoint_hit_catch_syscall
;
607 ops
->print_it
= print_it_catch_syscall
;
608 ops
->print_one
= print_one_catch_syscall
;
609 ops
->print_mention
= print_mention_catch_syscall
;
610 ops
->print_recreate
= print_recreate_catch_syscall
;
614 _initialize_break_catch_syscall (void)
616 initialize_syscall_catchpoint_ops ();
618 gdb::observers::inferior_exit
.attach (clear_syscall_counts
);
619 catch_syscall_inferior_data
620 = register_inferior_data_with_cleanup (NULL
,
621 catch_syscall_inferior_data_cleanup
);
623 add_catch_command ("syscall", _("\
624 Catch system calls by their names, groups and/or numbers.\n\
625 Arguments say which system calls to catch. If no arguments are given,\n\
626 every system call will be caught. Arguments, if given, should be one\n\
627 or more system call names (if your system supports that), system call\n\
628 groups or system call numbers."),
629 catch_syscall_command_1
,
630 catch_syscall_completer
,