Commit | Line | Data |
---|---|---|
916703c0 TT |
1 | /* Everything about catch/throw catchpoints, for GDB. |
2 | ||
32d0add0 | 3 | Copyright (C) 1986-2015 Free Software Foundation, Inc. |
916703c0 TT |
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" | |
15a73f56 | 32 | #include "linespec.h" |
fc4746a2 | 33 | #include "probe.h" |
72f1fe8a TT |
34 | #include "objfiles.h" |
35 | #include "cp-abi.h" | |
cc16e6c9 TT |
36 | #include "gdb_regex.h" |
37 | #include "cp-support.h" | |
916703c0 TT |
38 | |
39 | /* Enums for exception-handling support. */ | |
40 | enum exception_event_kind | |
41 | { | |
42 | EX_EVENT_THROW, | |
43 | EX_EVENT_RETHROW, | |
44 | EX_EVENT_CATCH | |
45 | }; | |
46 | ||
fc4746a2 TT |
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 | ||
51 | struct 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. */ | |
65 | static const struct exception_names exception_functions[] = | |
15a73f56 | 66 | { |
fc4746a2 TT |
67 | { "-probe-stap libstdcxx:throw", "__cxa_throw" }, |
68 | { "-probe-stap libstdcxx:rethrow", "__cxa_rethrow" }, | |
69 | { "-probe-stap libstdcxx:catch", "__cxa_begin_catch" } | |
15a73f56 TT |
70 | }; |
71 | ||
72 | static struct breakpoint_ops gnu_v3_exception_catchpoint_ops; | |
73 | ||
74 | /* The type of an exception catchpoint. */ | |
75 | ||
76 | struct 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; | |
cc16e6c9 TT |
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; | |
15a73f56 TT |
95 | }; |
96 | ||
cc16e6c9 TT |
97 | \f |
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 | ||
103 | static void | |
104 | fetch_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); | |
729662a5 | 108 | struct bound_probe pc_probe; |
cc16e6c9 TT |
109 | const struct sym_probe_fns *pc_probe_fns; |
110 | unsigned n_args; | |
111 | ||
112 | pc_probe = find_probe_by_pc (pc); | |
729662a5 TT |
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)) | |
cc16e6c9 TT |
118 | error (_("not stopped at a C++ exception catchpoint")); |
119 | ||
729662a5 | 120 | n_args = get_probe_argument_count (pc_probe.probe, frame); |
cc16e6c9 TT |
121 | if (n_args < 2) |
122 | error (_("C++ exception catchpoint has too few arguments")); | |
123 | ||
124 | if (arg0 != NULL) | |
729662a5 TT |
125 | *arg0 = evaluate_probe_argument (pc_probe.probe, 0, frame); |
126 | *arg1 = evaluate_probe_argument (pc_probe.probe, 1, frame); | |
cc16e6c9 TT |
127 | |
128 | if ((arg0 != NULL && *arg0 == NULL) || *arg1 == NULL) | |
129 | error (_("error computing probe argument at c++ exception catchpoint")); | |
130 | } | |
131 | ||
132 | \f | |
133 | ||
916703c0 TT |
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 | { | |
15a73f56 TT |
140 | struct exception_catchpoint *cp = (struct exception_catchpoint *) b; |
141 | ||
142 | return cp->kind; | |
143 | } | |
144 | ||
cc16e6c9 TT |
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; | |
fe978cb0 | 165 | char *type_name = NULL; |
cc16e6c9 TT |
166 | |
167 | bkpt_breakpoint_ops.check_status (bs); | |
168 | if (bs->stop == 0) | |
169 | return; | |
170 | ||
171 | if (self->pattern == NULL) | |
172 | return; | |
173 | ||
492d29ea | 174 | TRY |
cc16e6c9 TT |
175 | { |
176 | struct value *typeinfo_arg; | |
177 | char *canon; | |
178 | ||
179 | fetch_probe_arguments (NULL, &typeinfo_arg); | |
fe978cb0 | 180 | type_name = cplus_typename_from_type_info (typeinfo_arg); |
cc16e6c9 | 181 | |
fe978cb0 | 182 | canon = cp_canonicalize_string (type_name); |
cc16e6c9 TT |
183 | if (canon != NULL) |
184 | { | |
fe978cb0 PA |
185 | xfree (type_name); |
186 | type_name = canon; | |
cc16e6c9 TT |
187 | } |
188 | } | |
492d29ea PA |
189 | CATCH (e, RETURN_MASK_ERROR) |
190 | { | |
191 | exception_print (gdb_stderr, e); | |
192 | } | |
193 | END_CATCH | |
cc16e6c9 | 194 | |
7556d4a4 PA |
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 | } | |
cc16e6c9 TT |
202 | } |
203 | ||
15a73f56 TT |
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}; | |
15a73f56 TT |
211 | struct cleanup *cleanup; |
212 | enum exception_event_kind kind = classify_exception_breakpoint (self); | |
213 | ||
1bff71c3 | 214 | /* We first try to use the probe interface. */ |
492d29ea | 215 | TRY |
15a73f56 | 216 | { |
1bff71c3 SDJ |
217 | char *spec = ASTRDUP (exception_functions[kind].probe); |
218 | ||
219 | sals = parse_probes (&spec, NULL); | |
220 | } | |
221 | ||
492d29ea | 222 | CATCH (e, RETURN_MASK_ERROR) |
1bff71c3 | 223 | { |
1bff71c3 SDJ |
224 | |
225 | /* Using the probe interface failed. Let's fallback to the normal | |
226 | catchpoint mode. */ | |
492d29ea | 227 | TRY |
fc4746a2 | 228 | { |
1bff71c3 SDJ |
229 | char *spec = ASTRDUP (exception_functions[kind].function); |
230 | ||
231 | self->ops->decode_linespec (self, &spec, &sals); | |
fc4746a2 | 232 | } |
492d29ea | 233 | CATCH (ex, RETURN_MASK_ERROR) |
7556d4a4 PA |
234 | { |
235 | /* NOT_FOUND_ERROR just means the breakpoint will be | |
236 | pending, so let it through. */ | |
237 | if (ex.error != NOT_FOUND_ERROR) | |
238 | throw_exception (ex); | |
239 | } | |
492d29ea | 240 | END_CATCH |
15a73f56 | 241 | } |
492d29ea | 242 | END_CATCH |
15a73f56 TT |
243 | |
244 | cleanup = make_cleanup (xfree, sals.sals); | |
245 | update_breakpoint_locations (self, sals, sals_end); | |
246 | do_cleanups (cleanup); | |
916703c0 TT |
247 | } |
248 | ||
249 | static enum print_stop_action | |
250 | print_it_exception_catchpoint (bpstat bs) | |
251 | { | |
252 | struct ui_out *uiout = current_uiout; | |
253 | struct breakpoint *b = bs->breakpoint_at; | |
254 | int bp_temp; | |
255 | enum exception_event_kind kind = classify_exception_breakpoint (b); | |
256 | ||
257 | annotate_catchpoint (b->number); | |
258 | ||
259 | bp_temp = b->disposition == disp_del; | |
260 | ui_out_text (uiout, | |
261 | bp_temp ? "Temporary catchpoint " | |
262 | : "Catchpoint "); | |
263 | if (!ui_out_is_mi_like_p (uiout)) | |
264 | ui_out_field_int (uiout, "bkptno", b->number); | |
265 | ui_out_text (uiout, | |
266 | (kind == EX_EVENT_THROW ? " (exception thrown), " | |
267 | : (kind == EX_EVENT_CATCH ? " (exception caught), " | |
268 | : " (exception rethrown), "))); | |
269 | if (ui_out_is_mi_like_p (uiout)) | |
270 | { | |
271 | ui_out_field_string (uiout, "reason", | |
272 | async_reason_lookup (EXEC_ASYNC_BREAKPOINT_HIT)); | |
273 | ui_out_field_string (uiout, "disp", bpdisp_text (b->disposition)); | |
274 | ui_out_field_int (uiout, "bkptno", b->number); | |
275 | } | |
276 | return PRINT_SRC_AND_LOC; | |
277 | } | |
278 | ||
279 | static void | |
280 | print_one_exception_catchpoint (struct breakpoint *b, | |
281 | struct bp_location **last_loc) | |
282 | { | |
283 | struct value_print_options opts; | |
284 | struct ui_out *uiout = current_uiout; | |
285 | enum exception_event_kind kind = classify_exception_breakpoint (b); | |
286 | ||
287 | get_user_print_options (&opts); | |
288 | if (opts.addressprint) | |
289 | { | |
290 | annotate_field (4); | |
291 | if (b->loc == NULL || b->loc->shlib_disabled) | |
292 | ui_out_field_string (uiout, "addr", "<PENDING>"); | |
293 | else | |
294 | ui_out_field_core_addr (uiout, "addr", | |
295 | b->loc->gdbarch, b->loc->address); | |
296 | } | |
297 | annotate_field (5); | |
298 | if (b->loc) | |
299 | *last_loc = b->loc; | |
300 | ||
301 | switch (kind) | |
302 | { | |
303 | case EX_EVENT_THROW: | |
304 | ui_out_field_string (uiout, "what", "exception throw"); | |
305 | if (ui_out_is_mi_like_p (uiout)) | |
306 | ui_out_field_string (uiout, "catch-type", "throw"); | |
307 | break; | |
308 | ||
309 | case EX_EVENT_RETHROW: | |
310 | ui_out_field_string (uiout, "what", "exception rethrow"); | |
311 | if (ui_out_is_mi_like_p (uiout)) | |
312 | ui_out_field_string (uiout, "catch-type", "rethrow"); | |
313 | break; | |
314 | ||
315 | case EX_EVENT_CATCH: | |
316 | ui_out_field_string (uiout, "what", "exception catch"); | |
317 | if (ui_out_is_mi_like_p (uiout)) | |
318 | ui_out_field_string (uiout, "catch-type", "catch"); | |
319 | break; | |
320 | } | |
321 | } | |
322 | ||
cc16e6c9 TT |
323 | /* Implement the 'print_one_detail' method. */ |
324 | ||
325 | static void | |
326 | print_one_detail_exception_catchpoint (const struct breakpoint *b, | |
327 | struct ui_out *uiout) | |
328 | { | |
329 | const struct exception_catchpoint *cp | |
330 | = (const struct exception_catchpoint *) b; | |
331 | ||
332 | if (cp->exception_rx != NULL) | |
333 | { | |
334 | ui_out_text (uiout, _("\tmatching: ")); | |
335 | ui_out_field_string (uiout, "regexp", cp->exception_rx); | |
336 | ui_out_text (uiout, "\n"); | |
337 | } | |
338 | } | |
339 | ||
916703c0 TT |
340 | static void |
341 | print_mention_exception_catchpoint (struct breakpoint *b) | |
342 | { | |
343 | struct ui_out *uiout = current_uiout; | |
344 | int bp_temp; | |
345 | enum exception_event_kind kind = classify_exception_breakpoint (b); | |
346 | ||
347 | bp_temp = b->disposition == disp_del; | |
348 | ui_out_text (uiout, bp_temp ? _("Temporary catchpoint ") | |
349 | : _("Catchpoint ")); | |
350 | ui_out_field_int (uiout, "bkptno", b->number); | |
351 | ui_out_text (uiout, (kind == EX_EVENT_THROW ? _(" (throw)") | |
352 | : (kind == EX_EVENT_CATCH ? _(" (catch)") | |
353 | : _(" (rethrow)")))); | |
354 | } | |
355 | ||
356 | /* Implement the "print_recreate" breakpoint_ops method for throw and | |
357 | catch catchpoints. */ | |
358 | ||
359 | static void | |
360 | print_recreate_exception_catchpoint (struct breakpoint *b, | |
361 | struct ui_file *fp) | |
362 | { | |
363 | int bp_temp; | |
364 | enum exception_event_kind kind = classify_exception_breakpoint (b); | |
365 | ||
366 | bp_temp = b->disposition == disp_del; | |
367 | fprintf_unfiltered (fp, bp_temp ? "tcatch " : "catch "); | |
368 | switch (kind) | |
369 | { | |
370 | case EX_EVENT_THROW: | |
371 | fprintf_unfiltered (fp, "throw"); | |
372 | break; | |
373 | case EX_EVENT_CATCH: | |
374 | fprintf_unfiltered (fp, "catch"); | |
375 | break; | |
376 | case EX_EVENT_RETHROW: | |
377 | fprintf_unfiltered (fp, "rethrow"); | |
378 | break; | |
379 | } | |
380 | print_recreate_thread (b, fp); | |
381 | } | |
382 | ||
15a73f56 | 383 | static void |
cc16e6c9 | 384 | handle_gnu_v3_exceptions (int tempflag, char *except_rx, char *cond_string, |
916703c0 TT |
385 | enum exception_event_kind ex_event, int from_tty) |
386 | { | |
15a73f56 | 387 | struct exception_catchpoint *cp; |
cc16e6c9 TT |
388 | struct cleanup *cleanup = make_cleanup (null_cleanup, NULL); |
389 | regex_t *pattern = NULL; | |
390 | ||
391 | if (except_rx != NULL) | |
392 | { | |
393 | pattern = XNEW (regex_t); | |
394 | make_cleanup (xfree, pattern); | |
395 | ||
396 | compile_rx_or_error (pattern, except_rx, | |
397 | _("invalid type-matching regexp")); | |
398 | } | |
916703c0 | 399 | |
15a73f56 | 400 | cp = XCNEW (struct exception_catchpoint); |
cc16e6c9 TT |
401 | make_cleanup (xfree, cp); |
402 | ||
15a73f56 TT |
403 | init_catchpoint (&cp->base, get_current_arch (), tempflag, cond_string, |
404 | &gnu_v3_exception_catchpoint_ops); | |
405 | /* We need to reset 'type' in order for code in breakpoint.c to do | |
406 | the right thing. */ | |
407 | cp->base.type = bp_breakpoint; | |
408 | cp->kind = ex_event; | |
cc16e6c9 TT |
409 | cp->exception_rx = except_rx; |
410 | cp->pattern = pattern; | |
15a73f56 TT |
411 | |
412 | re_set_exception_catchpoint (&cp->base); | |
413 | ||
414 | install_breakpoint (0, &cp->base, 1); | |
cc16e6c9 TT |
415 | discard_cleanups (cleanup); |
416 | } | |
417 | ||
418 | /* Look for an "if" token in *STRING. The "if" token must be preceded | |
419 | by whitespace. | |
420 | ||
421 | If there is any non-whitespace text between *STRING and the "if" | |
422 | token, then it is returned in a newly-xmalloc'd string. Otherwise, | |
423 | this returns NULL. | |
424 | ||
425 | STRING is updated to point to the "if" token, if it exists, or to | |
426 | the end of the string. */ | |
427 | ||
428 | static char * | |
429 | extract_exception_regexp (char **string) | |
430 | { | |
431 | char *start; | |
432 | char *last, *last_space; | |
433 | ||
434 | start = skip_spaces (*string); | |
435 | ||
436 | last = start; | |
437 | last_space = start; | |
438 | while (*last != '\0') | |
439 | { | |
440 | char *if_token = last; | |
441 | ||
442 | /* Check for the "if". */ | |
443 | if (check_for_argument (&if_token, "if", 2)) | |
444 | break; | |
445 | ||
446 | /* No "if" token here. Skip to the next word start. */ | |
447 | last_space = skip_to_space (last); | |
448 | last = skip_spaces (last_space); | |
449 | } | |
450 | ||
451 | *string = last; | |
452 | if (last_space > start) | |
453 | return savestring (start, last_space - start); | |
454 | return NULL; | |
916703c0 TT |
455 | } |
456 | ||
457 | /* Deal with "catch catch", "catch throw", and "catch rethrow" | |
458 | commands. */ | |
459 | ||
460 | static void | |
461 | catch_exception_command_1 (enum exception_event_kind ex_event, char *arg, | |
462 | int tempflag, int from_tty) | |
463 | { | |
cc16e6c9 | 464 | char *except_rx; |
916703c0 | 465 | char *cond_string = NULL; |
cc16e6c9 | 466 | struct cleanup *cleanup; |
916703c0 TT |
467 | |
468 | if (!arg) | |
469 | arg = ""; | |
470 | arg = skip_spaces (arg); | |
471 | ||
cc16e6c9 TT |
472 | except_rx = extract_exception_regexp (&arg); |
473 | cleanup = make_cleanup (xfree, except_rx); | |
474 | ||
916703c0 TT |
475 | cond_string = ep_parse_optional_if_clause (&arg); |
476 | ||
477 | if ((*arg != '\0') && !isspace (*arg)) | |
478 | error (_("Junk at end of arguments.")); | |
479 | ||
480 | if (ex_event != EX_EVENT_THROW | |
481 | && ex_event != EX_EVENT_CATCH | |
482 | && ex_event != EX_EVENT_RETHROW) | |
483 | error (_("Unsupported or unknown exception event; cannot catch it")); | |
484 | ||
cc16e6c9 TT |
485 | handle_gnu_v3_exceptions (tempflag, except_rx, cond_string, |
486 | ex_event, from_tty); | |
487 | ||
488 | discard_cleanups (cleanup); | |
916703c0 TT |
489 | } |
490 | ||
491 | /* Implementation of "catch catch" command. */ | |
492 | ||
493 | static void | |
494 | catch_catch_command (char *arg, int from_tty, struct cmd_list_element *command) | |
495 | { | |
496 | int tempflag = get_cmd_context (command) == CATCH_TEMPORARY; | |
497 | ||
498 | catch_exception_command_1 (EX_EVENT_CATCH, arg, tempflag, from_tty); | |
499 | } | |
500 | ||
501 | /* Implementation of "catch throw" command. */ | |
502 | ||
503 | static void | |
504 | catch_throw_command (char *arg, int from_tty, struct cmd_list_element *command) | |
505 | { | |
506 | int tempflag = get_cmd_context (command) == CATCH_TEMPORARY; | |
507 | ||
508 | catch_exception_command_1 (EX_EVENT_THROW, arg, tempflag, from_tty); | |
509 | } | |
510 | ||
511 | /* Implementation of "catch rethrow" command. */ | |
512 | ||
513 | static void | |
514 | catch_rethrow_command (char *arg, int from_tty, | |
515 | struct cmd_list_element *command) | |
516 | { | |
517 | int tempflag = get_cmd_context (command) == CATCH_TEMPORARY; | |
518 | ||
519 | catch_exception_command_1 (EX_EVENT_RETHROW, arg, tempflag, from_tty); | |
520 | } | |
521 | ||
522 | \f | |
523 | ||
72f1fe8a TT |
524 | /* Implement the 'make_value' method for the $_exception |
525 | internalvar. */ | |
526 | ||
527 | static struct value * | |
528 | compute_exception (struct gdbarch *argc, struct internalvar *var, void *ignore) | |
529 | { | |
72f1fe8a TT |
530 | struct value *arg0, *arg1; |
531 | struct type *obj_type; | |
532 | ||
cc16e6c9 | 533 | fetch_probe_arguments (&arg0, &arg1); |
72f1fe8a TT |
534 | |
535 | /* ARG0 is a pointer to the exception object. ARG1 is a pointer to | |
536 | the std::type_info for the exception. Now we find the type from | |
537 | the type_info and cast the result. */ | |
538 | obj_type = cplus_type_from_type_info (arg1); | |
539 | return value_ind (value_cast (make_pointer_type (obj_type, NULL), arg0)); | |
540 | } | |
541 | ||
542 | /* Implementation of the '$_exception' variable. */ | |
543 | ||
544 | static const struct internalvar_funcs exception_funcs = | |
545 | { | |
546 | compute_exception, | |
547 | NULL, | |
548 | NULL | |
549 | }; | |
550 | ||
551 | \f | |
552 | ||
916703c0 TT |
553 | static void |
554 | initialize_throw_catchpoint_ops (void) | |
555 | { | |
556 | struct breakpoint_ops *ops; | |
557 | ||
558 | initialize_breakpoint_ops (); | |
559 | ||
560 | /* GNU v3 exception catchpoints. */ | |
561 | ops = &gnu_v3_exception_catchpoint_ops; | |
562 | *ops = bkpt_breakpoint_ops; | |
cc16e6c9 | 563 | ops->dtor = dtor_exception_catchpoint; |
15a73f56 | 564 | ops->re_set = re_set_exception_catchpoint; |
916703c0 TT |
565 | ops->print_it = print_it_exception_catchpoint; |
566 | ops->print_one = print_one_exception_catchpoint; | |
567 | ops->print_mention = print_mention_exception_catchpoint; | |
568 | ops->print_recreate = print_recreate_exception_catchpoint; | |
cc16e6c9 TT |
569 | ops->print_one_detail = print_one_detail_exception_catchpoint; |
570 | ops->check_status = check_status_exception_catchpoint; | |
916703c0 TT |
571 | } |
572 | ||
573 | initialize_file_ftype _initialize_break_catch_throw; | |
574 | ||
575 | void | |
576 | _initialize_break_catch_throw (void) | |
577 | { | |
578 | initialize_throw_catchpoint_ops (); | |
579 | ||
580 | /* Add catch and tcatch sub-commands. */ | |
581 | add_catch_command ("catch", _("\ | |
582 | Catch an exception, when caught."), | |
583 | catch_catch_command, | |
584 | NULL, | |
585 | CATCH_PERMANENT, | |
586 | CATCH_TEMPORARY); | |
587 | add_catch_command ("throw", _("\ | |
588 | Catch an exception, when thrown."), | |
589 | catch_throw_command, | |
590 | NULL, | |
591 | CATCH_PERMANENT, | |
592 | CATCH_TEMPORARY); | |
593 | add_catch_command ("rethrow", _("\ | |
594 | Catch an exception, when rethrown."), | |
595 | catch_rethrow_command, | |
596 | NULL, | |
597 | CATCH_PERMANENT, | |
598 | CATCH_TEMPORARY); | |
72f1fe8a TT |
599 | |
600 | create_internalvar_type_lazy ("_exception", &exception_funcs, NULL); | |
916703c0 | 601 | } |