Skip to content

Commit 49ea349

Browse files
authored
fix: HLIL member_index masking + operand-count table (root cause) (#24)
Python's _get_member_index masks the sentinel (1<<63) and returns None when there is no named member; the binding returned the raw ulong and never returned null. Investigation showed the deeper root cause: the OperationOperands table undercounted the three field instructions by omitting the member_index slot, so RawOperands was one short and ANY operand access on them (including the existing Offset) threw IndexOutOfRangeException. member_index was therefore never readable at all. - OperationOperands: HLIL_STRUCT_FIELD 2->3, HLIL_DEREF_FIELD 2->3, HLIL_DEREF_FIELD_SSA 3->4 (source, offset/srcMem, member_index). Growing the count only adds the member_index slot; existing operand indices are unchanged. - HighLevelILInstruction.MemberIndexFromRawOperand: masks the (1<<63) sentinel to null, mirroring Python _get_member_index. - HLILStructField.MemberIndex, HLILDerefField.MemberIndex, HLILDerefFieldSSA.MemberIndex: long? via the helper. The two Deref members are renamed from MemoryIndex for parity with StructField (no internal callers).
1 parent 492c4b4 commit 49ea349

4 files changed

Lines changed: 36 additions & 9 deletions

File tree

HighLevelIL/HLILDerefField.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,16 @@ public long Offset
2727
}
2828
}
2929

30-
public ulong MemoryIndex
30+
/// <summary>
31+
/// The named-member index, or null when there is no named member. Mirrors Python
32+
/// <c>_get_member_index</c> (renamed from <c>MemoryIndex</c> for parity with
33+
/// <see cref="HLILStructField.MemberIndex"/> and <see cref="HLILDerefFieldSSA"/>).
34+
/// </summary>
35+
public long? MemberIndex
3136
{
3237
get
3338
{
34-
return this.RawOperands[2];
39+
return HighLevelILInstruction.MemberIndexFromRawOperand(this.RawOperands[2]);
3540
}
3641
}
3742
}

HighLevelIL/HLILDerefFieldSSA.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,16 @@ public long Offset
3535
}
3636
}
3737

38-
public ulong MemoryIndex
38+
/// <summary>
39+
/// The named-member index, or null when there is no named member. Mirrors Python
40+
/// <c>_get_member_index</c> (renamed from <c>MemoryIndex</c> for parity with
41+
/// <see cref="HLILStructField.MemberIndex"/> and <see cref="HLILDerefField"/>).
42+
/// </summary>
43+
public long? MemberIndex
3944
{
4045
get
4146
{
42-
return this.RawOperands[3];
47+
return HighLevelILInstruction.MemberIndexFromRawOperand(this.RawOperands[3]);
4348
}
4449
}
4550
}

HighLevelIL/HLILStructField.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,15 @@ public long Offset
2727
}
2828
}
2929

30-
public ulong MemberIndex
30+
/// <summary>
31+
/// The named-member index, or null when there is no named member. Mirrors Python
32+
/// <c>_get_member_index</c>: the sentinel (1&lt;&lt;63) means no named member.
33+
/// </summary>
34+
public long? MemberIndex
3135
{
3236
get
3337
{
34-
return this.RawOperands[2];
38+
return HighLevelILInstruction.MemberIndexFromRawOperand(this.RawOperands[2]);
3539
}
3640
}
3741
}

Struct/BNHighLevelILInstruction.cs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,11 +94,11 @@ public abstract class HighLevelILInstruction :
9494
{ HighLevelILOperation.HLIL_ASSERT, 1 }, // cond
9595

9696
{ HighLevelILOperation.HLIL_VAR, 1 }, // var
97-
{ HighLevelILOperation.HLIL_STRUCT_FIELD, 2 }, // base, fieldOffset/index
97+
{ HighLevelILOperation.HLIL_STRUCT_FIELD, 3 }, // base, fieldOffset, memberIndex
9898
{ HighLevelILOperation.HLIL_ARRAY_INDEX, 2 }, // base, index
9999
{ HighLevelILOperation.HLIL_SPLIT, 2 }, // hi, lo
100100
{ HighLevelILOperation.HLIL_DEREF, 1 }, // addr
101-
{ HighLevelILOperation.HLIL_DEREF_FIELD, 2 }, // addr, fieldOffset/index
101+
{ HighLevelILOperation.HLIL_DEREF_FIELD, 3 }, // addr, fieldOffset, memberIndex
102102
{ HighLevelILOperation.HLIL_ADDRESS_OF, 1 }, // var/expr
103103

104104
{ HighLevelILOperation.HLIL_CONST, 1 }, // value
@@ -201,7 +201,7 @@ public abstract class HighLevelILInstruction :
201201
{ HighLevelILOperation.HLIL_VAR_SSA, 2 }, // var, version
202202
{ HighLevelILOperation.HLIL_ARRAY_INDEX_SSA, 3 }, // base, index, srcMem
203203
{ HighLevelILOperation.HLIL_DEREF_SSA, 2 }, // addr, srcMem
204-
{ HighLevelILOperation.HLIL_DEREF_FIELD_SSA, 3 }, // addr, field, srcMem
204+
{ HighLevelILOperation.HLIL_DEREF_FIELD_SSA, 4 }, // addr, srcMem, fieldOffset, memberIndex
205205

206206
{ HighLevelILOperation.HLIL_CALL_SSA, 4 }, // dest, params(list), outputs(list), srcMem
207207
{ HighLevelILOperation.HLIL_SYSCALL_SSA, 3 }, // params(list), outputs(list), srcMem
@@ -986,6 +986,19 @@ public double GetOperandAsDouble(OperandIndex operand)
986986
{
987987
return BitConverter.UInt64BitsToDouble(this.RawOperands[(ulong)operand]);
988988
}
989+
990+
// member_index mask: mirrors Python HighLevelILInstruction._get_member_index. The sentinel
991+
// (1<<63) means "no named member" and is returned as null; otherwise the (non-negative)
992+
// named-member index. Callers pass the already-extracted raw operand value.
993+
internal static long? MemberIndexFromRawOperand(ulong rawOperand)
994+
{
995+
if (0UL != (rawOperand & (1UL << 63)))
996+
{
997+
return null;
998+
}
999+
1000+
return (long)rawOperand;
1001+
}
9891002

9901003
public RegisterValue GetOperandAsConstantData(
9911004
OperandIndex operand1 ,

0 commit comments

Comments
 (0)