Skip to content

Commit

Permalink
i#1569 AArch64: Add incomplete encoder and decoder.
Browse files Browse the repository at this point in the history
This is a temporary solution: proper encoder and decoder will follow.

Branches and PC-relative instructions are recognised and decoded, but
nearly all other instructions are decoded as OP_xx. However, this will
be enough to run programs that do not use the stolen register, X28.

Review-URL: https://codereview.appspot.com/287480043
  • Loading branch information
egrimley-arm committed Mar 23, 2016
1 parent e09208e commit 66d0cc9
Show file tree
Hide file tree
Showing 2 changed files with 240 additions and 20 deletions.
146 changes: 131 additions & 15 deletions core/arch/aarch64/decode.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,19 +35,18 @@
#include "decode.h"
#include "decode_private.h"
#include "decode_fast.h" /* ensure we export decode_next_pc, decode_sizeof */
#include "instr_create.h"

bool
is_isa_mode_legal(dr_isa_mode_t mode)
{
ASSERT_NOT_IMPLEMENTED(false); /* FIXME i#1569 */
return false;
return (mode == DR_ISA_ARM_A64);
}

app_pc
canonicalize_pc_target(dcontext_t *dcontext, app_pc pc)
{
ASSERT_NOT_IMPLEMENTED(false); /* FIXME i#1569 */
return 0;
return pc;
}

DR_API
Expand All @@ -70,8 +69,8 @@ byte *
decode_eflags_usage(dcontext_t *dcontext, byte *pc, uint *usage,
dr_opnd_query_flags_t flags)
{
ASSERT_NOT_IMPLEMENTED(false); /* FIXME i#1569 */
return NULL;
*usage = 0; /* FIXME i#1569 */
return pc + 4;
}

byte *
Expand All @@ -81,11 +80,129 @@ decode_opcode(dcontext_t *dcontext, byte *pc, instr_t *instr)
return NULL;
}

