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 * 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 * 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 * 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 * 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 * 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 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 * 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 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 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 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 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 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 * 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 * 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 * 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 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 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 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 291*ef5ccd6cSJohn Marino null_cleanup (void *arg) 292*ef5ccd6cSJohn Marino { 293*ef5ccd6cSJohn Marino } 294