Store register type in decoded instruction

This commit is contained in:
Alexis Engelke
2019-05-05 12:53:10 +02:00
parent 899278600b
commit 3f278bc6cc
3 changed files with 75 additions and 35 deletions

View File

@@ -277,6 +277,7 @@ struct InstrDesc
uint8_t gp_fixed_operand_size : 3; uint8_t gp_fixed_operand_size : 3;
uint8_t lock : 1; uint8_t lock : 1;
uint8_t vsib : 1; uint8_t vsib : 1;
uint16_t reg_types;
} __attribute__((packed)); } __attribute__((packed));
#define DESC_HAS_MODRM(desc) (((desc)->operand_indices & (3 << 0)) != 0) #define DESC_HAS_MODRM(desc) (((desc)->operand_indices & (3 << 0)) != 0)
@@ -573,6 +574,17 @@ fd_decode(const uint8_t* buffer, size_t len_sz, int mode_int, uintptr_t address,
if ((prefixes & PREFIX_LOCK) && instr->operands[0].type != FD_OT_MEM) if ((prefixes & PREFIX_LOCK) && instr->operands[0].type != FD_OT_MEM)
return -1; return -1;
for (int i = 0; i < 4; i++)
{
if (instr->operands[i].type != FD_OT_REG)
continue;
uint32_t reg_type = (desc->reg_types >> 4 * i) & 0xf;
if (reg_type == FD_RT_GPL && !(prefixes & PREFIX_REX) &&
instr->operands[i].size == 1 && instr->operands[i].reg >= 4)
reg_type = FD_RT_GPH;
instr->operands[i].misc = reg_type;
}
instr->size = off; instr->size = off;
return off; return off;

50
fadec.h
View File

@@ -48,10 +48,36 @@ typedef enum {
FD_OT_MEM = 3, FD_OT_MEM = 3,
} FdOpType; } FdOpType;
typedef enum {
/** Register type is encoded in mnemonic **/
FD_RT_IMP = 0,
/** Low general purpose register **/
FD_RT_GPL = 1,
/** High-byte general purpose register **/
FD_RT_GPH = 2,
/** Segment register **/
FD_RT_SEG = 3,
/** FPU register ST(n) **/
FD_RT_FPU = 4,
/** MMX register MMn **/
FD_RT_MMX = 5,
/** Vector (SSE/AVX) register XMMn/YMMn/ZMMn **/
FD_RT_VEC = 6,
/** Vector mask (AVX-512) register Kn **/
FD_RT_MASK = 7,
/** Bound register BNDn **/
FD_RT_BND = 8,
/** Control Register CRn **/
FD_RT_CR = 9,
/** Debug Register DRn **/
FD_RT_DR = 10,
} FdRegType;
typedef struct { typedef struct {
uint8_t type; uint8_t type;
uint8_t size; uint8_t size;
int8_t reg; int8_t reg;
uint8_t misc;
} FdOp; } FdOp;
typedef struct { typedef struct {
@@ -137,22 +163,18 @@ void fd_format(const FdInstr* instr, char* buf, size_t len);
#define FD_OP_SIZE(instr,idx) ((instr)->operands[idx].size) #define FD_OP_SIZE(instr,idx) ((instr)->operands[idx].size)
/** Gets the accessed register index of a register operand. Note that /only/ the /** Gets the accessed register index of a register operand. Note that /only/ the
* index is returned, no further interpretation of the index (which depends on * index is returned, no further interpretation of the index (which depends on
* the instruction type) is done. When an instruction accesses an 8-bit general * the instruction type) is done. The register type can be fetches using
* purpose register with an index in the range 4-7, it needs to be determined * FD_OP_REG_TYPE, e.g. for distinguishing high-byte registers.
* explicitly whether a high-byte register is accessed (using FD_OP_REG_HIGH).
* If that is the case, the index needs to be decreased by 4.
* Only valid if FD_OP_TYPE == FD_OT_REG **/ * Only valid if FD_OP_TYPE == FD_OT_REG **/
#define FD_OP_REG(instr,idx) ((FdReg) (instr)->operands[idx].reg) #define FD_OP_REG(instr,idx) ((FdReg) (instr)->operands[idx].reg)
/** Returns whether the accessed register is a actually high-byte register when /** Gets the type of the accessed register.
* used on a general purpose instruction. In that case, the register index has * Only valid if FD_OP_TYPE == FD_OT_REG **/
* to be decreased by 4. #define FD_OP_REG_TYPE(instr,idx) ((FdRegType) (instr)->operands[idx].misc)
* Only valid if FD_OP_TYPE == FD_OT_REG and the operand refers to a general /** DEPRECATED: use FD_OP_REG_TYPE() == FD_RT_GPH instead.
* purpose register (depends on the instruction type) **/ * Returns whether the accessed register is a high-byte register. In that case,
#define FD_OP_REG_HIGH(instr,idx) ( \ * the register index has to be decreased by 4.
(instr)->operands[idx].size == 1 && \ * Only valid if FD_OP_TYPE == FD_OT_REG **/
(instr)->operands[idx].reg >= 4 && \ #define FD_OP_REG_HIGH(instr,idx) (FD_OP_REG_TYPE(instr,idx) == FD_RT_GPH)
((instr)->flags & FD_FLAG_REX) == 0 \
)
/** Gets the index of the base register from a memory operand, or FD_REG_NONE, /** Gets the index of the base register from a memory operand, or FD_REG_NONE,
* if the memory operand has no base register. This is the only case where the * if the memory operand has no base register. This is the only case where the
* 64-bit register RIP can be returned, in which case the operand also has no * 64-bit register RIP can be returned, in which case the operand also has no

View File

@@ -40,6 +40,7 @@ InstrFlags = bitstruct("InstrFlags", [
"gp_fixed_operand_size:3", "gp_fixed_operand_size:3",
"lock:1", "lock:1",
"vsib:1", "vsib:1",
"reg_types:16",
]) ])
ENCODINGS = { ENCODINGS = {
@@ -72,26 +73,28 @@ ENCODINGS = {
} }
OPKIND_LOOKUP = { OPKIND_LOOKUP = {
"-": (0, 0), # sizeidx (0, fixedsz, opsz, vecsz), fixedsz (log2), regtype
"IMM": (2, 0), "-": (0, 0, 0),
"IMM8": (1, 0), "IMM": (2, 0, 0),
"IMM16": (1, 1), "IMM8": (1, 0, 0),
"IMM32": (1, 2), "IMM16": (1, 1, 0),
"GP": (2, 0), "IMM32": (1, 2, 0),
"GP8": (1, 0), "GP": (2, 0, 1),
"GP16": (1, 1), "GP8": (1, 0, 1),
"GP32": (1, 2), "GP16": (1, 1, 1),
"GP64": (1, 3), "GP32": (1, 2, 1),
"XMM": (3, 0), "GP64": (1, 3, 1),
"XMM8": (1, 0), "XMM": (3, 0, 6),
"XMM16": (1, 1), "XMM8": (1, 0, 6),
"XMM32": (1, 2), "XMM16": (1, 1, 6),
"XMM64": (1, 3), "XMM32": (1, 2, 6),
"XMM128": (1, 4), "XMM64": (1, 3, 6),
"XMM256": (1, 5), "XMM128": (1, 4, 6),
"SREG": (0, 0), "XMM256": (1, 5, 6),
"FPU": (0, 0), "SREG": (0, 0, 3),
"MEMZ": (0, 0), "FPU": (0, 0, 4),
"MEMZ": (0, 0, 0),
"BND": (0, 0, 0),
} }
class InstrDesc(namedtuple("InstrDesc", "mnemonic,flags,encoding")): class InstrDesc(namedtuple("InstrDesc", "mnemonic,flags,encoding")):
@@ -102,13 +105,16 @@ class InstrDesc(namedtuple("InstrDesc", "mnemonic,flags,encoding")):
fixed_opsz = set() fixed_opsz = set()
opsizes = 0 opsizes = 0
reg_types = 0
for i, opkind in enumerate(desc[1:5]): for i, opkind in enumerate(desc[1:5]):
enc_size, fixed_size = OPKIND_LOOKUP[opkind] enc_size, fixed_size, reg_type = OPKIND_LOOKUP[opkind]
if enc_size == 1: fixed_opsz.add(fixed_size) if enc_size == 1: fixed_opsz.add(fixed_size)
opsizes |= enc_size << 2 * i opsizes |= enc_size << 2 * i
reg_types |= reg_type << 4 * i
flags = copy(ENCODINGS[desc[0]]) flags = copy(ENCODINGS[desc[0]])
flags.operand_sizes = opsizes flags.operand_sizes = opsizes
flags.reg_types = reg_types
if fixed_opsz: flags.gp_fixed_operand_size = next(iter(fixed_opsz)) if fixed_opsz: flags.gp_fixed_operand_size = next(iter(fixed_opsz))
# Miscellaneous Flags # Miscellaneous Flags