libunwind-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Libunwind-devel] [PATCH 1/8] Have the ARM extbtl-parser operate on the


From: Ken Werner
Subject: [Libunwind-devel] [PATCH 1/8] Have the ARM extbtl-parser operate on the DWARF model directly.
Date: Wed, 23 Mar 2011 15:54:59 +0000

This eliminates the arm_stackframe and therefore the need to synchronize the
two models. It also clears the way for unwinding call stacks with mixed
DWARF- and extbl-frames.

Signed-off-by: Ken Werner <address@hidden>
---
 include/tdep-arm/ex_tables.h   |   35 +------
 include/tdep-arm/libunwind_i.h |    1 -
 src/arm/Ginit_local.c          |   14 +---
 src/arm/Gstep.c                |   41 +++++---
 src/arm/ex_tables.c            |  228 ++++++++++++++++++---------------------
 5 files changed, 138 insertions(+), 181 deletions(-)

diff --git a/include/tdep-arm/ex_tables.h b/include/tdep-arm/ex_tables.h
index 3805c60..7369b35 100644
--- a/include/tdep-arm/ex_tables.h
+++ b/include/tdep-arm/ex_tables.h
@@ -64,16 +64,12 @@ enum arm_exbuf_cmd_flags {
 #define ARM_EXBUF_COUNT(x)     ((x) & 0x0f)
 #define ARM_EXBUF_END(x)       (ARM_EXBUF_START(x) + ARM_EXBUF_COUNT(x))
 
-struct arm_exbuf_callback_data {
-  uint8_t ops[11];
-  uint8_t n_ops;
+struct arm_exbuf_data
+{
   arm_exbuf_cmd_t cmd;
   uint32_t data;
-  void *cb_data;
 };
 
-typedef int (*arm_exbuf_callback_t)(struct arm_exbuf_callback_data *aecb);
-
 static inline void *
 prel31_to_addr (void *addr)
 {
@@ -99,30 +95,7 @@ int arm_exidx_entry_extract (struct elf_image *ei,
 int arm_exidx_extract (struct arm_exidx_entry *entry, uint8_t *buf);
 
 int arm_exidx_decode (const uint8_t *buf, uint8_t len,
-               arm_exbuf_callback_t cb, void *cb_data);
-
-struct arm_stackframe {
-  void *fp;
-  void *sp;
-  void *lr;
-  void *pc;
-};
-
-struct arm_exidx_vrs {
-  uint32_t vrs[16];
-};
-
-enum arm_exidx_vrs_regs {
-  FP_thumb = 7,
-  FP_arm = 11,
-  SP = 13,
-  LR = 14,
-  PC = 15,
-};
-
-void arm_exidx_frame_to_vrs(struct arm_stackframe *f, struct arm_exidx_vrs *s);
-int arm_exidx_vrs_to_frame(struct arm_exidx_vrs *s, struct arm_stackframe *f);
-
-int arm_exidx_vrs_callback (struct arm_exbuf_callback_data *aecd);
+                     struct dwarf_cursor *c);
+int arm_exidx_apply_cmd (struct arm_exbuf_data *edata, struct dwarf_cursor *c);
 
 #endif // ARM_EX_TABLES_H
diff --git a/include/tdep-arm/libunwind_i.h b/include/tdep-arm/libunwind_i.h
index 839415c..acaf6d7 100644
--- a/include/tdep-arm/libunwind_i.h
+++ b/include/tdep-arm/libunwind_i.h
@@ -55,7 +55,6 @@ struct unw_addr_space
 struct cursor
   {
     struct dwarf_cursor dwarf;         /* must be first */
-    struct arm_stackframe frame;
     unw_word_t sigcontext_addr;
   };
 
diff --git a/src/arm/Ginit_local.c b/src/arm/Ginit_local.c
index 2a0d73a..cdf05d2 100644
--- a/src/arm/Ginit_local.c
+++ b/src/arm/Ginit_local.c
@@ -39,7 +39,6 @@ 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)
@@ -51,18 +50,7 @@ unw_init_local (unw_cursor_t *cursor, ucontext_t *uc)
   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;
-    }
+    arm_exidx_init_local ("libunwind");
 
   return common_init (c, 1);
 }
