diff mbox

[3/4] Use ARM-specific unwinding tables in unw_step

Message ID 1300212944-24984-4-git-send-email-ken.werner@linaro.org
State Accepted
Commit 6a671546741e8355dd9f821f171e4a3c895d28ec
Headers show

Commit Message

Ken Werner March 15, 2011, 6:15 p.m. UTC
From: Zachary T Welch <zwelch@codesourcery.com>

Uses ex_tables routines to provide a new means of unwinding the stack.
Set UNW_ARM_UNWIND_METHOD=4 to use ARM-specific unwinding tables.

Signed-off-by: Ken Werner <ken.werner@linaro.org>
---
 include/tdep-arm/libunwind_i.h |    1 +
 src/arm/Ginit_local.c          |   17 +++++++++++++++++
 src/arm/Gstep.c                |   40 ++++++++++++++++++++++++++++++++++++++--
 3 files changed, 56 insertions(+), 2 deletions(-)
diff mbox

Patch

diff --git a/include/tdep-arm/libunwind_i.h b/include/tdep-arm/libunwind_i.h
index a565d9b..839415c 100644
--- a/include/tdep-arm/libunwind_i.h
+++ b/include/tdep-arm/libunwind_i.h
@@ -261,6 +261,7 @@  extern int tdep_access_fpreg (struct cursor *c, unw_regnum_t reg,
 #define UNW_ARM_METHOD_ALL          0xFF
 #define UNW_ARM_METHOD_DWARF        0x01
 #define UNW_ARM_METHOD_FRAME        0x02
+#define UNW_ARM_METHOD_EXIDX        0x04
 
 #define unwi_unwind_method   UNW_OBJ(unwind_method)
 extern int unwi_unwind_method;
diff --git a/src/arm/Ginit_local.c b/src/arm/Ginit_local.c
index debf5bb..2a0d73a 100644
--- a/src/arm/Ginit_local.c
+++ b/src/arm/Ginit_local.c
@@ -1,5 +1,6 @@ 
 /* libunwind - a platform-independent unwind library
    Copyright (C) 2008 CodeSourcery
+   Copyright 2011 Linaro Limited
 
 This file is part of libunwind.
 
@@ -38,6 +39,7 @@  unw_init_local (unw_cursor_t *cursor, ucontext_t *uc)
 PROTECTED int
 unw_init_local (unw_cursor_t *cursor, ucontext_t *uc)
 {
+  register void *current_sp asm ("sp");
   struct cursor *c = (struct cursor *) cursor;
 
   if (tdep_needs_initialization)
@@ -47,6 +49,21 @@  unw_init_local (unw_cursor_t *cursor, ucontext_t *uc)
 
   c->dwarf.as = unw_local_addr_space;
   c->dwarf.as_arg = uc;
+
+  if (UNW_TRY_METHOD (UNW_ARM_METHOD_EXIDX))
+    {
+      int arm_exidx_init_done = 0;
+      if (!arm_exidx_init_done)
+	{
+	  arm_exidx_init_done = 1;
+	  arm_exidx_init_local ("libunwind");
+	}
+      c->frame.fp = __builtin_frame_address (0);
+      c->frame.sp = current_sp;
+      c->frame.lr = __builtin_return_address (0);
+      c->frame.pc = &unw_init_local;
+    }
+
   return common_init (c, 1);
 }
 
diff --git a/src/arm/Gstep.c b/src/arm/Gstep.c
index 5eac5f0..ab556d7 100644
--- a/src/arm/Gstep.c
+++ b/src/arm/Gstep.c
@@ -1,5 +1,6 @@ 
 /* libunwind - a platform-independent unwind library
    Copyright (C) 2008 CodeSourcery
+   Copyright 2011 Linaro Limited
 
 This file is part of libunwind.
 
@@ -24,6 +25,33 @@  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
 
 #include "unwind_i.h"
 #include "offsets.h"
+#include "ex_tables.h"
+
+static inline int
+arm_exidx_step (struct cursor *c)
+{
+  struct arm_exidx_table *table = arm_exidx_table_find (c->frame.pc);
+  if (NULL == table)
+    return -UNW_ENOINFO;
+
+  struct arm_exidx_entry *entry = arm_exidx_table_lookup (table, c->frame.pc);
+  if (NULL == entry)
+    return -UNW_ENOINFO;
+
+  struct arm_exidx_vrs s;
+  arm_exidx_frame_to_vrs (&c->frame, &s);
+
+  uint8_t buf[32];
+  int ret = arm_exidx_extract (entry, buf);
+  if (ret < 0)
+    return ret;
+
+  ret = arm_exidx_decode (buf, ret, &arm_exidx_vrs_callback, &s);
+  if (ret < 0)
+    return -ret;
+
+  return arm_exidx_vrs_to_frame (&s, &c->frame);
+}
 
 PROTECTED int
 unw_step (unw_cursor_t *cursor)
@@ -33,8 +61,16 @@  unw_step (unw_cursor_t *cursor)
 
   Debug (1, "(cursor=%p)\n", c);
 
-  /* Try DWARF-based unwinding...  this is the only method likely to work for
-     ARM.  */
+  if (UNW_TRY_METHOD (UNW_ARM_METHOD_EXIDX))
+    {
+      ret = arm_exidx_step (c);
+      if (ret >= 0)
+        return ret;
+      if (ret < 0 && ret != -UNW_ENOINFO)
+	return ret;
+    }
+
+  /* Next, try DWARF-based unwinding. */
   if (UNW_TRY_METHOD(UNW_ARM_METHOD_DWARF))
     {
       ret = dwarf_step (&c->dwarf);