Skip to content

Commit 68ebec3

Browse files
plafosseclaude
andcommitted
Add Unknown() and IsUnknown() to Unimplemented IL across LLIL/MLIL/HLIL
Adds Unknown() and UnknownMemoryRef() as first-class IL builder functions (alongside Unimplemented/UnimplementedMemoryRef) that emit the same opcodes with an unknown flag set. When the flag is set, the expression renders as "unknown" instead of "unimplemented", indicating a genuinely unknowable value rather than a missing lift. Suppresses the "Unimplemented Instruction" auto-address tag. IsUnknown() accessors on LLIL/MLIL/HLIL instruction types allow callers to distinguish the two cases. Copy paths preserve the flag correctly. 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 68ebec3

File tree

10 files changed

+150
-22
lines changed

10 files changed

+150
-22
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.Unknown();
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: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15036,13 +15036,21 @@ namespace BinaryNinja {
1503615036
*/
1503715037
ExprId Undefined(const ILSourceLocation& loc = ILSourceLocation());
1503815038

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

1504115041
\param loc Optional IL Location this expression was added from.
1504215042
\return The unimplemented expression
1504315043
*/
1504415044
ExprId Unimplemented(const ILSourceLocation& loc = ILSourceLocation());
1504515045

15046+
/*! Returns an unknown expression for values that are genuinely unknowable at analysis time
15047+
(e.g. runtime-dependent flags). Renders as "unknown" and suppresses unimplemented warnings.
15048+
15049+
\param loc Optional IL Location this expression was added from.
15050+
\return The unknown expression
15051+
*/
15052+
ExprId Unknown(const ILSourceLocation& loc = ILSourceLocation());
15053+
1504615054
/*! A memory reference to expression \c addr of size \c size with unimplemented operation.
1504715055

1504815056
\param size Size in bytes of the memory reference
@@ -15051,6 +15059,16 @@ namespace BinaryNinja {
1505115059
\return The unimplemented memory reference expression.
1505215060
*/
1505315061
ExprId UnimplementedMemoryRef(size_t size, ExprId addr, const ILSourceLocation& loc = ILSourceLocation());
15062+
15063+
/*! A memory reference to expression \c addr of size \c size for a genuinely unknowable value.
15064+
Renders as "unknown" and suppresses unimplemented warnings.
15065+
15066+
\param size Size in bytes of the memory reference
15067+
\param addr Expression to reference memory
15068+
\param loc Optional IL Location this expression was added from.
15069+
\return The unknown memory reference expression.
15070+
*/
15071+
ExprId UnknownMemoryRef(size_t size, ExprId addr, const ILSourceLocation& loc = ILSourceLocation());
1505415072
ExprId RegisterPhi(const SSARegister& dest, const std::vector<SSARegister>& sources,
1505515073
const ILSourceLocation& loc = ILSourceLocation());
1505615074
ExprId RegisterStackPhi(const SSARegisterStack& dest, const std::vector<SSARegisterStack>& sources,
@@ -15696,7 +15714,9 @@ namespace BinaryNinja {
1569615714
const ILSourceLocation& loc = ILSourceLocation());
1569715715
ExprId Undefined(const ILSourceLocation& loc = ILSourceLocation());
1569815716
ExprId Unimplemented(const ILSourceLocation& loc = ILSourceLocation());
15717+
ExprId Unknown(const ILSourceLocation& loc = ILSourceLocation());
1569915718
ExprId UnimplementedMemoryRef(size_t size, ExprId target, const ILSourceLocation& loc = ILSourceLocation());
15719+
ExprId UnknownMemoryRef(size_t size, ExprId target, const ILSourceLocation& loc = ILSourceLocation());
1570015720
ExprId VarPhi(const SSAVariable& dest, const std::vector<SSAVariable>& sources,
1570115721
const ILSourceLocation& loc = ILSourceLocation());
1570215722
ExprId MemoryPhi(size_t destMemVersion, const std::vector<size_t>& sourceMemVersions,
@@ -16058,7 +16078,9 @@ namespace BinaryNinja {
1605816078
size_t srcMemVersion, const ILSourceLocation& loc = ILSourceLocation());
1605916079
ExprId Undefined(const ILSourceLocation& loc = ILSourceLocation());
1606016080
ExprId Unimplemented(const ILSourceLocation& loc = ILSourceLocation());
16081+
ExprId Unknown(const ILSourceLocation& loc = ILSourceLocation());
1606116082
ExprId UnimplementedMemoryRef(size_t size, ExprId target, const ILSourceLocation& loc = ILSourceLocation());
16083+
ExprId UnknownMemoryRef(size_t size, ExprId target, const ILSourceLocation& loc = ILSourceLocation());
1606216084
ExprId FloatAdd(size_t size, ExprId a, ExprId b, const ILSourceLocation& loc = ILSourceLocation());
1606316085
ExprId FloatSub(size_t size, ExprId a, ExprId b, const ILSourceLocation& loc = ILSourceLocation());
1606416086
ExprId FloatMult(size_t size, ExprId a, ExprId b, const ILSourceLocation& loc = ILSourceLocation());

highlevelilinstruction.cpp

Lines changed: 17 additions & 4 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 As<HLIL_UNIMPL>().IsUnknown() ? dest->Unknown(loc) : dest->Unimplemented(loc);
16621663
default:
16631664
throw HighLevelILInstructionAccessException();
16641665
}
@@ -3240,13 +3241,25 @@ ExprId HighLevelILFunction::Undefined(const ILSourceLocation& loc)
32403241

32413242
ExprId HighLevelILFunction::Unimplemented(const ILSourceLocation& loc)
32423243
{
3243-
return AddExprWithLocation(HLIL_UNIMPL, loc, 0);
3244+
return AddExprWithLocation(HLIL_UNIMPL, loc, 0, 0);
3245+
}
3246+
3247+
3248+
ExprId HighLevelILFunction::Unknown(const ILSourceLocation& loc)
3249+
{
3250+
return AddExprWithLocation(HLIL_UNIMPL, loc, 0, 1);
32443251
}
32453252

32463253

32473254
ExprId HighLevelILFunction::UnimplementedMemoryRef(size_t size, ExprId target, const ILSourceLocation& loc)
32483255
{
3249-
return AddExprWithLocation(HLIL_UNIMPL_MEM, loc, size, target);
3256+
return AddExprWithLocation(HLIL_UNIMPL_MEM, loc, size, target, 0);
3257+
}
3258+
3259+
3260+
ExprId HighLevelILFunction::UnknownMemoryRef(size_t size, ExprId target, const ILSourceLocation& loc)
3261+
{
3262+
return AddExprWithLocation(HLIL_UNIMPL_MEM, loc, size, target, 1);
32503263
}
32513264

32523265

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 IsUnknown() 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 IsUnknown() const { return GetRawOperandAsInteger(1) != 0; }
1473+
};
14701474
template <>
14711475
struct HighLevelILInstructionAccessor<HLIL_FSQRT> : public HighLevelILOneOperandInstruction
14721476
{};

lowlevelilinstruction.cpp

Lines changed: 18 additions & 4 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:
@@ -3611,13 +3613,25 @@ ExprId LowLevelILFunction::Undefined(const ILSourceLocation& loc)
36113613

36123614
ExprId LowLevelILFunction::Unimplemented(const ILSourceLocation& loc)
36133615
{
3614-
return AddExprWithLocation(LLIL_UNIMPL, loc, 0, 0);
3616+
return AddExprWithLocation(LLIL_UNIMPL, loc, 0, 0, 0);
3617+
}
3618+
3619+
3620+
ExprId LowLevelILFunction::Unknown(const ILSourceLocation& loc)
3621+
{
3622+
return AddExprWithLocation(LLIL_UNIMPL, loc, 0, 0, 1);
36153623
}
36163624

36173625

36183626
ExprId LowLevelILFunction::UnimplementedMemoryRef(size_t size, ExprId addr, const ILSourceLocation& loc)
36193627
{
3620-
return AddExprWithLocation(LLIL_UNIMPL_MEM, loc, size, 0, addr);
3628+
return AddExprWithLocation(LLIL_UNIMPL_MEM, loc, size, 0, addr, 0);
3629+
}
3630+
3631+
3632+
ExprId LowLevelILFunction::UnknownMemoryRef(size_t size, ExprId addr, const ILSourceLocation& loc)
3633+
{
3634+
return AddExprWithLocation(LLIL_UNIMPL_MEM, loc, size, 0, addr, 1);
36213635
}
36223636

36233637

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 IsUnknown() 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 IsUnknown() const { return GetRawOperandAsInteger(1) != 0; }
2074+
};
20712075
template <>
20722076
struct LowLevelILInstructionAccessor<LLIL_FSQRT> : public LowLevelILOneOperandInstruction
20732077
{};

