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