diff --git a/gdb/dwarf2-frame.c b/gdb/dwarf2-frame.c
index f8e6522..89e574b 100644
--- a/gdb/dwarf2-frame.c
+++ b/gdb/dwarf2-frame.c
@@ -919,6 +919,8 @@ dwarf2_fetch_cfa_info (struct gdbarch *gdbarch, CORE_ADDR pc,
 
 struct dwarf2_frame_cache
 {
+  explicit dwarf2_frame_cache (frame_info *frame);
+
   /* DWARF Call Frame Address.  */
   CORE_ADDR cfa;
 
@@ -960,24 +962,17 @@ struct dwarf2_frame_cache
   int entry_cfa_sp_offset_p;
 };
 
-static struct dwarf2_frame_cache *
-dwarf2_frame_cache (struct frame_info *this_frame, void **this_cache)
+dwarf2_frame_cache::dwarf2_frame_cache (struct frame_info *this_frame)
 {
+  struct dwarf2_frame_cache *cache = this;
   struct gdbarch *gdbarch = get_frame_arch (this_frame);
   const int num_regs = gdbarch_num_regs (gdbarch)
 		       + gdbarch_num_pseudo_regs (gdbarch);
-  struct dwarf2_frame_cache *cache;
   struct dwarf2_fde *fde;
   CORE_ADDR entry_pc;
   const gdb_byte *instr;
 
-  if (*this_cache)
-    return (struct dwarf2_frame_cache *) *this_cache;
-
-  /* Allocate a new cache.  */
-  cache = FRAME_OBSTACK_ZALLOC (struct dwarf2_frame_cache);
   cache->reg = FRAME_OBSTACK_CALLOC (num_regs, struct dwarf2_frame_state_reg);
-  *this_cache = cache;
 
   /* Unwind the PC.
 
@@ -1066,7 +1061,7 @@ dwarf2_frame_cache (struct frame_info *this_frame, void **this_cache)
       if (ex.error == NOT_AVAILABLE_ERROR)
 	{
 	  cache->unavailable_retaddr = 1;
-	  return cache;
+	  return;
 	}
 
       throw_exception (ex);
@@ -1170,16 +1165,13 @@ incomplete CFI data; unspecified registers (e.g., %s) at %s"),
   if (fs.retaddr_column < fs.regs.num_regs
       && fs.regs.reg[fs.retaddr_column].how == DWARF2_FRAME_REG_UNDEFINED)
     cache->undefined_retaddr = 1;
-
-  return cache;
 }
 
 static enum unwind_stop_reason
 dwarf2_frame_unwind_stop_reason (struct frame_info *this_frame,
 				 void **this_cache)
 {
-  struct dwarf2_frame_cache *cache
-    = dwarf2_frame_cache (this_frame, this_cache);
+  auto *cache = get_frame_cache<dwarf2_frame_cache> (this_frame, this_cache);
 
   if (cache->unavailable_retaddr)
     return UNWIND_UNAVAILABLE;
@@ -1194,8 +1186,7 @@ static void
 dwarf2_frame_this_id (struct frame_info *this_frame, void **this_cache,
 		      struct frame_id *this_id)
 {
-  struct dwarf2_frame_cache *cache =
-    dwarf2_frame_cache (this_frame, this_cache);
+  auto *cache = get_frame_cache<dwarf2_frame_cache> (this_frame, this_cache);
 
   if (cache->unavailable_retaddr)
     (*this_id) = frame_id_build_unavailable_stack (get_frame_func (this_frame));
@@ -1210,8 +1201,7 @@ dwarf2_frame_prev_register (struct frame_info *this_frame, void **this_cache,
 			    int regnum)
 {
   struct gdbarch *gdbarch = get_frame_arch (this_frame);
-  struct dwarf2_frame_cache *cache =
-    dwarf2_frame_cache (this_frame, this_cache);
+  auto *cache = get_frame_cache<dwarf2_frame_cache> (this_frame, this_cache);
   CORE_ADDR addr;
   int realnum;
 
@@ -1316,7 +1306,7 @@ dwarf2_frame_prev_register (struct frame_info *this_frame, void **this_cache,
 static void
 dwarf2_frame_dealloc_cache (struct frame_info *self, void *this_cache)
 {
-  struct dwarf2_frame_cache *cache = dwarf2_frame_cache (self, &this_cache);
+  auto *cache = get_frame_cache<dwarf2_frame_cache> (self, &this_cache);
 
   if (cache->tailcall_cache)
     dwarf2_tailcall_frame_unwind.dealloc_cache (self, cache->tailcall_cache);
@@ -1401,8 +1391,7 @@ dwarf2_append_unwinders (struct gdbarch *gdbarch)
 static CORE_ADDR
 dwarf2_frame_base_address (struct frame_info *this_frame, void **this_cache)
 {
-  struct dwarf2_frame_cache *cache =
-    dwarf2_frame_cache (this_frame, this_cache);
+  auto *cache = get_frame_cache<dwarf2_frame_cache> (this_frame, this_cache);
 
   return cache->cfa;
 }
diff --git a/gdb/frame-unwind.h b/gdb/frame-unwind.h
index 8226b6d..b2c65d0 100644
--- a/gdb/frame-unwind.h
+++ b/gdb/frame-unwind.h
@@ -29,6 +29,7 @@ struct regcache;
 struct value;
 
 #include "frame.h"		/* For enum frame_type.  */
+#include "gdb_obstack.h"
 
 /* The following unwind functions assume a chain of frames forming the
    sequence: (outer) prev <-> this <-> next (inner).  All the
@@ -220,4 +221,30 @@ struct value *frame_unwind_got_bytes (struct frame_info *frame, int regnum,
 struct value *frame_unwind_got_address (struct frame_info *frame, int regnum,
 					CORE_ADDR addr);
 
+template<typename Cache>
+Cache *
+get_frame_cache (struct frame_info *this_frame, void **this_cache)
+{
+  if (*this_cache)
+    return (Cache *) *this_cache;
+
+  /* Allocate a new cache.  */
+  Cache *cache = FRAME_OBSTACK_ZALLOC (Cache);
+
+  /* If an exception happens here, free everything on the obstack up
+     to CACHE.  */
+  scoped_obstack_freer obstack_freer (&frame_cache_obstack, cache);
+
+  /* Install CACHE in *THIS_CACHE, and set up to clear it if something
+     goes wrong.  */
+  scoped_restore restore_this_cache = make_scoped_restore (this_cache);
+  *this_cache = cache;
+
+  cache = new (cache) Cache (this_frame);
+
+  obstack_freer.dont_free ();
+  restore_this_cache.release ();
+  return cache;
+}
+
 #endif
diff --git a/gdb/frame.c b/gdb/frame.c
index 30e4aea..f4f7a5d 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -1552,7 +1552,7 @@ create_sentinel_frame (struct program_space *pspace, struct regcache *regcache)
    inferior is stopped.  Control variables for the frame cache should
    be local to this module.  */
 
-static struct obstack frame_cache_obstack;
+struct obstack frame_cache_obstack;
 
 void *
 frame_obstack_zalloc (unsigned long size)
diff --git a/gdb/frame.h b/gdb/frame.h
index 56cbd44..1694241 100644
--- a/gdb/frame.h
+++ b/gdb/frame.h
@@ -679,6 +679,8 @@ extern void *frame_obstack_zalloc (unsigned long size);
 #define FRAME_OBSTACK_CALLOC(NUMBER,TYPE) \
   ((TYPE *) frame_obstack_zalloc ((NUMBER) * sizeof (TYPE)))
 
+extern struct obstack frame_cache_obstack;
+
 /* Create a regcache, and copy the frame's registers into it.  */
 struct regcache *frame_save_as_regcache (struct frame_info *this_frame);
 
diff --git a/gdb/gdb_obstack.h b/gdb/gdb_obstack.h
index b241c82..b481396 100644
--- a/gdb/gdb_obstack.h
+++ b/gdb/gdb_obstack.h
@@ -78,4 +78,34 @@ struct auto_obstack : obstack
   { obstack_free (this, obstack_base (this)); }
 };
 
+/* RAII object that automatically frees all objects allocated in an
+   obstack starting at a specified object.  Since the obstack is a
+   stack of objects, freeing one object automatically frees all other
+   objects allocated more recently in the same obstack.  */
+class scoped_obstack_freer
+{
+public:
+  scoped_obstack_freer (struct obstack *obstack, void *from_obj)
+    ATTRIBUTE_NONNULL (2) ATTRIBUTE_NONNULL (3)
+    : m_obstack (obstack),
+      m_from_obj (from_obj)
+  {
+    gdb_assert (m_obstack != NULL);
+    gdb_assert (m_from_obj != NULL);
+  }
+
+  ~scoped_obstack_freer ()
+  {
+    if (m_from_obj != NULL)
+      obstack_free (m_obstack, m_from_obj);
+  }
+
+  /* Don't free objects.  */
+  void dont_free () { m_from_obj = NULL; }
+
+private:
+  struct obstack *m_obstack;
+  void *m_from_obj;
+};
+
 #endif
