windows-nat: Don't change current_event.dwThreadId in handle_output_debug_string()
[deliverable/binutils-gdb.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 = 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 }
This page took 0.083896 seconds and 4 git commands to generate.