diff --git a/src/arm/Gstep.c b/src/arm/Gstep.c
index ab556d7..1b4b135 100644
--- a/src/arm/Gstep.c
+++ b/src/arm/Gstep.c
@@ -30,27 +30,42 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
SOFTWARE.  */
 static inline int
 arm_exidx_step (struct cursor *c)
 {
-  struct arm_exidx_table *table = arm_exidx_table_find (c->frame.pc);
+  unw_word_t old_ip, old_cfa;
+  struct arm_exidx_table *table;
+  struct arm_exidx_entry *entry;
+  uint8_t buf[32];
+  int ret;
+
+  old_ip = c->dwarf.ip;
+  old_cfa = c->dwarf.cfa;
+
+  /* mark PC unsaved */
+  c->dwarf.loc[UNW_ARM_R15] = DWARF_NULL_LOC;
+
+  table = arm_exidx_table_find ((void *)c->dwarf.ip);
   if (NULL == table)
     return -UNW_ENOINFO;
 
-  struct arm_exidx_entry *entry = arm_exidx_table_lookup (table, c->frame.pc);
+  entry = arm_exidx_table_lookup (table, (void *)c->dwarf.ip);
   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);
+  ret = arm_exidx_extract (entry, buf);
   if (ret < 0)
     return ret;
 
-  ret = arm_exidx_decode (buf, ret, &arm_exidx_vrs_callback, &s);
+  ret = arm_exidx_decode (buf, ret, &c->dwarf);
   if (ret < 0)
-    return -ret;
+    return ret;
 
-  return arm_exidx_vrs_to_frame (&s, &c->frame);
+  if (c->dwarf.ip == old_ip && c->dwarf.cfa == old_cfa)
+    {
+      Dprintf ("%s: ip and cfa unchanged; stopping here (ip=0x%lx)\n",
+              __FUNCTION__, (long) c->dwarf.ip);
+      return -UNW_EBADFRAME;
+    }
+
+  return (c->dwarf.ip == 0) ? 0 : 1;
 }
 
 PROTECTED int
@@ -65,9 +80,9 @@ unw_step (unw_cursor_t *cursor)
     {
       ret = arm_exidx_step (c);
       if (ret >= 0)
-        return ret;
-      if (ret < 0 && ret != -UNW_ENOINFO)
-       return ret;
+       return 1;
+      if (ret == -UNW_ESTOPUNWIND)
+       return 0;
     }
 
   /* Next, try DWARF-based unwinding. */
diff --git a/src/arm/ex_tables.c b/src/arm/ex_tables.c
index 3b5e8ef..6fe2947 100644
--- a/src/arm/ex_tables.c
+++ b/src/arm/ex_tables.c
@@ -120,164 +120,146 @@ arm_exidx_table_lookup (struct arm_exidx_table *table, 
void *pc)
   return first;
 }
 
-static inline int
-arm_exidx_frame_reg(void *pc)
-{
-  return ((unsigned)pc & 1) ? FP_thumb : FP_arm;
-}
-
-HIDDEN void
-arm_exidx_frame_to_vrs(struct arm_stackframe *f, struct arm_exidx_vrs *s)
-{
-  int fp_reg = arm_exidx_frame_reg(f->pc);
-  s->vrs[fp_reg] = (uint32_t)f->fp;
-  s->vrs[SP] = (uint32_t)f->sp;
-  s->vrs[LR] = (uint32_t)f->lr;
-  s->vrs[PC] = 0;
-}
-
+/**
+ * Applies the given command onto the new state to the given dwarf_cursor.
+ */
 HIDDEN int
-arm_exidx_vrs_to_frame(struct arm_exidx_vrs *s, struct arm_stackframe *f)
+arm_exidx_apply_cmd (struct arm_exbuf_data *edata, struct dwarf_cursor *c)
 {
-  if (s->vrs[PC] == 0)
-    s->vrs[PC] = s->vrs[LR];
-
-  if (f->pc == (void *)s->vrs[PC])
-    return -1;
-
-  int fp_reg = arm_exidx_frame_reg(f->pc);
-  f->fp = (void *)s->vrs[fp_reg];
-  f->sp = (void *)s->vrs[SP];
-  f->lr = (void *)s->vrs[LR];
-  f->pc = (void *)s->vrs[PC];
-
-  return 0;
-}
+  int ret = 0;
+  unsigned i;
 
