1 /* Exception (throw catch) mechanism, for GDB, the GNU debugger.
3 Copyright (C) 1986-2024 Free Software Foundation, Inc.
5 This file is part of GDB.
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.
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.
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/>. */
20 #include "common-exceptions.h"
21 #include <forward_list>
23 /* Possible catcher states. */
25 /* Initial state, a new catcher has just been created. */
27 /* The catch code is running. */
30 /* The catch code threw an exception. */
34 /* Possible catcher actions. */
43 enum catcher_state state
= CATCHER_CREATED
;
44 /* Jump buffer pointing back at the exception handler. */
46 /* Status buffer belonging to the exception handler. */
47 struct gdb_exception exception
;
50 /* Where to go for throw_exception(). */
51 static std::forward_list
<struct catcher
> catchers
;
54 exceptions_state_mc_init ()
56 catchers
.emplace_front ();
57 return &catchers
.front ().buf
;
60 /* Catcher state machine. Returns non-zero if the m/c should be run
61 again, zero if it should abort. */
64 exceptions_state_mc (enum catcher_action action
)
66 switch (catchers
.front ().state
)
72 /* Allow the code to run the catcher. */
73 catchers
.front ().state
= CATCHER_RUNNING
;
76 internal_error (_("bad state"));
82 /* No error/quit has occurred. */
85 catchers
.front ().state
= CATCHER_RUNNING_1
;
88 catchers
.front ().state
= CATCHER_ABORTING
;
89 /* See also throw_exception. */
92 internal_error (_("bad switch"));
94 case CATCHER_RUNNING_1
:
98 /* The did a "break" from the inner while loop. */
101 catchers
.front ().state
= CATCHER_RUNNING
;
104 catchers
.front ().state
= CATCHER_ABORTING
;
105 /* See also throw_exception. */
108 internal_error (_("bad switch"));
110 case CATCHER_ABORTING
:
115 /* Exit normally if this catcher can handle this
116 exception. The caller analyses the func return
121 internal_error (_("bad state"));
124 internal_error (_("bad switch"));
129 exceptions_state_mc_catch (struct gdb_exception
*exception
,
132 *exception
= std::move (catchers
.front ().exception
);
133 catchers
.pop_front ();
135 if (exception
->reason
< 0)
137 if (mask
& RETURN_MASK (exception
->reason
))
139 /* Exit normally and let the caller handle the
144 /* The caller didn't request that the event be caught, relay the
145 event to the next exception_catch/CATCH_SJLJ. */
146 throw_exception_sjlj (*exception
);
149 /* No exception was thrown. */
154 exceptions_state_mc_action_iter (void)
156 return exceptions_state_mc (CATCH_ITER
);
160 exceptions_state_mc_action_iter_1 (void)
162 return exceptions_state_mc (CATCH_ITER_1
);
165 /* Return EXCEPTION to the nearest containing CATCH_SJLJ block. */
168 throw_exception_sjlj (const struct gdb_exception
&exception
)
170 /* Jump to the nearest CATCH_SJLJ block, communicating REASON to
171 that call via setjmp's return value. Note that REASON can't be
172 zero, by definition in common-exceptions.h. */
173 exceptions_state_mc (CATCH_THROWING
);
174 enum return_reason reason
= exception
.reason
;
175 catchers
.front ().exception
= exception
;
176 longjmp (catchers
.front ().buf
, reason
);
179 /* Implementation of throw_exception that uses C++ try/catch. */
182 throw_exception (gdb_exception
&&exception
)
184 if (exception
.reason
== RETURN_QUIT
)
185 throw gdb_exception_quit (std::move (exception
));
186 else if (exception
.reason
== RETURN_FORCED_QUIT
)
187 throw gdb_exception_forced_quit (std::move (exception
));
188 else if (exception
.reason
== RETURN_ERROR
)
189 throw gdb_exception_error (std::move (exception
));
191 gdb_assert_not_reached ("invalid return reason");
194 [[noreturn
]] static void ATTRIBUTE_PRINTF (3, 0)
195 throw_it (enum return_reason reason
, enum errors error
, const char *fmt
,
198 if (reason
== RETURN_QUIT
)
199 throw gdb_exception_quit (fmt
, ap
);
200 else if (reason
== RETURN_FORCED_QUIT
)
201 throw gdb_exception_forced_quit (fmt
, ap
);
202 else if (reason
== RETURN_ERROR
)
203 throw gdb_exception_error (error
, fmt
, ap
);
205 gdb_assert_not_reached ("invalid return reason");
209 throw_verror (enum errors error
, const char *fmt
, va_list ap
)
211 throw_it (RETURN_ERROR
, error
, fmt
, ap
);
215 throw_vquit (const char *fmt
, va_list ap
)
217 throw_it (RETURN_QUIT
, GDB_NO_ERROR
, fmt
, ap
);
221 throw_error (enum errors error
, const char *fmt
, ...)
225 va_start (args
, fmt
);
226 throw_verror (error
, fmt
, args
);
231 throw_quit (const char *fmt
, ...)
235 va_start (args
, fmt
);
236 throw_vquit (fmt
, args
);
241 throw_forced_quit (const char *fmt
, ...)
245 va_start (args
, fmt
);
246 throw_it (RETURN_FORCED_QUIT
, GDB_NO_ERROR
, fmt
, args
);