blob: d8f47f0da75deaf0739e8a5553c844157a2833f8 [file] [log] [blame]
/* **********************************************************
* Copyright (c) 2014 Google, Inc. 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 Goole, Inc. 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 VMWARE, INC. 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.
*/
/* file "decode_private.h" */
#ifndef DECODE_PRIVATE_H
#define DECODE_PRIVATE_H
/* instr_info_t.type special codes: */
enum {
/* not a valid opcode */
INVALID = OP_LAST + 1,
EXT_OPC4, /* Indexed by bits 7:4 */
EXT_OPC4X, /* Indexed by bits 7:4 in specific manner: see table */
EXT_OPC4Y, /* Indexed by bits 7:4 w/ 1st entry covering all evens */
EXT_IMM1916, /* Indexed by whether imm4 in 19:16 is zero or not */
EXT_IMM5, /* Indexed by whether imm5 11:7 is zero or not */
EXT_BITS0, /* Indexed by bits 2:0 */
EXT_BITS8, /* Indexed by bits 9:8 */
EXT_BIT4, /* Indexed by bit 4 */
EXT_BIT5, /* Indexed by bit 5 */
EXT_BIT9, /* Indexed by bit 9 */
EXT_FP, /* Indexed by bits 11:8 but collapsed */
EXT_FPA, /* Indexed by bits 6:4 but collapsed */
EXT_FPB, /* Indexed by bits 6:4 */
EXT_BITS16, /* Indexed by bits 19:16 */
EXT_RBPC, /* Indexed by whether RB != PC */
EXT_RDPC, /* Indexed by whether RD != PC */
/* A32 unpred only */
EXT_BIT6, /* Indexed by bit 6 */
EXT_BIT7, /* Indexed by bit 7 */
EXT_BIT19, /* Indexed by bit 19 */
EXT_BIT22, /* Indexed by bit 22 */
EXT_BITS20, /* Indexed by bits 23:20 */
EXT_IMM1816, /* Indexed by whether imm3 in 18:16 is zero or not */
EXT_IMM2016, /* Indexed by whether imm5 in 20:16 is zero or not */
EXT_SIMD6, /* Indexed by 6 bits 11:8,6,4 */
EXT_SIMD5, /* Indexed by bits 11:8,5 */
EXT_SIMD5B, /* Indexed by bits 18:16,8:7 */
EXT_SIMD8, /* Indexed by bits 11:8,7:4, but 7:4 collapsed */
EXT_SIMD6B, /* Indexed by bits 11:8,7:6 */
EXT_SIMD6C, /* Indexed by bits 10:8,7:6 + extra set of 7:6 for bit 11 being set */
EXT_SIMD2, /* Indexed by bits 11,6 */
EXT_VLDA, /* Indexed by bits (11:8,7:6)*3+X where X based on value of 3:0 */
EXT_VLDB, /* Indexed by bits (11:8,Y)*3+X (see table descr) */
EXT_VLDC, /* Indexed by bits (9:8,7:5)*3+X where X based on value of 3:0 */
/* else, from OP_ enum */
};
/* instr_info_t.opcode: holds all the 1 bits for the opcode.
* We set it first, so we don't need to store 0's explicitly.
*/
/* instr_info_t.name: we store lowercase, and the disassembler upcases it
* for ARM-style disasm.
*/
/* instr_info.t operands: because the type tells us the encoding bit location,
* we are free to reorder them. We pick the asm order.
*/
/* instr_info_t.flags values: */
enum {
DECODE_EXTRA_OPERANDS = 0x0001, /* additional opnds in entry at code field */
DECODE_EXTRA_SHIFT = 0x0002, /* has 2 additional srcs @exop[0] */
DECODE_EXTRA_WRITEBACK = 0x0004, /* has 1 additional src @exop[1] */
DECODE_EXTRA_WRITEBACK2 = 0x0008, /* has 2 additional src @exop[2] */
DECODE_4_SRCS = 0x0010, /* dst2==src1, src1==src2, etc. */
DECODE_3_DSTS = 0x0020, /* src1==dst3, src2==src1, etc. */
DECODE_PREDICATE = 0x0040, /* takes a predicate */
DECODE_PREDICATE_AL_ONLY = 0x0080, /* takes AL predicate only */
DECODE_UNPREDICTABLE = 0x0100, /* unpredictable according to ISA spec */
/* ARM versions we care about */
DECODE_ARM_V8 = 0x0200, /* added in v8: not present in v7 */
DECODE_ARM_VFP = 0x0400, /* VFP instruction */
};
/* instr_info_t.code:
* + for EXTENSION and *_EXT: index into extensions table
* + for OP_: pointer to next entry of that opcode
* + may also point to extra operand table
*/
struct _decode_info_t {
uint instr_word;
dr_isa_mode_t isa_mode;
uint opcode;
uint predicate;
/* For pc-relative references */
byte *start_pc;
byte *final_pc;
byte *orig_pc;
/* For decoding reglists. Max 1 reglist per template (we check this in
* decode_debug_checks_arch()).
*/
size_t reglist_sz;
/* For instr_t* target encoding */
ptr_int_t cur_note;
bool has_instr_opnds;
/* For encoding error messages */
const char *errmsg; /* can contain one integer format parameter */
int errmsg_param;
};
/* N.B.: if you change the type enum, change the string names for
* them, kept in encode.c
*/
/* Operand types have 2 parts, type and size. The type tells us in which bits
* the operand is encoded, and the type of operand.
*/
enum {
/* operand types */
TYPE_NONE, /* must be 0 for invalid_instr */
/* We name the registers according to their encoded position: A, B, C, D.
* XXX: Rd is T32-11:8; T16-2:0; A64-4:0 so not always "C"
*
* XXX: record which registers are "unpredictable" if PC (or SP, or LR) is
* passed? Many are, for many different opcodes.
*/
TYPE_R_A, /* A32-19:16 = Rn: source register, often memory base */
TYPE_R_B, /* A32-15:12 = Rd or Rt: dest reg */
TYPE_R_C, /* A32-11:8 = Rs: source register, often used as shift value */
TYPE_R_D, /* A32-3:0 = Rm: source register, often used as offset */
TYPE_R_A_TOP, /* top half of register */
TYPE_R_B_TOP, /* top half of register */
TYPE_R_C_TOP, /* top half of register */
TYPE_R_D_TOP, /* top half of register */
TYPE_R_D_NEGATED, /* register's value is negated */
TYPE_R_B_EVEN, /* Must be an even-numbered reg */
TYPE_R_B_PLUS1, /* Subsequent reg after prior TYPE_R_B_EVEN opnd */
TYPE_R_D_EVEN, /* Must be an even-numbered reg */
TYPE_R_D_PLUS1, /* Subsequent reg after prior TYPE_R_D_EVEN opnd */
TYPE_CR_A, /* Coprocessor register in A slot */
TYPE_CR_B, /* Coprocessor register in B slot */
TYPE_CR_C, /* Coprocessor register in C slot */
TYPE_CR_D, /* Coprocessor register in D slot */
TYPE_V_A, /* A32-7,19:16 = Vn: some (bottom) part of 128-bit src reg */
TYPE_V_B, /* A32-22,15:12 = Vd: some (bottom) part of 128-bit dst reg */
TYPE_V_C, /* A32-5,3:0 = Vm: some (bottom) part of 128-bit src reg */
TYPE_V_C_3b,/* A32-2:0 = Vm<2:0>: some (bottom) part of 128-bit src reg */
TYPE_V_C_4b,/* A32-3:0 = Vm<3:0>: some (bottom) part of 128-bit src reg */
TYPE_W_A, /* A32-19:16,7 = Vn VFP non-double: part of 128-bit src reg */
TYPE_W_B, /* A32-15:12,22 = Vd VFP non-double: part of 128-bit dst reg */
TYPE_W_C, /* A32-3:0,5 = Vm VFP non-double: part of 128-bit src reg */
TYPE_W_C_PLUS1, /* Subsequent reg after TYPE_W_C */
TYPE_SPSR, /* Saved Program Status Register */
TYPE_CPSR, /* Current Program Status Register */
TYPE_FPSCR, /* Floating Point Status and Control Register */
TYPE_LR, /* Link register */
TYPE_SP, /* Stack pointer */
/* FIXME i#1551: some immediates have built-in shifting or scaling: we
* need to add handling for that.
*/
/* Immediates are at several different bit positions and come in several
* different sizes. We considered storing a bitmask to cover any type
* of immediate, but there are few enough that we are enumerating them:
*/
TYPE_I_b0,
TYPE_NI_b0, /* negated immed */
TYPE_I_b3,
TYPE_I_b4,
TYPE_I_b5,
TYPE_I_b6,
TYPE_I_b7,
TYPE_I_b8,
TYPE_I_b9,
TYPE_I_b10,
TYPE_I_b16,
TYPE_I_b17,
TYPE_I_b18,
TYPE_I_b19,
TYPE_I_b20,
TYPE_I_b21, /* OP_vmov */
TYPE_I_b0_b5, /* OP_cvt: immed is either 32 or 16 minus [3:0,5] */
TYPE_I_b0_b24, /* OP_blx imm24:H:0 */
TYPE_I_b5_b3, /* OP_vmla scalar: M:Vm<3> */
TYPE_I_b8_b0,
TYPE_NI_b8_b0, /* negated immed */
TYPE_I_b8_b16,
TYPE_I_b16_b0,
TYPE_I_b21_b5, /* OP_vmov: 21,6:5 */
TYPE_I_b21_b6, /* OP_vmov: 21,6 */
TYPE_I_b24_b16_b0, /* OP_vbic, OP_vmov: 24,18:16,3:0 */
TYPE_SHIFT_b5,
TYPE_SHIFT_b6, /* value is :0 */
TYPE_SHIFT_LSL, /* shift logical left */
TYPE_SHIFT_ASR, /* shift arithmetic right */
TYPE_L_8b, /* 8-bit register list */
TYPE_L_13b, /* 13-bit register list */
TYPE_L_16b, /* 16-bit register list */
TYPE_L_CONSEC, /* Consecutive multimedia regs: dword count in immed 7:0 */
TYPE_L_VBx2, /* 2 consecutive multimedia regs starting at TYPE_V_B */
TYPE_L_VBx3, /* 3 consecutive multimedia regs starting at TYPE_V_B */
TYPE_L_VBx4, /* 4 consecutive multimedia regs starting at TYPE_V_B */
TYPE_L_VBx2D, /* 2 doubly-spaced multimedia regs starting at TYPE_V_B */
TYPE_L_VBx3D, /* 3 doubly-spaced multimedia regs starting at TYPE_V_B */
TYPE_L_VBx4D, /* 4 doubly-spaced multimedia regs starting at TYPE_V_B */
/* All memory addressing modes use fixed base and index registers:
* A32: base = RA 19:16 ("Rn" in manual)
* index = RD 3:0 ("Rm" in manual)
* T16: base =
* index =
* T32: base =
* index =
* A64: base =
* index =
*
* Shifted registers always use sh2, i5.
*
* To be compatible w/ x86, we don't want to list the index, offset, or shift
* operands separately for regular offset addressing: we want to hide them
* inside the memref. So we have to record exactly how to decode and encode
* each piece.
*
* We don't encode in the memref whether it has writeback ("[Rn + Rm]!") or
* is post-indexed ("[Rn], Rm"): the disassembler has to look at the other
* opnds to figure out how to write down the memref, and single-memref-opnd
* disasm will NOT contain writeback or post-index info.
*/
TYPE_M, /* mem w/ just base */
TYPE_M_POS_REG, /* mem offs + reg index */
TYPE_M_NEG_REG, /* mem offs - reg index */
TYPE_M_POS_SHREG, /* mem offs + reg-shifted (or extended for A64) index */
TYPE_M_NEG_SHREG, /* mem offs - reg-shifted (or extended for A64) index */
TYPE_M_POS_I12, /* mem offs + 12-bit immed @ 11:0 (A64: 21:10 + scaled) */
TYPE_M_NEG_I12, /* mem offs - 12-bit immed @ 11:0 (A64: 21:10 + scaled) */
TYPE_M_SI9, /* mem offs + signed 9-bit immed @ 20:12 */
TYPE_M_POS_I8, /* mem offs + 4 * 8-bit immed @ 7:0 */
TYPE_M_NEG_I8, /* mem offs - 4 * 8-bit immed @ 7:0 */
TYPE_M_POS_I4_4, /* mem offs + 8-bit immed split @ 11:8|3:0 */
TYPE_M_NEG_I4_4, /* mem offs - 8-bit immed split @ 11:8|3:0 */
TYPE_M_SI7, /* mem offs + signed 7-bit immed @ 6:0 */
TYPE_M_POS_I5, /* mem offs + 5-bit immed @ 5:0 */
TYPE_M_PCREL_S9, /* mem offs pc-relative w/ signed 9-bit immed 23:5 scaled */
TYPE_M_PCREL_U9, /* mem offs pc-relative w/ unsigned 9-bit immed 23:5 scaled */
TYPE_M_UP_OFFS, /* mem w/ base plus ptr-sized disp */
TYPE_M_DOWN, /* mem w/ base pointing at endpoint */
TYPE_M_DOWN_OFFS, /* mem w/ base minus ptr-sized disp pointing at endpoint */
TYPE_K, /* integer constant, size ignored, value stored in size */
/* when adding new types, update type_names[] in encode.c */
TYPE_BEYOND_LAST_ENUM,
/* Non-incremental-enum valus */
DECODE_INDEX_SHIFT_TYPE_BITPOS = 5,
DECODE_INDEX_SHIFT_TYPE_SIZE = OPSZ_2b,
DECODE_INDEX_SHIFT_AMOUNT_BITPOS = 7,
DECODE_INDEX_SHIFT_AMOUNT_SIZE = OPSZ_5b,
SHIFT_ENCODING_LSL = 0,
SHIFT_ENCODING_LSR = 1,
SHIFT_ENCODING_ASR = 2,
SHIFT_ENCODING_RRX = 3,
};
/* exported tables */
extern const instr_info_t A32_pred_opc8[];
extern const instr_info_t A32_ext_opc4x[][6];
extern const instr_info_t A32_ext_opc4y[][9];
extern const instr_info_t A32_ext_opc4[][16];
extern const instr_info_t A32_ext_imm1916[][2];
extern const instr_info_t A32_ext_bits0[][8];
extern const instr_info_t A32_ext_bits8[][4];
extern const instr_info_t A32_ext_bit9[][2];
extern const instr_info_t A32_ext_bit5[][2];
extern const instr_info_t A32_ext_bit4[][2];
extern const instr_info_t A32_ext_fp[][3];
extern const instr_info_t A32_ext_opc4fpA[][3];
extern const instr_info_t A32_ext_opc4fpB[][8];
extern const instr_info_t A32_ext_bits16[][16];
extern const instr_info_t A32_ext_RBPC[][2];
extern const instr_info_t A32_ext_RDPC[][2];
extern const instr_info_t A32_ext_imm5[][2];
extern const instr_info_t A32_extra_operands[];
extern const instr_info_t A32_unpred_opc7[];
extern const instr_info_t A32_ext_bits20[][16];
extern const instr_info_t A32_ext_imm2016[][2];
extern const instr_info_t A32_ext_imm1816[][2];
extern const instr_info_t A32_ext_bit7[][2];
extern const instr_info_t A32_ext_bit6[][2];
extern const instr_info_t A32_ext_bit19[][2];
extern const instr_info_t A32_ext_bit22[][2];
extern const instr_info_t A32_ext_simd6[][64];
extern const instr_info_t A32_ext_simd5[][32];
extern const instr_info_t A32_ext_simd5b[][32];
extern const instr_info_t A32_ext_simd8[][144];
extern const instr_info_t A32_ext_simd6b[][64];
extern const instr_info_t A32_ext_simd6c[][36];
extern const instr_info_t A32_ext_simd2[][4];
extern const instr_info_t A32_ext_vldA[][132];
extern const instr_info_t A32_ext_vldB[][96];
extern const instr_info_t A32_ext_vldC[][96];
/* tables that translate opcode enums into pointers into decoding tables */
extern const instr_info_t * const op_instr_A32[];
opnd_size_t
resolve_size_upward(opnd_size_t size);
opnd_size_t
resolve_size_downward(opnd_size_t size);
bool
optype_is_reg(int optype);
#endif /* DECODE_PRIVATE_H */