[pushed] Eliminate most remaining cleanups under gdb/guile/

Message ID f73888ef-d947-baab-471c-93dab6a7c715@redhat.com
State New
Headers show
Series
  • [pushed] Eliminate most remaining cleanups under gdb/guile/
Related show

Commit Message

Pedro Alves July 18, 2018, 10:26 p.m.
I've pushed in this patch, as discussed here:
 https://sourceware.org/ml/gdb-patches/2018-07/msg00542.html

The main complication with the Guile code is that we have two types of
exceptions to consider.  GDB/C++ exceptions, and Guile/SJLJ
exceptions.  Code that is facing the Guile interpreter must not throw
GDB exceptions, instead Scheme exceptions must be thrown.  Also,
because Guile exceptions are SJLJ based, Guile-facing code must not
use local objects with dtors, unless wrapped in a scope with a
TRY/CATCH, because the dtors won't otherwise be run when a Guile
exceptions is thrown.

This commit adds a new gdbscm_wrap wrapper function than encapsulates
a pattern I noticed in many of the functions using
GDBSCM_HANDLE_GDB_EXCEPTION_WITH_CLEANUPS.  The wrapper is written
such that you can pass either a lambda to it, or a function plus a
variable number of forwarded args.  I used a lambda when its body
would be reasonably short, and a separate function in the larger
cases.

This also convers a few functions that were using
GDBSCM_HANDLE_GDB_EXCEPTION to use gdbscm_wrap too because they
followed a similar pattern.

A few cases of make_cleanup calls are replaced with explicit xfree
calls.  The make_cleanup/do_cleanups calls in those cases are
pointless, because do_cleanups won't be called when a Scheme exception
is thrown.

We also have a couple cases of Guile-facing code using RAII-type
objects to manage memory, but those are incorrect, exactly because
their dtor won't be called if a Guile exception is thrown.

gdb/ChangeLog:
2018-07-18  Pedro Alves  <palves@redhat.com>

	* guile/guile-internal.h: Add comment about mixing GDB and Scheme
	exceptions.
	(GDBSCM_HANDLE_GDB_EXCEPTION_WITH_CLEANUPS): Delete.
	(gdbscm_wrap): New.
	* guile/scm-frame.c (gdbscm_frame_read_register): Use xfree
	directly instead of a cleanup.
	* guile/scm-math.c (vlscm_unop_gdbthrow): New, factored out from ...
	(vlscm_unop): ... this.  Reimplement using gdbscm_wrap.
	(vlscm_binop_gdbthrow): New, factored out from ...
	(vlscm_binop): ... this.  Reimplement using gdbscm_wrap.
	(vlscm_rich_compare): Use gdbscm_wrap.
	* guile/scm-symbol.c (gdbscm_lookup_symbol): Use xfree directly
	instead of a cleanup.
	(gdbscm_lookup_global_symbol): Use xfree directly instead of a
	cleanup.
	* guile/scm-type.c (gdbscm_type_field, gdbscm_type_has_field_p):
	Use xfree directly instead of a cleanup.
	* guile/scm-value.c (gdbscm_make_value, gdbscm_make_lazy_value):
	Adjust to use gdbscm_wrap and scoped_value_mark.
	(gdbscm_value_optimized_out_p): Adjust to use gdbscm_wrap.
	(gdbscm_value_address, gdbscm_value_dereference)
	(gdbscm_value_referenced_value): Adjust to use gdbscm_wrap and
	scoped_value_mark.
	(gdbscm_value_dynamic_type): Use scoped_value_mark.
	(vlscm_do_cast, gdbscm_value_field): Adjust to use gdbscm_wrap and
	scoped_value_mark.
	(gdbscm_value_subscript, gdbscm_value_call): Adjust to use
	gdbscm_wrap and scoped_value_mark.
	(gdbscm_value_to_string): Use xfree directly instead of a
	cleanup.  Move 'buffer' unique_ptr to TRY scope.
	(gdbscm_value_to_lazy_string): Use xfree directly instead of a
	cleanup.  Move 'buffer' unique_ptr to TRY scope.  Use
	scoped_value_mark.
	(gdbscm_value_fetch_lazy_x): Use gdbscm_wrap.
	(gdbscm_parse_and_eval): Adjust to use gdbscm_wrap and
	scoped_value_mark.
	(gdbscm_history_ref, gdbscm_history_append_x): Adjust to use
	gdbscm_wrap.
---
 gdb/ChangeLog              |  41 +++++
 gdb/guile/guile-internal.h |  55 ++++--
 gdb/guile/scm-frame.c      |  11 +-
 gdb/guile/scm-math.c       | 374 +++++++++++++++++--------------------
 gdb/guile/scm-symbol.c     |  17 +-
 gdb/guile/scm-type.c       |  16 +-
 gdb/guile/scm-value.c      | 445 +++++++++++++--------------------------------
 7 files changed, 398 insertions(+), 561 deletions(-)

-- 
2.14.4

Patch

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 65096d67203..6d1a1c6df23 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,44 @@ 
+2018-07-18  Pedro Alves  <palves@redhat.com>
+
+	* guile/guile-internal.h: Add comment about mixing GDB and Scheme
+	exceptions.
+	(GDBSCM_HANDLE_GDB_EXCEPTION_WITH_CLEANUPS): Delete.
+	(gdbscm_wrap): New.
+	* guile/scm-frame.c (gdbscm_frame_read_register): Use xfree
+	directly instead of a cleanup.
+	* guile/scm-math.c (vlscm_unop_gdbthrow): New, factored out from ...
+	(vlscm_unop): ... this.  Reimplement using gdbscm_wrap.
+	(vlscm_binop_gdbthrow): New, factored out from ...
+	(vlscm_binop): ... this.  Reimplement using gdbscm_wrap.
+	(vlscm_rich_compare): Use gdbscm_wrap.
+	* guile/scm-symbol.c (gdbscm_lookup_symbol): Use xfree directly
+	instead of a cleanup.
+	(gdbscm_lookup_global_symbol): Use xfree directly instead of a
+	cleanup.
+	* guile/scm-type.c (gdbscm_type_field, gdbscm_type_has_field_p):
+	Use xfree directly instead of a cleanup.
+	* guile/scm-value.c (gdbscm_make_value, gdbscm_make_lazy_value):
+	Adjust to use gdbscm_wrap and scoped_value_mark.
+	(gdbscm_value_optimized_out_p): Adjust to use gdbscm_wrap.
+	(gdbscm_value_address, gdbscm_value_dereference)
+	(gdbscm_value_referenced_value): Adjust to use gdbscm_wrap and
+	scoped_value_mark.
+	(gdbscm_value_dynamic_type): Use scoped_value_mark.
+	(vlscm_do_cast, gdbscm_value_field): Adjust to use gdbscm_wrap and
+	scoped_value_mark.
+	(gdbscm_value_subscript, gdbscm_value_call): Adjust to use
+	gdbscm_wrap and scoped_value_mark.
+	(gdbscm_value_to_string): Use xfree directly instead of a
+	cleanup.  Move 'buffer' unique_ptr to TRY scope.
+	(gdbscm_value_to_lazy_string): Use xfree directly instead of a
+	cleanup.  Move 'buffer' unique_ptr to TRY scope.  Use
+	scoped_value_mark.
+	(gdbscm_value_fetch_lazy_x): Use gdbscm_wrap.
+	(gdbscm_parse_and_eval): Adjust to use gdbscm_wrap and
+	scoped_value_mark.
+	(gdbscm_history_ref, gdbscm_history_append_x): Adjust to use
+	gdbscm_wrap.
+
 2018-07-18  Tom de Vries  <tdevries@suse.de>
 
 	* findvar.c (default_read_var_value): Also resolve dynamic type for
