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