gold: Add a linker configure option --enable-relro
[external/binutils.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)
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 or a number.  */
468       syscall_number = (int) strtol (cur_name, &endptr, 0);
469       if (*endptr == '\0')
470         get_syscall_by_number (gdbarch, syscall_number, &s);
471       else
472         {
473           /* We have a name.  Let's check if it's valid and convert it
474              to a number.  */
475           get_syscall_by_name (gdbarch, cur_name, &s);
476
477           if (s.number == UNKNOWN_SYSCALL)
478             /* Here we have to issue an error instead of a warning,
479                because GDB cannot do anything useful if there's no
480                syscall number to be caught.  */
481             error (_("Unknown syscall name '%s'."), cur_name);
482         }
483
484       /* Ok, it's valid.  */
485       VEC_safe_push (int, result, s.number);
486     }
487
488   discard_cleanups (cleanup);
489   return result;
490 }
491
492 /* Implement the "catch syscall" command.  */
493
494 static void
495 catch_syscall_command_1 (char *arg, int from_tty, 
496                          struct cmd_list_element *command)
497 {
498   int tempflag;
499   VEC(int) *filter;
500   struct syscall s;
501   struct gdbarch *gdbarch = get_current_arch ();
502
503   /* Checking if the feature if supported.  */
504   if (gdbarch_get_syscall_number_p (gdbarch) == 0)
505     error (_("The feature 'catch syscall' is not supported on \
506 this architecture yet."));
507
508   tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
509
510   arg = skip_spaces (arg);
511
512   /* We need to do this first "dummy" translation in order
513      to get the syscall XML file loaded or, most important,
514      to display a warning to the user if there's no XML file
515      for his/her architecture.  */
516   get_syscall_by_number (gdbarch, 0, &s);
517
518   /* The allowed syntax is:
519      catch syscall
520      catch syscall <name | number> [<name | number> ... <name | number>]
521
522      Let's check if there's a syscall name.  */
523
524   if (arg != NULL)
525     filter = catch_syscall_split_args (arg);
526   else
527     filter = NULL;
528
529   create_syscall_event_catchpoint (tempflag, filter,
530                                    &catch_syscall_breakpoint_ops);
531 }
532
533
534 /* Returns 0 if 'bp' is NOT a syscall catchpoint,
535    non-zero otherwise.  */
536 static int
537 is_syscall_catchpoint_enabled (struct breakpoint *bp)
538 {
539   if (syscall_catchpoint_p (bp)
540       && bp->enable_state != bp_disabled
541       && bp->enable_state != bp_call_disabled)
542     return 1;
543   else
544     return 0;
545 }
546
547 int
548 catch_syscall_enabled (void)
549 {
550   struct catch_syscall_inferior_data *inf_data
551     = get_catch_syscall_inferior_data (current_inferior ());
552
553   return inf_data->total_syscalls_count != 0;
554 }
555
556 /* Helper function for catching_syscall_number.  If B is a syscall
557    catchpoint for SYSCALL_NUMBER, return 1 (which will make
558    'breakpoint_find_if' return).  Otherwise, return 0.  */
559
560 static int
561 catching_syscall_number_1 (struct breakpoint *b,
562                            void *data)
563 {
564   int syscall_number = (int) (uintptr_t) data;
565
566   if (is_syscall_catchpoint_enabled (b))
567     {
568       struct syscall_catchpoint *c = (struct syscall_catchpoint *) b;
569
570       if (c->syscalls_to_be_caught)
571         {
572           int i, iter;
573           for (i = 0;
574                VEC_iterate (int, c->syscalls_to_be_caught, i, iter);
575                i++)
576             if (syscall_number == iter)
577               return 1;
578         }
579       else
580         return 1;
581     }
582
583   return 0;
584 }
585
586 int
587 catching_syscall_number (int syscall_number)
588 {
589   struct breakpoint *b = breakpoint_find_if (catching_syscall_number_1,
590                                          (void *) (uintptr_t) syscall_number);
591
592   return b != NULL;
593 }
594
595 /* Complete syscall names.  Used by "catch syscall".  */
596 static VEC (char_ptr) *
597 catch_syscall_completer (struct cmd_list_element *cmd,
598                          const char *text, const char *word)
599 {
600   const char **list = get_syscall_names (get_current_arch ());
601   VEC (char_ptr) *retlist
602     = (list == NULL) ? NULL : complete_on_enum (list, word, word);
603
604   xfree (list);
605   return retlist;
606 }
607
608 static void
609 clear_syscall_counts (struct inferior *inf)
610 {
611   struct catch_syscall_inferior_data *inf_data
612     = get_catch_syscall_inferior_data (inf);
613
614   inf_data->total_syscalls_count = 0;
615   inf_data->any_syscall_count = 0;
616   VEC_free (int, inf_data->syscalls_counts);
617 }
618
619 static void
620 initialize_syscall_catchpoint_ops (void)
621 {
622   struct breakpoint_ops *ops;
623
624   initialize_breakpoint_ops ();
625
626   /* Syscall catchpoints.  */
627   ops = &catch_syscall_breakpoint_ops;
628   *ops = base_breakpoint_ops;
629   ops->dtor = dtor_catch_syscall;
630   ops->insert_location = insert_catch_syscall;
631   ops->remove_location = remove_catch_syscall;
632   ops->breakpoint_hit = breakpoint_hit_catch_syscall;
633   ops->print_it = print_it_catch_syscall;
634   ops->print_one = print_one_catch_syscall;
635   ops->print_mention = print_mention_catch_syscall;
636   ops->print_recreate = print_recreate_catch_syscall;
637 }
638
639 initialize_file_ftype _initialize_break_catch_syscall;
640
641 void
642 _initialize_break_catch_syscall (void)
643 {
644   initialize_syscall_catchpoint_ops ();
645
646   observer_attach_inferior_exit (clear_syscall_counts);
647   catch_syscall_inferior_data
648     = register_inferior_data_with_cleanup (NULL,
649                                            catch_syscall_inferior_data_cleanup);
650
651   add_catch_command ("syscall", _("\
652 Catch system calls by their names and/or numbers.\n\
653 Arguments say which system calls to catch.  If no arguments\n\
654 are given, every system call will be caught.\n\
655 Arguments, if given, should be one or more system call names\n\
656 (if your system supports that), or system call numbers."),
657                      catch_syscall_command_1,
658                      catch_syscall_completer,
659                      CATCH_PERMANENT,
660                      CATCH_TEMPORARY);
661 }