diff --git a/gdb/guile/guile-internal.h b/gdb/guile/guile-internal.h
index 0ef114ac501..20e002a28e2 100644
--- a/gdb/guile/guile-internal.h
+++ b/gdb/guile/guile-internal.h
@@ -639,8 +639,18 @@  extern void gdbscm_initialize_symtabs (void);
 extern void gdbscm_initialize_types (void);
 extern void gdbscm_initialize_values (void);
 
-/* Use these after a TRY_CATCH to throw the appropriate Scheme exception
-   if a GDB error occurred.  */
+
+/* A complication with the Guile code is that we have two types of
+   exceptions to consider.  GDB/C++ exceptions, and Guile/SJLJ
+   exceptions.  Code that is facing the Guile interpreter must not
+   throw GDB exceptions, instead Scheme exceptions must be thrown.
+   Also, because Guile exceptions are SJLJ based, Guile-facing code
+   must not use local objects with dtors, unless wrapped in a scope
+   with a TRY/CATCH, because the dtors won't otherwise be run when a
+   Guile exceptions is thrown.  */
+
+/* Use this after a TRY/CATCH to throw the appropriate Scheme
+   exception if a GDB error occurred.  */
 
 #define GDBSCM_HANDLE_GDB_EXCEPTION(exception)		\
   do {							\
@@ -651,16 +661,35 @@  extern void gdbscm_initialize_values (void);
       }							\
   } while (0)
 
-/* If cleanups are establish outside the TRY_CATCH block, use this version.  */
-
-#define GDBSCM_HANDLE_GDB_EXCEPTION_WITH_CLEANUPS(exception, cleanups)	\
-  do {									\
-    if (exception.reason < 0)						\
-      {									\
-	do_cleanups (cleanups);						\
-	gdbscm_throw_gdb_exception (exception);				\
-        /*NOTREACHED */							\
-      }									\
-  } while (0)
+/* Use this to wrap a callable to throw the appropriate Scheme
+   exception if the callable throws a GDB error.  ARGS are forwarded
+   to FUNC.  Returns the result of FUNC, unless FUNC returns a Scheme
+   exception, in which case that exception is thrown.  Note that while
+   the callable is free to use objects of types with destructors,
+   because GDB errors are C++ exceptions, the caller of gdbscm_wrap
+   must not use such objects, because their destructors would not be
+   called when a Scheme exception is thrown.  */
+
+template<typename Function, typename... Args>
+SCM
+gdbscm_wrap (Function &&func, Args... args)
+{
+  SCM result = SCM_BOOL_F;
+
+  TRY
+    {
+      result = func (std::forward<Args> (args)...);
+    }
+  CATCH (except, RETURN_MASK_ALL)
+    {
+      GDBSCM_HANDLE_GDB_EXCEPTION (except);
+    }
+  END_CATCH
+
+  if (gdbscm_is_exception (result))
+    gdbscm_throw (result);
+
+  return result;
+}
 
 #endif /* GDB_GUILE_INTERNAL_H */
diff --git a/gdb/guile/scm-frame.c b/gdb/guile/scm-frame.c
index 7b539677ffd..afd9702e64f 100644
--- a/gdb/guile/scm-frame.c
+++ b/gdb/guile/scm-frame.c
@@ -783,13 +783,13 @@  gdbscm_frame_read_register (SCM self, SCM register_scm)
   char *register_str;
   struct value *value = NULL;
   struct frame_info *frame = NULL;
-  struct cleanup *cleanup;
   frame_smob *f_smob;
 
   f_smob = frscm_get_frame_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
   gdbscm_parse_function_args (FUNC_NAME, SCM_ARG2, NULL, "s",
 			      register_scm, &register_str);
-  cleanup = make_cleanup (xfree, register_str);
+
+  struct gdb_exception except = exception_none;
 
   TRY
     {
@@ -805,13 +805,14 @@  gdbscm_frame_read_register (SCM self, SCM register_scm)
 	    value = value_of_register (regnum, frame);
 	}
     }
-  CATCH (except, RETURN_MASK_ALL)
+  CATCH (ex, RETURN_MASK_ALL)
     {
-      GDBSCM_HANDLE_GDB_EXCEPTION (except);
+      except = ex;
     }
   END_CATCH
 
