From 3f9ec1cab18efab5da1e906fa186cd1b98485b9d Mon Sep 17 00:00:00 2001 From: tinysec Date: Thu, 9 Jul 2026 12:05:37 +0800 Subject: [PATCH] feat: add HLIL DetailedOperands/Operands/Traverse navigation (#13,#15) Mirror Python HighLevelILInstruction.detailed_operands / operands / traverse (highlevelil.py:795/786/802). A static descriptor table (operation -> named, typed operands) drives a kind-dispatched reader; Operands and Traverse derive from it, exactly as in Python. - HighLevelILOperand: enum Kind + readonly Operand/Descriptor structs. - HighLevelILDetailedOperandsTable: 114-op descriptor table generated from the Python detailed_operands overrides, abstract bases expanded to concrete ops. - HighLevelILInstruction: GetOperandAsInteger, virtual DetailedOperands, ReadDetailedOperandByKind (SSA var + constant data occupy two raw slots), Operands, generic Traverse (DFS, shallow blacklist matches Python). - HLILVariableDeclare: expose the .Variable accessor (the one missing accessor). Divergence from Python (intentional, documented in the table header): HLIL_ROR omits the "carry" operand -- Python's HighLevelILRor inherits CarryBase but the core (highlevelilinstruction.cpp:189) defines ROR with only {left,right}, so Python's Ror.carry reads a non-existent slot. C# follows the core (OperationOperands = 2, matching PR #26's removal of the bogus Carry accessor). E2E (harness, not in this repo): DetailedOperands parity vs the Python spec for ADD/STRUCT_FIELD/CONST(+PTR/FLOAT); Operands + Traverse; full cat.bndb sweep no-throw; static consistency test reflecting over the table + OperationOperands catches out-of-bounds indices (the ROR bug above was found + fixed by it). 76/76 pass. --- HighLevelIL/HLILVariableDeclare.cs | 3 +- .../HighLevelILDetailedOperandsTable.cs | 141 +++++++++++++++ HighLevelIL/HighLevelILOperand.cs | 110 ++++++++++++ Struct/BNHighLevelILInstruction.cs | 165 ++++++++++++++++++ 4 files changed, 417 insertions(+), 2 deletions(-) create mode 100644 HighLevelIL/HighLevelILDetailedOperandsTable.cs create mode 100644 HighLevelIL/HighLevelILOperand.cs diff --git a/HighLevelIL/HLILVariableDeclare.cs b/HighLevelIL/HLILVariableDeclare.cs index df455ee..7d18bda 100644 --- a/HighLevelIL/HLILVariableDeclare.cs +++ b/HighLevelIL/HLILVariableDeclare.cs @@ -11,7 +11,7 @@ BNHighLevelILInstruction native } - /* + /// The declared variable (Python HighLevelILVarDeclare.var, highlevelil.py). public HighLevelILVariable Variable { get @@ -19,6 +19,5 @@ public HighLevelILVariable Variable return this.GetOperandAsVariable((OperandIndex)0); } } - */ } } diff --git a/HighLevelIL/HighLevelILDetailedOperandsTable.cs b/HighLevelIL/HighLevelILDetailedOperandsTable.cs new file mode 100644 index 0000000..345f214 --- /dev/null +++ b/HighLevelIL/HighLevelILDetailedOperandsTable.cs @@ -0,0 +1,141 @@ +using System.Collections.Generic; + +namespace BinaryNinja +{ + // Static table driving HighLevelILInstruction.DetailedOperands. Maps each HighLevelILOperation + // to its named operand descriptors (name, kind, raw operand index, Python type name). Generated + // from the official Python HighLevelILInstruction.detailed_operands overrides (highlevelil.py), + // with abstract-base operands expanded to every concrete op via the Python class hierarchy. Ops + // absent from the table have no detailed operands (the base DetailedOperands returns an empty + // list). The HLILDetailedOperandsConsistencyTests in the harness assert this table's count + + // raw indices still agree with the per-op accessor classes (the guard against the second-table + // drift seen with OperationOperands in PR #26/#27/#28). + // + // ONE intentional divergence from Python: HLIL_ROR. In Python, HighLevelILRor inherits + // HighLevelILCarryBase, so its detailed_operands lists a third "carry" operand -- but the core + // (highlevelilinstruction.cpp:189) defines HLIL_ROR with only {left, right}; Python's + // Ror.carry reads a non-existent slot (garbage). The C# binding follows the core, so ROR has + // just {left, right} here and OperationOperands[HLIL_ROR] = 2. RLC/RRC/ADC/SBB genuinely have a + // carry slot in the core, so they keep it. + internal static class HighLevelILDetailedOperandsTable + { + internal static readonly Dictionary Table = + new Dictionary + { + { HighLevelILOperation.HLIL_ADC, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("left", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("right", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("carry", HighLevelILOperandKind.Expression, 2, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_ADD, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("left", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("right", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_ADDRESS_OF, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("src", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_ADD_OVERFLOW, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("left", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("right", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_AND, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("left", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("right", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_ARRAY_INDEX, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("src", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("index", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_ARRAY_INDEX_SSA, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("src", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("src_memory", HighLevelILOperandKind.Integer, 1, "int"), new HighLevelILOperandDescriptor("index", HighLevelILOperandKind.Expression, 2, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_ASR, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("left", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("right", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_ASSIGN, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("dest", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("src", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_ASSIGN_MEM_SSA, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("dest", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("dest_memory", HighLevelILOperandKind.Integer, 1, "int"), new HighLevelILOperandDescriptor("src", HighLevelILOperandKind.Expression, 2, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("src_memory", HighLevelILOperandKind.Integer, 3, "int") } }, + { HighLevelILOperation.HLIL_ASSIGN_UNPACK, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("dest", HighLevelILOperandKind.ExpressionList, 0, "List[HighLevelILInstruction]"), new HighLevelILOperandDescriptor("src", HighLevelILOperandKind.Expression, 2, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_ASSIGN_UNPACK_MEM_SSA, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("dest", HighLevelILOperandKind.ExpressionList, 0, "List[HighLevelILInstruction]"), new HighLevelILOperandDescriptor("dest_memory", HighLevelILOperandKind.Integer, 2, "int"), new HighLevelILOperandDescriptor("src", HighLevelILOperandKind.Expression, 3, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("src_memory", HighLevelILOperandKind.Integer, 4, "int") } }, + { HighLevelILOperation.HLIL_BLOCK, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("body", HighLevelILOperandKind.ExpressionList, 0, "List[HighLevelILInstruction]") } }, + { HighLevelILOperation.HLIL_BOOL_TO_INT, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("src", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_CALL, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("dest", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("params", HighLevelILOperandKind.ExpressionList, 1, "List[HighLevelILInstruction]") } }, + { HighLevelILOperation.HLIL_CALL_SSA, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("dest", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("params", HighLevelILOperandKind.ExpressionList, 1, "List[HighLevelILInstruction]"), new HighLevelILOperandDescriptor("dest_memory", HighLevelILOperandKind.Integer, 3, "int"), new HighLevelILOperandDescriptor("src_memory", HighLevelILOperandKind.Integer, 4, "int") } }, + { HighLevelILOperation.HLIL_CASE, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("values", HighLevelILOperandKind.ExpressionList, 0, "List[HighLevelILInstruction]"), new HighLevelILOperandDescriptor("body", HighLevelILOperandKind.Expression, 2, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_CEIL, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("src", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_CMP_E, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("left", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("right", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_CMP_NE, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("left", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("right", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_CMP_SGE, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("left", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("right", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_CMP_SGT, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("left", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("right", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_CMP_SLE, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("left", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("right", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_CMP_SLT, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("left", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("right", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_CMP_UGE, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("left", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("right", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_CMP_UGT, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("left", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("right", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_CMP_ULE, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("left", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("right", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_CMP_ULT, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("left", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("right", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_CONST, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("constant", HighLevelILOperandKind.Integer, 0, "int") } }, + { HighLevelILOperation.HLIL_CONST_DATA, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("constant", HighLevelILOperandKind.ConstantData, 0, "ConstantData") } }, + { HighLevelILOperation.HLIL_CONST_PTR, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("constant", HighLevelILOperandKind.Integer, 0, "int") } }, + { HighLevelILOperation.HLIL_DEREF, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("src", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_DEREF_FIELD, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("src", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("offset", HighLevelILOperandKind.Integer, 1, "int"), new HighLevelILOperandDescriptor("member_index", HighLevelILOperandKind.Integer, 2, "Optional[int]") } }, + { HighLevelILOperation.HLIL_DEREF_FIELD_SSA, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("src", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("src_memory", HighLevelILOperandKind.Integer, 1, "int"), new HighLevelILOperandDescriptor("offset", HighLevelILOperandKind.Integer, 2, "int"), new HighLevelILOperandDescriptor("member_index", HighLevelILOperandKind.Integer, 3, "Optional[int]") } }, + { HighLevelILOperation.HLIL_DEREF_SSA, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("src", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("src_memory", HighLevelILOperandKind.Integer, 1, "int") } }, + { HighLevelILOperation.HLIL_DIVS, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("left", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("right", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_DIVS_DP, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("left", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("right", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_DIVU, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("left", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("right", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_DIVU_DP, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("left", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("right", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_DO_WHILE, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("body", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("condition", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_DO_WHILE_SSA, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("body", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("condition_phi", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("condition", HighLevelILOperandKind.Expression, 2, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_EXTERN_PTR, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("constant", HighLevelILOperandKind.Integer, 0, "int"), new HighLevelILOperandDescriptor("offset", HighLevelILOperandKind.Integer, 1, "int") } }, + { HighLevelILOperation.HLIL_FABS, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("src", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_FADD, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("left", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("right", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_FCMP_E, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("left", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("right", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_FCMP_GE, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("left", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("right", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_FCMP_GT, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("left", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("right", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_FCMP_LE, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("left", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("right", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_FCMP_LT, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("left", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("right", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_FCMP_NE, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("left", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("right", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_FCMP_O, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("left", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("right", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_FCMP_UO, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("left", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("right", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_FDIV, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("left", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("right", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_FLOAT_CONST, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("constant", HighLevelILOperandKind.Float, 0, "float") } }, + { HighLevelILOperation.HLIL_FLOAT_CONV, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("src", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_FLOAT_TO_INT, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("src", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_FLOOR, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("src", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_FMUL, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("left", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("right", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_FNEG, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("src", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_FOR, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("init", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("condition", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("update", HighLevelILOperandKind.Expression, 2, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("body", HighLevelILOperandKind.Expression, 3, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_FOR_SSA, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("init", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("condition_phi", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("condition", HighLevelILOperandKind.Expression, 2, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("update", HighLevelILOperandKind.Expression, 3, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("body", HighLevelILOperandKind.Expression, 4, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_FSQRT, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("src", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_FSUB, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("left", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("right", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_FTRUNC, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("src", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_GOTO, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("target", HighLevelILOperandKind.GotoLabel, 0, "GotoLabel") } }, + { HighLevelILOperation.HLIL_IF, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("condition", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("true", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("false", HighLevelILOperandKind.Expression, 2, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_IMPORT, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("constant", HighLevelILOperandKind.Integer, 0, "int") } }, + { HighLevelILOperation.HLIL_INTRINSIC, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("intrinsic", HighLevelILOperandKind.Intrinsic, 0, "ILIntrinsic"), new HighLevelILOperandDescriptor("params", HighLevelILOperandKind.ExpressionList, 1, "List[HighLevelILInstruction]") } }, + { HighLevelILOperation.HLIL_INTRINSIC_SSA, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("intrinsic", HighLevelILOperandKind.Intrinsic, 0, "ILIntrinsic"), new HighLevelILOperandDescriptor("params", HighLevelILOperandKind.ExpressionList, 1, "List[HighLevelILInstruction]"), new HighLevelILOperandDescriptor("dest_memory", HighLevelILOperandKind.Integer, 3, "int"), new HighLevelILOperandDescriptor("src_memory", HighLevelILOperandKind.Integer, 4, "int") } }, + { HighLevelILOperation.HLIL_INT_TO_FLOAT, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("src", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_JUMP, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("dest", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_LABEL, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("target", HighLevelILOperandKind.GotoLabel, 0, "GotoLabel") } }, + { HighLevelILOperation.HLIL_LOW_PART, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("src", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_LSL, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("left", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("right", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_LSR, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("left", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("right", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_MEM_PHI, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("dest", HighLevelILOperandKind.Integer, 0, "int"), new HighLevelILOperandDescriptor("src", HighLevelILOperandKind.IntegerList, 1, "List[int]") } }, + { HighLevelILOperation.HLIL_MODS, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("left", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("right", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_MODS_DP, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("left", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("right", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_MODU, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("left", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("right", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_MODU_DP, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("left", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("right", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_MUL, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("left", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("right", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_MULS_DP, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("left", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("right", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_MULU_DP, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("left", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("right", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_NEG, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("src", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_NOT, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("src", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_OR, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("left", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("right", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_RET, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("src", HighLevelILOperandKind.ExpressionList, 0, "List[HighLevelILInstruction]") } }, + { HighLevelILOperation.HLIL_RLC, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("left", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("right", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("carry", HighLevelILOperandKind.Expression, 2, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_ROL, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("left", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("right", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_ROR, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("left", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("right", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction") } }, // See file header: ROR intentionally omits Python's buggy "carry" (no slot in the core). + { HighLevelILOperation.HLIL_ROUND_TO_INT, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("src", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_RRC, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("left", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("right", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("carry", HighLevelILOperandKind.Expression, 2, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_SBB, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("left", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("right", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("carry", HighLevelILOperandKind.Expression, 2, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_SPLIT, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("high", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("low", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_STRUCT_FIELD, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("src", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("offset", HighLevelILOperandKind.Integer, 1, "int"), new HighLevelILOperandDescriptor("member_index", HighLevelILOperandKind.Integer, 2, "Optional[int]") } }, + { HighLevelILOperation.HLIL_SUB, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("left", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("right", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_SWITCH, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("condition", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("default", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("cases", HighLevelILOperandKind.ExpressionList, 2, "List[HighLevelILInstruction]") } }, + { HighLevelILOperation.HLIL_SX, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("src", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_SYSCALL, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("params", HighLevelILOperandKind.ExpressionList, 0, "List[HighLevelILInstruction]") } }, + { HighLevelILOperation.HLIL_SYSCALL_SSA, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("params", HighLevelILOperandKind.ExpressionList, 0, "List[HighLevelILInstruction]"), new HighLevelILOperandDescriptor("dest_memory", HighLevelILOperandKind.Integer, 2, "int"), new HighLevelILOperandDescriptor("src_memory", HighLevelILOperandKind.Integer, 3, "int") } }, + { HighLevelILOperation.HLIL_TAILCALL, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("dest", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("params", HighLevelILOperandKind.ExpressionList, 1, "List[HighLevelILInstruction]") } }, + { HighLevelILOperation.HLIL_TEST_BIT, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("left", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("right", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_TRAP, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("vector", HighLevelILOperandKind.Integer, 0, "int") } }, + { HighLevelILOperation.HLIL_UNIMPL_MEM, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("src", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_VAR, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("var", HighLevelILOperandKind.Variable, 0, "Variable") } }, + { HighLevelILOperation.HLIL_VAR_DECLARE, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("var", HighLevelILOperandKind.Variable, 0, "Variable") } }, + { HighLevelILOperation.HLIL_VAR_INIT, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("dest", HighLevelILOperandKind.Variable, 0, "Variable"), new HighLevelILOperandDescriptor("src", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_VAR_INIT_SSA, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("dest", HighLevelILOperandKind.SSAVariable, 0, "SSAVariable"), new HighLevelILOperandDescriptor("src", HighLevelILOperandKind.Expression, 2, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_VAR_PHI, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("dest", HighLevelILOperandKind.SSAVariable, 0, "SSAVariable"), new HighLevelILOperandDescriptor("src", HighLevelILOperandKind.SSAVariableList, 2, "List[SSAVariable]") } }, + { HighLevelILOperation.HLIL_VAR_SSA, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("var", HighLevelILOperandKind.SSAVariable, 0, "SSAVariable") } }, + { HighLevelILOperation.HLIL_WHILE, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("condition", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("body", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_WHILE_SSA, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("condition_phi", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("condition", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("body", HighLevelILOperandKind.Expression, 2, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_XOR, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("left", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction"), new HighLevelILOperandDescriptor("right", HighLevelILOperandKind.Expression, 1, "HighLevelILInstruction") } }, + { HighLevelILOperation.HLIL_ZX, new HighLevelILOperandDescriptor[] { new HighLevelILOperandDescriptor("src", HighLevelILOperandKind.Expression, 0, "HighLevelILInstruction") } }, + }; + } +} diff --git a/HighLevelIL/HighLevelILOperand.cs b/HighLevelIL/HighLevelILOperand.cs new file mode 100644 index 0000000..576562e --- /dev/null +++ b/HighLevelIL/HighLevelILOperand.cs @@ -0,0 +1,110 @@ +namespace BinaryNinja +{ + /// + /// Categorizes one detailed operand of a by how it is read + /// from the native instruction's raw operand slots. Mirrors the type strings returned by Python's + /// HighLevelILInstruction.detailed_operands (highlevelil.py), collapsed to the reader + /// dispatched in . + /// + public enum HighLevelILOperandKind + { + /// A single sub-expression (Python type "HighLevelILInstruction"). + Expression, + + /// A list of sub-expressions (Python type "List[HighLevelILInstruction]"). + ExpressionList, + + /// A single integer slot (Python type "int" or "Optional[int]"). + Integer, + + /// A list of integer slots (Python type "List[int]"). + IntegerList, + + /// A single variable (Python type "Variable"). + Variable, + + /// A list of variables (Python type "List[Variable]"). + VariableList, + + /// A single SSA variable occupying two raw slots (Python type "SSAVariable"). + SSAVariable, + + /// A list of SSA variables (Python type "List[SSAVariable]"). + SSAVariableList, + + /// A floating-point constant (Python type "float"). + Float, + + /// A goto label reference (Python type "GotoLabel"). + GotoLabel, + + /// Constant data (Python type "ConstantData"). + ConstantData, + + /// An intrinsic reference (Python type "ILIntrinsic"). + Intrinsic + } + + /// + /// A named, typed operand of a : the value plus its name, + /// kind, and the Python type string. This is the C# equivalent of one + /// (name, value, type_str) tuple from Python + /// HighLevelILInstruction.detailed_operands (highlevelil.py:795). + /// + public readonly struct HighLevelILOperand + { + /// The operand's name, e.g. "left", "src", "condition" (matches Python). + public string Name { get; } + + /// + /// The operand value. The runtime type follows : a + /// , long, , + /// , float, or an array of those. May be null + /// when the underlying native operand is absent. + /// + public object? Value { get; } + + /// How the value was read; drives traversal and variable collection. + public HighLevelILOperandKind Kind { get; } + + /// The Python type string, e.g. "HighLevelILInstruction", "int", "Variable". + public string TypeName { get; } + + internal HighLevelILOperand(string name, object? value, HighLevelILOperandKind kind, string typeName) + { + this.Name = name; + this.Value = value; + this.Kind = kind; + this.TypeName = typeName; + } + } + + /// + /// One row of the static detailed-operands table: an operand's name, the reader kind, the raw + /// operand index it occupies, and the Python type string. Used to build + /// values at query time. + /// + internal readonly struct HighLevelILOperandDescriptor + { + internal string Name { get; } + + internal HighLevelILOperandKind Kind { get; } + + /// + /// The raw operand slot the value starts at. For + /// the version occupies the next slot (index + 1). + /// + internal int RawIndex { get; } + + internal string TypeName { get; } + + internal HighLevelILOperandDescriptor( + string name, HighLevelILOperandKind kind, int rawIndex, string typeName) + { + this.Name = name; + this.Kind = kind; + this.RawIndex = rawIndex; + this.TypeName = typeName; + } + } +} diff --git a/Struct/BNHighLevelILInstruction.cs b/Struct/BNHighLevelILInstruction.cs index dc49da3..b632fcd 100644 --- a/Struct/BNHighLevelILInstruction.cs +++ b/Struct/BNHighLevelILInstruction.cs @@ -1738,6 +1738,171 @@ public LowLevelILInstruction[] LowLevelILs } } + /// + /// Reads one raw operand slot as a signed integer, mirroring the integer operands exposed by + /// Python HighLevelILInstruction detailed_operands (e.g. StructField.offset, Const.constant). + /// + public long GetOperandAsInteger(OperandIndex operand) + { + return (long)this.RawOperands[(ulong)operand]; + } + + /// + /// The named, typed operands of this instruction, mirroring Python + /// HighLevelILInstruction.detailed_operands (highlevelil.py:795). Each entry pairs the operand + /// name (e.g. "left", "src", "condition"), its value, its kind, and the Python type string. + /// Operations with no operands return an empty list. This is the foundation for + /// and . + /// + public virtual IList DetailedOperands + { + get + { + if (false == HighLevelILDetailedOperandsTable.Table.TryGetValue( + this.Operation, out HighLevelILOperandDescriptor[]? descriptors)) + { + return new List(); + } + + List result = new List(descriptors.Length); + + foreach (HighLevelILOperandDescriptor descriptor in descriptors) + { + object? value = this.ReadDetailedOperandByKind(descriptor.Kind, descriptor.RawIndex); + result.Add(new HighLevelILOperand( + descriptor.Name, value, descriptor.Kind, descriptor.TypeName)); + } + + return result; + } + } + + /// + /// Reads one operand by its descriptor kind. An SSA variable occupies two raw slots -- the + /// variable identifier at RawIndex and its version at RawIndex + 1. + /// + private object? ReadDetailedOperandByKind(HighLevelILOperandKind kind, int rawIndex) + { + OperandIndex index = (OperandIndex)(ulong)rawIndex; + + switch (kind) + { + case HighLevelILOperandKind.Expression: + return this.GetOperandAsExpression(index); + + case HighLevelILOperandKind.ExpressionList: + return this.GetOperandAsExpressionList(index); + + case HighLevelILOperandKind.Integer: + return this.GetOperandAsInteger(index); + + case HighLevelILOperandKind.IntegerList: + return this.GetOperandAsIntegerArray(index); + + case HighLevelILOperandKind.Variable: + return this.GetOperandAsVariable(index); + + case HighLevelILOperandKind.VariableList: + return this.GetOperandAsVariableList(index); + + case HighLevelILOperandKind.SSAVariable: + return this.GetOperandAsSSAVariable(index, (OperandIndex)(ulong)(rawIndex + 1)); + + case HighLevelILOperandKind.SSAVariableList: + return this.GetOperandAsSSAVariableList(index); + + case HighLevelILOperandKind.Float: + return this.GetOperandAsDouble(index); + + case HighLevelILOperandKind.GotoLabel: + return this.GetOperandAsLabel(index); + + case HighLevelILOperandKind.ConstantData: + return this.GetOperandAsConstantData(index, (OperandIndex)(ulong)(rawIndex + 1)); + + case HighLevelILOperandKind.Intrinsic: + return this.GetOperandAsIntrinsic(index); + + default: + return null; + } + } + + /// + /// The operand values of this instruction (the value component of + /// ), mirroring Python HighLevelILInstruction.operands + /// (highlevelil.py:786). Prefer the named accessors (Source, Left, Condition, ...) when the + /// operand kind is known at the call site. + /// + public IList Operands + { + get + { + IList detailed = this.DetailedOperands; + List result = new List(detailed.Count); + + foreach (HighLevelILOperand operand in detailed) + { + result.Add(operand.Value); + } + + return result; + } + } + + /// + /// Depth-first traversal of this instruction's operand tree, mirroring Python + /// HighLevelILInstruction.traverse (highlevelil.py:802). The callback is invoked on this node + /// and every reachable sub-instruction; each non-null result is yielded. Pass a named method + /// (method group) as the callback. When is true (the default) the + /// block bodies, switch cases/defaults, and if true/false branches are not descended into, + /// matching Python's blacklisted operand names. + /// + /// The result type; constrained to a reference type so null signals + /// "do not yield". + public IEnumerable Traverse( + Func callback, bool shallow = true) where T : class + { + T? root = callback(this); + + if (null != root) + { + yield return root; + } + + foreach (HighLevelILOperand operand in this.DetailedOperands) + { + if (shallow && HighLevelILInstruction.ShallowTraversalBlacklist.Contains(operand.Name)) + { + continue; + } + + if (operand.Value is HighLevelILInstruction subInstruction) + { + foreach (T nested in subInstruction.Traverse(callback, shallow)) + { + yield return nested; + } + } + else if (operand.Value is HighLevelILInstruction[] subList) + { + foreach (HighLevelILInstruction item in subList) + { + foreach (T nested in item.Traverse(callback, shallow)) + { + yield return nested; + } + } + } + } + } + + // Operand names Python skips during shallow traversal (highlevelil.py:826): descending into + // block bodies, switch cases/defaults, or if true/false branches would leave the enclosing + // instruction's scope. Allocated once and reused across traversals. + private static readonly HashSet ShallowTraversalBlacklist = + new HashSet { "true", "false", "body", "cases", "default" }; + } } \ No newline at end of file