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