X86 SigHandler: Add support for BEXTR instruction

BEXTR is emitted for znver CPUs in recent LLVM.
This commit is contained in:
Ivan Chikish 2023-05-05 12:39:09 +03:00 committed by Ivan
parent 3947250daa
commit 3cf8c629fa

View File

@ -277,8 +277,11 @@ enum x64_op_t : u32
X64OP_ADC, // lock adc [mem], ...
X64OP_SUB, // lock sub [mem], ...
X64OP_SBB, // lock sbb [mem], ...
X64OP_BEXTR,
};
static thread_local x64_reg_t s_tls_reg3{};
void decode_x64_reg_op(const u8* code, x64_op_t& out_op, x64_reg_t& out_reg, usz& out_size, usz& out_length)
{
// simple analysis of x64 code allows to reinterpret MOV or other instructions in any desired way
@ -739,10 +742,12 @@ void decode_x64_reg_op(const u8* code, x64_op_t& out_op, x64_reg_t& out_reg, usz
const u8 vopm = op1 == 0xc5 ? 1 : op2 & 0x1f;
const u8 vop1 = op1 == 0xc5 ? op3 : code[2];
const u8 vlen = (opx & 0x4) ? 32 : 16;
//const u8 vreg = (~opx >> 3) & 0xf;
const u8 vreg = (~opx >> 3) & 0xf;
out_length += op1 == 0xc5 ? 2 : 3;
code += op1 == 0xc5 ? 2 : 3;
s_tls_reg3 = x64_reg_t{vreg};
if (vopm == 0x1) switch (vop1) // Implied leading byte 0x0F
{
case 0x11:
@ -772,6 +777,22 @@ void decode_x64_reg_op(const u8* code, x64_op_t& out_op, x64_reg_t& out_reg, usz
}
}
if (vopm == 0x2) switch (vop1) // Implied leading bytes 0x0F 0x38
{
case 0xf7:
{
if (!repe && !repne && vlen == 16) // BEXTR r32,mem,r32
{
out_op = X64OP_BEXTR;
out_reg = get_modRM_reg_xmm(code, rex);
out_size = opx & 0x80 ? 8 : 4;
out_length += get_modRM_size(code);
return;
}
break;
}
}
break;
}
case 0xc6:
@ -1367,6 +1388,37 @@ bool handle_access_violation(u32 addr, bool is_writing, ucontext_t* context) noe
break;
}
case X64OP_BEXTR:
{
u32 value;
if (is_writing || !thread->read_reg(addr, value))
{
return false;
}
value = stx::se_storage<u32>::swap(value);
u64 ctrl;
if (!get_x64_reg_value(context, s_tls_reg3, d_size, i_size, ctrl))
{
return false;
}
u8 start = ctrl & 0xff;
u8 _len = (ctrl & 0xff00) >> 8;
if (_len > 32)
_len = 32;
if (start > 32)
start = 32;
value = (u64{value} >> start) & ~(u64{umax} << _len);
if (!put_x64_reg_value(context, reg, d_size, value) || !set_x64_cmp_flags(context, d_size, value, 0))
{
return false;
}
break;
}
case X64OP_STORE:
case X64OP_STORE_BE:
{