xref: /dflybsd-src/contrib/gdb-7/gdb/cleanups.c (revision de8e141f24382815c10a4012d209bbbf7abf1112)
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