]> Git Repo - binutils.git/blob - gdb/common/common-exceptions.c
Rename gdb exception types
[binutils.git] / gdb / common / common-exceptions.c
1 /* Exception (throw catch) mechanism, for GDB, the GNU debugger.
2
3    Copyright (C) 1986-2019 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 "common-defs.h"
21 #include "common-exceptions.h"
22 #include <forward_list>
23
24 const struct gdb_exception exception_none;
25
26 /* Possible catcher states.  */
27 enum catcher_state {
28   /* Initial state, a new catcher has just been created.  */
29   CATCHER_CREATED,
30   /* The catch code is running.  */
31   CATCHER_RUNNING,
32   CATCHER_RUNNING_1,
33   /* The catch code threw an exception.  */
34   CATCHER_ABORTING
35 };
36
37 /* Possible catcher actions.  */
38 enum catcher_action {
39   CATCH_ITER,
40   CATCH_ITER_1,
41   CATCH_THROWING
42 };
43
44 struct catcher
45 {
46   enum catcher_state state = CATCHER_CREATED;
47   /* Jump buffer pointing back at the exception handler.  */
48   jmp_buf buf;
49   /* Status buffer belonging to the exception handler.  */
50   struct gdb_exception exception = exception_none;
51 };
52
53 /* Where to go for throw_exception().  */
54 static std::forward_list<struct catcher> catchers;
55
56 jmp_buf *
57 exceptions_state_mc_init ()
58 {
59   catchers.emplace_front ();
60   return &catchers.front ().buf;
61 }
62
63 /* Catcher state machine.  Returns non-zero if the m/c should be run
64    again, zero if it should abort.  */
65
66 static int
67 exceptions_state_mc (enum catcher_action action)
68 {
69   switch (catchers.front ().state)
70     {
71     case CATCHER_CREATED:
72       switch (action)
73         {
74         case CATCH_ITER:
75           /* Allow the code to run the catcher.  */
76           catchers.front ().state = CATCHER_RUNNING;
77           return 1;
78         default:
79           internal_error (__FILE__, __LINE__, _("bad state"));
80         }
81     case CATCHER_RUNNING:
82       switch (action)
83         {
84         case CATCH_ITER:
85           /* No error/quit has occured.  */
86           return 0;
87         case CATCH_ITER_1:
88           catchers.front ().state = CATCHER_RUNNING_1;
89           return 1;
90         case CATCH_THROWING:
91           catchers.front ().state = CATCHER_ABORTING;
92           /* See also throw_exception.  */
93           return 1;
94         default:
95           internal_error (__FILE__, __LINE__, _("bad switch"));
96         }
97     case CATCHER_RUNNING_1:
98       switch (action)
99         {
100         case CATCH_ITER:
101           /* The did a "break" from the inner while loop.  */
102           return 0;
103         case CATCH_ITER_1:
104           catchers.front ().state = CATCHER_RUNNING;
105           return 0;
106         case CATCH_THROWING:
107           catchers.front ().state = CATCHER_ABORTING;
108           /* See also throw_exception.  */
109           return 1;
110         default:
111           internal_error (__FILE__, __LINE__, _("bad switch"));
112         }
113     case CATCHER_ABORTING:
114       switch (action)
115         {
116         case CATCH_ITER:
117           {
118             /* Exit normally if this catcher can handle this
119                exception.  The caller analyses the func return
120                values.  */
121             return 0;
122           }
123         default:
124           internal_error (__FILE__, __LINE__, _("bad state"));
125         }
126     default:
127       internal_error (__FILE__, __LINE__, _("bad switch"));
128     }
129 }
130
131 int
132 exceptions_state_mc_catch (struct gdb_exception *exception,
133                            int mask)
134 {
135   *exception = std::move (catchers.front ().exception);
136   catchers.pop_front ();
137
138   if (exception->reason < 0)
139     {
140       if (mask & RETURN_MASK (exception->reason))
141         {
142           /* Exit normally and let the caller handle the
143              exception.  */
144           return 1;
145         }
146
147       /* The caller didn't request that the event be caught, relay the
148          event to the next exception_catch/CATCH_SJLJ.  */
149       throw_exception_sjlj (*exception);
150     }
151
152   /* No exception was thrown.  */
153   return 0;
154 }
155
156 int
157 exceptions_state_mc_action_iter (void)
158 {
159   return exceptions_state_mc (CATCH_ITER);
160 }
161
162 int
163 exceptions_state_mc_action_iter_1 (void)
164 {
165   return exceptions_state_mc (CATCH_ITER_1);
166 }
167
168 /* Called by the default catch block.  IOW, we'll get here before
169    jumping out to the next outermost scope an exception if a GDB
170    exception is not caught.  */
171
172 void
173 exception_rethrow (void)
174 {
175   throw;
176 }
177
178 /* Return EXCEPTION to the nearest containing CATCH_SJLJ block.  */
179
180 void
181 throw_exception_sjlj (struct gdb_exception exception)
182 {
183   /* Jump to the nearest CATCH_SJLJ block, communicating REASON to
184      that call via setjmp's return value.  Note that REASON can't be
185      zero, by definition in common-exceptions.h.  */
186   exceptions_state_mc (CATCH_THROWING);
187   catchers.front ().exception = exception;
188   longjmp (catchers.front ().buf, exception.reason);
189 }
190
191 /* Implementation of throw_exception that uses C++ try/catch.  */
192
193 static ATTRIBUTE_NORETURN void
194 throw_exception_cxx (struct gdb_exception exception)
195 {
196   if (exception.reason == RETURN_QUIT)
197     {
198       gdb_exception_quit ex (exception);
199       throw ex;
200     }
201   else if (exception.reason == RETURN_ERROR)
202     {
203       gdb_exception_error ex (exception);
204       throw ex;
205     }
206   else
207     gdb_assert_not_reached ("invalid return reason");
208 }
209
210 void
211 throw_exception (struct gdb_exception exception)
212 {
213   throw_exception_cxx (exception);
214 }
215
216 static void ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (3, 0)
217 throw_it (enum return_reason reason, enum errors error, const char *fmt,
218           va_list ap)
219 {
220   struct gdb_exception e;
221
222   /* Create the exception.  */
223   e.reason = reason;
224   e.error = error;
225   e.message.reset (new std::string (string_vprintf (fmt, ap)));
226
227   /* Throw the exception.  */
228   throw_exception (e);
229 }
230
231 void
232 throw_verror (enum errors error, const char *fmt, va_list ap)
233 {
234   throw_it (RETURN_ERROR, error, fmt, ap);
235 }
236
237 void
238 throw_vquit (const char *fmt, va_list ap)
239 {
240   throw_it (RETURN_QUIT, GDB_NO_ERROR, fmt, ap);
241 }
242
243 void
244 throw_error (enum errors error, const char *fmt, ...)
245 {
246   va_list args;
247
248   va_start (args, fmt);
249   throw_verror (error, fmt, args);
250   va_end (args);
251 }
252
253 void
254 throw_quit (const char *fmt, ...)
255 {
256   va_list args;
257
258   va_start (args, fmt);
259   throw_vquit (fmt, args);
260   va_end (args);
261 }
This page took 0.042176 seconds and 4 git commands to generate.