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