GDB (xrefs)
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. */
64 
65 /* Chain of cleanup actions established with make_final_cleanup,
66  to be executed when gdb exits. */
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 *
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 *
127 {
129  function, arg, dtor);
130 }
131 
132 /* Same as make_cleanup except the cleanup is added to final_cleanup_chain. */
133 
134 struct cleanup *
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 *
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 {
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 *
243 {
245 }
246 
247 /* Set the final_cleanup_chain to 0, and return the old
248  final_cleanup_chain. */
249 
250 struct cleanup *
252 {
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 {
276 }
277 
278 /* Restore the final cleanup chain from a previously saved chain. */
279 
280 void
282 {
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
295 {
296 }
static struct cleanup * final_cleanup_chain
Definition: cleanups.c:67
void restore_final_cleanups(struct cleanup *chain)
Definition: cleanups.c:281
void(* function)(void *)
Definition: cleanups.c:41
void xfree(void *)
static struct cleanup * cleanup_chain
Definition: cleanups.c:63
struct cleanup * next
Definition: cleanups.c:40
void do_final_cleanups(struct cleanup *old_chain)
Definition: cleanups.c:183
void discard_final_cleanups(struct cleanup *old_chain)
Definition: cleanups.c:221
void(* free_arg)(void *)
Definition: cleanups.c:42
void restore_cleanups(struct cleanup *chain)
Definition: cleanups.c:273
static void do_my_cleanups(struct cleanup **pmy_chain, struct cleanup *old_chain)
Definition: cleanups.c:146
#define _(String)
Definition: gdb_locale.h:35
static void discard_my_cleanups(struct cleanup **pmy_chain, struct cleanup *old_chain)
Definition: cleanups.c:194
static void restore_my_cleanups(struct cleanup **pmy_chain, struct cleanup *chain)
Definition: cleanups.c:261
#define XNEW(T)
Definition: poison.h:109
struct cleanup * all_cleanups(void)
Definition: cleanups.c:165
void null_cleanup(void *arg)
Definition: cleanups.c:294
struct cleanup * save_final_cleanups(void)
Definition: cleanups.c:251
static struct cleanup * make_my_cleanup(struct cleanup **pmy_chain, make_cleanup_ftype *function, void *arg)
Definition: cleanups.c:104
struct cleanup * save_cleanups(void)
Definition: cleanups.c:242
struct cleanup * make_cleanup_dtor(make_cleanup_ftype *function, void *arg, make_cleanup_dtor_ftype *dtor)
Definition: cleanups.c:125
void() make_cleanup_ftype(void *)
Definition: cleanups.h:30
struct cleanup * make_cleanup(make_cleanup_ftype *function, void *arg)
Definition: cleanups.c:116
static struct cleanup * save_my_cleanups(struct cleanup **pmy_chain)
Definition: cleanups.c:231
#define gdb_assert(expr)
Definition: gdb_assert.h:32
static const struct cleanup sentinel_cleanup
Definition: cleanups.c:56
void discard_cleanups(struct cleanup *old_chain)
Definition: cleanups.c:212
struct cleanup * make_final_cleanup(make_cleanup_ftype *function, void *arg)
Definition: cleanups.c:135
#define SENTINEL_CLEANUP
Definition: cleanups.c:59
void() make_cleanup_dtor_ftype(void *)
Definition: cleanups.h:33
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:174
static struct cleanup * make_my_cleanup2(struct cleanup **pmy_chain, make_cleanup_ftype *function, void *arg, void(*free_arg)(void *))
Definition: cleanups.c:79