1 /* Cleanup routines for GDB, the GNU debugger. 2 3 Copyright (C) 1986-2013 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 "defs.h" 21 #include "gdb_assert.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 *new 83 = (struct cleanup *) xmalloc (sizeof (struct cleanup)); 84 struct cleanup *old_chain = *pmy_chain; 85 86 new->next = *pmy_chain; 87 new->function = function; 88 new->free_arg = free_arg; 89 new->arg = arg; 90 *pmy_chain = new; 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 TDOR, 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, 127 void (*dtor) (void *)) 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 * 136 make_final_cleanup (make_cleanup_ftype *function, void *arg) 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 * 166 all_cleanups (void) 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 * 243 save_cleanups (void) 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 * 252 save_final_cleanups (void) 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 *pmy_chain = chain; 265 } 266 267 /* Restore the cleanup chain from a previously saved chain. */ 268 269 void 270 restore_cleanups (struct cleanup *chain) 271 { 272 restore_my_cleanups (&cleanup_chain, chain); 273 } 274 275 /* Restore the final cleanup chain from a previously saved chain. */ 276 277 void 278 restore_final_cleanups (struct cleanup *chain) 279 { 280 restore_my_cleanups (&final_cleanup_chain, chain); 281 } 282 283 /* Provide a known function that does nothing, to use as a base for 284 a possibly long chain of cleanups. This is useful where we 285 use the cleanup chain for handling normal cleanups as well as dealing 286 with cleanups that need to be done as a result of a call to error(). 287 In such cases, we may not be certain where the first cleanup is, unless 288 we have a do-nothing one to always use as the base. */ 289 290 void 291 null_cleanup (void *arg) 292 { 293 } 294