Imported Upstream version 1.3.1
[platform/upstream/libunwind.git] / src / dwarf / Gexpr.c
index b4f2bc9..f63c3d2 100644 (file)
@@ -1,6 +1,6 @@
 /* libunwind - a platform-independent unwind library
    Copyright (c) 2003, 2005 Hewlett-Packard Development Company, L.P.
-       Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
+        Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
 
 This file is part of libunwind.
 
@@ -30,81 +30,81 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
    that the stack could at least have a depth of up to 256 elements,
    but the GCC unwinder restricts the depth to 64, which seems
    reasonable so we use the same value here.  */
-#define MAX_EXPR_STACK_SIZE    64
+#define MAX_EXPR_STACK_SIZE     64
 
-#define NUM_OPERANDS(signature)        (((signature) >> 6) & 0x3)
-#define OPND1_TYPE(signature)  (((signature) >> 3) & 0x7)
-#define OPND2_TYPE(signature)  (((signature) >> 0) & 0x7)
+#define NUM_OPERANDS(signature) (((signature) >> 6) & 0x3)
+#define OPND1_TYPE(signature)   (((signature) >> 3) & 0x7)
+#define OPND2_TYPE(signature)   (((signature) >> 0) & 0x7)
 
 #define OPND_SIGNATURE(n, t1, t2) (((n) << 6) | ((t1) << 3) | ((t2) << 0))
