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 ui_out_text (uiout, "Temporary catchpoint "); 261 else 262 ui_out_text (uiout, "Catchpoint "); 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 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 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 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 = 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. */ 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 } 737