1 /* Everything about syscall catchpoints, for GDB.
3 Copyright (C) 2009-2015 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"
31 #include "xml-syscall.h"
33 /* An instance of this type is used to represent a syscall catchpoint.
34 It includes a "struct breakpoint" as a kind of base class; users
35 downcast to "struct breakpoint *" when needed. A breakpoint is
36 really of this type iff its ops pointer points to
37 CATCH_SYSCALL_BREAKPOINT_OPS. */
39 struct syscall_catchpoint
42 struct breakpoint base
;
44 /* Syscall numbers used for the 'catch syscall' feature. If no
45 syscall has been specified for filtering, its value is NULL.
46 Otherwise, it holds a list of all syscalls to be caught. The
47 list elements are allocated with xmalloc. */
48 VEC(int) *syscalls_to_be_caught
;
51 /* Implement the "dtor" breakpoint_ops method for syscall
55 dtor_catch_syscall (struct breakpoint
*b
)
57 struct syscall_catchpoint
*c
= (struct syscall_catchpoint
*) b
;
59 VEC_free (int, c
->syscalls_to_be_caught
);
61 base_breakpoint_ops
.dtor (b
);
64 static const struct inferior_data
*catch_syscall_inferior_data
= NULL
;
66 struct catch_syscall_inferior_data
68 /* We keep a count of the number of times the user has requested a
69 particular syscall to be tracked, and pass this information to the
70 target. This lets capable targets implement filtering directly. */
72 /* Number of times that "any" syscall is requested. */
73 int any_syscall_count
;
75 /* Count of each system call. */
76 VEC(int) *syscalls_counts
;
78 /* This counts all syscall catch requests, so we can readily determine
79 if any catching is necessary. */
80 int total_syscalls_count
;
83 static struct catch_syscall_inferior_data
*
84 get_catch_syscall_inferior_data (struct inferior
*inf
)
86 struct catch_syscall_inferior_data
*inf_data
;
88 inf_data
= ((struct catch_syscall_inferior_data
*)
89 inferior_data (inf
, catch_syscall_inferior_data
));
92 inf_data
= XCNEW (struct catch_syscall_inferior_data
);
93 set_inferior_data (inf
, catch_syscall_inferior_data
, inf_data
);
100 catch_syscall_inferior_data_cleanup (struct inferior
*inf
, void *arg
)
106 /* Implement the "insert" breakpoint_ops method for syscall
110 insert_catch_syscall (struct bp_location
*bl
)
112 struct syscall_catchpoint
*c
= (struct syscall_catchpoint
*) bl
->owner
;
113 struct inferior
*inf
= current_inferior ();
114 struct catch_syscall_inferior_data
*inf_data
115 = get_catch_syscall_inferior_data (inf
);
117 ++inf_data
->total_syscalls_count
;
118 if (!c
->syscalls_to_be_caught
)
119 ++inf_data
->any_syscall_count
;
125 VEC_iterate (int, c
->syscalls_to_be_caught
, i
, iter
);
130 if (iter
>= VEC_length (int, inf_data
->syscalls_counts
))
132 int old_size
= VEC_length (int, inf_data
->syscalls_counts
);
133 uintptr_t vec_addr_offset
134 = old_size
* ((uintptr_t) sizeof (int));
136 VEC_safe_grow (int, inf_data
->syscalls_counts
, iter
+ 1);
137 vec_addr
= ((uintptr_t) VEC_address (int,
138 inf_data
->syscalls_counts
)
140 memset ((void *) vec_addr
, 0,
141 (iter
+ 1 - old_size
) * sizeof (int));
143 elem
= VEC_index (int, inf_data
->syscalls_counts
, iter
);
144 VEC_replace (int, inf_data
->syscalls_counts
, iter
, ++elem
);
148 return target_set_syscall_catchpoint (ptid_get_pid (inferior_ptid
),
149 inf_data
->total_syscalls_count
!= 0,
150 inf_data
->any_syscall_count
,
152 inf_data
->syscalls_counts
),
154 inf_data
->syscalls_counts
));
157 /* Implement the "remove" breakpoint_ops method for syscall
161 remove_catch_syscall (struct bp_location
*bl
)
163 struct syscall_catchpoint
*c
= (struct syscall_catchpoint
*) bl
->owner
;
164 struct inferior
*inf
= current_inferior ();
165 struct catch_syscall_inferior_data
*inf_data
166 = get_catch_syscall_inferior_data (inf
);
168 --inf_data
->total_syscalls_count
;
169 if (!c
->syscalls_to_be_caught
)
170 --inf_data
->any_syscall_count
;
176 VEC_iterate (int, c
->syscalls_to_be_caught
, i
, iter
);
180 if (iter
>= VEC_length (int, inf_data
->syscalls_counts
))
181 /* Shouldn't happen. */
183 elem
= VEC_index (int, inf_data
->syscalls_counts
, iter
);
184 VEC_replace (int, inf_data
->syscalls_counts
, iter
, --elem
);
188 return target_set_syscall_catchpoint (ptid_get_pid (inferior_ptid
),
189 inf_data
->total_syscalls_count
!= 0,
190 inf_data
->any_syscall_count
,
192 inf_data
->syscalls_counts
),
194 inf_data
->syscalls_counts
));
197 /* Implement the "breakpoint_hit" breakpoint_ops method for syscall
201 breakpoint_hit_catch_syscall (const struct bp_location
*bl
,
202 struct address_space
*aspace
, CORE_ADDR bp_addr
,
203 const struct target_waitstatus
*ws
)
205 /* We must check if we are catching specific syscalls in this
206 breakpoint. If we are, then we must guarantee that the called
207 syscall is the same syscall we are catching. */
208 int syscall_number
= 0;
209 const struct syscall_catchpoint
*c
210 = (const struct syscall_catchpoint
*) bl
->owner
;
212 if (ws
->kind
!= TARGET_WAITKIND_SYSCALL_ENTRY
213 && ws
->kind
!= TARGET_WAITKIND_SYSCALL_RETURN
)
216 syscall_number
= ws
->value
.syscall_number
;
218 /* Now, checking if the syscall is the same. */
219 if (c
->syscalls_to_be_caught
)
224 VEC_iterate (int, c
->syscalls_to_be_caught
, i
, iter
);
226 if (syscall_number
== iter
)
235 /* Implement the "print_it" breakpoint_ops method for syscall
238 static enum print_stop_action
239 print_it_catch_syscall (bpstat bs
)
241 struct ui_out
*uiout
= current_uiout
;
242 struct breakpoint
*b
= bs
->breakpoint_at
;
243 /* These are needed because we want to know in which state a
244 syscall is. It can be in the TARGET_WAITKIND_SYSCALL_ENTRY
245 or TARGET_WAITKIND_SYSCALL_RETURN, and depending on it we
246 must print "called syscall" or "returned from syscall". */
248 struct target_waitstatus last
;
250 struct gdbarch
*gdbarch
= bs
->bp_location_at
->gdbarch
;
252 get_last_target_status (&ptid
, &last
);
254 get_syscall_by_number (gdbarch
, last
.value
.syscall_number
, &s
);
256 annotate_catchpoint (b
->number
);
258 if (b
->disposition
== disp_del
)
259 ui_out_text (uiout
, "\nTemporary catchpoint ");
261 ui_out_text (uiout
, "\nCatchpoint ");
262 if (ui_out_is_mi_like_p (uiout
))
264 ui_out_field_string (uiout
, "reason",
265 async_reason_lookup (last
.kind
== TARGET_WAITKIND_SYSCALL_ENTRY
266 ? EXEC_ASYNC_SYSCALL_ENTRY
267 : EXEC_ASYNC_SYSCALL_RETURN
));
268 ui_out_field_string (uiout
, "disp", bpdisp_text (b
->disposition
));
270 ui_out_field_int (uiout
, "bkptno", b
->number
);
272 if (last
.kind
== TARGET_WAITKIND_SYSCALL_ENTRY
)
273 ui_out_text (uiout
, " (call to syscall ");
275 ui_out_text (uiout
, " (returned from syscall ");
277 if (s
.name
== NULL
|| ui_out_is_mi_like_p (uiout
))
278 ui_out_field_int (uiout
, "syscall-number", last
.value
.syscall_number
);
280 ui_out_field_string (uiout
, "syscall-name", s
.name
);
282 ui_out_text (uiout
, "), ");
284 return PRINT_SRC_AND_LOC
;
287 /* Implement the "print_one" breakpoint_ops method for syscall
291 print_one_catch_syscall (struct breakpoint
*b
,
292 struct bp_location
**last_loc
)
294 struct syscall_catchpoint
*c
= (struct syscall_catchpoint
*) b
;
295 struct value_print_options opts
;
296 struct ui_out
*uiout
= current_uiout
;
297 struct gdbarch
*gdbarch
= b
->loc
->gdbarch
;
299 get_user_print_options (&opts
);
300 /* Field 4, the address, is omitted (which makes the columns not
301 line up too nicely with the headers, but the effect is relatively
303 if (opts
.addressprint
)
304 ui_out_field_skip (uiout
, "addr");
307 if (c
->syscalls_to_be_caught
308 && VEC_length (int, c
->syscalls_to_be_caught
) > 1)
309 ui_out_text (uiout
, "syscalls \"");
311 ui_out_text (uiout
, "syscall \"");
313 if (c
->syscalls_to_be_caught
)
316 char *text
= xstrprintf ("%s", "");
319 VEC_iterate (int, c
->syscalls_to_be_caught
, i
, iter
);
324 get_syscall_by_number (gdbarch
, iter
, &s
);
327 text
= xstrprintf ("%s%s, ", text
, s
.name
);
329 text
= xstrprintf ("%s%d, ", text
, iter
);
331 /* We have to xfree the last 'text' (now stored at 'x')
332 because xstrprintf dynamically allocates new space for it
336 /* Remove the last comma. */
337 text
[strlen (text
) - 2] = '\0';
338 ui_out_field_string (uiout
, "what", text
);
341 ui_out_field_string (uiout
, "what", "<any syscall>");
342 ui_out_text (uiout
, "\" ");
344 if (ui_out_is_mi_like_p (uiout
))
345 ui_out_field_string (uiout
, "catch-type", "syscall");
348 /* Implement the "print_mention" breakpoint_ops method for syscall
352 print_mention_catch_syscall (struct breakpoint
*b
)
354 struct syscall_catchpoint
*c
= (struct syscall_catchpoint
*) b
;
355 struct gdbarch
*gdbarch
= b
->loc
->gdbarch
;
357 if (c
->syscalls_to_be_caught
)
361 if (VEC_length (int, c
->syscalls_to_be_caught
) > 1)
362 printf_filtered (_("Catchpoint %d (syscalls"), b
->number
);
364 printf_filtered (_("Catchpoint %d (syscall"), b
->number
);
367 VEC_iterate (int, c
->syscalls_to_be_caught
, i
, iter
);
371 get_syscall_by_number (gdbarch
, iter
, &s
);
374 printf_filtered (" '%s' [%d]", s
.name
, s
.number
);
376 printf_filtered (" %d", s
.number
);
378 printf_filtered (")");
381 printf_filtered (_("Catchpoint %d (any syscall)"),
385 /* Implement the "print_recreate" breakpoint_ops method for syscall
389 print_recreate_catch_syscall (struct breakpoint
*b
, struct ui_file
*fp
)
391 struct syscall_catchpoint
*c
= (struct syscall_catchpoint
*) b
;
392 struct gdbarch
*gdbarch
= b
->loc
->gdbarch
;
394 fprintf_unfiltered (fp
, "catch syscall");
396 if (c
->syscalls_to_be_caught
)
401 VEC_iterate (int, c
->syscalls_to_be_caught
, i
, iter
);
406 get_syscall_by_number (gdbarch
, iter
, &s
);
408 fprintf_unfiltered (fp
, " %s", s
.name
);
410 fprintf_unfiltered (fp
, " %d", s
.number
);
413 print_recreate_thread (b
, fp
);
416 /* The breakpoint_ops structure to be used in syscall catchpoints. */
418 static struct breakpoint_ops catch_syscall_breakpoint_ops
;
420 /* Returns non-zero if 'b' is a syscall catchpoint. */
423 syscall_catchpoint_p (struct breakpoint
*b
)
425 return (b
->ops
== &catch_syscall_breakpoint_ops
);
429 create_syscall_event_catchpoint (int tempflag
, VEC(int) *filter
,
430 const struct breakpoint_ops
*ops
)
432 struct syscall_catchpoint
*c
;
433 struct gdbarch
*gdbarch
= get_current_arch ();
435 c
= XNEW (struct syscall_catchpoint
);
436 init_catchpoint (&c
->base
, gdbarch
, tempflag
, NULL
, ops
);
437 c
->syscalls_to_be_caught
= filter
;
439 install_breakpoint (0, &c
->base
, 1);
442 /* Splits the argument using space as delimiter. Returns an xmalloc'd
443 filter list, or NULL if no filtering is required. */
445 catch_syscall_split_args (char *arg
)
447 VEC(int) *result
= NULL
;
448 struct cleanup
*cleanup
= make_cleanup (VEC_cleanup (int), &result
);
449 struct gdbarch
*gdbarch
= target_gdbarch ();
453 int i
, syscall_number
;
458 /* Skip whitespace. */
459 arg
= skip_spaces (arg
);
461 for (i
= 0; i
< 127 && arg
[i
] && !isspace (arg
[i
]); ++i
)
462 cur_name
[i
] = arg
[i
];
466 /* Check if the user provided a syscall name or a number. */
467 syscall_number
= (int) strtol (cur_name
, &endptr
, 0);
469 get_syscall_by_number (gdbarch
, syscall_number
, &s
);
472 /* We have a name. Let's check if it's valid and convert it
474 get_syscall_by_name (gdbarch
, cur_name
, &s
);
476 if (s
.number
== UNKNOWN_SYSCALL
)
477 /* Here we have to issue an error instead of a warning,
478 because GDB cannot do anything useful if there's no
479 syscall number to be caught. */
480 error (_("Unknown syscall name '%s'."), cur_name
);
483 /* Ok, it's valid. */
484 VEC_safe_push (int, result
, s
.number
);
487 discard_cleanups (cleanup
);
491 /* Implement the "catch syscall" command. */
494 catch_syscall_command_1 (char *arg
, int from_tty
,
495 struct cmd_list_element
*command
)
500 struct gdbarch
*gdbarch
= get_current_arch ();
502 /* Checking if the feature if supported. */
503 if (gdbarch_get_syscall_number_p (gdbarch
) == 0)
504 error (_("The feature 'catch syscall' is not supported on \
505 this architecture yet."));
507 tempflag
= get_cmd_context (command
) == CATCH_TEMPORARY
;
509 arg
= skip_spaces (arg
);
511 /* We need to do this first "dummy" translation in order
512 to get the syscall XML file loaded or, most important,
513 to display a warning to the user if there's no XML file
514 for his/her architecture. */
515 get_syscall_by_number (gdbarch
, 0, &s
);
517 /* The allowed syntax is:
519 catch syscall <name | number> [<name | number> ... <name | number>]
521 Let's check if there's a syscall name. */
524 filter
= catch_syscall_split_args (arg
);
528 create_syscall_event_catchpoint (tempflag
, filter
,
529 &catch_syscall_breakpoint_ops
);
533 /* Returns 0 if 'bp' is NOT a syscall catchpoint,
534 non-zero otherwise. */
536 is_syscall_catchpoint_enabled (struct breakpoint
*bp
)
538 if (syscall_catchpoint_p (bp
)
539 && bp
->enable_state
!= bp_disabled
540 && bp
->enable_state
!= bp_call_disabled
)
547 catch_syscall_enabled (void)
549 struct catch_syscall_inferior_data
*inf_data
550 = get_catch_syscall_inferior_data (current_inferior ());
552 return inf_data
->total_syscalls_count
!= 0;
555 /* Helper function for catching_syscall_number. If B is a syscall
556 catchpoint for SYSCALL_NUMBER, return 1 (which will make
557 'breakpoint_find_if' return). Otherwise, return 0. */
560 catching_syscall_number_1 (struct breakpoint
*b
,
563 int syscall_number
= (int) (uintptr_t) data
;
565 if (is_syscall_catchpoint_enabled (b
))
567 struct syscall_catchpoint
*c
= (struct syscall_catchpoint
*) b
;
569 if (c
->syscalls_to_be_caught
)
573 VEC_iterate (int, c
->syscalls_to_be_caught
, i
, iter
);
575 if (syscall_number
== iter
)
586 catching_syscall_number (int syscall_number
)
588 struct breakpoint
*b
= breakpoint_find_if (catching_syscall_number_1
,
589 (void *) (uintptr_t) syscall_number
);
594 /* Complete syscall names. Used by "catch syscall". */
595 static VEC (char_ptr
) *
596 catch_syscall_completer (struct cmd_list_element
*cmd
,
597 const char *text
, const char *word
)
599 const char **list
= get_syscall_names (get_current_arch ());
600 VEC (char_ptr
) *retlist
601 = (list
== NULL
) ? NULL
: complete_on_enum (list
, word
, word
);
608 clear_syscall_counts (struct inferior
*inf
)
610 struct catch_syscall_inferior_data
*inf_data
611 = get_catch_syscall_inferior_data (inf
);
613 inf_data
->total_syscalls_count
= 0;
614 inf_data
->any_syscall_count
= 0;
615 VEC_free (int, inf_data
->syscalls_counts
);
619 initialize_syscall_catchpoint_ops (void)
621 struct breakpoint_ops
*ops
;
623 initialize_breakpoint_ops ();
625 /* Syscall catchpoints. */
626 ops
= &catch_syscall_breakpoint_ops
;
627 *ops
= base_breakpoint_ops
;
628 ops
->dtor
= dtor_catch_syscall
;
629 ops
->insert_location
= insert_catch_syscall
;
630 ops
->remove_location
= remove_catch_syscall
;
631 ops
->breakpoint_hit
= breakpoint_hit_catch_syscall
;
632 ops
->print_it
= print_it_catch_syscall
;
633 ops
->print_one
= print_one_catch_syscall
;
634 ops
->print_mention
= print_mention_catch_syscall
;
635 ops
->print_recreate
= print_recreate_catch_syscall
;
638 initialize_file_ftype _initialize_break_catch_syscall
;
641 _initialize_break_catch_syscall (void)
643 initialize_syscall_catchpoint_ops ();
645 observer_attach_inferior_exit (clear_syscall_counts
);
646 catch_syscall_inferior_data
647 = register_inferior_data_with_cleanup (NULL
,
648 catch_syscall_inferior_data_cleanup
);
650 add_catch_command ("syscall", _("\
651 Catch system calls by their names and/or numbers.\n\
652 Arguments say which system calls to catch. If no arguments\n\
653 are given, every system call will be caught.\n\
654 Arguments, if given, should be one or more system call names\n\
655 (if your system supports that), or system call numbers."),
656 catch_syscall_command_1
,
657 catch_syscall_completer
,