[ARC] Fix typo in extension instruction name.
[deliverable/binutils-gdb.git] / gdb / break-catch-syscall.c
CommitLineData
10304ef3
SDJ
1/* Everything about syscall catchpoints, for GDB.
2
618f726f 3 Copyright (C) 2009-2016 Free Software Foundation, Inc.
10304ef3
SDJ
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 "observer.h"
31#include "xml-syscall.h"
32
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. */
38
39struct syscall_catchpoint
40{
41 /* The base class. */
42 struct breakpoint base;
43
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;
49};
50
51/* Implement the "dtor" breakpoint_ops method for syscall
52 catchpoints. */
53
54static void
55dtor_catch_syscall (struct breakpoint *b)
56{
57 struct syscall_catchpoint *c = (struct syscall_catchpoint *) b;
58
59 VEC_free (int, c->syscalls_to_be_caught);
60
61 base_breakpoint_ops.dtor (b);
62}
63
64static const struct inferior_data *catch_syscall_inferior_data = NULL;
65
66struct catch_syscall_inferior_data
67{
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. */
71
72 /* Number of times that "any" syscall is requested. */
73 int any_syscall_count;
74
75 /* Count of each system call. */
76 VEC(int) *syscalls_counts;
77
78 /* This counts all syscall catch requests, so we can readily determine
79 if any catching is necessary. */
80 int total_syscalls_count;
81};
82
83static struct catch_syscall_inferior_data*
84get_catch_syscall_inferior_data (struct inferior *inf)
85{
86 struct catch_syscall_inferior_data *inf_data;
87
9a3c8263
SM
88 inf_data = ((struct catch_syscall_inferior_data *)
89 inferior_data (inf, catch_syscall_inferior_data));
10304ef3
SDJ
90 if (inf_data == NULL)
91 {
92 inf_data = XCNEW (struct catch_syscall_inferior_data);
93 set_inferior_data (inf, catch_syscall_inferior_data, inf_data);
94 }
95
96 return inf_data;
97}
98
99static void
100catch_syscall_inferior_data_cleanup (struct inferior *inf, void *arg)
101{
102 xfree (arg);
103}
104
105
106/* Implement the "insert" breakpoint_ops method for syscall
107 catchpoints. */
108
109static int
110insert_catch_syscall (struct bp_location *bl)
111{
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);
116
117 ++inf_data->total_syscalls_count;
118 if (!c->syscalls_to_be_caught)
119 ++inf_data->any_syscall_count;
120 else
121 {
122 int i, iter;
123
124 for (i = 0;
125 VEC_iterate (int, c->syscalls_to_be_caught, i, iter);
126 i++)
127 {
128 int elem;
129
130 if (iter >= VEC_length (int, inf_data->syscalls_counts))
131 {
132 int old_size = VEC_length (int, inf_data->syscalls_counts);
133 uintptr_t vec_addr_offset
134 = old_size * ((uintptr_t) sizeof (int));
135 uintptr_t vec_addr;
136 VEC_safe_grow (int, inf_data->syscalls_counts, iter + 1);
137 vec_addr = ((uintptr_t) VEC_address (int,
138 inf_data->syscalls_counts)
139 + vec_addr_offset);
140 memset ((void *) vec_addr, 0,
141 (iter + 1 - old_size) * sizeof (int));
142 }
143 elem = VEC_index (int, inf_data->syscalls_counts, iter);
144 VEC_replace (int, inf_data->syscalls_counts, iter, ++elem);
145 }
146 }
147
148 return target_set_syscall_catchpoint (ptid_get_pid (inferior_ptid),
149 inf_data->total_syscalls_count != 0,
150 inf_data->any_syscall_count,
151 VEC_length (int,
152 inf_data->syscalls_counts),
153 VEC_address (int,
154 inf_data->syscalls_counts));
155}
156
157/* Implement the "remove" breakpoint_ops method for syscall
158 catchpoints. */
159
160static int
161remove_catch_syscall (struct bp_location *bl)
162{
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);
167
168 --inf_data->total_syscalls_count;
169 if (!c->syscalls_to_be_caught)
170 --inf_data->any_syscall_count;
171 else
172 {
173 int i, iter;
174
175 for (i = 0;
176 VEC_iterate (int, c->syscalls_to_be_caught, i, iter);
177 i++)
178 {
179 int elem;
180 if (iter >= VEC_length (int, inf_data->syscalls_counts))
181 /* Shouldn't happen. */
182 continue;
183 elem = VEC_index (int, inf_data->syscalls_counts, iter);
184 VEC_replace (int, inf_data->syscalls_counts, iter, --elem);
185 }
186 }
187
188 return target_set_syscall_catchpoint (ptid_get_pid (inferior_ptid),
189 inf_data->total_syscalls_count != 0,
190 inf_data->any_syscall_count,
191 VEC_length (int,
192 inf_data->syscalls_counts),
193 VEC_address (int,
194 inf_data->syscalls_counts));
195}
196
197/* Implement the "breakpoint_hit" breakpoint_ops method for syscall
198 catchpoints. */
199
200static int
201breakpoint_hit_catch_syscall (const struct bp_location *bl,
202 struct address_space *aspace, CORE_ADDR bp_addr,
203 const struct target_waitstatus *ws)
204{
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;
211
212 if (ws->kind != TARGET_WAITKIND_SYSCALL_ENTRY
213 && ws->kind != TARGET_WAITKIND_SYSCALL_RETURN)
214 return 0;
215
216 syscall_number = ws->value.syscall_number;
217
218 /* Now, checking if the syscall is the same. */
219 if (c->syscalls_to_be_caught)
220 {
221 int i, iter;
222
223 for (i = 0;
224 VEC_iterate (int, c->syscalls_to_be_caught, i, iter);
225 i++)
226 if (syscall_number == iter)
227 return 1;
228
229 return 0;
230 }
231
232 return 1;
233}
234
235/* Implement the "print_it" breakpoint_ops method for syscall
236 catchpoints. */
237
238static enum print_stop_action
239print_it_catch_syscall (bpstat bs)
240{
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". */
247 ptid_t ptid;
248 struct target_waitstatus last;
249 struct syscall s;
250 struct gdbarch *gdbarch = bs->bp_location_at->gdbarch;
251
252 get_last_target_status (&ptid, &last);
253
254 get_syscall_by_number (gdbarch, last.value.syscall_number, &s);
255
256 annotate_catchpoint (b->number);
f303dbd6 257 maybe_print_thread_hit_breakpoint (uiout);
10304ef3
SDJ
258
259 if (b->disposition == disp_del)
f303dbd6 260 ui_out_text (uiout, "Temporary catchpoint ");
10304ef3 261 else
f303dbd6 262 ui_out_text (uiout, "Catchpoint ");
10304ef3
SDJ
263 if (ui_out_is_mi_like_p (uiout))
264 {
265 ui_out_field_string (uiout, "reason",
266 async_reason_lookup (last.kind == TARGET_WAITKIND_SYSCALL_ENTRY
267 ? EXEC_ASYNC_SYSCALL_ENTRY
268 : EXEC_ASYNC_SYSCALL_RETURN));
269 ui_out_field_string (uiout, "disp", bpdisp_text (b->disposition));
270 }
271 ui_out_field_int (uiout, "bkptno", b->number);
272
273 if (last.kind == TARGET_WAITKIND_SYSCALL_ENTRY)
274 ui_out_text (uiout, " (call to syscall ");
275 else
276 ui_out_text (uiout, " (returned from syscall ");
277
278 if (s.name == NULL || ui_out_is_mi_like_p (uiout))
279 ui_out_field_int (uiout, "syscall-number", last.value.syscall_number);
280 if (s.name != NULL)
281 ui_out_field_string (uiout, "syscall-name", s.name);
282
283 ui_out_text (uiout, "), ");
284
285 return PRINT_SRC_AND_LOC;
286}
287
288/* Implement the "print_one" breakpoint_ops method for syscall
289 catchpoints. */
290
291static void
292print_one_catch_syscall (struct breakpoint *b,
293 struct bp_location **last_loc)
294{
295 struct syscall_catchpoint *c = (struct syscall_catchpoint *) b;
296 struct value_print_options opts;
297 struct ui_out *uiout = current_uiout;
298 struct gdbarch *gdbarch = b->loc->gdbarch;
299
300 get_user_print_options (&opts);
301 /* Field 4, the address, is omitted (which makes the columns not
302 line up too nicely with the headers, but the effect is relatively
303 readable). */
304 if (opts.addressprint)
305 ui_out_field_skip (uiout, "addr");
306 annotate_field (5);
307
308 if (c->syscalls_to_be_caught
309 && VEC_length (int, c->syscalls_to_be_caught) > 1)
310 ui_out_text (uiout, "syscalls \"");
311 else
312 ui_out_text (uiout, "syscall \"");
313
314 if (c->syscalls_to_be_caught)
315 {
316 int i, iter;
317 char *text = xstrprintf ("%s", "");
318
319 for (i = 0;
320 VEC_iterate (int, c->syscalls_to_be_caught, i, iter);
321 i++)
322 {
323 char *x = text;
324 struct syscall s;
325 get_syscall_by_number (gdbarch, iter, &s);
326
327 if (s.name != NULL)
328 text = xstrprintf ("%s%s, ", text, s.name);
329 else
330 text = xstrprintf ("%s%d, ", text, iter);
331
332 /* We have to xfree the last 'text' (now stored at 'x')
333 because xstrprintf dynamically allocates new space for it
334 on every call. */
335 xfree (x);
336 }
337 /* Remove the last comma. */
338 text[strlen (text) - 2] = '\0';
339 ui_out_field_string (uiout, "what", text);
340 }
341 else
342 ui_out_field_string (uiout, "what", "<any syscall>");
343 ui_out_text (uiout, "\" ");
344
345 if (ui_out_is_mi_like_p (uiout))
346 ui_out_field_string (uiout, "catch-type", "syscall");
347}
348
349/* Implement the "print_mention" breakpoint_ops method for syscall
350 catchpoints. */
351
352static void
353print_mention_catch_syscall (struct breakpoint *b)
354{
355 struct syscall_catchpoint *c = (struct syscall_catchpoint *) b;
356 struct gdbarch *gdbarch = b->loc->gdbarch;
357
358 if (c->syscalls_to_be_caught)
359 {
360 int i, iter;
361
362 if (VEC_length (int, c->syscalls_to_be_caught) > 1)
363 printf_filtered (_("Catchpoint %d (syscalls"), b->number);
364 else
365 printf_filtered (_("Catchpoint %d (syscall"), b->number);
366
367 for (i = 0;
368 VEC_iterate (int, c->syscalls_to_be_caught, i, iter);
369 i++)
370 {
371 struct syscall s;
372 get_syscall_by_number (gdbarch, iter, &s);
373
374 if (s.name)
375 printf_filtered (" '%s' [%d]", s.name, s.number);
376 else
377 printf_filtered (" %d", s.number);
378 }
379 printf_filtered (")");
380 }
381 else
382 printf_filtered (_("Catchpoint %d (any syscall)"),
383 b->number);
384}
385
386/* Implement the "print_recreate" breakpoint_ops method for syscall
387 catchpoints. */
388
389static void
390print_recreate_catch_syscall (struct breakpoint *b, struct ui_file *fp)
391{
392 struct syscall_catchpoint *c = (struct syscall_catchpoint *) b;
393 struct gdbarch *gdbarch = b->loc->gdbarch;
394
395 fprintf_unfiltered (fp, "catch syscall");
396
397 if (c->syscalls_to_be_caught)
398 {
399 int i, iter;
400
401 for (i = 0;
402 VEC_iterate (int, c->syscalls_to_be_caught, i, iter);
403 i++)
404 {
405 struct syscall s;
406
407 get_syscall_by_number (gdbarch, iter, &s);
408 if (s.name)
409 fprintf_unfiltered (fp, " %s", s.name);
410 else
411 fprintf_unfiltered (fp, " %d", s.number);
412 }
413 }
414 print_recreate_thread (b, fp);
415}
416
417/* The breakpoint_ops structure to be used in syscall catchpoints. */
418
419static struct breakpoint_ops catch_syscall_breakpoint_ops;
420
421/* Returns non-zero if 'b' is a syscall catchpoint. */
422
423static int
424syscall_catchpoint_p (struct breakpoint *b)
425{
426 return (b->ops == &catch_syscall_breakpoint_ops);
427}
428
429static void
430create_syscall_event_catchpoint (int tempflag, VEC(int) *filter,
431 const struct breakpoint_ops *ops)
432{
433 struct syscall_catchpoint *c;
434 struct gdbarch *gdbarch = get_current_arch ();
435
436 c = XNEW (struct syscall_catchpoint);
437 init_catchpoint (&c->base, gdbarch, tempflag, NULL, ops);
438 c->syscalls_to_be_caught = filter;
439
440 install_breakpoint (0, &c->base, 1);
441}
442
443/* Splits the argument using space as delimiter. Returns an xmalloc'd
444 filter list, or NULL if no filtering is required. */
445static VEC(int) *
446catch_syscall_split_args (char *arg)
447{
448 VEC(int) *result = NULL;
449 struct cleanup *cleanup = make_cleanup (VEC_cleanup (int), &result);
450 struct gdbarch *gdbarch = target_gdbarch ();
451
452 while (*arg != '\0')
453 {
454 int i, syscall_number;
455 char *endptr;
456 char cur_name[128];
457 struct syscall s;
458
459 /* Skip whitespace. */
460 arg = skip_spaces (arg);
461
462 for (i = 0; i < 127 && arg[i] && !isspace (arg[i]); ++i)
463 cur_name[i] = arg[i];
464 cur_name[i] = '\0';
465 arg += i;
466
467 /* Check if the user provided a syscall name or a number. */
468 syscall_number = (int) strtol (cur_name, &endptr, 0);
469 if (*endptr == '\0')
470 get_syscall_by_number (gdbarch, syscall_number, &s);
471 else
472 {
473 /* We have a name. Let's check if it's valid and convert it
474 to a number. */
475 get_syscall_by_name (gdbarch, cur_name, &s);
476
477 if (s.number == UNKNOWN_SYSCALL)
478 /* Here we have to issue an error instead of a warning,
479 because GDB cannot do anything useful if there's no
480 syscall number to be caught. */
481 error (_("Unknown syscall name '%s'."), cur_name);
482 }
483
484 /* Ok, it's valid. */
485 VEC_safe_push (int, result, s.number);
486 }
487
488 discard_cleanups (cleanup);
489 return result;
490}
491
492/* Implement the "catch syscall" command. */
493
494static void
495catch_syscall_command_1 (char *arg, int from_tty,
496 struct cmd_list_element *command)
497{
498 int tempflag;
499 VEC(int) *filter;
500 struct syscall s;
501 struct gdbarch *gdbarch = get_current_arch ();
502
503 /* Checking if the feature if supported. */
504 if (gdbarch_get_syscall_number_p (gdbarch) == 0)
505 error (_("The feature 'catch syscall' is not supported on \
506this architecture yet."));
507
508 tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
509
510 arg = skip_spaces (arg);
511
512 /* We need to do this first "dummy" translation in order
513 to get the syscall XML file loaded or, most important,
514 to display a warning to the user if there's no XML file
515 for his/her architecture. */
516 get_syscall_by_number (gdbarch, 0, &s);
517
518 /* The allowed syntax is:
519 catch syscall
520 catch syscall <name | number> [<name | number> ... <name | number>]
521
522 Let's check if there's a syscall name. */
523
524 if (arg != NULL)
525 filter = catch_syscall_split_args (arg);
526 else
527 filter = NULL;
528
529 create_syscall_event_catchpoint (tempflag, filter,
530 &catch_syscall_breakpoint_ops);
531}
532
533
534/* Returns 0 if 'bp' is NOT a syscall catchpoint,
535 non-zero otherwise. */
536static int
537is_syscall_catchpoint_enabled (struct breakpoint *bp)
538{
539 if (syscall_catchpoint_p (bp)
540 && bp->enable_state != bp_disabled
541 && bp->enable_state != bp_call_disabled)
542 return 1;
543 else
544 return 0;
545}
546
547int
548catch_syscall_enabled (void)
549{
550 struct catch_syscall_inferior_data *inf_data
551 = get_catch_syscall_inferior_data (current_inferior ());
552
553 return inf_data->total_syscalls_count != 0;
554}
555
556/* Helper function for catching_syscall_number. If B is a syscall
557 catchpoint for SYSCALL_NUMBER, return 1 (which will make
558 'breakpoint_find_if' return). Otherwise, return 0. */
559
560static int
561catching_syscall_number_1 (struct breakpoint *b,
562 void *data)
563{
564 int syscall_number = (int) (uintptr_t) data;
565
566 if (is_syscall_catchpoint_enabled (b))
567 {
568 struct syscall_catchpoint *c = (struct syscall_catchpoint *) b;
569
570 if (c->syscalls_to_be_caught)
571 {
572 int i, iter;
573 for (i = 0;
574 VEC_iterate (int, c->syscalls_to_be_caught, i, iter);
575 i++)
576 if (syscall_number == iter)
577 return 1;
578 }
579 else
580 return 1;
581 }
582
583 return 0;
584}
585
586int
587catching_syscall_number (int syscall_number)
588{
589 struct breakpoint *b = breakpoint_find_if (catching_syscall_number_1,
590 (void *) (uintptr_t) syscall_number);
591
592 return b != NULL;
593}
594
595/* Complete syscall names. Used by "catch syscall". */
596static VEC (char_ptr) *
597catch_syscall_completer (struct cmd_list_element *cmd,
598 const char *text, const char *word)
599{
600 const char **list = get_syscall_names (get_current_arch ());
601 VEC (char_ptr) *retlist
602 = (list == NULL) ? NULL : complete_on_enum (list, word, word);
603
604 xfree (list);
605 return retlist;
606}
607
608static void
609clear_syscall_counts (struct inferior *inf)
610{
611 struct catch_syscall_inferior_data *inf_data
612 = get_catch_syscall_inferior_data (inf);
613
614 inf_data->total_syscalls_count = 0;
615 inf_data->any_syscall_count = 0;
616 VEC_free (int, inf_data->syscalls_counts);
617}
618
619static void
620initialize_syscall_catchpoint_ops (void)
621{
622 struct breakpoint_ops *ops;
623
624 initialize_breakpoint_ops ();
625
626 /* Syscall catchpoints. */
627 ops = &catch_syscall_breakpoint_ops;
628 *ops = base_breakpoint_ops;
629 ops->dtor = dtor_catch_syscall;
630 ops->insert_location = insert_catch_syscall;
631 ops->remove_location = remove_catch_syscall;
632 ops->breakpoint_hit = breakpoint_hit_catch_syscall;
633 ops->print_it = print_it_catch_syscall;
634 ops->print_one = print_one_catch_syscall;
635 ops->print_mention = print_mention_catch_syscall;
636 ops->print_recreate = print_recreate_catch_syscall;
637}
638
639initialize_file_ftype _initialize_break_catch_syscall;
640
641void
642_initialize_break_catch_syscall (void)
643{
644 initialize_syscall_catchpoint_ops ();
645
646 observer_attach_inferior_exit (clear_syscall_counts);
647 catch_syscall_inferior_data
648 = register_inferior_data_with_cleanup (NULL,
649 catch_syscall_inferior_data_cleanup);
650
651 add_catch_command ("syscall", _("\
652Catch system calls by their names and/or numbers.\n\
653Arguments say which system calls to catch. If no arguments\n\
654are given, every system call will be caught.\n\
655Arguments, if given, should be one or more system call names\n\
656(if your system supports that), or system call numbers."),
657 catch_syscall_command_1,
658 catch_syscall_completer,
659 CATCH_PERMANENT,
660 CATCH_TEMPORARY);
661}
This page took 0.115551 seconds and 4 git commands to generate.