Change get_syscalls_by_group to append to an existing vector of integers.
[deliverable/binutils-gdb.git] / gdb / break-catch-syscall.c
1 /* Everything about syscall catchpoints, for GDB.
2
3 Copyright (C) 2009-2018 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 "observable.h"
31 #include "xml-syscall.h"
32
33 /* An instance of this type is used to represent a syscall catchpoint.
34 A breakpoint is really of this type iff its ops pointer points to
35 CATCH_SYSCALL_BREAKPOINT_OPS. */
36
37 struct syscall_catchpoint : public breakpoint
38 {
39 /* Syscall numbers used for the 'catch syscall' feature. If no
40 syscall has been specified for filtering, it is empty.
41 Otherwise, it holds a list of all syscalls to be caught. */
42 std::vector<int> syscalls_to_be_caught;
43 };
44
45 static const struct inferior_data *catch_syscall_inferior_data = NULL;
46
47 struct catch_syscall_inferior_data
48 {
49 /* We keep a count of the number of times the user has requested a
50 particular syscall to be tracked, and pass this information to the
51 target. This lets capable targets implement filtering directly. */
52
53 /* Number of times that "any" syscall is requested. */
54 int any_syscall_count;
55
56 /* Count of each system call. */
57 std::vector<int> syscalls_counts;
58
59 /* This counts all syscall catch requests, so we can readily determine
60 if any catching is necessary. */
61 int total_syscalls_count;
62 };
63
64 static struct catch_syscall_inferior_data *
65 get_catch_syscall_inferior_data (struct inferior *inf)
66 {
67 struct catch_syscall_inferior_data *inf_data;
68
69 inf_data = ((struct catch_syscall_inferior_data *)
70 inferior_data (inf, catch_syscall_inferior_data));
71 if (inf_data == NULL)
72 {
73 inf_data = new struct catch_syscall_inferior_data ();
74 set_inferior_data (inf, catch_syscall_inferior_data, inf_data);
75 }
76
77 return inf_data;
78 }
79
80 static void
81 catch_syscall_inferior_data_cleanup (struct inferior *inf, void *arg)
82 {
83 struct catch_syscall_inferior_data *inf_data
84 = (struct catch_syscall_inferior_data *) arg;
85 delete inf_data;
86 }
87
88
89 /* Implement the "insert" breakpoint_ops method for syscall
90 catchpoints. */
91
92 static int
93 insert_catch_syscall (struct bp_location *bl)
94 {
95 struct syscall_catchpoint *c = (struct syscall_catchpoint *) bl->owner;
96 struct inferior *inf = current_inferior ();
97 struct catch_syscall_inferior_data *inf_data
98 = get_catch_syscall_inferior_data (inf);
99
100 ++inf_data->total_syscalls_count;
101 if (c->syscalls_to_be_caught.empty ())
102 ++inf_data->any_syscall_count;
103 else
104 {
105 for (int iter : c->syscalls_to_be_caught)
106 {
107 if (iter >= inf_data->syscalls_counts.size ())
108 inf_data->syscalls_counts.resize (iter + 1);
109 ++inf_data->syscalls_counts[iter];
110 }
111 }
112
113 return target_set_syscall_catchpoint (inferior_ptid.pid (),
114 inf_data->total_syscalls_count != 0,
115 inf_data->any_syscall_count,
116 inf_data->syscalls_counts);
117 }
118
119 /* Implement the "remove" breakpoint_ops method for syscall
120 catchpoints. */
121
122 static int
123 remove_catch_syscall (struct bp_location *bl, enum remove_bp_reason reason)
124 {
125 struct syscall_catchpoint *c = (struct syscall_catchpoint *) bl->owner;
126 struct inferior *inf = current_inferior ();
127 struct catch_syscall_inferior_data *inf_data
128 = get_catch_syscall_inferior_data (inf);
129
130 --inf_data->total_syscalls_count;
131 if (c->syscalls_to_be_caught.empty ())
132 --inf_data->any_syscall_count;
133 else
134 {
135 for (int iter : c->syscalls_to_be_caught)
136 {
137 if (iter >= inf_data->syscalls_counts.size ())
138 /* Shouldn't happen. */
139 continue;
140 --inf_data->syscalls_counts[iter];
141 }
142 }
143
144 return target_set_syscall_catchpoint (inferior_ptid.pid (),
145 inf_data->total_syscalls_count != 0,
146 inf_data->any_syscall_count,
147 inf_data->syscalls_counts);
148 }
149
150 /* Implement the "breakpoint_hit" breakpoint_ops method for syscall
151 catchpoints. */
152
153 static int
154 breakpoint_hit_catch_syscall (const struct bp_location *bl,
155 const address_space *aspace, CORE_ADDR bp_addr,
156 const struct target_waitstatus *ws)
157 {
158 /* We must check if we are catching specific syscalls in this
159 breakpoint. If we are, then we must guarantee that the called
160 syscall is the same syscall we are catching. */
161 int syscall_number = 0;
162 const struct syscall_catchpoint *c
163 = (const struct syscall_catchpoint *) bl->owner;
164
165 if (ws->kind != TARGET_WAITKIND_SYSCALL_ENTRY
166 && ws->kind != TARGET_WAITKIND_SYSCALL_RETURN)
167 return 0;
168
169 syscall_number = ws->value.syscall_number;
170
171 /* Now, checking if the syscall is the same. */
172 if (!c->syscalls_to_be_caught.empty ())
173 {
174 for (int iter : c->syscalls_to_be_caught)
175 if (syscall_number == iter)
176 return 1;
177
178 return 0;
179 }
180
181 return 1;
182 }
183
184 /* Implement the "print_it" breakpoint_ops method for syscall
185 catchpoints. */
186
187 static enum print_stop_action
188 print_it_catch_syscall (bpstat bs)
189 {
190 struct ui_out *uiout = current_uiout;
191 struct breakpoint *b = bs->breakpoint_at;
192 /* These are needed because we want to know in which state a
193 syscall is. It can be in the TARGET_WAITKIND_SYSCALL_ENTRY
194 or TARGET_WAITKIND_SYSCALL_RETURN, and depending on it we
195 must print "called syscall" or "returned from syscall". */
196 ptid_t ptid;
197 struct target_waitstatus last;
198 struct syscall s;
199 struct gdbarch *gdbarch = bs->bp_location_at->gdbarch;
200
201 get_last_target_status (&ptid, &last);
202
203 get_syscall_by_number (gdbarch, last.value.syscall_number, &s);
204
205 annotate_catchpoint (b->number);
206 maybe_print_thread_hit_breakpoint (uiout);
207
208 if (b->disposition == disp_del)
209 uiout->text ("Temporary catchpoint ");
210 else
211 uiout->text ("Catchpoint ");
212 if (uiout->is_mi_like_p ())
213 {
214 uiout->field_string ("reason",
215 async_reason_lookup (last.kind == TARGET_WAITKIND_SYSCALL_ENTRY
216 ? EXEC_ASYNC_SYSCALL_ENTRY
217 : EXEC_ASYNC_SYSCALL_RETURN));
218 uiout->field_string ("disp", bpdisp_text (b->disposition));
219 }
220 uiout->field_int ("bkptno", b->number);
221
222 if (last.kind == TARGET_WAITKIND_SYSCALL_ENTRY)
223 uiout->text (" (call to syscall ");
224 else
225 uiout->text (" (returned from syscall ");
226
227 if (s.name == NULL || uiout->is_mi_like_p ())
228 uiout->field_int ("syscall-number", last.value.syscall_number);
229 if (s.name != NULL)
230 uiout->field_string ("syscall-name", s.name);
231
232 uiout->text ("), ");
233
234 return PRINT_SRC_AND_LOC;
235 }
236
237 /* Implement the "print_one" breakpoint_ops method for syscall
238 catchpoints. */
239
240 static void
241 print_one_catch_syscall (struct breakpoint *b,
242 struct bp_location **last_loc)
243 {
244 struct syscall_catchpoint *c = (struct syscall_catchpoint *) b;
245 struct value_print_options opts;
246 struct ui_out *uiout = current_uiout;
247 struct gdbarch *gdbarch = b->loc->gdbarch;
248
249 get_user_print_options (&opts);
250 /* Field 4, the address, is omitted (which makes the columns not
251 line up too nicely with the headers, but the effect is relatively
252 readable). */
253 if (opts.addressprint)
254 uiout->field_skip ("addr");
255 annotate_field (5);
256
257 if (c->syscalls_to_be_caught.size () > 1)
258 uiout->text ("syscalls \"");
259 else
260 uiout->text ("syscall \"");
261
262 if (!c->syscalls_to_be_caught.empty ())
263 {
264 char *text = xstrprintf ("%s", "");
265
266 for (int iter : c->syscalls_to_be_caught)
267 {
268 char *x = text;
269 struct syscall s;
270 get_syscall_by_number (gdbarch, iter, &s);
271
272 if (s.name != NULL)
273 text = xstrprintf ("%s%s, ", text, s.name);
274 else
275 text = xstrprintf ("%s%d, ", text, iter);
276
277 /* We have to xfree the last 'text' (now stored at 'x')
278 because xstrprintf dynamically allocates new space for it
279 on every call. */
280 xfree (x);
281 }
282 /* Remove the last comma. */
283 text[strlen (text) - 2] = '\0';
284 uiout->field_string ("what", text);
285 }
286 else
287 uiout->field_string ("what", "<any syscall>");
288 uiout->text ("\" ");
289
290 if (uiout->is_mi_like_p ())
291 uiout->field_string ("catch-type", "syscall");
292 }
293
294 /* Implement the "print_mention" breakpoint_ops method for syscall
295 catchpoints. */
296
297 static void
298 print_mention_catch_syscall (struct breakpoint *b)
299 {
300 struct syscall_catchpoint *c = (struct syscall_catchpoint *) b;
301 struct gdbarch *gdbarch = b->loc->gdbarch;
302
303 if (!c->syscalls_to_be_caught.empty ())
304 {
305 if (c->syscalls_to_be_caught.size () > 1)
306 printf_filtered (_("Catchpoint %d (syscalls"), b->number);
307 else
308 printf_filtered (_("Catchpoint %d (syscall"), b->number);
309
310 for (int iter : c->syscalls_to_be_caught)
311 {
312 struct syscall s;
313 get_syscall_by_number (gdbarch, iter, &s);
314
315 if (s.name != NULL)
316 printf_filtered (" '%s' [%d]", s.name, s.number);
317 else
318 printf_filtered (" %d", s.number);
319 }
320 printf_filtered (")");
321 }
322 else
323 printf_filtered (_("Catchpoint %d (any syscall)"),
324 b->number);
325 }
326
327 /* Implement the "print_recreate" breakpoint_ops method for syscall
328 catchpoints. */
329
330 static void
331 print_recreate_catch_syscall (struct breakpoint *b, struct ui_file *fp)
332 {
333 struct syscall_catchpoint *c = (struct syscall_catchpoint *) b;
334 struct gdbarch *gdbarch = b->loc->gdbarch;
335
336 fprintf_unfiltered (fp, "catch syscall");
337
338 for (int iter : c->syscalls_to_be_caught)
339 {
340 struct syscall s;
341
342 get_syscall_by_number (gdbarch, iter, &s);
343 if (s.name != NULL)
344 fprintf_unfiltered (fp, " %s", s.name);
345 else
346 fprintf_unfiltered (fp, " %d", s.number);
347 }
348
349 print_recreate_thread (b, fp);
350 }
351
352 /* The breakpoint_ops structure to be used in syscall catchpoints. */
353
354 static struct breakpoint_ops catch_syscall_breakpoint_ops;
355
356 /* Returns non-zero if 'b' is a syscall catchpoint. */
357
358 static int
359 syscall_catchpoint_p (struct breakpoint *b)
360 {
361 return (b->ops == &catch_syscall_breakpoint_ops);
362 }
363
364 static void
365 create_syscall_event_catchpoint (int tempflag, std::vector<int> &&filter,
366 const struct breakpoint_ops *ops)
367 {
368 struct gdbarch *gdbarch = get_current_arch ();
369
370 std::unique_ptr<syscall_catchpoint> c (new syscall_catchpoint ());
371 init_catchpoint (c.get (), gdbarch, tempflag, NULL, ops);
372 c->syscalls_to_be_caught = std::move (filter);
373
374 install_breakpoint (0, std::move (c), 1);
375 }
376
377 /* Splits the argument using space as delimiter. */
378
379 static std::vector<int>
380 catch_syscall_split_args (const char *arg)
381 {
382 std::vector<int> result;
383 struct gdbarch *gdbarch = target_gdbarch ();
384
385 while (*arg != '\0')
386 {
387 int i, syscall_number;
388 char *endptr;
389 char cur_name[128];
390 struct syscall s;
391
392 /* Skip whitespace. */
393 arg = skip_spaces (arg);
394
395 for (i = 0; i < 127 && arg[i] && !isspace (arg[i]); ++i)
396 cur_name[i] = arg[i];
397 cur_name[i] = '\0';
398 arg += i;
399
400 /* Check if the user provided a syscall name, group, or a number. */
401 syscall_number = (int) strtol (cur_name, &endptr, 0);
402 if (*endptr == '\0')
403 {
404 get_syscall_by_number (gdbarch, syscall_number, &s);
405 result.push_back (s.number);
406 }
407 else if (startswith (cur_name, "g:")
408 || startswith (cur_name, "group:"))
409 {
410 /* We have a syscall group. Let's expand it into a syscall
411 list before inserting. */
412 const char *group_name;
413
414 /* Skip over "g:" and "group:" prefix strings. */
415 group_name = strchr (cur_name, ':') + 1;
416
417 if (!get_syscalls_by_group (gdbarch, group_name, &result))
418 error (_("Unknown syscall group '%s'."), group_name);
419 }
420 else
421 {
422 /* We have a name. Let's check if it's valid and convert it
423 to a number. */
424 get_syscall_by_name (gdbarch, cur_name, &s);
425
426 if (s.number == UNKNOWN_SYSCALL)
427 /* Here we have to issue an error instead of a warning,
428 because GDB cannot do anything useful if there's no
429 syscall number to be caught. */
430 error (_("Unknown syscall name '%s'."), cur_name);
431
432 /* Ok, it's valid. */
433 result.push_back (s.number);
434 }
435 }
436
437 return result;
438 }
439
440 /* Implement the "catch syscall" command. */
441
442 static void
443 catch_syscall_command_1 (const char *arg, int from_tty,
444 struct cmd_list_element *command)
445 {
446 int tempflag;
447 std::vector<int> filter;
448 struct syscall s;
449 struct gdbarch *gdbarch = get_current_arch ();
450
451 /* Checking if the feature if supported. */
452 if (gdbarch_get_syscall_number_p (gdbarch) == 0)
453 error (_("The feature 'catch syscall' is not supported on \
454 this architecture yet."));
455
456 tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
457
458 arg = skip_spaces (arg);
459
460 /* We need to do this first "dummy" translation in order
461 to get the syscall XML file loaded or, most important,
462 to display a warning to the user if there's no XML file
463 for his/her architecture. */
464 get_syscall_by_number (gdbarch, 0, &s);
465
466 /* The allowed syntax is:
467 catch syscall
468 catch syscall <name | number> [<name | number> ... <name | number>]
469
470 Let's check if there's a syscall name. */
471
472 if (arg != NULL)
473 filter = catch_syscall_split_args (arg);
474
475 create_syscall_event_catchpoint (tempflag, std::move (filter),
476 &catch_syscall_breakpoint_ops);
477 }
478
479
480 /* Returns 0 if 'bp' is NOT a syscall catchpoint,
481 non-zero otherwise. */
482 static int
483 is_syscall_catchpoint_enabled (struct breakpoint *bp)
484 {
485 if (syscall_catchpoint_p (bp)
486 && bp->enable_state != bp_disabled
487 && bp->enable_state != bp_call_disabled)
488 return 1;
489 else
490 return 0;
491 }
492
493 int
494 catch_syscall_enabled (void)
495 {
496 struct catch_syscall_inferior_data *inf_data
497 = get_catch_syscall_inferior_data (current_inferior ());
498
499 return inf_data->total_syscalls_count != 0;
500 }
501
502 /* Helper function for catching_syscall_number. If B is a syscall
503 catchpoint for SYSCALL_NUMBER, return 1 (which will make
504 'breakpoint_find_if' return). Otherwise, return 0. */
505
506 static int
507 catching_syscall_number_1 (struct breakpoint *b,
508 void *data)
509 {
510 int syscall_number = (int) (uintptr_t) data;
511
512 if (is_syscall_catchpoint_enabled (b))
513 {
514 struct syscall_catchpoint *c = (struct syscall_catchpoint *) b;
515
516 if (!c->syscalls_to_be_caught.empty ())
517 {
518 for (int iter : c->syscalls_to_be_caught)
519 if (syscall_number == iter)
520 return 1;
521 }
522 else
523 return 1;
524 }
525
526 return 0;
527 }
528
529 int
530 catching_syscall_number (int syscall_number)
531 {
532 struct breakpoint *b = breakpoint_find_if (catching_syscall_number_1,
533 (void *) (uintptr_t) syscall_number);
534
535 return b != NULL;
536 }
537
538 /* Complete syscall names. Used by "catch syscall". */
539
540 static void
541 catch_syscall_completer (struct cmd_list_element *cmd,
542 completion_tracker &tracker,
543 const char *text, const char *word)
544 {
545 struct gdbarch *gdbarch = get_current_arch ();
546 gdb::unique_xmalloc_ptr<const char *> group_list;
547 const char *prefix;
548
549 /* Completion considers ':' to be a word separator, so we use this to
550 verify whether the previous word was a group prefix. If so, we
551 build the completion list using group names only. */
552 for (prefix = word; prefix != text && prefix[-1] != ' '; prefix--)
553 ;
554
555 if (startswith (prefix, "g:") || startswith (prefix, "group:"))
556 {
557 /* Perform completion inside 'group:' namespace only. */
558 group_list.reset (get_syscall_group_names (gdbarch));
559 if (group_list != NULL)
560 complete_on_enum (tracker, group_list.get (), word, word);
561 }
562 else
563 {
564 /* Complete with both, syscall names and groups. */
565 gdb::unique_xmalloc_ptr<const char *> syscall_list
566 (get_syscall_names (gdbarch));
567 group_list.reset (get_syscall_group_names (gdbarch));
568
569 const char **group_ptr = group_list.get ();
570
571 /* Hold on to strings while we're using them. */
572 std::vector<std::string> holders;
573
574 /* Append "group:" prefix to syscall groups. */
575 for (int i = 0; group_ptr[i] != NULL; i++)
576 holders.push_back (string_printf ("group:%s", group_ptr[i]));
577
578 for (int i = 0; group_ptr[i] != NULL; i++)
579 group_ptr[i] = holders[i].c_str ();
580
581 if (syscall_list != NULL)
582 complete_on_enum (tracker, syscall_list.get (), word, word);
583 if (group_list != NULL)
584 complete_on_enum (tracker, group_ptr, word, word);
585 }
586 }
587
588 static void
589 clear_syscall_counts (struct inferior *inf)
590 {
591 struct catch_syscall_inferior_data *inf_data
592 = get_catch_syscall_inferior_data (inf);
593
594 inf_data->total_syscalls_count = 0;
595 inf_data->any_syscall_count = 0;
596 inf_data->syscalls_counts.clear ();
597 }
598
599 static void
600 initialize_syscall_catchpoint_ops (void)
601 {
602 struct breakpoint_ops *ops;
603
604 initialize_breakpoint_ops ();
605
606 /* Syscall catchpoints. */
607 ops = &catch_syscall_breakpoint_ops;
608 *ops = base_breakpoint_ops;
609 ops->insert_location = insert_catch_syscall;
610 ops->remove_location = remove_catch_syscall;
611 ops->breakpoint_hit = breakpoint_hit_catch_syscall;
612 ops->print_it = print_it_catch_syscall;
613 ops->print_one = print_one_catch_syscall;
614 ops->print_mention = print_mention_catch_syscall;
615 ops->print_recreate = print_recreate_catch_syscall;
616 }
617
618 void
619 _initialize_break_catch_syscall (void)
620 {
621 initialize_syscall_catchpoint_ops ();
622
623 gdb::observers::inferior_exit.attach (clear_syscall_counts);
624 catch_syscall_inferior_data
625 = register_inferior_data_with_cleanup (NULL,
626 catch_syscall_inferior_data_cleanup);
627
628 add_catch_command ("syscall", _("\
629 Catch system calls by their names, groups and/or numbers.\n\
630 Arguments say which system calls to catch. If no arguments are given,\n\
631 every system call will be caught. Arguments, if given, should be one\n\
632 or more system call names (if your system supports that), system call\n\
633 groups or system call numbers."),
634 catch_syscall_command_1,
635 catch_syscall_completer,
636 CATCH_PERMANENT,
637 CATCH_TEMPORARY);
638 }
This page took 0.044322 seconds and 5 git commands to generate.