GDB (xrefs)
cleanups.c
Go to the documentation of this file.
1 /* Cleanup routines for GDB, the GNU debugger.
2 
3  Copyright (C) 1986-2015 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
83  = (struct cleanup *) xmalloc (sizeof (struct cleanup));
84  struct cleanup *old_chain = *pmy_chain;
85 
86  newobj->next = *pmy_chain;
87  newobj->function = function;
88  newobj->free_arg = free_arg;
89  newobj->arg = arg;
90  *pmy_chain = newobj;
91 
92  gdb_assert (old_chain != NULL);
93  return old_chain;
94 }
95 
96 /* Worker routine to create a cleanup without a destructor.
97  PMY_CHAIN is a pointer to either cleanup_chain or final_cleanup_chain.
98  FUNCTION is the function to call to perform the cleanup.
99  ARG is passed to FUNCTION when called.
100 
101  The result is a pointer to the previous chain pointer
102  to be passed later to do_cleanups or discard_cleanups. */
103 
104 static struct cleanup *
105 make_my_cleanup (struct cleanup **pmy_chain, make_cleanup_ftype *function,
106  void *arg)
107 {
108  return make_my_cleanup2 (pmy_chain, function, arg, NULL);
109 }
110 
111 /* Add a new cleanup to the cleanup_chain,
112  and return the previous chain pointer
113  to be passed later to do_cleanups or discard_cleanups.
114  Args are FUNCTION to clean up with, and ARG to pass to it. */
115 
116 struct cleanup *
117 make_cleanup (make_cleanup_ftype *function, void *arg)
118 {
119  return make_my_cleanup (&cleanup_chain, function, arg);
120 }
121 
122 /* Same as make_cleanup except also includes DTOR, a destructor to free ARG.
123  DTOR is invoked when the cleanup is performed or when it is discarded. */
124 
125 struct cleanup *
126 make_cleanup_dtor (make_cleanup_ftype *function, void *arg,
128 {
129  return make_my_cleanup2 (&cleanup_chain,
130  function, arg, dtor);
131 }
132 
133 /* Same as make_cleanup except the cleanup is added to final_cleanup_chain. */
134 
135 struct cleanup *
137 {
138  return make_my_cleanup (&final_cleanup_chain, function, arg);
139 }
140 
141 /* Worker routine to perform cleanups.
142  PMY_CHAIN is a pointer to either cleanup_chain or final_cleanup_chain.
143  OLD_CHAIN is the result of a "make" cleanup routine.
144  Cleanups are performed until we get back to the old end of the chain. */
145 
146 static void
147 do_my_cleanups (struct cleanup **pmy_chain,
148  struct cleanup *old_chain)
149 {
150  struct cleanup *ptr;
151 
152  while ((ptr = *pmy_chain) != old_chain)
153  {
154  *pmy_chain = ptr->next; /* Do this first in case of recursion. */
155  (*ptr->function) (ptr->arg);
156  if (ptr->free_arg)
157  (*ptr->free_arg) (ptr->arg);
158  xfree (ptr);
159  }
160 }
161 
162 /* Return a value that can be passed to do_cleanups, do_final_cleanups to
163  indicate perform all cleanups. */
164 
165 struct cleanup *
167 {
168  return SENTINEL_CLEANUP;
169 }
170 
171 /* Discard cleanups and do the actions they describe
172  until we get back to the point OLD_CHAIN in the cleanup_chain. */
173 
174 void
175 do_cleanups (struct cleanup *old_chain)
176 {
177  do_my_cleanups (&cleanup_chain, old_chain);
178 }
179 
180 /* Discard cleanups and do the actions they describe
181  until we get back to the point OLD_CHAIN in the final_cleanup_chain. */
182 
183 void
184 do_final_cleanups (struct cleanup *old_chain)
185 {
186  do_my_cleanups (&final_cleanup_chain, old_chain);
187 }
188 
189 /* Main worker routine to discard cleanups.
190  PMY_CHAIN is a pointer to either cleanup_chain or final_cleanup_chain.
191  OLD_CHAIN is the result of a "make" cleanup routine.
192  Cleanups are discarded until we get back to the old end of the chain. */
193 
194 static void
195 discard_my_cleanups (struct cleanup **pmy_chain,
196  struct cleanup *old_chain)
197 {
198  struct cleanup *ptr;
199 
200  while ((ptr = *pmy_chain) != old_chain)
201  {
202  *pmy_chain = ptr->next;
203  if (ptr->free_arg)
204  (*ptr->free_arg) (ptr->arg);
205  xfree (ptr);
206  }
207 }
208 
209 /* Discard cleanups, not doing the actions they describe,
210  until we get back to the point OLD_CHAIN in the cleanup chain. */
211 
212 void
213 discard_cleanups (struct cleanup *old_chain)
214 {
215  discard_my_cleanups (&cleanup_chain, old_chain);
216 }
217 
218 /* Discard final cleanups, not doing the actions they describe,
219  until we get back to the point OLD_CHAIN in the final cleanup chain. */
220 
221 void
222 discard_final_cleanups (struct cleanup *old_chain)
223 {
224  discard_my_cleanups (&final_cleanup_chain, old_chain);
225 }
226 
227 /* Main worker routine to save cleanups.
228  PMY_CHAIN is a pointer to either cleanup_chain or final_cleanup_chain.
229  The chain is emptied and the result is a pointer to the old chain. */
230 
231 static struct cleanup *
232 save_my_cleanups (struct cleanup **pmy_chain)
233 {
234  struct cleanup *old_chain = *pmy_chain;
235 
236  *pmy_chain = SENTINEL_CLEANUP;
237  return old_chain;
238 }
239 
240 /* Set the cleanup_chain to 0, and return the old cleanup_chain. */
241 
242 struct cleanup *
244 {
245  return save_my_cleanups (&cleanup_chain);
246 }
247 
248 /* Set the final_cleanup_chain to 0, and return the old
249  final_cleanup_chain. */
250 
251 struct cleanup *
253 {
254  return save_my_cleanups (&final_cleanup_chain);
255 }
256 
257 /* Main worker routine to save cleanups.
258  PMY_CHAIN is a pointer to either cleanup_chain or final_cleanup_chain.
259  The chain is restored from CHAIN. */
260 
261 static void
262 restore_my_cleanups (struct cleanup **pmy_chain, struct cleanup *chain)
263 {
264  if (*pmy_chain != SENTINEL_CLEANUP)
265  internal_warning (__FILE__, __LINE__,
266  _("restore_my_cleanups has found a stale cleanup"));
267 
268  *pmy_chain = chain;
269 }
270 
271 /* Restore the cleanup chain from a previously saved chain. */
272 
273 void
274 restore_cleanups (struct cleanup *chain)
275 {
276  restore_my_cleanups (&cleanup_chain, chain);
277 }
278 
279 /* Restore the final cleanup chain from a previously saved chain. */
280 
281 void
283 {
284  restore_my_cleanups (&final_cleanup_chain, chain);
285 }
286 
287 /* Provide a known function that does nothing, to use as a base for
288  a possibly long chain of cleanups. This is useful where we
289  use the cleanup chain for handling normal cleanups as well as dealing
290  with cleanups that need to be done as a result of a call to error().
291  In such cases, we may not be certain where the first cleanup is, unless
292  we have a do-nothing one to always use as the base. */
293 
294 void
295 null_cleanup (void *arg)
296 {
297 }
void restore_final_cleanups(struct cleanup *chain)
Definition: cleanups.c:282
void(* function)(void *)
Definition: cleanups.c:41
void xfree(void *)
Definition: common-utils.c:97
struct cleanup * next
Definition: cleanups.c:40
void do_final_cleanups(struct cleanup *old_chain)
Definition: cleanups.c:184
void discard_final_cleanups(struct cleanup *old_chain)
Definition: cleanups.c:222
void(* free_arg)(void *)
Definition: cleanups.c:42
void restore_cleanups(struct cleanup *chain)
Definition: cleanups.c:274
static void do_my_cleanups(struct cleanup **pmy_chain, struct cleanup *old_chain)
Definition: cleanups.c:147
#define _(String)
Definition: gdb_locale.h:40
static void discard_my_cleanups(struct cleanup **pmy_chain, struct cleanup *old_chain)
Definition: cleanups.c:195
static void restore_my_cleanups(struct cleanup **pmy_chain, struct cleanup *chain)
Definition: cleanups.c:262
struct cleanup * all_cleanups(void)
Definition: cleanups.c:166
void null_cleanup(void *arg)
Definition: cleanups.c:295
struct cleanup * save_final_cleanups(void)
Definition: cleanups.c:252
static struct cleanup * make_my_cleanup(struct cleanup **pmy_chain, make_cleanup_ftype *function, void *arg)
Definition: cleanups.c:105
struct cleanup * save_cleanups(void)
Definition: cleanups.c:243
struct cleanup * make_cleanup_dtor(make_cleanup_ftype *function, void *arg, make_cleanup_dtor_ftype *dtor)
Definition: cleanups.c:126
void( make_cleanup_dtor_ftype)(void *)
Definition: cleanups.h:33
struct cleanup * make_cleanup(make_cleanup_ftype *function, void *arg)
Definition: cleanups.c:117
#define gdb_assert(expr)
Definition: gdb_assert.h:33
void * xmalloc(YYSIZE_T)
static struct cleanup * save_my_cleanups(struct cleanup **pmy_chain)
Definition: cleanups.c:232
void discard_cleanups(struct cleanup *old_chain)
Definition: cleanups.c:213
void( make_cleanup_ftype)(void *)
Definition: cleanups.h:30
struct cleanup * make_final_cleanup(make_cleanup_ftype *function, void *arg)
Definition: cleanups.c:136
#define SENTINEL_CLEANUP
Definition: cleanups.c:59
void * arg
Definition: cleanups.c:43
void internal_warning(const char *file, int line, const char *fmt,...)
Definition: errors.c:62
void do_cleanups(struct cleanup *old_chain)
Definition: cleanups.c:175
static struct cleanup * make_my_cleanup2(struct cleanup **pmy_chain, make_cleanup_ftype *function, void *arg, void(*free_arg)(void *))
Definition: cleanups.c:79