/* Common target dependent code for GDB on ARM systems.
- Copyright (C) 1988-2016 Free Software Foundation, Inc.
+ Copyright (C) 1988-2017 Free Software Foundation, Inc.
This file is part of GDB.
#include "gdbcmd.h"
#include "gdbcore.h"
#include "dis-asm.h" /* For register styles. */
+#include "disasm.h"
#include "regcache.h"
#include "reggroups.h"
#include "doublest.h"
#include "record.h"
#include "record-full.h"
-
-#include "features/arm-with-m.c"
-#include "features/arm-with-m-fpa-layout.c"
-#include "features/arm-with-m-vfp-d16.c"
-#include "features/arm-with-iwmmxt.c"
-#include "features/arm-with-vfpv2.c"
-#include "features/arm-with-vfpv3.c"
-#include "features/arm-with-neon.c"
+#include <algorithm>
+
+#include "features/arm/arm-with-m.c"
+#include "features/arm/arm-with-m-fpa-layout.c"
+#include "features/arm/arm-with-m-vfp-d16.c"
+#include "features/arm/arm-with-iwmmxt.c"
+#include "features/arm/arm-with-vfpv2.c"
+#include "features/arm/arm-with-vfpv3.c"
+#include "features/arm/arm-with-neon.c"
+
+#if GDB_SELF_TEST
+#include "selftest.h"
+#endif
static int arm_debug;
static const char *arm_fallback_mode_string = "auto";
static const char *arm_force_mode_string = "auto";
-/* Internal override of the execution mode. -1 means no override,
- 0 means override to ARM mode, 1 means override to Thumb mode.
- The effect is the same as if arm_force_mode has been set by the
- user (except the internal override has precedence over a user's
- arm_force_mode override). */
-static int arm_override_mode = -1;
-
-/* Number of different reg name sets (options). */
-static int num_disassembly_options;
-
/* The standard register names, and all the valid aliases for them. Note
that `fp', `sp' and `pc' are not added in this alias list, because they
have been added as builtin user registers in
"f4", "f5", "f6", "f7", /* 20 21 22 23 */
"fps", "cpsr" }; /* 24 25 */
+/* Holds the current set of options to be passed to the disassembler. */
+static char *arm_disassembler_options;
+
/* Valid register name styles. */
static const char **valid_disassembly_styles;
style. */
static void set_disassembly_style_sfunc(char *, int,
struct cmd_list_element *);
-static void set_disassembly_style (void);
-
-static void convert_from_extended (const struct floatformat *, const void *,
- void *, int);
-static void convert_to_extended (const struct floatformat *, void *,
- const void *, int);
+static void show_disassembly_style_sfunc (struct ui_file *, int,
+ struct cmd_list_element *,
+ const char *);
static enum register_status arm_neon_quad_read (struct gdbarch *gdbarch,
struct regcache *regcache,
int regnum, const gdb_byte *buf);
static CORE_ADDR
- arm_get_next_pcs_syscall_next_pc (struct arm_get_next_pcs *self,
- CORE_ADDR pc);
+ arm_get_next_pcs_syscall_next_pc (struct arm_get_next_pcs *self);
/* get_next_pcs operations. */
arm_get_next_pcs_read_memory_unsigned_integer,
arm_get_next_pcs_syscall_next_pc,
arm_get_next_pcs_addr_bits_remove,
- arm_get_next_pcs_is_thumb
+ arm_get_next_pcs_is_thumb,
+ NULL,
};
struct arm_prologue_cache
if (IS_THUMB_ADDR (memaddr))
return 1;
- /* Respect internal mode override if active. */
- if (arm_override_mode != -1)
- return arm_override_mode;
-
/* If the user wants to override the symbol table, let him. */
if (strcmp (arm_force_mode_string, "arm") == 0)
return 0;
return 0;
}
+/* Determine if the address specified equals any of these magic return
+ values, called EXC_RETURN, defined by the ARM v6-M and v7-M
+ architectures.
+
+ From ARMv6-M Reference Manual B1.5.8
+ Table B1-5 Exception return behavior
+
+ EXC_RETURN Return To Return Stack
+ 0xFFFFFFF1 Handler mode Main
+ 0xFFFFFFF9 Thread mode Main
+ 0xFFFFFFFD Thread mode Process
+
+ From ARMv7-M Reference Manual B1.5.8
+ Table B1-8 EXC_RETURN definition of exception return behavior, no FP
+
+ EXC_RETURN Return To Return Stack
+ 0xFFFFFFF1 Handler mode Main
+ 0xFFFFFFF9 Thread mode Main
+ 0xFFFFFFFD Thread mode Process
+
+ Table B1-9 EXC_RETURN definition of exception return behavior, with
+ FP
+
+ EXC_RETURN Return To Return Stack Frame Type
+ 0xFFFFFFE1 Handler mode Main Extended
+ 0xFFFFFFE9 Thread mode Main Extended
+ 0xFFFFFFED Thread mode Process Extended
+ 0xFFFFFFF1 Handler mode Main Basic
+ 0xFFFFFFF9 Thread mode Main Basic
+ 0xFFFFFFFD Thread mode Process Basic
+
+ For more details see "B1.5.8 Exception return behavior"
+ in both ARMv6-M and ARMv7-M Architecture Reference Manuals. */
+
+static int
+arm_m_addr_is_magic (CORE_ADDR addr)
+{
+ switch (addr)
+ {
+ /* Values from Tables in B1.5.8 the EXC_RETURN definitions of
+ the exception return behavior. */
+ case 0xffffffe1:
+ case 0xffffffe9:
+ case 0xffffffed:
+ case 0xfffffff1:
+ case 0xfffffff9:
+ case 0xfffffffd:
+ /* Address is magic. */
+ return 1;
+
+ default:
+ /* Address is not magic. */
+ return 0;
+ }
+}
+
/* Remove useless bits from addresses in a running program. */
static CORE_ADDR
arm_addr_bits_remove (struct gdbarch *gdbarch, CORE_ADDR val)
/* On M-profile devices, do not strip the low bit from EXC_RETURN
(the magic exception return address). */
if (gdbarch_tdep (gdbarch)->is_m
- && (val & 0xfffffff0) == 0xfffffff0)
+ && arm_m_addr_is_magic (val))
return val;
if (arm_apcs_32)
implementation (this is hand-written ARM assembler in glibc). */
if (!is_thumb
- && read_memory_unsigned_integer (pc, 4, byte_order_for_code)
+ && read_code_unsigned_integer (pc, 4, byte_order_for_code)
== 0xe3e00a0f /* mov r0, #0xffff0fff */
- && read_memory_unsigned_integer (pc + 4, 4, byte_order_for_code)
+ && read_code_unsigned_integer (pc + 4, 4, byte_order_for_code)
== 0xe240f01f) /* sub pc, r0, #31 */
return 1;
}
enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
int i;
pv_t regs[16];
- struct pv_area *stack;
- struct cleanup *back_to;
CORE_ADDR offset;
CORE_ADDR unrecognized_pc = 0;
for (i = 0; i < 16; i++)
regs[i] = pv_register (i, 0);
- stack = make_pv_area (ARM_SP_REGNUM, gdbarch_addr_bit (gdbarch));
- back_to = make_cleanup_free_pv_area (stack);
+ pv_area stack (ARM_SP_REGNUM, gdbarch_addr_bit (gdbarch));
while (start < limit)
{
unsigned short insn;
- insn = read_memory_unsigned_integer (start, 2, byte_order_for_code);
+ insn = read_code_unsigned_integer (start, 2, byte_order_for_code);
if ((insn & 0xfe00) == 0xb400) /* push { rlist } */
{
int regno;
int mask;
- if (pv_area_store_would_trash (stack, regs[ARM_SP_REGNUM]))
+ if (stack.store_would_trash (regs[ARM_SP_REGNUM]))
break;
/* Bits 0-7 contain a mask for registers R0-R7. Bit 8 says
{
regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM],
-4);
- pv_area_store (stack, regs[ARM_SP_REGNUM], 4, regs[regno]);
+ stack.store (regs[ARM_SP_REGNUM], 4, regs[regno]);
}
}
else if ((insn & 0xff80) == 0xb080) /* sub sp, #imm */
offset = (insn & 0xff) << 2;
addr = pv_add_constant (regs[ARM_SP_REGNUM], offset);
- if (pv_area_store_would_trash (stack, addr))
+ if (stack.store_would_trash (addr))
break;
- pv_area_store (stack, addr, 4, regs[regno]);
+ stack.store (addr, 4, regs[regno]);
}
else if ((insn & 0xf800) == 0x6000) /* str rd, [rn, #off] */
{
offset = bits (insn, 6, 10) << 2;
addr = pv_add_constant (regs[rn], offset);
- if (pv_area_store_would_trash (stack, addr))
+ if (stack.store_would_trash (addr))
break;
- pv_area_store (stack, addr, 4, regs[rd]);
+ stack.store (addr, 4, regs[rd]);
}
else if (((insn & 0xf800) == 0x7000 /* strb Rd, [Rn, #off] */
|| (insn & 0xf800) == 0x8000) /* strh Rd, [Rn, #off] */
{
unsigned short inst2;
- inst2 = read_memory_unsigned_integer (start + 2, 2,
- byte_order_for_code);
+ inst2 = read_code_unsigned_integer (start + 2, 2,
+ byte_order_for_code);
if ((insn & 0xf800) == 0xf000 && (inst2 & 0xe800) == 0xe800)
{
pv_t addr = regs[bits (insn, 0, 3)];
int regno;
- if (pv_area_store_would_trash (stack, addr))
+ if (stack.store_would_trash (addr))
break;
/* Calculate offsets of saved registers. */
if (inst2 & (1 << regno))
{
addr = pv_add_constant (addr, -4);
- pv_area_store (stack, addr, 4, regs[regno]);
+ stack.store (addr, 4, regs[regno]);
}
if (insn & 0x0020)
else
addr = pv_add_constant (addr, -offset);
- if (pv_area_store_would_trash (stack, addr))
+ if (stack.store_would_trash (addr))
break;
- pv_area_store (stack, addr, 4, regs[regno1]);
- pv_area_store (stack, pv_add_constant (addr, 4),
- 4, regs[regno2]);
+ stack.store (addr, 4, regs[regno1]);
+ stack.store (pv_add_constant (addr, 4),
+ 4, regs[regno2]);
if (insn & 0x0020)
regs[bits (insn, 0, 3)] = addr;
else
addr = pv_add_constant (addr, -offset);
- if (pv_area_store_would_trash (stack, addr))
+ if (stack.store_would_trash (addr))
break;
- pv_area_store (stack, addr, 4, regs[regno]);
+ stack.store (addr, 4, regs[regno]);
if (inst2 & 0x0100)
regs[bits (insn, 0, 3)] = addr;
offset = inst2 & 0xfff;
addr = pv_add_constant (regs[bits (insn, 0, 3)], offset);
- if (pv_area_store_would_trash (stack, addr))
+ if (stack.store_would_trash (addr))
break;
- pv_area_store (stack, addr, 4, regs[regno]);
+ stack.store (addr, 4, regs[regno]);
}
else if ((insn & 0xffd0) == 0xf880 /* str{bh}.w Rt,[Rn,#imm] */
unrecognized_pc = start;
if (cache == NULL)
- {
- do_cleanups (back_to);
- return unrecognized_pc;
- }
+ return unrecognized_pc;
if (pv_is_register (regs[ARM_FP_REGNUM], ARM_SP_REGNUM))
{
}
for (i = 0; i < 16; i++)
- if (pv_area_find_reg (stack, gdbarch, i, &offset))
+ if (stack.find_reg (gdbarch, i, &offset))
cache->saved_regs[i].addr = offset;
- do_cleanups (back_to);
return unrecognized_pc;
}
if (is_thumb)
{
unsigned short insn1
- = read_memory_unsigned_integer (pc, 2, byte_order_for_code);
+ = read_code_unsigned_integer (pc, 2, byte_order_for_code);
if ((insn1 & 0xf800) == 0x4800) /* ldr Rd, #immed */
{
else if ((insn1 & 0xfbf0) == 0xf240) /* movw Rd, #const */
{
unsigned short insn2
- = read_memory_unsigned_integer (pc + 2, 2, byte_order_for_code);
+ = read_code_unsigned_integer (pc + 2, 2, byte_order_for_code);
low = EXTRACT_MOVW_MOVT_IMM_T (insn1, insn2);
insn1
- = read_memory_unsigned_integer (pc + 4, 2, byte_order_for_code);
+ = read_code_unsigned_integer (pc + 4, 2, byte_order_for_code);
insn2
- = read_memory_unsigned_integer (pc + 6, 2, byte_order_for_code);
+ = read_code_unsigned_integer (pc + 6, 2, byte_order_for_code);
/* movt Rd, #const */
if ((insn1 & 0xfbc0) == 0xf2c0)
else
{
unsigned int insn
- = read_memory_unsigned_integer (pc, 4, byte_order_for_code);
+ = read_code_unsigned_integer (pc, 4, byte_order_for_code);
if ((insn & 0x0e5f0000) == 0x041f0000) /* ldr Rd, [PC, #immed] */
{
low = EXTRACT_MOVW_MOVT_IMM_A (insn);
insn
- = read_memory_unsigned_integer (pc + 4, 4, byte_order_for_code);
+ = read_code_unsigned_integer (pc + 4, 4, byte_order_for_code);
if ((insn & 0x0ff00000) == 0x03400000) /* movt Rd, #const */
{
{
unsigned int destreg;
unsigned short insn
- = read_memory_unsigned_integer (pc + offset, 2, byte_order_for_code);
+ = read_code_unsigned_integer (pc + offset, 2, byte_order_for_code);
/* Step 2: ldr Rd, [Rn, #immed], encoding T1. */
if ((insn & 0xf800) != 0x6800)
return pc;
destreg = bits (insn, 0, 2);
- insn = read_memory_unsigned_integer (pc + offset + 2, 2,
- byte_order_for_code);
+ insn = read_code_unsigned_integer (pc + offset + 2, 2,
+ byte_order_for_code);
/* Step 3: str Rd, [Rn, #immed], encoding T1. */
if ((insn & 0xf800) != 0x6000)
return pc;
{
unsigned int destreg;
unsigned int insn
- = read_memory_unsigned_integer (pc + offset, 4, byte_order_for_code);
+ = read_code_unsigned_integer (pc + offset, 4, byte_order_for_code);
/* Step 2: ldr Rd, [Rn, #immed], encoding A1. */
if ((insn & 0x0e500000) != 0x04100000)
return pc;
destreg = bits (insn, 12, 15);
/* Step 3: str Rd, [Rn, #immed], encoding A1. */
- insn = read_memory_unsigned_integer (pc + offset + 4,
+ insn = read_code_unsigned_integer (pc + offset + 4,
4, byte_order_for_code);
if ((insn & 0x0e500000) != 0x04000000)
return pc;
static CORE_ADDR
arm_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
{
- enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
- unsigned long inst;
CORE_ADDR func_addr, limit_pc;
/* See if we can determine the end of the prologue via the symbol table.
function is. */
return;
- prologue_end = min (prologue_end, prev_pc);
+ prologue_end = std::min (prologue_end, prev_pc);
thumb_analyze_prologue (gdbarch, prologue_start, prologue_end, cache);
}
CORE_ADDR prologue_start, CORE_ADDR prologue_end,
struct arm_prologue_cache *cache)
{
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
int regno;
CORE_ADDR offset, current_pc;
pv_t regs[ARM_FPS_REGNUM];
- struct pv_area *stack;
- struct cleanup *back_to;
CORE_ADDR unrecognized_pc = 0;
/* Search the prologue looking for instructions that set up the
for (regno = 0; regno < ARM_FPS_REGNUM; regno++)
regs[regno] = pv_register (regno, 0);
- stack = make_pv_area (ARM_SP_REGNUM, gdbarch_addr_bit (gdbarch));
- back_to = make_cleanup_free_pv_area (stack);
+ pv_area stack (ARM_SP_REGNUM, gdbarch_addr_bit (gdbarch));
for (current_pc = prologue_start;
current_pc < prologue_end;
current_pc += 4)
{
unsigned int insn
- = read_memory_unsigned_integer (current_pc, 4, byte_order_for_code);
+ = read_code_unsigned_integer (current_pc, 4, byte_order_for_code);
if (insn == 0xe1a0c00d) /* mov ip, sp */
{
else if ((insn & 0xffff0fff) == 0xe52d0004) /* str Rd,
[sp, #-4]! */
{
- if (pv_area_store_would_trash (stack, regs[ARM_SP_REGNUM]))
+ if (stack.store_would_trash (regs[ARM_SP_REGNUM]))
break;
regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM], -4);
- pv_area_store (stack, regs[ARM_SP_REGNUM], 4,
- regs[bits (insn, 12, 15)]);
+ stack.store (regs[ARM_SP_REGNUM], 4,
+ regs[bits (insn, 12, 15)]);
continue;
}
else if ((insn & 0xffff0000) == 0xe92d0000)
{
int mask = insn & 0xffff;
- if (pv_area_store_would_trash (stack, regs[ARM_SP_REGNUM]))
+ if (stack.store_would_trash (regs[ARM_SP_REGNUM]))
break;
/* Calculate offsets of saved registers. */
{
regs[ARM_SP_REGNUM]
= pv_add_constant (regs[ARM_SP_REGNUM], -4);
- pv_area_store (stack, regs[ARM_SP_REGNUM], 4, regs[regno]);
+ stack.store (regs[ARM_SP_REGNUM], 4, regs[regno]);
}
}
else if ((insn & 0xffff0000) == 0xe54b0000 /* strb rx,[r11,#-n] */
[sp, -#c]! */
&& gdbarch_tdep (gdbarch)->have_fpa_registers)
{
- if (pv_area_store_would_trash (stack, regs[ARM_SP_REGNUM]))
+ if (stack.store_would_trash (regs[ARM_SP_REGNUM]))
break;
regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM], -12);
regno = ARM_F0_REGNUM + ((insn >> 12) & 0x07);
- pv_area_store (stack, regs[ARM_SP_REGNUM], 12, regs[regno]);
+ stack.store (regs[ARM_SP_REGNUM], 12, regs[regno]);
}
else if ((insn & 0xffbf0fff) == 0xec2d0200 /* sfmfd f0, 4,
[sp!] */
int n_saved_fp_regs;
unsigned int fp_start_reg, fp_bound_reg;
- if (pv_area_store_would_trash (stack, regs[ARM_SP_REGNUM]))
+ if (stack.store_would_trash (regs[ARM_SP_REGNUM]))
break;
if ((insn & 0x800) == 0x800) /* N0 is set */
for (; fp_start_reg < fp_bound_reg; fp_start_reg++)
{
regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM], -12);
- pv_area_store (stack, regs[ARM_SP_REGNUM], 12,
- regs[fp_start_reg++]);
+ stack.store (regs[ARM_SP_REGNUM], 12,
+ regs[fp_start_reg++]);
}
}
else if ((insn & 0xff000000) == 0xeb000000 && cache == NULL) /* bl */
cache->framesize = framesize;
for (regno = 0; regno < ARM_FPS_REGNUM; regno++)
- if (pv_area_find_reg (stack, gdbarch, regno, &offset))
+ if (stack.find_reg (gdbarch, regno, &offset))
cache->saved_regs[regno].addr = offset;
}
fprintf_unfiltered (gdb_stdlog, "Prologue scan stopped at %s\n",
paddress (gdbarch, unrecognized_pc));
- do_cleanups (back_to);
return unrecognized_pc;
}
{
struct gdbarch *gdbarch = get_frame_arch (this_frame);
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- int regno;
- CORE_ADDR prologue_start, prologue_end, current_pc;
+ CORE_ADDR prologue_start, prologue_end;
CORE_ADDR prev_pc = get_frame_pc (this_frame);
CORE_ADDR block_addr = get_frame_address_in_block (this_frame);
- pv_t regs[ARM_FPS_REGNUM];
- struct pv_area *stack;
- struct cleanup *back_to;
- CORE_ADDR offset;
/* Assume there is no frame until proven otherwise. */
cache->framereg = ARM_SP_REGNUM;
the callee (or at the present moment if this is the innermost frame).
The value stored there should be the address of the stmfd + 8. */
CORE_ADDR frame_loc;
- LONGEST return_value;
+ ULONGEST return_value;
frame_loc = get_frame_register_unsigned (this_frame, ARM_FP_REGNUM);
- if (!safe_read_memory_integer (frame_loc, 4, byte_order, &return_value))
+ if (!safe_read_memory_unsigned_integer (frame_loc, 4, byte_order,
+ &return_value))
return;
else
{
ensure this, so that e.g. pthread cancellation works. */
if (arm_frame_is_thumb (this_frame))
{
- LONGEST insn;
+ ULONGEST insn;
- if (safe_read_memory_integer (get_frame_pc (this_frame) - 2, 2,
- byte_order_for_code, &insn)
+ if (safe_read_memory_unsigned_integer (get_frame_pc (this_frame) - 2,
+ 2, byte_order_for_code, &insn)
&& (insn & 0xff00) == 0xdf00 /* svc */)
exc_valid = 1;
}
else
{
- LONGEST insn;
+ ULONGEST insn;
- if (safe_read_memory_integer (get_frame_pc (this_frame) - 4, 4,
- byte_order_for_code, &insn)
+ if (safe_read_memory_unsigned_integer (get_frame_pc (this_frame) - 4,
+ 4, byte_order_for_code, &insn)
&& (insn & 0x0f000000) == 0x0f000000 /* svc */)
exc_valid = 1;
}
arm_exidx_unwind_sniffer
};
+static struct arm_prologue_cache *
+arm_make_epilogue_frame_cache (struct frame_info *this_frame)
+{
+ struct arm_prologue_cache *cache;
+ int reg;
+
+ cache = FRAME_OBSTACK_ZALLOC (struct arm_prologue_cache);
+ cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
+
+ /* Still rely on the offset calculated from prologue. */
+ arm_scan_prologue (this_frame, cache);
+
+ /* Since we are in epilogue, the SP has been restored. */
+ cache->prev_sp = get_frame_register_unsigned (this_frame, ARM_SP_REGNUM);
+
+ /* Calculate actual addresses of saved registers using offsets
+ determined by arm_scan_prologue. */
+ for (reg = 0; reg < gdbarch_num_regs (get_frame_arch (this_frame)); reg++)
+ if (trad_frame_addr_p (cache->saved_regs, reg))
+ cache->saved_regs[reg].addr += cache->prev_sp;
+
+ return cache;
+}
+
+/* Implementation of function hook 'this_id' in
+ 'struct frame_uwnind' for epilogue unwinder. */
+
+static void
+arm_epilogue_frame_this_id (struct frame_info *this_frame,
+ void **this_cache,
+ struct frame_id *this_id)
+{
+ struct arm_prologue_cache *cache;
+ CORE_ADDR pc, func;
+
+ if (*this_cache == NULL)
+ *this_cache = arm_make_epilogue_frame_cache (this_frame);
+ cache = (struct arm_prologue_cache *) *this_cache;
+
+ /* 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 == 0)
+ func = pc;
+
+ (*this_id) = frame_id_build (cache->prev_sp, pc);
+}
+
+/* Implementation of function hook 'prev_register' in
+ 'struct frame_uwnind' for epilogue unwinder. */
+
+static struct value *
+arm_epilogue_frame_prev_register (struct frame_info *this_frame,
+ void **this_cache, int regnum)
+{
+ if (*this_cache == NULL)
+ *this_cache = arm_make_epilogue_frame_cache (this_frame);
+
+ return arm_prologue_prev_register (this_frame, this_cache, regnum);
+}
+
+static int arm_stack_frame_destroyed_p_1 (struct gdbarch *gdbarch,
+ CORE_ADDR pc);
+static int thumb_stack_frame_destroyed_p (struct gdbarch *gdbarch,
+ CORE_ADDR pc);
+
+/* Implementation of function hook 'sniffer' in
+ 'struct frame_uwnind' for epilogue unwinder. */
+
+static int
+arm_epilogue_frame_sniffer (const struct frame_unwind *self,
+ struct frame_info *this_frame,
+ void **this_prologue_cache)
+{
+ if (frame_relative_level (this_frame) == 0)
+ {
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ CORE_ADDR pc = get_frame_pc (this_frame);
+
+ if (arm_frame_is_thumb (this_frame))
+ return thumb_stack_frame_destroyed_p (gdbarch, pc);
+ else
+ return arm_stack_frame_destroyed_p_1 (gdbarch, pc);
+ }
+ else
+ return 0;
+}
+
+/* Frame unwinder from epilogue. */
+
+static const struct frame_unwind arm_epilogue_frame_unwind =
+{
+ NORMAL_FRAME,
+ default_frame_unwind_stop_reason,
+ arm_epilogue_frame_this_id,
+ arm_epilogue_frame_prev_register,
+ NULL,
+ arm_epilogue_frame_sniffer,
+};
+
/* Recognize GCC's trampoline for thumb call-indirect. If we are in a
trampoline, return the target PC. Otherwise return 0.
void **this_cache,
int prev_regnum)
{
- struct gdbarch *gdbarch = get_frame_arch (this_frame);
struct arm_prologue_cache *cache;
if (*this_cache == NULL)
/* No need to check is_m; this sniffer is only registered for
M-profile architectures. */
- /* Exception frames return to one of these magic PCs. Other values
- are not defined as of v7-M. See details in "B1.5.8 Exception
- return behavior" in "ARMv7-M Architecture Reference Manual". */
- if (this_pc == 0xfffffff1 || this_pc == 0xfffffff9
- || this_pc == 0xfffffffd)
- return 1;
-
- return 0;
+ /* Check if exception frame returns to a magic PC value. */
+ return arm_m_addr_is_magic (this_pc);
}
/* Frame unwinder for M-profile exceptions. */
return found_stack_adjust;
}
-/* Implement the stack_frame_destroyed_p gdbarch method. */
-
static int
-arm_stack_frame_destroyed_p (struct gdbarch *gdbarch, CORE_ADDR pc)
+arm_stack_frame_destroyed_p_1 (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;
CORE_ADDR func_start, func_end;
- if (arm_pc_is_thumb (gdbarch, pc))
- return thumb_stack_frame_destroyed_p (gdbarch, pc);
-
if (!find_pc_partial_function (pc, NULL, &func_start, &func_end))
return 0;
return 0;
}
+/* Implement the stack_frame_destroyed_p gdbarch method. */
+
+static int
+arm_stack_frame_destroyed_p (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+ if (arm_pc_is_thumb (gdbarch, pc))
+ return thumb_stack_frame_destroyed_p (gdbarch, pc);
+ else
+ return arm_stack_frame_destroyed_p_1 (gdbarch, pc);
+}
/* When arguments must be pushed onto the stack, they go on in reverse
order. The code below implements a FILO (stack) to do this. */
case TYPE_CODE_SET:
case TYPE_CODE_RANGE:
case TYPE_CODE_REF:
+ case TYPE_CODE_RVALUE_REF:
case TYPE_CODE_CHAR:
case TYPE_CODE_BOOL:
return TYPE_LENGTH (t);
int i;
for (i = 0; i < TYPE_NFIELDS (t); i++)
{
- int sub_count = arm_vfp_cprc_sub_candidate (TYPE_FIELD_TYPE (t, i),
- base_type);
+ int sub_count = 0;
+
+ if (!field_is_static (&TYPE_FIELD (t, i)))
+ sub_count = arm_vfp_cprc_sub_candidate (TYPE_FIELD_TYPE (t, i),
+ base_type);
if (sub_count == -1)
return -1;
count += sub_count;
internal_error (__FILE__, __LINE__, _("Bad REGNUM %d"), regnum);
}
-/* NOTE: cagney/2001-08-20: Both convert_from_extended() and
- convert_to_extended() use floatformat_arm_ext_littlebyte_bigword.
- It is thought that this is is the floating-point register format on
- little-endian systems. */
-
-static void
-convert_from_extended (const struct floatformat *fmt, const void *ptr,
- void *dbl, int endianess)
-{
- DOUBLEST d;
-
- if (endianess == BFD_ENDIAN_BIG)
- floatformat_to_doublest (&floatformat_arm_ext_big, ptr, &d);
- else
- floatformat_to_doublest (&floatformat_arm_ext_littlebyte_bigword,
- ptr, &d);
- floatformat_from_doublest (fmt, &d, dbl);
-}
-
-static void
-convert_to_extended (const struct floatformat *fmt, void *dbl, const void *ptr,
- int endianess)
-{
- DOUBLEST d;
-
- floatformat_to_doublest (fmt, ptr, &d);
- if (endianess == BFD_ENDIAN_BIG)
- floatformat_from_doublest (&floatformat_arm_ext_big, &d, dbl);
- else
- floatformat_from_doublest (&floatformat_arm_ext_littlebyte_bigword,
- &d, dbl);
-}
-
-/* Like insert_single_step_breakpoint, but make sure we use a breakpoint
- of the appropriate mode (as encoded in the PC value), even if this
- differs from what would be expected according to the symbol tables. */
-
-void
-arm_insert_single_step_breakpoint (struct gdbarch *gdbarch,
- struct address_space *aspace,
- CORE_ADDR pc)
-{
- struct cleanup *old_chain
- = make_cleanup_restore_integer (&arm_override_mode);
-
- arm_override_mode = IS_THUMB_ADDR (pc);
- pc = gdbarch_addr_bits_remove (gdbarch, pc);
-
- insert_single_step_breakpoint (gdbarch, aspace, pc);
-
- do_cleanups (old_chain);
-}
-
/* Given BUF, which is OLD_LEN bytes ending at ENDADDR, expand
the buffer to be NEW_LEN bytes ending at ENDADDR. Return
NULL if an error occurs. BUF is freed. */
new_buf = (gdb_byte *) xmalloc (new_len);
memcpy (new_buf + bytes_to_read, buf, old_len);
xfree (buf);
- if (target_read_memory (endaddr - new_len, new_buf, bytes_to_read) != 0)
+ if (target_read_code (endaddr - new_len, new_buf, bytes_to_read) != 0)
{
xfree (new_buf);
return NULL;
footwork to distinguish a real IT instruction from the second
half of a 32-bit instruction, but there is no need for that if
there's no candidate. */
- buf_len = min (bpaddr - boundary, MAX_IT_BLOCK_PREFIX);
+ buf_len = std::min (bpaddr - boundary, (CORE_ADDR) MAX_IT_BLOCK_PREFIX);
if (buf_len == 0)
/* No room for an IT instruction. */
return bpaddr;
buf = (gdb_byte *) xmalloc (buf_len);
- if (target_read_memory (bpaddr - buf_len, buf, buf_len) != 0)
+ if (target_read_code (bpaddr - buf_len, buf, buf_len) != 0)
return bpaddr;
any = 0;
for (i = 0; i < buf_len; i += 2)
Generally ARM displaced stepping works as follows:
1. When an instruction is to be single-stepped, it is first decoded by
- arm_process_displaced_insn (called from arm_displaced_step_copy_insn).
- Depending on the type of instruction, it is then copied to a scratch
- location, possibly in a modified form. The copy_* set of functions
- performs such modification, as necessary. A breakpoint is placed after
- the modified instruction in the scratch space to return control to GDB.
- Note in particular that instructions which modify the PC will no longer
- do so after modification.
+ arm_process_displaced_insn. Depending on the type of instruction, it is
+ then copied to a scratch location, possibly in a modified form. The
+ copy_* set of functions performs such modification, as necessary. A
+ breakpoint is placed after the modified instruction in the scratch space
+ to return control to GDB. Note in particular that instructions which
+ modify the PC will no longer do so after modification.
2. The instruction is single-stepped, by setting the PC to the scratch
location address, and resuming. Control returns to GDB when the
contiguous chunk r0...rX before doing the transfer, then shuffling
registers into the correct places in the cleanup routine. */
unsigned int regmask = insn & 0xffff;
- unsigned int num_in_list = bitcount (regmask), new_regmask, bit = 1;
- unsigned int to = 0, from = 0, i, new_rn;
+ unsigned int num_in_list = bitcount (regmask), new_regmask;
+ unsigned int i;
for (i = 0; i < num_in_list; i++)
dsc->tmp[i] = displaced_read_reg (regs, dsc, i);
else
{
unsigned int regmask = dsc->u.block.regmask;
- unsigned int num_in_list = bitcount (regmask), new_regmask, bit = 1;
- unsigned int to = 0, from = 0, i, new_rn;
+ unsigned int num_in_list = bitcount (regmask), new_regmask;
+ unsigned int i;
for (i = 0; i < num_in_list; i++)
dsc->tmp[i] = displaced_read_reg (regs, dsc, i);
/* Wrapper over syscall_next_pc for use in get_next_pcs. */
static CORE_ADDR
-arm_get_next_pcs_syscall_next_pc (struct arm_get_next_pcs *self,
- CORE_ADDR pc)
+arm_get_next_pcs_syscall_next_pc (struct arm_get_next_pcs *self)
{
return 0;
}
single-step support. We find the target of the coming instructions
and breakpoint them. */
-int
-arm_software_single_step (struct frame_info *frame)
+std::vector<CORE_ADDR>
+arm_software_single_step (struct regcache *regcache)
{
- struct regcache *regcache = get_current_regcache ();
struct gdbarch *gdbarch = get_regcache_arch (regcache);
- struct address_space *aspace = get_regcache_aspace (regcache);
struct arm_get_next_pcs next_pcs_ctx;
- CORE_ADDR pc;
- int i;
- VEC (CORE_ADDR) *next_pcs = NULL;
- struct cleanup *old_chain = make_cleanup (VEC_cleanup (CORE_ADDR), &next_pcs);
arm_get_next_pcs_ctor (&next_pcs_ctx,
&arm_get_next_pcs_ops,
0,
regcache);
- next_pcs = arm_get_next_pcs (&next_pcs_ctx);
-
- for (i = 0; VEC_iterate (CORE_ADDR, next_pcs, i, pc); i++)
- arm_insert_single_step_breakpoint (gdbarch, aspace, pc);
+ std::vector<CORE_ADDR> next_pcs = arm_get_next_pcs (&next_pcs_ctx);
- do_cleanups (old_chain);
+ for (CORE_ADDR &pc_ref : next_pcs)
+ pc_ref = gdbarch_addr_bits_remove (gdbarch, pc_ref);
- return 1;
+ return next_pcs;
}
/* Cleanup/copy SVC (SWI) instructions. These two functions are overridden
unsigned int op1 = bits (insn, 20, 26), op2 = bits (insn, 4, 7);
unsigned int rn = bits (insn, 16, 19);
- if (op1 == 0x10 && (op2 & 0x2) == 0x0 && (rn & 0xe) == 0x0)
+ if (op1 == 0x10 && (op2 & 0x2) == 0x0 && (rn & 0x1) == 0x0)
return arm_copy_unmodified (gdbarch, insn, "cps", dsc);
- else if (op1 == 0x10 && op2 == 0x0 && (rn & 0xe) == 0x1)
+ else if (op1 == 0x10 && op2 == 0x0 && (rn & 0x1) == 0x1)
return arm_copy_unmodified (gdbarch, insn, "setend", dsc);
else if ((op1 & 0x60) == 0x20)
return arm_copy_unmodified (gdbarch, insn, "neon dataproc", dsc);
{
unsigned int op2 = bits (insn, 4, 6);
unsigned int op = bits (insn, 21, 22);
- unsigned int op1 = bits (insn, 16, 19);
switch (op2)
{
{
int a = bit (insn, 25), b = bit (insn, 4);
uint32_t op1 = bits (insn, 20, 24);
- int rn_f = bits (insn, 16, 19) == 0xf;
if ((!a && (op1 & 0x05) == 0x00 && (op1 & 0x17) != 0x02)
|| (a && (op1 & 0x05) == 0x00 && (op1 & 0x17) != 0x02 && !b))
}
static int
-arm_decode_svc_copro (struct gdbarch *gdbarch, uint32_t insn, CORE_ADDR to,
+arm_decode_svc_copro (struct gdbarch *gdbarch, uint32_t insn,
struct regcache *regs, struct displaced_step_closure *dsc)
{
unsigned int op1 = bits (insn, 20, 25);
int op = bit (insn, 4);
unsigned int coproc = bits (insn, 8, 11);
- unsigned int rn = bits (insn, 16, 19);
if ((op1 & 0x20) == 0x00 && (op1 & 0x3a) != 0x00 && (coproc & 0xe) == 0xa)
return arm_decode_ext_reg_ld_st (gdbarch, insn, regs, dsc);
struct displaced_step_closure *dsc)
{
unsigned int coproc = bits (insn2, 8, 11);
- unsigned int op1 = bits (insn1, 4, 9);
unsigned int bit_5_8 = bits (insn1, 5, 8);
unsigned int bit_9 = bit (insn1, 9);
unsigned int bit_4 = bit (insn1, 4);
- unsigned int rn = bits (insn1, 0, 3);
if (bit_9 == 0)
{
unsigned int rt = bits (insn1, 8, 10);
unsigned int pc;
int imm8 = (bits (insn1, 0, 7) << 2);
- CORE_ADDR from = dsc->insn_addr;
/* LDR Rd, #imm8
else
{
unsigned int num_in_list = bitcount (dsc->u.block.regmask);
- unsigned int new_regmask, bit = 1;
- unsigned int to = 0, from = 0, i, new_rn;
+ unsigned int i;
+ unsigned int new_regmask;
for (i = 0; i < num_in_list + 1; i++)
dsc->tmp[i] = displaced_read_reg (regs, dsc, i);
int rt = bits (insn2, 12, 15);
int rn = bits (insn1, 0, 3);
int op1 = bits (insn1, 7, 8);
- int err = 0;
switch (bits (insn1, 5, 6))
{
static void
thumb_process_displaced_insn (struct gdbarch *gdbarch, CORE_ADDR from,
- CORE_ADDR to, struct regcache *regs,
+ struct regcache *regs,
struct displaced_step_closure *dsc)
{
enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
dsc->wrote_to_pc = 0;
if (!displaced_in_arm_mode (regs))
- return thumb_process_displaced_insn (gdbarch, from, to, regs, dsc);
+ return thumb_process_displaced_insn (gdbarch, from, regs, dsc);
dsc->is_thumb = 0;
dsc->insn_size = 4;
break;
case 0xc: case 0xd: case 0xe: case 0xf:
- err = arm_decode_svc_copro (gdbarch, insn, to, regs, dsc);
+ err = arm_decode_svc_copro (gdbarch, insn, regs, dsc);
break;
}
paddress (gdbarch, from), paddress (gdbarch, to));
}
-/* Entry point for copying an instruction into scratch space for displaced
- stepping. */
-
-struct displaced_step_closure *
-arm_displaced_step_copy_insn (struct gdbarch *gdbarch,
- CORE_ADDR from, CORE_ADDR to,
- struct regcache *regs)
-{
- 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);
-
- return dsc;
-}
-
/* Entry point for cleaning things up after a displaced instruction has been
single-stepped. */
static int
gdb_print_insn_arm (bfd_vma memaddr, disassemble_info *info)
{
- struct gdbarch *gdbarch = (struct gdbarch *) info->application_data;
+ gdb_disassembler *di
+ = static_cast<gdb_disassembler *>(info->application_data);
+ struct gdbarch *gdbarch = di->arch ();
if (arm_pc_is_thumb (gdbarch, memaddr))
{
else
info->symbols = NULL;
- if (info->endian == BFD_ENDIAN_BIG)
- return print_insn_big_arm (memaddr, info);
- else
- return print_insn_little_arm (memaddr, info);
+ /* GDB is able to get bfd_mach from the exe_bfd, info->mach is
+ accurate, so mark USER_SPECIFIED_MACHINE_TYPE bit. Otherwise,
+ opcodes/arm-dis.c:print_insn reset info->mach, and it will trigger
+ the assert on the mismatch of info->mach and bfd_get_mach (exec_bfd)
+ in default_print_insn. */
+ if (exec_bfd != NULL)
+ info->flags |= USER_SPECIFIED_MACHINE_TYPE;
+
+ return default_print_insn (memaddr, info);
}
/* The following define instruction sequences that will cause ARM
static const gdb_byte arm_default_thumb_le_breakpoint[] = THUMB_LE_BREAKPOINT;
static const gdb_byte arm_default_thumb_be_breakpoint[] = THUMB_BE_BREAKPOINT;
-/* Determine the type and size of breakpoint to insert at PCPTR. Uses
- the program counter value to determine whether a 16-bit or 32-bit
- breakpoint should be used. It returns a pointer to a string of
- bytes that encode a breakpoint instruction, stores the length of
- the string to *lenptr, and adjusts the program counter (if
- necessary) to point to the actual memory location where the
- breakpoint should be inserted. */
+/* Implement the breakpoint_kind_from_pc gdbarch method. */
-static const unsigned char *
-arm_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr, int *lenptr)
+static int
+arm_breakpoint_kind_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
if (tdep->thumb2_breakpoint != NULL)
{
gdb_byte buf[2];
+
if (target_read_memory (*pcptr, buf, 2) == 0)
{
unsigned short inst1;
+
inst1 = extract_unsigned_integer (buf, 2, byte_order_for_code);
if (thumb_insn_size (inst1) == 4)
- {
- *lenptr = tdep->thumb2_breakpoint_size;
- return tdep->thumb2_breakpoint;
- }
+ return ARM_BP_KIND_THUMB2;
}
}
- *lenptr = tdep->thumb_breakpoint_size;
- return tdep->thumb_breakpoint;
+ return ARM_BP_KIND_THUMB;
}
else
+ return ARM_BP_KIND_ARM;
+
+}
+
+/* Implement the sw_breakpoint_from_kind gdbarch method. */
+
+static const gdb_byte *
+arm_sw_breakpoint_from_kind (struct gdbarch *gdbarch, int kind, int *size)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ switch (kind)
{
- *lenptr = tdep->arm_breakpoint_size;
+ case ARM_BP_KIND_ARM:
+ *size = tdep->arm_breakpoint_size;
return tdep->arm_breakpoint;
+ case ARM_BP_KIND_THUMB:
+ *size = tdep->thumb_breakpoint_size;
+ return tdep->thumb_breakpoint;
+ case ARM_BP_KIND_THUMB2:
+ *size = tdep->thumb2_breakpoint_size;
+ return tdep->thumb2_breakpoint;
+ default:
+ gdb_assert_not_reached ("unexpected arm breakpoint kind");
}
}
-static void
-arm_remote_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr,
- int *kindptr)
+/* Implement the breakpoint_kind_from_current_state gdbarch method. */
+
+static int
+arm_breakpoint_kind_from_current_state (struct gdbarch *gdbarch,
+ struct regcache *regcache,
+ CORE_ADDR *pcptr)
{
- arm_breakpoint_from_pc (gdbarch, pcptr, kindptr);
+ gdb_byte buf[4];
+
+ /* Check the memory pointed by PC is readable. */
+ if (target_read_memory (regcache_read_pc (regcache), buf, 4) == 0)
+ {
+ struct arm_get_next_pcs next_pcs_ctx;
+
+ arm_get_next_pcs_ctor (&next_pcs_ctx,
+ &arm_get_next_pcs_ops,
+ gdbarch_byte_order (gdbarch),
+ gdbarch_byte_order_for_code (gdbarch),
+ 0,
+ regcache);
+
+ std::vector<CORE_ADDR> next_pcs = arm_get_next_pcs (&next_pcs_ctx);
+
+ /* If MEMADDR is the next instruction of current pc, do the
+ software single step computation, and get the thumb mode by
+ the destination address. */
+ for (CORE_ADDR pc : next_pcs)
+ {
+ if (UNMAKE_THUMB_ADDR (pc) == *pcptr)
+ {
+ if (IS_THUMB_ADDR (pc))
+ {
+ *pcptr = MAKE_THUMB_ADDR (*pcptr);
+ return arm_breakpoint_kind_from_pc (gdbarch, pcptr);
+ }
+ else
+ return ARM_BP_KIND_ARM;
+ }
+ }
+ }
- if (arm_pc_is_thumb (gdbarch, *pcptr) && *kindptr == 4)
- /* The documented magic value for a 32-bit Thumb-2 breakpoint, so
- that this is not confused with a 32-bit ARM breakpoint. */
- *kindptr = 3;
+ return arm_breakpoint_kind_from_pc (gdbarch, pcptr);
}
/* Extract from an array REGBUF containing the (raw) register state a
bfd_byte tmpbuf[FP_REGISTER_SIZE];
regcache_cooked_read (regs, ARM_F0_REGNUM, tmpbuf);
- convert_from_extended (floatformat_from_type (type), tmpbuf,
- valbuf, gdbarch_byte_order (gdbarch));
+ convert_typed_floating (tmpbuf, arm_ext_type (gdbarch),
+ valbuf, type);
}
break;
|| TYPE_CODE (type) == TYPE_CODE_CHAR
|| TYPE_CODE (type) == TYPE_CODE_BOOL
|| TYPE_CODE (type) == TYPE_CODE_PTR
- || TYPE_CODE (type) == TYPE_CODE_REF
+ || TYPE_IS_REFERENCE (type)
|| TYPE_CODE (type) == TYPE_CODE_ENUM)
{
/* If the type is a plain integer, then the access is
if (TYPE_CODE (type) == TYPE_CODE_FLT)
{
- gdb_byte buf[MAX_REGISTER_SIZE];
+ gdb_byte buf[FP_REGISTER_SIZE];
switch (gdbarch_tdep (gdbarch)->fp_model)
{
case ARM_FLOAT_FPA:
- convert_to_extended (floatformat_from_type (type), buf, valbuf,
- gdbarch_byte_order (gdbarch));
+ convert_typed_floating (valbuf, type, buf, arm_ext_type (gdbarch));
regcache_cooked_write (regs, ARM_F0_REGNUM, buf);
break;
|| TYPE_CODE (type) == TYPE_CODE_CHAR
|| TYPE_CODE (type) == TYPE_CODE_BOOL
|| TYPE_CODE (type) == TYPE_CODE_PTR
- || TYPE_CODE (type) == TYPE_CODE_REF
+ || TYPE_IS_REFERENCE (type)
|| TYPE_CODE (type) == TYPE_CODE_ENUM)
{
if (TYPE_LENGTH (type) <= 4)
{
/* Use the name suffix to determine which register contains the
target PC. */
- static char *table[15] =
+ static const char *table[15] =
{"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
"r8", "r9", "sl", "fp", "ip", "sp", "lr"
};
}
static void
-set_arm_command (char *args, int from_tty)
+set_arm_command (const char *args, int from_tty)
{
printf_unfiltered (_("\
\"set arm\" must be followed by an apporpriate subcommand.\n"));
}
static void
-show_arm_command (char *args, int from_tty)
+show_arm_command (const char *args, int from_tty)
{
cmd_show_list (showarmcmdlist, from_tty, "");
}
arm_show_force_mode (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
- struct gdbarch_tdep *tdep = gdbarch_tdep (target_gdbarch ());
-
fprintf_filtered (file,
_("The current execution mode assumed "
"(even when symbols are available) is \"%s\".\n"),
static void
set_disassembly_style_sfunc (char *args, int from_tty,
- struct cmd_list_element *c)
+ struct cmd_list_element *c)
+{
+ /* Convert the short style name into the long style name (eg, reg-names-*)
+ before calling the generic set_disassembler_options() function. */
+ std::string long_name = std::string ("reg-names-") + disassembly_style;
+ set_disassembler_options (&long_name[0]);
+}
+
+static void
+show_disassembly_style_sfunc (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
{
- set_disassembly_style ();
+ struct gdbarch *gdbarch = get_current_arch ();
+ char *options = get_disassembler_options (gdbarch);
+ const char *style = "";
+ int len = 0;
+ const char *opt;
+
+ FOR_EACH_DISASSEMBLER_OPTION (opt, options)
+ if (CONST_STRNEQ (opt, "reg-names-"))
+ {
+ style = &opt[strlen ("reg-names-")];
+ len = strcspn (style, ",");
+ }
+
+ fprintf_unfiltered (file, "The disassembly style is \"%.*s\".\n", len, style);
}
\f
/* Return the ARM register name corresponding to register I. */
return arm_register_names[i];
}
-static void
-set_disassembly_style (void)
-{
- int current;
-
- /* Find the style that the user wants. */
- for (current = 0; current < num_disassembly_options; current++)
- if (disassembly_style == valid_disassembly_styles[current])
- break;
- gdb_assert (current < num_disassembly_options);
-
- /* Synchronize the disassembler. */
- set_arm_regname_option (current);
-}
-
/* Test whether the coff symbol specific value corresponds to a Thumb
function. */
static void
arm_elf_make_msymbol_special(asymbol *sym, struct minimal_symbol *msym)
{
- if (ARM_SYM_BRANCH_TYPE (&((elf_symbol_type *)sym)->internal_elf_sym)
+ elf_symbol_type *elfsym = (elf_symbol_type *) sym;
+
+ if (ARM_GET_SYM_BRANCH_TYPE (elfsym->internal_elf_sym.st_target_internal)
== ST_BRANCH_TO_THUMB)
MSYMBOL_SET_SPECIAL (msym);
}
/* Otherwise we don't have a useful guess. */
}
+/* Implement the code_of_frame_writable gdbarch method. */
+
+static int
+arm_code_of_frame_writable (struct gdbarch *gdbarch, struct frame_info *frame)
+{
+ if (gdbarch_tdep (gdbarch)->is_m
+ && get_frame_type (frame) == SIGTRAMP_FRAME)
+ {
+ /* M-profile exception frames return to some magic PCs, where
+ isn't writable at all. */
+ return 0;
+ }
+ else
+ return 1;
+}
+
\f
/* Initialize the current architecture based on INFO. If possible,
re-use an architecture from ARCHES, which is a list of
switch (bfd_get_flavour (info.abfd))
{
- case bfd_target_aout_flavour:
- /* Assume it's an old APCS-style ABI. */
- arm_abi = ARM_ABI_APCS;
- break;
-
case bfd_target_coff_flavour:
/* Assume it's an old APCS-style ABI. */
/* XXX WinCE? */
/* On ARM targets char defaults to unsigned. */
set_gdbarch_char_signed (gdbarch, 0);
+ /* wchar_t is unsigned under the AAPCS. */
+ if (tdep->arm_abi == ARM_ABI_AAPCS)
+ set_gdbarch_wchar_signed (gdbarch, 0);
+ else
+ set_gdbarch_wchar_signed (gdbarch, 1);
+
/* Note: for displaced stepping, this includes the breakpoint, and one word
of additional scratch space. This setting isn't used for anything beside
displaced stepping at present. */
set_gdbarch_push_dummy_call (gdbarch, arm_push_dummy_call);
set_gdbarch_frame_align (gdbarch, arm_frame_align);
+ if (is_m)
+ set_gdbarch_code_of_frame_writable (gdbarch, arm_code_of_frame_writable);
+
set_gdbarch_write_pc (gdbarch, arm_write_pc);
/* Frame handling. */
set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
/* Breakpoint manipulation. */
- set_gdbarch_breakpoint_from_pc (gdbarch, arm_breakpoint_from_pc);
- set_gdbarch_remote_breakpoint_from_pc (gdbarch,
- arm_remote_breakpoint_from_pc);
+ set_gdbarch_breakpoint_kind_from_pc (gdbarch, arm_breakpoint_kind_from_pc);
+ set_gdbarch_sw_breakpoint_from_kind (gdbarch, arm_sw_breakpoint_from_kind);
+ set_gdbarch_breakpoint_kind_from_current_state (gdbarch,
+ arm_breakpoint_kind_from_current_state);
/* Information about registers, etc. */
set_gdbarch_sp_regnum (gdbarch, ARM_SP_REGNUM);
frame_unwind_append_unwinder (gdbarch, &arm_stub_unwind);
dwarf2_append_unwinders (gdbarch);
frame_unwind_append_unwinder (gdbarch, &arm_exidx_unwind);
+ frame_unwind_append_unwinder (gdbarch, &arm_epilogue_frame_unwind);
frame_unwind_append_unwinder (gdbarch, &arm_prologue_unwind);
/* Now we have tuned the configuration, set a few final things,
user_reg_add (gdbarch, arm_register_aliases[i].name,
value_of_arm_user_reg, &arm_register_aliases[i].regnum);
+ set_gdbarch_disassembler_options (gdbarch, &arm_disassembler_options);
+ set_gdbarch_valid_disassembler_options (gdbarch, disassembler_options_arm ());
+
return gdbarch;
}
(unsigned long) tdep->lowest_pc);
}
-extern initialize_file_ftype _initialize_arm_tdep; /* -Wmissing-prototypes */
+#if GDB_SELF_TEST
+namespace selftests
+{
+static void arm_record_test (void);
+}
+#endif
void
_initialize_arm_tdep (void)
{
- struct ui_file *stb;
long length;
- struct cmd_list_element *new_set, *new_show;
const char *setname;
const char *setdesc;
- const char *const *regnames;
- int numregs, i, j;
- static char *helptext;
+ int i, j;
char regdesc[1024], *rdptr = regdesc;
size_t rest = sizeof (regdesc);
initialize_tdesc_arm_with_vfpv3 ();
initialize_tdesc_arm_with_neon ();
- /* Get the number of possible sets of register names defined in opcodes. */
- num_disassembly_options = get_arm_regname_num_options ();
-
/* Add root prefix command for all "set arm"/"show arm" commands. */
add_prefix_cmd ("arm", no_class, set_arm_command,
_("Various ARM-specific commands."),
_("Various ARM-specific commands."),
&showarmcmdlist, "show arm ", 0, &showlist);
- /* Sync the opcode insn printer with our register viewer. */
- parse_arm_disassembler_option ("reg-names-std");
- /* Initialize the array that will be passed to
- add_setshow_enum_cmd(). */
+ arm_disassembler_options = xstrdup ("reg-names-std");
+ const disasm_options_t *disasm_options = disassembler_options_arm ();
+ int num_disassembly_styles = 0;
+ for (i = 0; disasm_options->name[i] != NULL; i++)
+ if (CONST_STRNEQ (disasm_options->name[i], "reg-names-"))
+ num_disassembly_styles++;
+
+ /* Initialize the array that will be passed to add_setshow_enum_cmd(). */
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);
- valid_disassembly_styles[i] = setname;
- length = snprintf (rdptr, rest, "%s - %s\n", setname, setdesc);
- rdptr += length;
- rest -= length;
- /* When we find the default names, tell the disassembler to use
- them. */
- if (!strcmp (setname, "std"))
- {
- disassembly_style = setname;
- set_arm_regname_option (i);
- }
- }
+ num_disassembly_styles + 1);
+ for (i = j = 0; disasm_options->name[i] != NULL; i++)
+ if (CONST_STRNEQ (disasm_options->name[i], "reg-names-"))
+ {
+ size_t offset = strlen ("reg-names-");
+ const char *style = disasm_options->name[i];
+ valid_disassembly_styles[j++] = &style[offset];
+ length = snprintf (rdptr, rest, "%s - %s\n", &style[offset],
+ disasm_options->description[i]);
+ rdptr += length;
+ rest -= length;
+ }
/* Mark the end of valid options. */
- valid_disassembly_styles[num_disassembly_options] = NULL;
+ valid_disassembly_styles[num_disassembly_styles] = NULL;
/* Create the help text. */
- stb = mem_fileopen ();
- fprintf_unfiltered (stb, "%s%s%s",
- _("The valid values are:\n"),
- regdesc,
- _("The default is \"std\"."));
- helptext = ui_file_xstrdup (stb, NULL);
- ui_file_delete (stb);
+ std::string helptext = string_printf ("%s%s%s",
+ _("The valid values are:\n"),
+ regdesc,
+ _("The default is \"std\"."));
add_setshow_enum_cmd("disassembler", no_class,
valid_disassembly_styles, &disassembly_style,
_("Set the disassembly style."),
_("Show the disassembly style."),
- helptext,
+ helptext.c_str (),
set_disassembly_style_sfunc,
- NULL, /* FIXME: i18n: The disassembly style is
- \"%s\". */
+ show_disassembly_style_sfunc,
&setarmcmdlist, &showarmcmdlist);
add_setshow_boolean_cmd ("apcs32", no_class, &arm_apcs_32,
NULL,
NULL, /* FIXME: i18n: "ARM debugging is %s. */
&setdebuglist, &showdebuglist);
+
+#if GDB_SELF_TEST
+ selftests::register_test ("arm-record", selftests::arm_record_test);
+#endif
+
}
/* ARM-reversible process record data structures. */
uint32_t reg_src1 = 0, reg_src2 = 0;
uint32_t immed_high = 0, immed_low = 0,offset_8 = 0, tgt_mem_addr = 0;
- uint32_t opcode1 = 0;
arm_insn_r->opcode = bits (arm_insn_r->arm_insn, 21, 24);
arm_insn_r->decode = bits (arm_insn_r->arm_insn, 4, 7);
- opcode1 = bits (arm_insn_r->arm_insn, 20, 24);
-
if (14 == arm_insn_r->opcode || 10 == arm_insn_r->opcode)
{
uint32_t opcode1 = 0, opcode2 = 0, insn_op1 = 0;
uint32_t record_buf[8], record_buf_mem[8];
uint32_t reg_src1 = 0;
- uint32_t immed_high = 0, immed_low = 0,offset_8 = 0, tgt_mem_addr = 0;
struct regcache *reg_cache = arm_insn_r->regcache;
ULONGEST u_regval = 0;
{
/* SPSR is going to be changed. */
/* We need to get SPSR value, which is yet to be done. */
- printf_unfiltered (_("Process record does not support "
- "instruction 0x%0x at address %s.\n"),
- arm_insn_r->arm_insn,
- paddress (arm_insn_r->gdbarch,
- arm_insn_r->this_addr));
return -1;
}
}
arm_insn_r->reg_rec_count = 2;
/* Save SPSR also;how? */
- printf_unfiltered (_("Process record does not support "
- "instruction 0x%0x at address %s.\n"),
- arm_insn_r->arm_insn,
- paddress (arm_insn_r->gdbarch, arm_insn_r->this_addr));
return -1;
}
else if(8 == bits (arm_insn_r->arm_insn, 4, 7)
{
/* SPSR is going to be changed. */
/* we need to get SPSR value, which is yet to be done */
- printf_unfiltered (_("Process record does not support "
- "instruction 0x%0x at address %s.\n"),
- arm_insn_r->arm_insn,
- paddress (arm_insn_r->gdbarch,
- arm_insn_r->this_addr));
return -1;
}
}
/* To be done for ARMv5 and later; as of now we return -1. */
if (-1 == ret)
- printf_unfiltered (_("Process record does not support instruction x%0x "
- "at address %s.\n"),arm_insn_r->arm_insn,
- paddress (arm_insn_r->gdbarch, arm_insn_r->this_addr));
-
+ return ret;
REG_ALLOC (arm_insn_r->arm_regs, arm_insn_r->reg_rec_count, record_buf);
MEM_ALLOC (arm_insn_r->arm_mems, arm_insn_r->mem_rec_count, record_buf_mem);
uint32_t record_buf[8], record_buf_mem[8];
ULONGEST u_regval[2] = {0};
- uint32_t reg_src1 = 0, reg_src2 = 0, reg_dest = 0;
- uint32_t immed_high = 0, immed_low = 0, offset_8 = 0, tgt_mem_addr = 0;
+ uint32_t reg_src1 = 0, reg_dest = 0;
uint32_t opcode1 = 0;
arm_insn_r->opcode = bits (arm_insn_r->arm_insn, 21, 24);
{
/* SPSR is going to be changed. */
/* How to read SPSR value? */
- printf_unfiltered (_("Process record does not support instruction "
- "0x%0x at address %s.\n"),
- arm_insn_r->arm_insn,
- paddress (arm_insn_r->gdbarch, arm_insn_r->this_addr));
return -1;
}
}
arm_insn_r->reg_rec_count = 2;
/* Save SPSR also; how? */
- printf_unfiltered (_("Process record does not support instruction "
- "0x%0x at address %s.\n"),arm_insn_r->arm_insn,
- paddress (arm_insn_r->gdbarch,
- arm_insn_r->this_addr));
return -1;
}
else if (11 == arm_insn_r->decode
return 0;
}
-/* Handle ARM mode instructions with opcode 010. */
-
static int
-arm_record_ld_st_imm_offset (insn_decode_record *arm_insn_r)
+arm_record_media (insn_decode_record *arm_insn_r)
{
- struct regcache *reg_cache = arm_insn_r->regcache;
+ uint32_t record_buf[8];
+
+ switch (bits (arm_insn_r->arm_insn, 22, 24))
+ {
+ case 0:
+ /* Parallel addition and subtraction, signed */
+ case 1:
+ /* Parallel addition and subtraction, unsigned */
+ case 2:
+ case 3:
+ /* Packing, unpacking, saturation and reversal */
+ {
+ int rd = bits (arm_insn_r->arm_insn, 12, 15);
+
+ record_buf[arm_insn_r->reg_rec_count++] = rd;
+ }
+ break;
+
+ case 4:
+ case 5:
+ /* Signed multiplies */
+ {
+ int rd = bits (arm_insn_r->arm_insn, 16, 19);
+ unsigned int op1 = bits (arm_insn_r->arm_insn, 20, 22);
+
+ record_buf[arm_insn_r->reg_rec_count++] = rd;
+ if (op1 == 0x0)
+ record_buf[arm_insn_r->reg_rec_count++] = ARM_PS_REGNUM;
+ else if (op1 == 0x4)
+ record_buf[arm_insn_r->reg_rec_count++]
+ = bits (arm_insn_r->arm_insn, 12, 15);
+ }
+ break;
+
+ case 6:
+ {
+ if (bit (arm_insn_r->arm_insn, 21)
+ && bits (arm_insn_r->arm_insn, 5, 6) == 0x2)
+ {
+ /* SBFX */
+ record_buf[arm_insn_r->reg_rec_count++]
+ = bits (arm_insn_r->arm_insn, 12, 15);
+ }
+ else if (bits (arm_insn_r->arm_insn, 20, 21) == 0x0
+ && bits (arm_insn_r->arm_insn, 5, 7) == 0x0)
+ {
+ /* USAD8 and USADA8 */
+ record_buf[arm_insn_r->reg_rec_count++]
+ = bits (arm_insn_r->arm_insn, 16, 19);
+ }
+ }
+ break;
+
+ case 7:
+ {
+ if (bits (arm_insn_r->arm_insn, 20, 21) == 0x3
+ && bits (arm_insn_r->arm_insn, 5, 7) == 0x7)
+ {
+ /* Permanently UNDEFINED */
+ return -1;
+ }
+ else
+ {
+ /* BFC, BFI and UBFX */
+ record_buf[arm_insn_r->reg_rec_count++]
+ = bits (arm_insn_r->arm_insn, 12, 15);
+ }
+ }
+ break;
+
+ default:
+ return -1;
+ }
+
+ REG_ALLOC (arm_insn_r->arm_regs, arm_insn_r->reg_rec_count, record_buf);
+
+ return 0;
+}
+
+/* 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_base , reg_dest;
uint32_t offset_12, tgt_mem_addr;
LONGEST s_word;
ULONGEST u_regval[2];
+ if (bit (arm_insn_r->arm_insn, 4))
+ return arm_record_media (arm_insn_r);
+
arm_insn_r->opcode = bits (arm_insn_r->arm_insn, 21, 24);
arm_insn_r->decode = bits (arm_insn_r->arm_insn, 4, 7);
return 0;
}
-/* Handling opcode 110 insns. */
-
static int
arm_record_unsupported_insn (insn_decode_record *arm_insn_r)
{
printf_unfiltered (_("Process record does not support instruction "
- "0x%0x at address %s.\n"),arm_insn_r->arm_insn,
- paddress (arm_insn_r->gdbarch, arm_insn_r->this_addr));
+ "0x%0x at address %s.\n"),arm_insn_r->arm_insn,
+ paddress (arm_insn_r->gdbarch, arm_insn_r->this_addr));
return -1;
}
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);
/* 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));
-
+ record_buf[0] = reg_t;
arm_insn_r->reg_rec_count = 1;
}
/* Handle VMRS instruction. */
/* 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));
+ record_buf[0] = ARM_D0_REGNUM + reg_v;
arm_insn_r->reg_rec_count = 1;
}
ULONGEST u_regval = 0;
struct regcache *reg_cache = arm_insn_r->regcache;
- const int num_regs = gdbarch_num_regs (arm_insn_r->gdbarch);
opcode = bits (arm_insn_r->arm_insn, 20, 24);
- single_reg = bit (arm_insn_r->arm_insn, 8);
+ single_reg = !bit (arm_insn_r->arm_insn, 8);
op_vldm_vstm = opcode & 0x1b;
/* Handle VMOV instructions. */
if ((opcode & 0x1e) == 0x04)
{
- if (bit (arm_insn_r->arm_insn, 4))
- {
- record_buf[0] = bits (arm_insn_r->arm_insn, 12, 15);
- record_buf[1] = bits (arm_insn_r->arm_insn, 16, 19);
- arm_insn_r->reg_rec_count = 2;
- }
+ if (bit (arm_insn_r->arm_insn, 20)) /* to_arm_registers bit 20? */
+ {
+ record_buf[0] = bits (arm_insn_r->arm_insn, 12, 15);
+ record_buf[1] = bits (arm_insn_r->arm_insn, 16, 19);
+ arm_insn_r->reg_rec_count = 2;
+ }
else
- {
- uint8_t reg_m = (bits (arm_insn_r->arm_insn, 0, 3) << 1)
- | bit (arm_insn_r->arm_insn, 5);
+ {
+ uint8_t reg_m = bits (arm_insn_r->arm_insn, 0, 3);
+ uint8_t bit_m = bit (arm_insn_r->arm_insn, 5);
- if (!single_reg)
- {
- record_buf[0] = num_regs + reg_m;
- record_buf[1] = num_regs + reg_m + 1;
- arm_insn_r->reg_rec_count = 2;
- }
- else
- {
- record_buf[0] = reg_m + ARM_D0_REGNUM;
- arm_insn_r->reg_rec_count = 1;
- }
- }
+ if (single_reg)
+ {
+ /* The first S register number m is REG_M:M (M is bit 5),
+ the corresponding D register number is REG_M:M / 2, which
+ is REG_M. */
+ record_buf[arm_insn_r->reg_rec_count++] = ARM_D0_REGNUM + reg_m;
+ /* The second S register number is REG_M:M + 1, the
+ corresponding D register number is (REG_M:M + 1) / 2.
+ IOW, if bit M is 1, the first and second S registers
+ are mapped to different D registers, otherwise, they are
+ in the same D register. */
+ if (bit_m)
+ {
+ record_buf[arm_insn_r->reg_rec_count++]
+ = ARM_D0_REGNUM + reg_m + 1;
+ }
+ }
+ else
+ {
+ record_buf[0] = ((bit_m << 4) + reg_m + ARM_D0_REGNUM);
+ arm_insn_r->reg_rec_count = 1;
+ }
+ }
}
/* Handle VSTM and VPUSH instructions. */
else if (op_vldm_vstm == 0x08 || op_vldm_vstm == 0x0a
- || op_vldm_vstm == 0x12)
+ || op_vldm_vstm == 0x12)
{
uint32_t start_address, reg_rn, imm_off32, imm_off8, memory_count;
uint32_t memory_index = 0;
reg_rn = bits (arm_insn_r->arm_insn, 16, 19);
regcache_raw_read_unsigned (reg_cache, reg_rn, &u_regval);
imm_off8 = bits (arm_insn_r->arm_insn, 0, 7);
- imm_off32 = imm_off8 << 24;
+ imm_off32 = imm_off8 << 2;
memory_count = imm_off8;
if (bit (arm_insn_r->arm_insn, 23))
- start_address = u_regval;
+ start_address = u_regval;
else
- start_address = u_regval - imm_off32;
+ start_address = u_regval - imm_off32;
if (bit (arm_insn_r->arm_insn, 21))
- {
- record_buf[0] = reg_rn;
- arm_insn_r->reg_rec_count = 1;
- }
+ {
+ record_buf[0] = reg_rn;
+ arm_insn_r->reg_rec_count = 1;
+ }
while (memory_count > 0)
- {
- if (!single_reg)
- {
- record_buf_mem[memory_index] = start_address;
- record_buf_mem[memory_index + 1] = 4;
- start_address = start_address + 4;
- memory_index = memory_index + 2;
- }
- else
- {
- record_buf_mem[memory_index] = start_address;
- record_buf_mem[memory_index + 1] = 4;
- record_buf_mem[memory_index + 2] = start_address + 4;
- record_buf_mem[memory_index + 3] = 4;
- start_address = start_address + 8;
- memory_index = memory_index + 4;
- }
- memory_count--;
- }
+ {
+ if (single_reg)
+ {
+ record_buf_mem[memory_index] = 4;
+ record_buf_mem[memory_index + 1] = start_address;
+ start_address = start_address + 4;
+ memory_index = memory_index + 2;
+ }
+ else
+ {
+ record_buf_mem[memory_index] = 4;
+ record_buf_mem[memory_index + 1] = start_address;
+ record_buf_mem[memory_index + 2] = 4;
+ record_buf_mem[memory_index + 3] = start_address + 4;
+ start_address = start_address + 8;
+ memory_index = memory_index + 4;
+ }
+ memory_count--;
+ }
arm_insn_r->mem_rec_count = (memory_index >> 1);
}
/* Handle VLDM instructions. */
else if (op_vldm_vstm == 0x09 || op_vldm_vstm == 0x0b
- || op_vldm_vstm == 0x13)
+ || op_vldm_vstm == 0x13)
{
uint32_t reg_count, reg_vd;
uint32_t reg_index = 0;
+ uint32_t bit_d = bit (arm_insn_r->arm_insn, 22);
reg_vd = bits (arm_insn_r->arm_insn, 12, 15);
reg_count = bits (arm_insn_r->arm_insn, 0, 7);
- if (single_reg)
- reg_vd = reg_vd | (bit (arm_insn_r->arm_insn, 22) << 4);
- else
- reg_vd = (reg_vd << 1) | bit (arm_insn_r->arm_insn, 22);
+ /* REG_VD is the first D register number. If the instruction
+ loads memory to S registers (SINGLE_REG is TRUE), the register
+ number is (REG_VD << 1 | bit D), so the corresponding D
+ register number is (REG_VD << 1 | bit D) / 2 = REG_VD. */
+ if (!single_reg)
+ reg_vd = reg_vd | (bit_d << 4);
- if (bit (arm_insn_r->arm_insn, 21))
- record_buf[reg_index++] = bits (arm_insn_r->arm_insn, 16, 19);
+ if (bit (arm_insn_r->arm_insn, 21) /* write back */)
+ record_buf[reg_index++] = bits (arm_insn_r->arm_insn, 16, 19);
- while (reg_count > 0)
- {
- if (single_reg)
- record_buf[reg_index++] = num_regs + reg_vd + reg_count - 1;
- else
- record_buf[reg_index++] = ARM_D0_REGNUM + reg_vd + reg_count - 1;
+ /* If the instruction loads memory to D register, REG_COUNT should
+ be divided by 2, according to the ARM Architecture Reference
+ Manual. If the instruction loads memory to S register, divide by
+ 2 as well because two S registers are mapped to D register. */
+ reg_count = reg_count / 2;
+ if (single_reg && bit_d)
+ {
+ /* Increase the register count if S register list starts from
+ an odd number (bit d is one). */
+ reg_count++;
+ }
- reg_count--;
- }
+ while (reg_count > 0)
+ {
+ record_buf[reg_index++] = ARM_D0_REGNUM + reg_vd + reg_count - 1;
+ reg_count--;
+ }
arm_insn_r->reg_rec_count = reg_index;
}
/* VSTR Vector store register. */
else if ((opcode & 0x13) == 0x10)
{
- uint32_t start_address, reg_rn, imm_off32, imm_off8, memory_count;
+ uint32_t start_address, reg_rn, imm_off32, imm_off8;
uint32_t memory_index = 0;
reg_rn = bits (arm_insn_r->arm_insn, 16, 19);
regcache_raw_read_unsigned (reg_cache, reg_rn, &u_regval);
imm_off8 = bits (arm_insn_r->arm_insn, 0, 7);
- imm_off32 = imm_off8 << 24;
- memory_count = imm_off8;
+ imm_off32 = imm_off8 << 2;
if (bit (arm_insn_r->arm_insn, 23))
- start_address = u_regval + imm_off32;
+ start_address = u_regval + imm_off32;
else
- start_address = u_regval - imm_off32;
+ start_address = u_regval - imm_off32;
if (single_reg)
- {
- record_buf_mem[memory_index] = start_address;
- record_buf_mem[memory_index + 1] = 4;
- arm_insn_r->mem_rec_count = 1;
- }
+ {
+ record_buf_mem[memory_index] = 4;
+ record_buf_mem[memory_index + 1] = start_address;
+ arm_insn_r->mem_rec_count = 1;
+ }
else
- {
- record_buf_mem[memory_index] = start_address;
- record_buf_mem[memory_index + 1] = 4;
- record_buf_mem[memory_index + 2] = start_address + 4;
- record_buf_mem[memory_index + 3] = 4;
- arm_insn_r->mem_rec_count = 2;
- }
+ {
+ record_buf_mem[memory_index] = 4;
+ record_buf_mem[memory_index + 1] = start_address;
+ record_buf_mem[memory_index + 2] = 4;
+ record_buf_mem[memory_index + 3] = start_address + 4;
+ arm_insn_r->mem_rec_count = 2;
+ }
}
/* VLDR Vector load register. */
else if ((opcode & 0x13) == 0x11)
uint32_t reg_vd = bits (arm_insn_r->arm_insn, 12, 15);
if (!single_reg)
- {
- reg_vd = reg_vd | (bit (arm_insn_r->arm_insn, 22) << 4);
- record_buf[0] = ARM_D0_REGNUM + reg_vd;
- }
+ {
+ reg_vd = reg_vd | (bit (arm_insn_r->arm_insn, 22) << 4);
+ record_buf[0] = ARM_D0_REGNUM + reg_vd;
+ }
else
- {
- reg_vd = (reg_vd << 1) | bit (arm_insn_r->arm_insn, 22);
- record_buf[0] = num_regs + reg_vd;
- }
+ {
+ reg_vd = (reg_vd << 1) | bit (arm_insn_r->arm_insn, 22);
+ /* Record register D rather than pseudo register S. */
+ record_buf[0] = ARM_D0_REGNUM + reg_vd / 2;
+ }
arm_insn_r->reg_rec_count = 1;
}
static int
arm_record_asimd_vfp_coproc (insn_decode_record *arm_insn_r)
{
- uint32_t op, op1, op1_sbit, op1_ebit, coproc;
+ uint32_t op1, op1_ebit, coproc;
coproc = bits (arm_insn_r->arm_insn, 8, 11);
op1 = bits (arm_insn_r->arm_insn, 20, 25);
uint32_t op, op1_sbit, op1_ebit, coproc;
struct gdbarch_tdep *tdep = gdbarch_tdep (arm_insn_r->gdbarch);
struct regcache *reg_cache = arm_insn_r->regcache;
- ULONGEST u_regval = 0;
arm_insn_r->opcode = bits (arm_insn_r->arm_insn, 24, 27);
coproc = bits (arm_insn_r->arm_insn, 8, 11);
if (bit (thumb_insn_r->arm_insn, 12))
{
/* Handle load/store register offset. */
- opcode2 = bits (thumb_insn_r->arm_insn, 9, 10);
- if (opcode2 >= 12 && opcode2 <= 15)
+ uint32_t opB = bits (thumb_insn_r->arm_insn, 9, 11);
+
+ if (opB >= 4 && opB <= 7)
{
/* LDR(2), LDRB(2) , LDRH(2), LDRSB, LDRSH. */
reg_src1 = bits (thumb_insn_r->arm_insn,0, 2);
record_buf[0] = reg_src1;
thumb_insn_r->reg_rec_count = 1;
}
- else if (opcode2 >= 8 && opcode2 <= 10)
+ else if (opB >= 0 && opB <= 2)
{
/* STR(2), STRB(2), STRH(2) . */
reg_src1 = bits (thumb_insn_r->arm_insn, 3, 5);
reg_src2 = bits (thumb_insn_r->arm_insn, 6, 8);
regcache_raw_read_unsigned (reg_cache, reg_src1, &u_regval[0]);
regcache_raw_read_unsigned (reg_cache, reg_src2, &u_regval[1]);
- if (8 == opcode2)
+ if (0 == opB)
record_buf_mem[0] = 4; /* STR (2). */
- else if (10 == opcode2)
+ else if (2 == opB)
record_buf_mem[0] = 1; /* STRB (2). */
- else if (9 == opcode2)
+ else if (1 == opB)
record_buf_mem[0] = 2; /* STRH (2). */
record_buf_mem[1] = u_regval[0] + u_regval[1];
thumb_insn_r->mem_rec_count = 1;
}
else if (opcode1)
{
+ /* Special data instructions and branch and exchange */
opcode2 = bits (thumb_insn_r->arm_insn, 8, 9);
opcode3 = bits (thumb_insn_r->arm_insn, 0, 2);
if ((3 == opcode2) && (!opcode3))
}
else
{
- /* Format 8; special data processing insns. */
- reg_src1 = bits (thumb_insn_r->arm_insn, 0, 2);
- record_buf[0] = ARM_PS_REGNUM;
- record_buf[1] = reg_src1;
+ /* Format 8; special data processing insns. */
+ record_buf[0] = ARM_PS_REGNUM;
+ record_buf[1] = (bit (thumb_insn_r->arm_insn, 7) << 3
+ | bits (thumb_insn_r->arm_insn, 0, 2));
thumb_insn_r->reg_rec_count = 2;
}
}
{
struct regcache *reg_cache = thumb_insn_r->regcache;
- uint32_t opcode = 0, opcode1 = 0, opcode2 = 0;
+ uint32_t opcode = 0;
uint32_t register_bits = 0, register_count = 0;
- uint32_t register_list[8] = {0}, index = 0, start_address = 0;
+ uint32_t index = 0, start_address = 0;
uint32_t record_buf[24], record_buf_mem[48];
uint32_t reg_src1;
ULONGEST u_regval = 0;
opcode = bits (thumb_insn_r->arm_insn, 11, 12);
- opcode1 = bits (thumb_insn_r->arm_insn, 8, 12);
- opcode2 = bits (thumb_insn_r->arm_insn, 9, 12);
- if (14 == opcode2)
- {
- /* POP. */
- register_bits = bits (thumb_insn_r->arm_insn, 0, 7);
- while (register_bits)
- {
- if (register_bits & 0x00000001)
- record_buf[index++] = register_count;
- register_bits = register_bits >> 1;
- register_count++;
- }
- record_buf[index++] = ARM_PS_REGNUM;
- record_buf[index++] = ARM_SP_REGNUM;
- thumb_insn_r->reg_rec_count = index;
- }
- else if (10 == opcode2)
+ if (opcode == 0 || opcode == 1)
{
- /* PUSH. */
- register_bits = bits (thumb_insn_r->arm_insn, 0, 7);
- regcache_raw_read_unsigned (reg_cache, ARM_SP_REGNUM, &u_regval);
- while (register_bits)
- {
- if (register_bits & 0x00000001)
- register_count++;
- register_bits = register_bits >> 1;
- }
- start_address = u_regval - \
- (4 * (bit (thumb_insn_r->arm_insn, 8) + register_count));
- thumb_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--;
- }
- record_buf[0] = ARM_SP_REGNUM;
- thumb_insn_r->reg_rec_count = 1;
- }
- else if (0x1E == opcode1)
- {
- /* BKPT insn. */
- /* Handle enhanced software breakpoint insn, BKPT. */
- /* CPSR is changed to be executed in ARM state, disabling normal
- interrupts, entering abort mode. */
- /* According to high vector configuration PC is set. */
- /* User hits breakpoint and type reverse, in that case, we need to go back with
- previous CPSR and Program Counter. */
- record_buf[0] = ARM_PS_REGNUM;
- record_buf[1] = ARM_LR_REGNUM;
- thumb_insn_r->reg_rec_count = 2;
- /* We need to save SPSR value, which is not yet done. */
- printf_unfiltered (_("Process record does not support instruction "
- "0x%0x at address %s.\n"),
- thumb_insn_r->arm_insn,
- paddress (thumb_insn_r->gdbarch,
- thumb_insn_r->this_addr));
- return -1;
- }
- else if ((0 == opcode) || (1 == opcode))
- {
- /* ADD(5), ADD(6). */
+ /* ADR and ADD (SP plus immediate) */
+
reg_src1 = bits (thumb_insn_r->arm_insn, 8, 10);
record_buf[0] = reg_src1;
thumb_insn_r->reg_rec_count = 1;
}
- else if (2 == opcode)
+ else
{
- /* ADD(7), SUB(4). */
- reg_src1 = bits (thumb_insn_r->arm_insn, 8, 10);
- record_buf[0] = ARM_SP_REGNUM;
- thumb_insn_r->reg_rec_count = 1;
+ /* Miscellaneous 16-bit instructions */
+ uint32_t opcode2 = bits (thumb_insn_r->arm_insn, 8, 11);
+
+ switch (opcode2)
+ {
+ case 6:
+ /* SETEND and CPS */
+ break;
+ case 0:
+ /* ADD/SUB (SP plus immediate) */
+ reg_src1 = bits (thumb_insn_r->arm_insn, 8, 10);
+ record_buf[0] = ARM_SP_REGNUM;
+ thumb_insn_r->reg_rec_count = 1;
+ break;
+ case 1: /* fall through */
+ case 3: /* fall through */
+ case 9: /* fall through */
+ case 11:
+ /* CBNZ, CBZ */
+ break;
+ case 2:
+ /* SXTH, SXTB, UXTH, UXTB */
+ record_buf[0] = bits (thumb_insn_r->arm_insn, 0, 2);
+ thumb_insn_r->reg_rec_count = 1;
+ break;
+ case 4: /* fall through */
+ case 5:
+ /* PUSH. */
+ register_bits = bits (thumb_insn_r->arm_insn, 0, 7);
+ regcache_raw_read_unsigned (reg_cache, ARM_SP_REGNUM, &u_regval);
+ while (register_bits)
+ {
+ if (register_bits & 0x00000001)
+ register_count++;
+ register_bits = register_bits >> 1;
+ }
+ start_address = u_regval - \
+ (4 * (bit (thumb_insn_r->arm_insn, 8) + register_count));
+ thumb_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--;
+ }
+ record_buf[0] = ARM_SP_REGNUM;
+ thumb_insn_r->reg_rec_count = 1;
+ break;
+ case 10:
+ /* REV, REV16, REVSH */
+ record_buf[0] = bits (thumb_insn_r->arm_insn, 0, 2);
+ thumb_insn_r->reg_rec_count = 1;
+ break;
+ case 12: /* fall through */
+ case 13:
+ /* POP. */
+ register_bits = bits (thumb_insn_r->arm_insn, 0, 7);
+ while (register_bits)
+ {
+ if (register_bits & 0x00000001)
+ record_buf[index++] = register_count;
+ register_bits = register_bits >> 1;
+ register_count++;
+ }
+ record_buf[index++] = ARM_PS_REGNUM;
+ record_buf[index++] = ARM_SP_REGNUM;
+ thumb_insn_r->reg_rec_count = index;
+ break;
+ case 0xe:
+ /* BKPT insn. */
+ /* Handle enhanced software breakpoint insn, BKPT. */
+ /* CPSR is changed to be executed in ARM state, disabling normal
+ interrupts, entering abort mode. */
+ /* According to high vector configuration PC is set. */
+ /* User hits breakpoint and type reverse, in that case, we need to go back with
+ previous CPSR and Program Counter. */
+ record_buf[0] = ARM_PS_REGNUM;
+ record_buf[1] = ARM_LR_REGNUM;
+ thumb_insn_r->reg_rec_count = 2;
+ /* We need to save SPSR value, which is not yet done. */
+ printf_unfiltered (_("Process record does not support instruction "
+ "0x%0x at address %s.\n"),
+ thumb_insn_r->arm_insn,
+ paddress (thumb_insn_r->gdbarch,
+ thumb_insn_r->this_addr));
+ return -1;
+
+ case 0xf:
+ /* If-Then, and hints */
+ break;
+ default:
+ return -1;
+ };
}
REG_ALLOC (thumb_insn_r->arm_regs, thumb_insn_r->reg_rec_count, record_buf);
uint32_t ret = 0; /* function return value: -1:record failure ; 0:success */
uint32_t reg_src1 = 0;
uint32_t opcode1 = 0, opcode2 = 0, register_bits = 0, register_count = 0;
- uint32_t register_list[8] = {0}, index = 0, start_address = 0;
+ uint32_t index = 0, start_address = 0;
uint32_t record_buf[24], record_buf_mem[48];
ULONGEST u_regval = 0;
uint32_t address, offset_addr;
uint32_t record_buf[8], record_buf_mem[8];
uint32_t op1, op2, op3;
- LONGEST s_word;
ULONGEST u_regval[2];
static int
thumb2_record_ld_word (insn_decode_record *thumb2_insn_r)
{
- uint32_t opcode1 = 0, opcode2 = 0;
uint32_t record_buf[8];
record_buf[0] = bits (thumb2_insn_r->arm_insn, 12, 15);
{
uint32_t opcode1 = 0, opcode2 = 0;
uint32_t record_buf[8];
- uint32_t reg_src1 = 0;
opcode1 = bits (thumb2_insn_r->arm_insn, 20, 22);
opcode2 = bits (thumb2_insn_r->arm_insn, 4, 7);
struct regcache *reg_cache = thumb2_insn_r->regcache;
uint32_t l_bit, a_bit, b_bits;
uint32_t record_buf[128], record_buf_mem[128];
- uint32_t reg_rn, reg_vd, address, f_esize, f_elem;
+ uint32_t reg_rn, reg_vd, address, f_elem;
uint32_t index_r = 0, index_e = 0, bf_regs = 0, index_m = 0, loop_t = 0;
uint8_t f_ebytes;
reg_vd = bits (thumb2_insn_r->arm_insn, 12, 15);
reg_vd = (bit (thumb2_insn_r->arm_insn, 22) << 4) | reg_vd;
f_ebytes = (1 << bits (thumb2_insn_r->arm_insn, 6, 7));
- f_esize = 8 * f_ebytes;
f_elem = 8 / f_ebytes;
if (!l_bit)
/* Load/store multiple instruction. */
return thumb2_record_ld_st_multiple (thumb2_insn_r);
}
- else if (!((op2 & 0x64) ^ 0x04))
+ else if ((op2 & 0x64) == 0x4)
{
/* Load/store (dual/exclusive) and table branch instruction. */
return thumb2_record_ld_st_dual_ex_tbb (thumb2_insn_r);
}
- else if (!((op2 & 0x20) ^ 0x20))
+ else if ((op2 & 0x60) == 0x20)
{
/* Data-processing (shifted register). */
return thumb2_record_data_proc_sreg_mimm (thumb2_insn_r);
return -1;
}
+namespace {
+/* Abstract memory reader. */
+
+class abstract_memory_reader
+{
+public:
+ /* Read LEN bytes of target memory at address MEMADDR, placing the
+ results in GDB's memory at BUF. Return true on success. */
+
+ virtual bool read (CORE_ADDR memaddr, gdb_byte *buf, const size_t len) = 0;
+};
+
+/* Instruction reader from real target. */
+
+class instruction_reader : public abstract_memory_reader
+{
+ public:
+ bool read (CORE_ADDR memaddr, gdb_byte *buf, const size_t len)
+ {
+ if (target_read_memory (memaddr, buf, len))
+ return false;
+ else
+ return true;
+ }
+};
+
+} // namespace
+
/* Extracts arm/thumb/thumb2 insn depending on the size, and returns 0 on success
and positive val on fauilure. */
static int
-extract_arm_insn (insn_decode_record *insn_record, uint32_t insn_size)
+extract_arm_insn (abstract_memory_reader& reader,
+ insn_decode_record *insn_record, uint32_t insn_size)
{
gdb_byte buf[insn_size];
memset (&buf[0], 0, insn_size);
- if (target_read_memory (insn_record->this_addr, &buf[0], insn_size))
+ if (!reader.read (insn_record->this_addr, buf, insn_size))
return 1;
insn_record->arm_insn = (uint32_t) extract_unsigned_integer (&buf[0],
insn_size,
dispatch it. */
static int
-decode_insn (insn_decode_record *arm_record, record_type_t record_type,
- uint32_t insn_size)
+decode_insn (abstract_memory_reader &reader, insn_decode_record *arm_record,
+ record_type_t record_type, uint32_t insn_size)
{
- /* (Starting from numerical 0); bits 25, 26, 27 decodes type of arm instruction. */
+ /* (Starting from numerical 0); bits 25, 26, 27 decodes type of arm
+ instruction. */
static const sti_arm_hdl_fp_t arm_handle_insn[8] =
{
arm_record_data_proc_misc_ld_str, /* 000. */
arm_record_coproc_data_proc /* 111. */
};
- /* (Starting from numerical 0); bits 13,14,15 decodes type of thumb instruction. */
+ /* (Starting from numerical 0); bits 13,14,15 decodes type of thumb
+ instruction. */
static const sti_arm_hdl_fp_t thumb_handle_insn[8] =
{ \
thumb_record_shift_add_sub, /* 000. */
uint32_t ret = 0; /* return value: negative:failure 0:success. */
uint32_t insn_id = 0;
- if (extract_arm_insn (arm_record, insn_size))
+ if (extract_arm_insn (reader, arm_record, insn_size))
{
if (record_debug)
- {
- printf_unfiltered (_("Process record: error reading memory at "
- "addr %s len = %d.\n"),
- paddress (arm_record->gdbarch, arm_record->this_addr), insn_size);
- }
+ {
+ printf_unfiltered (_("Process record: error reading memory at "
+ "addr %s len = %d.\n"),
+ paddress (arm_record->gdbarch,
+ arm_record->this_addr), insn_size);
+ }
return -1;
}
else if (ARM_RECORD == record_type)
{
arm_record->cond = bits (arm_record->arm_insn, 28, 31);
insn_id = bits (arm_record->arm_insn, 25, 27);
- ret = arm_record_extension_space (arm_record);
- /* If this insn has fallen into extension space
- then we need not decode it anymore. */
- if (ret != -1 && !INSN_RECORDED(arm_record))
- {
- ret = arm_handle_insn[insn_id] (arm_record);
- }
+
+ if (arm_record->cond == 0xf)
+ ret = arm_record_extension_space (arm_record);
+ else
+ {
+ /* If this insn has fallen into extension space
+ then we need not decode it anymore. */
+ ret = arm_handle_insn[insn_id] (arm_record);
+ }
+ if (ret != ARM_RECORD_SUCCESS)
+ {
+ arm_record_unsupported_insn (arm_record);
+ ret = -1;
+ }
}
else if (THUMB_RECORD == record_type)
{
arm_record->cond = -1;
insn_id = bits (arm_record->arm_insn, 13, 15);
ret = thumb_handle_insn[insn_id] (arm_record);
+ if (ret != ARM_RECORD_SUCCESS)
+ {
+ arm_record_unsupported_insn (arm_record);
+ ret = -1;
+ }
}
else if (THUMB2_RECORD == record_type)
{
/* Swap first half of 32bit thumb instruction with second half. */
arm_record->arm_insn
- = (arm_record->arm_insn >> 16) | (arm_record->arm_insn << 16);
+ = (arm_record->arm_insn >> 16) | (arm_record->arm_insn << 16);
- insn_id = thumb2_record_decode_insn_handler (arm_record);
+ ret = thumb2_record_decode_insn_handler (arm_record);
- if (insn_id != ARM_RECORD_SUCCESS)
- {
- arm_record_unsupported_insn (arm_record);
- ret = -1;
- }
+ if (ret != ARM_RECORD_SUCCESS)
+ {
+ arm_record_unsupported_insn (arm_record);
+ ret = -1;
+ }
}
else
{
return ret;
}
+#if GDB_SELF_TEST
+namespace selftests {
+
+/* Provide both 16-bit and 32-bit thumb instructions. */
+
+class instruction_reader_thumb : public abstract_memory_reader
+{
+public:
+ template<size_t SIZE>
+ instruction_reader_thumb (enum bfd_endian endian,
+ const uint16_t (&insns)[SIZE])
+ : m_endian (endian), m_insns (insns), m_insns_size (SIZE)
+ {}
+
+ bool read (CORE_ADDR memaddr, gdb_byte *buf, const size_t len)
+ {
+ SELF_CHECK (len == 4 || len == 2);
+ SELF_CHECK (memaddr % 2 == 0);
+ SELF_CHECK ((memaddr / 2) < m_insns_size);
+
+ store_unsigned_integer (buf, 2, m_endian, m_insns[memaddr / 2]);
+ if (len == 4)
+ {
+ store_unsigned_integer (&buf[2], 2, m_endian,
+ m_insns[memaddr / 2 + 1]);
+ }
+ return true;
+ }
+
+private:
+ enum bfd_endian m_endian;
+ const uint16_t *m_insns;
+ size_t m_insns_size;
+};
+
+static void
+arm_record_test (void)
+{
+ struct gdbarch_info info;
+ gdbarch_info_init (&info);
+ info.bfd_arch_info = bfd_scan_arch ("arm");
+
+ struct gdbarch *gdbarch = gdbarch_find_by_info (info);
+
+ SELF_CHECK (gdbarch != NULL);
+
+ /* 16-bit Thumb instructions. */
+ {
+ insn_decode_record arm_record;
+
+ memset (&arm_record, 0, sizeof (insn_decode_record));
+ arm_record.gdbarch = gdbarch;
+
+ static const uint16_t insns[] = {
+ /* db b2 uxtb r3, r3 */
+ 0xb2db,
+ /* cd 58 ldr r5, [r1, r3] */
+ 0x58cd,
+ };
+
+ enum bfd_endian endian = gdbarch_byte_order_for_code (arm_record.gdbarch);
+ instruction_reader_thumb reader (endian, insns);
+ int ret = decode_insn (reader, &arm_record, THUMB_RECORD,
+ THUMB_INSN_SIZE_BYTES);
+
+ SELF_CHECK (ret == 0);
+ SELF_CHECK (arm_record.mem_rec_count == 0);
+ SELF_CHECK (arm_record.reg_rec_count == 1);
+ SELF_CHECK (arm_record.arm_regs[0] == 3);
+
+ arm_record.this_addr += 2;
+ ret = decode_insn (reader, &arm_record, THUMB_RECORD,
+ THUMB_INSN_SIZE_BYTES);
+
+ SELF_CHECK (ret == 0);
+ SELF_CHECK (arm_record.mem_rec_count == 0);
+ SELF_CHECK (arm_record.reg_rec_count == 1);
+ SELF_CHECK (arm_record.arm_regs[0] == 5);
+ }
+
+ /* 32-bit Thumb-2 instructions. */
+ {
+ insn_decode_record arm_record;
+
+ memset (&arm_record, 0, sizeof (insn_decode_record));
+ arm_record.gdbarch = gdbarch;
+
+ static const uint16_t insns[] = {
+ /* 1d ee 70 7f mrc 15, 0, r7, cr13, cr0, {3} */
+ 0xee1d, 0x7f70,
+ };
+
+ enum bfd_endian endian = gdbarch_byte_order_for_code (arm_record.gdbarch);
+ instruction_reader_thumb reader (endian, insns);
+ int ret = decode_insn (reader, &arm_record, THUMB2_RECORD,
+ THUMB2_INSN_SIZE_BYTES);
+
+ SELF_CHECK (ret == 0);
+ SELF_CHECK (arm_record.mem_rec_count == 0);
+ SELF_CHECK (arm_record.reg_rec_count == 1);
+ SELF_CHECK (arm_record.arm_regs[0] == 7);
+ }
+}
+} // namespace selftests
+#endif /* GDB_SELF_TEST */
/* Cleans up local record registers and memory allocations. */
}
-/* Parse the current instruction and record the values of the registers and
+/* Parse the current instruction and record the values of the registers and
memory that will be changed in current instruction to record_arch_list".
Return -1 if something is wrong. */
int
-arm_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
- CORE_ADDR insn_addr)
+arm_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
+ CORE_ADDR insn_addr)
{
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
uint32_t no_of_rec = 0;
uint32_t ret = 0; /* return value: -1:record failure ; 0:success */
ULONGEST t_bit = 0, insn_id = 0;
if (record_debug > 1)
{
fprintf_unfiltered (gdb_stdlog, "Process record: arm_process_record "
- "addr = %s\n",
+ "addr = %s\n",
paddress (gdbarch, arm_record.this_addr));
}
- if (extract_arm_insn (&arm_record, 2))
+ instruction_reader reader;
+ if (extract_arm_insn (reader, &arm_record, 2))
{
if (record_debug)
- {
- printf_unfiltered (_("Process record: error reading memory at "
- "addr %s len = %d.\n"),
- paddress (arm_record.gdbarch,
- arm_record.this_addr), 2);
- }
+ {
+ printf_unfiltered (_("Process record: error reading memory at "
+ "addr %s len = %d.\n"),
+ paddress (arm_record.gdbarch,
+ arm_record.this_addr), 2);
+ }
return -1;
}
if (!(u_regval & t_bit))
{
/* We are decoding arm insn. */
- ret = decode_insn (&arm_record, ARM_RECORD, ARM_INSN_SIZE_BYTES);
+ ret = decode_insn (reader, &arm_record, ARM_RECORD, ARM_INSN_SIZE_BYTES);
}
else
{
insn_id = bits (arm_record.arm_insn, 11, 15);
/* is it thumb2 insn? */
if ((0x1D == insn_id) || (0x1E == insn_id) || (0x1F == insn_id))
- {
- ret = decode_insn (&arm_record, THUMB2_RECORD,
- THUMB2_INSN_SIZE_BYTES);
- }
+ {
+ ret = decode_insn (reader, &arm_record, THUMB2_RECORD,
+ THUMB2_INSN_SIZE_BYTES);
+ }
else
- {
- /* We are decoding thumb insn. */
- ret = decode_insn (&arm_record, THUMB_RECORD, THUMB_INSN_SIZE_BYTES);
- }
+ {
+ /* We are decoding thumb insn. */
+ ret = decode_insn (reader, &arm_record, THUMB_RECORD,
+ THUMB_INSN_SIZE_BYTES);
+ }
}
if (0 == ret)
/* Record registers. */
record_full_arch_list_add_reg (arm_record.regcache, ARM_PC_REGNUM);
if (arm_record.arm_regs)
- {
- for (no_of_rec = 0; no_of_rec < arm_record.reg_rec_count; no_of_rec++)
- {
- if (record_full_arch_list_add_reg
+ {
+ for (no_of_rec = 0; no_of_rec < arm_record.reg_rec_count; no_of_rec++)
+ {
+ if (record_full_arch_list_add_reg
(arm_record.regcache , arm_record.arm_regs[no_of_rec]))
- ret = -1;
- }
- }
+ ret = -1;
+ }
+ }
/* Record memories. */
if (arm_record.arm_mems)
- {
- for (no_of_rec = 0; no_of_rec < arm_record.mem_rec_count; no_of_rec++)
- {
- if (record_full_arch_list_add_mem
- ((CORE_ADDR)arm_record.arm_mems[no_of_rec].addr,
+ {
+ for (no_of_rec = 0; no_of_rec < arm_record.mem_rec_count; no_of_rec++)
+ {
+ if (record_full_arch_list_add_mem
+ ((CORE_ADDR)arm_record.arm_mems[no_of_rec].addr,
arm_record.arm_mems[no_of_rec].len))
- ret = -1;
- }
- }
+ ret = -1;
+ }
+ }
if (record_full_arch_list_add_end ())
- ret = -1;
+ ret = -1;
}
return ret;
}
-