[RFC] gdbscm_wrap, eliminate GDBSCM_HANDLE_GDB_EXCEPTION_WITH_CLEANUPS (Re: [RFA 2/4] Change gdbscm_exception_message_to_string to return a unique_xmalloc_ptr)

Message ID 191b7d63-3e83-6bc2-39d6-98a84f3aae27@redhat.com
State New
Headers show
Series
  • [RFC] gdbscm_wrap, eliminate GDBSCM_HANDLE_GDB_EXCEPTION_WITH_CLEANUPS (Re: [RFA 2/4] Change gdbscm_exception_message_to_string to return a unique_xmalloc_ptr)
Related show

Commit Message

Pedro Alves July 18, 2018, 1:28 p.m.
On 07/17/2018 08:10 PM, Tom Tromey wrote:
>>>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes:

> 

>>> gdbscm_print_exception_message (port, SCM_BOOL_F, key, args);

>>> -  result = gdbscm_scm_to_c_string (scm_get_output_string (port));

>>> +  gdb::unique_xmalloc_ptr<char> result

>>> +    (gdbscm_scm_to_c_string (scm_get_output_string (port)));

>>> scm_close_port (port);

>>> -

>>> return result;

>>> }

> 

> Pedro> Did you try making gdbscm_scm_to_c_string return a unique_ptr too?

> 

> Yes, but this runs into the use of

> GDBSCM_HANDLE_GDB_EXCEPTION_WITH_CLEANUPS in (at least) gdbscm_value_field.

> I haven't looked into what to do about this.


I gave this a try today.  How about this?

The main issue 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 Guile 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 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.

I converted a few functions that were using 
GDBSCM_HANDLE_GDB_EXCEPTION to use gdbscm_wrap too because
they followed a similar pattern.

You'll notice that 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.  There's
one case like that that I did not fix here, both a cleanup
and a std::string in  gdbscm_execute_gdb_command.

There are only a handful of cleanups in gdb/guile/ after this:

 $ grep make_cleanup *
 guile.c:  cleanups = make_cleanup (xfree, command);
 scm-pretty-print.c:  cleanups = make_cleanup (null_cleanup, NULL);
 scm-pretty-print.c:      struct cleanup *inner_cleanup = make_cleanup (null_cleanup, NULL);
 scm-pretty-print.c:      make_cleanup (xfree, name);
 scm-pretty-print.c:  cleanups = make_cleanup (null_cleanup, NULL);
 scm-value.c:      struct cleanup *cleanups = make_cleanup (xfree, field);