-HIDDEN int
-arm_exidx_vrs_callback (struct arm_exbuf_callback_data *aecd)
-{
-  struct arm_exidx_vrs *s = aecd->cb_data;
-  int ret = 0, i;
-  switch (aecd->cmd)
+  switch (edata->cmd)
     {
-      case ARM_EXIDX_CMD_FINISH:
-       break;
-      case ARM_EXIDX_CMD_DATA_PUSH:
-       Debug (2, "vsp = vsp - %d\n", aecd->data);
-       s->vrs[SP] -= aecd->data;
-       break;
-      case ARM_EXIDX_CMD_DATA_POP:
-       Debug (2, "vsp = vsp + %d\n", aecd->data);
-       s->vrs[SP] += aecd->data;
-       break;
-      case ARM_EXIDX_CMD_REG_POP:
-       for (i = 0; i < 16; i++)
-         if (aecd->data & (1 << i))
-           {
-             s->vrs[i] = *(uint32_t*)s->vrs[SP];
-             s->vrs[SP] += 4;
-             Debug (2, "pop {r%d}\n", i);
-           }
-       break;
-      case ARM_EXIDX_CMD_REG_TO_SP:
-       assert (aecd->data < 16);
-       Debug (2, "vsp = r%d\n", aecd->data);
-       s->vrs[SP] = s->vrs[aecd->data];
-       break;
-      case ARM_EXIDX_CMD_VFP_POP:
-       /* Skip VFP registers, but be sure to adjust stack */
-       for (i = ARM_EXBUF_START (aecd->data); i < ARM_EXBUF_END (aecd->data); 
i++)
-         s->vrs[SP] += 8;
-       if (!(aecd->data & ARM_EXIDX_VFP_DOUBLE))
-         s->vrs[SP] += 4;
-       break;
-      case ARM_EXIDX_CMD_WREG_POP:
-       for (i = ARM_EXBUF_START (aecd->data); i < ARM_EXBUF_END (aecd->data); 
i++)
-         s->vrs[SP] += 8;
-       break;
-      case ARM_EXIDX_CMD_WCGR_POP:
-       for (i = 0; i < 4; i++)
-         if (aecd->data & (1 << i))
-           s->vrs[SP] += 4;
-       break;
-      case ARM_EXIDX_CMD_REFUSED:
-      case ARM_EXIDX_CMD_RESERVED:
-       ret = -1;
-       break;
+    case ARM_EXIDX_CMD_FINISH:
+      /* Set LR to PC if not set already.  */
+      if (DWARF_IS_NULL_LOC (c->loc[UNW_ARM_R15]))
+       c->loc[UNW_ARM_R15] = c->loc[UNW_ARM_R14];
+      /* Set IP.  */
+      dwarf_get (c, c->loc[UNW_ARM_R15], &c->ip);
+      break;
+    case ARM_EXIDX_CMD_DATA_PUSH:
+      Debug (2, "vsp = vsp - %d\n", edata->data);
+      c->cfa -= edata->data;
+      break;
+    case ARM_EXIDX_CMD_DATA_POP:
+      Debug (2, "vsp = vsp + %d\n", edata->data);
+      c->cfa += edata->data;
+      break;
+    case ARM_EXIDX_CMD_REG_POP:
+      for (i = 0; i < 16; i++)
+       if (edata->data & (1 << i))
+         {
+           Debug (2, "pop {r%d}\n", i);
+           c->loc[UNW_ARM_R0 + i] = DWARF_LOC (c->cfa, 0);
+           c->cfa += 4;
+         }
+      /* Set cfa in case the SP got popped. */
+      if (edata->data & (1 << 13))
+       dwarf_get (c, c->loc[UNW_ARM_R13], &c->cfa);
+      break;
+    case ARM_EXIDX_CMD_REG_TO_SP:
+      assert (edata->data < 16);
+      Debug (2, "vsp = r%d\n", edata->data);
+      c->loc[UNW_ARM_R13] = c->loc[UNW_ARM_R0 + edata->data];
+      dwarf_get (c, c->loc[UNW_ARM_R13], &c->cfa);
+      break;
+    case ARM_EXIDX_CMD_VFP_POP:
+      /* Skip VFP registers, but be sure to adjust stack */
+      for (i = ARM_EXBUF_START (edata->data); i < ARM_EXBUF_END (edata->data);
+          i++)
+       c->cfa += 8;
+      if (!(edata->data & ARM_EXIDX_VFP_DOUBLE))
+       c->cfa += 4;
+      break;
+    case ARM_EXIDX_CMD_WREG_POP:
+      for (i = ARM_EXBUF_START (edata->data); i < ARM_EXBUF_END (edata->data);
+          i++)
+       c->cfa += 8;
+      break;
+    case ARM_EXIDX_CMD_WCGR_POP:
+      for (i = 0; i < 4; i++)
+       if (edata->data & (1 << i))
+         c->cfa += 4;
+      break;
+    case ARM_EXIDX_CMD_REFUSED:
+    case ARM_EXIDX_CMD_RESERVED:
+      ret = -1;
+      break;
     }
   return ret;
 }
 
