Skip to content

Commit 06b6b4f

Browse files
plafosseclaude
andcommitted
Add intentional parameter to Unimplemented IL across LLIL/MLIL/HLIL
When intentional=true, the expression renders as "unknown" instead of "unimplemented", indicating a genuinely unknowable value rather than a missing lift. Semantics for analysis are unchanged. Suppresses the "Unimplemented Instruction" auto-address tag for intentional unknowns. The motivating case is the x87 C1 rounding flag (IL_FLAGWRITE_X87RND), which is runtime-dependent and cannot be statically determined. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 508ba2b commit 06b6b4f

File tree

10 files changed

+89
-35
lines changed

10 files changed

+89
-35
lines changed

arch/x86/arch_x86.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2154,7 +2154,7 @@ size_t X86CommonArchitecture::GetFlagWriteLowLevelIL(BNLowLevelILOperation op, s
21542154
}
21552155

21562156
if (flagWriteType == IL_FLAGWRITE_X87RND && flag == IL_FLAG_C1)
2157-
return il.Undefined();
2157+
return il.Unimplemented(/*intentional=*/true);
21582158

21592159
if (((flagWriteType == IL_FLAGWRITE_X87COM) || (flagWriteType == IL_FLAGWRITE_X87C1Z)) && (flag == IL_FLAG_C1))
21602160
return il.Const(0, 0);