-  do_cleanups (cleanup);
+  xfree (register_str);
+  GDBSCM_HANDLE_GDB_EXCEPTION (except);
 
   if (frame == NULL)
     {
diff --git a/gdb/guile/scm-math.c b/gdb/guile/scm-math.c
index 5507dd7d897..74d50754a47 100644
--- a/gdb/guile/scm-math.c
+++ b/gdb/guile/scm-math.c
@@ -67,88 +67,77 @@  enum valscm_binary_opcode
 #define STRIP_REFERENCE(TYPE) \
   ((TYPE_CODE (TYPE) == TYPE_CODE_REF) ? (TYPE_TARGET_TYPE (TYPE)) : (TYPE))
 
-/* Returns a value object which is the result of applying the operation
-   specified by OPCODE to the given argument.
-   If there's an error a Scheme exception is thrown.  */
+/* Helper for vlscm_unop.  Contains all the code that may throw a GDB
+   exception.  */
 
 static SCM
-vlscm_unop (enum valscm_unary_opcode opcode, SCM x, const char *func_name)
+vlscm_unop_gdbthrow (enum valscm_unary_opcode opcode, SCM x,
+		     const char *func_name)
 {
   struct gdbarch *gdbarch = get_current_arch ();
   const struct language_defn *language = current_language;
-  struct value *arg1;
   SCM result = SCM_BOOL_F;
-  struct value *res_val = NULL;
-  SCM except_scm;
-  struct cleanup *cleanups;
 
-  cleanups = make_cleanup_value_free_to_mark (value_mark ());
+  scoped_value_mark free_values;
 
-  arg1 = vlscm_convert_value_from_scheme (func_name, SCM_ARG1, x,
-					  &except_scm, gdbarch, language);
+  SCM except_scm;
+  value *arg1 = vlscm_convert_value_from_scheme (func_name, SCM_ARG1, x,
+						 &except_scm, gdbarch,
+						 language);
   if (arg1 == NULL)
-    {
-      do_cleanups (cleanups);
-      gdbscm_throw (except_scm);
-    }
+    return except_scm;
 
-  TRY
-    {
-      switch (opcode)
-	{
-	case VALSCM_NOT:
-	  /* Alas gdb and guile use the opposite meaning for "logical not".  */
-	  {
-	    struct type *type = language_bool_type (language, gdbarch);
-	    res_val
-	      = value_from_longest (type, (LONGEST) value_logical_not (arg1));
-	  }
-	  break;
-	case VALSCM_NEG:
-	  res_val = value_neg (arg1);
-	  break;
-	case VALSCM_NOP:
-	  /* Seemingly a no-op, but if X was a Scheme value it is now
-	     a <gdb:value> object.  */
-	  res_val = arg1;
-	  break;
-	case VALSCM_ABS:
-	  if (value_less (arg1, value_zero (value_type (arg1), not_lval)))
-	    res_val = value_neg (arg1);
-	  else
-	    res_val = arg1;
-	  break;
-	case VALSCM_LOGNOT:
-	  res_val = value_complement (arg1);
-	  break;
-	default:
-	  gdb_assert_not_reached ("unsupported operation");
-	}
-    }
-  CATCH (except, RETURN_MASK_ALL)
+  struct value *res_val = NULL;
+
+  switch (opcode)
     {
-      GDBSCM_HANDLE_GDB_EXCEPTION_WITH_CLEANUPS (except, cleanups);
+    case VALSCM_NOT:
+      /* Alas gdb and guile use the opposite meaning for "logical
+	 not".  */
+      {
+	struct type *type = language_bool_type (language, gdbarch);
+	res_val
+	  = value_from_longest (type,
+				(LONGEST) value_logical_not (arg1));
+      }
+      break;
+    case VALSCM_NEG:
+      res_val = value_neg (arg1);
+      break;
+    case VALSCM_NOP:
+      /* Seemingly a no-op, but if X was a Scheme value it is now a
+	 <gdb:value> object.  */
+      res_val = arg1;
+      break;
+    case VALSCM_ABS:
+      if (value_less (arg1, value_zero (value_type (arg1), not_lval)))
+	res_val = value_neg (arg1);
+      else
+	res_val = arg1;
+      break;
+    case VALSCM_LOGNOT:
+      res_val = value_complement (arg1);
+      break;
+    default:
+      gdb_assert_not_reached ("unsupported operation");
     }
-  END_CATCH
 
   gdb_assert (res_val != NULL);
-  result = vlscm_scm_from_value (res_val);
-
-  do_cleanups (cleanups);
-
-  if (gdbscm_is_exception (result))
-    gdbscm_throw (result);
+  return vlscm_scm_from_value (res_val);
+}
 
-  return result;
+static SCM
+vlscm_unop (enum valscm_unary_opcode opcode, SCM x, const char *func_name)
+{
+  return gdbscm_wrap (vlscm_unop_gdbthrow, opcode, x, func_name);
 }
 
-/* Returns a value object which is the result of applying the operation
-   specified by OPCODE to the given arguments.
-   If there's an error a Scheme exception is thrown.  */
+/* Helper for vlscm_binop.  Contains all the code that may throw a GDB
+   exception.  */
 
 static SCM
-vlscm_binop (enum valscm_binary_opcode opcode, SCM x, SCM y,
-	     const char *func_name)
+vlscm_binop_gdbthrow (enum valscm_binary_opcode opcode, SCM x, SCM y,
+		      const char *func_name)
 {
   struct gdbarch *gdbarch = get_current_arch ();
   const struct language_defn *language = current_language;
@@ -156,129 +145,119 @@  vlscm_binop (enum valscm_binary_opcode opcode, SCM x, SCM y,
   SCM result = SCM_BOOL_F;
   struct value *res_val = NULL;
   SCM except_scm;
-  struct cleanup *cleanups;
 
-  cleanups = make_cleanup_value_free_to_mark (value_mark ());
+  scoped_value_mark free_values;
 
   arg1 = vlscm_convert_value_from_scheme (func_name, SCM_ARG1, x,
 					  &except_scm, gdbarch, language);
   if (arg1 == NULL)
-    {
-      do_cleanups (cleanups);
-      gdbscm_throw (except_scm);
-    }
+    return except_scm;
+
   arg2 = vlscm_convert_value_from_scheme (func_name, SCM_ARG2, y,
 					  &except_scm, gdbarch, language);
   if (arg2 == NULL)
-    {
-      do_cleanups (cleanups);
-      gdbscm_throw (except_scm);
-    }
+    return except_scm;
 
-  TRY
+  switch (opcode)
     {
-      switch (opcode)
-	{
-	case VALSCM_ADD:
-	  {
-	    struct type *ltype = value_type (arg1);
-	    struct type *rtype = value_type (arg2);
-
-	    ltype = check_typedef (ltype);
-	    ltype = STRIP_REFERENCE (ltype);
-	    rtype = check_typedef (rtype);
-	    rtype = STRIP_REFERENCE (rtype);
-
-	    if (TYPE_CODE (ltype) == TYPE_CODE_PTR
-		&& is_integral_type (rtype))
-	      res_val = value_ptradd (arg1, value_as_long (arg2));
-	    else if (TYPE_CODE (rtype) == TYPE_CODE_PTR
-		     && is_integral_type (ltype))
-	      res_val = value_ptradd (arg2, value_as_long (arg1));
-	    else
-	      res_val = value_binop (arg1, arg2, BINOP_ADD);
-	  }
-	  break;
-	case VALSCM_SUB:
+    case VALSCM_ADD:
+      {
+	struct type *ltype = value_type (arg1);
+	struct type *rtype = value_type (arg2);
+
+	ltype = check_typedef (ltype);
+	ltype = STRIP_REFERENCE (ltype);
+	rtype = check_typedef (rtype);
+	rtype = STRIP_REFERENCE (rtype);
+
+	if (TYPE_CODE (ltype) == TYPE_CODE_PTR
+	    && is_integral_type (rtype))
+	  res_val = value_ptradd (arg1, value_as_long (arg2));
+	else if (TYPE_CODE (rtype) == TYPE_CODE_PTR
+		 && is_integral_type (ltype))
+	  res_val = value_ptradd (arg2, value_as_long (arg1));
+	else
+	  res_val = value_binop (arg1, arg2, BINOP_ADD);
+      }
+      break;
+    case VALSCM_SUB:
+      {
+	struct type *ltype = value_type (arg1);
+	struct type *rtype = value_type (arg2);
+
+	ltype = check_typedef (ltype);
+	ltype = STRIP_REFERENCE (ltype);
+	rtype = check_typedef (rtype);
+	rtype = STRIP_REFERENCE (rtype);
+
+	if (TYPE_CODE (ltype) == TYPE_CODE_PTR
+	    && TYPE_CODE (rtype) == TYPE_CODE_PTR)
 	  {
-	    struct type *ltype = value_type (arg1);
-	    struct type *rtype = value_type (arg2);
-
-	    ltype = check_typedef (ltype);
-	    ltype = STRIP_REFERENCE (ltype);
-	    rtype = check_typedef (rtype);
-	    rtype = STRIP_REFERENCE (rtype);
-
-	    if (TYPE_CODE (ltype) == TYPE_CODE_PTR
-		&& TYPE_CODE (rtype) == TYPE_CODE_PTR)
-	      {
-		/* A ptrdiff_t for the target would be preferable here.  */
-		res_val
-		  = value_from_longest (builtin_type (gdbarch)->builtin_long,
-					value_ptrdiff (arg1, arg2));
-	      }
-	    else if (TYPE_CODE (ltype) == TYPE_CODE_PTR
-		     && is_integral_type (rtype))
-	      res_val = value_ptradd (arg1, - value_as_long (arg2));
-	    else
-	      res_val = value_binop (arg1, arg2, BINOP_SUB);
+	    /* A ptrdiff_t for the target would be preferable here.  */
+	    res_val
+	      = value_from_longest (builtin_type (gdbarch)->builtin_long,
+				    value_ptrdiff (arg1, arg2));
 	  }
-	  break;
-	case VALSCM_MUL:
-	  res_val = value_binop (arg1, arg2, BINOP_MUL);
-	  break;
-	case VALSCM_DIV:
-	  res_val = value_binop (arg1, arg2, BINOP_DIV);
-	  break;
-	case VALSCM_REM:
-	  res_val = value_binop (arg1, arg2, BINOP_REM);
-	  break;
-	case VALSCM_MOD:
-	  res_val = value_binop (arg1, arg2, BINOP_MOD);
-	  break;
-	case VALSCM_POW:
-	  res_val = value_binop (arg1, arg2, BINOP_EXP);
-	  break;
-	case VALSCM_LSH:
-	  res_val = value_binop (arg1, arg2, BINOP_LSH);
-	  break;
-	case VALSCM_RSH:
-	  res_val = value_binop (arg1, arg2, BINOP_RSH);
-	  break;
-	case VALSCM_MIN:
-	  res_val = value_binop (arg1, arg2, BINOP_MIN);
-	  break;
-	case VALSCM_MAX:
-	  res_val = value_binop (arg1, arg2, BINOP_MAX);
-	  break;
-	case VALSCM_BITAND:
-	  res_val = value_binop (arg1, arg2, BINOP_BITWISE_AND);
-	  break;
-	case VALSCM_BITOR:
-	  res_val = value_binop (arg1, arg2, BINOP_BITWISE_IOR);
-	  break;
-	case VALSCM_BITXOR:
-	  res_val = value_binop (arg1, arg2, BINOP_BITWISE_XOR);
-	  break;
-	default:
-	  gdb_assert_not_reached ("unsupported operation");
-	}
-    }
-  CATCH (except, RETURN_MASK_ALL)
-    {
-      GDBSCM_HANDLE_GDB_EXCEPTION_WITH_CLEANUPS (except, cleanups);
+	else if (TYPE_CODE (ltype) == TYPE_CODE_PTR
+		 && is_integral_type (rtype))
+	  res_val = value_ptradd (arg1, - value_as_long (arg2));
+	else
+	  res_val = value_binop (arg1, arg2, BINOP_SUB);
+      }
+      break;
+    case VALSCM_MUL:
+      res_val = value_binop (arg1, arg2, BINOP_MUL);
+      break;
+    case VALSCM_DIV:
+      res_val = value_binop (arg1, arg2, BINOP_DIV);
+      break;
+    case VALSCM_REM:
+      res_val = value_binop (arg1, arg2, BINOP_REM);
+      break;
+    case VALSCM_MOD:
+      res_val = value_binop (arg1, arg2, BINOP_MOD);
+      break;
+    case VALSCM_POW:
+      res_val = value_binop (arg1, arg2, BINOP_EXP);
+      break;
+    case VALSCM_LSH:
+      res_val = value_binop (arg1, arg2, BINOP_LSH);
+      break;
+    case VALSCM_RSH:
+      res_val = value_binop (arg1, arg2, BINOP_RSH);
+      break;
+    case VALSCM_MIN:
+      res_val = value_binop (arg1, arg2, BINOP_MIN);
+      break;
+    case VALSCM_MAX:
+      res_val = value_binop (arg1, arg2, BINOP_MAX);
+      break;
+    case VALSCM_BITAND:
+      res_val = value_binop (arg1, arg2, BINOP_BITWISE_AND);
+      break;
+    case VALSCM_BITOR:
+      res_val = value_binop (arg1, arg2, BINOP_BITWISE_IOR);
+      break;
+    case VALSCM_BITXOR:
+      res_val = value_binop (arg1, arg2, BINOP_BITWISE_XOR);
+      break;
+    default:
+      gdb_assert_not_reached ("unsupported operation");
     }
-  END_CATCH
 
   gdb_assert (res_val != NULL);
-  result = vlscm_scm_from_value (res_val);
-
-  do_cleanups (cleanups);
+  return vlscm_scm_from_value (res_val);
+}
 
-  if (gdbscm_is_exception (result))
-    gdbscm_throw (result);
+/* Returns a value object which is the result of applying the operation
+   specified by OPCODE to the given arguments.
+   If there's an error a Scheme exception is thrown.  */
 
-  return result;
+static SCM
+vlscm_binop (enum valscm_binary_opcode opcode, SCM x, SCM y,
+	     const char *func_name)
+{
+  return gdbscm_wrap (vlscm_binop_gdbthrow, opcode, x, y, func_name);
 }
 
 /* (value-add x y) -> <gdb:value> */
@@ -439,33 +418,27 @@  gdbscm_value_logxor (SCM x, SCM y)
 static SCM
 vlscm_rich_compare (int op, SCM x, SCM y, const char *func_name)
 {
-  struct gdbarch *gdbarch = get_current_arch ();
-  const struct language_defn *language = current_language;
-  struct value *v1, *v2;
-  int result = 0;
-  SCM except_scm;
-  struct cleanup *cleanups;
-  struct gdb_exception except = exception_none;
+  return gdbscm_wrap ([=]
+    {
+      struct gdbarch *gdbarch = get_current_arch ();
+      const struct language_defn *language = current_language;
+      SCM except_scm;
 
-  cleanups = make_cleanup_value_free_to_mark (value_mark ());
+      scoped_value_mark free_values;
 
-  v1 = vlscm_convert_value_from_scheme (func_name, SCM_ARG1, x,
-					&except_scm, gdbarch, language);
-  if (v1 == NULL)
-    {
-      do_cleanups (cleanups);
-      gdbscm_throw (except_scm);
-    }
-  v2 = vlscm_convert_value_from_scheme (func_name, SCM_ARG2, y,
-					&except_scm, gdbarch, language);
-  if (v2 == NULL)
-    {
-      do_cleanups (cleanups);
-      gdbscm_throw (except_scm);
-    }
+      value *v1
+	= vlscm_convert_value_from_scheme (func_name, SCM_ARG1, x,
+					   &except_scm, gdbarch, language);
+      if (v1 == NULL)
+	return except_scm;
 
-  TRY
-    {
+      value *v2
+	= vlscm_convert_value_from_scheme (func_name, SCM_ARG2, y,
+					   &except_scm, gdbarch, language);
+      if (v2 == NULL)
+	return except_scm;
+
+      int result;
       switch (op)
 	{
         case BINOP_LESS:
@@ -489,18 +462,9 @@  vlscm_rich_compare (int op, SCM x, SCM y, const char *func_name)
 	  break;
 	default:
 	  gdb_assert_not_reached ("invalid <gdb:value> comparison");
-      }
-    }
-  CATCH (ex, RETURN_MASK_ALL)
-    {
-      except = ex;
-    }
-  END_CATCH
-
-  do_cleanups (cleanups);
-  GDBSCM_HANDLE_GDB_EXCEPTION (except);
-
-  return scm_from_bool (result);
+	}
+      return scm_from_bool (result);
+    });
 }
 
 /* (value=? x y) -> boolean
diff --git a/gdb/guile/scm-symbol.c b/gdb/guile/scm-symbol.c
index 88027067a30..8495ca5b0a3 100644
--- a/gdb/guile/scm-symbol.c
+++ b/gdb/guile/scm-symbol.c
@@ -582,16 +582,12 @@  gdbscm_lookup_symbol (SCM name_scm, SCM rest)
   int block_arg_pos = -1, domain_arg_pos = -1;
   struct field_of_this_result is_a_field_of_this;
   struct symbol *symbol = NULL;
-  struct cleanup *cleanups;
-  struct gdb_exception except = exception_none;
 
   gdbscm_parse_function_args (FUNC_NAME, SCM_ARG1, keywords, "s#Oi",
 			      name_scm, &name, rest,
 			      &block_arg_pos, &block_scm,
 			      &domain_arg_pos, &domain);
 
-  cleanups = make_cleanup (xfree, name);
-
   if (block_arg_pos >= 0)
     {
       SCM except_scm;
@@ -600,7 +596,7 @@  gdbscm_lookup_symbol (SCM name_scm, SCM rest)
 				  &except_scm);
       if (block == NULL)
 	{
-	  do_cleanups (cleanups);
+	  xfree (name);
 	  gdbscm_throw (except_scm);
 	}
     }
@@ -615,11 +611,13 @@  gdbscm_lookup_symbol (SCM name_scm, SCM rest)
 	}
       CATCH (except, RETURN_MASK_ALL)
 	{
-	  GDBSCM_HANDLE_GDB_EXCEPTION_WITH_CLEANUPS (except, cleanups);
+	  xfree (name);
+	  GDBSCM_HANDLE_GDB_EXCEPTION (except);
 	}
       END_CATCH
     }
 
+  struct gdb_exception except = exception_none;
   TRY
     {
       symbol = lookup_symbol (name, block, (domain_enum) domain,
@@ -631,7 +629,7 @@  gdbscm_lookup_symbol (SCM name_scm, SCM rest)
     }
   END_CATCH
 
-  do_cleanups (cleanups);
+  xfree (name);
   GDBSCM_HANDLE_GDB_EXCEPTION (except);
 
   if (symbol == NULL)
@@ -652,15 +650,12 @@  gdbscm_lookup_global_symbol (SCM name_scm, SCM rest)
   int domain_arg_pos = -1;
   int domain = VAR_DOMAIN;
   struct symbol *symbol = NULL;
-  struct cleanup *cleanups;
   struct gdb_exception except = exception_none;
 
   gdbscm_parse_function_args (FUNC_NAME, SCM_ARG1, keywords, "s#i",
 			      name_scm, &name, rest,
 			      &domain_arg_pos, &domain);
 
-  cleanups = make_cleanup (xfree, name);
-
   TRY
     {
       symbol = lookup_global_symbol (name, NULL, (domain_enum) domain).symbol;
@@ -671,7 +666,7 @@  gdbscm_lookup_global_symbol (SCM name_scm, SCM rest)
     }
   END_CATCH
 
-  do_cleanups (cleanups);
+  xfree (name);
   GDBSCM_HANDLE_GDB_EXCEPTION (except);
 
   if (symbol == NULL)
diff --git a/gdb/guile/scm-type.c b/gdb/guile/scm-type.c
index cc997563dab..5c4490d5ffc 100644
--- a/gdb/guile/scm-type.c
+++ b/gdb/guile/scm-type.c
@@ -977,7 +977,6 @@  gdbscm_type_field (SCM self, SCM field_scm)
   struct type *type = t_smob->type;
   char *field;
   int i;
-  struct cleanup *cleanups;
 
   SCM_ASSERT_TYPE (scm_is_string (field_scm), field_scm, SCM_ARG2, FUNC_NAME,
 		   _("string"));
@@ -992,7 +991,6 @@  gdbscm_type_field (SCM self, SCM field_scm)
 			       _(not_composite_error));
 
   field = gdbscm_scm_to_c_string (field_scm);
-  cleanups = make_cleanup (xfree, field);
 
   for (i = 0; i < TYPE_NFIELDS (type); i++)
     {
@@ -1000,12 +998,12 @@  gdbscm_type_field (SCM self, SCM field_scm)
 
       if (t_field_name && (strcmp_iw (t_field_name, field) == 0))
 	{
-	    do_cleanups (cleanups);
-	    return tyscm_make_field_smob (self, i);
+	  xfree (field);
+	  return tyscm_make_field_smob (self, i);
 	}
     }
 
-  do_cleanups (cleanups);
+  xfree (field);
 
   gdbscm_out_of_range_error (FUNC_NAME, SCM_ARG1, field_scm,
 			     _("Unknown field"));
@@ -1022,7 +1020,6 @@  gdbscm_type_has_field_p (SCM self, SCM field_scm)
   struct type *type = t_smob->type;
   char *field;
   int i;
-  struct cleanup *cleanups;
 
   SCM_ASSERT_TYPE (scm_is_string (field_scm), field_scm, SCM_ARG2, FUNC_NAME,
 		   _("string"));
@@ -1037,7 +1034,6 @@  gdbscm_type_has_field_p (SCM self, SCM field_scm)
 			       _(not_composite_error));
 
   field = gdbscm_scm_to_c_string (field_scm);
-  cleanups = make_cleanup (xfree, field);
 
   for (i = 0; i < TYPE_NFIELDS (type); i++)
     {
@@ -1045,12 +1041,12 @@  gdbscm_type_has_field_p (SCM self, SCM field_scm)
 
       if (t_field_name && (strcmp_iw (t_field_name, field) == 0))
 	{
-	    do_cleanups (cleanups);
-	    return SCM_BOOL_T;
+	  xfree (field);
+	  return SCM_BOOL_T;
 	}
     }
 
-  do_cleanups (cleanups);
+  xfree (field);
 
   return SCM_BOOL_F;
 }
diff --git a/gdb/guile/scm-value.c b/gdb/guile/scm-value.c
index fccddfec413..8d42d930bce 100644
--- a/gdb/guile/scm-value.c
+++ b/gdb/guile/scm-value.c
@@ -303,46 +303,38 @@  vlscm_scm_to_value (SCM v_scm)
 static SCM
 gdbscm_make_value (SCM x, SCM rest)
 {
-  struct gdbarch *gdbarch = get_current_arch ();
-  const struct language_defn *language = current_language;
   const SCM keywords[] = { type_keyword, SCM_BOOL_F };
+
   int type_arg_pos = -1;
   SCM type_scm = SCM_UNDEFINED;
-  SCM except_scm, result;
-  type_smob *t_smob;
-  struct type *type = NULL;
-  struct value *value;
-  struct cleanup *cleanups;
-
   gdbscm_parse_function_args (FUNC_NAME, SCM_ARG2, keywords, "#O", rest,
 			      &type_arg_pos, &type_scm);
 
+  struct type *type = NULL;
   if (type_arg_pos > 0)
     {
-      t_smob = tyscm_get_type_smob_arg_unsafe (type_scm, type_arg_pos,
-					       FUNC_NAME);
+      type_smob *t_smob = tyscm_get_type_smob_arg_unsafe (type_scm,
+							  type_arg_pos,
+							  FUNC_NAME);
       type = tyscm_type_smob_type (t_smob);
     }
 
-  cleanups = make_cleanup_value_free_to_mark (value_mark ());
+  return gdbscm_wrap ([=]
+    {
+      scoped_value_mark free_values;
 
-  value = vlscm_convert_typed_value_from_scheme (FUNC_NAME, SCM_ARG1, x,
+      SCM except_scm;
+      struct value *value
+	= vlscm_convert_typed_value_from_scheme (FUNC_NAME, SCM_ARG1, x,
 						 type_arg_pos, type_scm, type,
 						 &except_scm,
-						 gdbarch, language);
-  if (value == NULL)
-    {
-      do_cleanups (cleanups);
-      gdbscm_throw (except_scm);
-    }
+						 get_current_arch (),
+						 current_language);
+      if (value == NULL)
+	return except_scm;
 
-  result = vlscm_scm_from_value (value);
-
-  do_cleanups (cleanups);
-
-  if (gdbscm_is_exception (result))
-    gdbscm_throw (result);
-  return result;
+      return vlscm_scm_from_value (value);
+    });
 }
 
 /* (make-lazy-value <gdb:type> address) -> <gdb:value> */
@@ -350,40 +342,22 @@  gdbscm_make_value (SCM x, SCM rest)
 static SCM
 gdbscm_make_lazy_value (SCM type_scm, SCM address_scm)
 {
-  type_smob *t_smob;
-  struct type *type;
-  ULONGEST address;
-  struct value *value = NULL;
-  SCM result;
-  struct cleanup *cleanups;
-
-  t_smob = tyscm_get_type_smob_arg_unsafe (type_scm, SCM_ARG1, FUNC_NAME);
-  type = tyscm_type_smob_type (t_smob);
+  type_smob *t_smob = tyscm_get_type_smob_arg_unsafe (type_scm,
+						      SCM_ARG1, FUNC_NAME);
+  struct type *type = tyscm_type_smob_type (t_smob);
 
+  ULONGEST address;
   gdbscm_parse_function_args (FUNC_NAME, SCM_ARG2, NULL, "U",
 			      address_scm, &address);
 
-  cleanups = make_cleanup_value_free_to_mark (value_mark ());
-
-  /* There's no (current) need to wrap this in a TRY_CATCH, but for consistency
-     and future-proofing we do.  */
-  TRY
-  {
-    value = value_from_contents_and_address (type, NULL, address);
-  }
-  CATCH (except, RETURN_MASK_ALL)
+  return gdbscm_wrap ([=]
     {
-      GDBSCM_HANDLE_GDB_EXCEPTION_WITH_CLEANUPS (except, cleanups);
-    }
-  END_CATCH
-
-  result = vlscm_scm_from_value (value);
+      scoped_value_mark free_values;
 
-  do_cleanups (cleanups);
-
-  if (gdbscm_is_exception (result))
-    gdbscm_throw (result);
-  return result;
+      struct value *value = value_from_contents_and_address (type, NULL,
+							     address);
+      return vlscm_scm_from_value (value);
+    });
 }
 
 /* (value-optimized-out? <gdb:value>) -> boolean */
