Use aarch64_decode_insn in aarch64_analyze_prologue

This patch convert aarch64_analyze_prologue to using aarch64_decode_insn
to decode instructions.  After this change, aarch64_analyze_prologue
looks much simple, and some aarch64_decode_* functions are removed
accordingly.

gdb:

2015-11-05  Yao Qi  <yao.qi@linaro.org>

	* aarch64-tdep.c (extract_signed_bitfield): Remove.
	(decode_masked_match): Remove.
	(aarch64_decode_add_sub_imm): Remove.
	(aarch64_decode_br): Remove.
	(aarch64_decode_eret): Remove.
	(aarch64_decode_movz): Remove.
	(aarch64_decode_orr_shifted_register_x): Remove.
	(aarch64_decode_ret): Remove.
	(aarch64_decode_stp_offset): Remove.
	(aarch64_decode_stur): Remove.
	(aarch64_analyze_prologue): Call aarch64_decode_insn
	and use aarch64_inst to decode instructions.
This commit is contained in:
Yao Qi 2015-11-05 09:44:32 +00:00
parent 93d960127c
commit d9ebcbce29
2 changed files with 98 additions and 343 deletions

View File

@ -1,3 +1,18 @@
2015-11-05 Yao Qi <yao.qi@linaro.org>
* aarch64-tdep.c (extract_signed_bitfield): Remove.
(decode_masked_match): Remove.
(aarch64_decode_add_sub_imm): Remove.
(aarch64_decode_br): Remove.
(aarch64_decode_eret): Remove.
(aarch64_decode_movz): Remove.
(aarch64_decode_orr_shifted_register_x): Remove.
(aarch64_decode_ret): Remove.
(aarch64_decode_stp_offset): Remove.
(aarch64_decode_stur): Remove.
(aarch64_analyze_prologue): Call aarch64_decode_insn
and use aarch64_inst to decode instructions.
2015-11-05 Yao Qi <yao.qi@linaro.org>
* aarch64-tdep.c (aarch64_decode_stp_offset): New argument

View File

