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