[PATCH v2 05/17] arm-tdep.c: Use relocation visitor in Thumb 32-bits instruction decoding

Antoine Tremblay
2016-06-09T12:57:10Z

This is the same as the previous patch, but for the 32-bits Thumb
instructions.

gdb/ChangeLog:

* arm-tdep.c (struct thumb_32bit_insn_reloc_visitor): New.
(thumb2_decode_dp_shift_reg): Add visitor parameter and use it.
(thumb2_decode_ext_reg_ld_st): Likewise.
(thumb2_decode_svc_copro): Likewise.
(decode_thumb_32bit_ld_mem_hints): Likewise.
(thumb_32bit_relocate_insn): Add and use visitor parameter.
(thumb_32bit_insn_reloc_visitor): New.
(arm_process_displaced_insn): Pass
thumb_32bit_insn_reloc_visitor to
thumb_32bit_relocate_insn.
---
gdb/arm-tdep.c | 160 +++++++++++++++++++++++++++++++++++----------------------
1 file changed, 99 insertions(+), 61 deletions(-)

diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index dcd65eeb..6a9d110 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -4502,6 +4502,33 @@ struct arm_insn_reloc_visitor
int (*unpred) (uint32_t insn, struct arm_insn_reloc_data *data);
};

+struct thumb_32bit_insn_reloc_visitor
+{
+ int (*alu_imm) (uint16_t insn1, uint16_t insn2,
+ struct arm_insn_reloc_data *data);
+ int (*b_bl_blx) (uint16_t insn1, uint16_t insn2,
+ struct arm_insn_reloc_data *data);
+ int (*block_xfer) (uint16_t insn1, uint16_t insn2,
+ struct arm_insn_reloc_data *data);
+ int (*copro_load_store) (uint16_t insn1, uint16_t insn2,
+ struct arm_insn_reloc_data *data);
+ int (*load_literal) (uint16_t insn1, uint16_t insn2,
+ struct arm_insn_reloc_data *data, int size);
+ int (*load_reg_imm) (uint16_t insn1, uint16_t insn2,
+ struct arm_insn_reloc_data *data, int writeback,
+ int immed);
+ int (*others) (uint16_t insn1, uint16_t insn2, const char *iname,
+ struct arm_insn_reloc_data *data);
+ int (*pc_relative_32bit) (uint16_t insn1, uint16_t insn2,
+ struct arm_insn_reloc_data *data);
+ int (*preload) (uint16_t insn1, uint16_t insn2,
+ struct arm_insn_reloc_data *data);
+ int (*undef) (uint16_t insn1, uint16_t insn2,
+ struct arm_insn_reloc_data *data);
+ int (*table_branch) (uint16_t insn1, uint16_t insn2,
+ struct arm_insn_reloc_data *data);
+};
+
/* Helper for register reads for displaced stepping. In particular, this
returns the PC as it would be seen by the instruction at its original
location. */
@@ -6856,6 +6883,7 @@ arm_decode_ext_reg_ld_st (uint32_t insn, struct arm_insn_reloc_visitor *visitor,

static int
thumb2_decode_dp_shift_reg (uint16_t insn1, uint16_t insn2,
+ struct thumb_32bit_insn_reloc_visitor *visitor,
struct arm_insn_reloc_data *data)
{
/* PC is only allowed to be used in instruction MOV. */
@@ -6864,9 +6892,9 @@ thumb2_decode_dp_shift_reg (uint16_t insn1, uint16_t insn2,
unsigned int rn = bits (insn1, 0, 3);

if (op == 0x2 && rn == 0xf) /* MOV */
- return thumb2_copy_alu_imm (insn1, insn2, data);
+ return visitor->alu_imm (insn1, insn2, data);
else
- return thumb_copy_unmodified_32bit (insn1, insn2, "dp (shift reg)", data);
+ return visitor->others (insn1, insn2, "dp (shift reg)", data);
}

@@ -6875,6 +6903,7 @@ thumb2_decode_dp_shift_reg (uint16_t insn1, uint16_t insn2,

static int
thumb2_decode_ext_reg_ld_st (uint16_t insn1, uint16_t insn2,
+ struct thumb_32bit_insn_reloc_visitor *visitor,
struct arm_insn_reloc_data *data)
{
unsigned int opcode = bits (insn1, 4, 8);
@@ -6882,24 +6911,22 @@ thumb2_decode_ext_reg_ld_st (uint16_t insn1, uint16_t insn2,
switch (opcode)
{
case 0x04: case 0x05:
- return thumb_copy_unmodified_32bit (insn1, insn2, "vfp/neon vmov", data);
+ return visitor->others (insn1, insn2, "vfp/neon vmov", data);

case 0x08: case 0x0c: /* 01x00 */
case 0x0a: case 0x0e: /* 01x10 */
case 0x12: case 0x16: /* 10x10 */
- return thumb_copy_unmodified_32bit (insn1, insn2,
- "vfp/neon vstm/vpush", data);
+ return visitor->others (insn1, insn2, "vfp/neon vstm/vpush", data);

case 0x09: case 0x0d: /* 01x01 */
case 0x0b: case 0x0f: /* 01x11 */
case 0x13: case 0x17: /* 10x11 */
- return thumb_copy_unmodified_32bit (insn1, insn2,
- "vfp/neon vldm/vpop", data);
+ return visitor->others (insn1, insn2, "vfp/neon vldm/vpop", data);

case 0x10: case 0x14: case 0x18: case 0x1c: /* vstr. */
- return thumb_copy_unmodified_32bit (insn1, insn2, "vstr", data);
+ return visitor->others (insn1, insn2, "vstr", data);
case 0x11: case 0x15: case 0x19: case 0x1d: /* vldr. */
- return thumb2_copy_copro_load_store (insn1, insn2, data);
+ return visitor->copro_load_store (insn1, insn2, data);
}

/* Should be unreachable. */
@@ -6953,6 +6980,7 @@ arm_decode_svc_copro (uint32_t insn, struct arm_insn_reloc_visitor *visitor,

static int
thumb2_decode_svc_copro (uint16_t insn1, uint16_t insn2,
+ struct thumb_32bit_insn_reloc_visitor *visitor,
struct arm_insn_reloc_data *data)
{
unsigned int coproc = bits (insn2, 8, 11);
@@ -6963,27 +6991,26 @@ thumb2_decode_svc_copro (uint16_t insn1, uint16_t insn2,
if (bit_9 == 0)
{
if (bit_5_8 == 2)
- return thumb_copy_unmodified_32bit (
- insn1, insn2, "neon 64bit xfer/mrrc/mrrc2/mcrr/mcrr2", data);
+ return visitor->others (insn1, insn2,
+ "neon 64bit xfer/mrrc/mrrc2/mcrr/mcrr2", data);
else if (bit_5_8 == 0) /* UNDEFINED. */
- return thumb_32bit_copy_undef (insn1, insn2, data);
+ return visitor->undef (insn1, insn2, data);
else
{
/*coproc is 101x. SIMD/VFP, ext registers load/store. */
if ((coproc & 0xe) == 0xa)
- return thumb2_decode_ext_reg_ld_st (insn1, insn2, data);
+ return thumb2_decode_ext_reg_ld_st (insn1, insn2, visitor, data);
else /* coproc is not 101x. */
{
if (bit_4 == 0) /* STC/STC2. */
- return thumb_copy_unmodified_32bit (insn1, insn2, "stc/stc2",
- data);
+ return visitor->others (insn1, insn2, "stc/stc2", data);
else /* LDC/LDC2 {literal, immeidate}. */
- return thumb2_copy_copro_load_store (insn1, insn2, data);
+ return visitor->copro_load_store (insn1, insn2, data);
}
}
}
else
- return thumb_copy_unmodified_32bit (insn1, insn2, "coproc", data);
+ return visitor->others (insn1, insn2, "coproc", data);

return 0;
}
@@ -7387,6 +7414,7 @@ thumb_16bit_relocate_insn (uint16_t insn1, struct arm_insn_reloc_data *data)

static int
decode_thumb_32bit_ld_mem_hints (uint16_t insn1, uint16_t insn2,
+ struct thumb_32bit_insn_reloc_visitor *visitor,
struct arm_insn_reloc_data *data)
{
int rt = bits (insn2, 12, 15);
@@ -7400,32 +7428,29 @@ decode_thumb_32bit_ld_mem_hints (uint16_t insn1, uint16_t insn2,
{
if (rn == 0xf)
/* PLD literal or Encoding T3 of PLI(immediate, literal). */
- return thumb2_copy_preload (insn1, insn2, data);
+ return visitor->preload (insn1, insn2, data);
else
- return thumb_copy_unmodified_32bit (insn1, insn2, "pli/pld", data);
+ return visitor->others (insn1, insn2, "pli/pld", data);
}
else
{
if (rn == 0xf) /* LDRB/LDRSB (literal) */
- return thumb2_copy_load_literal (insn1, insn2, data, 1);
+ return visitor->load_literal (insn1, insn2, data, 1);
else
- return thumb_copy_unmodified_32bit (insn1, insn2,
- "ldrb{reg, immediate}/ldrbt",
- data);
+ return visitor->others (insn1, insn2, "ldrb{reg, immediate}/ldrbt",
+ data);
}

break;
case 1: /* Load halfword and memory hints. */
if (rt == 0xf) /* PLD{W} and Unalloc memory hint. */
- return thumb_copy_unmodified_32bit (insn1, insn2, "pld/unalloc memhint",
- data);
+ return visitor->others (insn1, insn2, "pld/unalloc memhint", data);
else
{
if (rn == 0xf)
- return thumb2_copy_load_literal (insn1, insn2, data, 2);
+ return visitor->load_literal (insn1, insn2, data, 2);
else
- return thumb_copy_unmodified_32bit (insn1, insn2, "ldrh/ldrht",
- data);
+ return visitor->others (insn1, insn2, "ldrh/ldrht", data);
}
break;
case 2: /* Load word */
@@ -7433,32 +7458,32 @@ decode_thumb_32bit_ld_mem_hints (uint16_t insn1, uint16_t insn2,
int insn2_bit_8_11 = bits (insn2, 8, 11);

if (rn == 0xf)
- return thumb2_copy_load_literal (insn1, insn2, data, 4);
+ return visitor->load_literal (insn1, insn2, data, 4);
else if (op1 == 0x1) /* Encoding T3 */
- return thumb2_copy_load_reg_imm (insn1, insn2, data, 0, 1);
+ return visitor->load_reg_imm (insn1, insn2, data, 0, 1);
else /* op1 == 0x0 */
{
if (insn2_bit_8_11 == 0xc || (insn2_bit_8_11 & 0x9) == 0x9)
/* LDR (immediate) */
- return thumb2_copy_load_reg_imm (insn1, insn2, data,
+ return visitor->load_reg_imm (insn1, insn2, data,
bit (insn2, 8), 1);
else if (insn2_bit_8_11 == 0xe) /* LDRT */
- return thumb_copy_unmodified_32bit (insn1, insn2, "ldrt", data);
+ return visitor->others (insn1, insn2, "ldrt", data);
else
/* LDR (register) */
- return thumb2_copy_load_reg_imm (insn1, insn2, data, 0, 0);
+ return visitor->load_reg_imm (insn1, insn2, data, 0, 0);
}
break;
}
default:
- return thumb_32bit_copy_undef (insn1, insn2, data);
- break;
+ return visitor->undef (insn1, insn2, data);
}
return 0;
}

static int
thumb_32bit_relocate_insn (uint16_t insn1, uint16_t insn2,
+ struct thumb_32bit_insn_reloc_visitor *visitor,
struct arm_insn_reloc_data *data)
{
int err = 0;
@@ -7477,24 +7502,22 @@ thumb_32bit_relocate_insn (uint16_t insn1, uint16_t insn2,
/* Load/store {dual, execlusive}, table branch. */
if (bits (insn1, 7, 8) == 1 && bits (insn1, 4, 5) == 1
&& bits (insn2, 5, 7) == 0)
- err = thumb2_copy_table_branch (insn1, insn2, data);
+ err = visitor->table_branch (insn1, insn2, data);
else
/* PC is not allowed to use in load/store {dual, exclusive}
instructions. */
- err = thumb_copy_unmodified_32bit (insn1, insn2,
- "load/store dual/ex",
- data);
+ err = visitor->others (insn1, insn2, "load/store dual/ex",
+ data);
}
else /* load/store multiple */
{
switch (bits (insn1, 7, 8))
{
case 0: case 3: /* SRS, RFE */
- err = thumb_copy_unmodified_32bit (insn1, insn2, "srs/rfe",
- data);
+ err = visitor->others (insn1, insn2, "srs/rfe", data);
break;
case 1: case 2: /* LDM/STM/PUSH/POP */
- err = thumb2_copy_block_xfer (insn1, insn2, data);
+ err = visitor->block_xfer (insn1, insn2, data);
break;
}
}
@@ -7502,10 +7525,10 @@ thumb_32bit_relocate_insn (uint16_t insn1, uint16_t insn2,

case 1:
/* Data-processing (shift register). */
- err = thumb2_decode_dp_shift_reg (insn1, insn2, data);
+ err = thumb2_decode_dp_shift_reg (insn1, insn2, visitor, data);
break;
default: /* Coprocessor instructions. */
- err = thumb2_decode_svc_copro (insn1, insn2, data);
+ err = thumb2_decode_svc_copro (insn1, insn2, visitor, data);
break;
}
break;
@@ -7516,9 +7539,9 @@ thumb_32bit_relocate_insn (uint16_t insn1, uint16_t insn2,
if (bit (insn2, 14) /* BLX/BL */
|| bit (insn2, 12) /* Unconditional branch */
|| (bits (insn1, 7, 9) != 0x7)) /* Conditional branch */
- err = thumb2_copy_b_bl_blx (insn1, insn2, data);
+ err = visitor->b_bl_blx (insn1, insn2, data);
else
- err = thumb_copy_unmodified_32bit (insn1, insn2, "misc ctrl", data);
+ err = visitor->others (insn1, insn2, "misc ctrl", data);
}
else
{
@@ -7527,12 +7550,12 @@ thumb_32bit_relocate_insn (uint16_t insn1, uint16_t insn2,
int op = bits (insn1, 4, 8);
int rn = bits (insn1, 0, 3);
if ((op == 0 || op == 0xa) && rn == 0xf)
- err = thumb_copy_pc_relative_32bit (insn1, insn2, data);
+ err = visitor->pc_relative_32bit (insn1, insn2, data);
else
- err = thumb_copy_unmodified_32bit (insn1, insn2, "dp/pb", data);
+ err = visitor->others (insn1, insn2, "dp/pb", data);
}
else /* Data processing (modified immeidate) */
- err = thumb_copy_unmodified_32bit (insn1, insn2, "dp/mi", data);
+ err = visitor->others (insn1, insn2, "dp/mi", data);
}
break;
case 3: /* op1 = 3 */
@@ -7540,30 +7563,27 @@ thumb_32bit_relocate_insn (uint16_t insn1, uint16_t insn2,
{
case 0:
if (bit (insn1, 4))
- err = decode_thumb_32bit_ld_mem_hints (insn1, insn2, data);
+ err = decode_thumb_32bit_ld_mem_hints (insn1, insn2, visitor, data);
else /* NEON Load/Store and Store single data item */
- err = thumb_copy_unmodified_32bit (insn1, insn2,
- "neon elt/struct load/store",
- data);
+ err = visitor->others (insn1, insn2, "neon elt/struct load/store",
+ data);
break;
case 1: /* op1 = 3, bits (9, 10) == 1 */
switch (bits (insn1, 7, 8))
{
case 0: case 1: /* Data processing (register) */
- err = thumb_copy_unmodified_32bit (insn1, insn2, "dp(reg)", data);
+ err = visitor->others (insn1, insn2, "dp(reg)", data);
break;
case 2: /* Multiply and absolute difference */
- err = thumb_copy_unmodified_32bit (insn1, insn2, "mul/mua/diff",
- data);
+ err = visitor->others (insn1, insn2, "mul/mua/diff", data);
break;
case 3: /* Long multiply and divide */
- err = thumb_copy_unmodified_32bit (insn1, insn2, "lmul/lmua",
- data);
+ err = visitor->others (insn1, insn2, "lmul/lmua", data);
break;
}
break;
default: /* Coprocessor instructions */
- err = thumb2_decode_svc_copro (insn1, insn2, data);
+ err = thumb2_decode_svc_copro (insn1, insn2, visitor, data);
break;
}
break;
@@ -7628,6 +7648,21 @@ static struct arm_insn_reloc_visitor arm_insn_reloc_visitor =
arm_copy_unpred,
};

+static struct thumb_32bit_insn_reloc_visitor thumb_32bit_insn_reloc_visitor =
+{
+ thumb2_copy_alu_imm,
+ thumb2_copy_b_bl_blx,
+ thumb2_copy_block_xfer,
+ thumb2_copy_copro_load_store,
+ thumb2_copy_load_literal,
+ thumb2_copy_load_reg_imm,
+ thumb_copy_unmodified_32bit,
+ thumb_copy_pc_relative_32bit,
+ thumb2_copy_preload,
+ thumb2_copy_table_branch,
+ thumb_32bit_copy_undef,
+};
+
void
arm_process_displaced_insn (struct gdbarch *gdbarch, CORE_ADDR from,
CORE_ADDR to, struct regcache *regs,
@@ -7681,8 +7716,11 @@ arm_process_displaced_insn (struct gdbarch *gdbarch, CORE_ADDR from,
{
uint16_t insn2
= read_memory_unsigned_integer (from + 2, 2, byte_order_for_code);
- err = thumb_32bit_relocate_insn (insn1, insn2, &reloc_data);
- }
+
+ err = thumb_32bit_relocate_insn (insn1, insn2,
+ &thumb_32bit_insn_reloc_visitor,
+ &reloc_data);
+ }
else
err = thumb_16bit_relocate_insn (insn1, &reloc_data);
}
--
2.8.1