diff options
| author | Rusty Wagner <rusty@vector35.com> | 2019-08-01 16:31:34 -0400 |
|---|---|---|
| committer | Rusty Wagner <rusty@vector35.com> | 2020-04-17 14:20:36 -0400 |
| commit | c9845e5a200228f20809336d9e9afee45e776d19 (patch) | |
| tree | 3b02742c03e6a63075663a68c0a36d9ad16187fa | |
| parent | 652dd72149b9c030e438d6de1a03ef54eafd8091 (diff) | |
Add mem SSA to HLIL
| -rw-r--r-- | binaryninjaapi.h | 21 | ||||
| -rw-r--r-- | binaryninjacore.h | 11 | ||||
| -rw-r--r-- | highlevelil.cpp | 13 | ||||
| -rw-r--r-- | highlevelilinstruction.cpp | 257 | ||||
| -rw-r--r-- | highlevelilinstruction.h | 126 | ||||
| -rw-r--r-- | python/highlevelil.py | 9 |
6 files changed, 424 insertions, 13 deletions
diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 1cbcc973..eba63058 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -4068,17 +4068,29 @@ __attribute__ ((format (printf, 1, 2))) ExprId Assign(size_t size, ExprId dest, ExprId src, const ILSourceLocation& loc = ILSourceLocation()); ExprId AssignUnpack(const std::vector<ExprId>& output, ExprId src, const ILSourceLocation& loc = ILSourceLocation()); + ExprId AssignMemSSA(size_t size, ExprId dest, size_t destMemVersion, ExprId src, size_t srcMemVersion, + const ILSourceLocation& loc = ILSourceLocation()); + ExprId AssignUnpackMemSSA(const std::vector<ExprId>& output, size_t destMemVersion, ExprId src, + size_t srcMemVersion, const ILSourceLocation& loc = ILSourceLocation()); ExprId Var(size_t size, const Variable& src, const ILSourceLocation& loc = ILSourceLocation()); ExprId VarSSA(size_t size, const SSAVariable& src, const ILSourceLocation& loc = ILSourceLocation()); ExprId VarPhi(const SSAVariable& dest, const std::vector<SSAVariable>& sources, const ILSourceLocation& loc = ILSourceLocation()); + ExprId MemPhi(size_t dest, const std::vector<size_t>& sources, + const ILSourceLocation& loc = ILSourceLocation()); ExprId StructField(size_t size, ExprId src, uint64_t offset, const ILSourceLocation& loc = ILSourceLocation()); ExprId ArrayIndex(size_t size, ExprId src, ExprId idx, const ILSourceLocation& loc = ILSourceLocation()); + ExprId ArrayIndexSSA(size_t size, ExprId src, size_t srcMemVersion, ExprId idx, + const ILSourceLocation& loc = ILSourceLocation()); ExprId Split(size_t size, ExprId high, ExprId low, const ILSourceLocation& loc = ILSourceLocation()); ExprId Deref(size_t size, ExprId src, const ILSourceLocation& loc = ILSourceLocation()); ExprId DerefField(size_t size, ExprId src, uint64_t offset, const ILSourceLocation& loc = ILSourceLocation()); + ExprId DerefSSA(size_t size, ExprId src, size_t srcMemVersion, + const ILSourceLocation& loc = ILSourceLocation()); + ExprId DerefFieldSSA(size_t size, ExprId src, size_t srcMemVersion, uint64_t offset, + const ILSourceLocation& loc = ILSourceLocation()); ExprId AddressOf(ExprId src, const ILSourceLocation& loc = ILSourceLocation()); ExprId Const(size_t size, uint64_t val, const ILSourceLocation& loc = ILSourceLocation()); ExprId ConstPointer(size_t size, uint64_t val, const ILSourceLocation& loc = ILSourceLocation()); @@ -4141,6 +4153,10 @@ __attribute__ ((format (printf, 1, 2))) ExprId Syscall(const std::vector<ExprId>& params, const ILSourceLocation& loc = ILSourceLocation()); ExprId TailCall(ExprId dest, const std::vector<ExprId>& params, const ILSourceLocation& loc = ILSourceLocation()); + ExprId CallSSA(ExprId dest, const std::vector<ExprId>& params, size_t destMemVersion, size_t srcMemVersion, + const ILSourceLocation& loc = ILSourceLocation()); + ExprId SyscallSSA(const std::vector<ExprId>& params, size_t destMemVersion, size_t srcMemVersion, + const ILSourceLocation& loc = ILSourceLocation()); ExprId CompareEqual(size_t size, ExprId left, ExprId right, const ILSourceLocation& loc = ILSourceLocation()); ExprId CompareNotEqual(size_t size, ExprId left, ExprId right, @@ -4170,6 +4186,8 @@ __attribute__ ((format (printf, 1, 2))) ExprId Trap(int64_t vector, const ILSourceLocation& loc = ILSourceLocation()); ExprId Intrinsic(uint32_t intrinsic, const std::vector<ExprId>& params, const ILSourceLocation& loc = ILSourceLocation()); + ExprId IntrinsicSSA(uint32_t intrinsic, const std::vector<ExprId>& params, size_t destMemVersion, + size_t srcMemVersion, const ILSourceLocation& loc = ILSourceLocation()); ExprId Undefined(const ILSourceLocation& loc = ILSourceLocation()); ExprId Unimplemented(const ILSourceLocation& loc = ILSourceLocation()); ExprId UnimplementedMemoryRef(size_t size, ExprId target, @@ -4198,7 +4216,8 @@ __attribute__ ((format (printf, 1, 2))) ExprId FloatCompareUnordered(size_t size, ExprId a, ExprId b, const ILSourceLocation& loc = ILSourceLocation()); std::vector<uint64_t> GetOperandList(ExprId i, size_t listOperand); - ExprId AddOperandList(const std::vector<ExprId> operands); + ExprId AddOperandList(const std::vector<ExprId>& operands); + ExprId AddIndexList(const std::vector<size_t>& operands); ExprId AddSSAVariableList(const std::vector<SSAVariable>& vars); BNHighLevelILInstruction GetRawExpr(size_t i) const; diff --git a/binaryninjacore.h b/binaryninjacore.h index 03ddcd4d..077f743b 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -1157,8 +1157,17 @@ extern "C" HLIL_FCMP_UO, // The following instructions are only used in SSA form + HLIL_ASSIGN_MEM_SSA, + HLIL_ASSIGN_UNPACK_MEM_SSA, HLIL_VAR_SSA, - HLIL_VAR_PHI + HLIL_ARRAY_INDEX_SSA, + HLIL_DEREF_SSA, + HLIL_DEREF_FIELD_SSA, + HLIL_CALL_SSA, + HLIL_SYSCALL_SSA, + HLIL_INTRINSIC_SSA, + HLIL_VAR_PHI, + HLIL_MEM_PHI }; struct BNHighLevelILInstruction diff --git a/highlevelil.cpp b/highlevelil.cpp index 10fb9703..679344ce 100644 --- a/highlevelil.cpp +++ b/highlevelil.cpp @@ -124,7 +124,18 @@ vector<uint64_t> HighLevelILFunction::GetOperandList(ExprId expr, size_t listOpe } -ExprId HighLevelILFunction::AddOperandList(const vector<ExprId> operands) +ExprId HighLevelILFunction::AddOperandList(const vector<ExprId>& operands) +{ + uint64_t* operandList = new uint64_t[operands.size()]; + for (size_t i = 0; i < operands.size(); i++) + operandList[i] = operands[i]; + ExprId result = (ExprId)BNHighLevelILAddOperandList(m_object, operandList, operands.size()); + delete[] operandList; + return result; +} + + +ExprId HighLevelILFunction::AddIndexList(const vector<size_t>& operands) { uint64_t* operandList = new uint64_t[operands.size()]; for (size_t i = 0; i < operands.size(); i++) diff --git a/highlevelilinstruction.cpp b/highlevelilinstruction.cpp index a53d5fe4..801f5ec1 100644 --- a/highlevelilinstruction.cpp +++ b/highlevelilinstruction.cpp @@ -63,7 +63,10 @@ unordered_map<HighLevelILOperandUsage, HighLevelILOperandType> {DestExprsHighLevelOperandUsage, ExprListHighLevelOperand}, {BlockExprsHighLevelOperandUsage, ExprListHighLevelOperand}, {CasesHighLevelOperandUsage, ExprListHighLevelOperand}, - {SourceSSAVariablesHighLevelOperandUsage, SSAVariableListHighLevelOperand} + {SourceSSAVariablesHighLevelOperandUsage, SSAVariableListHighLevelOperand}, + {SourceMemoryVersionHighLevelOperandUsage, IndexHighLevelOperand}, + {SourceMemoryVersionsHighLevelOperandUsage, IndexListHighLevelOperand}, + {DestMemoryVersionHighLevelOperandUsage, IndexHighLevelOperand} }; @@ -92,19 +95,35 @@ unordered_map<BNHighLevelILOperation, vector<HighLevelILOperandUsage>> {HLIL_LABEL, {TargetHighLevelOperandUsage}}, {HLIL_ASSIGN, {DestExprHighLevelOperandUsage, SourceExprHighLevelOperandUsage}}, {HLIL_ASSIGN_UNPACK, {DestExprsHighLevelOperandUsage, SourceExprHighLevelOperandUsage}}, + {HLIL_ASSIGN_MEM_SSA, {DestExprHighLevelOperandUsage, DestMemoryVersionHighLevelOperandUsage, + SourceExprHighLevelOperandUsage, SourceMemoryVersionHighLevelOperandUsage}}, + {HLIL_ASSIGN_UNPACK, {DestExprsHighLevelOperandUsage, DestMemoryVersionHighLevelOperandUsage, + SourceExprHighLevelOperandUsage, SourceMemoryVersionHighLevelOperandUsage}}, {HLIL_VAR, {VariableHighLevelOperandUsage}}, {HLIL_VAR_SSA, {SSAVariableHighLevelOperandUsage}}, {HLIL_VAR_PHI, {DestSSAVariableHighLevelOperandUsage, SourceSSAVariablesHighLevelOperandUsage}}, + {HLIL_MEM_PHI, {DestMemoryVersionHighLevelOperandUsage, SourceMemoryVersionsHighLevelOperandUsage}}, {HLIL_STRUCT_FIELD, {SourceExprHighLevelOperandUsage, OffsetHighLevelOperandUsage}}, {HLIL_ARRAY_INDEX, {SourceExprHighLevelOperandUsage, IndexExprHighLevelOperandUsage}}, + {HLIL_ARRAY_INDEX_SSA, {SourceExprHighLevelOperandUsage, SourceMemoryVersionHighLevelOperandUsage, + IndexExprHighLevelOperandUsage}}, {HLIL_SPLIT, {HighExprHighLevelOperandUsage, LowExprHighLevelOperandUsage}}, {HLIL_DEREF, {SourceExprHighLevelOperandUsage}}, {HLIL_DEREF_FIELD, {SourceExprHighLevelOperandUsage, OffsetHighLevelOperandUsage}}, + {HLIL_DEREF_SSA, {SourceExprHighLevelOperandUsage, SourceMemoryVersionHighLevelOperandUsage}}, + {HLIL_DEREF_FIELD_SSA, {SourceExprHighLevelOperandUsage, SourceMemoryVersionHighLevelOperandUsage, + OffsetHighLevelOperandUsage}}, {HLIL_ADDRESS_OF, {SourceExprHighLevelOperandUsage}}, {HLIL_CALL, {DestExprHighLevelOperandUsage, ParameterExprsHighLevelOperandUsage}}, {HLIL_SYSCALL, {ParameterExprsHighLevelOperandUsage}}, {HLIL_TAILCALL, {DestExprHighLevelOperandUsage, ParameterExprsHighLevelOperandUsage}}, {HLIL_INTRINSIC, {IntrinsicHighLevelOperandUsage, ParameterExprsHighLevelOperandUsage}}, + {HLIL_CALL_SSA, {DestExprHighLevelOperandUsage, ParameterExprsHighLevelOperandUsage, + DestMemoryVersionHighLevelOperandUsage, SourceMemoryVersionHighLevelOperandUsage}}, + {HLIL_SYSCALL_SSA, {ParameterExprsHighLevelOperandUsage, DestMemoryVersionHighLevelOperandUsage, + SourceMemoryVersionHighLevelOperandUsage}}, + {HLIL_INTRINSIC_SSA, {IntrinsicHighLevelOperandUsage, ParameterExprsHighLevelOperandUsage, + DestMemoryVersionHighLevelOperandUsage, SourceMemoryVersionHighLevelOperandUsage}}, {HLIL_TRAP, {VectorHighLevelOperandUsage}}, {HLIL_CONST, {ConstantHighLevelOperandUsage}}, {HLIL_CONST_PTR, {ConstantHighLevelOperandUsage}}, @@ -201,6 +220,7 @@ static unordered_map<BNHighLevelILOperation, unordered_map<HighLevelILOperandUsa case SSAVariableHighLevelOperand: case SSAVariableListHighLevelOperand: case ExprListHighLevelOperand: + case IndexListHighLevelOperand: // SSA variables and lists take two operand slots operand += 2; break; @@ -310,6 +330,60 @@ HighLevelILIntegerList::operator vector<uint64_t>() const } +size_t HighLevelILIndexList::ListIterator::operator*() +{ + return (size_t)*pos; +} + + +HighLevelILIndexList::HighLevelILIndexList(HighLevelILFunction* func, + const BNHighLevelILInstruction& instr, size_t count): m_list(func, instr, count) +{ +} + + +HighLevelILIndexList::const_iterator HighLevelILIndexList::begin() const +{ + const_iterator result; + result.pos = m_list.begin(); + return result; +} + + +HighLevelILIndexList::const_iterator HighLevelILIndexList::end() const +{ + const_iterator result; + result.pos = m_list.end(); + return result; +} + + +size_t HighLevelILIndexList::size() const +{ + return m_list.size(); +} + + +size_t HighLevelILIndexList::operator[](size_t i) const +{ + if (i >= size()) + throw HighLevelILInstructionAccessException(); + auto iter = begin(); + for (size_t j = 0; j < i; j++) + ++iter; + return *iter; +} + + +HighLevelILIndexList::operator vector<size_t>() const +{ + vector<size_t> result; + for (auto i : *this) + result.push_back(i); + return result; +} + + const HighLevelILInstruction HighLevelILInstructionList::ListIterator::operator*() { return HighLevelILInstruction(pos.GetFunction(), pos.GetFunction()->GetRawExpr((size_t)*pos), (size_t)*pos); @@ -497,6 +571,14 @@ HighLevelILSSAVariableList HighLevelILOperand::GetSSAVariableList() const } +HighLevelILIndexList HighLevelILOperand::GetIndexList() const +{ + if (m_type != IndexListHighLevelOperand) + throw HighLevelILInstructionAccessException(); + return m_instr.GetRawOperandAsIndexList(m_operandIndex); +} + + const HighLevelILOperand HighLevelILOperandList::ListIterator::operator*() { HighLevelILOperandUsage usage = *pos; @@ -659,6 +741,12 @@ HighLevelILSSAVariableList HighLevelILInstructionBase::GetRawOperandAsSSAVariabl } +HighLevelILIndexList HighLevelILInstructionBase::GetRawOperandAsIndexList(size_t operand) const +{ + return HighLevelILIndexList(function, function->GetRawExpr(operands[operand + 1]), operands[operand]); +} + + void HighLevelILInstructionBase::UpdateRawOperand(size_t operandIndex, ExprId value) { operands[operandIndex] = value; @@ -806,6 +894,16 @@ void HighLevelILInstruction::VisitExprs(const std::function<bool(const HighLevel for (auto i = exprs.rbegin(); i != exprs.rend(); ++i) toProcess.push(i->exprIndex); break; + case HLIL_ASSIGN_MEM_SSA: + toProcess.push(cur.GetSourceExpr<HLIL_ASSIGN_MEM_SSA>().exprIndex); + toProcess.push(cur.GetDestExpr<HLIL_ASSIGN_MEM_SSA>().exprIndex); + break; + case HLIL_ASSIGN_UNPACK_MEM_SSA: + toProcess.push(cur.GetSourceExpr<HLIL_ASSIGN_UNPACK_MEM_SSA>().exprIndex); + exprs = cur.GetDestExprs<HLIL_ASSIGN_UNPACK_MEM_SSA>(); + for (auto i = exprs.rbegin(); i != exprs.rend(); ++i) + toProcess.push(i->exprIndex); + break; case HLIL_STRUCT_FIELD: toProcess.push(cur.GetSourceExpr<HLIL_STRUCT_FIELD>().exprIndex); break; @@ -813,6 +911,10 @@ void HighLevelILInstruction::VisitExprs(const std::function<bool(const HighLevel toProcess.push(cur.GetIndexExpr<HLIL_ARRAY_INDEX>().exprIndex); toProcess.push(cur.GetSourceExpr<HLIL_ARRAY_INDEX>().exprIndex); break; + case HLIL_ARRAY_INDEX_SSA: + toProcess.push(cur.GetIndexExpr<HLIL_ARRAY_INDEX_SSA>().exprIndex); + toProcess.push(cur.GetSourceExpr<HLIL_ARRAY_INDEX_SSA>().exprIndex); + break; case HLIL_SPLIT: toProcess.push(cur.GetLowExpr<HLIL_SPLIT>().exprIndex); toProcess.push(cur.GetHighExpr<HLIL_SPLIT>().exprIndex); @@ -820,6 +922,12 @@ void HighLevelILInstruction::VisitExprs(const std::function<bool(const HighLevel case HLIL_DEREF_FIELD: toProcess.push(cur.GetSourceExpr<HLIL_DEREF_FIELD>().exprIndex); break; + case HLIL_DEREF_SSA: + toProcess.push(cur.GetSourceExpr<HLIL_DEREF_SSA>().exprIndex); + break; + case HLIL_DEREF_FIELD_SSA: + toProcess.push(cur.GetSourceExpr<HLIL_DEREF_FIELD_SSA>().exprIndex); + break; case HLIL_CALL: exprs = cur.GetParameterExprs<HLIL_CALL>(); for (auto i = exprs.rbegin(); i != exprs.rend(); ++i) @@ -837,6 +945,17 @@ void HighLevelILInstruction::VisitExprs(const std::function<bool(const HighLevel toProcess.push(i->exprIndex); toProcess.push(cur.GetDestExpr<HLIL_TAILCALL>().exprIndex); break; + case HLIL_CALL_SSA: + exprs = cur.GetParameterExprs<HLIL_CALL_SSA>(); + for (auto i = exprs.rbegin(); i != exprs.rend(); ++i) + toProcess.push(i->exprIndex); + toProcess.push(cur.GetDestExpr<HLIL_CALL_SSA>().exprIndex); + break; + case HLIL_SYSCALL_SSA: + exprs = cur.GetParameterExprs<HLIL_SYSCALL_SSA>(); + for (auto i = exprs.rbegin(); i != exprs.rend(); ++i) + toProcess.push(i->exprIndex); + break; case HLIL_RET: exprs = cur.GetSourceExprs<HLIL_RET>(); for (auto i = exprs.rbegin(); i != exprs.rend(); ++i) @@ -925,6 +1044,11 @@ void HighLevelILInstruction::VisitExprs(const std::function<bool(const HighLevel for (auto i = exprs.rbegin(); i != exprs.rend(); ++i) toProcess.push(i->exprIndex); break; + case HLIL_INTRINSIC_SSA: + exprs = cur.GetParameterExprs<HLIL_INTRINSIC_SSA>(); + for (auto i = exprs.rbegin(); i != exprs.rend(); ++i) + toProcess.push(i->exprIndex); + break; default: break; } @@ -985,18 +1109,34 @@ ExprId HighLevelILInstruction::CopyTo(HighLevelILFunction* dest, output.push_back(subExprHandler(i)); return dest->AssignUnpack(output, subExprHandler(GetSourceExpr<HLIL_ASSIGN_UNPACK>()), *this); + case HLIL_ASSIGN_MEM_SSA: + return dest->AssignMemSSA(size, subExprHandler(GetDestExpr<HLIL_ASSIGN_MEM_SSA>()), + GetDestMemoryVersion<HLIL_ASSIGN_MEM_SSA>(), subExprHandler(GetSourceExpr<HLIL_ASSIGN_MEM_SSA>()), + GetSourceMemoryVersion<HLIL_ASSIGN_MEM_SSA>(), *this); + case HLIL_ASSIGN_UNPACK_MEM_SSA: + for (auto& i : GetDestExprs<HLIL_ASSIGN_UNPACK_MEM_SSA>()) + output.push_back(subExprHandler(i)); + return dest->AssignUnpackMemSSA(output, GetDestMemoryVersion<HLIL_ASSIGN_UNPACK_MEM_SSA>(), + subExprHandler(GetSourceExpr<HLIL_ASSIGN_UNPACK_MEM_SSA>()), + GetSourceMemoryVersion<HLIL_ASSIGN_UNPACK_MEM_SSA>(), *this); case HLIL_VAR: return dest->Var(size, GetVariable<HLIL_VAR>(), *this); case HLIL_VAR_SSA: return dest->VarSSA(size, GetSSAVariable<HLIL_VAR_SSA>(), *this); case HLIL_VAR_PHI: return dest->VarPhi(GetDestSSAVariable<HLIL_VAR_PHI>(), GetSourceSSAVariables<HLIL_VAR_PHI>(), *this); + case HLIL_MEM_PHI: + return dest->MemPhi(GetDestMemoryVersion<HLIL_MEM_PHI>(), GetSourceMemoryVersions<HLIL_MEM_PHI>(), *this); case HLIL_STRUCT_FIELD: return dest->StructField(size, subExprHandler(GetSourceExpr<HLIL_STRUCT_FIELD>()), GetOffset<HLIL_STRUCT_FIELD>(), *this); case HLIL_ARRAY_INDEX: return dest->ArrayIndex(size, subExprHandler(GetSourceExpr<HLIL_ARRAY_INDEX>()), subExprHandler(GetIndexExpr<HLIL_ARRAY_INDEX>()), *this); + case HLIL_ARRAY_INDEX_SSA: + return dest->ArrayIndexSSA(size, subExprHandler(GetSourceExpr<HLIL_ARRAY_INDEX_SSA>()), + GetSourceMemoryVersion<HLIL_ARRAY_INDEX_SSA>(), + subExprHandler(GetIndexExpr<HLIL_ARRAY_INDEX_SSA>()), *this); case HLIL_SPLIT: return dest->Split(size, subExprHandler(GetHighExpr<HLIL_SPLIT>()), subExprHandler(GetLowExpr<HLIL_SPLIT>()), *this); @@ -1005,6 +1145,12 @@ ExprId HighLevelILInstruction::CopyTo(HighLevelILFunction* dest, case HLIL_DEREF_FIELD: return dest->DerefField(size, subExprHandler(GetSourceExpr<HLIL_DEREF_FIELD>()), GetOffset<HLIL_DEREF_FIELD>(), *this); + case HLIL_DEREF_SSA: + return dest->DerefSSA(size, subExprHandler(GetSourceExpr<HLIL_DEREF_SSA>()), + GetSourceMemoryVersion<HLIL_DEREF_SSA>(), *this); + case HLIL_DEREF_FIELD_SSA: + return dest->DerefFieldSSA(size, subExprHandler(GetSourceExpr<HLIL_DEREF_FIELD_SSA>()), + GetSourceMemoryVersion<HLIL_DEREF_FIELD_SSA>(), GetOffset<HLIL_DEREF_FIELD_SSA>(), *this); case HLIL_ADDRESS_OF: return dest->AddressOf(subExprHandler(GetSourceExpr<HLIL_ADDRESS_OF>()), *this); case HLIL_CALL: @@ -1019,6 +1165,16 @@ ExprId HighLevelILInstruction::CopyTo(HighLevelILFunction* dest, for (auto& i : GetParameterExprs<HLIL_TAILCALL>()) params.push_back(subExprHandler(i)); return dest->TailCall(subExprHandler(GetDestExpr<HLIL_TAILCALL>()), params, *this); + case HLIL_CALL_SSA: + for (auto& i : GetParameterExprs<HLIL_CALL_SSA>()) + params.push_back(subExprHandler(i)); + return dest->CallSSA(subExprHandler(GetDestExpr<HLIL_CALL_SSA>()), params, + GetDestMemoryVersion<HLIL_CALL_SSA>(), GetSourceMemoryVersion<HLIL_CALL_SSA>(), *this); + case HLIL_SYSCALL_SSA: + for (auto& i : GetParameterExprs<HLIL_SYSCALL_SSA>()) + params.push_back(subExprHandler(i)); + return dest->SyscallSSA(params, GetDestMemoryVersion<HLIL_SYSCALL_SSA>(), + GetSourceMemoryVersion<HLIL_SYSCALL_SSA>(), *this); case HLIL_RET: for (auto& i : GetSourceExprs<HLIL_RET>()) params.push_back(subExprHandler(i)); @@ -1118,6 +1274,11 @@ ExprId HighLevelILInstruction::CopyTo(HighLevelILFunction* dest, for (auto& i : GetParameterExprs<HLIL_INTRINSIC>()) params.push_back(subExprHandler(i)); return dest->Intrinsic(GetIntrinsic<HLIL_INTRINSIC>(), params, *this); + case HLIL_INTRINSIC_SSA: + for (auto& i : GetParameterExprs<HLIL_INTRINSIC_SSA>()) + params.push_back(subExprHandler(i)); + return dest->IntrinsicSSA(GetIntrinsic<HLIL_INTRINSIC_SSA>(), params, + GetDestMemoryVersion<HLIL_INTRINSIC_SSA>(), GetSourceMemoryVersion<HLIL_INTRINSIC_SSA>(), *this); case HLIL_UNDEF: return dest->Undefined(*this); case HLIL_UNIMPL: @@ -1402,6 +1563,33 @@ HighLevelILSSAVariableList HighLevelILInstruction::GetSourceSSAVariables() const } +size_t HighLevelILInstruction::GetSourceMemoryVersion() const +{ + size_t operandIndex; + if (GetOperandIndexForUsage(SourceMemoryVersionHighLevelOperandUsage, operandIndex)) + return GetRawOperandAsIndex(operandIndex); + throw HighLevelILInstructionAccessException(); +} + + +HighLevelILIndexList HighLevelILInstruction::GetSourceMemoryVersions() const +{ + size_t operandIndex; + if (GetOperandIndexForUsage(SourceMemoryVersionsHighLevelOperandUsage, operandIndex)) + return GetRawOperandAsIndexList(operandIndex); + throw HighLevelILInstructionAccessException(); +} + + +size_t HighLevelILInstruction::GetDestMemoryVersion() const +{ + size_t operandIndex; + if (GetOperandIndexForUsage(DestMemoryVersionHighLevelOperandUsage, operandIndex)) + return GetRawOperandAsIndex(operandIndex); + throw HighLevelILInstructionAccessException(); +} + + ExprId HighLevelILFunction::Nop(const ILSourceLocation& loc) { return AddExprWithLocation(HLIL_NOP, loc, 0); @@ -1509,6 +1697,21 @@ ExprId HighLevelILFunction::AssignUnpack(const vector<ExprId>& output, ExprId sr } +ExprId HighLevelILFunction::AssignMemSSA(size_t size, ExprId dest, size_t destMemVersion, ExprId src, + size_t srcMemVersion, const ILSourceLocation& loc) +{ + return AddExprWithLocation(HLIL_ASSIGN_MEM_SSA, loc, size, dest, destMemVersion, src, srcMemVersion); +} + + +ExprId HighLevelILFunction::AssignUnpackMemSSA(const vector<ExprId>& output, size_t destMemVersion, ExprId src, + size_t srcMemVersion, const ILSourceLocation& loc) +{ + return AddExprWithLocation(HLIL_ASSIGN_UNPACK_MEM_SSA, loc, 0, output.size(), AddOperandList(output), + destMemVersion, src, srcMemVersion); +} + + ExprId HighLevelILFunction::Var(size_t size, const Variable& src, const ILSourceLocation& loc) { @@ -1530,6 +1733,12 @@ ExprId HighLevelILFunction::VarPhi(const SSAVariable& dest, const vector<SSAVari } +ExprId HighLevelILFunction::MemPhi(size_t dest, const vector<size_t>& sources, const ILSourceLocation& loc) +{ + return AddExprWithLocation(HLIL_MEM_PHI, loc, 0, dest, sources.size(), AddIndexList(sources)); +} + + ExprId HighLevelILFunction::StructField(size_t size, ExprId src, uint64_t offset, const ILSourceLocation& loc) { return AddExprWithLocation(HLIL_STRUCT_FIELD, loc, size, src, offset); @@ -1544,7 +1753,14 @@ ExprId HighLevelILFunction::Split(size_t size, ExprId high, ExprId low, const IL ExprId HighLevelILFunction::ArrayIndex(size_t size, ExprId src, ExprId idx, const ILSourceLocation& loc) { - return AddExprWithLocation(HLIL_STRUCT_FIELD, loc, size, src, idx); + return AddExprWithLocation(HLIL_ARRAY_INDEX, loc, size, src, idx); +} + + +ExprId HighLevelILFunction::ArrayIndexSSA(size_t size, ExprId src, size_t srcMemVersion, ExprId idx, + const ILSourceLocation& loc) +{ + return AddExprWithLocation(HLIL_ARRAY_INDEX_SSA, loc, size, src, srcMemVersion, idx); } @@ -1560,6 +1776,19 @@ ExprId HighLevelILFunction::DerefField(size_t size, ExprId src, uint64_t offset, } +ExprId HighLevelILFunction::DerefSSA(size_t size, ExprId src, size_t srcMemVersion, const ILSourceLocation& loc) +{ + return AddExprWithLocation(HLIL_DEREF_SSA, loc, size, src, srcMemVersion); +} + + +ExprId HighLevelILFunction::DerefFieldSSA(size_t size, ExprId src, size_t srcMemVersion, + uint64_t offset, const ILSourceLocation& loc) +{ + return AddExprWithLocation(HLIL_DEREF_FIELD_SSA, loc, size, src, srcMemVersion, offset); +} + + ExprId HighLevelILFunction::AddressOf(ExprId src, const ILSourceLocation& loc) { return AddExprWithLocation(HLIL_ADDRESS_OF, loc, 0, src); @@ -1839,6 +2068,22 @@ ExprId HighLevelILFunction::TailCall(ExprId dest, const vector<ExprId>& params, } +ExprId HighLevelILFunction::CallSSA(ExprId dest, const vector<ExprId>& params, size_t destMemVersion, + size_t srcMemVersion, const ILSourceLocation& loc) +{ + return AddExprWithLocation(HLIL_CALL_SSA, loc, 0, dest, params.size(), AddOperandList(params), + destMemVersion, srcMemVersion); +} + + +ExprId HighLevelILFunction::SyscallSSA(const vector<ExprId>& params, size_t destMemVersion, + size_t srcMemVersion, const ILSourceLocation& loc) +{ + return AddExprWithLocation(HLIL_SYSCALL_SSA, loc, 0, params.size(), AddOperandList(params), + destMemVersion, srcMemVersion); +} + + ExprId HighLevelILFunction::CompareEqual(size_t size, ExprId left, ExprId right, const ILSourceLocation& loc) { @@ -1949,6 +2194,14 @@ ExprId HighLevelILFunction::Intrinsic(uint32_t intrinsic, const vector<ExprId>& } +ExprId HighLevelILFunction::IntrinsicSSA(uint32_t intrinsic, const vector<ExprId>& params, + size_t destMemVersion, size_t srcMemVersion, const ILSourceLocation& loc) +{ + return AddExprWithLocation(HLIL_INTRINSIC_SSA, loc, 0, intrinsic, + params.size(), AddOperandList(params), destMemVersion, srcMemVersion); +} + + ExprId HighLevelILFunction::Undefined(const ILSourceLocation& loc) { return AddExprWithLocation(HLIL_UNDEF, loc, 0); diff --git a/highlevelilinstruction.h b/highlevelilinstruction.h index faf287cc..9dc6a604 100644 --- a/highlevelilinstruction.h +++ b/highlevelilinstruction.h @@ -60,7 +60,8 @@ namespace BinaryNinja VariableHighLevelOperand, SSAVariableHighLevelOperand, ExprListHighLevelOperand, - SSAVariableListHighLevelOperand + SSAVariableListHighLevelOperand, + IndexListHighLevelOperand }; enum HighLevelILOperandUsage @@ -93,7 +94,10 @@ namespace BinaryNinja DestExprsHighLevelOperandUsage, BlockExprsHighLevelOperandUsage, CasesHighLevelOperandUsage, - SourceSSAVariablesHighLevelOperandUsage + SourceSSAVariablesHighLevelOperandUsage, + SourceMemoryVersionHighLevelOperandUsage, + SourceMemoryVersionsHighLevelOperandUsage, + DestMemoryVersionHighLevelOperandUsage }; } @@ -176,6 +180,33 @@ namespace BinaryNinja operator std::vector<uint64_t>() const; }; + class HighLevelILIndexList + { + struct ListIterator + { + HighLevelILIntegerList::const_iterator pos; + bool operator==(const ListIterator& a) const { return pos == a.pos; } + bool operator!=(const ListIterator& a) const { return pos != a.pos; } + bool operator<(const ListIterator& a) const { return pos < a.pos; } + ListIterator& operator++() { ++pos; return *this; } + size_t operator*(); + }; + + HighLevelILIntegerList m_list; + + public: + typedef ListIterator const_iterator; + + HighLevelILIndexList(HighLevelILFunction* func, const BNHighLevelILInstruction& instr, size_t count); + + const_iterator begin() const; + const_iterator end() const; + size_t size() const; + size_t operator[](size_t i) const; + + operator std::vector<size_t>() const; + }; + class HighLevelILInstructionList { struct ListIterator @@ -255,6 +286,7 @@ namespace BinaryNinja SSAVariable GetRawOperandAsSSAVariable(size_t operand) const; HighLevelILInstructionList GetRawOperandAsExprList(size_t operand) const; HighLevelILSSAVariableList GetRawOperandAsSSAVariableList(size_t operand) const; + HighLevelILIndexList GetRawOperandAsIndexList(size_t operand) const; void UpdateRawOperand(size_t operandIndex, ExprId value); void UpdateRawOperandAsSSAVariableList(size_t operandIndex, const std::vector<SSAVariable>& vars); @@ -358,6 +390,9 @@ namespace BinaryNinja template <BNHighLevelILOperation N> HighLevelILInstructionList GetBlockExprs() const { return As<N>().GetBlockExprs(); } template <BNHighLevelILOperation N> HighLevelILInstructionList GetCases() const { return As<N>().GetCases(); } template <BNHighLevelILOperation N> HighLevelILSSAVariableList GetSourceSSAVariables() const { return As<N>().GetSourceSSAVariables(); } + template <BNHighLevelILOperation N> size_t GetSourceMemoryVersion() const { return As<N>().GetSourceMemoryVersion(); } + template <BNHighLevelILOperation N> HighLevelILIndexList GetSourceMemoryVersions() const { return As<N>().GetSourceMemoryVersions(); } + template <BNHighLevelILOperation N> size_t GetDestMemoryVersion() const { return As<N>().GetDestMemoryVersion(); } template <BNHighLevelILOperation N> void SetSSAVersion(size_t version) { As<N>().SetSSAVersion(version); } template <BNHighLevelILOperation N> void SetParameterExprs(const std::vector<MediumLevelILInstruction>& params) { As<N>().SetParameterExprs(params); } @@ -371,6 +406,8 @@ namespace BinaryNinja template <BNHighLevelILOperation N> void SetCases(const std::vector<MediumLevelILInstruction>& params) { As<N>().SetCases(params); } template <BNHighLevelILOperation N> void SetCases(const std::vector<ExprId>& params) { As<N>().SetCases(params); } template <BNHighLevelILOperation N> void SetSourceSSAVariables(const std::vector<SSAVariable>& vars) { As<N>().SetSourceSSAVariables(vars); } + template <BNHighLevelILOperation N> void SetSourceMemoryVersion(size_t version) { return As<N>().SetSourceMemoryVersion(version); } + template <BNHighLevelILOperation N> void SetDestMemoryVersion(size_t version) { return As<N>().SetDestMemoryVersion(version); } bool GetOperandIndexForUsage(HighLevelILOperandUsage usage, size_t& operandIndex) const; @@ -405,6 +442,9 @@ namespace BinaryNinja HighLevelILInstructionList GetBlockExprs() const; HighLevelILInstructionList GetCases() const; HighLevelILSSAVariableList GetSourceSSAVariables() const; + size_t GetSourceMemoryVersion() const; + HighLevelILIndexList GetSourceMemoryVersions() const; + size_t GetDestMemoryVersion() const; }; class HighLevelILOperand @@ -429,6 +469,7 @@ namespace BinaryNinja SSAVariable GetSSAVariable() const; HighLevelILInstructionList GetExprList() const; HighLevelILSSAVariableList GetSSAVariableList() const; + HighLevelILIndexList GetIndexList() const; }; class HighLevelILOperandList @@ -547,6 +588,29 @@ namespace BinaryNinja HighLevelILInstruction GetDestExpr() const { return GetRawOperandAsExpr(0); } HighLevelILInstruction GetSourceExpr() const { return GetRawOperandAsExpr(1); } }; + template <> struct HighLevelILInstructionAccessor<HLIL_ASSIGN_UNPACK>: public HighLevelILInstructionBase + { + HighLevelILInstructionList GetDestExprs() const { return GetRawOperandAsExprList(0); } + HighLevelILInstruction GetSourceExpr() const { return GetRawOperandAsExpr(2); } + }; + template <> struct HighLevelILInstructionAccessor<HLIL_ASSIGN_MEM_SSA>: public HighLevelILInstructionBase + { + HighLevelILInstruction GetDestExpr() const { return GetRawOperandAsExpr(0); } + size_t GetDestMemoryVersion() const { return GetRawOperandAsIndex(1); } + void SetDestMemoryVersion(size_t version) { UpdateRawOperand(1, version); } + HighLevelILInstruction GetSourceExpr() const { return GetRawOperandAsExpr(2); } + size_t GetSourceMemoryVersion() const { return GetRawOperandAsIndex(3); } + void SetSourceMemoryVersion(size_t version) { UpdateRawOperand(3, version); } + }; + template <> struct HighLevelILInstructionAccessor<HLIL_ASSIGN_UNPACK_MEM_SSA>: public HighLevelILInstructionBase + { + HighLevelILInstructionList GetDestExprs() const { return GetRawOperandAsExprList(0); } + size_t GetDestMemoryVersion() const { return GetRawOperandAsIndex(2); } + void SetDestMemoryVersion(size_t version) { UpdateRawOperand(2, version); } + HighLevelILInstruction GetSourceExpr() const { return GetRawOperandAsExpr(3); } + size_t GetSourceMemoryVersion() const { return GetRawOperandAsIndex(4); } + void SetSourceMemoryVersion(size_t version) { UpdateRawOperand(4, version); } + }; template <> struct HighLevelILInstructionAccessor<HLIL_STRUCT_FIELD>: public HighLevelILInstructionBase { @@ -558,11 +622,31 @@ namespace BinaryNinja HighLevelILInstruction GetSourceExpr() const { return GetRawOperandAsExpr(0); } uint64_t GetOffset() const { return GetRawOperandAsInteger(1); } }; + template <> struct HighLevelILInstructionAccessor<HLIL_DEREF_SSA>: public HighLevelILInstructionBase + { + HighLevelILInstruction GetSourceExpr() const { return GetRawOperandAsExpr(0); } + size_t GetSourceMemoryVersion() const { return GetRawOperandAsIndex(1); } + void SetSourceMemoryVersion(size_t version) { UpdateRawOperand(1, version); } + }; + template <> struct HighLevelILInstructionAccessor<HLIL_DEREF_FIELD_SSA>: public HighLevelILInstructionBase + { + HighLevelILInstruction GetSourceExpr() const { return GetRawOperandAsExpr(0); } + size_t GetSourceMemoryVersion() const { return GetRawOperandAsIndex(1); } + void SetSourceMemoryVersion(size_t version) { UpdateRawOperand(1, version); } + uint64_t GetOffset() const { return GetRawOperandAsInteger(2); } + }; template <> struct HighLevelILInstructionAccessor<HLIL_ARRAY_INDEX>: public HighLevelILInstructionBase { HighLevelILInstruction GetSourceExpr() const { return GetRawOperandAsExpr(0); } HighLevelILInstruction GetIndexExpr() const { return GetRawOperandAsExpr(1); } }; + template <> struct HighLevelILInstructionAccessor<HLIL_ARRAY_INDEX_SSA>: public HighLevelILInstructionBase + { + HighLevelILInstruction GetSourceExpr() const { return GetRawOperandAsExpr(0); } + size_t GetSourceMemoryVersion() const { return GetRawOperandAsIndex(1); } + void SetSourceMemoryVersion(size_t version) { UpdateRawOperand(1, version); } + HighLevelILInstruction GetIndexExpr() const { return GetRawOperandAsExpr(2); } + }; template <> struct HighLevelILInstructionAccessor<HLIL_SPLIT>: public HighLevelILInstructionBase { HighLevelILInstruction GetHighExpr() const { return GetRawOperandAsExpr(0); } @@ -584,6 +668,12 @@ namespace BinaryNinja HighLevelILSSAVariableList GetSourceSSAVariables() const { return GetRawOperandAsSSAVariableList(2); } void SetSourceSSAVariables(const std::vector<SSAVariable>& vars) { UpdateRawOperandAsSSAVariableList(2, vars); } }; + template <> struct HighLevelILInstructionAccessor<HLIL_MEM_PHI>: public HighLevelILInstructionBase + { + size_t GetDestMemoryVersion() const { return GetRawOperandAsIndex(0); } + void SetDestMemoryVersion(size_t version) { UpdateRawOperand(0, version); } + HighLevelILIndexList GetSourceMemoryVersions() const { return GetRawOperandAsIndexList(1); } + }; template <> struct HighLevelILInstructionAccessor<HLIL_JUMP>: public HighLevelILInstructionBase { @@ -604,17 +694,37 @@ namespace BinaryNinja HighLevelILInstruction GetDestExpr() const { return GetRawOperandAsExpr(0); } HighLevelILInstructionList GetParameterExprs() const { return GetRawOperandAsExprList(1); } }; - - template <> struct HighLevelILInstructionAccessor<HLIL_ASSIGN_UNPACK>: public HighLevelILInstructionBase + template <> struct HighLevelILInstructionAccessor<HLIL_CALL_SSA>: public HighLevelILInstructionBase { - HighLevelILInstructionList GetDestExprs() const { return GetRawOperandAsExprList(0); } - HighLevelILInstruction GetSourceExpr() const { return GetRawOperandAsExpr(2); } + HighLevelILInstruction GetDestExpr() const { return GetRawOperandAsExpr(0); } + HighLevelILInstructionList GetParameterExprs() const { return GetRawOperandAsExprList(1); } + size_t GetDestMemoryVersion() const { return GetRawOperandAsIndex(3); } + void SetDestMemoryVersion(size_t version) { UpdateRawOperand(3, version); } + size_t GetSourceMemoryVersion() const { return GetRawOperandAsIndex(4); } + void SetSourceMemoryVersion(size_t version) { UpdateRawOperand(4, version); } + }; + template <> struct HighLevelILInstructionAccessor<HLIL_SYSCALL_SSA>: public HighLevelILInstructionBase + { + HighLevelILInstructionList GetParameterExprs() const { return GetRawOperandAsExprList(0); } + size_t GetDestMemoryVersion() const { return GetRawOperandAsIndex(2); } + void SetDestMemoryVersion(size_t version) { UpdateRawOperand(2, version); } + size_t GetSourceMemoryVersion() const { return GetRawOperandAsIndex(3); } + void SetSourceMemoryVersion(size_t version) { UpdateRawOperand(3, version); } }; template <> struct HighLevelILInstructionAccessor<HLIL_INTRINSIC>: public HighLevelILInstructionBase { - uint32_t GetIntrinsic() const { return (uint32_t)GetRawOperandAsInteger(2); } - HighLevelILInstructionList GetParameterExprs() const { return GetRawOperandAsExprList(3); } + uint32_t GetIntrinsic() const { return (uint32_t)GetRawOperandAsInteger(0); } + HighLevelILInstructionList GetParameterExprs() const { return GetRawOperandAsExprList(1); } + }; + template <> struct HighLevelILInstructionAccessor<HLIL_INTRINSIC_SSA>: public HighLevelILInstructionBase + { + uint32_t GetIntrinsic() const { return (uint32_t)GetRawOperandAsInteger(0); } + HighLevelILInstructionList GetParameterExprs() const { return GetRawOperandAsExprList(1); } + size_t GetDestMemoryVersion() const { return GetRawOperandAsIndex(3); } + void SetDestMemoryVersion(size_t version) { UpdateRawOperand(3, version); } + size_t GetSourceMemoryVersion() const { return GetRawOperandAsIndex(4); } + void SetSourceMemoryVersion(size_t version) { UpdateRawOperand(4, version); } }; template <> struct HighLevelILInstructionAccessor<HLIL_TRAP>: public HighLevelILInstructionBase diff --git a/python/highlevelil.py b/python/highlevelil.py index 46fbe972..a5d0b661 100644 --- a/python/highlevelil.py +++ b/python/highlevelil.py @@ -95,14 +95,20 @@ class HighLevelILInstruction(object): HighLevelILOperation.HLIL_LABEL: [("target", "int")], HighLevelILOperation.HLIL_ASSIGN: [("dest", "expr"), ("src", "expr")], HighLevelILOperation.HLIL_ASSIGN_UNPACK: [("dest", "expr_list"), ("src", "expr")], + HighLevelILOperation.HLIL_ASSIGN_MEM_SSA: [("dest", "expr"), ("dest_memory", "int"), ("src", "expr"), ("src_memory", "int")], + HighLevelILOperation.HLIL_ASSIGN_UNPACK_MEM_SSA: [("dest", "expr_list"), ("dest_memory", "int"), ("src", "expr"), ("src_memory", "int")], HighLevelILOperation.HLIL_VAR: [("var", "var")], HighLevelILOperation.HLIL_VAR_SSA: [("var", "var_ssa")], HighLevelILOperation.HLIL_VAR_PHI: [("dest", "var_ssa"), ("src", "var_ssa_list")], + HighLevelILOperation.HLIL_MEM_PHI: [("dest", "int"), ("src", "int_list")], HighLevelILOperation.HLIL_STRUCT_FIELD: [("src", "expr"), ("offset", "int")], HighLevelILOperation.HLIL_ARRAY_INDEX: [("src", "expr"), ("index", "expr")], + HighLevelILOperation.HLIL_ARRAY_INDEX_SSA: [("src", "expr"), ("src_memory", "int"), ("index", "expr")], HighLevelILOperation.HLIL_SPLIT: [("high", "expr"), ("low", "expr")], HighLevelILOperation.HLIL_DEREF: [("src", "expr")], HighLevelILOperation.HLIL_DEREF_FIELD: [("src", "expr"), ("offset", "int")], + HighLevelILOperation.HLIL_DEREF_SSA: [("src", "expr"), ("src_memory", "int")], + HighLevelILOperation.HLIL_DEREF_FIELD_SSA: [("src", "expr"), ("src_memory", "int"), ("offset", "int")], HighLevelILOperation.HLIL_ADDRESS_OF: [("src", "expr")], HighLevelILOperation.HLIL_CONST: [("constant", "int")], HighLevelILOperation.HLIL_CONST_PTR: [("constant", "int")], @@ -140,6 +146,7 @@ class HighLevelILInstruction(object): HighLevelILOperation.HLIL_ZX: [("src", "expr")], HighLevelILOperation.HLIL_LOW_PART: [("src", "expr")], HighLevelILOperation.HLIL_CALL: [("dest", "expr"), ("params", "expr_list")], + HighLevelILOperation.HLIL_CALL_SSA: [("dest", "expr"), ("params", "expr_list"), ("dest_memory", "int"), ("src_memory", "int")], HighLevelILOperation.HLIL_CMP_E: [("left", "expr"), ("right", "expr")], HighLevelILOperation.HLIL_CMP_NE: [("left", "expr"), ("right", "expr")], HighLevelILOperation.HLIL_CMP_SLT: [("left", "expr"), ("right", "expr")], @@ -154,10 +161,12 @@ class HighLevelILInstruction(object): HighLevelILOperation.HLIL_BOOL_TO_INT: [("src", "expr")], HighLevelILOperation.HLIL_ADD_OVERFLOW: [("left", "expr"), ("right", "expr")], HighLevelILOperation.HLIL_SYSCALL: [("params", "expr_list")], + HighLevelILOperation.HLIL_SYSCALL_SSA: [("params", "expr_list"), ("dest_memory", "int"), ("src_memory", "int")], HighLevelILOperation.HLIL_TAILCALL: [("dest", "expr"), ("params", "expr_list")], HighLevelILOperation.HLIL_BP: [], HighLevelILOperation.HLIL_TRAP: [("vector", "int")], HighLevelILOperation.HLIL_INTRINSIC: [("intrinsic", "intrinsic"), ("params", "expr_list")], + HighLevelILOperation.HLIL_INTRINSIC_SSA: [("intrinsic", "intrinsic"), ("params", "expr_list"), ("dest_memory", "int"), ("src_memory", "int")], HighLevelILOperation.HLIL_UNDEF: [], HighLevelILOperation.HLIL_UNIMPL: [], HighLevelILOperation.HLIL_UNIMPL_MEM: [("src", "expr")], |
