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