1 /* Everything about catch/throw catchpoints, for GDB. 2 3 Copyright (C) 1986-2020 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 "arch-utils.h" 22 #include <ctype.h> 23 #include "breakpoint.h" 24 #include "gdbcmd.h" 25 #include "inferior.h" 26 #include "annotate.h" 27 #include "valprint.h" 28 #include "cli/cli-utils.h" 29 #include "completer.h" 30 #include "gdb_obstack.h" 31 #include "mi/mi-common.h" 32 #include "linespec.h" 33 #include "probe.h" 34 #include "objfiles.h" 35 #include "cp-abi.h" 36 #include "gdb_regex.h" 37 #include "cp-support.h" 38 #include "location.h" 39 40 /* Each spot where we may place an exception-related catchpoint has 41 two names: the SDT probe point and the function name. This 42 structure holds both. */ 43 44 struct exception_names 45 { 46 /* The name of the probe point to try, in the form accepted by 47 'parse_probes'. */ 48 49 const char *probe; 50 51 /* The name of the corresponding function. */ 52 53 const char *function; 54 }; 55 56 /* Names of the probe points and functions on which to break. This is 57 indexed by exception_event_kind. */ 58 static const struct exception_names exception_functions[] = 59 { 60 { "-probe-stap libstdcxx:throw", "__cxa_throw" }, 61 { "-probe-stap libstdcxx:rethrow", "__cxa_rethrow" }, 62 { "-probe-stap libstdcxx:catch", "__cxa_begin_catch" } 63 }; 64 65 static struct breakpoint_ops gnu_v3_exception_catchpoint_ops; 66 67 /* The type of an exception catchpoint. */ 68 69 struct exception_catchpoint : public breakpoint 70 { 71 /* The kind of exception catchpoint. */ 72 73 enum exception_event_kind kind; 74 75 /* If not empty, a string holding the source form of the regular 76 expression to match against. */ 77 78 std::string exception_rx; 79 80 /* If non-NULL, a compiled regular expression which is used to 81 determine which exceptions to stop on. */ 82 83 std::unique_ptr<compiled_regex> pattern; 84 }; 85 86 /* See breakpoint.h. */ 87 88 bool 89 is_exception_catchpoint (breakpoint *bp) 90 { 91 return bp->ops == &gnu_v3_exception_catchpoint_ops; 92 } 93 94 95 96 /* A helper function that fetches exception probe arguments. This 97 fills in *ARG0 (if non-NULL) and *ARG1 (which must be non-NULL). 98 It will throw an exception on any kind of failure. */ 99 100 static void 101 fetch_probe_arguments (struct value **arg0, struct value **arg1) 102 { 103 struct frame_info *frame = get_selected_frame (_("No frame selected")); 104 CORE_ADDR pc = get_frame_pc (frame); 105 struct bound_probe pc_probe; 106 unsigned n_args; 107 108 pc_probe = find_probe_by_pc (pc); 109 if (pc_probe.prob == NULL) 110 error (_("did not find exception probe (does libstdcxx have SDT probes?)")); 111 112 if (pc_probe.prob->get_provider () != "libstdcxx" 113 || (pc_probe.prob->get_name () != "catch" 114 && pc_probe.prob->get_name () != "throw" 115 && pc_probe.prob->get_name () != "rethrow")) 116 error (_("not stopped at a C++ exception catchpoint")); 117 118 n_args = pc_probe.prob->get_argument_count (get_frame_arch (frame)); 119 if (n_args < 2) 120 error (_("C++ exception catchpoint has too few arguments")); 121 122 if (arg0 != NULL) 123 *arg0 = pc_probe.prob->evaluate_argument (0, frame); 124 *arg1 = pc_probe.prob->evaluate_argument (1, frame); 125 126 if ((arg0 != NULL && *arg0 == NULL) || *arg1 == NULL) 127 error (_("error computing probe argument at c++ exception catchpoint")); 128 } 129 130 131 132 /* A helper function that returns a value indicating the kind of the 133 exception catchpoint B. */ 134 135 static enum exception_event_kind 136 classify_exception_breakpoint (struct breakpoint *b) 137 { 138 struct exception_catchpoint *cp = (struct exception_catchpoint *) b; 139 140 return cp->kind; 141 } 142 143 /* Implement the 'check_status' method. */ 144 145 static void 146 check_status_exception_catchpoint (struct bpstats *bs) 147 { 148 struct exception_catchpoint *self 149 = (struct exception_catchpoint *) bs->breakpoint_at; 150 std::string type_name; 151 152 bkpt_breakpoint_ops.check_status (bs); 153 if (bs->stop == 0) 154 return; 155 156 if (self->pattern == NULL) 157 return; 158 159 const char *name = nullptr; 160 gdb::unique_xmalloc_ptr<char> canon; 161 try 162 { 163 struct value *typeinfo_arg; 164 165 fetch_probe_arguments (NULL, &typeinfo_arg); 166 type_name = cplus_typename_from_type_info (typeinfo_arg); 167 168 canon = cp_canonicalize_string (type_name.c_str ()); 169 name = (canon != nullptr 170 ? canon.get () 171 : type_name.c_str ()); 172 } 173 catch (const gdb_exception_error &e) 174 { 175 exception_print (gdb_stderr, e); 176 } 177 178 if (name != nullptr) 179 { 180 if (self->pattern->exec (name, 0, NULL, 0) != 0) 181 bs->stop = 0; 182 } 183 } 184 185 /* Implement the 're_set' method. */ 186 187 static void 188 re_set_exception_catchpoint (struct breakpoint *self) 189 { 190 std::vector<symtab_and_line> sals; 191 enum exception_event_kind kind = classify_exception_breakpoint (self); 192 struct program_space *filter_pspace = current_program_space; 193 194 /* We first try to use the probe interface. */ 195 try 196 { 197 event_location_up location 198 = new_probe_location (exception_functions[kind].probe); 199 sals = parse_probes (location.get (), filter_pspace, NULL); 200 } 201 catch (const gdb_exception_error &e) 202 { 203 /* Using the probe interface failed. Let's fallback to the normal 204 catchpoint mode. */ 205 try 206 { 207 struct explicit_location explicit_loc; 208 209 initialize_explicit_location (&explicit_loc); 210 explicit_loc.function_name 211 = ASTRDUP (exception_functions[kind].function); 212 event_location_up location = new_explicit_location (&explicit_loc); 213 sals = self->ops->decode_location (self, location.get (), 214 filter_pspace); 215 } 216 catch (const gdb_exception_error &ex) 217 { 218 /* NOT_FOUND_ERROR just means the breakpoint will be 219 pending, so let it through. */ 220 if (ex.error != NOT_FOUND_ERROR) 221 throw; 222 } 223 } 224 225 update_breakpoint_locations (self, filter_pspace, sals, {}); 226 } 227 228 static enum print_stop_action 229 print_it_exception_catchpoint (bpstat bs) 230 { 231 struct ui_out *uiout = current_uiout; 232 struct breakpoint *b = bs->breakpoint_at; 233 int bp_temp; 234 enum exception_event_kind kind = classify_exception_breakpoint (b); 235 236 annotate_catchpoint (b->number); 237 maybe_print_thread_hit_breakpoint (uiout); 238 239 bp_temp = b->disposition == disp_del; 240 uiout->text (bp_temp ? "Temporary catchpoint " 241 : "Catchpoint "); 242 uiout->field_signed ("bkptno", b->number); 243 uiout->text ((kind == EX_EVENT_THROW ? " (exception thrown), " 244 : (kind == EX_EVENT_CATCH ? " (exception caught), " 245 : " (exception rethrown), "))); 246 if (uiout->is_mi_like_p ()) 247 { 248 uiout->field_string ("reason", 249 async_reason_lookup (EXEC_ASYNC_BREAKPOINT_HIT)); 250 uiout->field_string ("disp", bpdisp_text (b->disposition)); 251 } 252 return PRINT_SRC_AND_LOC; 253 } 254 255 static void 256 print_one_exception_catchpoint (struct breakpoint *b, 257 struct bp_location **last_loc) 258 { 259 struct value_print_options opts; 260 struct ui_out *uiout = current_uiout; 261 enum exception_event_kind kind = classify_exception_breakpoint (b); 262 263 get_user_print_options (&opts); 264 265 if (opts.addressprint) 266 uiout->field_skip ("addr"); 267 annotate_field (5); 268 269 switch (kind) 270 { 271 case EX_EVENT_THROW: 272 uiout->field_string ("what", "exception throw"); 273 if (uiout->is_mi_like_p ()) 274 uiout->field_string ("catch-type", "throw"); 275 break; 276 277 case EX_EVENT_RETHROW: 278 uiout->field_string ("what", "exception rethrow"); 279 if (uiout->is_mi_like_p ()) 280 uiout->field_string ("catch-type", "rethrow"); 281 break; 282 283 case EX_EVENT_CATCH: 284 uiout->field_string ("what", "exception catch"); 285 if (uiout->is_mi_like_p ()) 286 uiout->field_string ("catch-type", "catch"); 287 break; 288 } 289 } 290 291 /* Implement the 'print_one_detail' method. */ 292 293 static void 294 print_one_detail_exception_catchpoint (const struct breakpoint *b, 295 struct ui_out *uiout) 296 { 297 const struct exception_catchpoint *cp 298 = (const struct exception_catchpoint *) b; 299 300 if (!cp->exception_rx.empty ()) 301 { 302 uiout->text (_("\tmatching: ")); 303 uiout->field_string ("regexp", cp->exception_rx.c_str ()); 304 uiout->text ("\n"); 305 } 306 } 307 308 static void 309 print_mention_exception_catchpoint (struct breakpoint *b) 310 { 311 struct ui_out *uiout = current_uiout; 312 int bp_temp; 313 enum exception_event_kind kind = classify_exception_breakpoint (b); 314 315 bp_temp = b->disposition == disp_del; 316 uiout->message ("%s %d %s", 317 (bp_temp ? _("Temporary catchpoint ") : _("Catchpoint")), 318 b->number, 319 (kind == EX_EVENT_THROW 320 ? _("(throw)") : (kind == EX_EVENT_CATCH 321 ? _("(catch)") : _("(rethrow)")))); 322 } 323 324 /* Implement the "print_recreate" breakpoint_ops method for throw and 325 catch catchpoints. */ 326 327 static void 328 print_recreate_exception_catchpoint (struct breakpoint *b, 329 struct ui_file *fp) 330 { 331 int bp_temp; 332 enum exception_event_kind kind = classify_exception_breakpoint (b); 333 334 bp_temp = b->disposition == disp_del; 335 fprintf_unfiltered (fp, bp_temp ? "tcatch " : "catch "); 336 switch (kind) 337 { 338 case EX_EVENT_THROW: 339 fprintf_unfiltered (fp, "throw"); 340 break; 341 case EX_EVENT_CATCH: 342 fprintf_unfiltered (fp, "catch"); 343 break; 344 case EX_EVENT_RETHROW: 345 fprintf_unfiltered (fp, "rethrow"); 346 break; 347 } 348 print_recreate_thread (b, fp); 349 } 350 351 /* Implement the "allocate_location" breakpoint_ops method for throw 352 and catch catchpoints. */ 353 354 static bp_location * 355 allocate_location_exception_catchpoint (breakpoint *self) 356 { 357 return new bp_location (self, bp_loc_software_breakpoint); 358 } 359 360 static void 361 handle_gnu_v3_exceptions (int tempflag, std::string &&except_rx, 362 const char *cond_string, 363 enum exception_event_kind ex_event, int from_tty) 364 { 365 std::unique_ptr<compiled_regex> pattern; 366 367 if (!except_rx.empty ()) 368 { 369 pattern.reset (new compiled_regex (except_rx.c_str (), REG_NOSUB, 370 _("invalid type-matching regexp"))); 371 } 372 373 std::unique_ptr<exception_catchpoint> cp (new exception_catchpoint ()); 374 375 init_catchpoint (cp.get (), get_current_arch (), tempflag, cond_string, 376 &gnu_v3_exception_catchpoint_ops); 377 cp->kind = ex_event; 378 cp->exception_rx = std::move (except_rx); 379 cp->pattern = std::move (pattern); 380 381 re_set_exception_catchpoint (cp.get ()); 382 383 install_breakpoint (0, std::move (cp), 1); 384 } 385 386 /* Look for an "if" token in *STRING. The "if" token must be preceded 387 by whitespace. 388 389 If there is any non-whitespace text between *STRING and the "if" 390 token, then it is returned in a newly-xmalloc'd string. Otherwise, 391 this returns NULL. 392 393 STRING is updated to point to the "if" token, if it exists, or to 394 the end of the string. */ 395 396 static std::string 397 extract_exception_regexp (const char **string) 398 { 399 const char *start; 400 const char *last, *last_space; 401 402 start = skip_spaces (*string); 403 404 last = start; 405 last_space = start; 406 while (*last != '\0') 407 { 408 const char *if_token = last; 409 410 /* Check for the "if". */ 411 if (check_for_argument (&if_token, "if", 2)) 412 break; 413 414 /* No "if" token here. Skip to the next word start. */ 415 last_space = skip_to_space (last); 416 last = skip_spaces (last_space); 417 } 418 419 *string = last; 420 if (last_space > start) 421 return std::string (start, last_space - start); 422 return std::string (); 423 } 424 425 /* See breakpoint.h. */ 426 427 void 428 catch_exception_event (enum exception_event_kind ex_event, 429 const char *arg, bool tempflag, int from_tty) 430 { 431 const char *cond_string = NULL; 432 433 if (!arg) 434 arg = ""; 435 arg = skip_spaces (arg); 436 437 std::string except_rx = extract_exception_regexp (&arg); 438 439 cond_string = ep_parse_optional_if_clause (&arg); 440 441 if ((*arg != '\0') && !isspace (*arg)) 442 error (_("Junk at end of arguments.")); 443 444 if (ex_event != EX_EVENT_THROW 445 && ex_event != EX_EVENT_CATCH 446 && ex_event != EX_EVENT_RETHROW) 447 error (_("Unsupported or unknown exception event; cannot catch it")); 448 449 handle_gnu_v3_exceptions (tempflag, std::move (except_rx), cond_string, 450 ex_event, from_tty); 451 } 452 453 /* Implementation of "catch catch" command. */ 454 455 static void 456 catch_catch_command (const char *arg, int from_tty, 457 struct cmd_list_element *command) 458 { 459 bool tempflag = get_cmd_context (command) == CATCH_TEMPORARY; 460 461 catch_exception_event (EX_EVENT_CATCH, arg, tempflag, from_tty); 462 } 463 464 /* Implementation of "catch throw" command. */ 465 466 static void 467 catch_throw_command (const char *arg, int from_tty, 468 struct cmd_list_element *command) 469 { 470 bool tempflag = get_cmd_context (command) == CATCH_TEMPORARY; 471 472 catch_exception_event (EX_EVENT_THROW, arg, tempflag, from_tty); 473 } 474 475 /* Implementation of "catch rethrow" command. */ 476 477 static void 478 catch_rethrow_command (const char *arg, int from_tty, 479 struct cmd_list_element *command) 480 { 481 bool tempflag = get_cmd_context (command) == CATCH_TEMPORARY; 482 483 catch_exception_event (EX_EVENT_RETHROW, arg, tempflag, from_tty); 484 } 485 486 487 488 /* Implement the 'make_value' method for the $_exception 489 internalvar. */ 490 491 static struct value * 492 compute_exception (struct gdbarch *argc, struct internalvar *var, void *ignore) 493 { 494 struct value *arg0, *arg1; 495 struct type *obj_type; 496 497 fetch_probe_arguments (&arg0, &arg1); 498 499 /* ARG0 is a pointer to the exception object. ARG1 is a pointer to 500 the std::type_info for the exception. Now we find the type from 501 the type_info and cast the result. */ 502 obj_type = cplus_type_from_type_info (arg1); 503 return value_ind (value_cast (make_pointer_type (obj_type, NULL), arg0)); 504 } 505 506 /* Implementation of the '$_exception' variable. */ 507 508 static const struct internalvar_funcs exception_funcs = 509 { 510 compute_exception, 511 NULL, 512 NULL 513 }; 514 515 516 517 static void 518 initialize_throw_catchpoint_ops (void) 519 { 520 struct breakpoint_ops *ops; 521 522 initialize_breakpoint_ops (); 523 524 /* GNU v3 exception catchpoints. */ 525 ops = &gnu_v3_exception_catchpoint_ops; 526 *ops = bkpt_breakpoint_ops; 527 ops->re_set = re_set_exception_catchpoint; 528 ops->print_it = print_it_exception_catchpoint; 529 ops->print_one = print_one_exception_catchpoint; 530 ops->print_mention = print_mention_exception_catchpoint; 531 ops->print_recreate = print_recreate_exception_catchpoint; 532 ops->print_one_detail = print_one_detail_exception_catchpoint; 533 ops->check_status = check_status_exception_catchpoint; 534 ops->allocate_location = allocate_location_exception_catchpoint; 535 } 536 537 void _initialize_break_catch_throw (); 538 void 539 _initialize_break_catch_throw () 540 { 541 initialize_throw_catchpoint_ops (); 542 543 /* Add catch and tcatch sub-commands. */ 544 add_catch_command ("catch", _("\ 545 Catch an exception, when caught."), 546 catch_catch_command, 547 NULL, 548 CATCH_PERMANENT, 549 CATCH_TEMPORARY); 550 add_catch_command ("throw", _("\ 551 Catch an exception, when thrown."), 552 catch_throw_command, 553 NULL, 554 CATCH_PERMANENT, 555 CATCH_TEMPORARY); 556 add_catch_command ("rethrow", _("\ 557 Catch an exception, when rethrown."), 558 catch_rethrow_command, 559 NULL, 560 CATCH_PERMANENT, 561 CATCH_TEMPORARY); 562 563 create_internalvar_type_lazy ("_exception", &exception_funcs, NULL); 564 } 565