GDBserver

cleanups.c
Go to the documentation of this file.
1 /* Cleanup routines for GDB, the GNU debugger.
2
3 Copyright (C) 1986-2018 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 "cleanups.h"
22
23 /* The cleanup list records things that have to be undone
24 if an error happens (descriptors to be closed, memory to be freed, etc.)
25 Each link in the chain records a function to call and an
26 argument to give it.
27
28 Use make_cleanup to add an element to the cleanup chain.
29 Use do_cleanups to do all cleanup actions back to a given
30 point in the chain. Use discard_cleanups to remove cleanups
31 from the chain back to a given point, not doing them.
32
33 If the argument is pointer to allocated memory, then you need
34 to additionally set the 'free_arg' member to a function that will
35 free that memory. This function will be called both when the cleanup
36 is executed and when it's discarded. */
37
38 struct cleanup
39 {
40 struct cleanup *next;
41 void (*function) (void *);
42 void (*free_arg) (void *);
43 void *arg;
44 };
45
46 /* Used to mark the end of a cleanup chain.
47 The value is chosen so that it:
48 - is non-NULL so that make_cleanup never returns NULL,
49 - causes a segv if dereferenced
50 [though this won't catch errors that a value of, say,
51 ((struct cleanup *) -1) will]
52 - displays as something useful when printed in gdb.
53 This is const for a bit of extra robustness.
54 It is initialized to coax gcc into putting it into .rodata.
55 All fields are initialized to survive -Wextra. */
56 static const struct cleanup sentinel_cleanup = { 0, 0, 0, 0 };
57
58 /* Handy macro to use when referring to sentinel_cleanup. */
59 #define SENTINEL_CLEANUP ((struct cleanup *) &sentinel_cleanup)
60
61 /* Chain of cleanup actions established with make_cleanup,
62 to be executed if an error happens. */
63 static struct cleanup *cleanup_chain = SENTINEL_CLEANUP;
64
65 /* Chain of cleanup actions established with make_final_cleanup,
66 to be executed when gdb exits. */
67 static struct cleanup *final_cleanup_chain = SENTINEL_CLEANUP;
68
69 /* Main worker routine to create a cleanup.
70 PMY_CHAIN is a pointer to either cleanup_chain or final_cleanup_chain.
71 FUNCTION is the function to call to perform the cleanup.
72 ARG is passed to FUNCTION when called.
73 FREE_ARG, if non-NULL, is called after the cleanup is performed.
74
75 The result is a pointer to the previous chain pointer
76 to be passed later to do_cleanups or discard_cleanups. */
77
78 static struct cleanup *
79 make_my_cleanup2 (struct cleanup **pmy_chain, make_cleanup_ftype *function,
80 void *arg, void (*free_arg) (void *))
81 {
82 struct cleanup *newobj = XNEW (struct cleanup);
83 struct cleanup *old_chain = *pmy_chain;
84
85 newobj->next = *pmy_chain;
86 newobj->function = function;
87 newobj->free_arg = free_arg;
88 newobj->arg = arg;
89 *pmy_chain = newobj;
90
91 gdb_assert (old_chain != NULL);
92 return old_chain;
93 }
94
95 /* Worker routine to create a cleanup without a destructor.
96 PMY_CHAIN is a pointer to either cleanup_chain or final_cleanup_chain.
97 FUNCTION is the function to call to perform the cleanup.
98 ARG is passed to FUNCTION when called.
99
100 The result is a pointer to the previous chain pointer
101 to be passed later to do_cleanups or discard_cleanups. */
102
103 static struct cleanup *
104 make_my_cleanup (struct cleanup **pmy_chain, make_cleanup_ftype *function,
105 void *arg)
106 {
107 return make_my_cleanup2 (pmy_chain, function, arg, NULL);
108 }
109
110 /* Add a new cleanup to the cleanup_chain,
111 and return the previous chain pointer
112 to be passed later to do_cleanups or discard_cleanups.
113 Args are FUNCTION to clean up with, and ARG to pass to it. */
114
115 struct cleanup *
116 make_cleanup (make_cleanup_ftype *function, void *arg)
117 {
118 return make_my_cleanup (&cleanup_chain, function, arg);
119 }
120
121 /* Same as make_cleanup except also includes DTOR, a destructor to free ARG.
122 DTOR is invoked when the cleanup is performed or when it is discarded. */
123
124 struct cleanup *
125 make_cleanup_dtor (make_cleanup_ftype *function, void *arg,
126 make_cleanup_dtor_ftype *dtor)
127 {
128 return make_my_cleanup2 (&cleanup_chain,
129 function, arg, dtor);
130 }
131
132 /* Same as make_cleanup except the cleanup is added to final_cleanup_chain. */
133
134 struct cleanup *
135 make_final_cleanup (make_cleanup_ftype *function, void *arg)
136 {
137 return make_my_cleanup (&final_cleanup_chain, function, arg);
138 }
139
140 /* Worker routine to perform cleanups.
141 PMY_CHAIN is a pointer to either cleanup_chain or final_cleanup_chain.
142 OLD_CHAIN is the result of a "make" cleanup routine.
143 Cleanups are performed until we get back to the old end of the chain. */
144
145 static void
146 do_my_cleanups (struct cleanup **pmy_chain,
147 struct cleanup *old_chain)
148 {
149 struct cleanup *ptr;
150
151 while ((ptr = *pmy_chain) != old_chain)
152 {
153 *pmy_chain = ptr->next; /* Do this first in case of recursion. */
154 (*ptr->function) (ptr->arg);
155 if (ptr->free_arg)
156 (*ptr->free_arg) (ptr->arg);
157 xfree (ptr);
158 }
159 }
160
161 /* Return a value that can be passed to do_cleanups, do_final_cleanups to
162 indicate perform all cleanups. */
163
164 struct cleanup *
165 all_cleanups (void)
166 {
167 return SENTINEL_CLEANUP;
168 }
169
170 /* Discard cleanups and do the actions they describe
171 until we get back to the point OLD_CHAIN in the cleanup_chain. */
172
173 void
174 do_cleanups (struct cleanup *old_chain)
175 {
176 do_my_cleanups (&cleanup_chain, old_chain);
177 }
178
179 /* Discard cleanups and do the actions they describe
180 until we get back to the point OLD_CHAIN in the final_cleanup_chain. */
181
182 void
183 do_final_cleanups (struct cleanup *old_chain)
184 {
185 do_my_cleanups (&final_cleanup_chain, old_chain);
186 }
187
188 /* Main worker routine to discard cleanups.
189 PMY_CHAIN is a pointer to either cleanup_chain or final_cleanup_chain.
190 OLD_CHAIN is the result of a "make" cleanup routine.
191 Cleanups are discarded until we get back to the old end of the chain. */
192
193 static void
194 discard_my_cleanups (struct cleanup **pmy_chain,
195 struct cleanup *old_chain)
196 {
197 struct cleanup *ptr;
198
199 while ((ptr = *pmy_chain) != old_chain)
200 {
201 *pmy_chain = ptr->next;
202 if (ptr->free_arg)
203 (*ptr->free_arg) (ptr->arg);
204 xfree (ptr);
205 }
206 }
207
208 /* Discard cleanups, not doing the actions they describe,
209 until we get back to the point OLD_CHAIN in the cleanup chain. */
210
211 void
212 discard_cleanups (struct cleanup *old_chain)
213 {
214 discard_my_cleanups (&cleanup_chain, old_chain);
215 }
216
217 /* Discard final cleanups, not doing the actions they describe,
218 until we get back to the point OLD_CHAIN in the final cleanup chain. */
219
220 void
221 discard_final_cleanups (struct cleanup *old_chain)
222 {
223 discard_my_cleanups (&final_cleanup_chain, old_chain);
224 }
225
226 /* Main worker routine to save cleanups.
227 PMY_CHAIN is a pointer to either cleanup_chain or final_cleanup_chain.
228 The chain is emptied and the result is a pointer to the old chain. */
229
230 static struct cleanup *
231 save_my_cleanups (struct cleanup **pmy_chain)
232 {
233 struct cleanup *old_chain = *pmy_chain;
234
235 *pmy_chain = SENTINEL_CLEANUP;
236 return old_chain;
237 }
238
239 /* Set the cleanup_chain to 0, and return the old cleanup_chain. */
240
241 struct cleanup *
242 save_cleanups (void)
243 {
244 return save_my_cleanups (&cleanup_chain);
245 }
246
247 /* Set the final_cleanup_chain to 0, and return the old
248 final_cleanup_chain. */
249
250 struct cleanup *
251 save_final_cleanups (void)
252 {
253 return save_my_cleanups (&final_cleanup_chain);
254 }
255
256 /* Main worker routine to save cleanups.
257 PMY_CHAIN is a pointer to either cleanup_chain or final_cleanup_chain.
258 The chain is restored from CHAIN. */
259
260 static void
261 restore_my_cleanups (struct cleanup **pmy_chain, struct cleanup *chain)
262 {
263 if (*pmy_chain != SENTINEL_CLEANUP)
264 internal_warning (__FILE__, __LINE__,
265 _("restore_my_cleanups has found a stale cleanup"));
266
267 *pmy_chain = chain;
268 }
269
270 /* Restore the cleanup chain from a previously saved chain. */
271
272 void
273 restore_cleanups (struct cleanup *chain)
274 {
275 restore_my_cleanups (&cleanup_chain, chain);
276 }
277
278 /* Restore the final cleanup chain from a previously saved chain. */
279
280 void
281 restore_final_cleanups (struct cleanup *chain)
282 {
283 restore_my_cleanups (&final_cleanup_chain, chain);
284 }
285
286 /* Provide a known function that does nothing, to use as a base for
287 a possibly long chain of cleanups. This is useful where we
288 use the cleanup chain for handling normal cleanups as well as dealing
289 with cleanups that need to be done as a result of a call to error().
290 In such cases, we may not be certain where the first cleanup is, unless
291 we have a do-nothing one to always use as the base. */
292
293 void
294 null_cleanup (void *arg)
295 {
296 }
final_cleanup_chain
static struct cleanup * final_cleanup_chain
Definition: cleanups.c:67
xfree
static void xfree(T *ptr)
Definition: common-utils.h:54
restore_final_cleanups
void restore_final_cleanups(struct cleanup *chain)
Definition: cleanups.c:281
cleanup::function
void(* function)(void *)
Definition: cleanups.c:41
cleanup_chain
static struct cleanup * cleanup_chain
Definition: cleanups.c:63
cleanup::next
struct cleanup * next
Definition: cleanups.c:40
do_final_cleanups
void do_final_cleanups(struct cleanup *old_chain)
Definition: cleanups.c:183
discard_final_cleanups
void discard_final_cleanups(struct cleanup *old_chain)
Definition: cleanups.c:221
cleanup::free_arg
void(* free_arg)(void *)
Definition: cleanups.c:42
restore_cleanups
void restore_cleanups(struct cleanup *chain)
Definition: cleanups.c:273
do_my_cleanups
static void do_my_cleanups(struct cleanup **pmy_chain, struct cleanup *old_chain)
Definition: cleanups.c:146
cleanup
Definition: cleanups.c:38
_
#define _(String)
Definition: gdb_locale.h:35
discard_my_cleanups
static void discard_my_cleanups(struct cleanup **pmy_chain, struct cleanup *old_chain)
Definition: cleanups.c:194
restore_my_cleanups
static void restore_my_cleanups(struct cleanup **pmy_chain, struct cleanup *chain)
Definition: cleanups.c:261
XNEW
#define XNEW(T)
Definition: poison.h:109
all_cleanups
struct cleanup * all_cleanups(void)
Definition: cleanups.c:165
null_cleanup
void null_cleanup(void *arg)
Definition: cleanups.c:294
save_final_cleanups
struct cleanup * save_final_cleanups(void)
Definition: cleanups.c:251
make_my_cleanup
static struct cleanup * make_my_cleanup(struct cleanup **pmy_chain, make_cleanup_ftype *function, void *arg)
Definition: cleanups.c:104
save_cleanups
struct cleanup * save_cleanups(void)
Definition: cleanups.c:242
make_cleanup_dtor
struct cleanup * make_cleanup_dtor(make_cleanup_ftype *function, void *arg, make_cleanup_dtor_ftype *dtor)
Definition: cleanups.c:125
make_cleanup_ftype
void() make_cleanup_ftype(void *)
Definition: cleanups.h:30
cleanups.h
make_cleanup
struct cleanup * make_cleanup(make_cleanup_ftype *function, void *arg)
Definition: cleanups.c:116
common-defs.h
save_my_cleanups
static struct cleanup * save_my_cleanups(struct cleanup **pmy_chain)
Definition: cleanups.c:231
gdb_assert
#define gdb_assert(expr)
Definition: gdb_assert.h:32
sentinel_cleanup
static const struct cleanup sentinel_cleanup
Definition: cleanups.c:56
discard_cleanups
void discard_cleanups(struct cleanup *old_chain)
Definition: cleanups.c:212
make_final_cleanup
struct cleanup * make_final_cleanup(make_cleanup_ftype *function, void *arg)
Definition: cleanups.c:135
SENTINEL_CLEANUP
#define SENTINEL_CLEANUP
Definition: cleanups.c:59
make_cleanup_dtor_ftype
void() make_cleanup_dtor_ftype(void *)
Definition: cleanups.h:33
cleanup::arg
void * arg
Definition: cleanups.c:43
internal_warning
void internal_warning(const char *file, int line, const char *fmt,...)
Definition: errors.c:62
do_cleanups
void do_cleanups(struct cleanup *old_chain)
Definition: cleanups.c:174
make_my_cleanup2
static struct cleanup * make_my_cleanup2(struct cleanup **pmy_chain, make_cleanup_ftype *function, void *arg, void(*free_arg)(void *))
Definition: cleanups.c:79