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