xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/break-catch-syscall.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
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