gdb/common/cleanups.c - gdb

Global variables defined

Data types defined

Functions defined

Macros defined

Source code

  1. /* Cleanup routines for GDB, the GNU debugger.

  2.    Copyright (C) 1986-2015 Free Software Foundation, Inc.

  3.    This file is part of GDB.

  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 3 of the License, or
  7.    (at your option) any later version.

  8.    This program is distributed in the hope that it will be useful,
  9.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11.    GNU General Public License for more details.

  12.    You should have received a copy of the GNU General Public License
  13.    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */

  14. #include "common-defs.h"
  15. #include "cleanups.h"

  16. /* The cleanup list records things that have to be undone
  17.    if an error happens (descriptors to be closed, memory to be freed, etc.)
  18.    Each link in the chain records a function to call and an
  19.    argument to give it.

  20.    Use make_cleanup to add an element to the cleanup chain.
  21.    Use do_cleanups to do all cleanup actions back to a given
  22.    point in the chain.  Use discard_cleanups to remove cleanups
  23.    from the chain back to a given point, not doing them.

  24.    If the argument is pointer to allocated memory, then you need
  25.    to additionally set the 'free_arg' member to a function that will
  26.    free that memory.  This function will be called both when the cleanup
  27.    is executed and when it's discarded.  */

  28. struct cleanup
  29. {
  30.   struct cleanup *next;
  31.   void (*function) (void *);
  32.   void (*free_arg) (void *);
  33.   void *arg;
  34. };

  35. /* Used to mark the end of a cleanup chain.
  36.    The value is chosen so that it:
  37.    - is non-NULL so that make_cleanup never returns NULL,
  38.    - causes a segv if dereferenced
  39.      [though this won't catch errors that a value of, say,
  40.      ((struct cleanup *) -1) will]
  41.    - displays as something useful when printed in gdb.
  42.    This is const for a bit of extra robustness.
  43.    It is initialized to coax gcc into putting it into .rodata.
  44.    All fields are initialized to survive -Wextra.  */
  45. static const struct cleanup sentinel_cleanup = { 0, 0, 0, 0 };

  46. /* Handy macro to use when referring to sentinel_cleanup.  */
  47. #define SENTINEL_CLEANUP ((struct cleanup *) &sentinel_cleanup)

  48. /* Chain of cleanup actions established with make_cleanup,
  49.    to be executed if an error happens.  */
  50. static struct cleanup *cleanup_chain = SENTINEL_CLEANUP;

  51. /* Chain of cleanup actions established with make_final_cleanup,
  52.    to be executed when gdb exits.  */
  53. static struct cleanup *final_cleanup_chain = SENTINEL_CLEANUP;

  54. /* Main worker routine to create a cleanup.
  55.    PMY_CHAIN is a pointer to either cleanup_chain or final_cleanup_chain.
  56.    FUNCTION is the function to call to perform the cleanup.
  57.    ARG is passed to FUNCTION when called.
  58.    FREE_ARG, if non-NULL, is called after the cleanup is performed.

  59.    The result is a pointer to the previous chain pointer
  60.    to be passed later to do_cleanups or discard_cleanups.  */

  61. static struct cleanup *
  62. make_my_cleanup2 (struct cleanup **pmy_chain, make_cleanup_ftype *function,
  63.                   void *argvoid (*free_arg) (void *))
  64. {
  65.   struct cleanup *new
  66.     = (struct cleanup *) xmalloc (sizeof (struct cleanup));
  67.   struct cleanup *old_chain = *pmy_chain;

  68.   new->next = *pmy_chain;
  69.   new->function = function;
  70.   new->free_arg = free_arg;
  71.   new->arg = arg;
  72.   *pmy_chain = new;

  73.   gdb_assert (old_chain != NULL);
  74.   return old_chain;
  75. }

  76. /* Worker routine to create a cleanup without a destructor.
  77.    PMY_CHAIN is a pointer to either cleanup_chain or final_cleanup_chain.
  78.    FUNCTION is the function to call to perform the cleanup.
  79.    ARG is passed to FUNCTION when called.

  80.    The result is a pointer to the previous chain pointer
  81.    to be passed later to do_cleanups or discard_cleanups.  */

  82. static struct cleanup *
  83. make_my_cleanup (struct cleanup **pmy_chain, make_cleanup_ftype *function,
  84.                  void *arg)
  85. {
  86.   return make_my_cleanup2 (pmy_chain, function, arg, NULL);
  87. }

  88. /* Add a new cleanup to the cleanup_chain,
  89.    and return the previous chain pointer
  90.    to be passed later to do_cleanups or discard_cleanups.
  91.    Args are FUNCTION to clean up with, and ARG to pass to it.  */

  92. struct cleanup *
  93. make_cleanup (make_cleanup_ftype *function, void *arg)
  94. {
  95.   return make_my_cleanup (&cleanup_chain, function, arg);
  96. }

  97. /* Same as make_cleanup except also includes DTOR, a destructor to free ARG.
  98.    DTOR is invoked when the cleanup is performed or when it is discarded.  */

  99. struct cleanup *
  100. make_cleanup_dtor (make_cleanup_ftype *function, void *arg,
  101.                    make_cleanup_dtor_ftype *dtor)
  102. {
  103.   return make_my_cleanup2 (&cleanup_chain,
  104.                            function, arg, dtor);
  105. }

  106. /* Same as make_cleanup except the cleanup is added to final_cleanup_chain.  */

  107. struct cleanup *
  108. make_final_cleanup (make_cleanup_ftype *function, void *arg)
  109. {
  110.   return make_my_cleanup (&final_cleanup_chain, function, arg);
  111. }

  112. /* Worker routine to perform cleanups.
  113.    PMY_CHAIN is a pointer to either cleanup_chain or final_cleanup_chain.
  114.    OLD_CHAIN is the result of a "make" cleanup routine.
  115.    Cleanups are performed until we get back to the old end of the chain.  */

  116. static void
  117. do_my_cleanups (struct cleanup **pmy_chain,
  118.                 struct cleanup *old_chain)
  119. {
  120.   struct cleanup *ptr;

  121.   while ((ptr = *pmy_chain) != old_chain)
  122.     {
  123.       *pmy_chain = ptr->next;        /* Do this first in case of recursion.  */
  124.       (*ptr->function) (ptr->arg);
  125.       if (ptr->free_arg)
  126.         (*ptr->free_arg) (ptr->arg);
  127.       xfree (ptr);
  128.     }
  129. }

  130. /* Return a value that can be passed to do_cleanups, do_final_cleanups to
  131.    indicate perform all cleanups.  */

  132. struct cleanup *
  133. all_cleanups (void)
  134. {
  135.   return SENTINEL_CLEANUP;
  136. }

  137. /* Discard cleanups and do the actions they describe
  138.    until we get back to the point OLD_CHAIN in the cleanup_chain.  */

  139. void
  140. do_cleanups (struct cleanup *old_chain)
  141. {
  142.   do_my_cleanups (&cleanup_chain, old_chain);
  143. }

  144. /* Discard cleanups and do the actions they describe
  145.    until we get back to the point OLD_CHAIN in the final_cleanup_chain.  */

  146. void
  147. do_final_cleanups (struct cleanup *old_chain)
  148. {
  149.   do_my_cleanups (&final_cleanup_chain, old_chain);
  150. }

  151. /* Main worker routine to discard cleanups.
  152.    PMY_CHAIN is a pointer to either cleanup_chain or final_cleanup_chain.
  153.    OLD_CHAIN is the result of a "make" cleanup routine.
  154.    Cleanups are discarded until we get back to the old end of the chain.  */

  155. static void
  156. discard_my_cleanups (struct cleanup **pmy_chain,
  157.                      struct cleanup *old_chain)
  158. {
  159.   struct cleanup *ptr;

  160.   while ((ptr = *pmy_chain) != old_chain)
  161.     {
  162.       *pmy_chain = ptr->next;
  163.       if (ptr->free_arg)
  164.         (*ptr->free_arg) (ptr->arg);
  165.       xfree (ptr);
  166.     }
  167. }

  168. /* Discard cleanups, not doing the actions they describe,
  169.    until we get back to the point OLD_CHAIN in the cleanup chain.  */

  170. void
  171. discard_cleanups (struct cleanup *old_chain)
  172. {
  173.   discard_my_cleanups (&cleanup_chain, old_chain);
  174. }

  175. /* Discard final cleanups, not doing the actions they describe,
  176.    until we get back to the point OLD_CHAIN in the final cleanup chain.  */

  177. void
  178. discard_final_cleanups (struct cleanup *old_chain)
  179. {
  180.   discard_my_cleanups (&final_cleanup_chain, old_chain);
  181. }

  182. /* Main worker routine to save cleanups.
  183.    PMY_CHAIN is a pointer to either cleanup_chain or final_cleanup_chain.
  184.    The chain is emptied and the result is a pointer to the old chain.  */

  185. static struct cleanup *
  186. save_my_cleanups (struct cleanup **pmy_chain)
  187. {
  188.   struct cleanup *old_chain = *pmy_chain;

  189.   *pmy_chain = SENTINEL_CLEANUP;
  190.   return old_chain;
  191. }

  192. /* Set the cleanup_chain to 0, and return the old cleanup_chain.  */

  193. struct cleanup *
  194. save_cleanups (void)
  195. {
  196.   return save_my_cleanups (&cleanup_chain);
  197. }

  198. /* Set the final_cleanup_chain to 0, and return the old
  199.    final_cleanup_chain.  */

  200. struct cleanup *
  201. save_final_cleanups (void)
  202. {
  203.   return save_my_cleanups (&final_cleanup_chain);
  204. }

  205. /* Main worker routine to save cleanups.
  206.    PMY_CHAIN is a pointer to either cleanup_chain or final_cleanup_chain.
  207.    The chain is restored from CHAIN.  */

  208. static void
  209. restore_my_cleanups (struct cleanup **pmy_chain, struct cleanup *chain)
  210. {
  211.   if (*pmy_chain != SENTINEL_CLEANUP)
  212.     internal_warning (__FILE__, __LINE__,
  213.                       _("restore_my_cleanups has found a stale cleanup"));

  214.   *pmy_chain = chain;
  215. }

  216. /* Restore the cleanup chain from a previously saved chain.  */

  217. void
  218. restore_cleanups (struct cleanup *chain)
  219. {
  220.   restore_my_cleanups (&cleanup_chain, chain);
  221. }

  222. /* Restore the final cleanup chain from a previously saved chain.  */

  223. void
  224. restore_final_cleanups (struct cleanup *chain)
  225. {
  226.   restore_my_cleanups (&final_cleanup_chain, chain);
  227. }

  228. /* Provide a known function that does nothing, to use as a base for
  229.    a possibly long chain of cleanups.  This is useful where we
  230.    use the cleanup chain for handling normal cleanups as well as dealing
  231.    with cleanups that need to be done as a result of a call to error().
  232.    In such cases, we may not be certain where the first cleanup is, unless
  233.    we have a do-nothing one to always use as the base.  */

  234. void
  235. null_cleanup (void *arg)
  236. {
  237. }