This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[PATCH 5/9] Handle unwinding exceptions
- From: Yao Qi <qiyaoltc at gmail dot com>
- To: gdb-patches at sourceware dot org
- Date: Mon, 31 Jul 2017 23:21:51 +0100
- Subject: [PATCH 5/9] Handle unwinding exceptions
- Authentication-results: sourceware.org; auth=none
- References: <1501539715-8049-1-git-send-email-yao.qi@linaro.org>
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