@@ -393,20 +367,11 @@  gdbscm_value_optimized_out_p (SCM self)
 {
   value_smob *v_smob
     = vlscm_get_value_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
-  struct value *value = v_smob->value;
-  int opt = 0;
 
-  TRY
-    {
-      opt = value_optimized_out (value);
-    }
-  CATCH (except, RETURN_MASK_ALL)
+  return gdbscm_wrap ([=]
     {
-      GDBSCM_HANDLE_GDB_EXCEPTION (except);
-    }
-  END_CATCH
-
-  return scm_from_bool (opt);
+      return scm_from_bool (value_optimized_out (v_smob->value));
+    });
 }
 
 /* (value-address <gdb:value>) -> integer
@@ -419,30 +384,31 @@  gdbscm_value_address (SCM self)
     = vlscm_get_value_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
   struct value *value = v_smob->value;
 
-  if (SCM_UNBNDP (v_smob->address))
+  return gdbscm_wrap ([=]
     {
-      struct cleanup *cleanup
-	= make_cleanup_value_free_to_mark (value_mark ());
-      SCM address = SCM_BOOL_F;
-
-      TRY
+      if (SCM_UNBNDP (v_smob->address))
 	{
-	  address = vlscm_scm_from_value (value_addr (value));
-	}
-      CATCH (except, RETURN_MASK_ALL)
-	{
-	}
-      END_CATCH
+	  scoped_value_mark free_values;
 
-      do_cleanups (cleanup);
+	  SCM address = SCM_BOOL_F;
 
-      if (gdbscm_is_exception (address))
-	gdbscm_throw (address);
+	  TRY
+	    {
+	      address = vlscm_scm_from_value (value_addr (value));
+	    }
+	  CATCH (except, RETURN_MASK_ALL)
+	    {
+	    }
+	  END_CATCH
 
-      v_smob->address = address;
-    }
+	  if (gdbscm_is_exception (address))
+	    return address;
+
+	  v_smob->address = address;
+	}
 
-  return v_smob->address;
+      return v_smob->address;
+    });
 }
 
 /* (value-dereference <gdb:value>) -> <gdb:value>
@@ -453,31 +419,14 @@  gdbscm_value_dereference (SCM self)
 {
   value_smob *v_smob
     = vlscm_get_value_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
-  struct value *value = v_smob->value;
-  SCM result;
-  struct value *res_val = NULL;
-  struct cleanup *cleanups;
-
-  cleanups = make_cleanup_value_free_to_mark (value_mark ());
 
-  TRY
+  return gdbscm_wrap ([=]
     {
-      res_val = value_ind (value);
-    }
-  CATCH (except, RETURN_MASK_ALL)
-    {
-      GDBSCM_HANDLE_GDB_EXCEPTION_WITH_CLEANUPS (except, cleanups);
-    }
-  END_CATCH
+      scoped_value_mark free_values;
 
-  result = vlscm_scm_from_value (res_val);
-
-  do_cleanups (cleanups);
-
-  if (gdbscm_is_exception (result))
-    gdbscm_throw (result);
-
-  return result;
+      struct value *res_val = value_ind (v_smob->value);
+      return vlscm_scm_from_value (res_val);
+    });
 }
 
 /* (value-referenced-value <gdb:value>) -> <gdb:value>
@@ -495,14 +444,13 @@  gdbscm_value_referenced_value (SCM self)
   value_smob *v_smob
     = vlscm_get_value_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
   struct value *value = v_smob->value;
-  SCM result;
-  struct value *res_val = NULL;
-  struct cleanup *cleanups;
-
-  cleanups = make_cleanup_value_free_to_mark (value_mark ());
 
-  TRY
+  return gdbscm_wrap ([=]
     {
+      scoped_value_mark free_values;
+
+      struct value *res_val;
+
       switch (TYPE_CODE (check_typedef (value_type (value))))
         {
         case TYPE_CODE_PTR:
@@ -515,21 +463,9 @@  gdbscm_value_referenced_value (SCM self)
           error (_("Trying to get the referenced value from a value which is"
 		   " neither a pointer nor a reference"));
         }
-    }
-  CATCH (except, RETURN_MASK_ALL)
-    {
-      GDBSCM_HANDLE_GDB_EXCEPTION_WITH_CLEANUPS (except, cleanups);
-    }
-  END_CATCH
-
-  result = vlscm_scm_from_value (res_val);
 
-  do_cleanups (cleanups);
-
-  if (gdbscm_is_exception (result))
-    gdbscm_throw (result);
-
-  return result;
+      return vlscm_scm_from_value (res_val);
+    });
 }
 
 /* (value-type <gdb:value>) -> <gdb:type> */