binaryninjaapi.h

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15038,19 +15038,23 @@ namespace BinaryNinja {
1503815038

1503915039
/*! Returns the unimplemented expression. This should be used for instructions which aren't implemented
1504015040

15041+
\param intentional If true, renders as "unknown" to indicate the value is genuinely unknowable at
15042+
analysis time (not a missing implementation). Default is false.
1504115043
\param loc Optional IL Location this expression was added from.
1504215044
\return The unimplemented expression
1504315045
*/
15044-
ExprId Unimplemented(const ILSourceLocation& loc = ILSourceLocation());
15046+
ExprId Unimplemented(bool intentional = false, const ILSourceLocation& loc = ILSourceLocation());
1504515047

1504615048
/*! A memory reference to expression \c addr of size \c size with unimplemented operation.
1504715049

1504815050
\param size Size in bytes of the memory reference
1504915051
\param addr Expression to reference memory
15052+
\param intentional If true, renders as "unknown" to indicate the value is genuinely unknowable at
15053+
analysis time (not a missing implementation). Default is false.
1505015054
\param loc Optional IL Location this expression was added from.
1505115055
\return The unimplemented memory reference expression.
1505215056
*/
15053-
ExprId UnimplementedMemoryRef(size_t size, ExprId addr, const ILSourceLocation& loc = ILSourceLocation());
15057+
ExprId UnimplementedMemoryRef(size_t size, ExprId addr, bool intentional = false, const ILSourceLocation& loc = ILSourceLocation());
1505415058
ExprId RegisterPhi(const SSARegister& dest, const std::vector<SSARegister>& sources,
1505515059
const ILSourceLocation& loc = ILSourceLocation());
1505615060
ExprId RegisterStackPhi(const SSARegisterStack& dest, const std::vector<SSARegisterStack>& sources,
@@ -15695,8 +15699,8 @@ namespace BinaryNinja {
1569515699
ExprId FreeVarSlotSSA(const Variable& var, size_t newVersion, size_t prevVersion,
1569615700
const ILSourceLocation& loc = ILSourceLocation());
1569715701
ExprId Undefined(const ILSourceLocation& loc = ILSourceLocation());
15698-
ExprId Unimplemented(const ILSourceLocation& loc = ILSourceLocation());
15699-
ExprId UnimplementedMemoryRef(size_t size, ExprId target, const ILSourceLocation& loc = ILSourceLocation());
15702+
ExprId Unimplemented(bool intentional = false, const ILSourceLocation& loc = ILSourceLocation());
15703+
ExprId UnimplementedMemoryRef(size_t size, ExprId target, bool intentional = false, const ILSourceLocation& loc = ILSourceLocation());
1570015704
ExprId VarPhi(const SSAVariable& dest, const std::vector<SSAVariable>& sources,
1570115705
const ILSourceLocation& loc = ILSourceLocation());
1570215706
ExprId MemoryPhi(size_t destMemVersion, const std::vector<size_t>& sourceMemVersions,
@@ -16057,8 +16061,8 @@ namespace BinaryNinja {
1605716061
ExprId IntrinsicSSA(uint32_t intrinsic, const std::vector<ExprId>& params, size_t destMemVersion,
1605816062
size_t srcMemVersion, const ILSourceLocation& loc = ILSourceLocation());
1605916063
ExprId Undefined(const ILSourceLocation& loc = ILSourceLocation());
16060-
ExprId Unimplemented(const ILSourceLocation& loc = ILSourceLocation());
16061-
ExprId UnimplementedMemoryRef(size_t size, ExprId target, const ILSourceLocation& loc = ILSourceLocation());
16064+
ExprId Unimplemented(bool intentional = false, const ILSourceLocation& loc = ILSourceLocation());
16065+
ExprId UnimplementedMemoryRef(size_t size, ExprId target, bool intentional = false, const ILSourceLocation& loc = ILSourceLocation());
1606216066
ExprId FloatAdd(size_t size, ExprId a, ExprId b, const ILSourceLocation& loc = ILSourceLocation());
1606316067
ExprId FloatSub(size_t size, ExprId a, ExprId b, const ILSourceLocation& loc = ILSourceLocation());
1606416068
ExprId FloatMult(size_t size, ExprId a, ExprId b, const ILSourceLocation& loc = ILSourceLocation());

highlevelilinstruction.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1564,7 +1564,6 @@ ExprId HighLevelILInstruction::CopyTo(
15641564
case HLIL_LOW_PART:
15651565
case HLIL_BOOL_TO_INT:
15661566
case HLIL_JUMP:
1567-
case HLIL_UNIMPL_MEM:
15681567
case HLIL_FSQRT:
15691568
case HLIL_FNEG:
15701569
case HLIL_FABS:
@@ -1576,6 +1575,8 @@ ExprId HighLevelILInstruction::CopyTo(
15761575
case HLIL_CEIL:
15771576
case HLIL_FTRUNC:
15781577
return dest->AddExprWithLocation(operation, loc, size, subExprHandler(AsOneOperand().GetSourceExpr()));
1578+
case HLIL_UNIMPL_MEM:
1579+
return dest->AddExprWithLocation(operation, loc, size, subExprHandler(AsOneOperand().GetSourceExpr()), GetRawOperandAsInteger(1));
15791580
case HLIL_ADD:
15801581
case HLIL_SUB:
15811582
case HLIL_AND:
@@ -1658,7 +1659,7 @@ ExprId HighLevelILInstruction::CopyTo(
16581659
case HLIL_UNDEF:
16591660
return dest->Undefined(loc);
16601661
case HLIL_UNIMPL:
1661-
return dest->Unimplemented(loc);
1662+
return dest->Unimplemented(As<HLIL_UNIMPL>().IsIntentional(), loc);
16621663
default:
16631664
throw HighLevelILInstructionAccessException();
16641665
}
@@ -3238,15 +3239,15 @@ ExprId HighLevelILFunction::Undefined(const ILSourceLocation& loc)
32383239
}
32393240

32403241

3241-
ExprId HighLevelILFunction::Unimplemented(const ILSourceLocation& loc)
3242+
ExprId HighLevelILFunction::Unimplemented(bool intentional, const ILSourceLocation& loc)
32423243
{
3243-
return AddExprWithLocation(HLIL_UNIMPL, loc, 0);
3244+
return AddExprWithLocation(HLIL_UNIMPL, loc, 0, intentional ? 1 : 0);
32443245
}
32453246

32463247

3247-
ExprId HighLevelILFunction::UnimplementedMemoryRef(size_t size, ExprId target, const ILSourceLocation& loc)
3248+
ExprId HighLevelILFunction::UnimplementedMemoryRef(size_t size, ExprId target, bool intentional, const ILSourceLocation& loc)
32483249
{
3249-
return AddExprWithLocation(HLIL_UNIMPL_MEM, loc, size, target);
3250+
return AddExprWithLocation(HLIL_UNIMPL_MEM, loc, size, target, intentional ? 1 : 0);
32503251
}
32513252

32523253

highlevelilinstruction.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1270,7 +1270,9 @@ namespace BinaryNinja
12701270
{};
12711271
template <>
12721272
struct HighLevelILInstructionAccessor<HLIL_UNIMPL> : public HighLevelILInstructionBase
1273-
{};
1273+
{
1274+
bool IsIntentional() const { return GetRawOperandAsInteger(0) != 0; }
1275+
};
12741276
template <>
12751277
struct HighLevelILInstructionAccessor<HLIL_UNREACHABLE> : public HighLevelILInstructionBase
12761278
{};
@@ -1466,7 +1468,9 @@ namespace BinaryNinja
14661468
{};
14671469
template <>
14681470
struct HighLevelILInstructionAccessor<HLIL_UNIMPL_MEM> : public HighLevelILOneOperandInstruction
1469-
{};
1471+
{
1472+
bool IsIntentional() const { return GetRawOperandAsInteger(1) != 0; }
1473+
};
14701474
template <>
14711475
struct HighLevelILInstructionAccessor<HLIL_FSQRT> : public HighLevelILOneOperandInstruction
14721476
{};

lowlevelilinstruction.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2302,16 +2302,18 @@ ExprId LowLevelILInstruction::CopyTo(
23022302
case LLIL_SYSCALL:
23032303
case LLIL_BP:
23042304
case LLIL_UNDEF:
2305-
case LLIL_UNIMPL:
23062305
return dest->AddExprWithLocation(operation, loc, size, flags);
2306+
case LLIL_UNIMPL:
2307+
return dest->AddExprWithLocation(operation, loc, size, flags, GetRawOperandAsInteger(0));
2308+
case LLIL_UNIMPL_MEM:
2309+
return dest->AddExprWithLocation(operation, loc, size, flags, subExprHandler(AsOneOperand().GetSourceExpr()), GetRawOperandAsInteger(1));
23072310
case LLIL_PUSH:
23082311
case LLIL_NEG:
23092312
case LLIL_NOT:
23102313
case LLIL_SX:
23112314
case LLIL_ZX:
23122315
case LLIL_LOW_PART:
23132316
case LLIL_BOOL_TO_INT:
2314-
case LLIL_UNIMPL_MEM:
23152317
case LLIL_FSQRT:
23162318
case LLIL_FNEG:
23172319
case LLIL_FABS:
@@ -3609,15 +3611,15 @@ ExprId LowLevelILFunction::Undefined(const ILSourceLocation& loc)
36093611
}
36103612

36113613

3612-
ExprId LowLevelILFunction::Unimplemented(const ILSourceLocation& loc)
3614+
ExprId LowLevelILFunction::Unimplemented(bool intentional, const ILSourceLocation& loc)
36133615
{
3614-
return AddExprWithLocation(LLIL_UNIMPL, loc, 0, 0);
3616+
return AddExprWithLocation(LLIL_UNIMPL, loc, 0, 0, intentional ? 1 : 0);
36153617
}
36163618

36173619

3618-
ExprId LowLevelILFunction::UnimplementedMemoryRef(size_t size, ExprId addr, const ILSourceLocation& loc)
3620+
ExprId LowLevelILFunction::UnimplementedMemoryRef(size_t size, ExprId addr, bool intentional, const ILSourceLocation& loc)
36193621
{
3620-
return AddExprWithLocation(LLIL_UNIMPL_MEM, loc, size, 0, addr);
3622+
return AddExprWithLocation(LLIL_UNIMPL_MEM, loc, size, 0, addr, intentional ? 1 : 0);
36213623
}
36223624

36233625

lowlevelilinstruction.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1883,7 +1883,9 @@ namespace BinaryNinja
18831883
{};
18841884
template <>
18851885
struct LowLevelILInstructionAccessor<LLIL_UNIMPL> : public LowLevelILInstructionBase
1886-
{};
1886+
{
1887+
bool IsIntentional() const { return GetRawOperandAsInteger(0) != 0; }
1888+
};
18871889

18881890
template <>
18891891
struct LowLevelILInstructionAccessor<LLIL_CONST> : public LowLevelILConstantInstruction
@@ -2067,7 +2069,9 @@ namespace BinaryNinja
20672069
{};
20682070
template <>
20692071
struct LowLevelILInstructionAccessor<LLIL_UNIMPL_MEM> : public LowLevelILOneOperandInstruction
2070-
{};
2072+
{
2073+
bool IsIntentional() const { return GetRawOperandAsInteger(1) != 0; }
2074+
};
20712075
template <>
20722076
struct LowLevelILInstructionAccessor<LLIL_FSQRT> : public LowLevelILOneOperandInstruction
20732077
{};

mediumlevelilinstruction.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1762,7 +1762,6 @@ ExprId MediumLevelILInstruction::CopyTo(MediumLevelILFunction* dest,
17621762
case MLIL_BOOL_TO_INT:
17631763
case MLIL_JUMP:
17641764
case MLIL_RET_HINT:
1765-
case MLIL_UNIMPL_MEM:
17661765
case MLIL_FSQRT:
17671766
case MLIL_FNEG:
17681767
case MLIL_FABS:
@@ -1774,6 +1773,8 @@ ExprId MediumLevelILInstruction::CopyTo(MediumLevelILFunction* dest,
17741773
case MLIL_CEIL:
17751774
case MLIL_FTRUNC:
17761775
return dest->AddExprWithLocation(operation, loc, size, subExprHandler(AsOneOperand().GetSourceExpr()));
1776+
case MLIL_UNIMPL_MEM:
1777+
return dest->AddExprWithLocation(operation, loc, size, subExprHandler(AsOneOperand().GetSourceExpr()), GetRawOperandAsInteger(1));
17771778
case MLIL_ADD:
17781779
case MLIL_SUB:
17791780
case MLIL_AND:
@@ -1895,7 +1896,7 @@ ExprId MediumLevelILInstruction::CopyTo(MediumLevelILFunction* dest,
18951896
case MLIL_UNDEF:
18961897
return dest->Undefined(loc);
18971898
case MLIL_UNIMPL:
1898-
return dest->Unimplemented(loc);
1899+
return dest->Unimplemented(As<MLIL_UNIMPL>().IsIntentional(), loc);
18991900
default:
19001901
throw MediumLevelILInstructionAccessException();
19011902
}
@@ -2969,15 +2970,15 @@ ExprId MediumLevelILFunction::Undefined(const ILSourceLocation& loc)
29692970
}
29702971

29712972

2972-
ExprId MediumLevelILFunction::Unimplemented(const ILSourceLocation& loc)
2973+
ExprId MediumLevelILFunction::Unimplemented(bool intentional, const ILSourceLocation& loc)
29732974
{
2974-
return AddExprWithLocation(MLIL_UNIMPL, loc, 0);
2975+
return AddExprWithLocation(MLIL_UNIMPL, loc, 0, intentional ? 1 : 0);
29752976
}
29762977

29772978

2978-
ExprId MediumLevelILFunction::UnimplementedMemoryRef(size_t size, ExprId target, const ILSourceLocation& loc)
2979+
ExprId MediumLevelILFunction::UnimplementedMemoryRef(size_t size, ExprId target, bool intentional, const ILSourceLocation& loc)
29792980
{
2980-
return AddExprWithLocation(MLIL_UNIMPL_MEM, loc, size, target);
2981+
return AddExprWithLocation(MLIL_UNIMPL_MEM, loc, size, target, intentional ? 1 : 0);
29812982
}
29822983

29832984

mediumlevelilinstruction.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1579,7 +1579,9 @@ namespace BinaryNinja
15791579
{};
15801580
template <>
15811581
struct MediumLevelILInstructionAccessor<MLIL_UNIMPL> : public MediumLevelILInstructionBase
1582-
{};
1582+
{
1583+
bool IsIntentional() const { return GetRawOperandAsInteger(0) != 0; }
1584+
};
15831585

15841586
template <>
15851587
struct MediumLevelILInstructionAccessor<MLIL_CONST> : public MediumLevelILConstantInstruction
@@ -1766,7 +1768,9 @@ namespace BinaryNinja
17661768
{};
17671769
template <>
17681770
struct MediumLevelILInstructionAccessor<MLIL_UNIMPL_MEM> : public MediumLevelILOneOperandInstruction
1769-
{};
1771+
{
1772+
bool IsIntentional() const { return GetRawOperandAsInteger(1) != 0; }
1773+
};
17701774
template <>
17711775
struct MediumLevelILInstructionAccessor<MLIL_FSQRT> : public MediumLevelILOneOperandInstruction
17721776
{};

python/lowlevelil.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5621,28 +5621,32 @@ def undefined(self, loc: Optional['ILSourceLocation'] = None) -> ExpressionIndex
56215621
"""
56225622
return self.expr(LowLevelILOperation.LLIL_UNDEF, source_location=loc)
56235623

5624-
def unimplemented(self, loc: Optional['ILSourceLocation'] = None) -> ExpressionIndex:
5624+
def unimplemented(self, intentional: bool = False, loc: Optional['ILSourceLocation'] = None) -> ExpressionIndex:
56255625
"""
56265626
``unimplemented`` returns the unimplemented expression. This should be used for all instructions which aren't
56275627
implemented.
56285628
5629+
:param bool intentional: if True, renders as ``unknown`` to indicate the value is genuinely unknowable at \
5630+
analysis time (not a missing implementation)
56295631
:param ILSourceLocation loc: location of returned expression
56305632
:return: the unimplemented expression.
56315633
:rtype: ExpressionIndex
56325634
"""
5633-
return self.expr(LowLevelILOperation.LLIL_UNIMPL, source_location=loc)
5635+
return self.expr(LowLevelILOperation.LLIL_UNIMPL, intentional, source_location=loc)
56345636

5635-
def unimplemented_memory_ref(self, size: int, addr: ExpressionIndex, loc: Optional['ILSourceLocation'] = None) -> ExpressionIndex:
5637+
def unimplemented_memory_ref(self, size: int, addr: ExpressionIndex, intentional: bool = False, loc: Optional['ILSourceLocation'] = None) -> ExpressionIndex:
56365638
"""
56375639
``unimplemented_memory_ref`` a memory reference to expression ``addr`` of size ``size`` with unimplemented operation.
56385640
56395641
:param int size: size in bytes of the memory reference
56405642
:param ExpressionIndex addr: expression to reference memory
5643+
:param bool intentional: if True, renders as ``unknown`` to indicate the value is genuinely unknowable at \
5644+
analysis time (not a missing implementation)
56415645
:param ILSourceLocation loc: location of returned expression
56425646
:return: the unimplemented memory reference expression.
56435647
:rtype: ExpressionIndex
56445648
"""
5645-
return self.expr(LowLevelILOperation.LLIL_UNIMPL_MEM, addr, size=size, source_location=loc)
5649+
return self.expr(LowLevelILOperation.LLIL_UNIMPL_MEM, addr, intentional, size=size, source_location=loc)
56465650

56475651
def float_add(
56485652
self, size: int, a: ExpressionIndex, b: ExpressionIndex, flags: Optional['architecture.FlagWriteType'] = None,

rust/src/low_level_il/lifting.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1044,6 +1044,15 @@ impl LowLevelILMutableFunction {
10441044
}
10451045

10461046
no_arg_lifter!(unimplemented, LLIL_UNIMPL, ValueExpr);
1047+
1048+
pub fn unknown(&self) -> LowLevelILExpression<'_, Mutable, NonSSA, ValueExpr> {
1049+
use binaryninjacore_sys::BNLowLevelILAddExpr;
1050+
use binaryninjacore_sys::BNLowLevelILOperation::LLIL_UNIMPL;
1051+
1052+
let expr_idx = unsafe { BNLowLevelILAddExpr(self.handle, LLIL_UNIMPL, 0, 0, 1, 0, 0, 0) };
1053+
1054+
LowLevelILExpression::new(self, LowLevelExpressionIndex(expr_idx))
1055+
}
10471056
no_arg_lifter!(undefined, LLIL_UNDEF, ValueExpr);
10481057
no_arg_lifter!(nop, LLIL_NOP, VoidExpr);
10491058

@@ -1417,6 +1426,27 @@ impl LowLevelILMutableFunction {
14171426

14181427
size_changing_unary_op_lifter!(unimplemented_mem, LLIL_UNIMPL_MEM, ValueExpr);
14191428

1429+
pub fn unknown_mem<'a, E>(&'a self, size: usize, expr: E) -> ExpressionBuilder<'a, ValueExpr>
1430+
where
1431+
E: LiftableLowLevelILWithSize<'a>,
1432+
{
1433+
use binaryninjacore_sys::BNLowLevelILOperation::LLIL_UNIMPL_MEM;
1434+
1435+
let expr = E::lift(self, expr);
1436+
1437+
ExpressionBuilder {
1438+
function: self,
1439+
op: LLIL_UNIMPL_MEM,
1440+
size,
1441+
flag_write: FlagWriteId(0),
1442+
op1: expr.index.0 as u64,
1443+
op2: 1,
1444+
op3: 0,
1445+
op4: 0,
1446+
_ty: PhantomData,
1447+
}
1448+
}
1449+
14201450
sized_unary_op_lifter!(neg, LLIL_NEG, ValueExpr);
14211451
sized_unary_op_lifter!(not, LLIL_NOT, ValueExpr);
14221452

0 commit comments

Comments
 (0)