/* FIXME i#1569: Very incomplete decoder: decode most instructions as OP_xx.
* Temporary solution until a proper (table-driven) decoder is implemented.
* SP (stack pointer) and ZR (zero register) may be confused.
*/
static byte *
decode_common(dcontext_t *dcontext, byte *pc, byte *orig_pc, instr_t *instr)
{
byte *next_pc = pc + 4;
uint enc = *(uint *)pc;

CLIENT_ASSERT(instr->opcode == OP_INVALID || instr->opcode == OP_UNDECODED,
"decode: instr is already decoded, may need to call instr_reset()");

if ((enc & 0x7c000000) == 0x14000000) {
instr_set_opcode(instr, TEST(1U << 31, enc) ? OP_bl : OP_b);
instr_set_num_opnds(dcontext, instr, 0, 1);
instr->src0 = opnd_create_pc(pc + ((enc & 0x1ffffff) << 2) -
((enc & 0x2000000) << 2));
}
else if ((enc & 0xff000010) == 0x54000000) {
instr_set_opcode(instr, OP_bcond);
instr_set_num_opnds(dcontext, instr, 0, 2);
instr->src0 = opnd_create_pc(pc + ((enc >> 5 & 0x3ffff) << 2) -
((enc >> 5 & 0x40000) << 2));
instr->srcs[0] = OPND_CREATE_INT8(enc & 15);
}
else if ((enc & 0x7e000000) == 0x34000000) {
instr_set_opcode(instr, TEST(1 << 24, enc) ? OP_cbnz : OP_cbz);
instr_set_num_opnds(dcontext, instr, 0, 2);
instr->src0 = opnd_create_pc(pc + ((enc >> 5 & 0x3ffff) << 2) -
((enc >> 5 & 0x40000) << 2));
instr->srcs[0] = opnd_create_reg((TEST(1U << 31, enc) ?
DR_REG_X0 : DR_REG_W0) +
(enc & 31));
}
else if ((enc & 0x7e000000) == 0x36000000) {
instr_set_opcode(instr, TEST(1 << 24, enc) ? OP_tbnz : OP_tbz);
instr_set_num_opnds(dcontext, instr, 0, 3);
instr->src0 = opnd_create_pc(pc + ((enc >> 5 & 0x1fff) << 2) -
((enc >> 5 & 0x2000) << 2));
instr->srcs[0] = opnd_create_reg(DR_REG_X0 + (enc & 31));
instr->srcs[1] = OPND_CREATE_INT8((enc >> 19 & 31) | (enc >> 26 & 32));
}
else if ((enc & 0xff9ffc1f) == 0xd61f0000 &&
(enc & 0x00600000) != 0x00600000) {
int op = enc >> 21 & 3;
instr_set_opcode(instr, (op == 0 ? OP_br : op == 1 ? OP_blr : OP_ret));
instr_set_num_opnds(dcontext, instr, 0, 1);
instr->src0 = opnd_create_reg(DR_REG_X0 + (enc >> 5 & 31));
}
else if ((enc & 0x1f000000) == 0x10000000) {
ptr_int_t off = (((enc >> 3 & 0xffffc) | (enc >> 29 & 3)) -
(ptr_int_t)(enc >> 3 & 0x100000));
ptr_int_t x = TEST(1U << 31, enc) ?
((ptr_int_t)pc >> 12 << 12) + (off << 12) :
(ptr_int_t)pc + off;
instr_set_opcode(instr, TEST(1U << 31, enc) ? OP_adrp : OP_adr);
instr_set_num_opnds(dcontext, instr, 1, 1);
instr->dsts[0] = opnd_create_reg(DR_REG_X0 + (enc & 31));
instr->src0 = opnd_create_rel_addr((void *)x, OPSZ_8);
}
else if ((enc & 0xbf000000) == 0x18000000) {
int offs = (enc >> 3 & 0xffffc) - (enc >> 3 & 0x100000);
instr_set_opcode(instr, OP_ldr);
instr_set_num_opnds(dcontext, instr, 1, 1);
instr->dsts[0] = opnd_create_reg((TEST(1 << 30, enc) ?
DR_REG_X0 : DR_REG_W0) + (enc & 31));
instr->src0 = opnd_create_rel_addr(pc + offs, OPSZ_8);
}
else if ((enc & 0x3f000000) == 0x1c000000 &&
(enc & 0xc0000000) != 0xc0000000) {
int opc = enc >> 30 & 3;
int offs = (enc >> 3 & 0xffffc) - (enc >> 3 & 0x100000);
instr_set_opcode(instr, OP_ldr);
instr_set_num_opnds(dcontext, instr, 1, 1);
instr->dsts[0] = opnd_create_reg((opc == 0 ? DR_REG_S0 :
opc == 1 ? DR_REG_D0 : DR_REG_Q0) +
(enc & 31));
instr->src0 = opnd_create_rel_addr(pc + offs,
opc == 0 ? OPSZ_4 :
opc == 1 ? OPSZ_8 : OPSZ_16);
}
else if ((enc & 0xffffffe0) == 0xd53bd040) {
instr_set_opcode(instr, OP_mrs);
/* XXX DR_REG_TPIDR_EL0 as source operand */
instr_set_num_opnds(dcontext, instr, 1, 0);
instr->dsts[0] = opnd_create_reg(DR_REG_X0 + (enc & 31));
}
else if ((enc & 0xffffffe0) == 0xd51bd040) {
instr_set_opcode(instr, OP_msr);
/* XXX DR_REG_TPIDR_EL0 as destination operand */
instr_set_num_opnds(dcontext, instr, 0, 1);
instr->src0 = opnd_create_reg(DR_REG_X0 + (enc & 31));
}
else {
instr_set_opcode(instr, OP_xx);
instr_set_num_opnds(dcontext, instr, 0, 1);
instr->src0 = OPND_CREATE_INT32(enc);
}

instr_set_operands_valid(instr, true);

if (orig_pc != pc) {
/* We do not want to copy when encoding and condone an invalid
* relative target.
*/
instr_set_raw_bits_valid(instr, false);
instr_set_translation(instr, orig_pc);
} else {
/* We set raw bits AFTER setting all srcs and dsts because setting
* a src or dst marks instr as having invalid raw bits.
*/
ASSERT(CHECK_TRUNCATE_TYPE_uint(next_pc - pc));
instr_set_raw_bits(instr, pc, (uint)(next_pc - pc));
}

return next_pc;
}

byte *
decode(dcontext_t *dcontext, byte *pc, instr_t *instr)
{
ASSERT_NOT_IMPLEMENTED(false); /* FIXME i#1569 */
return NULL;
return decode_common(dcontext, pc, pc, instr);
}

