Add more precise error codes
This commit is contained in:
48
decode.c
48
decode.c
@@ -127,17 +127,17 @@ decode_prefixes(const uint8_t* buffer, int len, DecodeMode mode,
|
|||||||
#endif
|
#endif
|
||||||
case 0xc4: case 0xc5: // VEX
|
case 0xc4: case 0xc5: // VEX
|
||||||
if (UNLIKELY(off + 1 >= len))
|
if (UNLIKELY(off + 1 >= len))
|
||||||
return -1;
|
return FD_ERR_PARTIAL;
|
||||||
uint8_t byte = buffer[off + 1];
|
uint8_t byte = buffer[off + 1];
|
||||||
if (mode == DECODE_32 && (byte & 0xc0) != 0xc0)
|
if (mode == DECODE_32 && (byte & 0xc0) != 0xc0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
// VEX + 66/F2/F3/LOCK will #UD.
|
// VEX + 66/F2/F3/LOCK will #UD.
|
||||||
if (prefixes & (PREFIX_REP|PREFIX_REPNZ|PREFIX_OPSZ|PREFIX_LOCK))
|
if (prefixes & (PREFIX_REP|PREFIX_REPNZ|PREFIX_OPSZ|PREFIX_LOCK))
|
||||||
return -1;
|
return FD_ERR_UD;
|
||||||
// VEX + REX will #UD.
|
// VEX + REX will #UD.
|
||||||
if (rex_prefix)
|
if (rex_prefix)
|
||||||
return -1;
|
return FD_ERR_UD;
|
||||||
|
|
||||||
prefixes |= PREFIX_VEX;
|
prefixes |= PREFIX_VEX;
|
||||||
prefixes |= byte & 0x80 ? 0 : PREFIX_REXR;
|
prefixes |= byte & 0x80 ? 0 : PREFIX_REXR;
|
||||||
@@ -151,7 +151,7 @@ decode_prefixes(const uint8_t* buffer, int len, DecodeMode mode,
|
|||||||
|
|
||||||
// Load third byte of VEX prefix
|
// Load third byte of VEX prefix
|
||||||
if (UNLIKELY(off + 2 >= len))
|
if (UNLIKELY(off + 2 >= len))
|
||||||
return -1;
|
return FD_ERR_PARTIAL;
|
||||||
byte = buffer[off + 2];
|
byte = buffer[off + 2];
|
||||||
// SDM Vol 2A 2-16 (Dec. 2016) says that:
|
// SDM Vol 2A 2-16 (Dec. 2016) says that:
|
||||||
// - "In 32-bit modes, VEX.W is silently ignored."
|
// - "In 32-bit modes, VEX.W is silently ignored."
|
||||||
@@ -233,7 +233,7 @@ decode_modrm(const uint8_t* buffer, int len, DecodeMode mode, FdInstr* instr,
|
|||||||
if (rm == 4)
|
if (rm == 4)
|
||||||
{
|
{
|
||||||
if (UNLIKELY(off >= len))
|
if (UNLIKELY(off >= len))
|
||||||
return -1;
|
return FD_ERR_PARTIAL;
|
||||||
uint8_t sib = buffer[off++];
|
uint8_t sib = buffer[off++];
|
||||||
scale = (sib & 0xc0) >> 6;
|
scale = (sib & 0xc0) >> 6;
|
||||||
idx = (sib & 0x38) >> 3;
|
idx = (sib & 0x38) >> 3;
|
||||||
@@ -258,14 +258,14 @@ decode_modrm(const uint8_t* buffer, int len, DecodeMode mode, FdInstr* instr,
|
|||||||
if (mod == 1)
|
if (mod == 1)
|
||||||
{
|
{
|
||||||
if (UNLIKELY(off + 1 > len))
|
if (UNLIKELY(off + 1 > len))
|
||||||
return -1;
|
return FD_ERR_PARTIAL;
|
||||||
instr->disp = (int8_t) LOAD_LE_1(&buffer[off]);
|
instr->disp = (int8_t) LOAD_LE_1(&buffer[off]);
|
||||||
off += 1;
|
off += 1;
|
||||||
}
|
}
|
||||||
else if (mod == 2 || (mod == 0 && base == 5))
|
else if (mod == 2 || (mod == 0 && base == 5))
|
||||||
{
|
{
|
||||||
if (UNLIKELY(off + 4 > len))
|
if (UNLIKELY(off + 4 > len))
|
||||||
return -1;
|
return FD_ERR_PARTIAL;
|
||||||
instr->disp = (int32_t) LOAD_LE_4(&buffer[off]);
|
instr->disp = (int32_t) LOAD_LE_4(&buffer[off]);
|
||||||
off += 4;
|
off += 4;
|
||||||
}
|
}
|
||||||
@@ -326,7 +326,7 @@ fd_decode(const uint8_t* buffer, size_t len_sz, int mode_int, uintptr_t address,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (UNLIKELY(table == NULL))
|
if (UNLIKELY(table == NULL))
|
||||||
return -2;
|
return FD_ERR_INTERNAL;
|
||||||
|
|
||||||
int retval;
|
int retval;
|
||||||
int off = 0;
|
int off = 0;
|
||||||
@@ -338,8 +338,10 @@ fd_decode(const uint8_t* buffer, size_t len_sz, int mode_int, uintptr_t address,
|
|||||||
retval = decode_prefixes(buffer + off, len - off, mode, &prefixes,
|
retval = decode_prefixes(buffer + off, len - off, mode, &prefixes,
|
||||||
&mandatory_prefix, &instr->segment, &vex_operand,
|
&mandatory_prefix, &instr->segment, &vex_operand,
|
||||||
&opcode_escape);
|
&opcode_escape);
|
||||||
if (UNLIKELY(retval < 0 || off + retval >= len))
|
if (UNLIKELY(retval < 0))
|
||||||
return -1;
|
return retval;
|
||||||
|
if (UNLIKELY(off + retval >= len))
|
||||||
|
return FD_ERR_PARTIAL;
|
||||||
off += retval;
|
off += retval;
|
||||||
|
|
||||||
uint32_t kind = ENTRY_TABLE256;
|
uint32_t kind = ENTRY_TABLE256;
|
||||||
@@ -360,7 +362,7 @@ fd_decode(const uint8_t* buffer, size_t len_sz, int mode_int, uintptr_t address,
|
|||||||
ENTRY_UNPACK(table, kind, table[buffer[off++]]);
|
ENTRY_UNPACK(table, kind, table[buffer[off++]]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return -1;
|
return FD_ERR_UD;
|
||||||
|
|
||||||
// Then, walk through ModR/M-encoded opcode extensions.
|
// Then, walk through ModR/M-encoded opcode extensions.
|
||||||
if ((kind == ENTRY_TABLE8 || kind == ENTRY_TABLE72) && LIKELY(off < len))
|
if ((kind == ENTRY_TABLE8 || kind == ENTRY_TABLE72) && LIKELY(off < len))
|
||||||
@@ -394,7 +396,7 @@ fd_decode(const uint8_t* buffer, size_t len_sz, int mode_int, uintptr_t address,
|
|||||||
}
|
}
|
||||||
else if (prefixes & PREFIX_VEX)
|
else if (prefixes & PREFIX_VEX)
|
||||||
{
|
{
|
||||||
return -1;
|
return FD_ERR_UD;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kind == ENTRY_TABLE_PREFIX_REP)
|
if (kind == ENTRY_TABLE_PREFIX_REP)
|
||||||
@@ -416,7 +418,7 @@ fd_decode(const uint8_t* buffer, size_t len_sz, int mode_int, uintptr_t address,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (UNLIKELY(kind != ENTRY_INSTR))
|
if (UNLIKELY(kind != ENTRY_INSTR))
|
||||||
return -1;
|
return FD_ERR_UD;
|
||||||
|
|
||||||
struct InstrDesc* desc = (struct InstrDesc*) table;
|
struct InstrDesc* desc = (struct InstrDesc*) table;
|
||||||
|
|
||||||
@@ -478,7 +480,7 @@ fd_decode(const uint8_t* buffer, size_t len_sz, int mode_int, uintptr_t address,
|
|||||||
retval = decode_modrm(buffer + off, len - off, mode, instr, prefixes,
|
retval = decode_modrm(buffer + off, len - off, mode, instr, prefixes,
|
||||||
desc->vsib, operand1, operand2);
|
desc->vsib, operand1, operand2);
|
||||||
if (UNLIKELY(retval < 0))
|
if (UNLIKELY(retval < 0))
|
||||||
return -1;
|
return retval;
|
||||||
off += retval;
|
off += retval;
|
||||||
}
|
}
|
||||||
else if (DESC_HAS_MODREG(desc))
|
else if (DESC_HAS_MODREG(desc))
|
||||||
@@ -501,7 +503,7 @@ fd_decode(const uint8_t* buffer, size_t len_sz, int mode_int, uintptr_t address,
|
|||||||
}
|
}
|
||||||
else if (vex_operand != 0)
|
else if (vex_operand != 0)
|
||||||
{
|
{
|
||||||
return -1;
|
return FD_ERR_UD;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t imm_control = DESC_IMM_CONTROL(desc);
|
uint32_t imm_control = DESC_IMM_CONTROL(desc);
|
||||||
@@ -521,7 +523,7 @@ fd_decode(const uint8_t* buffer, size_t len_sz, int mode_int, uintptr_t address,
|
|||||||
instr->idx_reg = FD_REG_NONE;
|
instr->idx_reg = FD_REG_NONE;
|
||||||
|
|
||||||
if (UNLIKELY(off + addr_size > len))
|
if (UNLIKELY(off + addr_size > len))
|
||||||
return -1;
|
return FD_ERR_PARTIAL;
|
||||||
#if defined(ARCH_386)
|
#if defined(ARCH_386)
|
||||||
if (addr_size == 2)
|
if (addr_size == 2)
|
||||||
instr->disp = LOAD_LE_2(&buffer[off]);
|
instr->disp = LOAD_LE_2(&buffer[off]);
|
||||||
@@ -561,7 +563,7 @@ fd_decode(const uint8_t* buffer, size_t len_sz, int mode_int, uintptr_t address,
|
|||||||
imm_size = 4;
|
imm_size = 4;
|
||||||
|
|
||||||
if (UNLIKELY(off + imm_size > len))
|
if (UNLIKELY(off + imm_size > len))
|
||||||
return -1;
|
return FD_ERR_PARTIAL;
|
||||||
|
|
||||||
if (imm_size == 1)
|
if (imm_size == 1)
|
||||||
instr->imm = (int8_t) LOAD_LE_1(&buffer[off]);
|
instr->imm = (int8_t) LOAD_LE_1(&buffer[off]);
|
||||||
@@ -599,16 +601,16 @@ fd_decode(const uint8_t* buffer, size_t len_sz, int mode_int, uintptr_t address,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((prefixes & PREFIX_LOCK) && !desc->lock)
|
if ((prefixes & PREFIX_LOCK) && !desc->lock)
|
||||||
return -1;
|
return FD_ERR_UD;
|
||||||
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 FD_ERR_UD;
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++)
|
for (int i = 0; i < 4; i++)
|
||||||
{
|
{
|
||||||
uint32_t reg_type = (desc->reg_types >> 4 * i) & 0xf;
|
uint32_t reg_type = (desc->reg_types >> 4 * i) & 0xf;
|
||||||
uint32_t reg_idx = instr->operands[i].reg;
|
uint32_t reg_idx = instr->operands[i].reg;
|
||||||
if (reg_type == FD_RT_MEM && instr->operands[i].type != FD_OT_MEM)
|
if (reg_type == FD_RT_MEM && instr->operands[i].type != FD_OT_MEM)
|
||||||
return -1;
|
return FD_ERR_UD;
|
||||||
if (instr->operands[i].type != FD_OT_REG)
|
if (instr->operands[i].type != FD_OT_REG)
|
||||||
continue;
|
continue;
|
||||||
if (reg_type == FD_RT_GPL && !(prefixes & PREFIX_REX) &&
|
if (reg_type == FD_RT_GPL && !(prefixes & PREFIX_REX) &&
|
||||||
@@ -616,14 +618,14 @@ fd_decode(const uint8_t* buffer, size_t len_sz, int mode_int, uintptr_t address,
|
|||||||
reg_type = FD_RT_GPH;
|
reg_type = FD_RT_GPH;
|
||||||
// Reject invalid segment registers
|
// Reject invalid segment registers
|
||||||
if (reg_type == FD_RT_SEG && reg_idx >= 6)
|
if (reg_type == FD_RT_SEG && reg_idx >= 6)
|
||||||
return -1;
|
return FD_ERR_UD;
|
||||||
// Reject invalid control registers
|
// Reject invalid control registers
|
||||||
if (reg_type == FD_RT_CR && reg_idx != 0 && reg_idx != 2 &&
|
if (reg_type == FD_RT_CR && reg_idx != 0 && reg_idx != 2 &&
|
||||||
reg_idx != 3 && reg_idx != 4 && reg_idx != 8)
|
reg_idx != 3 && reg_idx != 4 && reg_idx != 8)
|
||||||
return -1;
|
return FD_ERR_UD;
|
||||||
// Reject invalid debug registers
|
// Reject invalid debug registers
|
||||||
if (reg_type == FD_RT_DR && reg_idx >= 8)
|
if (reg_type == FD_RT_DR && reg_idx >= 8)
|
||||||
return -1;
|
return FD_ERR_UD;
|
||||||
instr->operands[i].misc = reg_type;
|
instr->operands[i].misc = reg_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
6
fadec.h
6
fadec.h
@@ -103,6 +103,12 @@ typedef struct {
|
|||||||
uintptr_t address;
|
uintptr_t address;
|
||||||
} FdInstr;
|
} FdInstr;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
FD_ERR_UD = -1,
|
||||||
|
FD_ERR_INTERNAL = -2,
|
||||||
|
FD_ERR_PARTIAL = -3,
|
||||||
|
} FdErr;
|
||||||
|
|
||||||
|
|
||||||
/** Decode an instruction.
|
/** Decode an instruction.
|
||||||
* \param buf Buffer for instruction bytes.
|
* \param buf Buffer for instruction bytes.
|
||||||
|
|||||||
Reference in New Issue
Block a user