mediumlevelilinstruction.cpp

Lines changed: 17 additions & 4 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 As<MLIL_UNIMPL>().IsUnknown() ? dest->Unknown(loc) : dest->Unimplemented(loc);
18991900
default:
19001901
throw MediumLevelILInstructionAccessException();
19011902
}
@@ -2971,13 +2972,25 @@ ExprId MediumLevelILFunction::Undefined(const ILSourceLocation& loc)
29712972

29722973
ExprId MediumLevelILFunction::Unimplemented(const ILSourceLocation& loc)
29732974
{
2974-
return AddExprWithLocation(MLIL_UNIMPL, loc, 0);
2975+
return AddExprWithLocation(MLIL_UNIMPL, loc, 0, 0);
2976+
}
2977+
2978+
2979+
ExprId MediumLevelILFunction::Unknown(const ILSourceLocation& loc)
2980+
{
2981+
return AddExprWithLocation(MLIL_UNIMPL, loc, 0, 1);
29752982
}
29762983

29772984

29782985
ExprId MediumLevelILFunction::UnimplementedMemoryRef(size_t size, ExprId target, const ILSourceLocation& loc)
29792986
{
2980-
return AddExprWithLocation(MLIL_UNIMPL_MEM, loc, size, target);
2987+
return AddExprWithLocation(MLIL_UNIMPL_MEM, loc, size, target, 0);
2988+
}
2989+
2990+
2991+
ExprId MediumLevelILFunction::UnknownMemoryRef(size_t size, ExprId target, const ILSourceLocation& loc)
2992+
{
2993+
return AddExprWithLocation(MLIL_UNIMPL_MEM, loc, size, target, 1);
29812994
}
29822995

