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