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