]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/break-catch-syscall.c
Class-ify ui_out
[thirdparty/binutils-gdb.git] / gdb / break-catch-syscall.c
1 /* Everything about syscall catchpoints, for GDB.
2
3 Copyright (C) 2009-2016 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 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
39 struct 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
54 static void
55 dtor_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
64 static const struct inferior_data *catch_syscall_inferior_data = NULL;
65
66 struct 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
83 static struct catch_syscall_inferior_data*
84 get_catch_syscall_inferior_data (struct inferior *inf)
85 {
86 struct catch_syscall_inferior_data *inf_data;
87
88 inf_data = ((struct catch_syscall_inferior_data *)
89 inferior_data (inf, catch_syscall_inferior_data));
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
99 static void
100 catch_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
109 static int
110 insert_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
160 static int
161 remove_catch_syscall (struct bp_location *bl, enum remove_bp_reason reason)
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
200 static int
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)
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
238 static enum print_stop_action
239 print_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);
257 maybe_print_thread_hit_breakpoint (uiout);
258
259 if (b->disposition == disp_del)
260 uiout->text ("Temporary catchpoint ");
261 else
262 uiout->text ("Catchpoint ");
263 if (uiout->is_mi_like_p ())
264 {
265 uiout->field_string ("reason",
266 async_reason_lookup (last.kind == TARGET_WAITKIND_SYSCALL_ENTRY
267 ? EXEC_ASYNC_SYSCALL_ENTRY
268 : EXEC_ASYNC_SYSCALL_RETURN));
269 uiout->field_string ("disp", bpdisp_text (b->disposition));
270 }
271 uiout->field_int ("bkptno", b->number);
272
273 if (last.kind == TARGET_WAITKIND_SYSCALL_ENTRY)
274 uiout->text (" (call to syscall ");
275 else
276 uiout->text (" (returned from syscall ");
277
278 if (s.name == NULL || uiout->is_mi_like_p ())
279 uiout->field_int ("syscall-number", last.value.syscall_number);
280 if (s.name != NULL)
281 uiout->field_string ("syscall-name", s.name);
282
283 uiout->text ("), ");
284
285 return PRINT_SRC_AND_LOC;
286 }
287
288 /* Implement the "print_one" breakpoint_ops method for syscall
289 catchpoints. */
290
291 static void
292 print_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 uiout->field_skip ("addr");
306 annotate_field (5);
307
308 if (c->syscalls_to_be_caught
309 && VEC_length (int, c->syscalls_to_be_caught) > 1)
310 uiout->text ("syscalls \"");
311 else
312 uiout->text ("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 uiout->field_string ("what", text);
340 }
341 else
342 uiout->field_string ("what", "<any syscall>");
343 uiout->text ("\" ");
344
345 if (uiout->is_mi_like_p ())
346 uiout->field_string ("catch-type", "syscall");
347 }
348
349 /* Implement the "print_mention" breakpoint_ops method for syscall
350 catchpoints. */
351
352 static void
353 print_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
389 static void
390 print_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
419 static struct breakpoint_ops catch_syscall_breakpoint_ops;
420
421 /* Returns non-zero if 'b' is a syscall catchpoint. */
422
423 static int
424 syscall_catchpoint_p (struct breakpoint *b)
425 {
426 return (b->ops == &catch_syscall_breakpoint_ops);
427 }
428
429 static void
430 create_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 = new 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. */
445 static VEC(int) *
446 catch_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, group, or a number. */
468 syscall_number = (int) strtol (cur_name, &endptr, 0);
469 if (*endptr == '\0')
470 {
471 get_syscall_by_number (gdbarch, syscall_number, &s);
472 VEC_safe_push (int, result, s.number);
473 }
474 else if (startswith (cur_name, "g:")
475 || startswith (cur_name, "group:"))
476 {
477 /* We have a syscall group. Let's expand it into a syscall
478 list before inserting. */
479 struct syscall *syscall_list;
480 const char *group_name;
481
482 /* Skip over "g:" and "group:" prefix strings. */
483 group_name = strchr (cur_name, ':') + 1;
484
485 syscall_list = get_syscalls_by_group (gdbarch, group_name);
486
487 if (syscall_list == NULL)
488 error (_("Unknown syscall group '%s'."), group_name);
489
490 for (i = 0; syscall_list[i].name != NULL; i++)
491 {
492 /* Insert each syscall that are part of the group. No
493 need to check if it is valid. */
494 VEC_safe_push (int, result, syscall_list[i].number);
495 }
496
497 xfree (syscall_list);
498 }
499 else
500 {
501 /* We have a name. Let's check if it's valid and convert it
502 to a number. */
503 get_syscall_by_name (gdbarch, cur_name, &s);
504
505 if (s.number == UNKNOWN_SYSCALL)
506 /* Here we have to issue an error instead of a warning,
507 because GDB cannot do anything useful if there's no
508 syscall number to be caught. */
509 error (_("Unknown syscall name '%s'."), cur_name);
510
511 /* Ok, it's valid. */
512 VEC_safe_push (int, result, s.number);
513 }
514 }
515
516 discard_cleanups (cleanup);
517 return result;
518 }
519
520 /* Implement the "catch syscall" command. */
521
522 static void
523 catch_syscall_command_1 (char *arg, int from_tty,
524 struct cmd_list_element *command)
525 {
526 int tempflag;
527 VEC(int) *filter;
528 struct syscall s;
529 struct gdbarch *gdbarch = get_current_arch ();
530
531 /* Checking if the feature if supported. */
532 if (gdbarch_get_syscall_number_p (gdbarch) == 0)
533 error (_("The feature 'catch syscall' is not supported on \
534 this architecture yet."));
535
536 tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
537
538 arg = skip_spaces (arg);
539
540 /* We need to do this first "dummy" translation in order
541 to get the syscall XML file loaded or, most important,
542 to display a warning to the user if there's no XML file
543 for his/her architecture. */
544 get_syscall_by_number (gdbarch, 0, &s);
545
546 /* The allowed syntax is:
547 catch syscall
548 catch syscall <name | number> [<name | number> ... <name | number>]
549
550 Let's check if there's a syscall name. */
551
552 if (arg != NULL)
553 filter = catch_syscall_split_args (arg);
554 else
555 filter = NULL;
556
557 create_syscall_event_catchpoint (tempflag, filter,
558 &catch_syscall_breakpoint_ops);
559 }
560
561
562 /* Returns 0 if 'bp' is NOT a syscall catchpoint,
563 non-zero otherwise. */
564 static int
565 is_syscall_catchpoint_enabled (struct breakpoint *bp)
566 {
567 if (syscall_catchpoint_p (bp)
568 && bp->enable_state != bp_disabled
569 && bp->enable_state != bp_call_disabled)
570 return 1;
571 else
572 return 0;
573 }
574
575 int
576 catch_syscall_enabled (void)
577 {
578 struct catch_syscall_inferior_data *inf_data
579 = get_catch_syscall_inferior_data (current_inferior ());
580
581 return inf_data->total_syscalls_count != 0;
582 }
583
584 /* Helper function for catching_syscall_number. If B is a syscall
585 catchpoint for SYSCALL_NUMBER, return 1 (which will make
586 'breakpoint_find_if' return). Otherwise, return 0. */
587
588 static int
589 catching_syscall_number_1 (struct breakpoint *b,
590 void *data)
591 {
592 int syscall_number = (int) (uintptr_t) data;
593
594 if (is_syscall_catchpoint_enabled (b))
595 {
596 struct syscall_catchpoint *c = (struct syscall_catchpoint *) b;
597
598 if (c->syscalls_to_be_caught)
599 {
600 int i, iter;
601 for (i = 0;
602 VEC_iterate (int, c->syscalls_to_be_caught, i, iter);
603 i++)
604 if (syscall_number == iter)
605 return 1;
606 }
607 else
608 return 1;
609 }
610
611 return 0;
612 }
613
614 int
615 catching_syscall_number (int syscall_number)
616 {
617 struct breakpoint *b = breakpoint_find_if (catching_syscall_number_1,
618 (void *) (uintptr_t) syscall_number);
619
620 return b != NULL;
621 }
622
623 /* Complete syscall names. Used by "catch syscall". */
624 static VEC (char_ptr) *
625 catch_syscall_completer (struct cmd_list_element *cmd,
626 const char *text, const char *word)
627 {
628 struct gdbarch *gdbarch = get_current_arch ();
629 struct cleanup *cleanups = make_cleanup (null_cleanup, NULL);
630 VEC (char_ptr) *group_retlist = NULL;
631 VEC (char_ptr) *syscall_retlist = NULL;
632 VEC (char_ptr) *retlist = NULL;
633 const char **group_list = NULL;
634 const char **syscall_list = NULL;
635 const char *prefix;
636 int i;
637
638 /* Completion considers ':' to be a word separator, so we use this to
639 verify whether the previous word was a group prefix. If so, we
640 build the completion list using group names only. */
641 for (prefix = word; prefix != text && prefix[-1] != ' '; prefix--)
642 ;
643
644 if (startswith (prefix, "g:") || startswith (prefix, "group:"))
645 {
646 /* Perform completion inside 'group:' namespace only. */
647 group_list = get_syscall_group_names (gdbarch);
648 retlist = (group_list == NULL
649 ? NULL : complete_on_enum (group_list, word, word));
650 }
651 else
652 {
653 /* Complete with both, syscall names and groups. */
654 syscall_list = get_syscall_names (gdbarch);
655 group_list = get_syscall_group_names (gdbarch);
656
657 /* Append "group:" prefix to syscall groups. */
658 for (i = 0; group_list[i] != NULL; i++)
659 {
660 char *prefixed_group = xstrprintf ("group:%s", group_list[i]);
661
662 group_list[i] = prefixed_group;
663 make_cleanup (xfree, prefixed_group);
664 }
665
666 syscall_retlist = ((syscall_list == NULL)
667 ? NULL : complete_on_enum (syscall_list, word, word));
668 group_retlist = ((group_list == NULL)
669 ? NULL : complete_on_enum (group_list, word, word));
670
671 retlist = VEC_merge (char_ptr, syscall_retlist, group_retlist);
672 }
673
674 VEC_free (char_ptr, syscall_retlist);
675 VEC_free (char_ptr, group_retlist);
676 xfree (syscall_list);
677 xfree (group_list);
678 do_cleanups (cleanups);
679
680 return retlist;
681 }
682
683 static void
684 clear_syscall_counts (struct inferior *inf)
685 {
686 struct catch_syscall_inferior_data *inf_data
687 = get_catch_syscall_inferior_data (inf);
688
689 inf_data->total_syscalls_count = 0;
690 inf_data->any_syscall_count = 0;
691 VEC_free (int, inf_data->syscalls_counts);
692 }
693
694 static void
695 initialize_syscall_catchpoint_ops (void)
696 {
697 struct breakpoint_ops *ops;
698
699 initialize_breakpoint_ops ();
700
701 /* Syscall catchpoints. */
702 ops = &catch_syscall_breakpoint_ops;
703 *ops = base_breakpoint_ops;
704 ops->dtor = dtor_catch_syscall;
705 ops->insert_location = insert_catch_syscall;
706 ops->remove_location = remove_catch_syscall;
707 ops->breakpoint_hit = breakpoint_hit_catch_syscall;
708 ops->print_it = print_it_catch_syscall;
709 ops->print_one = print_one_catch_syscall;
710 ops->print_mention = print_mention_catch_syscall;
711 ops->print_recreate = print_recreate_catch_syscall;
712 }
713
714 initialize_file_ftype _initialize_break_catch_syscall;
715
716 void
717 _initialize_break_catch_syscall (void)
718 {
719 initialize_syscall_catchpoint_ops ();
720
721 observer_attach_inferior_exit (clear_syscall_counts);
722 catch_syscall_inferior_data
723 = register_inferior_data_with_cleanup (NULL,
724 catch_syscall_inferior_data_cleanup);
725
726 add_catch_command ("syscall", _("\
727 Catch system calls by their names, groups and/or numbers.\n\
728 Arguments say which system calls to catch. If no arguments are given,\n\
729 every system call will be caught. Arguments, if given, should be one\n\
730 or more system call names (if your system supports that), system call\n\
731 groups or system call numbers."),
732 catch_syscall_command_1,
733 catch_syscall_completer,
734 CATCH_PERMANENT,
735 CATCH_TEMPORARY);
736 }