Replace some $ARCH_{get,set}_pc with linux_{get,set}_pc_64bit
[deliverable/binutils-gdb.git] / gdb / break-catch-syscall.c
CommitLineData
10304ef3
SDJ
1/* Everything about syscall catchpoints, for GDB.
2
618f726f 3 Copyright (C) 2009-2016 Free Software Foundation, Inc.
10304ef3
SDJ
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
39struct 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
54static void
55dtor_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
64static const struct inferior_data *catch_syscall_inferior_data = NULL;
65
66struct 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
83static struct catch_syscall_inferior_data*
84get_catch_syscall_inferior_data (struct inferior *inf)
85{
86 struct catch_syscall_inferior_data *inf_data;
87
9a3c8263
SM
88 inf_data = ((struct catch_syscall_inferior_data *)
89 inferior_data (inf, catch_syscall_inferior_data));
10304ef3
SDJ
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
99static void
100catch_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
109static int
110insert_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
160static int
161remove_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
200static int
201breakpoint_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
238static enum print_stop_action
239print_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
290static void
291print_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
351static void
352print_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
388static void
389print_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
418static struct breakpoint_ops catch_syscall_breakpoint_ops;
419
420/* Returns non-zero if 'b' is a syscall catchpoint. */
421
422static int
423syscall_catchpoint_p (struct breakpoint *b)
424{
425 return (b->ops == &catch_syscall_breakpoint_ops);
426}
427
428static void
429create_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. */
444static VEC(int) *
445catch_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
493static void
494catch_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 \
505this 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. */
535static int
536is_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
546int
547catch_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
559static int
560catching_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
585int
586catching_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". */
595static VEC (char_ptr) *
596catch_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
607static void
608clear_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
618static void
619initialize_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
638initialize_file_ftype _initialize_break_catch_syscall;
639
640void
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", _("\
651Catch system calls by their names and/or numbers.\n\
652Arguments say which system calls to catch. If no arguments\n\
653are given, every system call will be caught.\n\
654Arguments, 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}
This page took 0.100867 seconds and 4 git commands to generate.