diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 1bcc4681498..9dcc31d9e91 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -192,6 +192,9 @@ elseif (ARM) arch/${ARCH_NAME}/table_t32_coproc.c arch/${ARCH_NAME}/table_t32_16.c arch/${ARCH_NAME}/table_t32_16_it.c) +elseif (AARCH64) + set(DECODER_SRCS ${DECODER_SRCS} + arch/${ARCH_NAME}/codec.c) endif () set(ARCH_SRCS diff --git a/core/arch/aarch64/codec.c b/core/arch/aarch64/codec.c new file mode 100644 index 00000000000..81775b0ced4 --- /dev/null +++ b/core/arch/aarch64/codec.c @@ -0,0 +1,870 @@ +/* ********************************************************** + * Copyright (c) 2016 ARM Limited. All rights reserved. + * **********************************************************/ + +/* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of ARM Limited nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL ARM LIMITED OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + */ + +#include "../globals.h" +#include "arch.h" +#include "decode.h" +#include "disassemble.h" +#include "instr.h" +#include "instr_create.h" + +#include "codec.h" + +/* The functions instr_set_0dst_0src, etc. could perhaps be moved to instr.h + * where instr_create_0dst_0src, etc. are declared. + */ + +static inline void +instr_set_0dst_0src(dcontext_t *dc, instr_t *instr, int op) +{ + instr_set_opcode(instr, op); + instr_set_num_opnds(dc, instr, 0, 0); +} + +static inline void +instr_set_0dst_1src(dcontext_t *dc, instr_t *instr, int op, + opnd_t src0) +{ + instr_set_opcode(instr, op); + instr_set_num_opnds(dc, instr, 0, 1); + instr_set_src(instr, 0, src0); +} + +static inline void +instr_set_0dst_2src(dcontext_t *dc, instr_t *instr, int op, + opnd_t src0, opnd_t src1) +{ + instr_set_opcode(instr, op); + instr_set_num_opnds(dc, instr, 0, 2); + instr_set_src(instr, 0, src0); + instr_set_src(instr, 1, src1); +} + +static inline void +instr_set_0dst_3src(dcontext_t *dc, instr_t *instr, int op, + opnd_t src0, opnd_t src1, opnd_t src2) +{ + instr_set_opcode(instr, op); + instr_set_num_opnds(dc, instr, 0, 3); + instr_set_src(instr, 0, src0); + instr_set_src(instr, 1, src1); + instr_set_src(instr, 2, src2); +} + +static inline void +instr_set_1dst_0src(dcontext_t *dc, instr_t *instr, int op, + opnd_t dst0) +{ + instr_set_opcode(instr, op); + instr_set_num_opnds(dc, instr, 1, 0); + instr_set_dst(instr, 0, dst0); +} + +static inline void +instr_set_1dst_1src(dcontext_t *dc, instr_t *instr, int op, + opnd_t dst0, opnd_t src0) +{ + instr_set_opcode(instr, op); + instr_set_num_opnds(dc, instr, 1, 1); + instr_set_dst(instr, 0, dst0); + instr_set_src(instr, 0, src0); +} + +static inline void +instr_set_1dst_2src(dcontext_t *dc, instr_t *instr, int op, + opnd_t dst0, opnd_t src0, opnd_t src1) +{ + instr_set_opcode(instr, op); + instr_set_num_opnds(dc, instr, 1, 2); + instr_set_dst(instr, 0, dst0); + instr_set_src(instr, 0, src0); + instr_set_src(instr, 1, src1); +} + +static inline void +instr_set_1dst_3src(dcontext_t *dc, instr_t *instr, int op, + opnd_t dst0, opnd_t src0, opnd_t src1, opnd_t src2) +{ + instr_set_opcode(instr, op); + instr_set_num_opnds(dc, instr, 1, 3); + instr_set_dst(instr, 0, dst0); + instr_set_src(instr, 0, src0); + instr_set_src(instr, 1, src1); + instr_set_src(instr, 2, src2); +} + +static inline void +instr_set_1dst_4src(dcontext_t *dc, instr_t *instr, int op, + opnd_t dst0, opnd_t src0, opnd_t src1, opnd_t src2, opnd_t src3) +{ + instr_set_opcode(instr, op); + instr_set_num_opnds(dc, instr, 1, 4); + instr_set_dst(instr, 0, dst0); + instr_set_src(instr, 0, src0); + instr_set_src(instr, 1, src1); + instr_set_src(instr, 2, src2); + instr_set_src(instr, 3, src3); +} + +static inline ptr_int_t +extract_int(uint enc, int pos, int len) +{ + uint u = ((enc >> pos & (((uint)1 << (len - 1)) - 1)) - + (enc >> pos & ((uint)1 << (len - 1)))); + return u << 1 < u ? -(ptr_int_t)~u - 1 : u; +} + +static inline ptr_uint_t +extract_uint(uint enc, int pos, int len) +{ + return enc >> pos & (((uint)1 << len) - 1); +} + +static inline bool +encode_imm(uint *imm, int bits, opnd_t opnd) +{ + ptr_int_t value; + if (!opnd_is_immed_int(opnd)) + return false; + value = opnd_get_immed_int(opnd); + if (!(0 <= value && value < (uint)1 << bits)) + return false; + *imm = value; + return true; +} + +static inline bool +encode_opnums(instr_t *i, int dsts, int srcs) +{ + return instr_num_dsts(i) == dsts && instr_num_srcs(i) == srcs; +} + +static inline bool +encode_pc_off(uint *poff, int bits, byte *pc, instr_t *instr, opnd_t opnd) +{ + ptr_uint_t off, range; + ASSERT(0 < bits && bits <= 32); + if (opnd.kind == PC_kind) + off = opnd.value.pc - pc; + else if (opnd.kind == INSTR_kind) + off = opnd_get_instr(opnd)->note - instr->note; + else + return false; + range = (ptr_uint_t)1 << bits; + if (TEST(~((range - 1) << 2), off + (range << 1))) + return false; + *poff = off >> 2 & (range - 1); + return true; +} + +static inline opnd_t +decode_sysreg(uint imm15) +{ + reg_t sysreg; + switch (imm15) { + case 0x5a10: sysreg = DR_REG_NZCV; break; + case 0x5a20: sysreg = DR_REG_FPCR; break; + case 0x5a21: sysreg = DR_REG_FPSR; break; + case 0x5e82: sysreg = DR_REG_TPIDR_EL0; break; + default: + return opnd_create_immed_uint(imm15, OPSZ_2); + } + return opnd_create_reg(sysreg); +} + +static inline bool +encode_sysreg(uint *imm15, opnd_t opnd) +{ + if (opnd_is_reg(opnd)) { + switch (opnd_get_reg(opnd)) { + case DR_REG_NZCV: *imm15 = 0x5a10; break; + case DR_REG_FPCR: *imm15 = 0x5a20; break; + case DR_REG_FPSR: *imm15 = 0x5a21; break; + case DR_REG_TPIDR_EL0: *imm15 = 0x5e82; break; + default: + return false; + } + return true; + } + if (opnd_is_immed_int(opnd)) { + uint imm; + if (encode_imm(&imm, 15, opnd) && !opnd_is_reg(decode_sysreg(imm))) { + *imm15 = imm; + return true; + } + return false; + } + return false; +} + +static inline opnd_t +decode_rreg(bool x, uint n, reg_t w31, reg_t x31) +{ + ASSERT(n < 32); + return opnd_create_reg(x ? + (n < 31 ? DR_REG_X0 + n : x31) : + (n < 31 ? DR_REG_W0 + n : w31)); +} + +static inline bool +encode_rreg(opnd_size_t *x, uint *r, opnd_t opnd, reg_t w31, reg_t x31) +{ + reg_id_t reg; + if (!opnd_is_reg(opnd)) + return false; + reg = opnd_get_reg(opnd); + if ((DR_REG_W0 <= reg && reg <= DR_REG_W30) || reg == w31) { + if (*x == OPSZ_NA) + *x = OPSZ_4; + else if (*x != OPSZ_4) + return false; + *r = (reg == w31) ? 31 : (reg - DR_REG_W0); + return true; + } + if ((DR_REG_X0 <= reg && reg <= DR_REG_X30) || reg == x31) { + if (*x == OPSZ_NA) + *x = OPSZ_8; + else if (*x != OPSZ_8) + return false; + *r = (reg == x31) ? 31 : (reg - DR_REG_X0); + return true; + } + return false; +} + +static inline opnd_t +decode_rregsp(bool x, uint n) +{ + return decode_rreg(x, n, DR_REG_WSP, DR_REG_XSP); +} + +static inline bool +encode_rregsp(opnd_size_t *x, uint *r, opnd_t opnd) +{ + return encode_rreg(x, r, opnd, DR_REG_WSP, DR_REG_XSP); +} + +static inline opnd_t +decode_rregz(bool x, uint n) +{ + return decode_rreg(x, n, DR_REG_WZR, DR_REG_XZR); +} + +static inline bool +encode_rregz(opnd_size_t *x, uint *r, opnd_t opnd) +{ + return encode_rreg(x, r, opnd, DR_REG_WZR, DR_REG_XZR); +} + +static inline opnd_t +decode_shift(uint sh) +{ + dr_shift_type_t type; + switch (sh) { + default: + ASSERT(false); + case 0: type = DR_SHIFT_LSL; break; + case 1: type = DR_SHIFT_LSR; break; + case 2: type = DR_SHIFT_ASR; break; + case 3: type = DR_SHIFT_ROR; break; + } + return opnd_create_immed_uint(type, OPSZ_2b); +} + +static inline bool +encode_shift(uint *sh, opnd_t opnd) +{ + ptr_int_t value; + if (!opnd_is_immed_int(opnd)) + return false; + value = opnd_get_immed_int(opnd); + switch (value) { + default: + return false; + case DR_SHIFT_LSL: *sh = 0; break; + case DR_SHIFT_LSR: *sh = 1; break; + case DR_SHIFT_ASR: *sh = 2; break; + case DR_SHIFT_ROR: *sh = 3; break; + } + return true; +} + +static inline bool +encode_vreg(opnd_size_t *x, uint *r, opnd_t opnd) +{ + reg_id_t reg; + opnd_size_t sz; + uint n; + if (!opnd_is_reg(opnd)) + return false; + reg = opnd_get_reg(opnd); + if ((uint)(reg - DR_REG_B0) < 32) { + n = reg - DR_REG_B0; + sz = OPSZ_1; + } else if ((uint)(reg - DR_REG_H0) < 32) { + n = reg - DR_REG_H0; + sz = OPSZ_2; + } else if ((uint)(reg - DR_REG_S0) < 32) { + n = reg - DR_REG_S0; + sz = OPSZ_4; + } else if ((uint)(reg - DR_REG_D0) < 32) { + n = reg - DR_REG_D0; + sz = OPSZ_8; + } else if ((uint)(reg - DR_REG_Q0) < 32) { + n = reg - DR_REG_Q0; + sz = OPSZ_16; + } else + return false; + if (*x == OPSZ_NA) + *x = sz; + else if (*x != sz) + return false; + *r = n; + return true; +} + +static inline bool +encode_xregsp_reg(uint *r, reg_t reg) +{ + if (DR_REG_X0 <= reg && reg <= DR_REG_X30) + *r = reg - DR_REG_X0; + else if (reg == DR_REG_XSP) + *r = 31; + else + return false; + return true; +} + +static inline opnd_t +decode_xregz(uint n) +{ + ASSERT(n < 32); + return opnd_create_reg(n < 31 ? DR_REG_X0 + n : DR_REG_XZR); +} + +static inline bool +encode_xregz(uint *r, opnd_t opnd) +{ + reg_id_t reg; + if (!opnd_is_reg(opnd)) + return false; + reg = opnd_get_reg(opnd); + if ((DR_REG_X0 <= reg && reg <= DR_REG_X30) || reg == DR_REG_XZR) { + *r = (reg == DR_REG_XZR) ? 31 : (reg - DR_REG_X0); + return true; + } + return false; +} + +static inline bool +encode_base_imm(opnd_size_t *x, uint *rn, uint *imm, int bits, bool signd, opnd_t opnd) +{ + uint reg; + if (opnd.kind == BASE_DISP_kind && + opnd.value.base_disp.index_reg == DR_REG_NULL && + encode_xregsp_reg(®, opnd.value.base_disp.base_reg) && + !TEST(opnd.value.base_disp.disp + (signd ? (ptr_uint_t)1 << (bits - 1) : 0), + ~(ptr_uint_t)0 << (bits - 1) << 1)) { + *x = opnd.size; + *rn = reg; + *imm = opnd.value.base_disp.disp; + return true; + } + return false; +} + +/******************************************************************************* + * Functions for decoding and encoding each "type" of instruction. + */ + +#define ENCFAIL (uint)0 /* a value that is not a valid instruction */ + +static inline bool +decode_add_imm(uint enc, dcontext_t *dc, byte *pc, instr_t *instr, int op) +{ + bool x = TEST(1U << 31, enc); + instr_set_1dst_4src(dc, instr, op, + decode_rregsp(x, enc & 31), + decode_rregsp(x, enc >> 5 & 31), + opnd_create_immed_uint(extract_uint(enc, 10, 12), OPSZ_4), + decode_shift(0), + opnd_create_immed_uint(extract_uint(enc, 22, 2) * 16, OPSZ_4)); + return true; +} + +static inline uint +encode_add_imm(byte *pc, instr_t *i, uint enc) +{ + uint rd, rn, imm12, shift_type, shift_amount; + opnd_size_t x = OPSZ_NA; + if (encode_opnums(i, 1, 4) && + encode_rregsp(&x, &rd, instr_get_dst(i, 0)) && + encode_rregsp(&x, &rn, instr_get_src(i, 0)) && + encode_imm(&imm12, 12, instr_get_src(i, 1)) && + encode_shift(&shift_type, instr_get_src(i, 2)) && + encode_imm(&shift_amount, 5, instr_get_src(i, 3)) && + shift_type == 0 && (shift_amount & 15) == 0) + return (enc | (uint)(x == OPSZ_8) << 31 | + rd | rn << 5 | imm12 << 10 | shift_amount >> 4 << 22); + return ENCFAIL; +} + +static inline bool +decode_adr(uint enc, dcontext_t *dc, byte *pc, instr_t *instr, int op) +{ + ptr_int_t off = (((enc >> 3 & 0xffffc) | (enc >> 29 & 3)) - + (ptr_int_t)(enc >> 3 & 0x100000)); + ptr_int_t x = op == OP_adrp ? + ((ptr_int_t)pc >> 12 << 12) + (off << 12) : + (ptr_int_t)pc + off; + instr_set_1dst_1src(dc, instr, op, + decode_xregz(enc & 31), + opnd_create_rel_addr((void *)x, OPSZ_8)); + return true; +} + +static inline uint +encode_adr(byte *pc, instr_t *i, uint enc) +{ + ASSERT_NOT_IMPLEMENTED(false); /* FIXME i#1569 */ + return ENCFAIL; +} + +static inline bool +decode_and_reg(uint enc, dcontext_t *dc, byte *pc, instr_t *instr, int op) +{ + bool x = TEST(1U << 31, enc); + uint imm6 = enc >> 10 & 63; + if (!x && imm6 >= 32) + return false; + instr_set_1dst_4src(dc, instr, op, + decode_rregz(x, enc & 31), + decode_rregz(x, enc >> 5 & 31), + decode_rregz(x, enc >> 16 & 31), + decode_shift(enc >> 22 & 3), + opnd_create_immed_uint(imm6, OPSZ_4)); + return true; +} + +static inline uint +encode_and_reg(byte *pc, instr_t *i, uint enc) +{ + uint rd, rn, rm, sh, imm6; + opnd_size_t x = OPSZ_NA; + if (encode_opnums(i, 1, 4) && + encode_rregz(&x, &rd, instr_get_dst(i, 0)) && + encode_rregz(&x, &rn, instr_get_src(i, 0)) && + encode_rregz(&x, &rm, instr_get_src(i, 1)) && + encode_shift(&sh, instr_get_src(i, 2)) && + encode_imm(&imm6, (x ? 6 : 5), instr_get_src(i, 3))) + return (enc | (uint)(x == OPSZ_8) << 31 | + rd | rn << 5 | rm << 16 | sh << 22 | imm6 << 10); + return ENCFAIL; +} + +static inline bool +decode_b(uint enc, dcontext_t *dc, byte *pc, instr_t *instr, int op) +{ + instr_set_0dst_1src(dc, instr, op, + opnd_create_pc(pc + extract_int(enc, 0, 26) * 4)); + return true; +} + +static inline uint +encode_b(byte *pc, instr_t *i, uint enc) +{ + uint off; + if (encode_opnums(i, 0, 1) && + encode_pc_off(&off, 26, pc, i, instr_get_src(i, 0))) + return (enc | (uint)(instr_get_opcode(i) == OP_bl) << 31 | off); + return ENCFAIL; +} + +static inline bool +decode_bcond(uint enc, dcontext_t *dc, byte *pc, instr_t *instr, int op) +{ + instr_set_0dst_1src(dc, instr, op, + opnd_create_pc(pc + extract_int(enc, 5, 19) * 4)); + instr_set_predicate(instr, enc & 15); + return true; +} + +static inline uint +encode_bcond(byte *pc, instr_t *i, uint enc) +{ + uint off; + if (encode_opnums(i, 0, 1) && + encode_pc_off(&off, 19, pc, i, instr_get_src(i, 0))) + return (enc | off << 5 | (instr_get_predicate(i) & 15)); + return ENCFAIL; +} + +static inline bool +decode_br(uint enc, dcontext_t *dc, byte *pc, instr_t *instr, int op) +{ + instr_set_0dst_1src(dc, instr, op, + decode_xregz(enc >> 5 & 31)); + return true; +} + +static inline uint +encode_br(byte *pc, instr_t *i, uint enc) +{ + ASSERT_NOT_IMPLEMENTED(false); /* FIXME i#1569 */ + return ENCFAIL; +} + +static inline bool +decode_cbz(uint enc, dcontext_t *dc, byte *pc, instr_t *instr, int op) +{ + instr_set_0dst_2src(dc, instr, op, + opnd_create_pc(pc + extract_int(enc, 5, 19) * 4), + decode_rregz(TEST(1U << 31, enc), enc & 31)); + return true; +} + +static inline uint +encode_cbz(byte *pc, instr_t *i, uint enc) +{ + opnd_size_t x = OPSZ_NA; + uint rt, off; + if (encode_opnums(i, 0, 2) && + encode_pc_off(&off, 19, pc, i, instr_get_src(i, 0)) && + encode_rregz(&x, &rt, instr_get_src(i, 1))) { + return (enc | (uint)(x == OPSZ_8) << 31 | off << 5 | rt); + } + return ENCFAIL; +} + +static inline bool +decode_ldr_imm(uint enc, dcontext_t *dc, byte *pc, instr_t *instr, int op) +{ + /* FIXME i#1569: NYI */ + return false; +} + +static inline uint +encode_ldr_imm(byte *pc, instr_t *i, uint enc) +{ + opnd_size_t x = OPSZ_NA; + opnd_size_t m = OPSZ_NA; + uint rt, xn, imm12; + if (encode_opnums(i, 1, 1) && + encode_rregz(&x, &rt, instr_get_dst(i, 0)) && + encode_base_imm(&m, &xn, &imm12, 12, false, instr_get_src(i, 0)) && + x == m && !TEST(opnd_size_in_bytes(m) - 1, imm12)) { + return (enc | (uint)(m == OPSZ_8) << 30 | + rt | xn << 5 | imm12 / opnd_size_in_bytes(m) << 10); + } + return ENCFAIL; +} + +static inline bool +decode_ldr_imm_simd(uint enc, dcontext_t *dc, byte *pc, instr_t *instr, int op) +{ + /* FIXME i#1569: NYI */ + return false; +} + +static inline uint +encode_ldr_imm_simd(byte *pc, instr_t *i, uint enc) +{ + opnd_size_t x = OPSZ_NA; + opnd_size_t m = OPSZ_NA; + uint vt, xn, imm12; + if (encode_opnums(i, 1, 1) && + encode_vreg(&x, &vt, instr_get_dst(i, 0)) && + opnd_size_in_bytes(x) >= 4 && + encode_base_imm(&m, &xn, &imm12, 12, false, instr_get_src(i, 0)) && + x == m && !TEST(opnd_size_in_bytes(m) - 1, imm12)) { + return (enc | (m == OPSZ_4 ? 0x80000000 : + m == OPSZ_8 ? 0xc0000000 : 0x00800000) | + vt | xn | imm12 / opnd_size_in_bytes(m) << 10); + } + return ENCFAIL; +} + +static inline bool +decode_ldr_literal(uint enc, dcontext_t *dc, byte *pc, instr_t *instr, int op) +{ + int offs = (enc >> 3 & 0xffffc) - (enc >> 3 & 0x100000); + instr_set_1dst_1src(dc, instr, op, + decode_rregz(TEST(1 << 30, enc), enc & 31), + opnd_create_rel_addr(pc + offs, OPSZ_8)); + return true; +} + +static inline uint +encode_ldr_literal(byte *pc, instr_t *i, uint enc) +{ + ASSERT_NOT_IMPLEMENTED(false); /* FIXME i#1569 */ + return ENCFAIL; +} + +static inline bool +decode_ldr_literal_simd(uint enc, dcontext_t *dc, byte *pc, instr_t *instr, int op) +{ + int opc = enc >> 30 & 3; + int offs = (enc >> 3 & 0xffffc) - (enc >> 3 & 0x100000); + if (opc == 3) + return false; + instr_set_1dst_1src(dc, instr, op, + opnd_create_reg((opc == 0 ? DR_REG_S0 : + opc == 1 ? DR_REG_D0 : DR_REG_Q0) + + (enc & 31)), + opnd_create_rel_addr(pc + offs, + opc == 0 ? OPSZ_4 : + opc == 1 ? OPSZ_8 : OPSZ_16)); + return true; +} + +static inline uint +encode_ldr_literal_simd(byte *pc, instr_t *i, uint enc) +{ + ASSERT_NOT_IMPLEMENTED(false); /* FIXME i#1569 */ + return ENCFAIL; +} + +static inline bool +decode_mrs(uint enc, dcontext_t *dc, byte *pc, instr_t *instr, int op) +{ + instr_set_1dst_1src(dc, instr, op, + decode_xregz(enc & 31), + decode_sysreg(enc >> 5 & 0x7fff)); + return true; +} + +static inline uint +encode_mrs(byte *pc, instr_t *i, uint enc) +{ + uint xt, imm15; + if (encode_opnums(i, 1, 1) && + encode_xregz(&xt, instr_get_dst(i, 0)) && + encode_sysreg(&imm15, instr_get_src(i, 0))) + return (enc | xt | imm15 << 5); + return ENCFAIL; +} + +static inline bool +decode_msr(uint enc, dcontext_t *dc, byte *pc, instr_t *instr, int op) +{ + opnd_t opnd = decode_sysreg(enc >> 5 & 0x7fff); + if (opnd_is_reg(opnd)) { + instr_set_1dst_1src(dc, instr, op, opnd, decode_xregz(enc & 31)); + return true; + } else { + instr_set_0dst_2src(dc, instr, op, decode_xregz(enc & 31), opnd); + return true; + } + return false; +} + +static inline uint +encode_msr(byte *pc, instr_t *i, uint enc) +{ + uint imm15, xt; + if (encode_opnums(i, 1, 1) && + opnd_is_reg(instr_get_dst(i, 0)) && + encode_sysreg(&imm15, instr_get_dst(i, 0)) && + encode_xregz(&xt, instr_get_src(i, 0))) + return (enc | xt | imm15 << 5); + if (encode_opnums(i, 0, 2) && + opnd_is_immed_int(instr_get_src(i, 1)) && + encode_xregz(&xt, instr_get_src(i, 0)) && + encode_sysreg(&imm15, instr_get_src(i, 1))) + return (enc | xt | imm15 << 5); + return ENCFAIL; +} + +static inline bool +decode_nop(uint enc, dcontext_t *dc, byte *pc, instr_t *instr, int op) +{ + instr_set_0dst_0src(dc, instr, op); + return true; +} + +static inline uint +encode_nop(byte *pc, instr_t *i, uint enc) +{ + if (encode_opnums(i, 0, 0)) + return enc; + return ENCFAIL; +} + +static inline bool +decode_str_imm(uint enc, dcontext_t *dc, byte *pc, instr_t *instr, int op) +{ + /* FIXME i#1569: NYI */ + return false; +} + +static inline uint +encode_str_imm(byte *pc, instr_t *i, uint enc) +{ + opnd_size_t x = OPSZ_NA; + opnd_size_t m = OPSZ_NA; + uint rt, xn, imm12; + if (encode_opnums(i, 1, 1) && + encode_base_imm(&m, &xn, &imm12, 12, false, instr_get_dst(i, 0)) && + encode_rregz(&x, &rt, instr_get_src(i, 0)) && + x == m && !TEST(opnd_size_in_bytes(m) - 1, imm12)) + return (enc | (uint)(m == OPSZ_8) << 30 | + rt | xn << 5 | imm12 / opnd_size_in_bytes(m) << 10); + return ENCFAIL; +} + +static inline bool +decode_strb_imm(uint enc, dcontext_t *dc, byte *pc, instr_t *instr, int op) +{ + /* FIXME i#1569: NYI */ + return false; +} + +static inline uint +encode_strb_imm(byte *pc, instr_t *i, uint enc) +{ + ASSERT_NOT_IMPLEMENTED(false); /* FIXME i#1569 */ + return ENCFAIL; +} + +static inline bool +decode_svc(uint enc, dcontext_t *dc, byte *pc, instr_t *instr, int op) +{ + instr_set_0dst_1src(dc, instr, op, + OPND_CREATE_INT16(enc >> 5 & 0xffff)); + return true; +} + +static inline uint +encode_svc(byte *pc, instr_t *i, uint enc) +{ + uint imm16; + if (encode_opnums(i, 0, 1) && + encode_imm(&imm16, 16, instr_get_src(i, 0))) + return (enc | imm16 << 5); + return ENCFAIL; +} + +static inline bool +decode_tbz(uint enc, dcontext_t *dc, byte *pc, instr_t *instr, int op) +{ + instr_set_0dst_3src(dc, instr, op, + opnd_create_pc(pc + extract_int(enc, 5, 14) * 4), + decode_xregz(enc & 31), + OPND_CREATE_INT8((enc >> 19 & 31) | (enc >> 26 & 32))); + return true; +} + +static inline uint +encode_tbz(byte *pc, instr_t *i, uint enc) +{ + uint xt, imm6, off; + if (encode_opnums(i, 0, 3) && + encode_pc_off(&off, 14, pc, i, instr_get_src(i, 0)) && + encode_xregz(&xt, instr_get_src(i, 1)) && + encode_imm(&imm6, 6, instr_get_src(i, 2))) + return (enc | (uint)(instr_get_opcode(i) == OP_tbnz) << 24 | off << 5 | xt | + (imm6 & 31) << 19 | (imm6 & 32) << 26); + return ENCFAIL; +} + +/******************************************************************************/ + +#include "codec_gen.h" + +/******************************************************************************/ + +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 (!decoder(enc, dcontext, orig_pc, instr)) { + /* We use OP_xx for instructions not yet handled by the decoder. + * If an A64 instruction accesses a general-purpose register + * (except X30) then the number of that register appears in one + * of four possible places in the instruction word, so we can + * pessimistically assume that an unrecognised instruction reads + * and writes all four of those registers, and this is + * sufficient to enable correct (though often excessive) mangling. + */ + instr_set_opcode(instr, OP_xx); + instr_set_num_opnds(dcontext, instr, 4, 5); + instr->src0 = OPND_CREATE_INT32(enc); + instr->srcs[0] = opnd_create_reg(DR_REG_X0 + (enc & 31)); + instr->dsts[0] = opnd_create_reg(DR_REG_X0 + (enc & 31)); + instr->srcs[1] = opnd_create_reg(DR_REG_X0 + (enc >> 5 & 31)); + instr->dsts[1] = opnd_create_reg(DR_REG_X0 + (enc >> 5 & 31)); + instr->srcs[2] = opnd_create_reg(DR_REG_X0 + (enc >> 10 & 31)); + instr->dsts[2] = opnd_create_reg(DR_REG_X0 + (enc >> 10 & 31)); + instr->srcs[3] = opnd_create_reg(DR_REG_X0 + (enc >> 16 & 31)); + instr->dsts[3] = opnd_create_reg(DR_REG_X0 + (enc >> 16 & 31)); + } + + 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; +} + +uint encode_common(byte *pc, instr_t *i) +{ + uint enc; + ASSERT(((ptr_int_t)pc & 3) == 0); + enc = encoder(pc, i); + if (enc != ENCFAIL) + return enc; + switch (instr_get_opcode(i)) { + case OP_xx: + ASSERT(instr_num_srcs(i) >= 1 && opnd_is_immed_int(instr_get_src(i, 0))); + return opnd_get_immed_int(instr_get_src(i, 0)); + } + ASSERT_NOT_IMPLEMENTED(false); /* FIXME i#1569 */ + return enc; +} diff --git a/core/arch/aarch64/codec.h b/core/arch/aarch64/codec.h new file mode 100644 index 00000000000..f2b62909188 --- /dev/null +++ b/core/arch/aarch64/codec.h @@ -0,0 +1,39 @@ +/* ********************************************************** + * Copyright (c) 2016 ARM Limited. All rights reserved. + * **********************************************************/ + +/* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of ARM Limited nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL ARM LIMITED OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + */ + +#ifndef CODEC_H +#define CODEC_H 1 + +byte *decode_common(dcontext_t *dcontext, byte *pc, byte *orig_pc, instr_t *instr); +uint encode_common(byte *pc, instr_t *i); + +#endif /* CODEC_H */ diff --git a/core/arch/aarch64/codec.py b/core/arch/aarch64/codec.py new file mode 100755 index 00000000000..4751534454a --- /dev/null +++ b/core/arch/aarch64/codec.py @@ -0,0 +1,226 @@ +#!/usr/bin/python + +# ********************************************************** +# Copyright (c) 2016 ARM Limited. All rights reserved. +# ********************************************************** + +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of ARM Limited nor the names of its contributors may be +# used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL ARM LIMITED OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +# DAMAGE. + +# This script reads "codec.txt" and generates "codec_gen.h" and "opcode.h". +# Run it manually, in this directory, when "codec.txt" has been changed. + +import re + +N = 32 # bits in an instruction word + +header = '/* This file was generated by codec.py from codec.txt. */\n\n' + +def encoding_to_str(enc): + return '%08x %08x %s %s' % enc + +def check(encodings): + tv = dict() + for i in range(len(encodings)): + if (encodings[i][0] & encodings[i][1]): + print 'Bad encoding:', encoding_to_str(encodings[i]) + raise Exception + if encodings[i][3] in tv: + if encodings[i][1] != tv[encodings[i][3]]: + print 'Inconsistent mask:', encoding_to_str(encodings[i]) + raise Exception + else: + tv[encodings[i][3]] = encodings[i][1] + for j in range(i): + if ((encodings[j][0] ^ encodings[i][0]) & + ~encodings[j][1] & ~encodings[i][1] == 0): + print 'Overlapping encodings:' + print encoding_to_str(encodings[j]) + print encoding_to_str(encodings[i]) + raise Exception + +def generate_decoder(encodings): + def gen(c, encs, depth): + indent = " " * depth + if len(encs) < 4: + for (f, v, m, t) in sorted(encs, key = lambda (f, v, m, t): (m, t, f, v)): + c.append('%sif ((enc & 0x%08x) == 0x%08x)' % + (indent, ((1 << N) - 1) & ~v, f)) + c.append('%s return decode_%s(enc, dc, pc, instr, OP_%s);' % + (indent, t, m)) + return + best_b = -1 + best_x = len(encs) + for b in range(N): + x0 = 0 + x1 = 0 + for (f, v, _, _) in encs: + if (1 << b) & (~f | v): + x0 += 1 + if (1 << b) & (f | v): + x1 += 1 + x = max(x0, x1) + if x < best_x: + best_b = b + best_x = x + c.append('%sif ((enc >> %d & 1) == 0) {' % (indent, best_b)) + encs0 = [] + encs1 = [] + for e in encs: + (f, v, _, _) = e + if (1 << best_b) & (~f | v): + encs0.append(e) + if (1 << best_b) & (f | v): + encs1.append(e) + gen(c, encs0, depth + 1) + c.append('%s} else {' % indent) + gen(c, encs1, depth + 1) + c.append('%s}' % indent) + + c = ['static bool', + 'decoder(uint enc, dcontext_t *dc, byte *pc, instr_t *instr)', + '{'] + gen(c, encodings, 1) + c.append(' return false;') + c.append('}') + return '\n'.join(c) + '\n' + +def generate_encoder(encodings): + case = dict() + for e in encodings: + (b, m, mn, f) = e + if not mn in case: + case[mn] = [] + case[mn].append(e) + c = ['static uint', + 'encoder(byte *pc, instr_t *i)', + '{', + ' uint enc;', + ' (void)enc;', + ' switch (i->opcode) {'] + for mn in sorted(case): + c.append(' case OP_%s:' % (mn)) + encs = sorted(case[mn], key = lambda (b, m, mn, f): (mn, f, b, m)) + enc1 = encs.pop() + for e in encs: + (b, m, mn, f) = e + c.append(' if ((enc = encode_%s(pc, i, 0x%08x)) != ENCFAIL)' % (f, b)) + c.append(' return enc;') + (b, m, mn, f) = enc1 + c.append(' return encode_%s(pc, i, 0x%08x);' % (f, b)) + c += [' }', + ' return ENCFAIL;', + '}'] + return '\n'.join(c) + '\n' + +def generate_opcodes(encodings): + mns = dict() + for e in encodings: + mns[e[2]] = 1 + c = ['#ifndef OPCODE_H', + '#define OPCODE_H 1', + '', + '/* DR_API EXPORT TOFILE dr_ir_opcodes_aarch64.h */', + '/* DR_API EXPORT BEGIN */', + '', + '/****************************************************************************', + ' * OPCODES', + ' */', + '/**', + ' * @file dr_ir_opcodes_aarch64.h', + ' * @brief Instruction opcode constants for AArch64.', + ' */', + '/** Opcode constants for use in the instr_t data structure. */', + 'enum {', + '/* 0 */ OP_INVALID, /* NULL, */ /**< INVALID opcode */', + '/* 1 */ OP_UNDECODED, /* NULL, */ /**< UNDECODED opcode */', + '/* 2 */ OP_CONTD, /* NULL, */ /**< CONTD opcode */', + '/* 3 */ OP_LABEL, /* NULL, */ /**< LABEL opcode */', + ''] + i = 4 + for mn in sorted(mns): + t = '/*%4d */ OP_%s,' % (i, mn) + t += ' ' * max(0, 34 - len(t)) + c.append(t + '/**< ARM %s opcode.*/' % mn) + i += 1 + c += ['', + ' OP_xx, /* placeholder for undecoded instructions */', + '', + ' OP_AFTER_LAST,', + ' OP_FIRST = OP_LABEL + 1, /**< First real opcode. */', + ' OP_LAST = OP_AFTER_LAST - 1, /**< Last real opcode. */', + '};', + '', + '/* alternative names */', + '#define OP_jmp OP_b ' + '/**< Platform-independent opcode name for jump. */', + '#define OP_jmp_short OP_b ' + '/**< Platform-independent opcode name for short jump. */', + '#define OP_load OP_ldr ' + '/**< Platform-independent opcode name for load. */', + '#define OP_store OP_str ' + '/**< Platform-independent opcode name for store. */', + '', + '/******************************' + '**********************************************/', + '/* DR_API EXPORT END */', + '', + '#endif /* OPCODE_H */'] + return '\n'.join(c) + '\n' + +def write_if_changed(file, data): + try: + if open(file, 'r').read() == data: + return + except IOError: + pass + open(file, 'w').write(data) + +def main(): + f = open('codec.txt', 'r') + encodings = [] + for line in f: + line = re.sub("\s*(#.*)?\n?$", "", line) + if line == '': + continue + x = line.split() + if (len(x) != 4): + print 'Wrong number of words:', x + raise Exception + if (not re.match("[0-9a-f]{8}$", x[0]) or + not re.match("[0-9a-f]{8}$", x[1])): + print 'Bad hex:', x[0], x[1] + raise Exception + encodings.append((int(x[0], 16), int(x[1], 16), x[2], x[3])) + check(encodings) + write_if_changed('codec_gen.h', + header + generate_decoder(encodings) + + '\n' + generate_encoder(encodings)) + write_if_changed('opcode.h', + header + generate_opcodes(encodings)) + +if __name__ == "__main__": + main() diff --git a/core/arch/aarch64/codec.txt b/core/arch/aarch64/codec.txt new file mode 100644 index 00000000000..60226351f36 --- /dev/null +++ b/core/arch/aarch64/codec.txt @@ -0,0 +1,71 @@ +# ********************************************************** +# Copyright (c) 2016 ARM Limited. All rights reserved. +# ********************************************************** + +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of ARM Limited nor the names of its contributors may be +# used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL ARM LIMITED OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +# DAMAGE. + +# Data read by "codec.py" and used to generate "codec_gen.h" and "opcode.h". +# After changing this file, run "codec.py" in this directory. + +# Columns are: +# - "fixed" : bits that are fixed for this encoding +# - "variable" : operand bits handled by encoder/decoder functions +# - "opcode" : mnemonic +# - "type" : name (suffix) of encoder/decoder functions +# +# Constraints: +# - Variable bits are zero in "fixed": (fixed & variable) == 0 +# - No overlaps: ((fixed_1 ^ fixed_2) & ~variable_1 & ~variable_2) != 0 +# - Consistent variable bits: type_1 != type_2 || variable_1 == variable_2 + +11000000 807fffff add add_imm +10000000 60ffffff adr adr +90000000 60ffffff adrp adr +14000000 03ffffff b b +54000000 00ffffef bcond bcond +94000000 03ffffff bl b +d63f0000 000003e0 blr br +d61f0000 000003e0 br br +d4200000 001fffe0 brk svc +35000000 80ffffff cbnz cbz +34000000 80ffffff cbz cbz +b9400000 403fffff ldr ldr_imm +3d400000 c0bfffff ldr ldr_imm_simd +18000000 40ffffff ldr ldr_literal +1c000000 c0ffffff ldr ldr_literal_simd +d5300000 000fffff mrs mrs +d5100000 000fffff msr msr +d503201f 00000000 nop nop +2a000000 80dfffff orr and_reg +d65f0000 000003e0 ret br +b9000000 403fffff str str_imm +39000000 003fffff strb strb_imm +79000000 003fffff strh strb_imm +51000000 807fffff sub add_imm +d4000001 001fffe0 svc svc +37000000 80ffffff tbnz tbz +36000000 80ffffff tbz tbz diff --git a/core/arch/aarch64/codec_gen.h b/core/arch/aarch64/codec_gen.h new file mode 100644 index 00000000000..ea1c38e867c --- /dev/null +++ b/core/arch/aarch64/codec_gen.h @@ -0,0 +1,192 @@ +/* This file was generated by codec.py from codec.txt. */ + +static bool +decoder(uint enc, dcontext_t *dc, byte *pc, instr_t *instr) +{ + if ((enc >> 24 & 1) == 0) { + if ((enc >> 25 & 1) == 0) { + if ((enc >> 31 & 1) == 0) { + if ((enc >> 26 & 1) == 0) { + if ((enc & 0x9f000000) == 0x10000000) + return decode_adr(enc, dc, pc, instr, OP_adr); + if ((enc & 0xbf000000) == 0x18000000) + return decode_ldr_literal(enc, dc, pc, instr, OP_ldr); + } else { + if ((enc >> 27 & 1) == 0) { + if ((enc & 0xfc000000) == 0x14000000) + return decode_b(enc, dc, pc, instr, OP_b); + if ((enc & 0xff000010) == 0x54000000) + return decode_bcond(enc, dc, pc, instr, OP_bcond); + if ((enc & 0x7f000000) == 0x34000000) + return decode_cbz(enc, dc, pc, instr, OP_cbz); + } else { + if ((enc & 0x3f000000) == 0x1c000000) + return decode_ldr_literal_simd(enc, dc, pc, instr, OP_ldr); + } + } + } else { + if ((enc >> 30 & 1) == 0) { + if ((enc >> 26 & 1) == 0) { + if ((enc & 0x9f000000) == 0x90000000) + return decode_adr(enc, dc, pc, instr, OP_adrp); + } else { + if ((enc & 0xfc000000) == 0x94000000) + return decode_b(enc, dc, pc, instr, OP_bl); + if ((enc & 0x7f000000) == 0x34000000) + return decode_cbz(enc, dc, pc, instr, OP_cbz); + if ((enc & 0x3f000000) == 0x1c000000) + return decode_ldr_literal_simd(enc, dc, pc, instr, OP_ldr); + } + } else { + if ((enc >> 0 & 1) == 0) { + if ((enc & 0x9f000000) == 0x90000000) + return decode_adr(enc, dc, pc, instr, OP_adrp); + if ((enc & 0xffe0001f) == 0xd4200000) + return decode_svc(enc, dc, pc, instr, OP_brk); + if ((enc & 0x3f000000) == 0x1c000000) + return decode_ldr_literal_simd(enc, dc, pc, instr, OP_ldr); + } else { + if ((enc & 0x9f000000) == 0x90000000) + return decode_adr(enc, dc, pc, instr, OP_adrp); + if ((enc & 0x3f000000) == 0x1c000000) + return decode_ldr_literal_simd(enc, dc, pc, instr, OP_ldr); + if ((enc & 0xffe0001f) == 0xd4000001) + return decode_svc(enc, dc, pc, instr, OP_svc); + } + } + } + } else { + if ((enc >> 30 & 1) == 0) { + if ((enc >> 29 & 1) == 0) { + if ((enc & 0xfc000000) == 0x14000000) + return decode_b(enc, dc, pc, instr, OP_b); + if ((enc & 0xfc000000) == 0x94000000) + return decode_b(enc, dc, pc, instr, OP_bl); + } else { + if ((enc & 0x7f200000) == 0x2a000000) + return decode_and_reg(enc, dc, pc, instr, OP_orr); + if ((enc & 0x7f000000) == 0x36000000) + return decode_tbz(enc, dc, pc, instr, OP_tbz); + } + } else { + if ((enc & 0xfffffc1f) == 0xd63f0000) + return decode_br(enc, dc, pc, instr, OP_blr); + if ((enc & 0xfffffc1f) == 0xd61f0000) + return decode_br(enc, dc, pc, instr, OP_br); + if ((enc & 0xfffffc1f) == 0xd65f0000) + return decode_br(enc, dc, pc, instr, OP_ret); + } + } + } else { + if ((enc >> 29 & 1) == 0) { + if ((enc >> 30 & 1) == 0) { + if ((enc & 0x7f800000) == 0x11000000) + return decode_add_imm(enc, dc, pc, instr, OP_add); + if ((enc & 0xfc000000) == 0x14000000) + return decode_b(enc, dc, pc, instr, OP_b); + if ((enc & 0xfc000000) == 0x94000000) + return decode_b(enc, dc, pc, instr, OP_bl); + } else { + if ((enc >> 20 & 1) == 0) { + if ((enc & 0xffffffff) == 0xd503201f) + return decode_nop(enc, dc, pc, instr, OP_nop); + if ((enc & 0x7f800000) == 0x51000000) + return decode_add_imm(enc, dc, pc, instr, OP_sub); + } else { + if ((enc & 0xfff00000) == 0xd5300000) + return decode_mrs(enc, dc, pc, instr, OP_mrs); + if ((enc & 0xfff00000) == 0xd5100000) + return decode_msr(enc, dc, pc, instr, OP_msr); + if ((enc & 0x7f800000) == 0x51000000) + return decode_add_imm(enc, dc, pc, instr, OP_sub); + } + } + } else { + if ((enc >> 26 & 1) == 0) { + if ((enc >> 31 & 1) == 0) { + if ((enc & 0xffc00000) == 0x39000000) + return decode_strb_imm(enc, dc, pc, instr, OP_strb); + if ((enc & 0xffc00000) == 0x79000000) + return decode_strb_imm(enc, dc, pc, instr, OP_strh); + } else { + if ((enc & 0xbfc00000) == 0xb9400000) + return decode_ldr_imm(enc, dc, pc, instr, OP_ldr); + if ((enc & 0xbfc00000) == 0xb9000000) + return decode_str_imm(enc, dc, pc, instr, OP_str); + } + } else { + if ((enc & 0x7f000000) == 0x35000000) + return decode_cbz(enc, dc, pc, instr, OP_cbnz); + if ((enc & 0x3f400000) == 0x3d400000) + return decode_ldr_imm_simd(enc, dc, pc, instr, OP_ldr); + if ((enc & 0x7f000000) == 0x37000000) + return decode_tbz(enc, dc, pc, instr, OP_tbnz); + } + } + } + return false; +} + +static uint +encoder(byte *pc, instr_t *i) +{ + uint enc; + (void)enc; + switch (i->opcode) { + case OP_add: + return encode_add_imm(pc, i, 0x11000000); + case OP_adr: + return encode_adr(pc, i, 0x10000000); + case OP_adrp: + return encode_adr(pc, i, 0x90000000); + case OP_b: + return encode_b(pc, i, 0x14000000); + case OP_bcond: + return encode_bcond(pc, i, 0x54000000); + case OP_bl: + return encode_b(pc, i, 0x94000000); + case OP_blr: + return encode_br(pc, i, 0xd63f0000); + case OP_br: + return encode_br(pc, i, 0xd61f0000); + case OP_brk: + return encode_svc(pc, i, 0xd4200000); + case OP_cbnz: + return encode_cbz(pc, i, 0x35000000); + case OP_cbz: + return encode_cbz(pc, i, 0x34000000); + case OP_ldr: + if ((enc = encode_ldr_imm(pc, i, 0xb9400000)) != ENCFAIL) + return enc; + if ((enc = encode_ldr_imm_simd(pc, i, 0x3d400000)) != ENCFAIL) + return enc; + if ((enc = encode_ldr_literal(pc, i, 0x18000000)) != ENCFAIL) + return enc; + return encode_ldr_literal_simd(pc, i, 0x1c000000); + case OP_mrs: + return encode_mrs(pc, i, 0xd5300000); + case OP_msr: + return encode_msr(pc, i, 0xd5100000); + case OP_nop: + return encode_nop(pc, i, 0xd503201f); + case OP_orr: + return encode_and_reg(pc, i, 0x2a000000); + case OP_ret: + return encode_br(pc, i, 0xd65f0000); + case OP_str: + return encode_str_imm(pc, i, 0xb9000000); + case OP_strb: + return encode_strb_imm(pc, i, 0x39000000); + case OP_strh: + return encode_strb_imm(pc, i, 0x79000000); + case OP_sub: + return encode_add_imm(pc, i, 0x51000000); + case OP_svc: + return encode_svc(pc, i, 0xd4000001); + case OP_tbnz: + return encode_tbz(pc, i, 0x37000000); + case OP_tbz: + return encode_tbz(pc, i, 0x36000000); + } + return ENCFAIL; +} diff --git a/core/arch/aarch64/decode.c b/core/arch/aarch64/decode.c index dea0616fe5f..d89a5dc6b99 100644 --- a/core/arch/aarch64/decode.c +++ b/core/arch/aarch64/decode.c @@ -33,9 +33,9 @@ #include "../globals.h" #include "instr.h" #include "decode.h" -#include "decode_private.h" #include "decode_fast.h" /* ensure we export decode_next_pc, decode_sizeof */ #include "instr_create.h" +#include "codec.h" bool is_isa_mode_legal(dr_isa_mode_t mode) @@ -80,145 +80,6 @@ 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, 1); - instr->src0 = opnd_create_pc(pc + ((enc >> 5 & 0x3ffff) << 2) - - ((enc >> 5 & 0x40000) << 2)); - instr_set_predicate(instr, enc & 0xf); - } - 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 if ((enc & 0xffe0001f) == 0xd4000001) { - instr_set_opcode(instr, OP_svc); - instr_set_num_opnds(dcontext, instr, 0, 1); - instr->src0 = OPND_CREATE_INT16(enc >> 5 & 0xffff); - } else { - /* We use OP_xx for instructions not yet handled by the decoder. - * If an A64 instruction accesses a general-purpose register - * (except X30) then the number of that register appears in one - * of four possible places in the instruction word, so we can - * pessimistically assume that an unrecognised instruction reads - * and writes all four of those registers, and this is - * sufficient to enable correct (though often excessive) mangling. - */ - instr_set_opcode(instr, OP_xx); - instr_set_num_opnds(dcontext, instr, 4, 5); - instr->src0 = OPND_CREATE_INT32(enc); - instr->srcs[0] = opnd_create_reg(DR_REG_X0 + (enc & 31)); - instr->dsts[0] = opnd_create_reg(DR_REG_X0 + (enc & 31)); - instr->srcs[1] = opnd_create_reg(DR_REG_X0 + (enc >> 5 & 31)); - instr->dsts[1] = opnd_create_reg(DR_REG_X0 + (enc >> 5 & 31)); - instr->srcs[2] = opnd_create_reg(DR_REG_X0 + (enc >> 10 & 31)); - instr->dsts[2] = opnd_create_reg(DR_REG_X0 + (enc >> 10 & 31)); - instr->srcs[3] = opnd_create_reg(DR_REG_X0 + (enc >> 16 & 31)); - instr->dsts[3] = opnd_create_reg(DR_REG_X0 + (enc >> 16 & 31)); - } - - 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) { diff --git a/core/arch/aarch64/disassemble.c b/core/arch/aarch64/disassemble.c index c662bdb3d40..85b9b0eaa31 100644 --- a/core/arch/aarch64/disassemble.c +++ b/core/arch/aarch64/disassemble.c @@ -34,7 +34,6 @@ #include "arch.h" #include "instr.h" #include "decode.h" -#include "decode_private.h" #include "disassemble.h" #include diff --git a/core/arch/aarch64/emit_utils.c b/core/arch/aarch64/emit_utils.c index a97bf6ba3d9..1eb596c2146 100644 --- a/core/arch/aarch64/emit_utils.c +++ b/core/arch/aarch64/emit_utils.c @@ -328,8 +328,8 @@ insert_load_dr_tls_base(dcontext_t *dcontext, instrlist_t *ilist, instr_t *where /* Load TLS base from user-mode thread pointer/ID register: * mrs reg_base, tpidr_el0 */ - PRE(ilist, where, INSTR_CREATE_xx(dcontext, - 0xd53bd040 | (reg_base - DR_REG_X0))); + PRE(ilist, where, INSTR_CREATE_mrs(dcontext, opnd_create_reg(reg_base), + opnd_create_reg(DR_REG_TPIDR_EL0))); /* ldr dr_reg_stolen, [reg_base, DR_TLS_BASE_OFFSET] */ PRE(ilist, where, INSTR_CREATE_xx(dcontext, 0xf9400000 | (dr_reg_stolen - DR_REG_X0) | @@ -352,7 +352,8 @@ append_fcache_enter_prologue(dcontext_t *dcontext, instrlist_t *ilist, bool abso /* Grab gen routine's parameter dcontext and put it into REG_DCXT: * mov x(dxct), x0 */ - APP(ilist, INSTR_CREATE_xx(dcontext, 0xaa0003e0 | (REG_DCXT - DR_REG_X0))); + APP(ilist, XINST_CREATE_move(dcontext, opnd_create_reg(REG_DCXT), + opnd_create_reg(DR_REG_X0))); /* set up stolen reg */ insert_load_dr_tls_base(dcontext, ilist, NULL/*append*/, SCRATCH_REG0); } @@ -371,9 +372,12 @@ append_restore_xflags(dcontext_t *dcontext, instrlist_t *ilist, bool absolute) APP(ilist, RESTORE_FROM_DC(dcontext, DR_REG_W0, XFLAGS_OFFSET)); APP(ilist, RESTORE_FROM_DC(dcontext, DR_REG_W1, XFLAGS_OFFSET + 4)); APP(ilist, RESTORE_FROM_DC(dcontext, DR_REG_W2, XFLAGS_OFFSET + 8)); - APP(ilist, INSTR_CREATE_xx(dcontext, 0xd51b4200)); /* msr nzcv,x0 */ - APP(ilist, INSTR_CREATE_xx(dcontext, 0xd51b4401)); /* msr fpcr,x1 */ - APP(ilist, INSTR_CREATE_xx(dcontext, 0xd51b4422)); /* msr fpsr,x2 */ + APP(ilist, INSTR_CREATE_msr(dcontext, opnd_create_reg(DR_REG_NZCV), + opnd_create_reg(DR_REG_X0))); + APP(ilist, INSTR_CREATE_msr(dcontext, opnd_create_reg(DR_REG_FPCR), + opnd_create_reg(DR_REG_X1))); + APP(ilist, INSTR_CREATE_msr(dcontext, opnd_create_reg(DR_REG_FPSR), + opnd_create_reg(DR_REG_X2))); } /* dcontext is in REG_DCXT; other registers can be used as scratch. @@ -514,9 +518,12 @@ append_save_simd_reg(dcontext_t *dcontext, instrlist_t *ilist, bool absolute) void append_save_clear_xflags(dcontext_t *dcontext, instrlist_t *ilist, bool absolute) { - APP(ilist, INSTR_CREATE_xx(dcontext, 0xd53b4201)); /* mrs x1, nzcv */ - APP(ilist, INSTR_CREATE_xx(dcontext, 0xd53b4402)); /* mrs x2, fpcr */ - APP(ilist, INSTR_CREATE_xx(dcontext, 0xd53b4423)); /* mrs x3, fpsr */ + APP(ilist, INSTR_CREATE_mrs(dcontext, opnd_create_reg(DR_REG_X1), + opnd_create_reg(DR_REG_NZCV))); + APP(ilist, INSTR_CREATE_mrs(dcontext, opnd_create_reg(DR_REG_X2), + opnd_create_reg(DR_REG_FPCR))); + APP(ilist, INSTR_CREATE_mrs(dcontext, opnd_create_reg(DR_REG_X3), + opnd_create_reg(DR_REG_FPSR))); APP(ilist, SAVE_TO_DC(dcontext, DR_REG_W1, XFLAGS_OFFSET)); APP(ilist, SAVE_TO_DC(dcontext, DR_REG_W2, XFLAGS_OFFSET + 4)); APP(ilist, SAVE_TO_DC(dcontext, DR_REG_W3, XFLAGS_OFFSET + 8)); diff --git a/core/arch/aarch64/encode.c b/core/arch/aarch64/encode.c index e39872acee3..9e5ea9117cf 100644 --- a/core/arch/aarch64/encode.c +++ b/core/arch/aarch64/encode.c @@ -35,7 +35,7 @@ #include "instr.h" #include "decode.h" #include "disassemble.h" -#include "decode_private.h" +#include "codec.h" /* Extra logging for encoding */ #define ENC_LEVEL 6 @@ -107,121 +107,6 @@ 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) -{ - ptr_uint_t off; - 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 == 1 && - i->src0.kind == PC_kind); - return (0x54000000 | - (0x001fffff & (uint)(i->src0.value.pc - pc)) >> 2 << 5 | - (instr_get_predicate(i) & 0xf)); - case OP_cbnz: - case OP_cbz: - ASSERT(i->num_dsts == 0 && i->num_srcs == 2 && - (i->src0.kind == PC_kind || i->src0.kind == INSTR_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)); - off = ((i->src0.kind == PC_kind) ? - (uint)(i->src0.value.pc - pc) : - (ptr_int_t)(opnd_get_instr(i->src0)->note - i->note)); - return (0x34000000 | (i->opcode == OP_cbnz) << 24 | - (uint)((uint)(i->srcs[0].value.reg - DR_REG_X0) < 32) << 31 | - (0x001fffff & off) >> 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.value.base_disp.index_reg == DR_REG_NULL); - if (reg_is_gpr(i->dsts[0].value.reg)) { - uint rt = (i->dsts[0].value.reg - - (i->src0.size == OPSZ_8 ? DR_REG_X0 : DR_REG_W0)); - ASSERT(i->src0.size == OPSZ_4 || i->src0.size == OPSZ_8); - ASSERT(rt < 31); - return ((i->src0.size == OPSZ_8 ? 0xf9400000 : 0xb9400000 ) | - rt | - (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); - } else { - uint rt = (i->dsts[0].value.reg - - (i->src0.size == OPSZ_4 ? DR_REG_S0 : - i->src0.size == OPSZ_8 ? DR_REG_D0 : DR_REG_Q0)); - ASSERT(i->src0.size == OPSZ_4 || i->src0.size == OPSZ_8 || - i->src0.size == OPSZ_16); - ASSERT(rt < 32); - return ((i->src0.size == OPSZ_4 ? 0xbd400000 : - i->src0.size == OPSZ_8 ? 0xfd400000 : 0x3dc00000) | - rt | - (i->src0.value.base_disp.base_reg - DR_REG_X0) << 5 | - i->src0.value.base_disp.disp >> - (i->src0.size == OPSZ_4 ? 2 : - i->src0.size == OPSZ_8 ? 3 : 4 ) << 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_svc: - ASSERT(i->num_dsts == 0 && i->num_srcs == 1 && - i->src0.kind == IMMED_INTEGER_kind); - return (0xd4000001 | (i->src0.value.immed_int & 0xffff) << 5); - case OP_tbnz: - case OP_tbz: - ASSERT(i->num_dsts == 0 && i->num_srcs == 3 && - (i->src0.kind == PC_kind || i->src0.kind == INSTR_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); - off = ((i->src0.kind == PC_kind) ? - (uint)(i->src0.value.pc - pc) : - (ptr_int_t)(opnd_get_instr(i->src0)->note - i->note)); - return (0x36000000 | (i->opcode == OP_tbnz) << 24 | - (0xffff & off) >> 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: - /* 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*/ diff --git a/core/arch/aarch64/instr.c b/core/arch/aarch64/instr.c index 0e69e4e51ad..c6c78fd26b0 100644 --- a/core/arch/aarch64/instr.c +++ b/core/arch/aarch64/instr.c @@ -311,17 +311,18 @@ instr_create_nbyte_nop(dcontext_t *dcontext, uint num_bytes, bool raw) bool instr_reads_thread_register(instr_t *instr) { - /* FIXME i#1569: Handle MRS instances other than MRS Xt, TPIDR_EL0. */ - int opcode = instr_get_opcode(instr); - return (opcode == OP_mrs); + return (instr_get_opcode(instr) == OP_mrs && + opnd_is_reg(instr_get_src(instr, 0)) && + opnd_get_reg(instr_get_src(instr, 0)) == DR_REG_TPIDR_EL0); } bool instr_writes_thread_register(instr_t *instr) { - /* FIXME i#1569: Handle MSR instances other than MSR TPIDR_EL0, Xt. */ - int opcode = instr_get_opcode(instr); - return (opcode == OP_msr); + return (instr_get_opcode(instr) == OP_msr && + instr_num_dsts(instr) == 1 && + opnd_is_reg(instr_get_dst(instr, 0)) && + opnd_get_reg(instr_get_dst(instr, 0)) == DR_REG_TPIDR_EL0); } DR_API diff --git a/core/arch/aarch64/instr_create.h b/core/arch/aarch64/instr_create.h index 0ad37d3389a..959117388ad 100644 --- a/core/arch/aarch64/instr_create.h +++ b/core/arch/aarch64/instr_create.h @@ -65,7 +65,7 @@ * \param dc The void * dcontext used to allocate memory for the instr_t. */ #define XINST_CREATE_debug_instr(dc) \ - INSTR_CREATE_brk((dc), OPND_CREATE_INT16(1)) + INSTR_CREATE_brk((dc), OPND_CREATE_INT16(0)) /** * This platform-independent macro creates an instr_t for a 4-byte @@ -101,7 +101,15 @@ * \param d The destination register opnd. * \param s The source register opnd. */ -#define XINST_CREATE_move(dc, d, s) INSTR_CREATE_mov((dc), (d), (s)) +#define XINST_CREATE_move(dc, d, s) \ + ((opnd_get_reg(d) == DR_REG_XSP || opnd_get_reg(s) == DR_REG_XSP || \ + opnd_get_reg(d) == DR_REG_WSP || opnd_get_reg(s) == DR_REG_WSP) ? \ + instr_create_1dst_4src((dc), OP_add, (d), (s), \ + OPND_CREATE_INT16(0), \ + OPND_CREATE_INT8(DR_SHIFT_LSL), OPND_CREATE_INT8(0)) : \ + instr_create_1dst_4src((dc), OP_orr, (d), \ + opnd_create_reg(opnd_get_size(d) == OPSZ_8 ? DR_REG_XZR : DR_REG_WZR), \ + (s), OPND_CREATE_INT8(DR_SHIFT_LSL), OPND_CREATE_INT8(0))) /** * This platform-independent macro creates an instr_t for a multimedia @@ -128,7 +136,8 @@ * \param r The destination register opnd. * \param i The source immediate integer opnd. */ -#define XINST_CREATE_load_int(dc, r, i) INSTR_CREATE_mov((dc), (r), (i)) +#define XINST_CREATE_load_int(dc, r, i) \ + ((void)(r), (void)(i), INSTR_CREATE_xx((dc), 0xf36d19)) /* FIXME i#1569 */ /** * This platform-independent macro creates an instr_t for a return instruction. @@ -176,7 +185,9 @@ * \param d The opnd_t explicit destination operand for the instruction. * \param s The opnd_t explicit source operand for the instruction. */ -#define XINST_CREATE_add(dc, d, s) INSTR_CREATE_add((dc), (d), (d), (s)) +#define XINST_CREATE_add(dc, d, s) \ + INSTR_CREATE_add((dc), (d), (d), (s), \ + OPND_CREATE_INT8(DR_SHIFT_LSL), OPND_CREATE_INT8(0)) /** * This platform-independent macro creates an instr_t for an addition @@ -190,7 +201,8 @@ * can be either a register or an immediate integer. */ #define XINST_CREATE_add_2src(dc, d, s1, s2) \ - INSTR_CREATE_add((dc), (d), (s1), (s2)) + INSTR_CREATE_add((dc), (d), (s1), (s2), \ + OPND_CREATE_INT8(DR_SHIFT_LSL), OPND_CREATE_INT8(0)) /** * This platform-independent macro creates an instr_t for a subtraction @@ -211,21 +223,20 @@ * Manually-added ARM-specific INSTR_CREATE_* macros */ -#define INSTR_CREATE_add(dc, Rd, Rn, Rm_or_imm) \ - (opnd_is_reg(Rm_or_imm) ? \ - INSTR_CREATE_add_shimm((dc), (Rd), (Rn), (Rm_or_imm), \ - OPND_CREATE_INT8(DR_SHIFT_NONE), OPND_CREATE_INT8(0)) : \ - instr_create_1dst_2src((dc), OP_add, (Rd), (Rn), (Rm_or_imm))) +#define INSTR_CREATE_add(dc, Rd, Rn, Rm_or_imm, sht, sha) \ + instr_create_1dst_4src((dc), OP_add, (Rd), (Rn), (Rm_or_imm), (sht), (sha)) #define INSTR_CREATE_b(dc, pc) \ instr_create_0dst_1src((dc), OP_b, (pc)) #define INSTR_CREATE_br(dc, Xn) \ instr_create_0dst_1src((dc), OP_br, (Xn)) #define INSTR_CREATE_brk(dc, imm) \ instr_create_0dst_1src((dc), OP_brk, (imm)) +#define INSTR_CREATE_cbnz(dc, pc, reg) \ + instr_create_0dst_2src((dc), OP_cbnz, (pc), (reg)) +#define INSTR_CREATE_cbz(dc, pc, reg) \ + instr_create_0dst_2src((dc), OP_cbz, (pc), (reg)) #define INSTR_CREATE_ldr(dc, Rd, mem) \ instr_create_1dst_1src((dc), OP_ldr, (Rd), (mem)) -#define INSTR_CREATE_mov(dc, Rd, Rm_or_imm) \ - instr_create_1dst_1src((dc), OP_mov, (Rd), (Rm_or_imm)) #define INSTR_CREATE_mrs(dc, Xt, sysreg) \ instr_create_1dst_1src((dc), OP_mrs, (Xt), (sysreg)) #define INSTR_CREATE_msr(dc, sysreg, Xt) \ @@ -246,6 +257,7 @@ #define INSTR_CREATE_svc(dc, imm) \ instr_create_0dst_1src((dc), OP_svc, (imm)) +/* FIXME i#1569: these two are probably wrong */ #define INSTR_CREATE_add_shimm(dc, Rd, Rn, Rm, shift, imm) \ instr_create_1dst_4src((dc), OP_add, (Rd), (Rn), \ opnd_create_reg_ex(opnd_get_reg(Rm), 0, DR_OPND_SHIFTED), \ diff --git a/core/arch/aarch64/opcode.h b/core/arch/aarch64/opcode.h index eab09da5634..d855160e8f3 100644 --- a/core/arch/aarch64/opcode.h +++ b/core/arch/aarch64/opcode.h @@ -1,34 +1,4 @@ -/* ********************************************************** - * Copyright (c) 2016 ARM Limited. All rights reserved. - * **********************************************************/ - -/* - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * * Neither the name of ARM Limited nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL ARM LIMITED OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - */ +/* This file was generated by codec.py from codec.txt. */ #ifndef OPCODE_H #define OPCODE_H 1 @@ -50,30 +20,32 @@ enum { /* 2 */ OP_CONTD, /* NULL, */ /**< CONTD opcode */ /* 3 */ OP_LABEL, /* NULL, */ /**< LABEL opcode */ -/* */ OP_add, -/* */ OP_adr, -/* */ OP_adrp, -/* */ OP_b, -/* */ OP_bcond, -/* */ OP_bl, -/* */ OP_blr, -/* */ OP_br, -/* */ OP_brk, -/* */ OP_cbnz, -/* */ OP_cbz, -/* */ OP_ldr, -/* */ OP_mov, -/* */ OP_mrs, -/* */ OP_msr, -/* */ OP_nop, -/* */ OP_ret, -/* */ OP_str, -/* */ OP_strh, -/* */ OP_sub, -/* */ OP_svc, -/* */ OP_tbnz, -/* */ OP_tbz, -/* */ OP_xx, /* placeholder for undecoded instructions */ +/* 4 */ OP_add, /**< ARM add opcode.*/ +/* 5 */ OP_adr, /**< ARM adr opcode.*/ +/* 6 */ OP_adrp, /**< ARM adrp opcode.*/ +/* 7 */ OP_b, /**< ARM b opcode.*/ +/* 8 */ OP_bcond, /**< ARM bcond opcode.*/ +/* 9 */ OP_bl, /**< ARM bl opcode.*/ +/* 10 */ OP_blr, /**< ARM blr opcode.*/ +/* 11 */ OP_br, /**< ARM br opcode.*/ +/* 12 */ OP_brk, /**< ARM brk opcode.*/ +/* 13 */ OP_cbnz, /**< ARM cbnz opcode.*/ +/* 14 */ OP_cbz, /**< ARM cbz opcode.*/ +/* 15 */ OP_ldr, /**< ARM ldr opcode.*/ +/* 16 */ OP_mrs, /**< ARM mrs opcode.*/ +/* 17 */ OP_msr, /**< ARM msr opcode.*/ +/* 18 */ OP_nop, /**< ARM nop opcode.*/ +/* 19 */ OP_orr, /**< ARM orr opcode.*/ +/* 20 */ OP_ret, /**< ARM ret opcode.*/ +/* 21 */ OP_str, /**< ARM str opcode.*/ +/* 22 */ OP_strb, /**< ARM strb opcode.*/ +/* 23 */ OP_strh, /**< ARM strh opcode.*/ +/* 24 */ OP_sub, /**< ARM sub opcode.*/ +/* 25 */ OP_svc, /**< ARM svc opcode.*/ +/* 26 */ OP_tbnz, /**< ARM tbnz opcode.*/ +/* 27 */ OP_tbz, /**< ARM tbz opcode.*/ + + OP_xx, /* placeholder for undecoded instructions */ OP_AFTER_LAST, OP_FIRST = OP_LABEL + 1, /**< First real opcode. */ diff --git a/core/arch/aarchxx/mangle.c b/core/arch/aarchxx/mangle.c index 1e1a26c29f7..a3b38d467c5 100644 --- a/core/arch/aarchxx/mangle.c +++ b/core/arch/aarchxx/mangle.c @@ -1549,9 +1549,9 @@ restore_app_value_to_stolen_reg(dcontext_t *dcontext, instrlist_t *ilist, instr_t *instr, reg_id_t reg, ushort slot) { insert_save_to_tls_if_necessary(dcontext, ilist, instr, reg, slot); - PRE(ilist, instr, INSTR_CREATE_mov(dcontext, - opnd_create_reg(reg), - opnd_create_reg(dr_reg_stolen))); + PRE(ilist, instr, XINST_CREATE_move(dcontext, + opnd_create_reg(reg), + opnd_create_reg(dr_reg_stolen))); /* We always read the app value to make sure we write back * the correct value in the case of predicated execution. */ @@ -1594,9 +1594,9 @@ restore_tls_base_to_stolen_reg(dcontext_t *dcontext, instrlist_t *ilist, }); } /* restore stolen reg from spill reg */ - PRE(ilist, next_instr, INSTR_CREATE_mov(dcontext, - opnd_create_reg(dr_reg_stolen), - opnd_create_reg(reg))); + PRE(ilist, next_instr, XINST_CREATE_move(dcontext, + opnd_create_reg(dr_reg_stolen), + opnd_create_reg(reg))); } /* XXX: merge with or refactor out old STEAL_REGISTER x86 code? */ @@ -1620,6 +1620,7 @@ mangle_stolen_reg(dcontext_t *dcontext, instrlist_t *ilist, */ ASSERT(!instr_is_meta(instr) && instr_uses_reg(instr, dr_reg_stolen)); +#ifndef AARCH64 /* FIXME i#1569: recognise "move" on AArch64 */ /* optimization, convert simple mov to ldr/str: * - "mov r0 -> r10" ==> "str r0 -> [r10_slot]" * - "mov r10 -> r0" ==> "ldr [r10_slot] -> r0" @@ -1651,6 +1652,7 @@ mangle_stolen_reg(dcontext_t *dcontext, instrlist_t *ilist, ASSERT_NOT_REACHED(); } } +#endif /* move stolen reg value into tmp reg for app instr execution */ tmp = pick_scratch_reg(dcontext, instr, false, &slot, &should_restore); @@ -2257,9 +2259,9 @@ mangle_gpr_list_write(dcontext_t *dcontext, instrlist_t *ilist, instr_t *instr, insert_save_to_tls_if_necessary(dcontext, ilist, instr, SCRATCH_REG1, TLS_REG1_SLOT); /* mov r0 => r1, */ - mov = INSTR_CREATE_mov(dcontext, - opnd_create_reg(SCRATCH_REG1), - opnd_create_reg(SCRATCH_REG0)); + mov = XINST_CREATE_move(dcontext, + opnd_create_reg(SCRATCH_REG1), + opnd_create_reg(SCRATCH_REG0)); instr_set_predicate(mov, instr_get_predicate(instr)); PRE(ilist, instr, mov); /* We will only come to here iff instr is "ldm r0, {r0-rx}", diff --git a/core/arch/emit_utils_shared.c b/core/arch/emit_utils_shared.c index 5ca873d5b5f..ba7e692adec 100644 --- a/core/arch/emit_utils_shared.c +++ b/core/arch/emit_utils_shared.c @@ -4910,6 +4910,7 @@ decode_syscall_num(dcontext_t *dcontext, byte *entry) if (instr_num_dsts(&instr) > 0 && opnd_is_reg(instr_get_dst(&instr, 0)) && opnd_get_reg(instr_get_dst(&instr, 0)) == SCRATCH_REG0) { +#ifndef AARCH64 /* FIXME i#1569: recognise "move" on AArch64 */ if (instr_get_opcode(&instr) == IF_X86_ELSE(OP_mov_imm, OP_mov)) { IF_X64(ASSERT_TRUNCATE(int, int, opnd_get_immed_int(instr_get_src(&instr, 0)))); @@ -4917,6 +4918,7 @@ decode_syscall_num(dcontext_t *dcontext, byte *entry) LOG(GLOBAL, LOG_EMIT, 3, "\tfound syscall num: 0x%x\n", syscall); break; } else +#endif break; /* give up gracefully */ } } diff --git a/ext/drutil/drutil.c b/ext/drutil/drutil.c index 6287091f868..01632de5b61 100644 --- a/ext/drutil/drutil.c +++ b/ext/drutil/drutil.c @@ -315,10 +315,10 @@ drutil_insert_get_mem_addr_arm(void *drcontext, instrlist_t *bb, instr_t *where, opnd_create_reg(dst), opnd_create_reg(base), OPND_CREATE_INT(disp)) : - INSTR_CREATE_add(drcontext, - opnd_create_reg(dst), - opnd_create_reg(base), - OPND_CREATE_INT(disp)); + XINST_CREATE_add_2src(drcontext, + opnd_create_reg(dst), + opnd_create_reg(base), + OPND_CREATE_INT(disp)); if (instr_is_encoding_possible(instr)) { PRE(bb, where, instr); return true; @@ -352,9 +352,9 @@ drutil_insert_get_mem_addr_arm(void *drcontext, instrlist_t *bb, instr_t *where, OPND_CREATE_INT(amount)); PRE(bb, where, instr); } else if (base != dst) { - PRE(bb, where, INSTR_CREATE_mov(drcontext, - opnd_create_reg(dst), - opnd_create_reg(base))); + PRE(bb, where, XINST_CREATE_move(drcontext, + opnd_create_reg(dst), + opnd_create_reg(base))); } } return true;