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