[PATCH 5/9] Handle unwinding exceptions

Yao Qi qiyaoltc@gmail.com
Mon Jul 31 22:22:00 GMT 2017


unwinder methods (sniffer, this_id, stop_reason, etc) can throw
exceptions, at least when some data is unavailable during examining
traceframes.  We deal with this problem by catching exceptions in each
unwinders, dwarf unwinders and different arch-specific prologue unwinders.
done by https://www.sourceware.org/ml/gdb-patches/2011-02/msg00611.html
This requires each arch-specific prologue unwinder needs to catch
exceptions.

This patch centralizes the exception handling in the callers of unwinders
methods, and the following patches remove the exception handling in each
arch prologue unwinders.  This patch is a follow-up to discussion
https://sourceware.org/ml/gdb-patches/2016-02/msg00778.html

This patch not only catches exceptions from unwinder methods, but also
catches exceptions from frame_base methods, because they call
arch-specific prologue analyzer, which can throw exceptions.

gdb:

2017-07-27  Yao Qi  <yao.qi@linaro.org>

	* frame.c (compute_frame_id): Catch exception, if it is
	NOT_AVAILABLE_ERROR, call frame_id_build_unavailable_stack,
	otherwise throw the exception again.
	(frame_unwind_register_value): Catch exception from
	unwind->prev_register, if it is NOT_AVAILABLE_ERROR, set value
	unavailable, otherwise throw the exception again.
	(get_prev_frame_always_1): Catch exception from
	unwind->stop_reason, if it is NOT_AVAILABLE_ERROR, set stop_reason
	to UNWIND_UNAVAILABLE, otherwise throw the exception.
	(get_frame_locals_address): Catch exception base->this_locals.
	(get_frame_args_address): Likewise.
---
 gdb/frame.c | 109 +++++++++++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 93 insertions(+), 16 deletions(-)

diff --git a/gdb/frame.c b/gdb/frame.c
index 30e4aea..f5037d5 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -502,7 +502,32 @@ compute_frame_id (struct frame_info *fi)
   /* Find THIS frame's ID.  */
   /* Default to outermost if no ID is found.  */
   fi->this_id.value = outer_frame_id;
-  fi->unwind->this_id (fi, &fi->prologue_cache, &fi->this_id.value);
+
+  TRY
+    {
+      fi->unwind->this_id (fi, &fi->prologue_cache, &fi->this_id.value);
+    }
+  CATCH (ex, RETURN_MASK_ERROR)
+    {
+      if (ex.error == NOT_AVAILABLE_ERROR)
+	{
+	  CORE_ADDR pc;
+
+	  /* Use function start address as part of the frame ID.  If we
+	     can't find the start address (due to missing symbol
+	     information), faill back to just using the current PC.  If
+	     PC isn't available, we can't construct any meaningful frame
+	     ID, so do nothing here, and the frame id is
+	     outer_frame_id.  */
+	  if ((get_frame_func_if_available (fi, &pc) && pc != 0)
+	      || get_frame_pc_if_available (fi, &pc))
+	    fi->this_id.value = frame_id_build_unavailable_stack (pc);
+	}
+      else
+	throw_exception (ex);
+    }
+  END_CATCH
+
   gdb_assert (frame_id_p (fi->this_id.value));
   fi->this_id.p = 1;
   if (frame_debug)
@@ -1196,8 +1221,25 @@ frame_unwind_register_value (struct frame_info *frame, int regnum)
   if (frame->unwind == NULL)
     frame_unwind_find_by_frame (frame, &frame->prologue_cache);
 
-  /* Ask this frame to unwind its register.  */
-  value = frame->unwind->prev_register (frame, &frame->prologue_cache, regnum);
+  TRY
+    {
+      /* Ask this frame to unwind its register.  */
+      value = frame->unwind->prev_register (frame, &frame->prologue_cache,
+					    regnum);
+    }
+  CATCH (ex, RETURN_MASK_ERROR)
+    {
+      if (ex.error == NOT_AVAILABLE_ERROR)
+	{
+	  value = frame_unwind_got_register (frame, regnum, regnum);
+	  set_value_lazy (value, 0);
+	  mark_value_bytes_unavailable (value, 0,
+					TYPE_LENGTH (value_type (value)));
+	}
+      else
+	throw_exception (ex);
+    }
+  END_CATCH
 
   if (frame_debug)
     {
@@ -2009,9 +2051,20 @@ get_prev_frame_always_1 (struct frame_info *this_frame)
 
   /* Check that this frame is unwindable.  If it isn't, don't try to
      unwind to the prev frame.  */
-  this_frame->stop_reason
-    = this_frame->unwind->stop_reason (this_frame,
-				       &this_frame->prologue_cache);
+  TRY
+    {
+      this_frame->stop_reason
+	= this_frame->unwind->stop_reason (this_frame,
+					   &this_frame->prologue_cache);
+    }
+  CATCH (ex, RETURN_MASK_ERROR)
+    {
+      if (ex.error == NOT_AVAILABLE_ERROR)
+	this_frame->stop_reason = UNWIND_UNAVAILABLE;
+      else
+	throw_exception (ex);
+    }
+  END_CATCH
 
   if (this_frame->stop_reason != UNWIND_NO_REASON)
     {
@@ -2596,11 +2649,23 @@ get_frame_locals_address (struct frame_info *fi)
   /* If there isn't a frame address method, find it.  */
   if (fi->base == NULL)
     fi->base = frame_base_find_by_frame (fi);
-  /* Sneaky: If the low-level unwind and high-level base code share a
-     common unwinder, let them share the prologue cache.  */
-  if (fi->base->unwind == fi->unwind)
-    return fi->base->this_locals (fi, &fi->prologue_cache);
-  return fi->base->this_locals (fi, &fi->base_cache);
+
+  TRY
+    {
+      /* Sneaky: If the low-level unwind and high-level base code share a
+	 common unwinder, let them share the prologue cache.  */
+      if (fi->base->unwind == fi->unwind)
+	return fi->base->this_locals (fi, &fi->prologue_cache);
+      return fi->base->this_locals (fi, &fi->base_cache);
+    }
+  CATCH (ex, RETURN_MASK_ERROR)
+    {
+      if (ex.error != NOT_AVAILABLE_ERROR)
+	throw_exception (ex);
+    }
+  END_CATCH
+
+  return 0;
 }
 
 CORE_ADDR
@@ -2611,11 +2676,23 @@ get_frame_args_address (struct frame_info *fi)
   /* If there isn't a frame address method, find it.  */
   if (fi->base == NULL)
     fi->base = frame_base_find_by_frame (fi);
-  /* Sneaky: If the low-level unwind and high-level base code share a
-     common unwinder, let them share the prologue cache.  */
-  if (fi->base->unwind == fi->unwind)
-    return fi->base->this_args (fi, &fi->prologue_cache);
-  return fi->base->this_args (fi, &fi->base_cache);
+
+  TRY
+    {
+      /* Sneaky: If the low-level unwind and high-level base code share a
+	 common unwinder, let them share the prologue cache.  */
+      if (fi->base->unwind == fi->unwind)
+	return fi->base->this_args (fi, &fi->prologue_cache);
+      return fi->base->this_args (fi, &fi->base_cache);
+    }
+  CATCH (ex, RETURN_MASK_ERROR)
+    {
+      if (ex.error != NOT_AVAILABLE_ERROR)
+	throw_exception (ex);
+    }
+  END_CATCH
+
+  return 0;
 }
 
 /* Return true if the frame unwinder for frame FI is UNWINDER; false
-- 
1.9.1



More information about the Gdb-patches mailing list