Browse Source

Implemented a reverse oprand lookup table. It holds pointers to relevant operands inside INSTRUX, for quick lookup.

Moved helper functions in bdhelpers.c.
Added a dedicated BranchInfo field inside INSTRUX, containing the most relevant branch information.
pull/53/head
BITDEFENDER\vlutas 11 months ago
parent
commit
433e723e07
  1. 218
      bddisasm/bddisasm.c
  2. 1
      bddisasm/bddisasm.vcxproj
  3. 3
      bddisasm/bddisasm.vcxproj.filters
  4. 321
      bddisasm/bdhelpers.c
  5. 15
      bddisasm/include/instructions.h
  6. 5
      bddisasm/include/nd_crt.h
  7. 4
      bddisasm_test/basic/tsx_64.result
  8. 2
      bddisasm_test/basic/vmx_64.result
  9. 4
      bddisasm_test/fred/fred_64.result
  10. 2
      bddisasm_test/uintr/uintr_64.result
  11. 2
      bindings/pybddisasm/setup.py
  12. 125
      inc/bddisasm.h
  13. 1
      inc/constants.h
  14. 2
      inc/version.h
  15. 10
      isagenerator/instructions/table_0F.dat
  16. 2
      isagenerator/instructions/table_base.dat

218
bddisasm/bddisasm.c