WDYT?  Passes gdb.guile/*.exp here.

From 61aa83947adda43af7edf560b231884311841a84 Mon Sep 17 00:00:00 2001
From: Pedro Alves <palves@redhat.com>

Date: Wed, 18 Jul 2018 14:08:08 +0100
Subject: [PATCH] gdbscm_wrap, eliminate
 GDBSCM_HANDLE_GDB_EXCEPTION_WITH_CLEANUPS

This eliminates most remaining cleanups under gdb/guile/.
---
 gdb/guile/guile-internal.h |  41 +++--
 gdb/guile/scm-frame.c      |   4 +-
 gdb/guile/scm-math.c       | 374 +++++++++++++++++--------------------
 gdb/guile/scm-symbol.c     |  17 +-
 gdb/guile/scm-type.c       |  16 +-
 gdb/guile/scm-value.c      | 445 +++++++++++++--------------------------------
 6 files changed, 340 insertions(+), 557 deletions(-)

-- 
2.14.4

Comments

Tom Tromey July 18, 2018, 7:33 p.m. | #1
>>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes:


Pedro> I gave this a try today.  How about this?

Pedro> +/* Use this to wrap a callable to throw the appropriate Scheme
Pedro> +   exception if the callable throws a GDB error.  ARGS are forwarded
Pedro> +   to FUNC.  Returns the result of FUNC, unless FUNC returns a Scheme
Pedro> +   exception, in which case that exception is thrown.  Note that while
Pedro> +   the callable is free is use objects of types with destructors,

Typo - "free to use objects".

Pedro> +++ b/gdb/guile/scm-frame.c
Pedro> @@ -783,13 +783,11 @@ gdbscm_frame_read_register (SCM self, SCM register_scm)
Pedro>    char *register_str;
Pedro>    struct value *value = NULL;
Pedro>    struct frame_info *frame = NULL;
Pedro> -  struct cleanup *cleanup;
Pedro>    frame_smob *f_smob;
 
Pedro>    f_smob = frscm_get_frame_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);
Pedro>    gdbscm_parse_function_args (FUNC_NAME, SCM_ARG2, NULL, "s",
Pedro>  			      register_scm, &register_str);
Pedro> -  cleanup = make_cleanup (xfree, register_str);
 
Pedro>    TRY
Pedro>      {
Pedro> @@ -811,7 +809,7 @@ gdbscm_frame_read_register (SCM self, SCM register_scm)
Pedro>      }
Pedro>    END_CATCH
 
Pedro> -  do_cleanups (cleanup);
Pedro> +  xfree (register_str);

I think this will leak register_str if anything throws.  Maybe the xfree
should be duplicated in the catch block, or maybe the whole try/catch
should be replaced with a call to gdbscm_wrap (where the callback would
take ownership of register_str).

This seems like a latent bug here as well - I think the code should be using
GDBSCM_HANDLE_GDB_EXCEPTION_WITH_CLEANUPS here.


Otherwise this all looks good to me.  Thanks for doing this, guile was
one of the larger cleanup holdouts

Tom
Pedro Alves July 18, 2018, 10:31 p.m. | #2
On 07/18/2018 08:33 PM, Tom Tromey wrote:
>>>>>> "Pedro" == Pedro Alves <palves@redhat.com> writes:

> 

> Pedro> I gave this a try today.  How about this?

> 

> Pedro> +/* Use this to wrap a callable to throw the appropriate Scheme

> Pedro> +   exception if the callable throws a GDB error.  ARGS are forwarded

> Pedro> +   to FUNC.  Returns the result of FUNC, unless FUNC returns a Scheme

> Pedro> +   exception, in which case that exception is thrown.  Note that while

> Pedro> +   the callable is free is use objects of types with destructors,

> 

> Typo - "free to use objects".


Thanks, fixed.

> 

> Pedro> +++ b/gdb/guile/scm-frame.c

> Pedro> @@ -783,13 +783,11 @@ gdbscm_frame_read_register (SCM self, SCM register_scm)

> Pedro>    char *register_str;

> Pedro>    struct value *value = NULL;

> Pedro>    struct frame_info *frame = NULL;

> Pedro> -  struct cleanup *cleanup;

> Pedro>    frame_smob *f_smob;

>  

> Pedro>    f_smob = frscm_get_frame_smob_arg_unsafe (self, SCM_ARG1, FUNC_NAME);

> Pedro>    gdbscm_parse_function_args (FUNC_NAME, SCM_ARG2, NULL, "s",

> Pedro>  			      register_scm, &register_str);

> Pedro> -  cleanup = make_cleanup (xfree, register_str);

>  

> Pedro>    TRY

> Pedro>      {

> Pedro> @@ -811,7 +809,7 @@ gdbscm_frame_read_register (SCM self, SCM register_scm)

> Pedro>      }

> Pedro>    END_CATCH

>  

> Pedro> -  do_cleanups (cleanup);

> Pedro> +  xfree (register_str);

> 

> I think this will leak register_str if anything throws.  Maybe the xfree

> should be duplicated in the catch block, or maybe the whole try/catch

> should be replaced with a call to gdbscm_wrap (where the callback would

> take ownership of register_str).

> 

> This seems like a latent bug here as well - I think the code should be using

> GDBSCM_HANDLE_GDB_EXCEPTION_WITH_CLEANUPS here.

> 


Indeed.  I fixed this using the same pattern used elsewhere, of saving
the exception object in the CATCH block:

--- c/gdb/guile/scm-frame.c
+++ w/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)
     {

> Otherwise this all looks good to me.  Thanks for doing this, guile was

> one of the larger cleanup holdouts


Great.  I wrote a ChangeLog entry and pushed it in:
 https://sourceware.org/ml/gdb-patches/2018-07/msg00567.html

The only other change is that I copied the first paragraph of
the commit log to guile/guile-internal.h.

Thanks,
Pedro Alves

Patch

diff --git a/gdb/guile/guile-internal.h b/gdb/guile/guile-internal.h
index 0ef114ac501..0983c06452c 100644
--- a/gdb/guile/guile-internal.h
+++ b/gdb/guile/guile-internal.h
@@ -651,16 +651,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 is 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..5894a07c5b8 100644
--- a/gdb/guile/scm-frame.c
+++ b/gdb/guile/scm-frame.c
@@ -783,13 +783,11 @@  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);
 
   TRY
     {
@@ -811,7 +809,7 @@  gdbscm_frame_read_register (SCM self, SCM register_scm)
     }
   END_CATCH
 
-  do_cleanups (cleanup);
+  xfree (register_str);
 
   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..c2938643756 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.  */