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