1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
|
From bc7b50355cb37cfa56f6131b2f9174b499053188 Mon Sep 17 00:00:00 2001
From: Yichao Yu <yyc1992@gmail.com>
Date: Sat, 1 Oct 2016 16:55:40 +0000
Subject: [PATCH] Prefer EXTBL unwinding on ARM
It is part of the C++ ABI so a EXTBL unwind info that's not `CANT_UNWIND`
should always be reliable/correct.
Ignore `ESTOPUNWIND` so that a `CANT_UNWIND` info can fallback to unwinding
using the debug info instead.
---
include/tdep-arm/libunwind_i.h | 4 ++++
src/arm/Gex_tables.c | 18 ++++++++++++++----
src/arm/Gstep.c | 35 +++++++++++++++++++++--------------
3 files changed, 39 insertions(+), 18 deletions(-)
diff --git a/include/tdep-arm/libunwind_i.h b/include/tdep-arm/libunwind_i.h
index 2602f41c..074fc8cb 100644
--- a/include/tdep-arm/libunwind_i.h
+++ b/include/tdep-arm/libunwind_i.h
@@ -253,6 +253,7 @@ dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val)
#define tdep_init_done UNW_OBJ(init_done)
#define tdep_init UNW_OBJ(init)
#define arm_find_proc_info UNW_OBJ(find_proc_info)
+#define arm_find_proc_info2 UNW_OBJ(find_proc_info2)
#define arm_put_unwind_info UNW_OBJ(put_unwind_info)
/* Platforms that support UNW_INFO_FORMAT_TABLE need to define
tdep_search_unwind_table. */
@@ -294,6 +295,9 @@ extern void tdep_init (void);
extern int arm_find_proc_info (unw_addr_space_t as, unw_word_t ip,
unw_proc_info_t *pi, int need_unwind_info,
void *arg);
+extern int arm_find_proc_info2 (unw_addr_space_t as, unw_word_t ip,
+ unw_proc_info_t *pi, int need_unwind_info,
+ void *arg, int methods);
extern void arm_put_unwind_info (unw_addr_space_t as,
unw_proc_info_t *pi, void *arg);
extern int tdep_search_unwind_table (unw_addr_space_t as, unw_word_t ip,
diff --git a/src/arm/Gex_tables.c b/src/arm/Gex_tables.c
index d6573a65..a895e0cc 100644
--- a/src/arm/Gex_tables.c
+++ b/src/arm/Gex_tables.c
@@ -506,18 +506,20 @@ arm_phdr_cb (struct dl_phdr_info *info, size_t size, void *data)
}
HIDDEN int
-arm_find_proc_info (unw_addr_space_t as, unw_word_t ip,
- unw_proc_info_t *pi, int need_unwind_info, void *arg)
+arm_find_proc_info2 (unw_addr_space_t as, unw_word_t ip,
+ unw_proc_info_t *pi, int need_unwind_info, void *arg,
+ int methods)
{
int ret = -1;
intrmask_t saved_mask;
Debug (14, "looking for IP=0x%lx\n", (long) ip);
- if (UNW_TRY_METHOD(UNW_ARM_METHOD_DWARF))
+ if (UNW_TRY_METHOD (UNW_ARM_METHOD_DWARF) && (methods & UNW_ARM_METHOD_DWARF))
ret = dwarf_find_proc_info (as, ip, pi, need_unwind_info, arg);
- if (ret < 0 && UNW_TRY_METHOD (UNW_ARM_METHOD_EXIDX))
+ if (ret < 0 && UNW_TRY_METHOD (UNW_ARM_METHOD_EXIDX) &&
+ (methods & UNW_ARM_METHOD_EXIDX))
{
struct arm_cb_data cb_data;
@@ -540,6 +542,14 @@ arm_find_proc_info (unw_addr_space_t as, unw_word_t ip,
return ret;
}
+HIDDEN int
+arm_find_proc_info (unw_addr_space_t as, unw_word_t ip,
+ unw_proc_info_t *pi, int need_unwind_info, void *arg)
+{
+ return arm_find_proc_info2 (as, ip, pi, need_unwind_info, arg,
+ UNW_ARM_METHOD_ALL);
+}
+
HIDDEN void
arm_put_unwind_info (unw_addr_space_t as, unw_proc_info_t *proc_info, void *arg)
{
diff --git a/src/arm/Gstep.c b/src/arm/Gstep.c
index adec02e0..c43daa1c 100644
--- a/src/arm/Gstep.c
+++ b/src/arm/Gstep.c
@@ -53,8 +53,15 @@ arm_exidx_step (struct cursor *c)
c->dwarf.as_arg);
if (ret == -UNW_ENOINFO)
{
+#ifdef UNW_LOCAL_ONLY
+ if ((ret = arm_find_proc_info2 (c->dwarf.as, ip, &c->dwarf.pi,
+ 1, c->dwarf.as_arg,
+ UNW_ARM_METHOD_EXIDX)) < 0)
+ return ret;
+#else
if ((ret = tdep_find_proc_info (&c->dwarf, ip, 1)) < 0)
return ret;
+#endif
}
if (c->dwarf.pi.format != UNW_INFO_FORMAT_ARM_EXIDX)
@@ -94,8 +101,21 @@ unw_step (unw_cursor_t *cursor)
if (unw_is_signal_frame (cursor) > 0)
return arm_handle_signal_frame (cursor);
+ /* First, try extbl-based unwinding. */
+ if (UNW_TRY_METHOD (UNW_ARM_METHOD_EXIDX))
+ {
+ Debug (13, "%s(ret=%d), trying extbl\n",
+ UNW_TRY_METHOD(UNW_ARM_METHOD_DWARF) ? "dwarf_step() failed " : "",
+ ret);
+ ret = arm_exidx_step (c);
+ if (ret > 0)
+ return 1;
+ if (ret == 0)
+ return ret;
+ }
+
#ifdef CONFIG_DEBUG_FRAME
- /* First, try DWARF-based unwinding. */
+ /* Second, try DWARF-based unwinding. */
if (UNW_TRY_METHOD(UNW_ARM_METHOD_DWARF))
{
ret = dwarf_step (&c->dwarf);
@@ -114,16 +129,6 @@ unw_step (unw_cursor_t *cursor)
}
#endif /* CONFIG_DEBUG_FRAME */
- /* Next, try extbl-based unwinding. */
- if (UNW_TRY_METHOD (UNW_ARM_METHOD_EXIDX))
- {
- ret = arm_exidx_step (c);
- if (ret > 0)
- return 1;
- if (ret == -UNW_ESTOPUNWIND || ret == 0)
- return ret;
- }
-
/* Fall back on APCS frame parsing.
Note: This won't work in case the ARM EABI is used. */
#ifdef __FreeBSD__
--
2.16.1
|