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