@ -1719,6 +1719,7 @@ NdParseOperand(
operand->Info.Register.Type = ND_REG_SEG;
operand->Info.Register.Size = (ND_REG_SIZE)size;
operand->Info.Register.Reg = NDR_CS;
Instrux->CsAccess |= operand->Access.Access;
break;
case ND_OPT_SEG_SS:
@ -4101,6 +4102,18 @@ NdDecodeWithContext(
Instrux->IsCetTracked = ND_HAS_CETT(Instrux) && ((!ND_DNT_SUPPORT(Instrux)) ||
(Instrux->Seg != ND_PREFIX_G2_NO_TRACK));
// Fill in branch information.
if (!!(Instrux->RipAccess & ND_ACCESS_ANY_WRITE))
{
Instrux->BranchInfo.IsBranch = 1;
Instrux->BranchInfo.IsConditional = Instrux->Category == ND_CAT_COND_BR;
// Indirect branches are those which get their target address from a register or memory, including RET familly.
Instrux->BranchInfo.IsIndirect = ((!Instrux->Operands[0].Flags.IsDefault) &&
(Instrux->Operands[0].Type == ND_OP_REG) || (Instrux->Operands[0].Type == ND_OP_MEM)) ||
(Instrux->Category == ND_CAT_RET);
Instrux->BranchInfo.IsFar = !!(Instrux->CsAccess & ND_ACCESS_ANY_WRITE);
}
// Do instruction validations. These checks are made in order to filter out encodings that would normally
// be invalid and would generate #UD.
status = NdValidateInstruction(Instrux);
@ -4145,212 +4158,9 @@ NdDecode(
}
//
// NdIsInstruxRipRelative
//
bool
NdIsInstruxRipRelative(
const INSTRUX *Instrux
)
//
// Provided for backwards compatibility with existing code that uses disasm 1.0
//
{
if (NULL == Instrux)
{
return false;
}
else
{
return Instrux->IsRipRelative;
}
}
//
// NdGetFullAccessMap
// NdInitContext
//
NDSTATUS
NdGetFullAccessMap(
const INSTRUX *Instrux,
ND_ACCESS_MAP *AccessMap
)
{
uint32_t i;
const ND_OPERAND *pOp;
// pre-init
i = 0;
pOp = NULL;
// validate
if (NULL == Instrux)
{
return ND_STATUS_INVALID_PARAMETER;
}
if (NULL == AccessMap)
{
return ND_STATUS_INVALID_PARAMETER;
}
for (i = 0; i < Instrux->OperandsCount; i++)
{
pOp = &Instrux->Operands[i];
if (ND_OP_MEM == pOp->Type)
{
if (pOp->Info.Memory.IsStack)
{
AccessMap->StackAccess |= pOp->Access.Access;
AccessMap->GprAccess[NDR_RSP] |= ND_ACCESS_READ|ND_ACCESS_WRITE;
AccessMap->SegAccess[NDR_SS] |= ND_ACCESS_READ;
}
else
{
AccessMap->MemAccess |= pOp->Access.Access;
if (pOp->Info.Memory.HasSeg)
{
AccessMap->SegAccess[pOp->Info.Memory.Seg] |= ND_ACCESS_READ;
}
if (pOp->Info.Memory.HasBase)
{
AccessMap->GprAccess[pOp->Info.Memory.Base] |= ND_ACCESS_READ;
}
if (pOp->Info.Memory.HasIndex)
{
if (pOp->Info.Memory.IsVsib)
{
AccessMap->SseAccess[pOp->Info.Memory.Index] |= ND_ACCESS_READ;
}
else
{
AccessMap->GprAccess[pOp->Info.Memory.Index] |= ND_ACCESS_READ;
}
}
}
}
else if (ND_OP_REG == pOp->Type)
{
switch (pOp->Info.Register.Type)
{
case ND_REG_GPR:
{
uint32_t k;
for (k = 0; k < pOp->Info.Register.Count; k++)
{
AccessMap->GprAccess[pOp->Info.Register.Reg + k] |= pOp->Access.Access;
}
}
break;
case ND_REG_SEG:
AccessMap->SegAccess[pOp->Info.Register.Reg] |= pOp->Access.Access;
break;
case ND_REG_FPU:
AccessMap->FpuAccess[pOp->Info.Register.Reg] |= pOp->Access.Access;
break;
case ND_REG_MMX:
AccessMap->MmxAccess[pOp->Info.Register.Reg] |= pOp->Access.Access;
break;
case ND_REG_SSE:
{
uint32_t k;
for (k = 0; k < pOp->Info.Register.Count; k++)
{
AccessMap->SseAccess[pOp->Info.Register.Reg + k] |= pOp->Access.Access;
}
}
break;
case ND_REG_CR:
AccessMap->CrAccess[pOp->Info.Register.Reg] |= pOp->Access.Access;
break;
case ND_REG_DR:
AccessMap->DrAccess[pOp->Info.Register.Reg] |= pOp->Access.Access;
break;
case ND_REG_TR:
AccessMap->TrAccess[pOp->Info.Register.Reg] |= pOp->Access.Access;
break;
case ND_REG_BND:
AccessMap->BndAccess[pOp->Info.Register.Reg] |= pOp->Access.Access;
break;
case ND_REG_MSK:
AccessMap->MskAccess[pOp->Info.Register.Reg] |= pOp->Access.Access;
break;
case ND_REG_SYS:
AccessMap->SysAccess[pOp->Info.Register.Reg] |= pOp->Access.Access;
break;
case ND_REG_X87:
AccessMap->X87Access[pOp->Info.Register.Reg] |= pOp->Access.Access;
break;
case ND_REG_FLG:
AccessMap->FlagsAccess |= pOp->Access.Access;
break;
case ND_REG_RIP:
AccessMap->RipAccess |= pOp->Access.Access;
break;
case ND_REG_MXCSR:
AccessMap->MxcsrAccess |= pOp->Access.Access;
break;
case ND_REG_PKRU:
AccessMap->PkruAccess |= pOp->Access.Access;
break;
case ND_REG_SSP:
AccessMap->SspAccess |= pOp->Access.Access;
break;
default:
break;
}
}
else if (ND_OP_BANK == Instrux->Operands[i].Type)
{
uint8_t j;
// Bank registers access. This needs special handling. Note that LOADALL/LOADALLD is not supported, as
// it is too old and it's not valid since the good old 486.
if (ND_INS_FNSAVE == Instrux->Instruction)
{
for (j = 0; j < ND_MAX_FPU_REGS; j++)
{
AccessMap->FpuAccess[j] |= ND_ACCESS_READ;
}
}
else if (ND_INS_FRSTOR == Instrux->Instruction)
{
for (j = 0; j < ND_MAX_FPU_REGS; j++)
{
AccessMap->FpuAccess[j] |= ND_ACCESS_WRITE;
}
}
if ((ND_INS_XSAVE == Instrux->Instruction) || (ND_INS_XSAVEOPT == Instrux->Instruction) ||
(ND_INS_XSAVES == Instrux->Instruction) || (ND_INS_XSAVEC == Instrux->Instruction))
{
for (j = 0; j < ND_MAX_SSE_REGS; j++)
{
AccessMap->SseAccess[j] |= ND_ACCESS_READ;
}
}
else if ((ND_INS_XRSTOR == Instrux->Instruction) || (ND_INS_XRSTORS == Instrux->Instruction))
{
for (j = 0; j < ND_MAX_SSE_REGS; j++)
{
AccessMap->SseAccess[j] |= ND_ACCESS_WRITE;
}
}
}
}
return ND_STATUS_SUCCESS;
}
void
NdInitContext(
ND_CONTEXT *Context

1
bddisasm/bddisasm.vcxproj

@ -421,6 +421,7 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="bdformat.c" />
<ClCompile Include="bdhelpers.c" />
<ClCompile Include="crt.c" />
<ClCompile Include="bddisasm.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='ReleaseKernel|Win32'">NotUsing</PrecompiledHeader>

3
bddisasm/bddisasm.vcxproj.filters

@ -30,6 +30,9 @@
<ClCompile Include="bdformat.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="bdhelpers.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="include\instructions.h">

321
bddisasm/bdhelpers.c

@ -0,0 +1,321 @@
#include "include/nd_crt.h"
#include "../inc/bddisasm.h"
//
// NdIsInstruxRipRelative
//
bool
NdIsInstruxRipRelative(
const INSTRUX *Instrux
)
//
// Provided for backwards compatibility with existing code that uses disasm 1.0
//
{
if (NULL == Instrux)
{
return false;
}
else
{
return Instrux->IsRipRelative;
}
}
//
// NdGetFullAccessMap
//
NDSTATUS
NdGetFullAccessMap(
const INSTRUX *Instrux,
ND_ACCESS_MAP *AccessMap
)
{
uint32_t i;
const ND_OPERAND *pOp;
// pre-init
i = 0;
pOp = NULL;
// validate
if (NULL == Instrux)
{
return ND_STATUS_INVALID_PARAMETER;
}
if (NULL == AccessMap)
{
return ND_STATUS_INVALID_PARAMETER;
}
for (i = 0; i < Instrux->OperandsCount; i++)
{
pOp = &Instrux->Operands[i];
if (ND_OP_MEM == pOp->Type)
{
if (pOp->Info.Memory.IsStack)
{
AccessMap->StackAccess |= pOp->Access.Access;
AccessMap->GprAccess[NDR_RSP] |= ND_ACCESS_READ|ND_ACCESS_WRITE;
AccessMap->SegAccess[NDR_SS] |= ND_ACCESS_READ;
}
else
{
AccessMap->MemAccess |= pOp->Access.Access;
if (pOp->Info.Memory.HasSeg)
{
AccessMap->SegAccess[pOp->Info.Memory.Seg] |= ND_ACCESS_READ;
}
if (pOp->Info.Memory.HasBase)
{
AccessMap->GprAccess[pOp->Info.Memory.Base] |= ND_ACCESS_READ;
}
if (pOp->Info.Memory.HasIndex)
{
if (pOp->Info.Memory.IsVsib)
{
AccessMap->SseAccess[pOp->Info.Memory.Index] |= ND_ACCESS_READ;
}
else
{
AccessMap->GprAccess[pOp->Info.Memory.Index] |= ND_ACCESS_READ;
}
}
}
}
else if (ND_OP_REG == pOp->Type)
{
switch (pOp->Info.Register.Type)
{
case ND_REG_GPR:
{
uint32_t k;
for (k = 0; k < pOp->Info.Register.Count; k++)
{
AccessMap->GprAccess[pOp->Info.Register.Reg + k] |= pOp->Access.Access;
}
}
break;
case ND_REG_SEG:
AccessMap->SegAccess[pOp->Info.Register.Reg] |= pOp->Access.Access;
break;
case ND_REG_FPU:
AccessMap->FpuAccess[pOp->Info.Register.Reg] |= pOp->Access.Access;
break;
case ND_REG_MMX:
AccessMap->MmxAccess[pOp->Info.Register.Reg] |= pOp->Access.Access;
break;
case ND_REG_SSE:
{
uint32_t k;
for (k = 0; k < pOp->Info.Register.Count; k++)
{
AccessMap->SseAccess[pOp->Info.Register.Reg + k] |= pOp->Access.Access;
}
}
break;
case ND_REG_CR:
AccessMap->CrAccess[pOp->Info.Register.Reg] |= pOp->Access.Access;
break;
case ND_REG_DR:
AccessMap->DrAccess[pOp->Info.Register.Reg] |= pOp->Access.Access;
break;
case ND_REG_TR:
AccessMap->TrAccess[pOp->Info.Register.Reg] |= pOp->Access.Access;
break;
case ND_REG_BND:
AccessMap->BndAccess[pOp->Info.Register.Reg] |= pOp->Access.Access;
break;
case ND_REG_MSK:
AccessMap->MskAccess[pOp->Info.Register.Reg] |= pOp->Access.Access;
break;
case ND_REG_SYS:
AccessMap->SysAccess[pOp->Info.Register.Reg] |= pOp->Access.Access;
break;
case ND_REG_X87:
AccessMap->X87Access[pOp->Info.Register.Reg] |= pOp->Access.Access;
break;
case ND_REG_FLG:
AccessMap->FlagsAccess |= pOp->Access.Access;
break;
case ND_REG_RIP:
AccessMap->RipAccess |= pOp->Access.Access;
break;
case ND_REG_MXCSR:
AccessMap->MxcsrAccess |= pOp->Access.Access;
break;
case ND_REG_PKRU:
AccessMap->PkruAccess |= pOp->Access.Access;
break;
case ND_REG_SSP:
AccessMap->SspAccess |= pOp->Access.Access;
break;
case ND_REG_TILE:
AccessMap->TmmAccess[pOp->Info.Register.Reg] |= pOp->Access.Access;
break;
default:
break;
}
}
else if (ND_OP_BANK == Instrux->Operands[i].Type)
{
uint8_t j;
// Bank registers access. This needs special handling. Note that LOADALL/LOADALLD is not supported, as
// it is too old and it's not valid since the good old 486.
if (ND_INS_FNSAVE == Instrux->Instruction)
{
for (j = 0; j < ND_MAX_FPU_REGS; j++)
{
AccessMap->FpuAccess[j] |= ND_ACCESS_READ;
}
}
else if (ND_INS_FRSTOR == Instrux->Instruction)
{
for (j = 0; j < ND_MAX_FPU_REGS; j++)
{
AccessMap->FpuAccess[j] |= ND_ACCESS_WRITE;
}
}
if ((ND_INS_XSAVE == Instrux->Instruction) || (ND_INS_XSAVEOPT == Instrux->Instruction) ||
(ND_INS_XSAVES == Instrux->Instruction) || (ND_INS_XSAVEC == Instrux->Instruction))
{
for (j = 0; j < ND_MAX_SSE_REGS; j++)
{
AccessMap->SseAccess[j] |= ND_ACCESS_READ;
}
}
else if ((ND_INS_XRSTOR == Instrux->Instruction) || (ND_INS_XRSTORS == Instrux->Instruction))
{
for (j = 0; j < ND_MAX_SSE_REGS; j++)
{
AccessMap->SseAccess[j] |= ND_ACCESS_WRITE;
}
}
}
}
return ND_STATUS_SUCCESS;
}
//
// NdGetOperandRlut
//
NDSTATUS
NdGetOperandRlut(
INSTRUX *Instrux,
ND_OPERAND_RLUT *Rlut
)
{
if (NULL == Instrux)
{
return ND_STATUS_INVALID_PARAMETER;
}
if (NULL == Rlut)
{
return ND_STATUS_INVALID_PARAMETER;
}
// Initialize the RLUT.
nd_memset(Rlut, 0, sizeof(*Rlut));
for (uint8_t i = 0; i < Instrux->OperandsCount; i++)
{
if (!!(Instrux->Operands[i].Access.Access & ND_ACCESS_ANY_WRITE))
{
// We only care about the first 2 destination operands.
if (Rlut->Dst1 == NULL)
{
Rlut->Dst1 = &Instrux->Operands[i];
}
else if (Rlut->Dst2 == NULL)
{
Rlut->Dst2 = &Instrux->Operands[i];
}
}
if (!!(Instrux->Operands[i].Access.Access & ND_ACCESS_ANY_READ))
{
// We only care about the first 4 source operands.
if (Rlut->Src1 == NULL)
{
Rlut->Src1 = &Instrux->Operands[i];
}
else if (Rlut->Src2 == NULL)
{
Rlut->Src2 = &Instrux->Operands[i];
}
else if (Rlut->Src3 == NULL)
{
Rlut->Src3 = &Instrux->Operands[i];
}
else if (Rlut->Src4 == NULL)
{
Rlut->Src4 = &Instrux->Operands[i];
}
}
if (Instrux->Operands[i].Type == ND_OP_MEM)
{
// We only care about the first 2 memory operands.
if (Rlut->Mem1 == NULL)
{
Rlut->Mem1 = &Instrux->Operands[i];
}
else if (Rlut->Mem2 == NULL)
{
Rlut->Mem2 = &Instrux->Operands[i];
}
if (Instrux->Operands[i].Info.Memory.IsStack)
{
Rlut->Stack = &Instrux->Operands[i];
}
}
if (Instrux->Operands[i].Type == ND_OP_REG && Instrux->Operands->Flags.IsDefault)
{
switch (Instrux->Operands[i].Info.Register.Type)
{
case ND_REG_FLG:
Rlut->Flags = &Instrux->Operands[i];
break;
case ND_REG_RIP:
Rlut->Rip = &Instrux->Operands[i];;
break;
case ND_REG_SEG:
if (Instrux->Operands[i].Info.Register.Reg == NDR_CS)
{
Rlut->Cs = &Instrux->Operands[i];
}
else if (Instrux->Operands[i].Info.Register.Reg == NDR_SS)
{
Rlut->Ss = &Instrux->Operands[i];
}
break;
case ND_REG_GPR:
if (Instrux->Operands[i].Info.Register.Reg < 8)
{
*(&Rlut->Rax + Instrux->Operands[i].Info.Register.Reg) = &Instrux->Operands[i];
}
break;
default:
break;
}
}
}
return ND_STATUS_SUCCESS;
}

15
bddisasm/include/instructions.h

@ -3983,7 +3983,7 @@ const ND_INSTRUCTION gInstructions[2701] =
// Pos:239 Instruction:"ERETS" Encoding:"0xF2 0x0F 0x01 /0xCA"/""
{
ND_INS_ERETS, ND_CAT_FRED, ND_SET_FRED, 169,
ND_INS_ERETS, ND_CAT_RET, ND_SET_FRED, 169,
0,
ND_MOD_R0|ND_MOD_LONG|ND_MOD_VMXR|ND_MOD_VMXN|ND_MOD_VMXR_SEAM|ND_MOD_VMXN_SEAM|ND_MOD_VMX_OFF|ND_MOD_SMM|ND_MOD_SMM_OFF|ND_MOD_SGX_OFF|ND_MOD_TSX_OFF,
0, ND_OPS_CNT(0, 5), 0, 0, 0, 0, 0, 0, ND_FLAG_F64|ND_FLAG_MODRM|ND_FLAG_O64, ND_CFF_FRED,
@ -4002,7 +4002,7 @@ const ND_INSTRUCTION gInstructions[2701] =
// Pos:240 Instruction:"ERETU" Encoding:"0xF3 0x0F 0x01 /0xCA"/""
{
ND_INS_ERETU, ND_CAT_FRED, ND_SET_FRED, 170,
ND_INS_ERETU, ND_CAT_RET, ND_SET_FRED, 170,
0,
ND_MOD_R0|ND_MOD_LONG|ND_MOD_VMXR|ND_MOD_VMXN|ND_MOD_VMXR_SEAM|ND_MOD_VMXN_SEAM|ND_MOD_VMX_OFF|ND_MOD_SMM|ND_MOD_SMM_OFF|ND_MOD_SGX_OFF|ND_MOD_TSX_OFF,
0, ND_OPS_CNT(0, 9), 0, 0, 0, 0, 0, 0, ND_FLAG_F64|ND_FLAG_MODRM|ND_FLAG_O64, ND_CFF_FRED,
@ -22273,7 +22273,7 @@ const ND_INSTRUCTION gInstructions[2701] =
// Pos:1349 Instruction:"UIRET" Encoding:"0xF3 0x0F 0x01 /0xEC"/""
{
ND_INS_UIRET, ND_CAT_UINTR, ND_SET_UINTR, 810,
ND_INS_UIRET, ND_CAT_RET, ND_SET_UINTR, 810,
0,
ND_MOD_R0|ND_MOD_R1|ND_MOD_R2|ND_MOD_R3|ND_MOD_LONG|ND_MOD_VMXR|ND_MOD_VMXN|ND_MOD_VMXR_SEAM|ND_MOD_VMXN_SEAM|ND_MOD_VMX_OFF|ND_MOD_SMM|ND_MOD_SMM_OFF|ND_MOD_SGX_OFF|ND_MOD_TSX_OFF,
0, ND_OPS_CNT(0, 6), 0, 0, 0, 0, 0, 0, ND_FLAG_F64|ND_FLAG_MODRM|ND_FLAG_O64, ND_CFF_UINTR,
@ -30955,7 +30955,7 @@ const ND_INSTRUCTION gInstructions[2701] =
{
ND_INS_VMCALL, ND_CAT_VTX, ND_SET_VTX, 1160,
0,
ND_MOD_R0|ND_MOD_R1|ND_MOD_R2|ND_MOD_R3|ND_MOD_REAL|ND_MOD_V8086|ND_MOD_PROT|ND_MOD_COMPAT|ND_MOD_LONG|ND_MOD_VMXR|ND_MOD_VMXN|ND_MOD_VMXR_SEAM|ND_MOD_VMXN_SEAM|ND_MOD_SMM|ND_MOD_SMM_OFF|ND_MOD_SGX_OFF|ND_MOD_TSX|ND_MOD_TSX_OFF,
ND_MOD_R0|ND_MOD_R1|ND_MOD_R2|ND_MOD_R3|ND_MOD_REAL|ND_MOD_V8086|ND_MOD_PROT|ND_MOD_COMPAT|ND_MOD_LONG|ND_MOD_VMXR|ND_MOD_VMXN|ND_MOD_VMXR_SEAM|ND_MOD_VMXN_SEAM|ND_MOD_SMM|ND_MOD_SMM_OFF|ND_MOD_SGX_OFF|ND_MOD_TSX_OFF,
0, ND_OPS_CNT(0, 0), 0, 0, 0, 0, 0, 0, ND_FLAG_MODRM, ND_CFF_VTX,
0,
0,
@ -44744,13 +44744,14 @@ const ND_INSTRUCTION gInstructions[2701] =
ND_INS_XABORT, ND_CAT_UNCOND_BR, ND_SET_TSX, 1661,
0,
ND_MOD_R0|ND_MOD_R1|ND_MOD_R2|ND_MOD_R3|ND_MOD_REAL|ND_MOD_V8086|ND_MOD_PROT|ND_MOD_COMPAT|ND_MOD_LONG|ND_MOD_VMXR|ND_MOD_VMXN|ND_MOD_VMXR_SEAM|ND_MOD_VMXN_SEAM|ND_MOD_VMX_OFF|ND_MOD_SMM|ND_MOD_SMM_OFF|ND_MOD_SGX|ND_MOD_SGX_OFF|ND_MOD_TSX_OFF,
0, ND_OPS_CNT(1, 1), 0, 0, 0, 0, 0, 0, ND_FLAG_MODRM, ND_CFF_RTM,
0, ND_OPS_CNT(1, 2), 0, 0, 0, 0, 0, 0, ND_FLAG_MODRM, ND_CFF_RTM,
0,
0,
0,
0,
{
OP(ND_OPT_I, ND_OPS_b, 0, ND_OPA_R, 0, 0),
OP(ND_OPT_RIP, ND_OPS_yf, ND_OPF_DEFAULT, ND_OPA_W, 0, 0),
OP(ND_OPT_GPR_rAX, ND_OPS_d, ND_OPF_DEFAULT, ND_OPA_RCW, 0, 0),
},
},
@ -45046,13 +45047,13 @@ const ND_INSTRUCTION gInstructions[2701] =
ND_INS_XEND, ND_CAT_COND_BR, ND_SET_TSX, 1670,
0,
ND_MOD_ANY,
0, ND_OPS_CNT(0, 0), 0, 0, 0, 0, 0, 0, ND_FLAG_MODRM, ND_CFF_RTM,
0, ND_OPS_CNT(0, 1), 0, 0, 0, 0, 0, 0, ND_FLAG_MODRM, ND_CFF_RTM,
0,
0,
0,
0,
{
0
OP(ND_OPT_RIP, ND_OPS_yf, ND_OPF_DEFAULT, ND_OPA_CW, 0, 0),
},
},

5
bddisasm/include/nd_crt.h

@ -12,8 +12,7 @@
#endif
#if defined(_MSC_VER)
typedef char * va_list;
#include <vadefs.h>
# ifndef _ADDRESSOF
# ifdef __cplusplus
@ -27,8 +26,6 @@ typedef char * va_list;
# if defined(AMD64) || defined(WIN64)
extern void __cdecl __va_start(__out va_list *, ...); // is this exported by VC compiler?
# define _crt_va_start(ap, x) ( __va_start(&ap, x) )
# define _crt_va_arg(ap, t) ( ( sizeof(t) > sizeof(QWORD) || ( sizeof(t) & (sizeof(t) - 1) ) != 0 ) \
? **(t **)( ( ap += sizeof(QWORD) ) - sizeof(QWORD) ) \

4
bddisasm_test/basic/tsx_64.result

@ -46,7 +46,8 @@
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: R-, Type: Immediate, Size: 1, RawSize: 1, Encoding: I
Operand: 1, Acc: RCW, Type: Register, Size: 4, RawSize: 4, Encoding: S, RegType: General Purpose, RegSize: 4, RegId: 0, RegCount: 1
Operand: 1, Acc: -W, Type: Register, Size: 8, RawSize: 8, Encoding: S, RegType: IP, RegSize: 8, RegId: 0, RegCount: 1
Operand: 2, Acc: RCW, Type: Register, Size: 4, RawSize: 4, Encoding: S, RegType: General Purpose, RegSize: 4, RegId: 0, RegCount: 1
000000000000000C 0f01d5 XEND
DSIZE: 32, ASIZE: 64, VLEN: -
@ -61,6 +62,7 @@
REP: no, REPcc: no, LOCK: no
HLE: no, XACQUIRE only: no, XRELEASE only: no
BND: no, BHINT: no, DNT: no
Operand: 0, Acc: CW, Type: Register, Size: 8, RawSize: 8, Encoding: S, RegType: IP, RegSize: 8, RegId: 0, RegCount: 1
000000000000000F f20f01e8 XSUSLDTRK
DSIZE: 32, ASIZE: 64, VLEN: -

2
bddisasm_test/basic/vmx_64.result

@ -5,7 +5,7 @@
Valid modes
R0: yes, R1: yes, R2: yes, R3: yes
Real: yes, V8086: yes, Prot: yes, Compat: yes, Long: yes
SMM on: yes, SMM off: yes, SGX on: no, SGX off: yes, TSX on: yes, TSX off: yes
SMM on: yes, SMM off: yes, SGX on: no, SGX off: yes, TSX on: no, TSX off: yes
VMXRoot: yes, VMXNonRoot: yes, VMXRoot SEAM: yes, VMXNonRoot SEAM: yes, VMX off: no
Valid prefixes
REP: no, REPcc: no, LOCK: no

4
bddisasm_test/fred/fred_64.result

@ -1,6 +1,6 @@
0000000000000000 f30f01ca ERETU
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: FRED, Ins cat: FRED, CET tracked: no
ISA Set: FRED, Ins cat: RET, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 17
FLAGS access
Entire register
@ -26,7 +26,7 @@
0000000000000004 f20f01ca ERETS
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: FRED, Ins cat: FRED, CET tracked: no
ISA Set: FRED, Ins cat: RET, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000001, reg: eax, bit: 17
FLAGS access
Entire register

2
bddisasm_test/uintr/uintr_64.result

@ -1,6 +1,6 @@
0000000000000000 f30f01ec UIRET
DSIZE: 64, ASIZE: 64, VLEN: -
ISA Set: UINTR, Ins cat: UINTR, CET tracked: no
ISA Set: UINTR, Ins cat: RET, CET tracked: no
CPUID leaf: 0x00000007, sub-leaf: 0x00000000, reg: edx, bit: 5
FLAGS access
Entire register

2
bindings/pybddisasm/setup.py

@ -12,7 +12,7 @@ from setuptools import find_packages, setup, Command, Extension, Distribution
from codecs import open
VERSION = (0, 1, 3)
LIBRARY_VERSION = (1, 34, 5)
LIBRARY_VERSION = (1, 34, 7)
LIBRARY_INSTRUX_SIZE = 864
packages = ['pybddisasm']

125
inc/bddisasm.h

@ -669,35 +669,6 @@ typedef enum _ND_EX_TYPE_AMX
} ND_EX_TYPE_AMX;
//
// Operands access map. Contains every register except for MSR & XCR, includes memory, flags, RIP, stack.
// Use NdGetFullAccessMap to populate this structure.
//
typedef struct _ND_ACCESS_MAP
{
uint8_t RipAccess;
uint8_t FlagsAccess;
uint8_t StackAccess;
uint8_t MemAccess;
uint8_t MxcsrAccess;
uint8_t PkruAccess;
uint8_t SspAccess;
uint8_t GprAccess[ND_MAX_GPR_REGS];
uint8_t SegAccess[ND_MAX_SEG_REGS];
uint8_t FpuAccess[ND_MAX_FPU_REGS];
uint8_t MmxAccess[ND_MAX_MMX_REGS];
uint8_t SseAccess[ND_MAX_SSE_REGS];
uint8_t CrAccess [ND_MAX_CR_REGS ];
uint8_t DrAccess [ND_MAX_DR_REGS ];
uint8_t TrAccess [ND_MAX_TR_REGS ];
uint8_t BndAccess[ND_MAX_BND_REGS];
uint8_t MskAccess[ND_MAX_MSK_REGS];
uint8_t SysAccess[ND_MAX_SYS_REGS];
uint8_t X87Access[ND_MAX_X87_REGS];
} ND_ACCESS_MAP, *PND_ACCESS_MAP;
//
// Operand access mode.
//
@ -1231,6 +1202,18 @@ typedef struct _ND_FPU_FLAGS
} ND_FPU_FLAGS, *PND_FPU_FLAGS;
//
// Branch information.
//
typedef struct _ND_BRANCH_INFO
{
uint8_t IsBranch : 1;
uint8_t IsConditional : 1;
uint8_t IsIndirect : 1;
uint8_t IsFar : 1;
} ND_BRANCH_INFO;
//
// Describes a decoded instruction. All the possible information about the instruction is contained in this structure.
// You don't have to call any other APIs to gather any more info about it.
@ -1394,10 +1377,13 @@ typedef struct _INSTRUX
ND_OPERAND Operands[ND_MAX_OPERAND]; // Instruction operands.
// As extracted from the operands themselves.
uint8_t CsAccess; // CS access mode (read/write). Includes only implicit CS accesses.
uint8_t RipAccess; // RIP access mode (read/write).
uint8_t StackAccess; // Stack access mode (push/pop).
uint8_t MemoryAccess; // Memory access mode (read/write, including stack or shadow stack).
ND_BRANCH_INFO BranchInfo; // Branch information.
struct
{
uint8_t RegAccess; // RFLAGS access mode (read/write), as per the entire register.
@ -1429,11 +1415,9 @@ typedef struct _INSTRUX
ND_VALID_MODES ValidModes; // Valid CPU modes for the instruction.
ND_VALID_PREFIXES ValidPrefixes; // Indicates which prefixes are valid for this instruction.
ND_VALID_DECORATORS ValidDecorators; // What decorators are accepted by the instruction.
uint8_t Reserved1[3]; // Padding purpose. Aligns the mnemonic to 8 bytes.
char Mnemonic[ND_MAX_MNEMONIC_LENGTH]; // Instruction mnemonic.
uint8_t OpCodeBytes[3]; // Opcode bytes - escape codes and main op code
uint8_t PrimaryOpCode; // Main/nominal opcode
uint32_t Reserved2; // Padding purpose. Aligns the InstructionBytes to 16 bytes.
uint8_t InstructionBytes[16]; // The entire instruction.
} INSTRUX, *PINSTRUX;
@ -1454,6 +1438,76 @@ typedef struct _ND_CONTEXT
} ND_CONTEXT;
//
// Operands access map. Contains every register except for MSR & XCR, includes memory, flags, RIP, stack.
// Use NdGetFullAccessMap to populate this structure.
//
typedef struct _ND_ACCESS_MAP
{
uint8_t RipAccess;
uint8_t FlagsAccess;
uint8_t StackAccess;
uint8_t MemAccess;
uint8_t MxcsrAccess;
uint8_t PkruAccess;
uint8_t SspAccess;
uint8_t GprAccess[ND_MAX_GPR_REGS];
uint8_t SegAccess[ND_MAX_SEG_REGS];
uint8_t FpuAccess[ND_MAX_FPU_REGS];
uint8_t MmxAccess[ND_MAX_MMX_REGS];
uint8_t SseAccess[ND_MAX_SSE_REGS];
uint8_t CrAccess [ND_MAX_CR_REGS ];
uint8_t DrAccess [ND_MAX_DR_REGS ];
uint8_t TrAccess [ND_MAX_TR_REGS ];
uint8_t BndAccess[ND_MAX_BND_REGS];
uint8_t MskAccess[ND_MAX_MSK_REGS];
uint8_t TmmAccess[ND_MAX_TILE_REGS];
uint8_t SysAccess[ND_MAX_SYS_REGS];
uint8_t X87Access[ND_MAX_X87_REGS];
} ND_ACCESS_MAP, *PND_ACCESS_MAP;
//
// Operand reverse-lookup table. Each entry inside this structure contains the pointer to the relevant operand.
// Some rules govern this special structure:
// - It is not generated by default. The user must call NdGetOperandRlut manually to fill in this structure.
// - This structure holds pointers inside the INSTRUX provided to the NdGetOperandRlut function; please make sure
// you call NdGetOperandRlut again if the INSTRUX is relocated, as all the pointers will dangle.
// - Not all the operand types have a corresponding entry in ND_OPERAND_RLUT, only the usual ones.
// - Some operands may have multiple entries in ND_OPERAND_RLUT - for example, RMW (read-modify-write) instructions
// will have Dst1 and Src1 pointing to the same operand.
// - The implicit registers entries in ND_OPERAND_RLUT will point to the operand which is of that type, and implicit;
// for example, ND_OPERAND_RLUT.Rax will be NULL for `add rax, rcx`, since in this case, `rax` is not an implicit
// operand. For `cpuid`, however, ND_OPERAND_RLUT.Rax will point to the implicit `eax` register.
// Use NdGetOperandRlut to populate this structure.
//
typedef struct _ND_OPERAND_RLUT
{
PND_OPERAND Dst1; // First destination operand.
PND_OPERAND Dst2; // Second destination operand.
PND_OPERAND Src1; // First source operand.
PND_OPERAND Src2; // Second source operand.
PND_OPERAND Src3; // Third source operand.
PND_OPERAND Src4; // Fourth source operand.
PND_OPERAND Mem1; // First memory operand.
PND_OPERAND Mem2; // Second memory operand.
PND_OPERAND Stack; // Stack operand.
PND_OPERAND Flags; // Flags register operand.
PND_OPERAND Rip; // Instruction Pointer register operand.
PND_OPERAND Cs; // Implicit CS operand.
PND_OPERAND Ss; // Implicit SS operand.
PND_OPERAND Rax; // Implicit accumulator register operand.
PND_OPERAND Rcx; // Implicit counter register operand.
PND_OPERAND Rdx; // Implicit data register operand
PND_OPERAND Rbx; // Implicit base address register operand.
PND_OPERAND Rsp; // Implicit stack pointer operand.
PND_OPERAND Rbp; // Implicit base pointer operand.
PND_OPERAND Rsi; // Implicit source index operand.
PND_OPERAND Rdi; // Implicit destination index operand.
} ND_OPERAND_RLUT;
#ifdef __cplusplus
extern "C" {
#endif
@ -1560,6 +1614,15 @@ NdGetFullAccessMap(
ND_ACCESS_MAP *AccessMap
);
//
// Returns an operand reverse-lookup. One can use the Rlut to quickly reference different kinds of operands in INSTRUX.
//
NDSTATUS
NdGetOperandRlut(
INSTRUX *Instrux,
ND_OPERAND_RLUT *Rlut
);
//
// Initialize the decoder context.
//

1
inc/constants.h

@ -1758,7 +1758,6 @@ typedef enum _ND_INS_TYPE
ND_CAT_EXPAND,
ND_CAT_FLAGOP,
ND_CAT_FMA4,
ND_CAT_FRED,
ND_CAT_GATHER,
ND_CAT_GFNI,
ND_CAT_HRESET,

2
inc/version.h

@ -7,6 +7,6 @@
#define DISASM_VERSION_MAJOR 1
#define DISASM_VERSION_MINOR 34
#define DISASM_VERSION_REVISION 5
#define DISASM_VERSION_REVISION 7
#endif // DISASM_VER_H

10
isagenerator/instructions/table_0F.dat

@ -22,7 +22,7 @@ LMSW Ew CR0 [ 0x0F 0x01 /6
INVLPG Mb nil [ 0x0F 0x01 /7:mem] s:I486REAL, t:SYSTEM, w:R, a:AG, m:KERNEL|NOV86
RSTORSSP Mq SSP [ 0xF3 0x0F 0x01 /5:mem] s:CET_SS, t:CET, a:SHS, w:RW|RW, f:CF=m|ZF=0|PF=0|AF=0|OF=0|SF=0
ENCLV nil EAX,RBX,RCX,RDX [ NP 0x0F 0x01 /0xC0] s:SGX, t:SGX, w:R|CRW|CRW|CRW, m:KERNEL|NOSMM|NOTSX|VMX
VMCALL nil nil [ NP 0x0F 0x01 /0xC1] s:VTX, t:VTX, m:VMX|NOSGX
VMCALL nil nil [ NP 0x0F 0x01 /0xC1] s:VTX, t:VTX, m:VMX|NOTSX|NOSGX
VMLAUNCH nil Fv [ NP 0x0F 0x01 /0xC2] s:VTX, t:VTX, w:W, f:VMX, m:VMXROOT
VMRESUME nil Fv [ NP 0x0F 0x01 /0xC3] s:VTX, t:VTX, w:W, f:VMX, m:VMXROOT
VMXOFF nil Fv [ NP 0x0F 0x01 /0xC4] s:VTX, t:VTX, w:W, f:VMX, m:VMXROOT
@ -30,8 +30,8 @@ PCONFIG nil EAX,RBX,RCX,RDX [ NP 0x0F 0x01 /0
MONITOR nil pAXb,ECX,EDX [ NP 0x0F 0x01 /0xC8] s:SSE3, t:MISC, w:R|R|R, i:MONITOR, m:KERNEL|NOV86
MWAIT nil EAX,ECX [ NP 0x0F 0x01 /0xC9] s:SSE3, t:MISC, w:RW|R, i:MONITOR, m:KERNEL|NOV86
CLAC nil Fv [ NP 0x0F 0x01 /0xCA] s:SMAP, t:SMAP, w:W, f:AC=0, m:KERNEL|NOV86
ERETU nil rIP,Fv,rSP,CS,SS,Kv5,SSP,GSBASE,KGSBASE [0xF3 0x0F 0x01 /0xCA] s:FRED, t:FRED, w:W|W|W|W|W|R|CRCW|RW|RW, m:KERNEL|O64|NOTSX, a:F64
ERETS nil rIP,Fv,rSP,Kv5,SSP [ 0xF2 0x0F 0x01 /0xCA] s:FRED, t:FRED, w:W|W|W|R|CRCW, m:KERNEL|O64|NOTSX, a:F64
ERETU nil rIP,Fv,rSP,CS,SS,Kv5,SSP,GSBASE,KGSBASE [0xF3 0x0F 0x01 /0xCA] s:FRED, t:RET, w:W|W|W|W|W|R|CRCW|RW|RW, m:KERNEL|O64|NOTSX, a:F64
ERETS nil rIP,Fv,rSP,Kv5,SSP [ 0xF2 0x0F 0x01 /0xCA] s:FRED, t:RET, w:W|W|W|R|CRCW, m:KERNEL|O64|NOTSX, a:F64
STAC nil Fv [ NP 0x0F 0x01 /0xCB] s:SMAP, t:SMAP, w:W, f:AC=1, m:KERNEL|NOV86
TDCALL nil nil [ 0x66 0x0F 0x01 /0xCC] s:TDX, t:TDX, m:KERNEL|VMXNROOT
SEAMRET nil nil [ 0x66 0x0F 0x01 /0xCD] s:TDX, t:TDX, f:VMX, m:SEAMR
@ -41,7 +41,7 @@ ENCLS nil EAX,RBX,RCX,RDX [ NP 0x0F 0x01 /0
XGETBV nil ECX,EDX,EAX,XCR [ NP 0x0F 0x01 /0xD0] s:XSAVE, t:XSAVE, w:R|W|W|R
XSETBV nil ECX,EDX,EAX,XCR [ NP 0x0F 0x01 /0xD1] s:XSAVE, t:XSAVE, w:R|R|R|W, m:KERNEL
VMFUNC nil nil [ NP 0x0F 0x01 /0xD4] s:VTX, t:VTX, m:VMX|NOSGX
XEND nil nil [ NP 0x0F 0x01 /0xD5] s:TSX, t:COND_BR, i:RTM
XEND nil yIP [ NP 0x0F 0x01 /0xD5] s:TSX, t:COND_BR, w:CW, i:RTM
XTEST nil Fv [ NP 0x0F 0x01 /0xD6] s:TSX, t:LOGIC, w:W, i:RTM, f:CF=0|PF=0|AF=0|ZF=m|SF=0|OF=0
ENCLU nil EAX,RBX,RCX,RDX [ NP 0x0F 0x01 /0xD7] s:SGX, t:SGX, w:R|CRW|CRW|CRW, m:USER|NOSMM|NOTSX
VMRUN nil rAX [ 0x0F 0x01 /0xD8] s:SVM, t:SYSTEM, w:R, m:VMXROOT
@ -60,7 +60,7 @@ SETSSBSY nil SHS0,SSP [ 0xF3 0x0F 0x01 /0
XSUSLDTRK nil nil [ 0xF2 0x0F 0x01 /0xE8] s:TSXLDTRK, t:MISC
XRESLDTRK nil nil [ 0xF2 0x0F 0x01 /0xE9] s:TSXLDTRK, t:MISC
SAVEPREVSSP nil SHSS,SSP [ 0xF3 0x0F 0x01 /0xEA] s:CET_SS, t:CET, w:RW|R, f:CF=t
UIRET nil rIP,Fv,sSP,UIF,Kv3,SHS1 [ 0xF3 0x0F 0x01 /0xEC] s:UINTR, t:UINTR, a:F64, w:W|W|W|W|R|R, m:O64|NOTSX|NOSGX
UIRET nil rIP,Fv,sSP,UIF,Kv3,SHS1 [ 0xF3 0x0F 0x01 /0xEC] s:UINTR, t:RET, a:F64, w:W|W|W|W|R|R, m:O64|NOTSX|NOSGX
TESTUI nil UIF,Fv [ 0xF3 0x0F 0x01 /0xED] s:UINTR, t:UINTR, w:R|W, f:UINTR, m:O64|NOSGX
RDPKRU nil EDX,EAX,ECX,PKRU [ NP 0x0F 0x01 /0xEE] s:PKU, t:MISC, w:W|W|R|R
CLUI nil UIF [ 0xF3 0x0F 0x01 /0xEE] s:UINTR, t:UINTR, w:W, m:O64|NOTSX|NOSGX

2
isagenerator/instructions/table_base.dat

@ -331,7 +331,7 @@ RETN nil rIP,Kv,SHS1 [ 0xC3] s:I86
LES Gz,Mp ES [ 0xC4 /r:mem] s:I86, t:SEGOP, w:W|R|W, m:NO64|NOSGX
LDS Gz,Mp DS [ 0xC5 /r:mem] s:I86, t:SEGOP, w:W|R|W, m:NO64|NOSGX
MOV Eb,Ib nil [ 0xC6 /0 ib] s:I86, t:DATAXFER, w:W|R, p:XRELEASE|HLEWOL
XABORT Ib EAX [ 0xC6 /0xF8 ib] s:TSX, t:UNCOND_BR, w:R|RCW, i:RTM, m:NOTSX
XABORT Ib yIP,EAX [ 0xC6 /0xF8 ib] s:TSX, t:UNCOND_BR, w:R|W|RCW, i:RTM
MOV Ev,Iz nil [ 0xC7 /0 iz] s:I86, t:DATAXFER, w:W|R, a:OP2SEXO1, p:XRELEASE|HLEWOL
XBEGIN Jz yIP,EAX [ 0xC7 /0xF8 cz] s:TSX, t:COND_BR, w:R|RCW|CW, i:RTM
ENTER Iw,Ib rBP,sSP,Kv [ 0xC8 iw ib] s:I186, t:MISC, w:R|R|RW|RW|W, a:D64

Loading…
Cancel
Save