29832996

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 IsUnknown() 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 IsUnknown() const { return GetRawOperandAsInteger(1) != 0; }
1773+
};
17701774
template <>
17711775
struct MediumLevelILInstructionAccessor<MLIL_FSQRT> : public MediumLevelILOneOperandInstruction
17721776
{};

python/lowlevelil.py

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5630,7 +5630,18 @@ def unimplemented(self, loc: Optional['ILSourceLocation'] = None) -> ExpressionI
56305630
:return: the unimplemented expression.
56315631
:rtype: ExpressionIndex
56325632
"""
5633-
return self.expr(LowLevelILOperation.LLIL_UNIMPL, source_location=loc)
5633+
return self.expr(LowLevelILOperation.LLIL_UNIMPL, False, source_location=loc)
5634+
5635+
def unknown(self, loc: Optional['ILSourceLocation'] = None) -> ExpressionIndex:
5636+
"""
5637+
``unknown`` returns an unknown expression for values that are genuinely unknowable at analysis time
5638+
(e.g. runtime-dependent flags). Renders as ``unknown`` and suppresses unimplemented warnings.
5639+
5640+
:param ILSourceLocation loc: location of returned expression
5641+
:return: the unknown expression.
5642+
:rtype: ExpressionIndex
5643+
"""
5644+
return self.expr(LowLevelILOperation.LLIL_UNIMPL, True, source_location=loc)
56345645

56355646
def unimplemented_memory_ref(self, size: int, addr: ExpressionIndex, loc: Optional['ILSourceLocation'] = None) -> ExpressionIndex:
56365647
"""
@@ -5642,7 +5653,20 @@ def unimplemented_memory_ref(self, size: int, addr: ExpressionIndex, loc: Option
56425653
:return: the unimplemented memory reference expression.
56435654
:rtype: ExpressionIndex
56445655
"""
5645-
return self.expr(LowLevelILOperation.LLIL_UNIMPL_MEM, addr, size=size, source_location=loc)
5656+
return self.expr(LowLevelILOperation.LLIL_UNIMPL_MEM, addr, False, size=size, source_location=loc)
5657+
5658+
def unknown_memory_ref(self, size: int, addr: ExpressionIndex, loc: Optional['ILSourceLocation'] = None) -> ExpressionIndex:
5659+
"""
5660+
``unknown_memory_ref`` a memory reference to expression ``addr`` of size ``size`` for a genuinely unknowable
5661+
value. Renders as ``unknown`` and suppresses unimplemented warnings.
5662+
5663+
:param int size: size in bytes of the memory reference
5664+
:param ExpressionIndex addr: expression to reference memory
5665+
:param ILSourceLocation loc: location of returned expression
5666+
:return: the unknown memory reference expression.
5667+
:rtype: ExpressionIndex
5668+
"""
5669+
return self.expr(LowLevelILOperation.LLIL_UNIMPL_MEM, addr, True, size=size, source_location=loc)
56465670

56475671
def float_add(
56485672
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)