+/* Search for the exception table entry covering MEMADDR. If one is found,
+ return a pointer to its data. Otherwise, return 0. If START is non-NULL,
+ set *START to the start of the region covered by this entry. */
+
+static gdb_byte *
+arm_find_exidx_entry (CORE_ADDR memaddr, CORE_ADDR *start)
+{
+ struct obj_section *sec;
+
+ sec = find_pc_section (memaddr);
+ if (sec != NULL)
+ {
+ struct arm_exidx_data *data;
+ VEC(arm_exidx_entry_s) *map;
+ struct arm_exidx_entry map_key = { memaddr - obj_section_addr (sec), 0 };
+ unsigned int idx;
+
+ data = objfile_data (sec->objfile, arm_exidx_data_key);
+ if (data != NULL)
+ {
+ map = data->section_maps[sec->the_bfd_section->index];
+ if (!VEC_empty (arm_exidx_entry_s, map))
+ {
+ struct arm_exidx_entry *map_sym;
+
+ idx = VEC_lower_bound (arm_exidx_entry_s, map, &map_key,
+ arm_compare_exidx_entries);
+
+ /* VEC_lower_bound finds the earliest ordered insertion
+ point. If the following symbol starts at this exact
+ address, we use that; otherwise, the preceding
+ exception table entry covers this address. */
+ if (idx < VEC_length (arm_exidx_entry_s, map))
+ {
+ map_sym = VEC_index (arm_exidx_entry_s, map, idx);
+ if (map_sym->addr == map_key.addr)
+ {
+ if (start)
+ *start = map_sym->addr + obj_section_addr (sec);
+ return map_sym->entry;
+ }
+ }
+
+ if (idx > 0)
+ {
+ map_sym = VEC_index (arm_exidx_entry_s, map, idx - 1);
+ if (start)
+ *start = map_sym->addr + obj_section_addr (sec);
+ return map_sym->entry;
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/* Given the current frame THIS_FRAME, and its associated frame unwinding
+ instruction list from the ARM exception table entry ENTRY, allocate and
+ return a prologue cache structure describing how to unwind this frame.
+
+ Return NULL if the unwinding instruction list contains a "spare",
+ "reserved" or "refuse to unwind" instruction as defined in section
+ "9.3 Frame unwinding instructions" of the "Exception Handling ABI
+ for the ARM Architecture" document. */
+
+static struct arm_prologue_cache *
+arm_exidx_fill_cache (struct frame_info *this_frame, gdb_byte *entry)
+{
+ CORE_ADDR vsp = 0;
+ int vsp_valid = 0;
+
+ struct arm_prologue_cache *cache;
+ cache = FRAME_OBSTACK_ZALLOC (struct arm_prologue_cache);
+ cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
+
+ for (;;)
+ {
+ gdb_byte insn;
+
+ /* Whenever we reload SP, we actually have to retrieve its
+ actual value in the current frame. */
+ if (!vsp_valid)
+ {
+ if (trad_frame_realreg_p (cache->saved_regs, ARM_SP_REGNUM))
+ {
+ int reg = cache->saved_regs[ARM_SP_REGNUM].realreg;
+ vsp = get_frame_register_unsigned (this_frame, reg);
+ }
+ else
+ {
+ CORE_ADDR addr = cache->saved_regs[ARM_SP_REGNUM].addr;
+ vsp = get_frame_memory_unsigned (this_frame, addr, 4);
+ }
+
+ vsp_valid = 1;
+ }
+
+ /* Decode next unwind instruction. */
+ insn = *entry++;
+
+ if ((insn & 0xc0) == 0)
+ {
+ int offset = insn & 0x3f;
+ vsp += (offset << 2) + 4;
+ }
+ else if ((insn & 0xc0) == 0x40)
+ {
+ int offset = insn & 0x3f;
+ vsp -= (offset << 2) + 4;
+ }
+ else if ((insn & 0xf0) == 0x80)
+ {
+ int mask = ((insn & 0xf) << 8) | *entry++;
+ int i;
+
+ /* The special case of an all-zero mask identifies
+ "Refuse to unwind". We return NULL to fall back
+ to the prologue analyzer. */
+ if (mask == 0)
+ return NULL;
+
+ /* Pop registers r4..r15 under mask. */
+ for (i = 0; i < 12; i++)
+ if (mask & (1 << i))
+ {
+ cache->saved_regs[4 + i].addr = vsp;
+ vsp += 4;
+ }
+
+ /* Special-case popping SP -- we need to reload vsp. */
+ if (mask & (1 << (ARM_SP_REGNUM - 4)))
+ vsp_valid = 0;
+ }
+ else if ((insn & 0xf0) == 0x90)
+ {
+ int reg = insn & 0xf;
+
+ /* Reserved cases. */
+ if (reg == ARM_SP_REGNUM || reg == ARM_PC_REGNUM)
+ return NULL;
+
+ /* Set SP from another register and mark VSP for reload. */
+ cache->saved_regs[ARM_SP_REGNUM] = cache->saved_regs[reg];
+ vsp_valid = 0;
+ }
+ else if ((insn & 0xf0) == 0xa0)
+ {
+ int count = insn & 0x7;
+ int pop_lr = (insn & 0x8) != 0;
+ int i;
+
+ /* Pop r4..r[4+count]. */
+ for (i = 0; i <= count; i++)
+ {
+ cache->saved_regs[4 + i].addr = vsp;
+ vsp += 4;
+ }
+
+ /* If indicated by flag, pop LR as well. */
+ if (pop_lr)
+ {
+ cache->saved_regs[ARM_LR_REGNUM].addr = vsp;
+ vsp += 4;
+ }
+ }
+ else if (insn == 0xb0)
+ {
+ /* We could only have updated PC by popping into it; if so, it
+ will show up as address. Otherwise, copy LR into PC. */
+ if (!trad_frame_addr_p (cache->saved_regs, ARM_PC_REGNUM))
+ cache->saved_regs[ARM_PC_REGNUM]
+ = cache->saved_regs[ARM_LR_REGNUM];
+
+ /* We're done. */
+ break;
+ }
+ else if (insn == 0xb1)
+ {
+ int mask = *entry++;
+ int i;
+
+ /* All-zero mask and mask >= 16 is "spare". */
+ if (mask == 0 || mask >= 16)
+ return NULL;
+
+ /* Pop r0..r3 under mask. */
+ for (i = 0; i < 4; i++)
+ if (mask & (1 << i))
+ {
+ cache->saved_regs[i].addr = vsp;
+ vsp += 4;
+ }
+ }
+ else if (insn == 0xb2)
+ {
+ ULONGEST offset = 0;
+ unsigned shift = 0;
+
+ do
+ {
+ offset |= (*entry & 0x7f) << shift;
+ shift += 7;
+ }
+ while (*entry++ & 0x80);
+
+ vsp += 0x204 + (offset << 2);
+ }
+ else if (insn == 0xb3)
+ {
+ int start = *entry >> 4;
+ int count = (*entry++) & 0xf;
+ int i;
+
+ /* Only registers D0..D15 are valid here. */
+ if (start + count >= 16)
+ return NULL;
+
+ /* Pop VFP double-precision registers D[start]..D[start+count]. */
+ for (i = 0; i <= count; i++)
+ {
+ cache->saved_regs[ARM_D0_REGNUM + start + i].addr = vsp;
+ vsp += 8;
+ }
+
+ /* Add an extra 4 bytes for FSTMFDX-style stack. */
+ vsp += 4;
+ }
+ else if ((insn & 0xf8) == 0xb8)
+ {
+ int count = insn & 0x7;
+ int i;
+
+ /* Pop VFP double-precision registers D[8]..D[8+count]. */
+ for (i = 0; i <= count; i++)
+ {
+ cache->saved_regs[ARM_D0_REGNUM + 8 + i].addr = vsp;
+ vsp += 8;
+ }
+
+ /* Add an extra 4 bytes for FSTMFDX-style stack. */
+ vsp += 4;
+ }
+ else if (insn == 0xc6)
+ {
+ int start = *entry >> 4;
+ int count = (*entry++) & 0xf;
+ int i;
+
+ /* Only registers WR0..WR15 are valid. */
+ if (start + count >= 16)
+ return NULL;
+
+ /* Pop iwmmx registers WR[start]..WR[start+count]. */
+ for (i = 0; i <= count; i++)
+ {
+ cache->saved_regs[ARM_WR0_REGNUM + start + i].addr = vsp;
+ vsp += 8;
+ }
+ }
+ else if (insn == 0xc7)
+ {
+ int mask = *entry++;
+ int i;
+
+ /* All-zero mask and mask >= 16 is "spare". */
+ if (mask == 0 || mask >= 16)
+ return NULL;
+
+ /* Pop iwmmx general-purpose registers WCGR0..WCGR3 under mask. */
+ for (i = 0; i < 4; i++)
+ if (mask & (1 << i))
+ {
+ cache->saved_regs[ARM_WCGR0_REGNUM + i].addr = vsp;
+ vsp += 4;
+ }
+ }
+ else if ((insn & 0xf8) == 0xc0)
+ {
+ int count = insn & 0x7;
+ int i;
+
+ /* Pop iwmmx registers WR[10]..WR[10+count]. */
+ for (i = 0; i <= count; i++)
+ {
+ cache->saved_regs[ARM_WR0_REGNUM + 10 + i].addr = vsp;
+ vsp += 8;
+ }
+ }
+ else if (insn == 0xc8)
+ {
+ int start = *entry >> 4;
+ int count = (*entry++) & 0xf;
+ int i;
+
+ /* Only registers D0..D31 are valid. */
+ if (start + count >= 16)
+ return NULL;
+
+ /* Pop VFP double-precision registers
+ D[16+start]..D[16+start+count]. */
+ for (i = 0; i <= count; i++)
+ {
+ cache->saved_regs[ARM_D0_REGNUM + 16 + start + i].addr = vsp;
+ vsp += 8;
+ }
+ }
+ else if (insn == 0xc9)
+ {
+ int start = *entry >> 4;
+ int count = (*entry++) & 0xf;
+ int i;
+
+ /* Pop VFP double-precision registers D[start]..D[start+count]. */
+ for (i = 0; i <= count; i++)
+ {
+ cache->saved_regs[ARM_D0_REGNUM + start + i].addr = vsp;
+ vsp += 8;
+ }
+ }
+ else if ((insn & 0xf8) == 0xd0)
+ {
+ int count = insn & 0x7;
+ int i;
+
+ /* Pop VFP double-precision registers D[8]..D[8+count]. */
+ for (i = 0; i <= count; i++)
+ {
+ cache->saved_regs[ARM_D0_REGNUM + 8 + i].addr = vsp;
+ vsp += 8;
+ }
+ }
+ else
+ {
+ /* Everything else is "spare". */
+ return NULL;
+ }
+ }
+
+ /* If we restore SP from a register, assume this was the frame register.
+ Otherwise just fall back to SP as frame register. */
+ if (trad_frame_realreg_p (cache->saved_regs, ARM_SP_REGNUM))
+ cache->framereg = cache->saved_regs[ARM_SP_REGNUM].realreg;
+ else
+ cache->framereg = ARM_SP_REGNUM;
+
+ /* Determine offset to previous frame. */
+ cache->framesize
+ = vsp - get_frame_register_unsigned (this_frame, cache->framereg);
+
+ /* We already got the previous SP. */
+ cache->prev_sp = vsp;
+
+ return cache;
+}
+
+/* Unwinding via ARM exception table entries. Note that the sniffer
+ already computes a filled-in prologue cache, which is then used
+ with the same arm_prologue_this_id and arm_prologue_prev_register
+ routines also used for prologue-parsing based unwinding. */
+
+static int
+arm_exidx_unwind_sniffer (const struct frame_unwind *self,
+ struct frame_info *this_frame,
+ void **this_prologue_cache)
+{
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
+ CORE_ADDR addr_in_block, exidx_region, func_start;
+ struct arm_prologue_cache *cache;
+ gdb_byte *entry;
+
+ /* See if we have an ARM exception table entry covering this address. */
+ addr_in_block = get_frame_address_in_block (this_frame);
+ entry = arm_find_exidx_entry (addr_in_block, &exidx_region);
+ if (!entry)
+ return 0;
+
+ /* The ARM exception table does not describe unwind information
+ for arbitrary PC values, but is guaranteed to be correct only
+ at call sites. We have to decide here whether we want to use
+ ARM exception table information for this frame, or fall back
+ to using prologue parsing. (Note that if we have DWARF CFI,
+ this sniffer isn't even called -- CFI is always preferred.)
+
+ Before we make this decision, however, we check whether we
+ actually have *symbol* information for the current frame.
+ If not, prologue parsing would not work anyway, so we might
+ as well use the exception table and hope for the best. */
+ if (find_pc_partial_function (addr_in_block, NULL, &func_start, NULL))
+ {
+ int exc_valid = 0;
+
+ /* If the next frame is "normal", we are at a call site in this
+ frame, so exception information is guaranteed to be valid. */
+ if (get_next_frame (this_frame)
+ && get_frame_type (get_next_frame (this_frame)) == NORMAL_FRAME)
+ exc_valid = 1;
+
+ /* We also assume exception information is valid if we're currently
+ blocked in a system call. The system library is supposed to
+ ensure this, so that e.g. pthread cancellation works. */
+ if (arm_frame_is_thumb (this_frame))
+ {
+ LONGEST insn;
+
+ if (safe_read_memory_integer (get_frame_pc (this_frame) - 2, 2,
+ byte_order_for_code, &insn)
+ && (insn & 0xff00) == 0xdf00 /* svc */)
+ exc_valid = 1;
+ }
+ else
+ {
+ LONGEST insn;
+
+ if (safe_read_memory_integer (get_frame_pc (this_frame) - 4, 4,
+ byte_order_for_code, &insn)
+ && (insn & 0x0f000000) == 0x0f000000 /* svc */)
+ exc_valid = 1;
+ }
+
+ /* Bail out if we don't know that exception information is valid. */
+ if (!exc_valid)
+ return 0;
+
+ /* The ARM exception index does not mark the *end* of the region
+ covered by the entry, and some functions will not have any entry.
+ To correctly recognize the end of the covered region, the linker
+ should have inserted dummy records with a CANTUNWIND marker.
+
+ Unfortunately, current versions of GNU ld do not reliably do
+ this, and thus we may have found an incorrect entry above.
+ As a (temporary) sanity check, we only use the entry if it
+ lies *within* the bounds of the function. Note that this check
+ might reject perfectly valid entries that just happen to cover
+ multiple functions; therefore this check ought to be removed
+ once the linker is fixed. */
+ if (func_start > exidx_region)
+ return 0;
+ }
+
+ /* Decode the list of unwinding instructions into a prologue cache.
+ Note that this may fail due to e.g. a "refuse to unwind" code. */
+ cache = arm_exidx_fill_cache (this_frame, entry);
+ if (!cache)
+ return 0;
+
+ *this_prologue_cache = cache;
+ return 1;
+}
+
+struct frame_unwind arm_exidx_unwind = {
+ NORMAL_FRAME,
+ arm_prologue_this_id,
+ arm_prologue_prev_register,
+ NULL,
+ arm_exidx_unwind_sniffer
+};
+
+static struct arm_prologue_cache *
+arm_make_stub_cache (struct frame_info *this_frame)
+{
+ struct arm_prologue_cache *cache;
+
+ cache = FRAME_OBSTACK_ZALLOC (struct arm_prologue_cache);
+ cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
+
+ cache->prev_sp = get_frame_register_unsigned (this_frame, ARM_SP_REGNUM);
+
+ return cache;
+}
+
+/* Our frame ID for a stub frame is the current SP and LR. */
+
+static void
+arm_stub_this_id (struct frame_info *this_frame,
+ void **this_cache,
+ struct frame_id *this_id)
+{
+ struct arm_prologue_cache *cache;
+
+ if (*this_cache == NULL)
+ *this_cache = arm_make_stub_cache (this_frame);
+ cache = *this_cache;
+
+ *this_id = frame_id_build (cache->prev_sp, get_frame_pc (this_frame));
+}
+
+static int
+arm_stub_unwind_sniffer (const struct frame_unwind *self,
+ struct frame_info *this_frame,
+ void **this_prologue_cache)
+{
+ CORE_ADDR addr_in_block;
+ char dummy[4];
+
+ addr_in_block = get_frame_address_in_block (this_frame);
+ if (in_plt_section (addr_in_block, NULL)
+ /* We also use the stub winder if the target memory is unreadable
+ to avoid having the prologue unwinder trying to read it. */
+ || target_read_memory (get_frame_pc (this_frame), dummy, 4) != 0)
+ return 1;
+
+ return 0;
+}
+
+struct frame_unwind arm_stub_unwind = {
+ NORMAL_FRAME,
+ arm_stub_this_id,
+ arm_prologue_prev_register,
+ NULL,
+ arm_stub_unwind_sniffer
+};
+
+static CORE_ADDR
+arm_normal_frame_base (struct frame_info *this_frame, void **this_cache)
+{
+ struct arm_prologue_cache *cache;
+
+ if (*this_cache == NULL)
+ *this_cache = arm_make_prologue_cache (this_frame);
+ cache = *this_cache;
+
+ return cache->prev_sp - cache->framesize;
+}
+
+struct frame_base arm_normal_base = {
+ &arm_prologue_unwind,
+ arm_normal_frame_base,
+ arm_normal_frame_base,
+ arm_normal_frame_base
+};
+
+/* Assuming THIS_FRAME is a dummy, return the frame ID of that
+ dummy frame. The frame ID's base needs to match the TOS value
+ saved by save_dummy_frame_tos() and returned from
+ arm_push_dummy_call, and the PC needs to match the dummy frame's
+ breakpoint. */
+
+static struct frame_id
+arm_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+ return frame_id_build (get_frame_register_unsigned (this_frame,
+ ARM_SP_REGNUM),
+ get_frame_pc (this_frame));
+}
+
+/* Given THIS_FRAME, find the previous frame's resume PC (which will
+ be used to construct the previous frame's ID, after looking up the
+ containing function). */
+
+static CORE_ADDR
+arm_unwind_pc (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+ CORE_ADDR pc;
+ pc = frame_unwind_register_unsigned (this_frame, ARM_PC_REGNUM);
+ return arm_addr_bits_remove (gdbarch, pc);
+}
+
+static CORE_ADDR
+arm_unwind_sp (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+ return frame_unwind_register_unsigned (this_frame, ARM_SP_REGNUM);
+}
+
+static struct value *
+arm_dwarf2_prev_register (struct frame_info *this_frame, void **this_cache,
+ int regnum)
+{
+ struct gdbarch * gdbarch = get_frame_arch (this_frame);
+ CORE_ADDR lr, cpsr;
+ ULONGEST t_bit = arm_psr_thumb_bit (gdbarch);
+
+ switch (regnum)
+ {
+ case ARM_PC_REGNUM:
+ /* The PC is normally copied from the return column, which
+ describes saves of LR. However, that version may have an
+ extra bit set to indicate Thumb state. The bit is not
+ part of the PC. */
+ lr = frame_unwind_register_unsigned (this_frame, ARM_LR_REGNUM);
+ return frame_unwind_got_constant (this_frame, regnum,
+ arm_addr_bits_remove (gdbarch, lr));
+
+ case ARM_PS_REGNUM:
+ /* Reconstruct the T bit; see arm_prologue_prev_register for details. */
+ cpsr = get_frame_register_unsigned (this_frame, regnum);
+ lr = frame_unwind_register_unsigned (this_frame, ARM_LR_REGNUM);
+ if (IS_THUMB_ADDR (lr))
+ cpsr |= t_bit;
+ else
+ cpsr &= ~t_bit;
+ return frame_unwind_got_constant (this_frame, regnum, cpsr);
+
+ default:
+ internal_error (__FILE__, __LINE__,
+ _("Unexpected register %d"), regnum);
+ }
+}
+
+static void