-#define OPND1(t1)              OPND_SIGNATURE(1, t1, 0)
-#define OPND2(t1, t2)          OPND_SIGNATURE(2, t1, t2)
-
-#define VAL8   0x0
-#define VAL16  0x1
-#define VAL32  0x2
-#define VAL64  0x3
-#define ULEB128        0x4
-#define SLEB128        0x5
-#define OFFSET 0x6     /* 32-bit offset for 32-bit DWARF, 64-bit otherwise */
-#define ADDR   0x7     /* Machine address.  */
+#define OPND1(t1)               OPND_SIGNATURE(1, t1, 0)
+#define OPND2(t1, t2)           OPND_SIGNATURE(2, t1, t2)
+
+#define VAL8    0x0
+#define VAL16   0x1
+#define VAL32   0x2
+#define VAL64   0x3
+#define ULEB128 0x4
+#define SLEB128 0x5
+#define OFFSET  0x6     /* 32-bit offset for 32-bit DWARF, 64-bit otherwise */
+#define ADDR    0x7     /* Machine address.  */
 
 static const uint8_t operands[256] =
   {
-    [DW_OP_addr] =             OPND1 (ADDR),
-    [DW_OP_const1u] =          OPND1 (VAL8),
-    [DW_OP_const1s] =          OPND1 (VAL8),
-    [DW_OP_const2u] =          OPND1 (VAL16),
-    [DW_OP_const2s] =          OPND1 (VAL16),
-    [DW_OP_const4u] =          OPND1 (VAL32),
-    [DW_OP_const4s] =          OPND1 (VAL32),
-    [DW_OP_const8u] =          OPND1 (VAL64),
-    [DW_OP_const8s] =          OPND1 (VAL64),
-    [DW_OP_pick] =             OPND1 (VAL8),
-    [DW_OP_plus_uconst] =      OPND1 (ULEB128),
-    [DW_OP_skip] =             OPND1 (VAL16),
-    [DW_OP_bra] =              OPND1 (VAL16),
-    [DW_OP_breg0 +  0] =       OPND1 (SLEB128),
-    [DW_OP_breg0 +  1] =       OPND1 (SLEB128),
-    [DW_OP_breg0 +  2] =       OPND1 (SLEB128),
-    [DW_OP_breg0 +  3] =       OPND1 (SLEB128),
-    [DW_OP_breg0 +  4] =       OPND1 (SLEB128),
-    [DW_OP_breg0 +  5] =       OPND1 (SLEB128),
-    [DW_OP_breg0 +  6] =       OPND1 (SLEB128),
-    [DW_OP_breg0 +  7] =       OPND1 (SLEB128),
-    [DW_OP_breg0 +  8] =       OPND1 (SLEB128),
-    [DW_OP_breg0 +  9] =       OPND1 (SLEB128),
-    [DW_OP_breg0 + 10] =       OPND1 (SLEB128),
-    [DW_OP_breg0 + 11] =       OPND1 (SLEB128),
-    [DW_OP_breg0 + 12] =       OPND1 (SLEB128),
-    [DW_OP_breg0 + 13] =       OPND1 (SLEB128),
-    [DW_OP_breg0 + 14] =       OPND1 (SLEB128),
-    [DW_OP_breg0 + 15] =       OPND1 (SLEB128),
-    [DW_OP_breg0 + 16] =       OPND1 (SLEB128),
-    [DW_OP_breg0 + 17] =       OPND1 (SLEB128),
-    [DW_OP_breg0 + 18] =       OPND1 (SLEB128),
-    [DW_OP_breg0 + 19] =       OPND1 (SLEB128),
-    [DW_OP_breg0 + 20] =       OPND1 (SLEB128),
-    [DW_OP_breg0 + 21] =       OPND1 (SLEB128),
-    [DW_OP_breg0 + 22] =       OPND1 (SLEB128),
-    [DW_OP_breg0 + 23] =       OPND1 (SLEB128),
-    [DW_OP_breg0 + 24] =       OPND1 (SLEB128),
-    [DW_OP_breg0 + 25] =       OPND1 (SLEB128),
-    [DW_OP_breg0 + 26] =       OPND1 (SLEB128),
-    [DW_OP_breg0 + 27] =       OPND1 (SLEB128),
-    [DW_OP_breg0 + 28] =       OPND1 (SLEB128),
-    [DW_OP_breg0 + 29] =       OPND1 (SLEB128),
-    [DW_OP_breg0 + 30] =       OPND1 (SLEB128),
-    [DW_OP_breg0 + 31] =       OPND1 (SLEB128),
-    [DW_OP_regx] =             OPND1 (ULEB128),
-    [DW_OP_fbreg] =            OPND1 (SLEB128),
-    [DW_OP_bregx] =            OPND2 (ULEB128, SLEB128),
-    [DW_OP_piece] =            OPND1 (ULEB128),
-    [DW_OP_deref_size] =       OPND1 (VAL8),
-    [DW_OP_xderef_size] =      OPND1 (VAL8),
-    [DW_OP_call2] =            OPND1 (VAL16),
-    [DW_OP_call4] =            OPND1 (VAL32),
-    [DW_OP_call_ref] =         OPND1 (OFFSET)
+    [DW_OP_addr] =              OPND1 (ADDR),
+    [DW_OP_const1u] =           OPND1 (VAL8),
+    [DW_OP_const1s] =           OPND1 (VAL8),
+    [DW_OP_const2u] =           OPND1 (VAL16),
+    [DW_OP_const2s] =           OPND1 (VAL16),
+    [DW_OP_const4u] =           OPND1 (VAL32),
+    [DW_OP_const4s] =           OPND1 (VAL32),
+    [DW_OP_const8u] =           OPND1 (VAL64),
+    [DW_OP_const8s] =           OPND1 (VAL64),
+    [DW_OP_pick] =              OPND1 (VAL8),
+    [DW_OP_plus_uconst] =       OPND1 (ULEB128),
+    [DW_OP_skip] =              OPND1 (VAL16),
+    [DW_OP_bra] =               OPND1 (VAL16),
+    [DW_OP_breg0 +  0] =        OPND1 (SLEB128),
+    [DW_OP_breg0 +  1] =        OPND1 (SLEB128),
+    [DW_OP_breg0 +  2] =        OPND1 (SLEB128),
+    [DW_OP_breg0 +  3] =        OPND1 (SLEB128),
+    [DW_OP_breg0 +  4] =        OPND1 (SLEB128),
+    [DW_OP_breg0 +  5] =        OPND1 (SLEB128),
+    [DW_OP_breg0 +  6] =        OPND1 (SLEB128),
+    [DW_OP_breg0 +  7] =        OPND1 (SLEB128),
+    [DW_OP_breg0 +  8] =        OPND1 (SLEB128),
+    [DW_OP_breg0 +  9] =        OPND1 (SLEB128),
+    [DW_OP_breg0 + 10] =        OPND1 (SLEB128),
+    [DW_OP_breg0 + 11] =        OPND1 (SLEB128),
+    [DW_OP_breg0 + 12] =        OPND1 (SLEB128),
+    [DW_OP_breg0 + 13] =        OPND1 (SLEB128),
+    [DW_OP_breg0 + 14] =        OPND1 (SLEB128),
+    [DW_OP_breg0 + 15] =        OPND1 (SLEB128),
+    [DW_OP_breg0 + 16] =        OPND1 (SLEB128),
+    [DW_OP_breg0 + 17] =        OPND1 (SLEB128),
+    [DW_OP_breg0 + 18] =        OPND1 (SLEB128),
+    [DW_OP_breg0 + 19] =        OPND1 (SLEB128),
+    [DW_OP_breg0 + 20] =        OPND1 (SLEB128),
+    [DW_OP_breg0 + 21] =        OPND1 (SLEB128),
+    [DW_OP_breg0 + 22] =        OPND1 (SLEB128),
+    [DW_OP_breg0 + 23] =        OPND1 (SLEB128),
+    [DW_OP_breg0 + 24] =        OPND1 (SLEB128),
+    [DW_OP_breg0 + 25] =        OPND1 (SLEB128),
+    [DW_OP_breg0 + 26] =        OPND1 (SLEB128),
+    [DW_OP_breg0 + 27] =        OPND1 (SLEB128),
+    [DW_OP_breg0 + 28] =        OPND1 (SLEB128),
+    [DW_OP_breg0 + 29] =        OPND1 (SLEB128),
+    [DW_OP_breg0 + 30] =        OPND1 (SLEB128),
+    [DW_OP_breg0 + 31] =        OPND1 (SLEB128),
+    [DW_OP_regx] =              OPND1 (ULEB128),
+    [DW_OP_fbreg] =             OPND1 (SLEB128),
+    [DW_OP_bregx] =             OPND2 (ULEB128, SLEB128),
+    [DW_OP_piece] =             OPND1 (ULEB128),
+    [DW_OP_deref_size] =        OPND1 (VAL8),
+    [DW_OP_xderef_size] =       OPND1 (VAL8),
+    [DW_OP_call2] =             OPND1 (VAL16),
+    [DW_OP_call4] =             OPND1 (VAL32),
+    [DW_OP_call_ref] =          OPND1 (OFFSET)
   };
 
 static inline unw_sword_t
