| /* Cleanup routines for GDB, the GNU debugger. | 
 |  | 
 |    Copyright (C) 1986-2023 Free Software Foundation, Inc. | 
 |  | 
 |    This file is part of GDB. | 
 |  | 
 |    This program is free software; you can redistribute it and/or modify | 
 |    it under the terms of the GNU General Public License as published by | 
 |    the Free Software Foundation; either version 3 of the License, or | 
 |    (at your option) any later version. | 
 |  | 
 |    This program is distributed in the hope that it will be useful, | 
 |    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 |    GNU General Public License for more details. | 
 |  | 
 |    You should have received a copy of the GNU General Public License | 
 |    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */ | 
 |  | 
 | #include "common-defs.h" | 
 | #include "cleanups.h" | 
 |  | 
 | /* The cleanup list records things that have to be undone | 
 |    if an error happens (descriptors to be closed, memory to be freed, etc.) | 
 |    Each link in the chain records a function to call and an | 
 |    argument to give it. | 
 |  | 
 |    Use make_cleanup to add an element to the cleanup chain. | 
 |    Use do_cleanups to do all cleanup actions back to a given | 
 |    point in the chain.  Use discard_cleanups to remove cleanups | 
 |    from the chain back to a given point, not doing them. | 
 |  | 
 |    If the argument is pointer to allocated memory, then you need | 
 |    to additionally set the 'free_arg' member to a function that will | 
 |    free that memory.  This function will be called both when the cleanup | 
 |    is executed and when it's discarded.  */ | 
 |  | 
 | struct cleanup | 
 | { | 
 |   struct cleanup *next; | 
 |   void (*function) (void *); | 
 |   void (*free_arg) (void *); | 
 |   void *arg; | 
 | }; | 
 |  | 
 | /* Used to mark the end of a cleanup chain. | 
 |    The value is chosen so that it: | 
 |    - is non-NULL so that make_cleanup never returns NULL, | 
 |    - causes a segv if dereferenced | 
 |      [though this won't catch errors that a value of, say, | 
 |      ((struct cleanup *) -1) will] | 
 |    - displays as something useful when printed in gdb. | 
 |    This is const for a bit of extra robustness. | 
 |    It is initialized to coax gcc into putting it into .rodata. | 
 |    All fields are initialized to survive -Wextra.  */ | 
 | static const struct cleanup sentinel_cleanup = { 0, 0, 0, 0 }; | 
 |  | 
 | /* Handy macro to use when referring to sentinel_cleanup.  */ | 
 | #define SENTINEL_CLEANUP ((struct cleanup *) &sentinel_cleanup) | 
 |  | 
 | /* Chain of cleanup actions established with make_final_cleanup, | 
 |    to be executed when gdb exits.  */ | 
 | static struct cleanup *final_cleanup_chain = SENTINEL_CLEANUP; | 
 |  | 
 | /* Main worker routine to create a cleanup. | 
 |    PMY_CHAIN is a pointer to either cleanup_chain or final_cleanup_chain. | 
 |    FUNCTION is the function to call to perform the cleanup. | 
 |    ARG is passed to FUNCTION when called. | 
 |    FREE_ARG, if non-NULL, is called after the cleanup is performed. | 
 |  | 
 |    The result is a pointer to the previous chain pointer | 
 |    to be passed later to do_cleanups or discard_cleanups.  */ | 
 |  | 
 | static struct cleanup * | 
 | make_my_cleanup2 (struct cleanup **pmy_chain, make_cleanup_ftype *function, | 
 | 		  void *arg,  void (*free_arg) (void *)) | 
 | { | 
 |   struct cleanup *newobj = XNEW (struct cleanup); | 
 |   struct cleanup *old_chain = *pmy_chain; | 
 |  | 
 |   newobj->next = *pmy_chain; | 
 |   newobj->function = function; | 
 |   newobj->free_arg = free_arg; | 
 |   newobj->arg = arg; | 
 |   *pmy_chain = newobj; | 
 |  | 
 |   gdb_assert (old_chain != NULL); | 
 |   return old_chain; | 
 | } | 
 |  | 
 | /* Worker routine to create a cleanup without a destructor. | 
 |    PMY_CHAIN is a pointer to either cleanup_chain or final_cleanup_chain. | 
 |    FUNCTION is the function to call to perform the cleanup. | 
 |    ARG is passed to FUNCTION when called. | 
 |  | 
 |    The result is a pointer to the previous chain pointer | 
 |    to be passed later to do_cleanups or discard_cleanups.  */ | 
 |  | 
 | static struct cleanup * | 
 | make_my_cleanup (struct cleanup **pmy_chain, make_cleanup_ftype *function, | 
 | 		 void *arg) | 
 | { | 
 |   return make_my_cleanup2 (pmy_chain, function, arg, NULL); | 
 | } | 
 |  | 
 | /* Add a new cleanup to the final cleanup_chain, | 
 |    and return the previous chain pointer | 
 |    to be passed later to do_cleanups or discard_cleanups. | 
 |    Args are FUNCTION to clean up with, and ARG to pass to it.  */ | 
 |  | 
 | struct cleanup * | 
 | make_final_cleanup (make_cleanup_ftype *function, void *arg) | 
 | { | 
 |   return make_my_cleanup (&final_cleanup_chain, function, arg); | 
 | } | 
 |  | 
 | /* Worker routine to perform cleanups. | 
 |    PMY_CHAIN is a pointer to either cleanup_chain or final_cleanup_chain. | 
 |    OLD_CHAIN is the result of a "make" cleanup routine. | 
 |    Cleanups are performed until we get back to the old end of the chain.  */ | 
 |  | 
 | static void | 
 | do_my_cleanups (struct cleanup **pmy_chain, | 
 | 		struct cleanup *old_chain) | 
 | { | 
 |   struct cleanup *ptr; | 
 |  | 
 |   while ((ptr = *pmy_chain) != old_chain) | 
 |     { | 
 |       *pmy_chain = ptr->next;	/* Do this first in case of recursion.  */ | 
 |       (*ptr->function) (ptr->arg); | 
 |       if (ptr->free_arg) | 
 | 	(*ptr->free_arg) (ptr->arg); | 
 |       xfree (ptr); | 
 |     } | 
 | } | 
 |  | 
 | /* Discard final cleanups and do the actions they describe.  */ | 
 |  | 
 | void | 
 | do_final_cleanups () | 
 | { | 
 |   do_my_cleanups (&final_cleanup_chain, SENTINEL_CLEANUP); | 
 | } |