@@ -562,8 +498,7 @@  gdbscm_value_dynamic_type (SCM self)
 
   TRY
     {
-      struct cleanup *cleanup
-	= make_cleanup_value_free_to_mark (value_mark ());
+      scoped_value_mark free_values;
 
       type = value_type (value);
       type = check_typedef (type);
@@ -596,8 +531,6 @@  gdbscm_value_dynamic_type (SCM self)
 	  /* Re-use object's static type.  */
 	  type = NULL;
 	}
-
-      do_cleanups (cleanup);
     }
   CATCH (except, RETURN_MASK_ALL)
     {
@@ -625,14 +558,12 @@  vlscm_do_cast (SCM self, SCM type_scm, enum exp_opcode op,
   type_smob *t_smob
     = tyscm_get_type_smob_arg_unsafe (type_scm, SCM_ARG2, FUNC_NAME);
   struct type *type = tyscm_type_smob_type (t_smob);
-  SCM result;
-  struct value *res_val = NULL;
-  struct cleanup *cleanups;
-
-  cleanups = make_cleanup_value_free_to_mark (value_mark ());
 
-  TRY
+  return gdbscm_wrap ([=]
     {
+      scoped_value_mark free_values;
+
+      struct value *res_val;
       if (op == UNOP_DYNAMIC_CAST)
 	res_val = value_dynamic_cast (type, value);
       else if (op == UNOP_REINTERPRET_CAST)
@@ -642,22 +573,9 @@  vlscm_do_cast (SCM self, SCM type_scm, enum exp_opcode op,
 	  gdb_assert (op == UNOP_CAST);
 	  res_val = value_cast (type, value);
 	}
-    }
-  CATCH (except, RETURN_MASK_ALL)
-    {
-      GDBSCM_HANDLE_GDB_EXCEPTION_WITH_CLEANUPS (except, cleanups);
-    }
-  END_CATCH
-
-  gdb_assert (res_val != NULL);
-  result = vlscm_scm_from_value (res_val);
-
-  do_cleanups (cleanups);
 
-  if (gdbscm_is_exception (result))
-    gdbscm_throw (result);
-
-  return result;
+      return vlscm_scm_from_value (res_val);
+    });
 }
 
 /* (value-cast <gdb:value> <gdb:type>) -> <gdb:value> */
