gdb: add target_ops::supports_displaced_step
[deliverable/binutils-gdb.git] / gdbsupport / common-exceptions.cc
CommitLineData
ff55e1b5
GB
1/* Exception (throw catch) mechanism, for GDB, the GNU debugger.
2
b811d2c2 3 Copyright (C) 1986-2020 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
GB
23
24/* Possible catcher states. */
25enum 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. */
36enum catcher_action {
37 CATCH_ITER,
38 CATCH_ITER_1,
39 CATCH_THROWING
40};
41
42struct catcher
43{
3d6e9d23 44 enum catcher_state state = CATCHER_CREATED;
ff55e1b5 45 /* Jump buffer pointing back at the exception handler. */
173981bc 46 jmp_buf buf;
ff55e1b5 47 /* Status buffer belonging to the exception handler. */
cc06b668 48 struct gdb_exception exception;
ff55e1b5
GB
49};
50
51/* Where to go for throw_exception(). */
3d6e9d23 52static std::forward_list<struct catcher> catchers;
ff55e1b5 53
173981bc 54jmp_buf *
3d6e9d23 55exceptions_state_mc_init ()
ff55e1b5 56{
3d6e9d23
TT
57 catchers.emplace_front ();
58 return &catchers.front ().buf;
ff55e1b5
GB
59}
60
61/* Catcher state machine. Returns non-zero if the m/c should be run
62 again, zero if it should abort. */
63
64static int
65exceptions_state_mc (enum catcher_action action)
66{
3d6e9d23 67 switch (catchers.front ().state)
ff55e1b5
GB
68 {
69 case CATCHER_CREATED:
70 switch (action)
71 {
72 case CATCH_ITER:
73 /* Allow the code to run the catcher. */
3d6e9d23 74 catchers.front ().state = CATCHER_RUNNING;
ff55e1b5
GB
75 return 1;
76 default:
77 internal_error (__FILE__, __LINE__, _("bad state"));
78 }
79 case CATCHER_RUNNING:
80 switch (action)
81 {
82 case CATCH_ITER:
492d29ea 83 /* No error/quit has occured. */
ff55e1b5
GB
84 return 0;
85 case CATCH_ITER_1:
3d6e9d23 86 catchers.front ().state = CATCHER_RUNNING_1;
ff55e1b5
GB
87 return 1;
88 case CATCH_THROWING:
3d6e9d23 89 catchers.front ().state = CATCHER_ABORTING;
ff55e1b5
GB
90 /* See also throw_exception. */
91 return 1;
92 default:
93 internal_error (__FILE__, __LINE__, _("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. */
ff55e1b5
GB
100 return 0;
101 case CATCH_ITER_1:
3d6e9d23 102 catchers.front ().state = CATCHER_RUNNING;
ff55e1b5
GB
103 return 0;
104 case CATCH_THROWING:
3d6e9d23 105 catchers.front ().state = CATCHER_ABORTING;
ff55e1b5
GB
106 /* See also throw_exception. */
107 return 1;
108 default:
109 internal_error (__FILE__, __LINE__, _("bad switch"));
110 }
111 case CATCHER_ABORTING:
112 switch (action)
113 {
114 case CATCH_ITER:
115 {
492d29ea
PA
116 /* Exit normally if this catcher can handle this
117 exception. The caller analyses the func return
118 values. */
119 return 0;
ff55e1b5
GB
120 }
121 default:
122 internal_error (__FILE__, __LINE__, _("bad state"));
123 }
124 default:
125 internal_error (__FILE__, __LINE__, _("bad switch"));
126 }
127}
128
492d29ea
PA
129int
130exceptions_state_mc_catch (struct gdb_exception *exception,
131 int mask)
132{
3d6e9d23
TT
133 *exception = std::move (catchers.front ().exception);
134 catchers.pop_front ();
492d29ea
PA
135
136 if (exception->reason < 0)
137 {
138 if (mask & RETURN_MASK (exception->reason))
139 {
72df25b2 140 /* Exit normally and let the caller handle the
492d29ea
PA
141 exception. */
142 return 1;
143 }
144
145 /* The caller didn't request that the event be caught, relay the
89525768
PA
146 event to the next exception_catch/CATCH_SJLJ. */
147 throw_exception_sjlj (*exception);
492d29ea
PA
148 }
149
150 /* No exception was thrown. */
151 return 0;
152}
153
ff55e1b5
GB
154int
155exceptions_state_mc_action_iter (void)
156{
157 return exceptions_state_mc (CATCH_ITER);
158}
159
160int
161exceptions_state_mc_action_iter_1 (void)
162{
163 return exceptions_state_mc (CATCH_ITER_1);
164}
165
bf469271 166/* Return EXCEPTION to the nearest containing CATCH_SJLJ block. */
ff55e1b5
GB
167
168void
c6fdd8b2 169throw_exception_sjlj (const struct gdb_exception &exception)
ff55e1b5 170{
bf469271
PA
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. */
ff55e1b5 174 exceptions_state_mc (CATCH_THROWING);
c6fdd8b2 175 enum return_reason reason = exception.reason;
3d6e9d23 176 catchers.front ().exception = exception;
c6fdd8b2 177 longjmp (catchers.front ().buf, reason);
89525768
PA
178}
179
89525768
PA
180/* Implementation of throw_exception that uses C++ try/catch. */
181
26003a20 182void
94aeb44b 183throw_exception (gdb_exception &&exception)
89525768 184{
72df25b2 185 if (exception.reason == RETURN_QUIT)
94aeb44b 186 throw gdb_exception_quit (std::move (exception));
72df25b2 187 else if (exception.reason == RETURN_ERROR)
94aeb44b 188 throw gdb_exception_error (std::move (exception));
72df25b2
PA
189 else
190 gdb_assert_not_reached ("invalid return reason");
89525768
PA
191}
192
ff55e1b5
GB
193static void ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (3, 0)
194throw_it (enum return_reason reason, enum errors error, const char *fmt,
195 va_list ap)
196{
26003a20 197 if (reason == RETURN_QUIT)
56be6ea8 198 throw gdb_exception_quit (fmt, ap);
26003a20 199 else if (reason == RETURN_ERROR)
56be6ea8 200 throw gdb_exception_error (error, fmt, ap);
26003a20
TT
201 else
202 gdb_assert_not_reached ("invalid return reason");
ff55e1b5
GB
203}
204
205void
206throw_verror (enum errors error, const char *fmt, va_list ap)
207{
208 throw_it (RETURN_ERROR, error, fmt, ap);
209}
210
211void
212throw_vquit (const char *fmt, va_list ap)
213{
214 throw_it (RETURN_QUIT, GDB_NO_ERROR, fmt, ap);
215}
216
217void
218throw_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
227void
228throw_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.415051 seconds and 4 git commands to generate.