@ -194,302 +194,6 @@ show_aarch64_debug (struct ui_file *file, int from_tty,
fprintf_filtered (file, _("AArch64 debugging is %s.\n"), value);
}
/* Extract a signed value from a bit field within an instruction
encoding.
INSN is the instruction opcode.
WIDTH specifies the width of the bit field to extract (in bits).
OFFSET specifies the least significant bit of the field where bits
are numbered zero counting from least to most significant. */
static int32_t
extract_signed_bitfield (uint32_t insn, unsigned width, unsigned offset)
{
unsigned shift_l = sizeof (int32_t) * 8 - (offset + width);
unsigned shift_r = sizeof (int32_t) * 8 - width;
return ((int32_t) insn << shift_l) >> shift_r;
}
/* Determine if specified bits within an instruction opcode matches a
specific pattern.
INSN is the instruction opcode.
MASK specifies the bits within the opcode that are to be tested
agsinst for a match with PATTERN. */
static int
decode_masked_match (uint32_t insn, uint32_t mask, uint32_t pattern)
{
return (insn & mask) == pattern;
}
/* Decode an opcode if it represents an immediate ADD or SUB instruction.
ADDR specifies the address of the opcode.
INSN specifies the opcode to test.
RD receives the 'rd' field from the decoded instruction.
RN receives the 'rn' field from the decoded instruction.
Return 1 if the opcodes matches and is decoded, otherwise 0. */
static int
aarch64_decode_add_sub_imm (CORE_ADDR addr, uint32_t insn, unsigned *rd,
unsigned *rn, int32_t *imm)
{
if ((insn & 0x9f000000) == 0x91000000)
{
unsigned shift;
unsigned op_is_sub;
*rd = (insn >> 0) & 0x1f;
*rn = (insn >> 5) & 0x1f;
*imm = (insn >> 10) & 0xfff;
shift = (insn >> 22) & 0x3;
op_is_sub = (insn >> 30) & 0x1;
switch (shift)
{
case 0:
break;
case 1:
*imm <<= 12;
break;
default:
/* UNDEFINED */
return 0;
}
if (op_is_sub)
*imm = -*imm;
if (aarch64_debug)
{
debug_printf ("decode: 0x%s 0x%x add x%u, x%u, #%d\n",
core_addr_to_string_nz (addr), insn, *rd, *rn,
*imm);
}
return 1;
}
return 0;
}
/* Decode an opcode if it represents a branch via register instruction.
ADDR specifies the address of the opcode.
INSN specifies the opcode to test.
IS_BLR receives the 'op' bit from the decoded instruction.
RN receives the 'rn' field from the decoded instruction.
Return 1 if the opcodes matches and is decoded, otherwise 0. */
static int
aarch64_decode_br (CORE_ADDR addr, uint32_t insn, int *is_blr,
unsigned *rn)
{
/* 8 4 0 6 2 8 4 0 */
/* blr 110101100011111100000000000rrrrr */
/* br 110101100001111100000000000rrrrr */
if (decode_masked_match (insn, 0xffdffc1f, 0xd61f0000))
{
*is_blr = (insn >> 21) & 1;
*rn = (insn >> 5) & 0x1f;
if (aarch64_debug)
{
debug_printf ("decode: 0x%s 0x%x %s 0x%x\n",
core_addr_to_string_nz (addr), insn,
*is_blr ? "blr" : "br", *rn);
}
return 1;
}
return 0;
}
/* Decode an opcode if it represents a ERET instruction.
ADDR specifies the address of the opcode.
INSN specifies the opcode to test.
Return 1 if the opcodes matches and is decoded, otherwise 0. */
static int
aarch64_decode_eret (CORE_ADDR addr, uint32_t insn)
{
/* eret 1101 0110 1001 1111 0000 0011 1110 0000 */
if (insn == 0xd69f03e0)
{
if (aarch64_debug)
{
debug_printf ("decode: 0x%s 0x%x eret\n",
core_addr_to_string_nz (addr), insn);
}
return 1;
}
return 0;
}
/* Decode an opcode if it represents a MOVZ instruction.
ADDR specifies the address of the opcode.
INSN specifies the opcode to test.
RD receives the 'rd' field from the decoded instruction.
Return 1 if the opcodes matches and is decoded, otherwise 0. */
static int
aarch64_decode_movz (CORE_ADDR addr, uint32_t insn, unsigned *rd)
{
if (decode_masked_match (insn, 0xff800000, 0x52800000))
{
*rd = (insn >> 0) & 0x1f;
if (aarch64_debug)
{
debug_printf ("decode: 0x%s 0x%x movz x%u, #?\n",
core_addr_to_string_nz (addr), insn, *rd);
}
return 1;
}
return 0;
}
/* Decode an opcode if it represents a ORR (shifted register)
instruction.
ADDR specifies the address of the opcode.
INSN specifies the opcode to test.
RD receives the 'rd' field from the decoded instruction.
RN receives the 'rn' field from the decoded instruction.
RM receives the 'rm' field from the decoded instruction.
IMM receives the 'imm6' field from the decoded instruction.
Return 1 if the opcodes matches and is decoded, otherwise 0. */
static int
aarch64_decode_orr_shifted_register_x (CORE_ADDR addr, uint32_t insn,
unsigned *rd, unsigned *rn,
unsigned *rm, int32_t *imm)
{
if (decode_masked_match (insn, 0xff200000, 0xaa000000))
{
*rd = (insn >> 0) & 0x1f;
*rn = (insn >> 5) & 0x1f;
*rm = (insn >> 16) & 0x1f;
*imm = (insn >> 10) & 0x3f;
if (aarch64_debug)
{
debug_printf ("decode: 0x%s 0x%x orr x%u, x%u, x%u, #%u\n",
core_addr_to_string_nz (addr), insn, *rd, *rn,
*rm, *imm);
}
return 1;
}
return 0;
}
/* Decode an opcode if it represents a RET instruction.
ADDR specifies the address of the opcode.
INSN specifies the opcode to test.
RN receives the 'rn' field from the decoded instruction.
Return 1 if the opcodes matches and is decoded, otherwise 0. */
static int
aarch64_decode_ret (CORE_ADDR addr, uint32_t insn, unsigned *rn)
{
if (decode_masked_match (insn, 0xfffffc1f, 0xd65f0000))
{
*rn = (insn >> 5) & 0x1f;
if (aarch64_debug)
{
debug_printf ("decode: 0x%s 0x%x ret x%u\n",
core_addr_to_string_nz (addr), insn, *rn);
}
return 1;
}
return 0;
}
/* Decode an opcode if it represents the following instructions:
STP rt, rt2, [rn, #imm]
STP rt, rt2, [rn, #imm]!
ADDR specifies the address of the opcode.
INSN specifies the opcode to test.
RT1 receives the 'rt' field from the decoded instruction.
RT2 receives the 'rt2' field from the decoded instruction.
RN receives the 'rn' field from the decoded instruction.
IMM receives the 'imm' field from the decoded instruction.
*WBACK receives the bit 23 from the decoded instruction.
Return 1 if the opcodes matches and is decoded, otherwise 0. */
static int
aarch64_decode_stp_offset (CORE_ADDR addr, uint32_t insn, unsigned *rt1,
unsigned *rt2, unsigned *rn, int32_t *imm,
int *wback)
{
if (decode_masked_match (insn, 0xff400000, 0xa9000000))
{
*rt1 = (insn >> 0) & 0x1f;
*rn = (insn >> 5) & 0x1f;
*rt2 = (insn >> 10) & 0x1f;
*imm = extract_signed_bitfield (insn, 7, 15);
*imm <<= 3;
*wback = bit (insn, 23);
if (aarch64_debug)
{
debug_printf ("decode: 0x%s 0x%x stp x%u, x%u, [x%u + #%d]%s\n",
core_addr_to_string_nz (addr), insn, *rt1, *rt2,
*rn, *imm, *wback ? "" : "!");
}
return 1;
}
return 0;
}
/* Decode an opcode if it represents the following instruction:
STUR rt, [rn, #imm]
ADDR specifies the address of the opcode.
INSN specifies the opcode to test.
IS64 receives size field from the decoded instruction.
RT receives the 'rt' field from the decoded instruction.
RN receives the 'rn' field from the decoded instruction.
IMM receives the 'imm' field from the decoded instruction.
Return 1 if the opcodes matches and is decoded, otherwise 0. */
static int
aarch64_decode_stur (CORE_ADDR addr, uint32_t insn, int *is64,
unsigned *rt, unsigned *rn, int32_t *imm)
{
if (decode_masked_match (insn, 0xbfe00c00, 0xb8000000))
{
*is64 = (insn >> 30) & 1;
*rt = (insn >> 0) & 0x1f;
*rn = (insn >> 5) & 0x1f;
*imm = extract_signed_bitfield (insn, 9, 12);
if (aarch64_debug)
{
debug_printf ("decode: 0x%s 0x%x stur %c%u, [x%u + #%d]\n",
core_addr_to_string_nz (addr), insn,
*is64 ? 'x' : 'w', *rt, *rn, *imm);
}
return 1;
}
return 0;
}
/* Analyze a prologue, looking for a recognizable stack frame
and frame pointer. Scan until we encounter a store that could
clobber the stack frame unexpectedly, or an unknown instruction. */
@ -513,63 +217,82 @@ aarch64_analyze_prologue (struct gdbarch *gdbarch,
for (; start < limit; start += 4)
{
uint32_t insn;
unsigned rd;
unsigned rn;
unsigned rm;
unsigned rt;
unsigned rt1;
unsigned rt2;
int op_is_sub;
int wback;
int32_t imm;
unsigned cond;
int is64;
int is_link;
int is_cbnz;
int is_tbnz;
unsigned bit;
int is_adrp;
int32_t offset;
aarch64_inst inst;
insn = read_memory_unsigned_integer (start, 4, byte_order_for_code);
if (aarch64_decode_add_sub_imm (start, insn, &rd, &rn, &imm))
regs[rd] = pv_add_constant (regs[rn], imm);
else if (aarch64_decode_adr (start, insn, &is_adrp, &rd, &offset)
&& is_adrp)
regs[rd] = pv_unknown ();
else if (aarch64_decode_b (start, insn, &is_link, &offset))
if (aarch64_decode_insn (insn, &inst, 1) != 0)
break;
if (inst.opcode->iclass == addsub_imm
&& (inst.opcode->op == OP_ADD
|| strcmp ("sub", inst.opcode->name) == 0))
{
unsigned rd = inst.operands[0].reg.regno;
unsigned rn = inst.operands[1].reg.regno;
gdb_assert (aarch64_num_of_operands (inst.opcode) == 3);
gdb_assert (inst.operands[0].type == AARCH64_OPND_Rd_SP);
gdb_assert (inst.operands[1].type == AARCH64_OPND_Rn_SP);
gdb_assert (inst.operands[2].type == AARCH64_OPND_AIMM);
if (inst.opcode->op == OP_ADD)
{
regs[rd] = pv_add_constant (regs[rn],
inst.operands[2].imm.value);
}
else
{
regs[rd] = pv_add_constant (regs[rn],
-inst.operands[2].imm.value);
}
}
else if (inst.opcode->iclass == pcreladdr
&& inst.operands[1].type == AARCH64_OPND_ADDR_ADRP)
{
gdb_assert (aarch64_num_of_operands (inst.opcode) == 2);
gdb_assert (inst.operands[0].type == AARCH64_OPND_Rd);
regs[inst.operands[0].reg.regno] = pv_unknown ();
}
else if (inst.opcode->iclass == branch_imm)
{
/* Stop analysis on branch. */
break;
}
else if (aarch64_decode_bcond (start, insn, &cond, &offset))
else if (inst.opcode->iclass == condbranch)
{
/* Stop analysis on branch. */
break;
}
else if (aarch64_decode_br (start, insn, &is_link, &rn))
else if (inst.opcode->iclass == branch_reg)
{
/* Stop analysis on branch. */
break;
}
else if (aarch64_decode_cb (start, insn, &is64, &is_cbnz, &rn,
&offset))
else if (inst.opcode->iclass == compbranch)
{
/* Stop analysis on branch. */
break;
}
else if (aarch64_decode_eret (start, insn))
else if (inst.opcode->op == OP_MOVZ)
{
/* Stop analysis on branch. */
break;
gdb_assert (inst.operands[0].type == AARCH64_OPND_Rd);
regs[inst.operands[0].reg.regno] = pv_unknown ();
}
else if (aarch64_decode_movz (start, insn, &rd))
regs[rd] = pv_unknown ();
else if (aarch64_decode_orr_shifted_register_x (start, insn, &rd,
&rn, &rm, &imm))
else if (inst.opcode->iclass == log_shift
&& strcmp (inst.opcode->name, "orr") == 0)
{
if (imm == 0 && rn == 31)
unsigned rd = inst.operands[0].reg.regno;
unsigned rn = inst.operands[1].reg.regno;
unsigned rm = inst.operands[2].reg.regno;
gdb_assert (inst.operands[0].type == AARCH64_OPND_Rd);
gdb_assert (inst.operands[1].type == AARCH64_OPND_Rn);
gdb_assert (inst.operands[2].type == AARCH64_OPND_Rm_SFT);
if (inst.operands[2].shifter.amount == 0
&& rn == AARCH64_SP_REGNUM)
regs[rd] = regs[rm];
else
{
@ -582,19 +305,37 @@ aarch64_analyze_prologue (struct gdbarch *gdbarch,
break;
}
}
else if (aarch64_decode_ret (start, insn, &rn))
else if (inst.opcode->op == OP_STUR)
{
/* Stop analysis on branch. */
break;
}
else if (aarch64_decode_stur (start, insn, &is64, &rt, &rn, &offset))
{
pv_area_store (stack, pv_add_constant (regs[rn], offset),
unsigned rt = inst.operands[0].reg.regno;
unsigned rn = inst.operands[1].addr.base_regno;
int is64
= (aarch64_get_qualifier_esize (inst.operands[0].qualifier) == 8);
gdb_assert (aarch64_num_of_operands (inst.opcode) == 2);
gdb_assert (inst.operands[0].type == AARCH64_OPND_Rt);
gdb_assert (inst.operands[1].type == AARCH64_OPND_ADDR_SIMM9);
gdb_assert (!inst.operands[1].addr.offset.is_reg);
pv_area_store (stack, pv_add_constant (regs[rn],
inst.operands[1].addr.offset.imm),
is64 ? 8 : 4, regs[rt]);
}
else if (aarch64_decode_stp_offset (start, insn, &rt1, &rt2, &rn,
&imm, &wback))
else if ((inst.opcode->iclass == ldstpair_off
|| inst.opcode->iclass == ldstpair_indexed)
&& inst.operands[2].addr.preind
&& strcmp ("stp", inst.opcode->name) == 0)
{
unsigned rt1 = inst.operands[0].reg.regno;
unsigned rt2 = inst.operands[1].reg.regno;
unsigned rn = inst.operands[2].addr.base_regno;
int32_t imm = inst.operands[2].addr.offset.imm;
gdb_assert (inst.operands[0].type == AARCH64_OPND_Rt);
gdb_assert (inst.operands[1].type == AARCH64_OPND_Rt2);
gdb_assert (inst.operands[2].type == AARCH64_OPND_ADDR_SIMM7);
gdb_assert (!inst.operands[2].addr.offset.is_reg);
/* If recording this store would invalidate the store area
(perhaps because rn is not known) then we should abandon
further prologue analysis. */
@ -611,12 +352,11 @@ aarch64_analyze_prologue (struct gdbarch *gdbarch,
pv_area_store (stack, pv_add_constant (regs[rn], imm + 8), 8,
regs[rt2]);
if (wback)
if (inst.operands[2].addr.writeback)
regs[rn] = pv_add_constant (regs[rn], imm);
}
else if (aarch64_decode_tb (start, insn, &is_tbnz, &bit, &rn,
&offset))
else if (inst.opcode->iclass == testbranch)
{
/* Stop analysis on branch. */
break;