/* Common target dependent code for GDB on ARM systems.
- Copyright (C) 1988-2014 Free Software Foundation, Inc.
+ Copyright (C) 1988-2015 Free Software Foundation, Inc.
This file is part of GDB.
/* On soft-float targets, __truncdfsf2 is called to convert promoted
arguments to their argument types in non-prototyped
functions. */
- if (strncmp (name, "__truncdfsf2", strlen ("__truncdfsf2")) == 0)
+ if (startswith (name, "__truncdfsf2"))
return 1;
- if (strncmp (name, "__aeabi_d2f", strlen ("__aeabi_d2f")) == 0)
+ if (startswith (name, "__aeabi_d2f"))
return 1;
/* Internal functions related to thread-local storage. */
- if (strncmp (name, "__tls_get_addr", strlen ("__tls_get_addr")) == 0)
+ if (startswith (name, "__tls_get_addr"))
return 1;
- if (strncmp (name, "__aeabi_read_tp", strlen ("__aeabi_read_tp")) == 0)
+ if (startswith (name, "__aeabi_read_tp"))
return 1;
}
else
{
*destreg = bits (insn1, 8, 10);
*offset = 2;
- address = bits (insn1, 0, 7);
+ address = (pc & 0xfffffffc) + 4 + (bits (insn1, 0, 7) << 2);
+ address = read_memory_unsigned_integer (address, 4,
+ byte_order_for_code);
}
else if ((insn1 & 0xfbf0) == 0xf240) /* movw Rd, #const */
{
unsigned int insn
= read_memory_unsigned_integer (pc, 4, byte_order_for_code);
- if ((insn & 0x0e5f0000) == 0x041f0000) /* ldr Rd, #immed */
+ if ((insn & 0x0e5f0000) == 0x041f0000) /* ldr Rd, [PC, #immed] */
{
- address = bits (insn, 0, 11);
+ address = bits (insn, 0, 11) + pc + 8;
+ address = read_memory_unsigned_integer (address, 4,
+ byte_order_for_code);
+
*destreg = bits (insn, 12, 15);
*offset = 4;
}
return pc;
stack_chk_guard = lookup_minimal_symbol_by_pc (addr);
- /* If name of symbol doesn't start with '__stack_chk_guard', this
- instruction sequence is not for stack protector. If symbol is
- removed, we conservatively think this sequence is for stack protector. */
- if (stack_chk_guard.minsym
- && strncmp (MSYMBOL_LINKAGE_NAME (stack_chk_guard.minsym),
- "__stack_chk_guard",
- strlen ("__stack_chk_guard")) != 0)
+ /* ADDR must correspond to a symbol whose name is __stack_chk_guard.
+ Otherwise, this sequence cannot be for stack protector. */
+ if (stack_chk_guard.minsym == NULL
+ || !startswith (MSYMBOL_LINKAGE_NAME (stack_chk_guard.minsym), "__stack_chk_guard"))
return pc;
if (is_thumb)
{
enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
unsigned long inst;
- CORE_ADDR skip_pc;
CORE_ADDR func_addr, limit_pc;
/* See if we can determine the end of the prologue via the symbol table.
{
CORE_ADDR post_prologue_pc
= skip_prologue_using_sal (gdbarch, func_addr);
- struct symtab *s = find_pc_symtab (func_addr);
+ struct compunit_symtab *cust = find_pc_compunit_symtab (func_addr);
if (post_prologue_pc)
post_prologue_pc
will have producer information for most binaries; if it is
missing (e.g. for -gstabs), assuming the GNU tools. */
if (post_prologue_pc
- && (s == NULL
- || s->producer == NULL
- || strncmp (s->producer, "GNU ", sizeof ("GNU ") - 1) == 0
- || strncmp (s->producer, "clang ", sizeof ("clang ") - 1) == 0))
+ && (cust == NULL
+ || COMPUNIT_PRODUCER (cust) == NULL
+ || startswith (COMPUNIT_PRODUCER (cust), "GNU ")
+ || startswith (COMPUNIT_PRODUCER (cust), "clang ")))
return post_prologue_pc;
if (post_prologue_pc != 0)
/* Check if this is Thumb code. */
if (arm_pc_is_thumb (gdbarch, pc))
return thumb_analyze_prologue (gdbarch, pc, limit_pc, NULL);
-
- for (skip_pc = pc; skip_pc < limit_pc; skip_pc += 4)
- {
- inst = read_memory_unsigned_integer (skip_pc, 4, byte_order_for_code);
-
- /* "mov ip, sp" is no longer a required part of the prologue. */
- if (inst == 0xe1a0c00d) /* mov ip, sp */
- continue;
-
- if ((inst & 0xfffff000) == 0xe28dc000) /* add ip, sp #n */
- continue;
-
- if ((inst & 0xfffff000) == 0xe24dc000) /* sub ip, sp #n */
- continue;
-
- /* Some prologues begin with "str lr, [sp, #-4]!". */
- if (inst == 0xe52de004) /* str lr, [sp, #-4]! */
- continue;
-
- if ((inst & 0xfffffff0) == 0xe92d0000) /* stmfd sp!,{a1,a2,a3,a4} */
- continue;
-
- if ((inst & 0xfffff800) == 0xe92dd800) /* stmfd sp!,{fp,ip,lr,pc} */
- continue;
-
- /* Any insns after this point may float into the code, if it makes
- for better instruction scheduling, so we skip them only if we
- find them, but still consider the function to be frame-ful. */
-
- /* We may have either one sfmfd instruction here, or several stfe
- insns, depending on the version of floating point code we
- support. */
- if ((inst & 0xffbf0fff) == 0xec2d0200) /* sfmfd fn, <cnt>, [sp]! */
- continue;
-
- if ((inst & 0xffff8fff) == 0xed6d0103) /* stfe fn, [sp, #-12]! */
- continue;
-
- if ((inst & 0xfffff000) == 0xe24cb000) /* sub fp, ip, #nn */
- continue;
-
- if ((inst & 0xfffff000) == 0xe24dd000) /* sub sp, sp, #nn */
- continue;
-
- if ((inst & 0xffffc000) == 0xe54b0000 /* strb r(0123),[r11,#-nn] */
- || (inst & 0xffffc0f0) == 0xe14b00b0 /* strh r(0123),[r11,#-nn] */
- || (inst & 0xffffc000) == 0xe50b0000) /* str r(0123),[r11,#-nn] */
- continue;
-
- if ((inst & 0xffffc000) == 0xe5cd0000 /* strb r(0123),[sp,#nn] */
- || (inst & 0xffffc0f0) == 0xe1cd00b0 /* strh r(0123),[sp,#nn] */
- || (inst & 0xffffc000) == 0xe58d0000) /* str r(0123),[sp,#nn] */
- continue;
-
- /* Un-recognized instruction; stop scanning. */
- break;
- }
-
- return skip_pc; /* End of prologue. */
+ else
+ return arm_analyze_prologue (gdbarch, pc, limit_pc, NULL);
}
/* *INDENT-OFF* */
}
}
+/* Return 1 if the ARM instruction INSN restores SP in epilogue, 0
+ otherwise. */
+
+static int
+arm_instruction_restores_sp (unsigned int insn)
+{
+ if (bits (insn, 28, 31) != INST_NV)
+ {
+ if ((insn & 0x0df0f000) == 0x0080d000
+ /* ADD SP (register or immediate). */
+ || (insn & 0x0df0f000) == 0x0040d000
+ /* SUB SP (register or immediate). */
+ || (insn & 0x0ffffff0) == 0x01a0d000
+ /* MOV SP. */
+ || (insn & 0x0fff0000) == 0x08bd0000
+ /* POP (LDMIA). */
+ || (insn & 0x0fff0000) == 0x049d0000)
+ /* POP of a single register. */
+ return 1;
+ }
+
+ return 0;
+}
+
/* Analyze an ARM mode prologue starting at PROLOGUE_START and
continuing no further than PROLOGUE_END. If CACHE is non-NULL,
fill it in. Return the first address not recognized as a prologue
pv_t regs[ARM_FPS_REGNUM];
struct pv_area *stack;
struct cleanup *back_to;
- int framereg, framesize;
CORE_ADDR unrecognized_pc = 0;
/* Search the prologue looking for instructions that set up the
else if (arm_instruction_changes_pc (insn))
/* Don't scan past anything that might change control flow. */
break;
+ else if (arm_instruction_restores_sp (insn))
+ {
+ /* Don't scan past the epilogue. */
+ break;
+ }
else if ((insn & 0xfe500000) == 0xe8100000 /* ldm */
&& pv_is_register (regs[bits (insn, 16, 19)], ARM_SP_REGNUM))
/* Ignore block loads from the stack, potentially copying
continue;
else
{
- /* The optimizer might shove anything into the prologue,
- so we just skip what we don't recognize. */
+ /* The optimizer might shove anything into the prologue, if
+ we build up cache (cache != NULL) from scanning prologue,
+ we just skip what we don't recognize and scan further to
+ make cache as complete as possible. However, if we skip
+ prologue, we'll stop immediately on unrecognized
+ instruction. */
unrecognized_pc = current_pc;
- continue;
+ if (cache != NULL)
+ continue;
+ else
+ break;
}
}
if (unrecognized_pc == 0)
unrecognized_pc = current_pc;
- /* The frame size is just the distance from the frame register
- to the original stack pointer. */
- if (pv_is_register (regs[ARM_FP_REGNUM], ARM_SP_REGNUM))
- {
- /* Frame pointer is fp. */
- framereg = ARM_FP_REGNUM;
- framesize = -regs[ARM_FP_REGNUM].k;
- }
- else
- {
- /* Try the stack pointer... this is a bit desperate. */
- framereg = ARM_SP_REGNUM;
- framesize = -regs[ARM_SP_REGNUM].k;
- }
-
if (cache)
{
+ int framereg, framesize;
+
+ /* The frame size is just the distance from the frame register
+ to the original stack pointer. */
+ if (pv_is_register (regs[ARM_FP_REGNUM], ARM_SP_REGNUM))
+ {
+ /* Frame pointer is fp. */
+ framereg = ARM_FP_REGNUM;
+ framesize = -regs[ARM_FP_REGNUM].k;
+ }
+ else
+ {
+ /* Try the stack pointer... this is a bit desperate. */
+ framereg = ARM_SP_REGNUM;
+ framesize = -regs[ARM_SP_REGNUM].k;
+ }
+
cache->framereg = framereg;
cache->framesize = framesize;
return cache;
}
+/* Implementation of the stop_reason hook for arm_prologue frames. */
+
+static enum unwind_stop_reason
+arm_prologue_unwind_stop_reason (struct frame_info *this_frame,
+ void **this_cache)
+{
+ struct arm_prologue_cache *cache;
+ CORE_ADDR pc;
+
+ if (*this_cache == NULL)
+ *this_cache = arm_make_prologue_cache (this_frame);
+ cache = *this_cache;
+
+ /* This is meant to halt the backtrace at "_start". */
+ pc = get_frame_pc (this_frame);
+ if (pc <= gdbarch_tdep (get_frame_arch (this_frame))->lowest_pc)
+ return UNWIND_OUTERMOST;
+
+ /* If we've hit a wall, stop. */
+ if (cache->prev_sp == 0)
+ return UNWIND_OUTERMOST;
+
+ return UNWIND_NO_REASON;
+}
+
/* Our frame ID for a normal frame is the current function's starting PC
and the caller's SP when we were called. */
*this_cache = arm_make_prologue_cache (this_frame);
cache = *this_cache;
- /* This is meant to halt the backtrace at "_start". */
- pc = get_frame_pc (this_frame);
- if (pc <= gdbarch_tdep (get_frame_arch (this_frame))->lowest_pc)
- return;
-
- /* If we've hit a wall, stop. */
- if (cache->prev_sp == 0)
- return;
-
/* Use function start address as part of the frame ID. If we cannot
identify the start address (due to missing symbol information),
fall back to just using the current PC. */
+ pc = get_frame_pc (this_frame);
func = get_frame_func (this_frame);
if (!func)
func = pc;
struct frame_unwind arm_prologue_unwind = {
NORMAL_FRAME,
- default_frame_unwind_stop_reason,
+ arm_prologue_unwind_stop_reason,
arm_prologue_this_id,
arm_prologue_prev_register,
NULL,
}
}
-/* Return true if we are in the function's epilogue, i.e. after the
- instruction that destroyed the function's stack frame. */
+/* Implement the stack_frame_destroyed_p gdbarch method. */
static int
-thumb_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc)
+thumb_stack_frame_destroyed_p (struct gdbarch *gdbarch, CORE_ADDR pc)
{
enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
unsigned int insn, insn2;
found_return = 1;
else if (thumb_instruction_restores_sp (insn))
{
- if ((insn & 0xfe00) == 0xbd00) /* pop <registers, PC> */
+ if ((insn & 0xff00) == 0xbd00) /* pop <registers, PC> */
found_return = 1;
}
else if (thumb_insn_size (insn) == 4) /* 32-bit Thumb-2 instruction */
return found_stack_adjust;
}
-/* Return true if we are in the function's epilogue, i.e. after the
- instruction that destroyed the function's stack frame. */
+/* Implement the stack_frame_destroyed_p gdbarch method. */
static int
-arm_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc)
+arm_stack_frame_destroyed_p (struct gdbarch *gdbarch, CORE_ADDR pc)
{
enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
unsigned int insn;
- int found_return, found_stack_adjust;
+ int found_return;
CORE_ADDR func_start, func_end;
if (arm_pc_is_thumb (gdbarch, pc))
- return thumb_in_function_epilogue_p (gdbarch, pc);
+ return thumb_stack_frame_destroyed_p (gdbarch, pc);
if (!find_pc_partial_function (pc, NULL, &func_start, &func_end))
return 0;
if (pc < func_start + 4)
return 0;
- found_stack_adjust = 0;
insn = read_memory_unsigned_integer (pc - 4, 4, byte_order_for_code);
- if (bits (insn, 28, 31) != INST_NV)
- {
- if ((insn & 0x0df0f000) == 0x0080d000)
- /* ADD SP (register or immediate). */
- found_stack_adjust = 1;
- else if ((insn & 0x0df0f000) == 0x0040d000)
- /* SUB SP (register or immediate). */
- found_stack_adjust = 1;
- else if ((insn & 0x0ffffff0) == 0x01a0d000)
- /* MOV SP. */
- found_stack_adjust = 1;
- else if ((insn & 0x0fff0000) == 0x08bd0000)
- /* POP (LDMIA). */
- found_stack_adjust = 1;
- else if ((insn & 0x0fff0000) == 0x049d0000)
- /* POP of a single register. */
- found_stack_adjust = 1;
- }
-
- if (found_stack_adjust)
+ if (arm_instruction_restores_sp (insn))
return 1;
return 0;
push_stack_item (struct stack_item *prev, const void *contents, int len)
{
struct stack_item *si;
- si = xmalloc (sizeof (struct stack_item));
+ si = XNEW (struct stack_item);
si->data = xmalloc (len);
si->len = len;
si->prev = prev;
case 0x5: /* data transfer */
case 0x6:
case 0x7:
+ if (bits (this_instr, 25, 27) == 0x3 && bit (this_instr, 4) == 1)
+ {
+ /* Media instructions and architecturally undefined
+ instructions. */
+ break;
+ }
+
if (bit (this_instr, 20))
{
/* load */
Preparation: tmp1, tmp2, tmp3 <- r0, r1, r2;
r0, r1, r2 <- rd, rn, rm
- Insn: <op><cond> r0, r1, r2 [, <shift>]
+ Insn: <op><cond> r0, [r1,] r2 [, <shift>]
Cleanup: rd <- r0; r0, r1, r2 <- tmp1, tmp2, tmp3
*/
struct regcache *regs,
struct displaced_step_closure *dsc)
{
- unsigned rn, rm, rd;
+ unsigned rm, rd;
- rd = bits (insn, 3, 6);
- rn = (bit (insn, 7) << 3) | bits (insn, 0, 2);
- rm = 2;
+ rm = bits (insn, 3, 6);
+ rd = (bit (insn, 7) << 3) | bits (insn, 0, 2);
- if (rd != ARM_PC_REGNUM && rn != ARM_PC_REGNUM)
+ if (rd != ARM_PC_REGNUM && rm != ARM_PC_REGNUM)
return thumb_copy_unmodified_16bit (gdbarch, insn, "ALU reg", dsc);
if (debug_displaced)
- fprintf_unfiltered (gdb_stdlog, "displaced: copying reg %s insn %.4x\n",
- "ALU", (unsigned short) insn);
+ fprintf_unfiltered (gdb_stdlog, "displaced: copying ALU reg insn %.4x\n",
+ (unsigned short) insn);
- dsc->modinsn[0] = ((insn & 0xff00) | 0x08);
+ dsc->modinsn[0] = ((insn & 0xff00) | 0x10);
- install_alu_reg (gdbarch, regs, dsc, rd, rn, rm);
+ install_alu_reg (gdbarch, regs, dsc, rd, rd, rm);
return 0;
}
CORE_ADDR from, CORE_ADDR to,
struct regcache *regs)
{
- struct displaced_step_closure *dsc
- = xmalloc (sizeof (struct displaced_step_closure));
+ struct displaced_step_closure *dsc = XNEW (struct displaced_step_closure);
+
arm_process_displaced_insn (gdbarch, from, to, regs, dsc);
arm_displaced_init_closure (gdbarch, from, to, dsc);
int nRc;
enum type_code code;
- CHECK_TYPEDEF (type);
+ type = check_typedef (type);
/* In the ARM ABI, "integer" like aggregate types are returned in
registers. For an aggregate type to be integer like, its size
_call_via_xx, where x is the register name. The possible names
are r0-r9, sl, fp, ip, sp, and lr. ARM RealView has similar
functions, named __ARM_call_via_r[0-7]. */
- if (strncmp (name, "_call_via_", 10) == 0
- || strncmp (name, "__ARM_call_via_", strlen ("__ARM_call_via_")) == 0)
+ if (startswith (name, "_call_via_")
+ || startswith (name, "__ARM_call_via_"))
{
/* Use the name suffix to determine which register contains the
target PC. */
namelen = strlen (name);
if (name[0] == '_' && name[1] == '_'
&& ((namelen > 2 + strlen ("_from_thumb")
- && strncmp (name + namelen - strlen ("_from_thumb"), "_from_thumb",
- strlen ("_from_thumb")) == 0)
+ && startswith (name + namelen - strlen ("_from_thumb"), "_from_thumb"))
|| (namelen > 2 + strlen ("_from_arm")
- && strncmp (name + namelen - strlen ("_from_arm"), "_from_arm",
- strlen ("_from_arm")) == 0)))
+ && startswith (name + namelen - strlen ("_from_arm"), "_from_arm"))))
{
char *target_name;
int target_len = namelen - 2;
set_fp_model_sfunc (char *args, int from_tty,
struct cmd_list_element *c)
{
- enum arm_float_model fp_model;
+ int fp_model;
for (fp_model = ARM_FLOAT_AUTO; fp_model != ARM_FLOAT_LAST; fp_model++)
if (strcmp (current_fp_model, fp_model_strings[fp_model]) == 0)
{
- arm_fp_model = fp_model;
+ arm_fp_model = (enum arm_float_model) fp_model;
break;
}
arm_set_abi (char *args, int from_tty,
struct cmd_list_element *c)
{
- enum arm_abi_kind arm_abi;
+ int arm_abi;
for (arm_abi = ARM_ABI_AUTO; arm_abi != ARM_ABI_LAST; arm_abi++)
if (strcmp (arm_abi_string, arm_abi_strings[arm_abi]) == 0)
{
- arm_abi_global = arm_abi;
+ arm_abi_global = (enum arm_abi_kind) arm_abi;
break;
}
enum arm_float_model fp_model = arm_fp_model;
struct tdesc_arch_data *tdesc_data = NULL;
int i, is_m = 0;
- int have_vfp_registers = 0, have_vfp_pseudos = 0, have_neon_pseudos = 0;
+ int vfp_register_count = 0, have_vfp_pseudos = 0, have_neon_pseudos = 0;
+ int have_wmmx_registers = 0;
int have_neon = 0;
int have_fpa_registers = 1;
const struct target_desc *tdesc = info.target_desc;
anyway, so assume APCS. */
arm_abi = ARM_ABI_APCS;
}
- else if (ei_osabi == ELFOSABI_NONE)
+ else if (ei_osabi == ELFOSABI_NONE || ei_osabi == ELFOSABI_GNU)
{
int eabi_ver = EF_ARM_EABI_VERSION (e_flags);
int attr_arch, attr_profile;
OBJ_ATTR_PROC,
Tag_ABI_VFP_args))
{
- case 0:
+ case AEABI_VFP_args_base:
/* "The user intended FP parameter/result
passing to conform to AAPCS, base
variant". */
fp_model = ARM_FLOAT_SOFT_VFP;
break;
- case 1:
+ case AEABI_VFP_args_vfp:
/* "The user intended FP parameter/result
passing to conform to AAPCS, VFP
variant". */
fp_model = ARM_FLOAT_VFP;
break;
- case 2:
+ case AEABI_VFP_args_toolchain:
/* "The user intended FP parameter/result
passing to conform to tool chain-specific
conventions" - we don't know any such
conventions, so leave it as "auto". */
break;
+ case AEABI_VFP_args_compatible:
+ /* "Code is compatible with both the base
+ and VFP variants; the user did not permit
+ non-variadic functions to pass FP
+ parameters/results" - leave it as
+ "auto". */
+ break;
default:
/* Attribute value not mentioned in the
- October 2008 ABI, so leave it as
+ November 2012 ABI, so leave it as
"auto". */
break;
}
tdesc_data_cleanup (tdesc_data);
return NULL;
}
+
+ have_wmmx_registers = 1;
}
/* If we have a VFP unit, check whether the single precision registers
if (tdesc_unnumbered_register (feature, "s0") == 0)
have_vfp_pseudos = 1;
- have_vfp_registers = 1;
+ vfp_register_count = i;
/* If we have VFP, also check for NEON. The architecture allows
NEON without VFP (integer vector operations only), but GDB
return best_arch->gdbarch;
}
- tdep = xcalloc (1, sizeof (struct gdbarch_tdep));
+ tdep = XCNEW (struct gdbarch_tdep);
gdbarch = gdbarch_alloc (&info, tdep);
/* Record additional information about the architecture we are defining.
tdep->fp_model = fp_model;
tdep->is_m = is_m;
tdep->have_fpa_registers = have_fpa_registers;
- tdep->have_vfp_registers = have_vfp_registers;
+ tdep->have_wmmx_registers = have_wmmx_registers;
+ gdb_assert (vfp_register_count == 0
+ || vfp_register_count == 16
+ || vfp_register_count == 32);
+ tdep->vfp_register_count = vfp_register_count;
tdep->have_vfp_pseudos = have_vfp_pseudos;
tdep->have_neon_pseudos = have_neon_pseudos;
tdep->have_neon = have_neon;
/* Advance PC across function entry code. */
set_gdbarch_skip_prologue (gdbarch, arm_skip_prologue);
- /* Detect whether PC is in function epilogue. */
- set_gdbarch_in_function_epilogue_p (gdbarch, arm_in_function_epilogue_p);
+ /* Detect whether PC is at a point where the stack has been destroyed. */
+ set_gdbarch_stack_frame_destroyed_p (gdbarch, arm_stack_frame_destroyed_p);
/* Skip trampolines. */
set_gdbarch_skip_trampoline_code (gdbarch, arm_skip_stub);
/* Initialize the array that will be passed to
add_setshow_enum_cmd(). */
- valid_disassembly_styles
- = xmalloc ((num_disassembly_options + 1) * sizeof (char *));
+ valid_disassembly_styles = XNEWVEC (const char *,
+ num_disassembly_options + 1);
for (i = 0; i < num_disassembly_options; i++)
{
numregs = get_arm_regnames (i, &setname, &setdesc, ®names);
#define THUMB2_INSN_SIZE_BYTES 4
+/* Position of the bit within a 32-bit ARM instruction
+ that defines whether the instruction is a load or store. */
#define INSN_S_L_BIT_NUM 20
#define REG_ALLOC(REGS, LENGTH, RECORD_BUF) \
return 0;
}
-/* Handling opcode 010 insns. */
+/* Handle ARM mode instructions with opcode 010. */
static int
arm_record_ld_st_imm_offset (insn_decode_record *arm_insn_r)
{
struct regcache *reg_cache = arm_insn_r->regcache;
- uint32_t reg_src1 = 0 , reg_dest = 0;
- uint32_t offset_12 = 0, tgt_mem_addr = 0;
+ uint32_t reg_base , reg_dest;
+ uint32_t offset_12, tgt_mem_addr;
uint32_t record_buf[8], record_buf_mem[8];
+ unsigned char wback;
+ ULONGEST u_regval;
- ULONGEST u_regval = 0;
+ /* Calculate wback. */
+ wback = (bit (arm_insn_r->arm_insn, 24) == 0)
+ || (bit (arm_insn_r->arm_insn, 21) == 1);
- arm_insn_r->opcode = bits (arm_insn_r->arm_insn, 21, 24);
- arm_insn_r->decode = bits (arm_insn_r->arm_insn, 4, 7);
+ arm_insn_r->reg_rec_count = 0;
+ reg_base = bits (arm_insn_r->arm_insn, 16, 19);
if (bit (arm_insn_r->arm_insn, INSN_S_L_BIT_NUM))
{
+ /* LDR (immediate), LDR (literal), LDRB (immediate), LDRB (literal), LDRBT
+ and LDRT. */
+
reg_dest = bits (arm_insn_r->arm_insn, 12, 15);
- /* LDR insn has a capability to do branching, if
- MOV LR, PC is precedded by LDR insn having Rn as R15
- in that case, it emulates branch and link insn, and hence we
- need to save CSPR and PC as well. */
- if (ARM_PC_REGNUM != reg_dest)
- {
- record_buf[0] = bits (arm_insn_r->arm_insn, 12, 15);
- arm_insn_r->reg_rec_count = 1;
- }
- else
- {
- record_buf[0] = reg_dest;
- record_buf[1] = ARM_PS_REGNUM;
- arm_insn_r->reg_rec_count = 2;
- }
+ record_buf[arm_insn_r->reg_rec_count++] = reg_dest;
+
+ /* The LDR instruction is capable of doing branching. If MOV LR, PC
+ preceeds a LDR instruction having R15 as reg_base, it
+ emulates a branch and link instruction, and hence we need to save
+ CPSR and PC as well. */
+ if (ARM_PC_REGNUM == reg_dest)
+ record_buf[arm_insn_r->reg_rec_count++] = ARM_PS_REGNUM;
+
+ /* If wback is true, also save the base register, which is going to be
+ written to. */
+ if (wback)
+ record_buf[arm_insn_r->reg_rec_count++] = reg_base;
}
else
{
- /* Store, immediate offset, immediate pre-indexed,
- immediate post-indexed. */
- reg_src1 = bits (arm_insn_r->arm_insn, 16, 19);
+ /* STR (immediate), STRB (immediate), STRBT and STRT. */
+
offset_12 = bits (arm_insn_r->arm_insn, 0, 11);
- regcache_raw_read_unsigned (reg_cache, reg_src1, &u_regval);
- /* U == 1 */
+ regcache_raw_read_unsigned (reg_cache, reg_base, &u_regval);
+
+ /* Handle bit U. */
if (bit (arm_insn_r->arm_insn, 23))
- {
- tgt_mem_addr = u_regval + offset_12;
- }
+ {
+ /* U == 1: Add the offset. */
+ tgt_mem_addr = (uint32_t) u_regval + offset_12;
+ }
else
- {
- tgt_mem_addr = u_regval - offset_12;
- }
+ {
+ /* U == 0: subtract the offset. */
+ tgt_mem_addr = (uint32_t) u_regval - offset_12;
+ }
+
+ /* Bit 22 tells us whether the store instruction writes 1 byte or 4
+ bytes. */
+ if (bit (arm_insn_r->arm_insn, 22))
+ {
+ /* STRB and STRBT: 1 byte. */
+ record_buf_mem[0] = 1;
+ }
+ else
+ {
+ /* STR and STRT: 4 bytes. */
+ record_buf_mem[0] = 4;
+ }
+
+ /* Handle bit P. */
+ if (bit (arm_insn_r->arm_insn, 24))
+ record_buf_mem[1] = tgt_mem_addr;
+ else
+ record_buf_mem[1] = (uint32_t) u_regval;
- switch (arm_insn_r->opcode)
- {
- /* STR. */
- case 8:
- case 12:
- /* STR. */
- case 9:
- case 13:
- /* STRT. */
- case 1:
- case 5:
- /* STR. */
- case 4:
- case 0:
- record_buf_mem[0] = 4;
- break;
-
- /* STRB. */
- case 10:
- case 14:
- /* STRB. */
- case 11:
- case 15:
- /* STRBT. */
- case 3:
- case 7:
- /* STRB. */
- case 2:
- case 6:
- record_buf_mem[0] = 1;
- break;
-
- default:
- gdb_assert_not_reached ("no decoding pattern found");
- break;
- }
- record_buf_mem[1] = tgt_mem_addr;
arm_insn_r->mem_rec_count = 1;
- if (9 == arm_insn_r->opcode || 11 == arm_insn_r->opcode
- || 13 == arm_insn_r->opcode || 15 == arm_insn_r->opcode
- || 0 == arm_insn_r->opcode || 2 == arm_insn_r->opcode
- || 4 == arm_insn_r->opcode || 6 == arm_insn_r->opcode
- || 1 == arm_insn_r->opcode || 3 == arm_insn_r->opcode
- || 5 == arm_insn_r->opcode || 7 == arm_insn_r->opcode
- )
- {
- /* We are handling pre-indexed mode; post-indexed mode;
- where Rn is going to be changed. */
- record_buf[0] = reg_src1;
- arm_insn_r->reg_rec_count = 1;
- }
+ /* If wback is true, also save the base register, which is going to be
+ written to. */
+ if (wback)
+ record_buf[arm_insn_r->reg_rec_count++] = reg_base;
}
REG_ALLOC (arm_insn_r->arm_regs, arm_insn_r->reg_rec_count, record_buf);
return 0;
}
-/* Handling opcode 100 insns. */
+/* Handle ARM mode instructions with opcode 100. */
static int
arm_record_ld_st_multiple (insn_decode_record *arm_insn_r)
{
struct regcache *reg_cache = arm_insn_r->regcache;
-
- uint32_t register_list[16] = {0}, register_count = 0, register_bits = 0;
- uint32_t reg_src1 = 0, addr_mode = 0, no_of_regs = 0;
- uint32_t start_address = 0, index = 0;
+ uint32_t register_count = 0, register_bits;
+ uint32_t reg_base, addr_mode;
uint32_t record_buf[24], record_buf_mem[48];
+ uint32_t wback;
+ ULONGEST u_regval;
- ULONGEST u_regval[2] = {0};
+ /* Fetch the list of registers. */
+ register_bits = bits (arm_insn_r->arm_insn, 0, 15);
+ arm_insn_r->reg_rec_count = 0;
- /* This mode is exclusively for load and store multiple. */
- /* Handle incremenrt after/before and decrment after.before mode;
- Rn is changing depending on W bit, but as of now we store Rn too
- without optimization. */
+ /* Fetch the base register that contains the address we are loading data
+ to. */
+ reg_base = bits (arm_insn_r->arm_insn, 16, 19);
+
+ /* Calculate wback. */
+ wback = (bit (arm_insn_r->arm_insn, 21) == 1);
if (bit (arm_insn_r->arm_insn, INSN_S_L_BIT_NUM))
{
- /* LDM (1,2,3) where LDM (3) changes CPSR too. */
+ /* LDM/LDMIA/LDMFD, LDMDA/LDMFA, LDMDB and LDMIB. */
- if (bit (arm_insn_r->arm_insn, 20) && !bit (arm_insn_r->arm_insn, 22))
- {
- register_bits = bits (arm_insn_r->arm_insn, 0, 15);
- no_of_regs = 15;
- }
- else
- {
- register_bits = bits (arm_insn_r->arm_insn, 0, 14);
- no_of_regs = 14;
- }
- /* Get Rn. */
- reg_src1 = bits (arm_insn_r->arm_insn, 16, 19);
+ /* Find out which registers are going to be loaded from memory. */
while (register_bits)
- {
- if (register_bits & 0x00000001)
- record_buf[index++] = register_count;
- register_bits = register_bits >> 1;
- register_count++;
- }
+ {
+ if (register_bits & 0x00000001)
+ record_buf[arm_insn_r->reg_rec_count++] = register_count;
+ register_bits = register_bits >> 1;
+ register_count++;
+ }
+
+
+ /* If wback is true, also save the base register, which is going to be
+ written to. */
+ if (wback)
+ record_buf[arm_insn_r->reg_rec_count++] = reg_base;
- /* Extra space for Base Register and CPSR; wihtout optimization. */
- record_buf[index++] = reg_src1;
- record_buf[index++] = ARM_PS_REGNUM;
- arm_insn_r->reg_rec_count = index;
+ /* Save the CPSR register. */
+ record_buf[arm_insn_r->reg_rec_count++] = ARM_PS_REGNUM;
}
else
{
- /* It handles both STM(1) and STM(2). */
- addr_mode = bits (arm_insn_r->arm_insn, 23, 24);
+ /* STM (STMIA, STMEA), STMDA (STMED), STMDB (STMFD) and STMIB (STMFA). */
- register_bits = bits (arm_insn_r->arm_insn, 0, 15);
- /* Get Rn. */
- reg_src1 = bits (arm_insn_r->arm_insn, 16, 19);
- regcache_raw_read_unsigned (reg_cache, reg_src1, &u_regval[0]);
+ addr_mode = bits (arm_insn_r->arm_insn, 23, 24);
+
+ regcache_raw_read_unsigned (reg_cache, reg_base, &u_regval);
+
+ /* Find out how many registers are going to be stored to memory. */
while (register_bits)
- {
- if (register_bits & 0x00000001)
- register_count++;
- register_bits = register_bits >> 1;
- }
+ {
+ if (register_bits & 0x00000001)
+ register_count++;
+ register_bits = register_bits >> 1;
+ }
switch (addr_mode)
- {
- /* Decrement after. */
- case 0:
- start_address = (u_regval[0]) - (register_count * 4) + 4;
- arm_insn_r->mem_rec_count = register_count;
- while (register_count)
- {
- record_buf_mem[(register_count * 2) - 1] = start_address;
- record_buf_mem[(register_count * 2) - 2] = 4;
- start_address = start_address + 4;
- register_count--;
- }
- break;
-
- /* Increment after. */
- case 1:
- start_address = u_regval[0];
- arm_insn_r->mem_rec_count = register_count;
- while (register_count)
- {
- record_buf_mem[(register_count * 2) - 1] = start_address;
- record_buf_mem[(register_count * 2) - 2] = 4;
- start_address = start_address + 4;
- register_count--;
- }
- break;
-
- /* Decrement before. */
- case 2:
-
- start_address = (u_regval[0]) - (register_count * 4);
- arm_insn_r->mem_rec_count = register_count;
- while (register_count)
- {
- record_buf_mem[(register_count * 2) - 1] = start_address;
- record_buf_mem[(register_count * 2) - 2] = 4;
- start_address = start_address + 4;
- register_count--;
- }
- break;
-
- /* Increment before. */
- case 3:
- start_address = u_regval[0] + 4;
- arm_insn_r->mem_rec_count = register_count;
- while (register_count)
- {
- record_buf_mem[(register_count * 2) - 1] = start_address;
- record_buf_mem[(register_count * 2) - 2] = 4;
- start_address = start_address + 4;
- register_count--;
- }
- break;
-
- default:
- gdb_assert_not_reached ("no decoding pattern found");
- break;
- }
+ {
+ /* STMDA (STMED): Decrement after. */
+ case 0:
+ record_buf_mem[1] = (uint32_t) u_regval
+ - register_count * INT_REGISTER_SIZE + 4;
+ break;
+ /* STM (STMIA, STMEA): Increment after. */
+ case 1:
+ record_buf_mem[1] = (uint32_t) u_regval;
+ break;
+ /* STMDB (STMFD): Decrement before. */
+ case 2:
+ record_buf_mem[1] = (uint32_t) u_regval
+ - register_count * INT_REGISTER_SIZE;
+ break;
+ /* STMIB (STMFA): Increment before. */
+ case 3:
+ record_buf_mem[1] = (uint32_t) u_regval + INT_REGISTER_SIZE;
+ break;
+ default:
+ gdb_assert_not_reached ("no decoding pattern found");
+ break;
+ }
- /* Base register also changes; based on condition and W bit. */
- /* We save it anyway without optimization. */
- record_buf[0] = reg_src1;
- arm_insn_r->reg_rec_count = 1;
+ record_buf_mem[0] = register_count * INT_REGISTER_SIZE;
+ arm_insn_r->mem_rec_count = 1;
+
+ /* If wback is true, also save the base register, which is going to be
+ written to. */
+ if (wback)
+ record_buf[arm_insn_r->reg_rec_count++] = reg_base;
}
REG_ALLOC (arm_insn_r->arm_regs, arm_insn_r->reg_rec_count, record_buf);
return -1;
}
+/* Record handler for vector data transfer instructions. */
+
+static int
+arm_record_vdata_transfer_insn (insn_decode_record *arm_insn_r)
+{
+ uint32_t bits_a, bit_c, bit_l, reg_t, reg_v;
+ uint32_t record_buf[4];
+
+ const int num_regs = gdbarch_num_regs (arm_insn_r->gdbarch);
+ reg_t = bits (arm_insn_r->arm_insn, 12, 15);
+ reg_v = bits (arm_insn_r->arm_insn, 21, 23);
+ bits_a = bits (arm_insn_r->arm_insn, 21, 23);
+ bit_l = bit (arm_insn_r->arm_insn, 20);
+ bit_c = bit (arm_insn_r->arm_insn, 8);
+
+ /* Handle VMOV instruction. */
+ if (bit_l && bit_c)
+ {
+ record_buf[0] = reg_t;
+ arm_insn_r->reg_rec_count = 1;
+ }
+ else if (bit_l && !bit_c)
+ {
+ /* Handle VMOV instruction. */
+ if (bits_a == 0x00)
+ {
+ if (bit (arm_insn_r->arm_insn, 20))
+ record_buf[0] = reg_t;
+ else
+ record_buf[0] = num_regs + (bit (arm_insn_r->arm_insn, 7) |
+ (reg_v << 1));
+
+ arm_insn_r->reg_rec_count = 1;
+ }
+ /* Handle VMRS instruction. */
+ else if (bits_a == 0x07)
+ {
+ if (reg_t == 15)
+ reg_t = ARM_PS_REGNUM;
+
+ record_buf[0] = reg_t;
+ arm_insn_r->reg_rec_count = 1;
+ }
+ }
+ else if (!bit_l && !bit_c)
+ {
+ /* Handle VMOV instruction. */
+ if (bits_a == 0x00)
+ {
+ if (bit (arm_insn_r->arm_insn, 20))
+ record_buf[0] = reg_t;
+ else
+ record_buf[0] = num_regs + (bit (arm_insn_r->arm_insn, 7) |
+ (reg_v << 1));
+
+ arm_insn_r->reg_rec_count = 1;
+ }
+ /* Handle VMSR instruction. */
+ else if (bits_a == 0x07)
+ {
+ record_buf[0] = ARM_FPSCR_REGNUM;
+ arm_insn_r->reg_rec_count = 1;
+ }
+ }
+ else if (!bit_l && bit_c)
+ {
+ /* Handle VMOV instruction. */
+ if (!(bits_a & 0x04))
+ {
+ record_buf[0] = (reg_v | (bit (arm_insn_r->arm_insn, 7) << 4))
+ + ARM_D0_REGNUM;
+ arm_insn_r->reg_rec_count = 1;
+ }
+ /* Handle VDUP instruction. */
+ else
+ {
+ if (bit (arm_insn_r->arm_insn, 21))
+ {
+ reg_v = reg_v | (bit (arm_insn_r->arm_insn, 7) << 4);
+ record_buf[0] = reg_v + ARM_D0_REGNUM;
+ record_buf[1] = reg_v + ARM_D0_REGNUM + 1;
+ arm_insn_r->reg_rec_count = 2;
+ }
+ else
+ {
+ reg_v = reg_v | (bit (arm_insn_r->arm_insn, 7) << 4);
+ record_buf[0] = reg_v + ARM_D0_REGNUM;
+ arm_insn_r->reg_rec_count = 1;
+ }
+ }
+ }
+
+ REG_ALLOC (arm_insn_r->arm_regs, arm_insn_r->reg_rec_count, record_buf);
+ return 0;
+}
+
/* Record handler for extension register load/store instructions. */
static int
/* Advanced SIMD, VFP instructions. */
if (!op1_sbit && op)
- return arm_record_unsupported_insn (arm_insn_r);
+ return arm_record_vdata_transfer_insn (arm_insn_r);
}
else
{
return 1;
insn_record->arm_insn = (uint32_t) extract_unsigned_integer (&buf[0],
insn_size,
- gdbarch_byte_order (insn_record->gdbarch));
+ gdbarch_byte_order_for_code (insn_record->gdbarch));
return 0;
}
{
/* (Starting from numerical 0); bits 25, 26, 27 decodes type of arm instruction. */
- static const sti_arm_hdl_fp_t const arm_handle_insn[8] =
+ static const sti_arm_hdl_fp_t arm_handle_insn[8] =
{
arm_record_data_proc_misc_ld_str, /* 000. */
arm_record_data_proc_imm, /* 001. */
};
/* (Starting from numerical 0); bits 13,14,15 decodes type of thumb instruction. */
- static const sti_arm_hdl_fp_t const thumb_handle_insn[8] =
+ static const sti_arm_hdl_fp_t thumb_handle_insn[8] =
{ \
thumb_record_shift_add_sub, /* 000. */
thumb_record_add_sub_cmp_mov, /* 001. */