@@ -693,42 +611,29 @@  gdbscm_value_field (SCM self, SCM field_scm)
 {
   value_smob *v_smob
     = vlscm_get_value_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
-  struct value *value = v_smob->value;
-  char *field = NULL;
-  struct value *res_val = NULL;
-  SCM result;
-  struct cleanup *cleanups;
 
   SCM_ASSERT_TYPE (scm_is_string (field_scm), field_scm, SCM_ARG2, FUNC_NAME,
 		   _("string"));
 
-  cleanups = make_cleanup_value_free_to_mark (value_mark ());
+  return gdbscm_wrap ([=]
+    {
+      scoped_value_mark free_values;
 
-  field = gdbscm_scm_to_c_string (field_scm);
-  make_cleanup (xfree, field);
+      char *field = gdbscm_scm_to_c_string (field_scm);
 
-  TRY
-    {
-      struct value *tmp = value;
+      struct cleanup *cleanups = make_cleanup (xfree, field);
 
-      res_val = value_struct_elt (&tmp, NULL, field, NULL,
-				  "struct/class/union");
-    }
-  CATCH (except, RETURN_MASK_ALL)
-    {
-      GDBSCM_HANDLE_GDB_EXCEPTION_WITH_CLEANUPS (except, cleanups);
-    }
-  END_CATCH
+      struct value *tmp = v_smob->value;
 
-  gdb_assert (res_val != NULL);
-  result = vlscm_scm_from_value (res_val);
+      struct value *res_val = value_struct_elt (&tmp, NULL, field, NULL,
+						"struct/class/union");
 
-  do_cleanups (cleanups);
+      SCM result = vlscm_scm_from_value (res_val);
 
-  if (gdbscm_is_exception (result))
-    gdbscm_throw (result);
+      do_cleanups (cleanups);
 
-  return result;
+      return result;
+    });
 }
 
 /* (value-subscript <gdb:value> integer|<gdb:value>) -> <gdb:value>
@@ -740,61 +645,36 @@  gdbscm_value_subscript (SCM self, SCM index_scm)
   value_smob *v_smob
     = vlscm_get_value_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
   struct value *value = v_smob->value;
-  struct value *index = NULL;
-  struct value *res_val = NULL;
   struct type *type = value_type (value);
-  struct gdbarch *gdbarch;
-  SCM result, except_scm;
-  struct cleanup *cleanups;
-
-  /* The sequencing here, as everywhere else, is important.
-     We can't have existing cleanups when a Scheme exception is thrown.  */
 
   SCM_ASSERT (type != NULL, self, SCM_ARG2, FUNC_NAME);
