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