- /*
- * Have to convert the ARM unwind info into DWARF unwind info.
- * The ARM unwind info specifies a simple set of instructions which need to be
- * executed during unwinding. It manipulates a virtual stack pointer (vsp). The
- * connection with DWARF unwind info is the following: after all ARM unwind
- * opcodes have been executed, the stack should be completely unwound, i.e.
- * vsp == DWARF CFA. This allows us to construct the DWARF opcodes corresponding
- * to the ARM opcodes.
- * The ARM unwind info is not instruction precise, i. e. it can't handle
- * async exceptions etc.
- */
- /* The reg used to compute the initial value of vsp */
- vsp_reg = ARMREG_SP;
- /* The offset between vsp_reg and the CFA */
- vsp_offset = 0;
-
- /* The register save offsets from the initial value of vsp */
- reg_offsets = g_new0 (gint32, 16);
- for (i = 0; i < 16; ++i)
- reg_offsets [i] = -1;
-
- /* section 9.3 in the ehabi doc */
- for (i = 0; i < nops; ++i) {
- guint8 op = unwind_ops [i];
-
- if ((op >> 6) == 0) {
- /* vsp = vsp + (xxxxxx << 2) + 4. */
- vsp_offset += ((op & 0x3f) << 2) + 4;
- } else if ((op >> 6) == 1) {
- /* vsp = vsp - (xxxxxx << 2) - 4. */
- vsp_offset -= ((op & 0x3f) << 2) + 4;
- } else if (op == 0xb2) {
- /* vsp = vsp = vsp + 0x204 + (uleb128 << 2) */
- guint8 *p = unwind_ops + i + 1;
- guint32 v = decode_uleb128 (p, &p);
-
- vsp_offset += 0x204 + (v << 2);
- i = (p - unwind_ops) - 1;
- } else if (op >= 0x80 && op <= 0x8f) {
- /* pop registers */
- guint8 op2;
- GSList *regs;
- int j;
-
- g_assert (i + 1 < nops);
- op2 = unwind_ops [i + 1];
-
- regs = NULL;
- for (j = 0; j < 8; ++j)
- if (op2 & (0x1 << j))
- regs = g_slist_append (regs, GUINT_TO_POINTER (ARMREG_R4 + j));
- for (j = 0; j < 4; ++j)
- if (op & (0x1 << j))
- regs = g_slist_append (regs, GUINT_TO_POINTER (ARMREG_R12 + j));
- g_assert (regs);
-
- for (j = 0; j < g_slist_length (regs); ++j)
- reg_offsets [GPOINTER_TO_UINT (g_slist_nth (regs, j)->data)] = vsp_offset + (j * 4);
-
- vsp_offset += g_slist_length (regs) * 4;
-
- g_slist_free (regs);
-
- i ++;
- } else if (op >= 0xa8 && op <= 0xaf) {
- GSList *regs;
- int j;
-
- /* pop r4-r[4 + nnn], r14 */
-
- regs = NULL;
- for (j = 0; j <= (op & 0x7); ++j)
- regs = g_slist_append (regs, GUINT_TO_POINTER (ARMREG_R4 + j));
- regs = g_slist_append (regs, GUINT_TO_POINTER (ARMREG_R14));
-
- for (j = 0; j < g_slist_length (regs); ++j)
- reg_offsets [GPOINTER_TO_UINT (g_slist_nth (regs, j)->data)] = vsp_offset + (j * 4);
-
- vsp_offset += g_slist_length (regs) * 4;
-
- g_slist_free (regs);
- } else if (op == 0xb0) {
- /* finish */
- break;
- } else if (op >= 0x90 && op <= 0x9f && op != 0x9d && op != 0x9f) {
- /* vsp = <reg> */
- vsp_reg = op & 0xf;
- vsp_offset = 0;
- } else {
- int j;