* Makefile.in (SFILES): Add break-catch-throw.c
[external/binutils.git] / gdb / break-catch-throw.c
1 /* Everything about catch/throw catchpoints, for GDB.
2
3    Copyright (C) 1986-2013 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
33 /* Enums for exception-handling support.  */
34 enum exception_event_kind
35 {
36   EX_EVENT_THROW,
37   EX_EVENT_RETHROW,
38   EX_EVENT_CATCH
39 };
40
41 /* A helper function that returns a value indicating the kind of the
42    exception catchpoint B.  */
43
44 static enum exception_event_kind
45 classify_exception_breakpoint (struct breakpoint *b)
46 {
47   if (strstr (b->addr_string, "catch") != NULL)
48     return EX_EVENT_CATCH;
49   else if (strstr (b->addr_string, "rethrow") != NULL)
50     return EX_EVENT_RETHROW;
51   else
52     return EX_EVENT_THROW;
53 }
54
55 static enum print_stop_action
56 print_it_exception_catchpoint (bpstat bs)
57 {
58   struct ui_out *uiout = current_uiout;
59   struct breakpoint *b = bs->breakpoint_at;
60   int bp_temp;
61   enum exception_event_kind kind = classify_exception_breakpoint (b);
62
63   annotate_catchpoint (b->number);
64
65   bp_temp = b->disposition == disp_del;
66   ui_out_text (uiout, 
67                bp_temp ? "Temporary catchpoint "
68                        : "Catchpoint ");
69   if (!ui_out_is_mi_like_p (uiout))
70     ui_out_field_int (uiout, "bkptno", b->number);
71   ui_out_text (uiout,
72                (kind == EX_EVENT_THROW ? " (exception thrown), "
73                 : (kind == EX_EVENT_CATCH ? " (exception caught), "
74                    : " (exception rethrown), ")));
75   if (ui_out_is_mi_like_p (uiout))
76     {
77       ui_out_field_string (uiout, "reason", 
78                            async_reason_lookup (EXEC_ASYNC_BREAKPOINT_HIT));
79       ui_out_field_string (uiout, "disp", bpdisp_text (b->disposition));
80       ui_out_field_int (uiout, "bkptno", b->number);
81     }
82   return PRINT_SRC_AND_LOC;
83 }
84
85 static void
86 print_one_exception_catchpoint (struct breakpoint *b, 
87                                 struct bp_location **last_loc)
88 {
89   struct value_print_options opts;
90   struct ui_out *uiout = current_uiout;
91   enum exception_event_kind kind = classify_exception_breakpoint (b);
92
93   get_user_print_options (&opts);
94   if (opts.addressprint)
95     {
96       annotate_field (4);
97       if (b->loc == NULL || b->loc->shlib_disabled)
98         ui_out_field_string (uiout, "addr", "<PENDING>");
99       else
100         ui_out_field_core_addr (uiout, "addr",
101                                 b->loc->gdbarch, b->loc->address);
102     }
103   annotate_field (5);
104   if (b->loc)
105     *last_loc = b->loc;
106
107   switch (kind)
108     {
109     case EX_EVENT_THROW:
110       ui_out_field_string (uiout, "what", "exception throw");
111       if (ui_out_is_mi_like_p (uiout))
112         ui_out_field_string (uiout, "catch-type", "throw");
113       break;
114
115     case EX_EVENT_RETHROW:
116       ui_out_field_string (uiout, "what", "exception rethrow");
117       if (ui_out_is_mi_like_p (uiout))
118         ui_out_field_string (uiout, "catch-type", "rethrow");
119       break;
120
121     case EX_EVENT_CATCH:
122       ui_out_field_string (uiout, "what", "exception catch");
123       if (ui_out_is_mi_like_p (uiout))
124         ui_out_field_string (uiout, "catch-type", "catch");
125       break;
126     }
127 }
128
129 static void
130 print_mention_exception_catchpoint (struct breakpoint *b)
131 {
132   struct ui_out *uiout = current_uiout;
133   int bp_temp;
134   enum exception_event_kind kind = classify_exception_breakpoint (b);
135
136   bp_temp = b->disposition == disp_del;
137   ui_out_text (uiout, bp_temp ? _("Temporary catchpoint ")
138                               : _("Catchpoint "));
139   ui_out_field_int (uiout, "bkptno", b->number);
140   ui_out_text (uiout, (kind == EX_EVENT_THROW ? _(" (throw)")
141                        : (kind == EX_EVENT_CATCH ? _(" (catch)")
142                           : _(" (rethrow)"))));
143 }
144
145 /* Implement the "print_recreate" breakpoint_ops method for throw and
146    catch catchpoints.  */
147
148 static void
149 print_recreate_exception_catchpoint (struct breakpoint *b, 
150                                      struct ui_file *fp)
151 {
152   int bp_temp;
153   enum exception_event_kind kind = classify_exception_breakpoint (b);
154
155   bp_temp = b->disposition == disp_del;
156   fprintf_unfiltered (fp, bp_temp ? "tcatch " : "catch ");
157   switch (kind)
158     {
159     case EX_EVENT_THROW:
160       fprintf_unfiltered (fp, "throw");
161       break;
162     case EX_EVENT_CATCH:
163       fprintf_unfiltered (fp, "catch");
164       break;
165     case EX_EVENT_RETHROW:
166       fprintf_unfiltered (fp, "rethrow");
167       break;
168     }
169   print_recreate_thread (b, fp);
170 }
171
172 static struct breakpoint_ops gnu_v3_exception_catchpoint_ops;
173
174 static int
175 handle_gnu_v3_exceptions (int tempflag, char *cond_string,
176                           enum exception_event_kind ex_event, int from_tty)
177 {
178   char *trigger_func_name;
179  
180   if (ex_event == EX_EVENT_CATCH)
181     trigger_func_name = "__cxa_begin_catch";
182   else if (ex_event == EX_EVENT_RETHROW)
183     trigger_func_name = "__cxa_rethrow";
184   else
185     {
186       gdb_assert (ex_event == EX_EVENT_THROW);
187       trigger_func_name = "__cxa_throw";
188     }
189
190   create_breakpoint (get_current_arch (),
191                      trigger_func_name, cond_string, -1, NULL,
192                      0 /* condition and thread are valid.  */,
193                      tempflag, bp_breakpoint,
194                      0,
195                      AUTO_BOOLEAN_TRUE /* pending */,
196                      &gnu_v3_exception_catchpoint_ops, from_tty,
197                      1 /* enabled */,
198                      0 /* internal */,
199                      0);
200
201   return 1;
202 }
203
204 /* Deal with "catch catch", "catch throw", and "catch rethrow"
205    commands.  */
206
207 static void
208 catch_exception_command_1 (enum exception_event_kind ex_event, char *arg,
209                            int tempflag, int from_tty)
210 {
211   char *cond_string = NULL;
212
213   if (!arg)
214     arg = "";
215   arg = skip_spaces (arg);
216
217   cond_string = ep_parse_optional_if_clause (&arg);
218
219   if ((*arg != '\0') && !isspace (*arg))
220     error (_("Junk at end of arguments."));
221
222   if (ex_event != EX_EVENT_THROW
223       && ex_event != EX_EVENT_CATCH
224       && ex_event != EX_EVENT_RETHROW)
225     error (_("Unsupported or unknown exception event; cannot catch it"));
226
227   if (handle_gnu_v3_exceptions (tempflag, cond_string, ex_event, from_tty))
228     return;
229
230   warning (_("Unsupported with this platform/compiler combination."));
231 }
232
233 /* Implementation of "catch catch" command.  */
234
235 static void
236 catch_catch_command (char *arg, int from_tty, struct cmd_list_element *command)
237 {
238   int tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
239
240   catch_exception_command_1 (EX_EVENT_CATCH, arg, tempflag, from_tty);
241 }
242
243 /* Implementation of "catch throw" command.  */
244
245 static void
246 catch_throw_command (char *arg, int from_tty, struct cmd_list_element *command)
247 {
248   int tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
249
250   catch_exception_command_1 (EX_EVENT_THROW, arg, tempflag, from_tty);
251 }
252
253 /* Implementation of "catch rethrow" command.  */
254
255 static void
256 catch_rethrow_command (char *arg, int from_tty,
257                        struct cmd_list_element *command)
258 {
259   int tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
260
261   catch_exception_command_1 (EX_EVENT_RETHROW, arg, tempflag, from_tty);
262 }
263
264 \f
265
266 static void
267 initialize_throw_catchpoint_ops (void)
268 {
269   struct breakpoint_ops *ops;
270
271   initialize_breakpoint_ops ();
272
273   /* GNU v3 exception catchpoints.  */
274   ops = &gnu_v3_exception_catchpoint_ops;
275   *ops = bkpt_breakpoint_ops;
276   ops->print_it = print_it_exception_catchpoint;
277   ops->print_one = print_one_exception_catchpoint;
278   ops->print_mention = print_mention_exception_catchpoint;
279   ops->print_recreate = print_recreate_exception_catchpoint;
280 }
281
282 initialize_file_ftype _initialize_break_catch_throw;
283
284 void
285 _initialize_break_catch_throw (void)
286 {
287   initialize_throw_catchpoint_ops ();
288
289   /* Add catch and tcatch sub-commands.  */
290   add_catch_command ("catch", _("\
291 Catch an exception, when caught."),
292                      catch_catch_command,
293                      NULL,
294                      CATCH_PERMANENT,
295                      CATCH_TEMPORARY);
296   add_catch_command ("throw", _("\
297 Catch an exception, when thrown."),
298                      catch_throw_command,
299                      NULL,
300                      CATCH_PERMANENT,
301                      CATCH_TEMPORARY);
302   add_catch_command ("rethrow", _("\
303 Catch an exception, when rethrown."),
304                      catch_rethrow_command,
305                      NULL,
306                      CATCH_PERMANENT,
307                      CATCH_TEMPORARY);
308 }