@@ -122,7 +122,7 @@ sword (unw_addr_space_t as, unw_word_t val)
 
 static inline unw_word_t
 read_operand (unw_addr_space_t as, unw_accessors_t *a,
-             unw_word_t *addr, int operand_type, unw_word_t *val, void *arg)
+              unw_word_t *addr, int operand_type, unw_word_t *val, void *arg)
 {
   uint8_t u8;
   uint16_t u16;
@@ -145,28 +145,28 @@ read_operand (unw_addr_space_t as, unw_accessors_t *a,
     case VAL8:
       ret = dwarf_readu8 (as, a, addr, &u8, arg);
       if (ret < 0)
-       return ret;
+        return ret;
       *val = u8;
       break;
 
     case VAL16:
       ret = dwarf_readu16 (as, a, addr, &u16, arg);
       if (ret < 0)
-       return ret;
+        return ret;
       *val = u16;
       break;
 
     case VAL32:
       ret = dwarf_readu32 (as, a, addr, &u32, arg);
       if (ret < 0)
-       return ret;
+        return ret;
       *val = u32;
       break;
 
     case VAL64:
       ret = dwarf_readu64 (as, a, addr, &u64, arg);
       if (ret < 0)
-       return ret;
+        return ret;
       *val = u64;
       break;
 
@@ -187,10 +187,58 @@ read_operand (unw_addr_space_t as, unw_accessors_t *a,
 }
 
 HIDDEN int
+dwarf_stack_aligned(struct dwarf_cursor *c, unw_word_t cfa_addr,
+                    unw_word_t rbp_addr, unw_word_t *cfa_offset) {
+  unw_accessors_t *a;
+  int ret;
+  void *arg;
+  unw_word_t len;
+  uint8_t opcode;
+  unw_word_t operand1;
+
+  a = unw_get_accessors_int (c->as);
+  arg = c->as_arg;
+
+  ret = dwarf_read_uleb128(c->as, a, &rbp_addr, &len, arg);
+  if (len != 2 || ret < 0)
+    return 0;
+
+  ret = dwarf_readu8(c->as, a, &rbp_addr, &opcode, arg);
+  if (ret < 0 || opcode != DW_OP_breg6)
+    return 0;
+
+  ret = read_operand(c->as, a, &rbp_addr,
+                     OPND1_TYPE(operands[opcode]), &operand1, arg);
+
+  if (ret < 0 || operand1 != 0)
+    return 0;
+
+  ret = dwarf_read_uleb128(c->as, a, &cfa_addr, &len, arg);
+  if (ret < 0 || len != 3)
+    return 0;
+
+  ret = dwarf_readu8(c->as, a, &cfa_addr, &opcode, arg);
+  if (ret < 0 || opcode != DW_OP_breg6)
+    return 0;
+
+  ret = read_operand(c->as, a, &cfa_addr,
+                     OPND1_TYPE(operands[opcode]), &operand1, arg);
+  if (ret < 0)
+    return 0;
+
+  ret = dwarf_readu8(c->as, a, &cfa_addr, &opcode, arg);
+  if (ret < 0 || opcode != DW_OP_deref)
+    return 0;
+
+  *cfa_offset = operand1;
+  return 1;
+}
+
+HIDDEN int
 dwarf_eval_expr (struct dwarf_cursor *c, unw_word_t *addr, unw_word_t len,
-                unw_word_t *valp, int *is_register)
+                 unw_word_t *valp, int *is_register)
 {
-  unw_word_t operand1 = 0, operand2 = 0, tmp1, tmp2, tmp3, end_addr;
+  unw_word_t operand1 = 0, operand2 = 0, tmp1, tmp2 = 0, tmp3, end_addr;
   uint8_t opcode, operands_signature, u8;
   unw_addr_space_t as;
   unw_accessors_t *a;
@@ -201,445 +249,446 @@ dwarf_eval_expr (struct dwarf_cursor *c, unw_word_t *addr, unw_word_t len,
   uint32_t u32;
   uint64_t u64;
   int ret;
-# define pop()                                 \
-({                                             \
-  if ((tos - 1) >= MAX_EXPR_STACK_SIZE)                \
-    {                                          \
-      Debug (1, "Stack underflow\n");          \
-      return -UNW_EINVAL;                      \
-    }                                          \
-  stack[--tos];                                        \
+# define pop()                                  \
+({                                              \
+  if ((tos - 1) >= MAX_EXPR_STACK_SIZE)         \
+    {                                           \
+      Debug (1, "Stack underflow\n");           \
+      return -UNW_EINVAL;                       \
+    }                                           \
+  stack[--tos];                                 \
 })
-# define push(x)                               \
-do {                                           \
-  if (tos >= MAX_EXPR_STACK_SIZE)              \
-    {                                          \
-      Debug (1, "Stack overflow\n");           \
-      return -UNW_EINVAL;                      \
-    }                                          \
-  stack[tos++] = (x);                          \
+# define push(x)                                \
+do {                                            \
+  unw_word_t _x = (x);                          \
+  if (tos >= MAX_EXPR_STACK_SIZE)               \
+    {                                           \
+      Debug (1, "Stack overflow\n");            \
+      return -UNW_EINVAL;                       \
+    }                                           \
+  stack[tos++] = _x;                            \
 } while (0)
-# define pick(n)                               \
-({                                             \
-  unsigned int _index = tos - 1 - (n);         \
-  if (_index >= MAX_EXPR_STACK_SIZE)           \
-    {                                          \
-      Debug (1, "Out-of-stack pick\n");                \
-      return -UNW_EINVAL;                      \
-    }                                          \
-  stack[_index];                               \
+# define pick(n)                                \
+({                                              \
+  unsigned int _index = tos - 1 - (n);          \
+  if (_index >= MAX_EXPR_STACK_SIZE)            \
+    {                                           \
+      Debug (1, "Out-of-stack pick\n");         \
+      return -UNW_EINVAL;                       \
+    }                                           \
+  stack[_index];                                \
 })
 
   as = c->as;
   arg = c->as_arg;
-  a = unw_get_accessors (as);
+  a = unw_get_accessors_int (as);
   end_addr = *addr + len;
   *is_register = 0;
 
   Debug (14, "len=%lu, pushing cfa=0x%lx\n",
-        (unsigned long) len, (unsigned long) c->cfa);
+         (unsigned long) len, (unsigned long) c->cfa);
 
-  push (c->cfa);       /* push current CFA as required by DWARF spec */
+  push (c->cfa);        /* push current CFA as required by DWARF spec */
 
   while (*addr < end_addr)
     {
       if ((ret = dwarf_readu8 (as, a, addr, &opcode, arg)) < 0)
-       return ret;
+        return ret;
 
       operands_signature = operands[opcode];
 
       if (unlikely (NUM_OPERANDS (operands_signature) > 0))
-       {
-         if ((ret = read_operand (as, a, addr,
-                                  OPND1_TYPE (operands_signature),
-                                  &operand1, arg)) < 0)
-           return ret;
-         if (NUM_OPERANDS (operands_signature) > 1)
-           if ((ret = read_operand (as, a, addr,
-                                    OPND2_TYPE (operands_signature),
-                                    &operand2, arg)) < 0)
-             return ret;
-       }
+        {
+          if ((ret = read_operand (as, a, addr,
+                                   OPND1_TYPE (operands_signature),
+                                   &operand1, arg)) < 0)
+            return ret;
+          if (NUM_OPERANDS (operands_signature) > 1)
+            if ((ret = read_operand (as, a, addr,
+                                     OPND2_TYPE (operands_signature),
+                                     &operand2, arg)) < 0)
+              return ret;
+        }
 
       switch ((dwarf_expr_op_t) opcode)
-       {
-       case DW_OP_lit0:  case DW_OP_lit1:  case DW_OP_lit2:
-       case DW_OP_lit3:  case DW_OP_lit4:  case DW_OP_lit5:
-       case DW_OP_lit6:  case DW_OP_lit7:  case DW_OP_lit8:
-       case DW_OP_lit9:  case DW_OP_lit10: case DW_OP_lit11:
-       case DW_OP_lit12: case DW_OP_lit13: case DW_OP_lit14:
-       case DW_OP_lit15: case DW_OP_lit16: case DW_OP_lit17:
-       case DW_OP_lit18: case DW_OP_lit19: case DW_OP_lit20:
-       case DW_OP_lit21: case DW_OP_lit22: case DW_OP_lit23:
-       case DW_OP_lit24: case DW_OP_lit25: case DW_OP_lit26:
-       case DW_OP_lit27: case DW_OP_lit28: case DW_OP_lit29:
-       case DW_OP_lit30: case DW_OP_lit31:
-         Debug (15, "OP_lit(%d)\n", (int) opcode - DW_OP_lit0);
-         push (opcode - DW_OP_lit0);
-         break;
-
-       case DW_OP_breg0:  case DW_OP_breg1:  case DW_OP_breg2:
-       case DW_OP_breg3:  case DW_OP_breg4:  case DW_OP_breg5:
-       case DW_OP_breg6:  case DW_OP_breg7:  case DW_OP_breg8:
-       case DW_OP_breg9:  case DW_OP_breg10: case DW_OP_breg11:
-       case DW_OP_breg12: case DW_OP_breg13: case DW_OP_breg14:
-       case DW_OP_breg15: case DW_OP_breg16: case DW_OP_breg17:
-       case DW_OP_breg18: case DW_OP_breg19: case DW_OP_breg20:
-       case DW_OP_breg21: case DW_OP_breg22: case DW_OP_breg23:
-       case DW_OP_breg24: case DW_OP_breg25: case DW_OP_breg26:
-       case DW_OP_breg27: case DW_OP_breg28: case DW_OP_breg29:
-       case DW_OP_breg30: case DW_OP_breg31:
-         Debug (15, "OP_breg(r%d,0x%lx)\n",
-                (int) opcode - DW_OP_breg0, (unsigned long) operand1);
-         if ((ret = unw_get_reg (dwarf_to_cursor (c),
-                                 dwarf_to_unw_regnum (opcode - DW_OP_breg0),
-                                 &tmp1)) < 0)
-           return ret;
-         push (tmp1 + operand1);
-         break;
-
-       case DW_OP_bregx:
-         Debug (15, "OP_bregx(r%d,0x%lx)\n",
-                (int) operand1, (unsigned long) operand2);
-         if ((ret = unw_get_reg (dwarf_to_cursor (c),
-                                 dwarf_to_unw_regnum (operand1), &tmp1)) < 0)
-           return ret;
-         push (tmp1 + operand2);
-         break;
-
-       case DW_OP_reg0:  case DW_OP_reg1:  case DW_OP_reg2:
-       case DW_OP_reg3:  case DW_OP_reg4:  case DW_OP_reg5:
-       case DW_OP_reg6:  case DW_OP_reg7:  case DW_OP_reg8:
-       case DW_OP_reg9:  case DW_OP_reg10: case DW_OP_reg11:
-       case DW_OP_reg12: case DW_OP_reg13: case DW_OP_reg14:
-       case DW_OP_reg15: case DW_OP_reg16: case DW_OP_reg17:
-       case DW_OP_reg18: case DW_OP_reg19: case DW_OP_reg20:
-       case DW_OP_reg21: case DW_OP_reg22: case DW_OP_reg23:
-       case DW_OP_reg24: case DW_OP_reg25: case DW_OP_reg26:
-       case DW_OP_reg27: case DW_OP_reg28: case DW_OP_reg29:
-       case DW_OP_reg30: case DW_OP_reg31:
-         Debug (15, "OP_reg(r%d)\n", (int) opcode - DW_OP_reg0);
-         *valp = dwarf_to_unw_regnum (opcode - DW_OP_reg0);
-         *is_register = 1;
-         return 0;
-
-       case DW_OP_regx:
-         Debug (15, "OP_regx(r%d)\n", (int) operand1);
-         *valp = dwarf_to_unw_regnum (operand1);
-         *is_register = 1;
-         return 0;
-
-       case DW_OP_addr:
-       case DW_OP_const1u:
-       case DW_OP_const2u:
-       case DW_OP_const4u:
-       case DW_OP_const8u:
-       case DW_OP_constu:
-       case DW_OP_const8s:
-       case DW_OP_consts:
-         Debug (15, "OP_const(0x%lx)\n", (unsigned long) operand1);
-         push (operand1);
-         break;
-
-       case DW_OP_const1s:
-         if (operand1 & 0x80)
-           operand1 |= ((unw_word_t) -1) << 8;
-         Debug (15, "OP_const1s(%ld)\n", (long) operand1);
-         push (operand1);
-         break;
-
-       case DW_OP_const2s:
-         if (operand1 & 0x8000)
-           operand1 |= ((unw_word_t) -1) << 16;
-         Debug (15, "OP_const2s(%ld)\n", (long) operand1);
-         push (operand1);
-         break;
-
-       case DW_OP_const4s:
-         if (operand1 & 0x80000000)
-           operand1 |= (((unw_word_t) -1) << 16) << 16;
-         Debug (15, "OP_const4s(%ld)\n", (long) operand1);
-         push (operand1);
-         break;
-
-       case DW_OP_deref:
-         Debug (15, "OP_deref\n");
-         tmp1 = pop ();
-         if ((ret = dwarf_readw (as, a, &tmp1, &tmp2, arg)) < 0)
-           return ret;
-         push (tmp2);
-         break;
-
-       case DW_OP_deref_size:
-         Debug (15, "OP_deref_size(%d)\n", (int) operand1);
-         tmp1 = pop ();
-         switch (operand1)
-           {
-           default:
-             Debug (1, "Unexpected DW_OP_deref_size size %d\n",
-                    (int) operand1);
-             return -UNW_EINVAL;
-
-           case 1:
-             if ((ret = dwarf_readu8 (as, a, &tmp1, &u8, arg)) < 0)
-               return ret;
-             tmp2 = u8;
-             break;
-
-           case 2:
-             if ((ret = dwarf_readu16 (as, a, &tmp1, &u16, arg)) < 0)
-               return ret;
-             tmp2 = u16;
-             break;
-
-           case 3:
-           case 4:
-             if ((ret = dwarf_readu32 (as, a, &tmp1, &u32, arg)) < 0)
-               return ret;
-             tmp2 = u32;
-             if (operand1 == 3)
-               {
-                 if (dwarf_is_big_endian (as))
-                   tmp2 >>= 8;
-                 else
-                   tmp2 &= 0xffffff;
-               }
-             break;
-           case 5:
-           case 6:
-           case 7:
-           case 8:
-             if ((ret = dwarf_readu64 (as, a, &tmp1, &u64, arg)) < 0)
-               return ret;
-             tmp2 = u64;
-             if (operand1 != 8)
-               {
-                 if (dwarf_is_big_endian (as))
-                   tmp2 >>= 64 - 8 * operand1;
-                 else
-                   tmp2 &= (~ (unw_word_t) 0) << (8 * operand1);
-               }
-             break;
-           }
-         push (tmp2);
-         break;
-
-       case DW_OP_dup:
-         Debug (15, "OP_dup\n");
-         push (pick (0));
-         break;
-
-       case DW_OP_drop:
-         Debug (15, "OP_drop\n");
-         (void) pop ();
-         break;
-
-       case DW_OP_pick:
-         Debug (15, "OP_pick(%d)\n", (int) operand1);
-         push (pick (operand1));
-         break;
-
-       case DW_OP_over:
-         Debug (15, "OP_over\n");
-         push (pick (1));
-         break;
-
-       case DW_OP_swap:
-         Debug (15, "OP_swap\n");
-         tmp1 = pop ();
-         tmp2 = pop ();
-         push (tmp1);
-         push (tmp2);
-         break;
-
-       case DW_OP_rot:
-         Debug (15, "OP_rot\n");
-         tmp1 = pop ();
-         tmp2 = pop ();
-         tmp3 = pop ();
-         push (tmp1);
-         push (tmp3);
-         push (tmp2);
-         break;
-
-       case DW_OP_abs:
-         Debug (15, "OP_abs\n");
-         tmp1 = pop ();
-         if (tmp1 & ((unw_word_t) 1 << (8 * dwarf_addr_size (as) - 1)))
-           tmp1 = -tmp1;
-         push (tmp1);
-         break;
-
-       case DW_OP_and:
-         Debug (15, "OP_and\n");
-         tmp1 = pop ();
-         tmp2 = pop ();
-         push (tmp1 & tmp2);
-         break;
-
-       case DW_OP_div:
-         Debug (15, "OP_div\n");
-         tmp1 = pop ();
-         tmp2 = pop ();
-         if (tmp1)
-           tmp1 = sword (as, tmp2) / sword (as, tmp1);
-         push (tmp1);
-         break;
-
-       case DW_OP_minus:
-         Debug (15, "OP_minus\n");
-         tmp1 = pop ();
-         tmp2 = pop ();
-         tmp1 = tmp2 - tmp1;
-         push (tmp1);
-         break;
-
-       case DW_OP_mod:
-         Debug (15, "OP_mod\n");
-         tmp1 = pop ();
-         tmp2 = pop ();
-         if (tmp1)
-           tmp1 = tmp2 % tmp1;
-         push (tmp1);
-         break;
-
-       case DW_OP_mul:
-         Debug (15, "OP_mul\n");
-         tmp1 = pop ();
-         tmp2 = pop ();
-         if (tmp1)
-           tmp1 = tmp2 * tmp1;
-         push (tmp1);
-         break;
-
-       case DW_OP_neg:
-         Debug (15, "OP_neg\n");
-         push (-pop ());
-         break;
-
-       case DW_OP_not:
-         Debug (15, "OP_not\n");
-         push (~pop ());
-         break;
-
-       case DW_OP_or:
-         Debug (15, "OP_or\n");
-         tmp1 = pop ();
-         tmp2 = pop ();
-         push (tmp1 | tmp2);
-         break;
-
-       case DW_OP_plus:
-         Debug (15, "OP_plus\n");
-         tmp1 = pop ();
-         tmp2 = pop ();
-         push (tmp1 + tmp2);
-         break;
-
-       case DW_OP_plus_uconst:
-         Debug (15, "OP_plus_uconst(%lu)\n", (unsigned long) operand1);
-         tmp1 = pop ();
-         push (tmp1 + operand1);
-         break;
-
-       case DW_OP_shl:
-         Debug (15, "OP_shl\n");
-         tmp1 = pop ();
-         tmp2 = pop ();
-         push (tmp2 << tmp1);
-         break;
-
-       case DW_OP_shr:
-         Debug (15, "OP_shr\n");
-         tmp1 = pop ();
-         tmp2 = pop ();
-         push (tmp2 >> tmp1);
-         break;
-
-       case DW_OP_shra:
-         Debug (15, "OP_shra\n");
-         tmp1 = pop ();
-         tmp2 = pop ();
-         push (sword (as, tmp2) >> tmp1);
-         break;
-
-       case DW_OP_xor:
-         Debug (15, "OP_xor\n");
-         tmp1 = pop ();
-         tmp2 = pop ();
-         push (tmp1 ^ tmp2);
-         break;
-
-       case DW_OP_le:
-         Debug (15, "OP_le\n");
-         tmp1 = pop ();
-         tmp2 = pop ();
-         push (sword (as, tmp1) <= sword (as, tmp2));
-         break;
-
-       case DW_OP_ge:
-         Debug (15, "OP_ge\n");
-         tmp1 = pop ();
-         tmp2 = pop ();
-         push (sword (as, tmp1) >= sword (as, tmp2));
-         break;
-
-       case DW_OP_eq:
-         Debug (15, "OP_eq\n");
-         tmp1 = pop ();
-         tmp2 = pop ();
-         push (sword (as, tmp1) == sword (as, tmp2));
-         break;
-
-       case DW_OP_lt:
-         Debug (15, "OP_lt\n");
-         tmp1 = pop ();
-         tmp2 = pop ();
-         push (sword (as, tmp1) < sword (as, tmp2));
-         break;
-
-       case DW_OP_gt:
-         Debug (15, "OP_gt\n");
-         tmp1 = pop ();
-         tmp2 = pop ();
-         push (sword (as, tmp1) > sword (as, tmp2));
-         break;
-
-       case DW_OP_ne:
-         Debug (15, "OP_ne\n");
-         tmp1 = pop ();
-         tmp2 = pop ();
-         push (sword (as, tmp1) != sword (as, tmp2));
-         break;
-
-       case DW_OP_skip:
-         Debug (15, "OP_skip(%d)\n", (int16_t) operand1);
-         *addr += (int16_t) operand1;
-         break;
-
-       case DW_OP_bra:
-         Debug (15, "OP_skip(%d)\n", (int16_t) operand1);
-         tmp1 = pop ();
-         if (tmp1)
-           *addr += (int16_t) operand1;
-         break;
-
-       case DW_OP_nop:
-         Debug (15, "OP_nop\n");
-         break;
-
-       case DW_OP_call2:
-       case DW_OP_call4:
-       case DW_OP_call_ref:
-       case DW_OP_fbreg:
-       case DW_OP_piece:
-       case DW_OP_push_object_address:
-       case DW_OP_xderef:
-       case DW_OP_xderef_size:
-       default:
-         Debug (1, "Unexpected opcode 0x%x\n", opcode);
-         return -UNW_EINVAL;
-       }
+        {
+        case DW_OP_lit0:  case DW_OP_lit1:  case DW_OP_lit2:
+        case DW_OP_lit3:  case DW_OP_lit4:  case DW_OP_lit5:
+        case DW_OP_lit6:  case DW_OP_lit7:  case DW_OP_lit8:
+        case DW_OP_lit9:  case DW_OP_lit10: case DW_OP_lit11:
+        case DW_OP_lit12: case DW_OP_lit13: case DW_OP_lit14:
+        case DW_OP_lit15: case DW_OP_lit16: case DW_OP_lit17:
+        case DW_OP_lit18: case DW_OP_lit19: case DW_OP_lit20:
+        case DW_OP_lit21: case DW_OP_lit22: case DW_OP_lit23:
+        case DW_OP_lit24: case DW_OP_lit25: case DW_OP_lit26:
+        case DW_OP_lit27: case DW_OP_lit28: case DW_OP_lit29:
+        case DW_OP_lit30: case DW_OP_lit31:
+          Debug (15, "OP_lit(%d)\n", (int) opcode - DW_OP_lit0);
+          push (opcode - DW_OP_lit0);
+          break;
+
+        case DW_OP_breg0:  case DW_OP_breg1:  case DW_OP_breg2:
+        case DW_OP_breg3:  case DW_OP_breg4:  case DW_OP_breg5:
+        case DW_OP_breg6:  case DW_OP_breg7:  case DW_OP_breg8:
+        case DW_OP_breg9:  case DW_OP_breg10: case DW_OP_breg11:
+        case DW_OP_breg12: case DW_OP_breg13: case DW_OP_breg14:
+        case DW_OP_breg15: case DW_OP_breg16: case DW_OP_breg17:
+        case DW_OP_breg18: case DW_OP_breg19: case DW_OP_breg20:
+        case DW_OP_breg21: case DW_OP_breg22: case DW_OP_breg23:
+        case DW_OP_breg24: case DW_OP_breg25: case DW_OP_breg26:
+        case DW_OP_breg27: case DW_OP_breg28: case DW_OP_breg29:
+        case DW_OP_breg30: case DW_OP_breg31:
+          Debug (15, "OP_breg(r%d,0x%lx)\n",
+                 (int) opcode - DW_OP_breg0, (unsigned long) operand1);
+          if ((ret = unw_get_reg (dwarf_to_cursor (c),
+                                  dwarf_to_unw_regnum (opcode - DW_OP_breg0),
+                                  &tmp1)) < 0)
+            return ret;
+          push (tmp1 + operand1);
+          break;
+
+        case DW_OP_bregx:
+          Debug (15, "OP_bregx(r%d,0x%lx)\n",
+                 (int) operand1, (unsigned long) operand2);
+          if ((ret = unw_get_reg (dwarf_to_cursor (c),
+                                  dwarf_to_unw_regnum (operand1), &tmp1)) < 0)
+            return ret;
+          push (tmp1 + operand2);
+          break;
+
+        case DW_OP_reg0:  case DW_OP_reg1:  case DW_OP_reg2:
+        case DW_OP_reg3:  case DW_OP_reg4:  case DW_OP_reg5:
+        case DW_OP_reg6:  case DW_OP_reg7:  case DW_OP_reg8:
+        case DW_OP_reg9:  case DW_OP_reg10: case DW_OP_reg11:
+        case DW_OP_reg12: case DW_OP_reg13: case DW_OP_reg14:
+        case DW_OP_reg15: case DW_OP_reg16: case DW_OP_reg17:
+        case DW_OP_reg18: case DW_OP_reg19: case DW_OP_reg20:
+        case DW_OP_reg21: case DW_OP_reg22: case DW_OP_reg23:
+        case DW_OP_reg24: case DW_OP_reg25: case DW_OP_reg26:
+        case DW_OP_reg27: case DW_OP_reg28: case DW_OP_reg29:
+        case DW_OP_reg30: case DW_OP_reg31:
+          Debug (15, "OP_reg(r%d)\n", (int) opcode - DW_OP_reg0);
+          *valp = dwarf_to_unw_regnum (opcode - DW_OP_reg0);
+          *is_register = 1;
+          return 0;
+
+        case DW_OP_regx:
+          Debug (15, "OP_regx(r%d)\n", (int) operand1);
+          *valp = dwarf_to_unw_regnum (operand1);
+          *is_register = 1;
+          return 0;
+
+        case DW_OP_addr:
+        case DW_OP_const1u:
+        case DW_OP_const2u:
+        case DW_OP_const4u:
+        case DW_OP_const8u:
+        case DW_OP_constu:
+        case DW_OP_const8s:
+        case DW_OP_consts:
+          Debug (15, "OP_const(0x%lx)\n", (unsigned long) operand1);
+          push (operand1);
+          break;
+
+        case DW_OP_const1s:
+          if (operand1 & 0x80)
+            operand1 |= ((unw_word_t) -1) << 8;
+          Debug (15, "OP_const1s(%ld)\n", (long) operand1);
+          push (operand1);
+          break;
+
+        case DW_OP_const2s:
+          if (operand1 & 0x8000)
+            operand1 |= ((unw_word_t) -1) << 16;
+          Debug (15, "OP_const2s(%ld)\n", (long) operand1);
+          push (operand1);
+          break;
+
+        case DW_OP_const4s:
+          if (operand1 & 0x80000000)
+            operand1 |= (((unw_word_t) -1) << 16) << 16;
+          Debug (15, "OP_const4s(%ld)\n", (long) operand1);
+          push (operand1);
+          break;
+
+        case DW_OP_deref:
+          Debug (15, "OP_deref\n");
+          tmp1 = pop ();
+          if ((ret = dwarf_readw (as, a, &tmp1, &tmp2, arg)) < 0)
+            return ret;
+          push (tmp2);
+          break;
+
+        case DW_OP_deref_size:
+          Debug (15, "OP_deref_size(%d)\n", (int) operand1);
+          tmp1 = pop ();
+          switch (operand1)
+            {
+            default:
+              Debug (1, "Unexpected DW_OP_deref_size size %d\n",
+                     (int) operand1);
+              return -UNW_EINVAL;
+
+            case 1:
+              if ((ret = dwarf_readu8 (as, a, &tmp1, &u8, arg)) < 0)
+                return ret;
+              tmp2 = u8;
+              break;
+
+            case 2:
+              if ((ret = dwarf_readu16 (as, a, &tmp1, &u16, arg)) < 0)
+                return ret;
+              tmp2 = u16;
+              break;
+
+            case 3:
+            case 4:
+              if ((ret = dwarf_readu32 (as, a, &tmp1, &u32, arg)) < 0)
+                return ret;
+              tmp2 = u32;
+              if (operand1 == 3)
+                {
+                  if (dwarf_is_big_endian (as))
+                    tmp2 >>= 8;
+                  else
+                    tmp2 &= 0xffffff;
+                }
+              break;
+            case 5:
+            case 6:
+            case 7:
+            case 8:
+              if ((ret = dwarf_readu64 (as, a, &tmp1, &u64, arg)) < 0)
+                return ret;
+              tmp2 = u64;
+              if (operand1 != 8)
+                {
+                  if (dwarf_is_big_endian (as))
+                    tmp2 >>= 64 - 8 * operand1;
+                  else
+                    tmp2 &= (~ (unw_word_t) 0) << (8 * operand1);
+                }
+              break;
+            }
+          push (tmp2);
+          break;
+
+        case DW_OP_dup:
+          Debug (15, "OP_dup\n");
+          push (pick (0));
+          break;
+
+        case DW_OP_drop:
+          Debug (15, "OP_drop\n");
+          (void) pop ();
+          break;
+
+        case DW_OP_pick:
+          Debug (15, "OP_pick(%d)\n", (int) operand1);
+          push (pick (operand1));
+          break;
+
+        case DW_OP_over:
+          Debug (15, "OP_over\n");
+          push (pick (1));
+          break;
+
+        case DW_OP_swap:
+          Debug (15, "OP_swap\n");
+          tmp1 = pop ();
+          tmp2 = pop ();
+          push (tmp1);
+          push (tmp2);
+          break;
+
+        case DW_OP_rot:
+          Debug (15, "OP_rot\n");
+          tmp1 = pop ();
+          tmp2 = pop ();
+          tmp3 = pop ();
+          push (tmp1);
+          push (tmp3);
+          push (tmp2);
+          break;
+
+        case DW_OP_abs:
+          Debug (15, "OP_abs\n");
+          tmp1 = pop ();
+          if (tmp1 & ((unw_word_t) 1 << (8 * dwarf_addr_size (as) - 1)))
+            tmp1 = -tmp1;
+          push (tmp1);
+          break;
+
+        case DW_OP_and:
+          Debug (15, "OP_and\n");
+          tmp1 = pop ();
+          tmp2 = pop ();
+          push (tmp1 & tmp2);
+          break;
+
+        case DW_OP_div:
+          Debug (15, "OP_div\n");
+          tmp1 = pop ();
+          tmp2 = pop ();
+          if (tmp1)
+            tmp1 = sword (as, tmp2) / sword (as, tmp1);
+          push (tmp1);
+          break;
+
+        case DW_OP_minus:
+          Debug (15, "OP_minus\n");
+          tmp1 = pop ();
+          tmp2 = pop ();
+          tmp1 = tmp2 - tmp1;
+          push (tmp1);
+          break;
+
+        case DW_OP_mod:
+          Debug (15, "OP_mod\n");
+          tmp1 = pop ();
+          tmp2 = pop ();
+          if (tmp1)
+            tmp1 = tmp2 % tmp1;
+          push (tmp1);
+          break;
+
+        case DW_OP_mul:
+          Debug (15, "OP_mul\n");
+          tmp1 = pop ();
+          tmp2 = pop ();
+          if (tmp1)
+            tmp1 = tmp2 * tmp1;
+          push (tmp1);
+          break;
+
+        case DW_OP_neg:
+          Debug (15, "OP_neg\n");
+          push (-pop ());
+          break;
+
+        case DW_OP_not:
+          Debug (15, "OP_not\n");
+          push (~pop ());
+          break;
+
+        case DW_OP_or:
+          Debug (15, "OP_or\n");
+          tmp1 = pop ();
+          tmp2 = pop ();
+          push (tmp1 | tmp2);
+          break;
+
+        case DW_OP_plus:
+          Debug (15, "OP_plus\n");
+          tmp1 = pop ();
+          tmp2 = pop ();
+          push (tmp1 + tmp2);
+          break;
+
+        case DW_OP_plus_uconst:
+          Debug (15, "OP_plus_uconst(%lu)\n", (unsigned long) operand1);
+          tmp1 = pop ();
+          push (tmp1 + operand1);
+          break;
+
+        case DW_OP_shl:
+          Debug (15, "OP_shl\n");
+          tmp1 = pop ();
+          tmp2 = pop ();
+          push (tmp2 << tmp1);
+          break;
+
+        case DW_OP_shr:
+          Debug (15, "OP_shr\n");
+          tmp1 = pop ();
+          tmp2 = pop ();
+          push (tmp2 >> tmp1);
+          break;
+
+        case DW_OP_shra:
+          Debug (15, "OP_shra\n");
+          tmp1 = pop ();
+          tmp2 = pop ();
+          push (sword (as, tmp2) >> tmp1);
+          break;
+
+        case DW_OP_xor:
+          Debug (15, "OP_xor\n");
+          tmp1 = pop ();
+          tmp2 = pop ();
+          push (tmp1 ^ tmp2);
+          break;
+
+        case DW_OP_le:
+          Debug (15, "OP_le\n");
+          tmp1 = pop ();
+          tmp2 = pop ();
+          push (sword (as, tmp2) <= sword (as, tmp1));
+          break;
+
+        case DW_OP_ge:
+          Debug (15, "OP_ge\n");
+          tmp1 = pop ();
+          tmp2 = pop ();
+          push (sword (as, tmp2) >= sword (as, tmp1));
+          break;
+
+        case DW_OP_eq:
+          Debug (15, "OP_eq\n");
+          tmp1 = pop ();
+          tmp2 = pop ();
+          push (sword (as, tmp2) == sword (as, tmp1));
+          break;
+
+        case DW_OP_lt:
+          Debug (15, "OP_lt\n");
+          tmp1 = pop ();
+          tmp2 = pop ();
+          push (sword (as, tmp2) < sword (as, tmp1));
+          break;
+
+        case DW_OP_gt:
+          Debug (15, "OP_gt\n");
+          tmp1 = pop ();
+          tmp2 = pop ();
+          push (sword (as, tmp2) > sword (as, tmp1));
+          break;
+
+        case DW_OP_ne:
+          Debug (15, "OP_ne\n");
+          tmp1 = pop ();
+          tmp2 = pop ();
+          push (sword (as, tmp2) != sword (as, tmp1));
+          break;
+
+        case DW_OP_skip:
+          Debug (15, "OP_skip(%d)\n", (int16_t) operand1);
+          *addr += (int16_t) operand1;
+          break;
+
+        case DW_OP_bra:
+          Debug (15, "OP_skip(%d)\n", (int16_t) operand1);
+          tmp1 = pop ();
+          if (tmp1)
+            *addr += (int16_t) operand1;
+          break;
+
+        case DW_OP_nop:
+          Debug (15, "OP_nop\n");
+          break;
+
+        case DW_OP_call2:
+        case DW_OP_call4:
+        case DW_OP_call_ref:
+        case DW_OP_fbreg:
+        case DW_OP_piece:
+        case DW_OP_push_object_address:
+        case DW_OP_xderef:
+        case DW_OP_xderef_size:
+        default:
+          Debug (1, "Unexpected opcode 0x%x\n", opcode);
+          return -UNW_EINVAL;
+        }
     }
   *valp = pop ();
   Debug (14, "final value = 0x%lx\n", (unsigned long) *valp);