+
 HIDDEN int
-arm_exidx_decode (const uint8_t *buf, uint8_t len,
-               arm_exbuf_callback_t cb, void *cb_data)
+arm_exidx_decode (const uint8_t *buf, uint8_t len, struct dwarf_cursor *c)
 {
-#define READ_OP() aecb.ops[aecb.n_ops++] = *buf++
+#define READ_OP() *buf++
   const uint8_t *end = buf + len;
   int ret;
+  struct arm_exbuf_data edata;
 
   assert(buf != NULL);
-  assert(cb != NULL);
+  assert(len > 0);
+
   while (buf < end)
     {
-      struct arm_exbuf_callback_data aecb = { .cb_data = cb_data };
       uint8_t op = READ_OP ();
       if ((op & 0xc0) == 0x00)
        {
-         aecb.cmd = ARM_EXIDX_CMD_DATA_POP;
-         aecb.data = (((int)op & 0x3f) << 2) + 4;
+         edata.cmd = ARM_EXIDX_CMD_DATA_POP;
+         edata.data = (((int)op & 0x3f) << 2) + 4;
        }
       else if ((op & 0xc0) == 0x40)
        {
-         aecb.cmd = ARM_EXIDX_CMD_DATA_PUSH;
-         aecb.data = (((int)op & 0x3f) << 2) + 4;
+         edata.cmd = ARM_EXIDX_CMD_DATA_PUSH;
+         edata.data = (((int)op & 0x3f) << 2) + 4;
        }
       else if ((op & 0xf0) == 0x80)
        {
          uint8_t op2 = READ_OP ();
          if (op == 0x80 && op2 == 0x00)
-           aecb.cmd = ARM_EXIDX_CMD_REFUSED;
+           edata.cmd = ARM_EXIDX_CMD_REFUSED;
          else
            {
-             aecb.cmd = ARM_EXIDX_CMD_REG_POP;
-             aecb.data = ((op & 0xf) << 8) | op2;
-             aecb.data = aecb.data << 4;
+             edata.cmd = ARM_EXIDX_CMD_REG_POP;
+             edata.data = ((op & 0xf) << 8) | op2;
+             edata.data = edata.data << 4;
            }
        }
       else if ((op & 0xf0) == 0x90)
        {
          if (op == 0x9d || op == 0x9f)
-           aecb.cmd = ARM_EXIDX_CMD_RESERVED;
+           edata.cmd = ARM_EXIDX_CMD_RESERVED;
          else
            {
-             aecb.cmd = ARM_EXIDX_CMD_REG_TO_SP;
-             aecb.data = op & 0x0f;
+             edata.cmd = ARM_EXIDX_CMD_REG_TO_SP;
+             edata.data = op & 0x0f;
            }
        }
       else if ((op & 0xf0) == 0xa0)
        {
          unsigned end = (op & 0x07);
-         aecb.data = (1 << (end + 1)) - 1;
-         aecb.data = aecb.data << 4;
+         edata.data = (1 << (end + 1)) - 1;
+         edata.data = edata.data << 4;
          if (op & 0x08)
-           aecb.data |= 1 << 14;
-         aecb.cmd = ARM_EXIDX_CMD_REG_POP;
+           edata.data |= 1 << 14;
+         edata.cmd = ARM_EXIDX_CMD_REG_POP;
        }
       else if (op == ARM_EXTBL_OP_FINISH)
        {
-         aecb.cmd = ARM_EXIDX_CMD_FINISH;
+         edata.cmd = ARM_EXIDX_CMD_FINISH;
          buf = end;
        }
       else if (op == 0xb1)
        {
          uint8_t op2 = READ_OP ();
          if (op2 == 0 || (op2 & 0xf0))
-           aecb.cmd = ARM_EXIDX_CMD_RESERVED;
+           edata.cmd = ARM_EXIDX_CMD_RESERVED;
          else
            {
-             aecb.cmd = ARM_EXIDX_CMD_REG_POP;
-             aecb.data = op2 & 0x0f;
+             edata.cmd = ARM_EXIDX_CMD_REG_POP;
+             edata.data = op2 & 0x0f;
            }
        }
       else if (op == 0xb2)
@@ -291,50 +273,50 @@ arm_exidx_decode (const uint8_t *buf, uint8_t len,
              shift += 7;
            }
          while (byte & 0x80);
-         aecb.data = offset * 4 + 0x204;
-         aecb.cmd = ARM_EXIDX_CMD_DATA_POP;
+         edata.data = offset * 4 + 0x204;
+         edata.cmd = ARM_EXIDX_CMD_DATA_POP;
        }
       else if (op == 0xb3 || op == 0xc8 || op == 0xc9)
        {
-         aecb.cmd = ARM_EXIDX_CMD_VFP_POP;
-         aecb.data = READ_OP ();
+         edata.cmd = ARM_EXIDX_CMD_VFP_POP;
+         edata.data = READ_OP ();
          if (op == 0xc8)
-           aecb.data |= ARM_EXIDX_VFP_SHIFT_16;
+           edata.data |= ARM_EXIDX_VFP_SHIFT_16;
          if (op != 0xb3)
-           aecb.data |= ARM_EXIDX_VFP_DOUBLE;
+           edata.data |= ARM_EXIDX_VFP_DOUBLE;
        }
       else if ((op & 0xf8) == 0xb8 || (op & 0xf8) == 0xd0)
        {
-         aecb.cmd = ARM_EXIDX_CMD_VFP_POP;
-         aecb.data = 0x80 | (op & 0x07);
+         edata.cmd = ARM_EXIDX_CMD_VFP_POP;
+         edata.data = 0x80 | (op & 0x07);
          if ((op & 0xf8) == 0xd0)
-           aecb.data |= ARM_EXIDX_VFP_DOUBLE;
+           edata.data |= ARM_EXIDX_VFP_DOUBLE;
        }
       else if (op >= 0xc0 && op <= 0xc5)
        {
-         aecb.cmd = ARM_EXIDX_CMD_WREG_POP;
-         aecb.data = 0xa0 | (op & 0x07);
+         edata.cmd = ARM_EXIDX_CMD_WREG_POP;
+         edata.data = 0xa0 | (op & 0x07);
        }
       else if (op == 0xc6)
        {
-         aecb.cmd = ARM_EXIDX_CMD_WREG_POP;
-         aecb.data = READ_OP ();
+         edata.cmd = ARM_EXIDX_CMD_WREG_POP;
+         edata.data = READ_OP ();
        }
       else if (op == 0xc7)
        {
          uint8_t op2 = READ_OP ();
          if (op2 == 0 || (op2 & 0xf0))
-           aecb.cmd = ARM_EXIDX_CMD_RESERVED;
+           edata.cmd = ARM_EXIDX_CMD_RESERVED;
          else
            {
-             aecb.cmd = ARM_EXIDX_CMD_WCGR_POP;
-             aecb.data = op2 & 0x0f;
+             edata.cmd = ARM_EXIDX_CMD_WCGR_POP;
+             edata.data = op2 & 0x0f;
            }
        }
       else
-       aecb.cmd = ARM_EXIDX_CMD_RESERVED;
+       edata.cmd = ARM_EXIDX_CMD_RESERVED;
 
-      ret = (*cb) (&aecb);
+      ret = arm_exidx_apply_cmd (&edata, c);
       if (ret < 0)
        return ret;
     }
-- 
1.7.4.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]