Use forward_scope_exit for scoped_finish_thread_state
[deliverable/binutils-gdb.git] / gdb / break-catch-syscall.c
1 /* Everything about syscall catchpoints, for GDB.
2
3 Copyright (C) 2009-2019 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 *previous_text = 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 previous_text because xstrprintf dynamically
278 allocates new space for text on every call. */
279 xfree (previous_text);
280 }
281 /* Remove the last comma. */
282 text[strlen (text) - 2] = '\0';
283 uiout->field_string ("what", text);
284 /* xfree last text. */
285 xfree (text);
286 }
287 else
288 uiout->field_string ("what", "<any syscall>");
289 uiout->text ("\" ");
290
291 if (uiout->is_mi_like_p ())
292 uiout->field_string ("catch-type", "syscall");
293 }
294
295 /* Implement the "print_mention" breakpoint_ops method for syscall
296 catchpoints. */
297
298 static void
299 print_mention_catch_syscall (struct breakpoint *b)
300 {
301 struct syscall_catchpoint *c = (struct syscall_catchpoint *) b;
302 struct gdbarch *gdbarch = b->loc->gdbarch;
303
304 if (!c->syscalls_to_be_caught.empty ())
305 {
306 if (c->syscalls_to_be_caught.size () > 1)
307 printf_filtered (_("Catchpoint %d (syscalls"), b->number);
308 else
309 printf_filtered (_("Catchpoint %d (syscall"), b->number);
310
311 for (int iter : c->syscalls_to_be_caught)
312 {
313 struct syscall s;
314 get_syscall_by_number (gdbarch, iter, &s);
315
316 if (s.name != NULL)
317 printf_filtered (" '%s' [%d]", s.name, s.number);
318 else
319 printf_filtered (" %d", s.number);
320 }
321 printf_filtered (")");
322 }
323 else
324 printf_filtered (_("Catchpoint %d (any syscall)"),
325 b->number);
326 }
327
328 /* Implement the "print_recreate" breakpoint_ops method for syscall
329 catchpoints. */
330
331 static void
332 print_recreate_catch_syscall (struct breakpoint *b, struct ui_file *fp)
333 {
334 struct syscall_catchpoint *c = (struct syscall_catchpoint *) b;
335 struct gdbarch *gdbarch = b->loc->gdbarch;
336
337 fprintf_unfiltered (fp, "catch syscall");
338
339 for (int iter : c->syscalls_to_be_caught)
340 {
341 struct syscall s;
342
343 get_syscall_by_number (gdbarch, iter, &s);
344 if (s.name != NULL)
345 fprintf_unfiltered (fp, " %s", s.name);
346 else
347 fprintf_unfiltered (fp, " %d", s.number);
348 }
349
350 print_recreate_thread (b, fp);
351 }
352
353 /* The breakpoint_ops structure to be used in syscall catchpoints. */
354
355 static struct breakpoint_ops catch_syscall_breakpoint_ops;
356
357 /* Returns non-zero if 'b' is a syscall catchpoint. */
358
359 static int
360 syscall_catchpoint_p (struct breakpoint *b)
361 {
362 return (b->ops == &catch_syscall_breakpoint_ops);
363 }
364
365 static void
366 create_syscall_event_catchpoint (int tempflag, std::vector<int> &&filter,
367 const struct breakpoint_ops *ops)
368 {
369 struct gdbarch *gdbarch = get_current_arch ();
370
371 std::unique_ptr<syscall_catchpoint> c (new syscall_catchpoint ());
372 init_catchpoint (c.get (), gdbarch, tempflag, NULL, ops);
373 c->syscalls_to_be_caught = std::move (filter);
374
375 install_breakpoint (0, std::move (c), 1);
376 }
377
378 /* Splits the argument using space as delimiter. */
379
380 static std::vector<int>
381 catch_syscall_split_args (const char *arg)
382 {
383 std::vector<int> result;
384 struct gdbarch *gdbarch = target_gdbarch ();
385
386 while (*arg != '\0')
387 {
388 int i, syscall_number;
389 char *endptr;
390 char cur_name[128];
391 struct syscall s;
392
393 /* Skip whitespace. */
394 arg = skip_spaces (arg);
395
396 for (i = 0; i < 127 && arg[i] && !isspace (arg[i]); ++i)
397 cur_name[i] = arg[i];
398 cur_name[i] = '\0';
399 arg += i;
400
401 /* Check if the user provided a syscall name, group, or a number. */
402 syscall_number = (int) strtol (cur_name, &endptr, 0);
403 if (*endptr == '\0')
404 {
405 get_syscall_by_number (gdbarch, syscall_number, &s);
406 result.push_back (s.number);
407 }
408 else if (startswith (cur_name, "g:")
409 || startswith (cur_name, "group:"))
410 {
411 /* We have a syscall group. Let's expand it into a syscall
412 list before inserting. */
413 const char *group_name;
414
415 /* Skip over "g:" and "group:" prefix strings. */
416 group_name = strchr (cur_name, ':') + 1;
417
418 if (!get_syscalls_by_group (gdbarch, group_name, &result))
419 error (_("Unknown syscall group '%s'."), group_name);
420 }
421 else
422 {
423 /* We have a name. Let's check if it's valid and fetch a
424 list of matching numbers. */
425 if (!get_syscalls_by_name (gdbarch, cur_name, &result))
426 /* Here we have to issue an error instead of a warning,
427 because GDB cannot do anything useful if there's no
428 syscall number to be caught. */
429 error (_("Unknown syscall name '%s'."), cur_name);
430 }
431 }
432
433 return result;
434 }
435
436 /* Implement the "catch syscall" command. */
437
438 static void
439 catch_syscall_command_1 (const char *arg, int from_tty,
440 struct cmd_list_element *command)
441 {
442 int tempflag;
443 std::vector<int> filter;
444 struct syscall s;
445 struct gdbarch *gdbarch = get_current_arch ();
446
447 /* Checking if the feature if supported. */
448 if (gdbarch_get_syscall_number_p (gdbarch) == 0)
449 error (_("The feature 'catch syscall' is not supported on \
450 this architecture yet."));
451
452 tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
453
454 arg = skip_spaces (arg);
455
456 /* We need to do this first "dummy" translation in order
457 to get the syscall XML file loaded or, most important,
458 to display a warning to the user if there's no XML file
459 for his/her architecture. */
460 get_syscall_by_number (gdbarch, 0, &s);
461
462 /* The allowed syntax is:
463 catch syscall
464 catch syscall <name | number> [<name | number> ... <name | number>]
465
466 Let's check if there's a syscall name. */
467
468 if (arg != NULL)
469 filter = catch_syscall_split_args (arg);
470
471 create_syscall_event_catchpoint (tempflag, std::move (filter),
472 &catch_syscall_breakpoint_ops);
473 }
474
475
476 /* Returns 0 if 'bp' is NOT a syscall catchpoint,
477 non-zero otherwise. */
478 static int
479 is_syscall_catchpoint_enabled (struct breakpoint *bp)
480 {
481 if (syscall_catchpoint_p (bp)
482 && bp->enable_state != bp_disabled
483 && bp->enable_state != bp_call_disabled)
484 return 1;
485 else
486 return 0;
487 }
488
489 int
490 catch_syscall_enabled (void)
491 {
492 struct catch_syscall_inferior_data *inf_data
493 = get_catch_syscall_inferior_data (current_inferior ());
494
495 return inf_data->total_syscalls_count != 0;
496 }
497
498 /* Helper function for catching_syscall_number. If B is a syscall
499 catchpoint for SYSCALL_NUMBER, return 1 (which will make
500 'breakpoint_find_if' return). Otherwise, return 0. */
501
502 static int
503 catching_syscall_number_1 (struct breakpoint *b,
504 void *data)
505 {
506 int syscall_number = (int) (uintptr_t) data;
507
508 if (is_syscall_catchpoint_enabled (b))
509 {
510 struct syscall_catchpoint *c = (struct syscall_catchpoint *) b;
511
512 if (!c->syscalls_to_be_caught.empty ())
513 {
514 for (int iter : c->syscalls_to_be_caught)
515 if (syscall_number == iter)
516 return 1;
517 }
518 else
519 return 1;
520 }
521
522 return 0;
523 }
524
525 int
526 catching_syscall_number (int syscall_number)
527 {
528 struct breakpoint *b = breakpoint_find_if (catching_syscall_number_1,
529 (void *) (uintptr_t) syscall_number);
530
531 return b != NULL;
532 }
533
534 /* Complete syscall names. Used by "catch syscall". */
535
536 static void
537 catch_syscall_completer (struct cmd_list_element *cmd,
538 completion_tracker &tracker,
539 const char *text, const char *word)
540 {
541 struct gdbarch *gdbarch = get_current_arch ();
542 gdb::unique_xmalloc_ptr<const char *> group_list;
543 const char *prefix;
544
545 /* Completion considers ':' to be a word separator, so we use this to
546 verify whether the previous word was a group prefix. If so, we
547 build the completion list using group names only. */
548 for (prefix = word; prefix != text && prefix[-1] != ' '; prefix--)
549 ;
550
551 if (startswith (prefix, "g:") || startswith (prefix, "group:"))
552 {
553 /* Perform completion inside 'group:' namespace only. */
554 group_list.reset (get_syscall_group_names (gdbarch));
555 if (group_list != NULL)
556 complete_on_enum (tracker, group_list.get (), word, word);
557 }
558 else
559 {
560 /* Complete with both, syscall names and groups. */
561 gdb::unique_xmalloc_ptr<const char *> syscall_list
562 (get_syscall_names (gdbarch));
563 group_list.reset (get_syscall_group_names (gdbarch));
564
565 const char **group_ptr = group_list.get ();
566
567 /* Hold on to strings while we're using them. */
568 std::vector<std::string> holders;
569
570 /* Append "group:" prefix to syscall groups. */
571 for (int i = 0; group_ptr[i] != NULL; i++)
572 holders.push_back (string_printf ("group:%s", group_ptr[i]));
573
574 for (int i = 0; group_ptr[i] != NULL; i++)
575 group_ptr[i] = holders[i].c_str ();
576
577 if (syscall_list != NULL)
578 complete_on_enum (tracker, syscall_list.get (), word, word);
579 if (group_list != NULL)
580 complete_on_enum (tracker, group_ptr, word, word);
581 }
582 }
583
584 static void
585 clear_syscall_counts (struct inferior *inf)
586 {
587 struct catch_syscall_inferior_data *inf_data
588 = get_catch_syscall_inferior_data (inf);
589
590 inf_data->total_syscalls_count = 0;
591 inf_data->any_syscall_count = 0;
592 inf_data->syscalls_counts.clear ();
593 }
594
595 static void
596 initialize_syscall_catchpoint_ops (void)
597 {
598 struct breakpoint_ops *ops;
599
600 initialize_breakpoint_ops ();
601
602 /* Syscall catchpoints. */
603 ops = &catch_syscall_breakpoint_ops;
604 *ops = base_breakpoint_ops;
605 ops->insert_location = insert_catch_syscall;
606 ops->remove_location = remove_catch_syscall;
607 ops->breakpoint_hit = breakpoint_hit_catch_syscall;
608 ops->print_it = print_it_catch_syscall;
609 ops->print_one = print_one_catch_syscall;
610 ops->print_mention = print_mention_catch_syscall;
611 ops->print_recreate = print_recreate_catch_syscall;
612 }
613
614 void
615 _initialize_break_catch_syscall (void)
616 {
617 initialize_syscall_catchpoint_ops ();
618
619 gdb::observers::inferior_exit.attach (clear_syscall_counts);
620 catch_syscall_inferior_data
621 = register_inferior_data_with_cleanup (NULL,
622 catch_syscall_inferior_data_cleanup);
623
624 add_catch_command ("syscall", _("\
625 Catch system calls by their names, groups and/or numbers.\n\
626 Arguments say which system calls to catch. If no arguments are given,\n\
627 every system call will be caught. Arguments, if given, should be one\n\
628 or more system call names (if your system supports that), system call\n\
629 groups or system call numbers."),
630 catch_syscall_command_1,
631 catch_syscall_completer,
632 CATCH_PERMANENT,
633 CATCH_TEMPORARY);
634 }
This page took 0.055992 seconds and 4 git commands to generate.