-  gdbarch = get_type_arch (type);
-
-  cleanups = make_cleanup_value_free_to_mark (value_mark ());
 
-  index = vlscm_convert_value_from_scheme (FUNC_NAME, SCM_ARG2, index_scm,
-					   &except_scm,
-					   gdbarch, current_language);
-  if (index == NULL)
+  return gdbscm_wrap ([=]
     {
-      do_cleanups (cleanups);
-      gdbscm_throw (except_scm);
-    }
+      scoped_value_mark free_values;
 
-  TRY
-    {
-      struct value *tmp = value;
+      SCM except_scm;
+      struct value *index
+	= vlscm_convert_value_from_scheme (FUNC_NAME, SCM_ARG2, index_scm,
+					   &except_scm,
+					   get_type_arch (type),
+					   current_language);
+      if (index == NULL)
+	return except_scm;
 
       /* Assume we are attempting an array access, and let the value code
 	 throw an exception if the index has an invalid type.
 	 Check the value's type is something that can be accessed via
 	 a subscript.  */
-      tmp = coerce_ref (tmp);
-      type = check_typedef (value_type (tmp));
-      if (TYPE_CODE (type) != TYPE_CODE_ARRAY
-	  && TYPE_CODE (type) != TYPE_CODE_PTR)
+      struct value *tmp = coerce_ref (value);
+      struct type *tmp_type = check_typedef (value_type (tmp));
+      if (TYPE_CODE (tmp_type) != TYPE_CODE_ARRAY
+	  && TYPE_CODE (tmp_type) != TYPE_CODE_PTR)
 	error (_("Cannot subscript requested type"));
 
-      res_val = value_subscript (tmp, value_as_long (index));
-   }
-  CATCH (except, RETURN_MASK_ALL)
-    {
-      GDBSCM_HANDLE_GDB_EXCEPTION_WITH_CLEANUPS (except, cleanups);
-    }
-  END_CATCH
-
-  gdb_assert (res_val != NULL);
-  result = vlscm_scm_from_value (res_val);
-
-  do_cleanups (cleanups);
-
-  if (gdbscm_is_exception (result))
-    gdbscm_throw (result);
-
-  return result;
+      struct value *res_val = value_subscript (tmp, value_as_long (index));
+      return vlscm_scm_from_value (res_val);
+    });
 }
 
 /* (value-call <gdb:value> arg-list) -> <gdb:value>
@@ -854,25 +734,14 @@  gdbscm_value_call (SCM self, SCM args)
       gdb_assert (gdbscm_is_true (scm_null_p (args)));
     }
 
-  TRY
+  return gdbscm_wrap ([=]
     {
-      struct cleanup *cleanup = make_cleanup_value_free_to_mark (mark);
-      struct value *return_value;
+      scoped_value_mark free_values;
 
-      return_value = call_function_by_hand (function, NULL, args_count, vargs);
-      result = vlscm_scm_from_value (return_value);
-      do_cleanups (cleanup);
-    }
-  CATCH (except, RETURN_MASK_ALL)
-    {
-      GDBSCM_HANDLE_GDB_EXCEPTION (except);
-    }
-  END_CATCH
-
-  if (gdbscm_is_exception (result))
-    gdbscm_throw (result);
-
-  return result;
+      value *return_value = call_function_by_hand (function, NULL,
+						   args_count, vargs);
+      return vlscm_scm_from_value (return_value);
+    });
 }
 
 /* (value->bytevector <gdb:value>) -> bytevector */
@@ -1105,12 +974,11 @@  gdbscm_value_to_string (SCM self, SCM rest)
   int encoding_arg_pos = -1, errors_arg_pos = -1, length_arg_pos = -1;
   char *encoding = NULL;
   SCM errors = SCM_BOOL_F;
+  gdb_byte *buffer_contents;
   int length = -1;
-  gdb::unique_xmalloc_ptr<gdb_byte> buffer;
   const char *la_encoding = NULL;
   struct type *char_type = NULL;
   SCM result;
