]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/common/common-exceptions.c
Make exception throwing a bit more efficient
[thirdparty/binutils-gdb.git] / gdb / common / common-exceptions.c
CommitLineData
ff55e1b5
GB
1/* Exception (throw catch) mechanism, for GDB, the GNU debugger.
2
42a4f53d 3 Copyright (C) 1986-2019 Free Software Foundation, Inc.
ff55e1b5
GB
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"
3d6e9d23 22#include <forward_list>
ff55e1b5 23
3d6e9d23 24const struct gdb_exception exception_none;
ad6aff7d 25
ff55e1b5
GB
26/* Possible catcher states. */
27enum 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. */
38enum catcher_action {
39 CATCH_ITER,
40 CATCH_ITER_1,
41 CATCH_THROWING
42};
43
44struct catcher
45{
3d6e9d23 46 enum catcher_state state = CATCHER_CREATED;
ff55e1b5 47 /* Jump buffer pointing back at the exception handler. */
173981bc 48 jmp_buf buf;
ff55e1b5 49 /* Status buffer belonging to the exception handler. */
3d6e9d23 50 struct gdb_exception exception = exception_none;
ff55e1b5
GB
51};
52
53/* Where to go for throw_exception(). */
3d6e9d23 54static std::forward_list<struct catcher> catchers;
ff55e1b5 55
173981bc 56jmp_buf *
3d6e9d23 57exceptions_state_mc_init ()
ff55e1b5 58{
3d6e9d23
TT
59 catchers.emplace_front ();
60 return &catchers.front ().buf;
ff55e1b5
GB
61}
62
63/* Catcher state machine. Returns non-zero if the m/c should be run
64 again, zero if it should abort. */
65
66static int
67exceptions_state_mc (enum catcher_action action)
68{
3d6e9d23 69 switch (catchers.front ().state)
ff55e1b5
GB
70 {
71 case CATCHER_CREATED:
72 switch (action)
73 {
74 case CATCH_ITER:
75 /* Allow the code to run the catcher. */
3d6e9d23 76 catchers.front ().state = CATCHER_RUNNING;
ff55e1b5
GB
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:
492d29ea 85 /* No error/quit has occured. */
ff55e1b5
GB
86 return 0;
87 case CATCH_ITER_1:
3d6e9d23 88 catchers.front ().state = CATCHER_RUNNING_1;
ff55e1b5
GB
89 return 1;
90 case CATCH_THROWING:
3d6e9d23 91 catchers.front ().state = CATCHER_ABORTING;
ff55e1b5
GB
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. */
ff55e1b5
GB
102 return 0;
103 case CATCH_ITER_1:
3d6e9d23 104 catchers.front ().state = CATCHER_RUNNING;
ff55e1b5
GB
105 return 0;
106 case CATCH_THROWING:
3d6e9d23 107 catchers.front ().state = CATCHER_ABORTING;
ff55e1b5
GB
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 {
492d29ea
PA
118 /* Exit normally if this catcher can handle this
119 exception. The caller analyses the func return
120 values. */
121 return 0;
ff55e1b5
GB
122 }
123 default:
124 internal_error (__FILE__, __LINE__, _("bad state"));
125 }
126 default:
127 internal_error (__FILE__, __LINE__, _("bad switch"));
128 }
129}
130
492d29ea
PA
131int
132exceptions_state_mc_catch (struct gdb_exception *exception,
133 int mask)
134{
3d6e9d23
TT
135 *exception = std::move (catchers.front ().exception);
136 catchers.pop_front ();
492d29ea
PA
137
138 if (exception->reason < 0)
139 {
140 if (mask & RETURN_MASK (exception->reason))
141 {
72df25b2 142 /* Exit normally and let the caller handle the
492d29ea
PA
143 exception. */
144 return 1;
145 }
146
147 /* The caller didn't request that the event be caught, relay the
89525768
PA
148 event to the next exception_catch/CATCH_SJLJ. */
149 throw_exception_sjlj (*exception);
492d29ea
PA
150 }
151
152 /* No exception was thrown. */
153 return 0;
154}
155
ff55e1b5
GB
156int
157exceptions_state_mc_action_iter (void)
158{
159 return exceptions_state_mc (CATCH_ITER);
160}
161
162int
163exceptions_state_mc_action_iter_1 (void)
164{
165 return exceptions_state_mc (CATCH_ITER_1);
166}
167
bf469271 168/* Return EXCEPTION to the nearest containing CATCH_SJLJ block. */
ff55e1b5
GB
169
170void
89525768 171throw_exception_sjlj (struct gdb_exception exception)
ff55e1b5 172{
bf469271
PA
173 /* Jump to the nearest CATCH_SJLJ block, communicating REASON to
174 that call via setjmp's return value. Note that REASON can't be
175 zero, by definition in common-exceptions.h. */
ff55e1b5 176 exceptions_state_mc (CATCH_THROWING);
3d6e9d23
TT
177 catchers.front ().exception = exception;
178 longjmp (catchers.front ().buf, exception.reason);
89525768
PA
179}
180
89525768
PA
181/* Implementation of throw_exception that uses C++ try/catch. */
182
26003a20
TT
183void
184throw_exception (const gdb_exception &exception)
89525768 185{
72df25b2
PA
186 if (exception.reason == RETURN_QUIT)
187 {
230d2906 188 gdb_exception_quit ex (exception);
72df25b2
PA
189 throw ex;
190 }
191 else if (exception.reason == RETURN_ERROR)
192 {
230d2906 193 gdb_exception_error ex (exception);
72df25b2
PA
194 throw ex;
195 }
196 else
197 gdb_assert_not_reached ("invalid return reason");
89525768
PA
198}
199
ff55e1b5
GB
200static void ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (3, 0)
201throw_it (enum return_reason reason, enum errors error, const char *fmt,
202 va_list ap)
203{
26003a20
TT
204 if (reason == RETURN_QUIT)
205 {
206 gdb_exception_quit ex (reason, error);
207 ex.message.reset (new std::string (string_vprintf (fmt, ap)));
208 throw ex;
209 }
210 else if (reason == RETURN_ERROR)
211 {
212 gdb_exception_error ex (reason, error);
213 ex.message.reset (new std::string (string_vprintf (fmt, ap)));
214 throw ex;
215 }
216 else
217 gdb_assert_not_reached ("invalid return reason");
ff55e1b5
GB
218}
219
220void
221throw_verror (enum errors error, const char *fmt, va_list ap)
222{
223 throw_it (RETURN_ERROR, error, fmt, ap);
224}
225
226void
227throw_vquit (const char *fmt, va_list ap)
228{
229 throw_it (RETURN_QUIT, GDB_NO_ERROR, fmt, ap);
230}
231
232void
233throw_error (enum errors error, const char *fmt, ...)
234{
235 va_list args;
236
237 va_start (args, fmt);
238 throw_verror (error, fmt, args);
239 va_end (args);
240}
241
242void
243throw_quit (const char *fmt, ...)
244{
245 va_list args;
246
247 va_start (args, fmt);
248 throw_vquit (fmt, args);
249 va_end (args);
250}