byte *
Expand All @@ -98,8 +215,7 @@ decode_from_copy(dcontext_t *dcontext, byte *copy_pc, byte *orig_pc, instr_t *in
byte *
decode_cti(dcontext_t *dcontext, byte *pc, instr_t *instr)
{
ASSERT_NOT_IMPLEMENTED(false); /* FIXME i#1569 */
return NULL;
return decode(dcontext, pc, instr);
}

byte *
Expand Down Expand Up @@ -127,15 +243,15 @@ decode_raw(dcontext_t *dcontext, byte *pc, instr_t *instr)
bool
decode_raw_is_jmp(dcontext_t *dcontext, byte *pc)
{
ASSERT_NOT_IMPLEMENTED(false); /* FIXME i#1569 */
return false;
uint enc = *(uint *)pc;
return ((enc & 0xfc000000) == 0x14000000);
}

byte *
decode_raw_jmp_target(dcontext_t *dcontext, byte *pc)
{
ASSERT_NOT_IMPLEMENTED(false); /* FIXME i#1569 */
return NULL;
uint enc = *(uint *)pc;
return pc + ((enc & 0x1ffffff) << 2) - ((enc & 0x2000000) << 2);
}

const instr_info_t *
Expand Down Expand Up @@ -221,7 +337,7 @@ check_encode_decode_consistency(dcontext_t *dcontext, instrlist_t *ilist)
void
decode_debug_checks_arch(void)
{
ASSERT_NOT_IMPLEMENTED(false); /* FIXME i#1569 */
/* FIXME i#1569: NYI */
}
#endif /* DEBUG */

Expand Down
114 changes: 109 additions & 5 deletions core/arch/aarch64/encode.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ const reg_id_t dr_reg_fixer[] = {
void
encode_debug_checks(void)
{
ASSERT_NOT_IMPLEMENTED(false); /* FIXME i#1569 */
/* FIXME i#1569: NYI */
}
#endif

Expand All @@ -74,19 +74,123 @@ decode_info_init_for_instr(decode_info_t *di, instr_t *instr)
ASSERT_NOT_IMPLEMENTED(false); /* FIXME i#1569 */
}

/* FIXME i#1569: Very incomplete encoder.
* Temporary solution until a proper (table-driven) encoder is implemented.
* SP (stack pointer) and ZR (zero register) may be confused.
*/
static uint encode_common(byte *pc, instr_t *i)
{
ASSERT(((ptr_int_t)pc & 3) == 0);
switch (i->opcode) {
case OP_b:
case OP_bl:
ASSERT(i->num_dsts == 0 && i->num_srcs == 1 &&
i->src0.kind == PC_kind);
return (0x14000000 | (uint)(i->opcode == OP_bl) << 31 |
(0x3ffffff & (uint)(i->src0.value.pc - pc) >> 2));
case OP_bcond:
ASSERT(i->num_dsts == 0 && i->num_srcs == 2 &&
i->src0.kind == PC_kind &&
i->srcs[0].kind == IMMED_INTEGER_kind);
return (0x54000000 |
(0x001fffff & (uint)(i->src0.value.pc - pc)) >> 2 << 5 |
(i->srcs[0].value.immed_int & 15));
case OP_cbnz:
case OP_cbz:
ASSERT(i->num_dsts == 0 && i->num_srcs == 2 &&
i->src0.kind == PC_kind &&
i->srcs[0].kind == REG_kind && i->srcs[0].size == 0 &&
((uint)(i->srcs[0].value.reg - DR_REG_W0) < 32 ||
(uint)(i->srcs[0].value.reg - DR_REG_X0) < 32));
return (0x34000000 | (i->opcode == OP_cbnz) << 24 |
(uint)((uint)(i->srcs[0].value.reg - DR_REG_X0) < 32) << 31 |
(0x001fffff & (uint)(i->src0.value.pc - pc)) >> 2 << 5 |
((i->srcs[0].value.reg - DR_REG_X0) < 32 ?
(i->srcs[0].value.reg - DR_REG_X0) :
(i->srcs[0].value.reg - DR_REG_W0)));
case OP_load:
ASSERT(i->num_dsts == 1 && i->num_srcs == 1 &&
i->dsts[0].kind == REG_kind && i->dsts[0].size == 0 &&
i->src0.kind == BASE_DISP_kind &&
(i->src0.size == OPSZ_4 || i->src0.size == OPSZ_8) &&
i->src0.value.base_disp.index_reg == DR_REG_NULL);
return ((i->src0.size == OPSZ_8 ? 0xf9400000 : 0xb9400000 ) |
(i->dsts[0].value.reg - DR_REG_X0) |
(i->src0.value.base_disp.base_reg - DR_REG_X0) << 5 |
i->src0.value.base_disp.disp >>
(i->src0.size == OPSZ_8 ? 3 : 2 ) << 10);
case OP_mov:
ASSERT(i->num_dsts == 1 && i->num_srcs == 1 &&
i->dsts[0].kind == REG_kind && i->dsts[0].size == 0 &&
i->src0.kind == REG_kind && i->src0.size == 0);
return (0xaa0003e0 |
(i->dsts[0].value.reg - DR_REG_X0) |
(i->src0.value.reg - DR_REG_X0) << 16);
case OP_store:
ASSERT(i->num_dsts == 1 && i->num_srcs == 1 &&
i->src0.kind == REG_kind && i->src0.size == 0 &&
i->dsts[0].kind == BASE_DISP_kind &&
(i->dsts[0].size == OPSZ_4 || i->dsts[0].size == OPSZ_8) &&
i->dsts[0].value.base_disp.index_reg == DR_REG_NULL);
return ((i->dsts[0].size == OPSZ_8 ? 0xf9000000 : 0xb9000000 ) |
(i->src0.value.reg - DR_REG_X0) |
(i->dsts[0].value.base_disp.base_reg - DR_REG_X0) << 5 |
i->dsts[0].value.base_disp.disp >>
(i->dsts[0].size == OPSZ_8 ? 3 : 2 ) << 10);
case OP_tbnz:
case OP_tbz:
ASSERT(i->num_dsts == 0 && i->num_srcs == 3 &&
i->src0.kind == PC_kind &&
i->srcs[0].kind == REG_kind && i->srcs[0].size == 0 &&
(uint)(i->srcs[0].value.reg - DR_REG_X0) < 32 &&
i->srcs[1].kind == IMMED_INTEGER_kind);
return (0x36000000 | (i->opcode == OP_tbnz) << 24 |
(0xffff & (uint)(i->src0.value.pc - pc)) >> 2 << 5 |
(i->srcs[0].value.reg - DR_REG_X0) |
(i->srcs[1].value.immed_int & 31) << 19 |
(i->srcs[1].value.immed_int & 32) << 26);
case OP_xx:
return i->src0.value.immed_int;

default:
ASSERT_NOT_IMPLEMENTED(false); /* FIXME i#1569 */
case OP_add:
case OP_svc:
/* FIXME i#1569: These are encoded but never executed. */
return i->opcode;
}
}

byte *
instr_encode_arch(dcontext_t *dcontext, instr_t *instr, byte *copy_pc, byte *final_pc,
bool check_reachable, bool *has_instr_opnds/*OUT OPTIONAL*/
_IF_DEBUG(bool assert_reachable))
{
ASSERT_NOT_IMPLEMENTED(false); /* FIXME i#1569 */
return NULL;
if (has_instr_opnds != NULL)
*has_instr_opnds = false;

if (instr_is_label(instr))
return copy_pc;

/* First, handle the already-encoded instructions */
if (instr_raw_bits_valid(instr)) {
CLIENT_ASSERT(check_reachable, "internal encode error: cannot encode raw "
"bits and ignore reachability");
/* Copy raw bits, possibly re-relativizing */
return copy_and_re_relativize_raw_instr(dcontext, instr, copy_pc, final_pc);
}
CLIENT_ASSERT(instr_operands_valid(instr), "instr_encode error: operands invalid");

*(uint *)copy_pc = encode_common(final_pc, instr);
return copy_pc + 4;
}

byte *
copy_and_re_relativize_raw_instr(dcontext_t *dcontext, instr_t *instr,
byte *dst_pc, byte *final_pc)
{
ASSERT_NOT_IMPLEMENTED(false); /* FIXME i#1569 */
return NULL;
/* FIXME i#1569: re-relativizing is NYI */
ASSERT(instr_raw_bits_valid(instr));
memcpy(dst_pc, instr->bytes, instr->length);
return dst_pc + instr->length;
}

0 comments on commit 66d0cc9

Please sign in to comment.