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