Updated Russian translation and new Malay translation for the BFD sub-directory
[binutils-gdb.git] / gdbsupport / common-exceptions.cc
blob8301fb556fb1eed15b455a98f06c28ec5085df0e
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. */
24 enum catcher_state {
25 /* Initial state, a new catcher has just been created. */
26 CATCHER_CREATED,
27 /* The catch code is running. */
28 CATCHER_RUNNING,
29 CATCHER_RUNNING_1,
30 /* The catch code threw an exception. */
31 CATCHER_ABORTING
34 /* Possible catcher actions. */
35 enum catcher_action {
36 CATCH_ITER,
37 CATCH_ITER_1,
38 CATCH_THROWING
41 struct catcher
43 enum catcher_state state = CATCHER_CREATED;
44 /* Jump buffer pointing back at the exception handler. */
45 jmp_buf buf;
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;
53 jmp_buf *
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. */
63 static int
64 exceptions_state_mc (enum catcher_action action)
66 switch (catchers.front ().state)
68 case CATCHER_CREATED:
69 switch (action)
71 case CATCH_ITER:
72 /* Allow the code to run the catcher. */
73 catchers.front ().state = CATCHER_RUNNING;
74 return 1;
75 default:
76 internal_error (_("bad state"));
78 case CATCHER_RUNNING:
79 switch (action)
81 case CATCH_ITER:
82 /* No error/quit has occurred. */
83 return 0;
84 case CATCH_ITER_1:
85 catchers.front ().state = CATCHER_RUNNING_1;
86 return 1;
87 case CATCH_THROWING:
88 catchers.front ().state = CATCHER_ABORTING;
89 /* See also throw_exception. */
90 return 1;
91 default:
92 internal_error (_("bad switch"));
94 case CATCHER_RUNNING_1:
95 switch (action)
97 case CATCH_ITER:
98 /* The did a "break" from the inner while loop. */
99 return 0;
100 case CATCH_ITER_1:
101 catchers.front ().state = CATCHER_RUNNING;
102 return 0;
103 case CATCH_THROWING:
104 catchers.front ().state = CATCHER_ABORTING;
105 /* See also throw_exception. */
106 return 1;
107 default:
108 internal_error (_("bad switch"));
110 case CATCHER_ABORTING:
111 switch (action)
113 case CATCH_ITER:
115 /* Exit normally if this catcher can handle this
116 exception. The caller analyses the func return
117 values. */
118 return 0;
120 default:
121 internal_error (_("bad state"));
123 default:
124 internal_error (_("bad switch"));
129 exceptions_state_mc_catch (struct gdb_exception *exception,
130 int mask)
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
140 exception. */
141 return 1;
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. */
150 return 0;
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. */
167 void
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. */
181 void
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));
190 else
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,
196 va_list ap)
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);
204 else
205 gdb_assert_not_reached ("invalid return reason");
208 void
209 throw_verror (enum errors error, const char *fmt, va_list ap)
211 throw_it (RETURN_ERROR, error, fmt, ap);
214 void
215 throw_vquit (const char *fmt, va_list ap)
217 throw_it (RETURN_QUIT, GDB_NO_ERROR, fmt, ap);
220 void
221 throw_error (enum errors error, const char *fmt, ...)
223 va_list args;
225 va_start (args, fmt);
226 throw_verror (error, fmt, args);
227 va_end (args);
230 void
231 throw_quit (const char *fmt, ...)
233 va_list args;
235 va_start (args, fmt);
236 throw_vquit (fmt, args);
237 va_end (args);
240 void
241 throw_forced_quit (const char *fmt, ...)
243 va_list args;
245 va_start (args, fmt);
246 throw_it (RETURN_FORCED_QUIT, GDB_NO_ERROR, fmt, args);
247 va_end (args);