-  struct cleanup *cleanups;
 
   /* The sequencing here, as everywhere else, is important.
      We can't have existing cleanups when a Scheme exception is thrown.  */
@@ -1120,8 +988,6 @@  gdbscm_value_to_string (SCM self, SCM rest)
 			      &errors_arg_pos, &errors,
 			      &length_arg_pos, &length);
 
-  cleanups = make_cleanup (xfree, encoding);
-
   if (errors_arg_pos > 0
       && errors != SCM_BOOL_F
       && !scm_is_eq (errors, error_symbol)
@@ -1131,7 +997,7 @@  gdbscm_value_to_string (SCM self, SCM rest)
 	= gdbscm_make_out_of_range_error (FUNC_NAME, errors_arg_pos, errors,
 					  _("invalid error kind"));
 
-      do_cleanups (cleanups);
+      xfree (encoding);
       gdbscm_throw (excp);
     }
   if (errors == SCM_BOOL_F)
@@ -1148,22 +1014,23 @@  gdbscm_value_to_string (SCM self, SCM rest)
 
   TRY
     {
+      gdb::unique_xmalloc_ptr<gdb_byte> buffer;
       LA_GET_STRING (value, &buffer, &length, &char_type, &la_encoding);
+      buffer_contents = buffer.release ();
     }
   CATCH (except, RETURN_MASK_ALL)
     {
-      GDBSCM_HANDLE_GDB_EXCEPTION_WITH_CLEANUPS (except, cleanups);
+      xfree (encoding);
+      GDBSCM_HANDLE_GDB_EXCEPTION (except);
     }
   END_CATCH
 
-  /* If errors is "error" scm_from_stringn may throw a Scheme exception.
+  /* If errors is "error", scm_from_stringn may throw a Scheme exception.
      Make sure we don't leak.  This is done via scm_dynwind_begin, et.al.  */
-  discard_cleanups (cleanups);
 
   scm_dynwind_begin ((scm_t_dynwind_flags) 0);
 
   gdbscm_dynwind_xfree (encoding);
-  gdb_byte *buffer_contents = buffer.release ();
   gdbscm_dynwind_xfree (buffer_contents);
 
   result = scm_from_stringn ((const char *) buffer_contents,
@@ -1202,7 +1069,6 @@  gdbscm_value_to_lazy_string (SCM self, SCM rest)
   char *encoding = NULL;
   int length = -1;
   SCM result = SCM_BOOL_F; /* -Wall */
-  struct cleanup *cleanups;
   struct gdb_exception except = exception_none;
 
   /* The sequencing here, as everywhere else, is important.
@@ -1219,12 +1085,10 @@  gdbscm_value_to_lazy_string (SCM self, SCM rest)
 				 _("invalid length"));
     }
 
-  cleanups = make_cleanup (xfree, encoding);
-
   TRY
     {
-      struct cleanup *inner_cleanup
-	= make_cleanup_value_free_to_mark (value_mark ());
+      scoped_value_mark free_values;
+
       struct type *type, *realtype;
       CORE_ADDR addr;
 
@@ -1275,8 +1139,6 @@  gdbscm_value_to_lazy_string (SCM self, SCM rest)
 	}
 
       result = lsscm_make_lazy_string (addr, length, encoding, type);
-
-      do_cleanups (inner_cleanup);
     }
   CATCH (ex, RETURN_MASK_ALL)
     {
@@ -1284,7 +1146,7 @@  gdbscm_value_to_lazy_string (SCM self, SCM rest)
     }
   END_CATCH
 
-  do_cleanups (cleanups);
+  xfree (encoding);
   GDBSCM_HANDLE_GDB_EXCEPTION (except);
 
   if (gdbscm_is_exception (result))
@@ -1314,18 +1176,12 @@  gdbscm_value_fetch_lazy_x (SCM self)
     = vlscm_get_value_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
   struct value *value = v_smob->value;
 
-  TRY
+  return gdbscm_wrap ([=]
     {
       if (value_lazy (value))
 	value_fetch_lazy (value);
-    }
-  CATCH (except, RETURN_MASK_ALL)
-    {
-      GDBSCM_HANDLE_GDB_EXCEPTION (except);
-    }
-  END_CATCH
-
-  return SCM_UNSPECIFIED;
+      return SCM_UNSPECIFIED;
+    });
 }
 
 /* (value-print <gdb:value>) -> string */
@@ -1369,38 +1225,14 @@  static SCM
 gdbscm_parse_and_eval (SCM expr_scm)
 {
   char *expr_str;
-  struct value *res_val = NULL;
-  SCM result;
-  struct cleanup *cleanups;
-
-  /* The sequencing here, as everywhere else, is important.
-     We can't have existing cleanups when a Scheme exception is thrown.  */
-
   gdbscm_parse_function_args (FUNC_NAME, SCM_ARG1, NULL, "s",
 			      expr_scm, &expr_str);
 
-  cleanups = make_cleanup_value_free_to_mark (value_mark ());
-  make_cleanup (xfree, expr_str);
-
-  TRY
-    {
-      res_val = parse_and_eval (expr_str);
-    }
-  CATCH (except, RETURN_MASK_ALL)
+  return gdbscm_wrap ([=]
     {
-      GDBSCM_HANDLE_GDB_EXCEPTION_WITH_CLEANUPS (except, cleanups);
-    }
-  END_CATCH
-
-  gdb_assert (res_val != NULL);
-  result = vlscm_scm_from_value (res_val);
-
-  do_cleanups (cleanups);
-
-  if (gdbscm_is_exception (result))
-    gdbscm_throw (result);
-
-  return result;
+      scoped_value_mark free_values;
+      return vlscm_scm_from_value (parse_and_eval (expr_str));
+    });
 }
 
 /* (history-ref integer) -> <gdb:value>
@@ -1410,21 +1242,12 @@  static SCM
 gdbscm_history_ref (SCM index)
 {
   int i;
-  struct value *res_val = NULL; /* Initialize to appease gcc warning.  */
-
   gdbscm_parse_function_args (FUNC_NAME, SCM_ARG1, NULL, "i", index, &i);
 
-  TRY
+  return gdbscm_wrap ([=]
     {
-      res_val = access_value_history (i);
-    }
-  CATCH (except, RETURN_MASK_ALL)
-    {
-      GDBSCM_HANDLE_GDB_EXCEPTION (except);
-    }
-  END_CATCH
-
-  return vlscm_scm_from_value (res_val);
+      return vlscm_scm_from_value (access_value_history (i));
+    });
 }
 
 /* (history-append! <gdb:value>) -> index
@@ -1433,24 +1256,12 @@  gdbscm_history_ref (SCM index)
 static SCM
 gdbscm_history_append_x (SCM value)
 {
-  int res_index = -1;
-  struct value *v;
-  value_smob *v_smob;
-
-  v_smob = vlscm_get_value_smob_arg_unsafe (value, SCM_ARG1, FUNC_NAME);
-  v = v_smob->value;
-
-  TRY
-    {
-      res_index = record_latest_value (v);
-    }
-  CATCH (except, RETURN_MASK_ALL)
+  value_smob *v_smob
+    = vlscm_get_value_smob_arg_unsafe (value, SCM_ARG1, FUNC_NAME);
+  return gdbscm_wrap ([=]
     {
-      GDBSCM_HANDLE_GDB_EXCEPTION (except);
-    }
-  END_CATCH
-
-  return scm_from_int (res_index);
+      return scm_from_int (record_latest_value (v_smob->value));
+    });
 }
 
 /* Initialize the Scheme value code.  */