Add some more casts (1/2)
[external/binutils.git] / 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 = ((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)
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
258   if (b->disposition == disp_del)
259     ui_out_text (uiout, "\nTemporary catchpoint ");
260   else
261     ui_out_text (uiout, "\nCatchpoint ");
262   if (ui_out_is_mi_like_p (uiout))
263     {
264       ui_out_field_string (uiout, "reason",
265                            async_reason_lookup (last.kind == TARGET_WAITKIND_SYSCALL_ENTRY
266                                                 ? EXEC_ASYNC_SYSCALL_ENTRY
267                                                 : EXEC_ASYNC_SYSCALL_RETURN));
268       ui_out_field_string (uiout, "disp", bpdisp_text (b->disposition));
269     }
270   ui_out_field_int (uiout, "bkptno", b->number);
271
272   if (last.kind == TARGET_WAITKIND_SYSCALL_ENTRY)
273     ui_out_text (uiout, " (call to syscall ");
274   else
275     ui_out_text (uiout, " (returned from syscall ");
276
277   if (s.name == NULL || ui_out_is_mi_like_p (uiout))
278     ui_out_field_int (uiout, "syscall-number", last.value.syscall_number);
279   if (s.name != NULL)
280     ui_out_field_string (uiout, "syscall-name", s.name);
281
282   ui_out_text (uiout, "), ");
283
284   return PRINT_SRC_AND_LOC;
285 }
286
287 /* Implement the "print_one" breakpoint_ops method for syscall
288    catchpoints.  */
289
290 static void
291 print_one_catch_syscall (struct breakpoint *b,
292                          struct bp_location **last_loc)
293 {
294   struct syscall_catchpoint *c = (struct syscall_catchpoint *) b;
295   struct value_print_options opts;
296   struct ui_out *uiout = current_uiout;
297   struct gdbarch *gdbarch = b->loc->gdbarch;
298
299   get_user_print_options (&opts);
300   /* Field 4, the address, is omitted (which makes the columns not
301      line up too nicely with the headers, but the effect is relatively
302      readable).  */
303   if (opts.addressprint)
304     ui_out_field_skip (uiout, "addr");
305   annotate_field (5);
306
307   if (c->syscalls_to_be_caught
308       && VEC_length (int, c->syscalls_to_be_caught) > 1)
309     ui_out_text (uiout, "syscalls \"");
310   else
311     ui_out_text (uiout, "syscall \"");
312
313   if (c->syscalls_to_be_caught)
314     {
315       int i, iter;
316       char *text = xstrprintf ("%s", "");
317
318       for (i = 0;
319            VEC_iterate (int, c->syscalls_to_be_caught, i, iter);
320            i++)
321         {
322           char *x = text;
323           struct syscall s;
324           get_syscall_by_number (gdbarch, iter, &s);
325
326           if (s.name != NULL)
327             text = xstrprintf ("%s%s, ", text, s.name);
328           else
329             text = xstrprintf ("%s%d, ", text, iter);
330
331           /* We have to xfree the last 'text' (now stored at 'x')
332              because xstrprintf dynamically allocates new space for it
333              on every call.  */
334           xfree (x);
335         }
336       /* Remove the last comma.  */
337       text[strlen (text) - 2] = '\0';
338       ui_out_field_string (uiout, "what", text);
339     }
340   else
341     ui_out_field_string (uiout, "what", "<any syscall>");
342   ui_out_text (uiout, "\" ");
343
344   if (ui_out_is_mi_like_p (uiout))
345     ui_out_field_string (uiout, "catch-type", "syscall");
346 }
347
348 /* Implement the "print_mention" breakpoint_ops method for syscall
349    catchpoints.  */
350
351 static void
352 print_mention_catch_syscall (struct breakpoint *b)
353 {
354   struct syscall_catchpoint *c = (struct syscall_catchpoint *) b;
355   struct gdbarch *gdbarch = b->loc->gdbarch;
356
357   if (c->syscalls_to_be_caught)
358     {
359       int i, iter;
360
361       if (VEC_length (int, c->syscalls_to_be_caught) > 1)
362         printf_filtered (_("Catchpoint %d (syscalls"), b->number);
363       else
364         printf_filtered (_("Catchpoint %d (syscall"), b->number);
365
366       for (i = 0;
367            VEC_iterate (int, c->syscalls_to_be_caught, i, iter);
368            i++)
369         {
370           struct syscall s;
371           get_syscall_by_number (gdbarch, iter, &s);
372
373           if (s.name)
374             printf_filtered (" '%s' [%d]", s.name, s.number);
375           else
376             printf_filtered (" %d", s.number);
377         }
378       printf_filtered (")");
379     }
380   else
381     printf_filtered (_("Catchpoint %d (any syscall)"),
382                      b->number);
383 }
384
385 /* Implement the "print_recreate" breakpoint_ops method for syscall
386    catchpoints.  */
387
388 static void
389 print_recreate_catch_syscall (struct breakpoint *b, struct ui_file *fp)
390 {
391   struct syscall_catchpoint *c = (struct syscall_catchpoint *) b;
392   struct gdbarch *gdbarch = b->loc->gdbarch;
393
394   fprintf_unfiltered (fp, "catch syscall");
395
396   if (c->syscalls_to_be_caught)
397     {
398       int i, iter;
399
400       for (i = 0;
401            VEC_iterate (int, c->syscalls_to_be_caught, i, iter);
402            i++)
403         {
404           struct syscall s;
405
406           get_syscall_by_number (gdbarch, iter, &s);
407           if (s.name)
408             fprintf_unfiltered (fp, " %s", s.name);
409           else
410             fprintf_unfiltered (fp, " %d", s.number);
411         }
412     }
413   print_recreate_thread (b, fp);
414 }
415
416 /* The breakpoint_ops structure to be used in syscall catchpoints.  */
417
418 static struct breakpoint_ops catch_syscall_breakpoint_ops;
419
420 /* Returns non-zero if 'b' is a syscall catchpoint.  */
421
422 static int
423 syscall_catchpoint_p (struct breakpoint *b)
424 {
425   return (b->ops == &catch_syscall_breakpoint_ops);
426 }
427
428 static void
429 create_syscall_event_catchpoint (int tempflag, VEC(int) *filter,
430                                  const struct breakpoint_ops *ops)
431 {
432   struct syscall_catchpoint *c;
433   struct gdbarch *gdbarch = get_current_arch ();
434
435   c = XNEW (struct syscall_catchpoint);
436   init_catchpoint (&c->base, gdbarch, tempflag, NULL, ops);
437   c->syscalls_to_be_caught = filter;
438
439   install_breakpoint (0, &c->base, 1);
440 }
441
442 /* Splits the argument using space as delimiter.  Returns an xmalloc'd
443    filter list, or NULL if no filtering is required.  */
444 static VEC(int) *
445 catch_syscall_split_args (char *arg)
446 {
447   VEC(int) *result = NULL;
448   struct cleanup *cleanup = make_cleanup (VEC_cleanup (int), &result);
449   struct gdbarch *gdbarch = target_gdbarch ();
450
451   while (*arg != '\0')
452     {
453       int i, syscall_number;
454       char *endptr;
455       char cur_name[128];
456       struct syscall s;
457
458       /* Skip whitespace.  */
459       arg = skip_spaces (arg);
460
461       for (i = 0; i < 127 && arg[i] && !isspace (arg[i]); ++i)
462         cur_name[i] = arg[i];
463       cur_name[i] = '\0';
464       arg += i;
465
466       /* Check if the user provided a syscall name or a number.  */
467       syscall_number = (int) strtol (cur_name, &endptr, 0);
468       if (*endptr == '\0')
469         get_syscall_by_number (gdbarch, syscall_number, &s);
470       else
471         {
472           /* We have a name.  Let's check if it's valid and convert it
473              to a number.  */
474           get_syscall_by_name (gdbarch, cur_name, &s);
475
476           if (s.number == UNKNOWN_SYSCALL)
477             /* Here we have to issue an error instead of a warning,
478                because GDB cannot do anything useful if there's no
479                syscall number to be caught.  */
480             error (_("Unknown syscall name '%s'."), cur_name);
481         }
482
483       /* Ok, it's valid.  */
484       VEC_safe_push (int, result, s.number);
485     }
486
487   discard_cleanups (cleanup);
488   return result;
489 }
490
491 /* Implement the "catch syscall" command.  */
492
493 static void
494 catch_syscall_command_1 (char *arg, int from_tty, 
495                          struct cmd_list_element *command)
496 {
497   int tempflag;
498   VEC(int) *filter;
499   struct syscall s;
500   struct gdbarch *gdbarch = get_current_arch ();
501
502   /* Checking if the feature if supported.  */
503   if (gdbarch_get_syscall_number_p (gdbarch) == 0)
504     error (_("The feature 'catch syscall' is not supported on \
505 this architecture yet."));
506
507   tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
508
509   arg = skip_spaces (arg);
510
511   /* We need to do this first "dummy" translation in order
512      to get the syscall XML file loaded or, most important,
513      to display a warning to the user if there's no XML file
514      for his/her architecture.  */
515   get_syscall_by_number (gdbarch, 0, &s);
516
517   /* The allowed syntax is:
518      catch syscall
519      catch syscall <name | number> [<name | number> ... <name | number>]
520
521      Let's check if there's a syscall name.  */
522
523   if (arg != NULL)
524     filter = catch_syscall_split_args (arg);
525   else
526     filter = NULL;
527
528   create_syscall_event_catchpoint (tempflag, filter,
529                                    &catch_syscall_breakpoint_ops);
530 }
531
532
533 /* Returns 0 if 'bp' is NOT a syscall catchpoint,
534    non-zero otherwise.  */
535 static int
536 is_syscall_catchpoint_enabled (struct breakpoint *bp)
537 {
538   if (syscall_catchpoint_p (bp)
539       && bp->enable_state != bp_disabled
540       && bp->enable_state != bp_call_disabled)
541     return 1;
542   else
543     return 0;
544 }
545
546 int
547 catch_syscall_enabled (void)
548 {
549   struct catch_syscall_inferior_data *inf_data
550     = get_catch_syscall_inferior_data (current_inferior ());
551
552   return inf_data->total_syscalls_count != 0;
553 }
554
555 /* Helper function for catching_syscall_number.  If B is a syscall
556    catchpoint for SYSCALL_NUMBER, return 1 (which will make
557    'breakpoint_find_if' return).  Otherwise, return 0.  */
558
559 static int
560 catching_syscall_number_1 (struct breakpoint *b,
561                            void *data)
562 {
563   int syscall_number = (int) (uintptr_t) data;
564
565   if (is_syscall_catchpoint_enabled (b))
566     {
567       struct syscall_catchpoint *c = (struct syscall_catchpoint *) b;
568
569       if (c->syscalls_to_be_caught)
570         {
571           int i, iter;
572           for (i = 0;
573                VEC_iterate (int, c->syscalls_to_be_caught, i, iter);
574                i++)
575             if (syscall_number == iter)
576               return 1;
577         }
578       else
579         return 1;
580     }
581
582   return 0;
583 }
584
585 int
586 catching_syscall_number (int syscall_number)
587 {
588   struct breakpoint *b = breakpoint_find_if (catching_syscall_number_1,
589                                          (void *) (uintptr_t) syscall_number);
590
591   return b != NULL;
592 }
593
594 /* Complete syscall names.  Used by "catch syscall".  */
595 static VEC (char_ptr) *
596 catch_syscall_completer (struct cmd_list_element *cmd,
597                          const char *text, const char *word)
598 {
599   const char **list = get_syscall_names (get_current_arch ());
600   VEC (char_ptr) *retlist
601     = (list == NULL) ? NULL : complete_on_enum (list, word, word);
602
603   xfree (list);
604   return retlist;
605 }
606
607 static void
608 clear_syscall_counts (struct inferior *inf)
609 {
610   struct catch_syscall_inferior_data *inf_data
611     = get_catch_syscall_inferior_data (inf);
612
613   inf_data->total_syscalls_count = 0;
614   inf_data->any_syscall_count = 0;
615   VEC_free (int, inf_data->syscalls_counts);
616 }
617
618 static void
619 initialize_syscall_catchpoint_ops (void)
620 {
621   struct breakpoint_ops *ops;
622
623   initialize_breakpoint_ops ();
624
625   /* Syscall catchpoints.  */
626   ops = &catch_syscall_breakpoint_ops;
627   *ops = base_breakpoint_ops;
628   ops->dtor = dtor_catch_syscall;
629   ops->insert_location = insert_catch_syscall;
630   ops->remove_location = remove_catch_syscall;
631   ops->breakpoint_hit = breakpoint_hit_catch_syscall;
632   ops->print_it = print_it_catch_syscall;
633   ops->print_one = print_one_catch_syscall;
634   ops->print_mention = print_mention_catch_syscall;
635   ops->print_recreate = print_recreate_catch_syscall;
636 }
637
638 initialize_file_ftype _initialize_break_catch_syscall;
639
640 void
641 _initialize_break_catch_syscall (void)
642 {
643   initialize_syscall_catchpoint_ops ();
644
645   observer_attach_inferior_exit (clear_syscall_counts);
646   catch_syscall_inferior_data
647     = register_inferior_data_with_cleanup (NULL,
648                                            catch_syscall_inferior_data_cleanup);
649
650   add_catch_command ("syscall", _("\
651 Catch system calls by their names and/or numbers.\n\
652 Arguments say which system calls to catch.  If no arguments\n\
653 are given, every system call will be caught.\n\
654 Arguments, if given, should be one or more system call names\n\
655 (if your system supports that), or system call numbers."),
656                      catch_syscall_command_1,
657                      catch_syscall_completer,
658                      CATCH_PERMANENT,
659                      CATCH_TEMPORARY);
660 }