Skip to content

Commit

Permalink
Add support for memory intrinsics.
Browse files Browse the repository at this point in the history
  • Loading branch information
bpotchik committed Mar 2, 2024
1 parent ff2aa74 commit 2e3b9c9
Show file tree
Hide file tree
Showing 13 changed files with 319 additions and 27 deletions.
26 changes: 26 additions & 0 deletions architecture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,13 @@ void Architecture::GetRegisterStackInfoCallback(void* ctxt, uint32_t regStack, B
}


BNIntrinsicClass Architecture::GetIntrinsicClassCallback(void* ctxt, uint32_t intrinsic)
{
CallbackRef<Architecture> arch(ctxt);
return arch->GetIntrinsicClass(intrinsic);
}


char* Architecture::GetIntrinsicNameCallback(void* ctxt, uint32_t intrinsic)
{
CallbackRef<Architecture> arch(ctxt);
Expand Down Expand Up @@ -803,6 +810,7 @@ void Architecture::Register(Architecture* arch)
callbacks.getRegisterStackName = GetRegisterStackNameCallback;
callbacks.getAllRegisterStacks = GetAllRegisterStacksCallback;
callbacks.getRegisterStackInfo = GetRegisterStackInfoCallback;
callbacks.getIntrinsicClass = GetIntrinsicClassCallback;
callbacks.getIntrinsicName = GetIntrinsicNameCallback;
callbacks.getAllIntrinsics = GetAllIntrinsicsCallback;
callbacks.getIntrinsicInputs = GetIntrinsicInputsCallback;
Expand Down Expand Up @@ -1118,6 +1126,12 @@ uint32_t Architecture::GetRegisterStackForRegister(uint32_t reg)
}


BNIntrinsicClass Architecture::GetIntrinsicClass(uint32_t intrinsic)
{
return GeneralIntrinsicClass;
}


string Architecture::GetIntrinsicName(uint32_t intrinsic)
{
return fmt::format("intrinsic_{}", intrinsic);
Expand Down Expand Up @@ -1756,6 +1770,12 @@ BNRegisterStackInfo CoreArchitecture::GetRegisterStackInfo(uint32_t regStack)
}


BNIntrinsicClass CoreArchitecture::GetIntrinsicClass(uint32_t intrinsic)
{
return BNGetArchitectureIntrinsicClass(m_object, intrinsic);
}


string CoreArchitecture::GetIntrinsicName(uint32_t intrinsic)
{
char* name = BNGetArchitectureIntrinsicName(m_object, intrinsic);
Expand Down Expand Up @@ -2129,6 +2149,12 @@ BNRegisterStackInfo ArchitectureExtension::GetRegisterStackInfo(uint32_t regStac
}


BNIntrinsicClass ArchitectureExtension::GetIntrinsicClass(uint32_t intrinsic)
{
return m_base->GetIntrinsicClass(intrinsic);
}


string ArchitectureExtension::GetIntrinsicName(uint32_t intrinsic)
{
return m_base->GetIntrinsicName(intrinsic);
Expand Down
13 changes: 8 additions & 5 deletions binaryninjaapi.h
Original file line number Diff line number Diff line change
Expand Up @@ -7491,6 +7491,7 @@ namespace BinaryNinja {
static uint32_t* GetAllRegisterStacksCallback(void* ctxt, size_t* count);
static void GetRegisterStackInfoCallback(void* ctxt, uint32_t regStack, BNRegisterStackInfo* result);

static BNIntrinsicClass GetIntrinsicClassCallback(void* ctxt, uint32_t intrinsic);
static char* GetIntrinsicNameCallback(void* ctxt, uint32_t intrinsic);
static uint32_t* GetAllIntrinsicsCallback(void* ctxt, size_t* count);
static BNNameAndType* GetIntrinsicInputsCallback(void* ctxt, uint32_t intrinsic, size_t* count);
Expand Down Expand Up @@ -7774,11 +7775,7 @@ namespace BinaryNinja {
virtual BNRegisterStackInfo GetRegisterStackInfo(uint32_t regStack);
uint32_t GetRegisterStackForRegister(uint32_t reg);

/*! Gets an intrinsic name from an intrinsic number.

\param intrinsic Intrinsic number
\return The corresponding intrinsic string
*/
virtual BNIntrinsicClass GetIntrinsicClass(uint32_t intrinsic);
virtual std::string GetIntrinsicName(uint32_t intrinsic);
virtual std::vector<uint32_t> GetAllIntrinsics();
virtual std::vector<NameAndType> GetIntrinsicInputs(uint32_t intrinsic);
Expand Down Expand Up @@ -8058,6 +8055,7 @@ namespace BinaryNinja {
virtual std::vector<uint32_t> GetAllRegisterStacks() override;
virtual BNRegisterStackInfo GetRegisterStackInfo(uint32_t regStack) override;

virtual BNIntrinsicClass GetIntrinsicClass(uint32_t intrinsic) override;
virtual std::string GetIntrinsicName(uint32_t intrinsic) override;
virtual std::vector<uint32_t> GetAllIntrinsics() override;
virtual std::vector<NameAndType> GetIntrinsicInputs(uint32_t intrinsic) override;
Expand Down Expand Up @@ -8141,6 +8139,7 @@ namespace BinaryNinja {
virtual std::vector<uint32_t> GetAllRegisterStacks() override;
virtual BNRegisterStackInfo GetRegisterStackInfo(uint32_t regStack) override;

virtual BNIntrinsicClass GetIntrinsicClass(uint32_t intrinsic) override;
virtual std::string GetIntrinsicName(uint32_t intrinsic) override;
virtual std::vector<uint32_t> GetAllIntrinsics() override;
virtual std::vector<NameAndType> GetIntrinsicInputs(uint32_t intrinsic) override;
Expand Down Expand Up @@ -11999,6 +11998,8 @@ namespace BinaryNinja {
const std::vector<ExprId>& params, uint32_t flags = 0, const ILSourceLocation& loc = ILSourceLocation());
ExprId IntrinsicSSA(const std::vector<SSARegisterOrFlag>& outputs, uint32_t intrinsic,
const std::vector<ExprId>& params, const ILSourceLocation& loc = ILSourceLocation());
ExprId MemoryIntrinsicSSA(const std::vector<SSARegisterOrFlag>& outputs, uint32_t intrinsic,
const std::vector<ExprId>& params, size_t newMemVersion, size_t prevMemVersion, const ILSourceLocation& loc = ILSourceLocation());

/*! Returns a processor breakpoint expression.

Expand Down Expand Up @@ -12649,6 +12650,8 @@ namespace BinaryNinja {
const ILSourceLocation& loc = ILSourceLocation());
ExprId IntrinsicSSA(const std::vector<SSAVariable>& outputs, uint32_t intrinsic,
const std::vector<ExprId>& params, const ILSourceLocation& loc = ILSourceLocation());
ExprId MemoryIntrinsicSSA(const std::vector<SSAVariable>& outputs, uint32_t intrinsic,
const std::vector<ExprId>& params, size_t newMemVersion, size_t prevMemVersion, const ILSourceLocation& loc = ILSourceLocation());
ExprId FreeVarSlot(const Variable& var, const ILSourceLocation& loc = ILSourceLocation());
ExprId FreeVarSlotSSA(const Variable& var, size_t newVersion, size_t prevVersion,
const ILSourceLocation& loc = ILSourceLocation());
Expand Down
23 changes: 17 additions & 6 deletions binaryninjacore.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,14 @@
// Current ABI version for linking to the core. This is incremented any time
// there are changes to the API that affect linking, including new functions,
// new types, or modifications to existing functions or types.
#define BN_CURRENT_CORE_ABI_VERSION 54
#define BN_CURRENT_CORE_ABI_VERSION 55

// Minimum ABI version that is supported for loading of plugins. Plugins that
// are linked to an ABI version less than this will not be able to load and
// will require rebuilding. The minimum version is increased when there are
// incompatible changes that break binary compatibility, such as changes to
// existing types or functions.
#define BN_MINIMUM_CORE_ABI_VERSION 53
#define BN_MINIMUM_CORE_ABI_VERSION 55

#ifdef __GNUC__
#ifdef BINARYNINJACORE_LIBRARY
Expand Down Expand Up @@ -599,15 +599,16 @@ extern "C"
LLIL_SYSCALL_SSA,
LLIL_TAILCALL_SSA,
LLIL_CALL_PARAM, // Only valid within the LLIL_CALL_SSA, LLIL_SYSCALL_SSA, LLIL_INTRINSIC, LLIL_INTRINSIC_SSA,
// LLIL_TAILCALL, LLIL_TAILCALL_SSA instructions
// LLIL_MEMORY_INTRINSIC_SSA, LLIL_TAILCALL, LLIL_TAILCALL_SSA instructions
LLIL_CALL_STACK_SSA, // Only valid within the LLIL_CALL_SSA or LLIL_SYSCALL_SSA instructions
LLIL_CALL_OUTPUT_SSA, // Only valid within the LLIL_CALL_SSA or LLIL_SYSCALL_SSA instructions
LLIL_SEPARATE_PARAM_LIST_SSA, // Only valid within the LLIL_CALL_PARAM instruction
LLIL_SHARED_PARAM_SLOT_SSA, // Only valid within the LLIL_CALL_PARAM or LLIL_SEPARATE_PARAM_LIST_SSA
// instructions
LLIL_SHARED_PARAM_SLOT_SSA, // Only valid within the LLIL_CALL_PARAM or LLIL_SEPARATE_PARAM_LIST_SSA instructions
LLIL_MEMORY_INTRINSIC_OUTPUT_SSA, // Only valid within the LLIL_MEMORY_INTRINSIC_SSA instruction
LLIL_LOAD_SSA,
LLIL_STORE_SSA,
LLIL_INTRINSIC_SSA,
LLIL_MEMORY_INTRINSIC_SSA,
LLIL_REG_PHI,
LLIL_REG_STACK_PHI,
LLIL_FLAG_PHI,
Expand Down Expand Up @@ -933,6 +934,12 @@ extern "C"
ILPreventAliasAnalysis = 0x20
} BNILInstructionAttribute;

typedef enum BNIntrinsicClass
{
GeneralIntrinsicClass,
MemoryIntrinsicClass
} BNIntrinsicClass;

typedef struct BNLowLevelILInstruction
{
BNLowLevelILOperation operation;
Expand Down Expand Up @@ -1241,15 +1248,17 @@ extern "C"
MLIL_SYSCALL_UNTYPED_SSA,
MLIL_TAILCALL_SSA,
MLIL_TAILCALL_UNTYPED_SSA,
MLIL_CALL_PARAM_SSA, // Only valid within the MLIL_CALL_SSA, MLIL_SYSCALL_SSA, MLIL_TAILCALL_SSA family
MLIL_CALL_PARAM_SSA, // Only valid within the MLIL_CALL_SSA, MLIL_SYSCALL_SSA, MLIL_TAILCALL_SSA, MLIL_INTRINSIC_SSA family
// instructions
MLIL_CALL_OUTPUT_SSA, // Only valid within the MLIL_CALL_SSA or MLIL_SYSCALL_SSA, MLIL_TAILCALL_SSA family
// instructions
MLIL_MEMORY_INTRINSIC_OUTPUT_SSA, // Only valid within the MLIL_MEMORY_INTRINSIC_SSA instruction
MLIL_LOAD_SSA,
MLIL_LOAD_STRUCT_SSA,
MLIL_STORE_SSA,
MLIL_STORE_STRUCT_SSA,
MLIL_INTRINSIC_SSA,
MLIL_MEMORY_INTRINSIC_SSA,
MLIL_FREE_VAR_SLOT_SSA,
MLIL_VAR_PHI,
MLIL_MEM_PHI
Expand Down Expand Up @@ -1787,6 +1796,7 @@ extern "C"
uint32_t* (*getAllRegisterStacks)(void* ctxt, size_t* count);
void (*getRegisterStackInfo)(void* ctxt, uint32_t regStack, BNRegisterStackInfo* result);

BNIntrinsicClass (*getIntrinsicClass)(void* ctxt, uint32_t intrinsic);
char* (*getIntrinsicName)(void* ctxt, uint32_t intrinsic);
uint32_t* (*getAllIntrinsics)(void* ctxt, size_t* count);
BNNameAndType* (*getIntrinsicInputs)(void* ctxt, uint32_t intrinsic, size_t* count);
Expand Down Expand Up @@ -3975,6 +3985,7 @@ extern "C"
BINARYNINJACOREAPI BNRegisterStackInfo BNGetArchitectureRegisterStackInfo(BNArchitecture* arch, uint32_t regStack);
BINARYNINJACOREAPI uint32_t BNGetArchitectureRegisterStackForRegister(BNArchitecture* arch, uint32_t reg);

BINARYNINJACOREAPI BNIntrinsicClass BNGetArchitectureIntrinsicClass(BNArchitecture* arch, uint32_t intrinsic);
BINARYNINJACOREAPI char* BNGetArchitectureIntrinsicName(BNArchitecture* arch, uint32_t intrinsic);
BINARYNINJACOREAPI uint32_t* BNGetAllArchitectureIntrinsics(BNArchitecture* arch, size_t* count);
BINARYNINJACOREAPI BNNameAndType* BNGetArchitectureIntrinsicInputs(
Expand Down
19 changes: 10 additions & 9 deletions docs/dev/bnil-llil.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ Now with some knowledge of the `LowLevelIL` class let's try to do something with

Going into gross detail on all the instructions is out of scope of this article, but we'll go over the different instructions types and speak generally about how they are used.


### Registers, Constants & Flags

When parsing an instruction tree the terminals are registers, constants and flags. This provide the basis from which all instructions are built.
Expand Down Expand Up @@ -267,7 +267,7 @@ The double precision instruction multiply, divide, modulus instructions are part
* `LLIL_FABS` - Floating point absolute value
* `LLIL_FLOAT_TO_INT` - Floating point convert a floating point to an integer
* `LLIL_INT_TO_FLOAT` - Floating point convert an integer to a floating point
* `LLIL_FLOAT_CONV` -
* `LLIL_FLOAT_CONV` -
* `LLIL_ROUND_TO_INT` - Rounds to the nearest integer
* `LLIL_FLOOR` - Returns the floor of a floating point value
* `LLIL_CEILING` - Returns the ceiling of a floating point value
Expand All @@ -294,6 +294,7 @@ The rest of the instructions are pretty much self-explanatory to anyone with fam
* `LLIL_EXTERN_PTR` - A synthesized (fake) pointer to something which doesn't exist within the memory space of the current binary
* `LLIL_INTRINSIC ` - Intrinsics are operations with `output` and `params` and an `intrinsic` where the exact behavior is not modelled but the dataflow system can be improved by annotating the inputs and outputs. An example intrinsic would CPU AES instructions where the exact behavior is not modelled, but the inputs and outputs are.
* `LLIL_INTRINSIC_SSA ` - SSA form of the `LLIL_INTRINSIC` operation
* `LLIL_MEMORY_INTRINSIC_SSA ` - Memory versioning SSA form of the `LLIL_INTRINSIC` operation
* `LLIL_NOP` - No operation
* `LLIL_SX` - Sign extend
* `LLIL_TRAP` - Trap instruction
Expand All @@ -306,10 +307,10 @@ The rest of the instructions are pretty much self-explanatory to anyone with fam

### Currently Undocumented

* `LLIL_FLAG ` -
* `LLIL_FLAG_BIT ` -
* `LLIL_FLAG_GROUP ` -
* `LLIL_FLAG_BIT_SSA ` -
* `LLIL_FLAG_PHI ` -
* `LLIL_FLAG_SSA ` -
* `LLIL_TAILCALL_SSA ` -
* `LLIL_FLAG ` -
* `LLIL_FLAG_BIT ` -
* `LLIL_FLAG_GROUP ` -
* `LLIL_FLAG_BIT_SSA ` -
* `LLIL_FLAG_PHI ` -
* `LLIL_FLAG_SSA ` -
* `LLIL_TAILCALL_SSA ` -
26 changes: 26 additions & 0 deletions lowlevelilinstruction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ unordered_map<LowLevelILOperandUsage, LowLevelILOperandType> LowLevelILInstructi
{SourceSSAFlagsLowLevelOperandUsage, SSAFlagListLowLevelOperand},
{OutputRegisterOrFlagListLowLevelOperandUsage, RegisterOrFlagListLowLevelOperand},
{OutputSSARegisterOrFlagListLowLevelOperandUsage, SSARegisterOrFlagListLowLevelOperand},
{OutputMemoryIntrinsicLowLevelOperandUsage, SSARegisterOrFlagListLowLevelOperand},
{SourceMemoryVersionsLowLevelOperandUsage, IndexListLowLevelOperand},
{TargetsLowLevelOperandUsage, IndexMapLowLevelOperand},
{RegisterStackAdjustmentsLowLevelOperandUsage, RegisterStackAdjustmentsLowLevelOperand}};
Expand Down Expand Up @@ -203,6 +204,8 @@ unordered_map<BNLowLevelILOperation, vector<LowLevelILOperandUsage>> LowLevelILI
ParameterExprsLowLevelOperandUsage}},
{LLIL_INTRINSIC_SSA, {OutputSSARegisterOrFlagListLowLevelOperandUsage, IntrinsicLowLevelOperandUsage,
ParameterExprsLowLevelOperandUsage}},
{LLIL_MEMORY_INTRINSIC_SSA, {OutputMemoryIntrinsicLowLevelOperandUsage, OutputMemoryVersionLowLevelOperandUsage, IntrinsicLowLevelOperandUsage,
ParameterExprsLowLevelOperandUsage, SourceMemoryVersionLowLevelOperandUsage}},
{LLIL_UNIMPL_MEM, {SourceExprLowLevelOperandUsage}},
{LLIL_FADD, {LeftExprLowLevelOperandUsage, RightExprLowLevelOperandUsage}},
{LLIL_FSUB, {LeftExprLowLevelOperandUsage, RightExprLowLevelOperandUsage}},
Expand Down Expand Up @@ -267,6 +270,9 @@ static unordered_map<BNLowLevelILOperation, unordered_map<LowLevelILOperandUsage
case DestSSARegisterStackLowLevelOperandUsage:
// PartialSSARegisterStackSourceLowLevelOperandUsage follows at same operand
break;
case OutputMemoryIntrinsicLowLevelOperandUsage:
// OutputMemoryVersionLowLevelOperandUsage follows at same operand
break;
default:
switch (LowLevelILInstructionBase::operandTypeForUsage[usage])
{
Expand Down Expand Up @@ -2020,6 +2026,10 @@ void LowLevelILInstruction::VisitExprs(const std::function<bool(const LowLevelIL
for (auto i : GetParameterExprs<LLIL_INTRINSIC_SSA>())
i.VisitExprs(func);
break;
case LLIL_MEMORY_INTRINSIC_SSA:
for (auto i : GetParameterExprs<LLIL_MEMORY_INTRINSIC_SSA>())
i.VisitExprs(func);
break;
case LLIL_SEPARATE_PARAM_LIST_SSA:
for (auto i : GetParameterExprs<LLIL_SEPARATE_PARAM_LIST_SSA>())
i.VisitExprs(func);
Expand Down Expand Up @@ -2322,6 +2332,11 @@ ExprId LowLevelILInstruction::CopyTo(
params.push_back(subExprHandler(i));
return dest->IntrinsicSSA(
GetOutputSSARegisterOrFlagList<LLIL_INTRINSIC_SSA>(), GetIntrinsic<LLIL_INTRINSIC_SSA>(), params, *this);
case LLIL_MEMORY_INTRINSIC_SSA:
for (auto i : GetParameterExprs<LLIL_MEMORY_INTRINSIC_SSA>())
params.push_back(subExprHandler(i));
return dest->MemoryIntrinsicSSA(GetOutputSSARegisterOrFlagList<LLIL_MEMORY_INTRINSIC_SSA>(), GetIntrinsic<LLIL_MEMORY_INTRINSIC_SSA>(),
params, GetDestMemoryVersion<LLIL_MEMORY_INTRINSIC_SSA>(), GetSourceMemoryVersion<LLIL_MEMORY_INTRINSIC_SSA>(), *this);
case LLIL_SEPARATE_PARAM_LIST_SSA:
for (auto i : GetParameterExprs<LLIL_SEPARATE_PARAM_LIST_SSA>())
params.push_back(subExprHandler(i));
Expand Down Expand Up @@ -2769,6 +2784,8 @@ LowLevelILSSARegisterOrFlagList LowLevelILInstruction::GetOutputSSARegisterOrFla
size_t operandIndex;
if (GetOperandIndexForUsage(OutputSSARegisterOrFlagListLowLevelOperandUsage, operandIndex))
return GetRawOperandAsSSARegisterOrFlagList(operandIndex);
if (GetOperandIndexForUsage(OutputMemoryIntrinsicLowLevelOperandUsage, operandIndex))
return GetRawOperandAsExpr(operandIndex).GetRawOperandAsSSARegisterOrFlagList(1);
throw LowLevelILInstructionAccessException();
}

Expand Down Expand Up @@ -3475,6 +3492,15 @@ ExprId LowLevelILFunction::IntrinsicSSA(const vector<SSARegisterOrFlag>& outputs
}


ExprId LowLevelILFunction::MemoryIntrinsicSSA(const vector<SSARegisterOrFlag>& outputs, uint32_t intrinsic, const vector<ExprId>& params,
size_t newMemVersion, size_t prevMemVersion, const ILSourceLocation& loc)
{
return AddExprWithLocation(LLIL_MEMORY_INTRINSIC_SSA, loc, 0, 0,
AddExprWithLocation(LLIL_MEMORY_INTRINSIC_OUTPUT_SSA, loc, 0, 0, newMemVersion, outputs.size() * 2, AddSSARegisterOrFlagList(outputs)),
intrinsic, AddExprWithLocation(LLIL_CALL_PARAM, loc, 0, 0, params.size(), AddOperandList(params)), prevMemVersion);
}


ExprId LowLevelILFunction::Breakpoint(const ILSourceLocation& loc)
{
return AddExprWithLocation(LLIL_BP, loc, 0, 0);
Expand Down
22 changes: 22 additions & 0 deletions lowlevelilinstruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@ namespace BinaryNinja
SourceSSAFlagsLowLevelOperandUsage,
OutputRegisterOrFlagListLowLevelOperandUsage,
OutputSSARegisterOrFlagListLowLevelOperandUsage,
OutputMemoryIntrinsicLowLevelOperandUsage,
SourceMemoryVersionsLowLevelOperandUsage,
TargetsLowLevelOperandUsage,
RegisterStackAdjustmentsLowLevelOperandUsage,
Expand Down Expand Up @@ -1701,6 +1702,27 @@ namespace BinaryNinja
UpdateRawOperandAsSSARegisterOrFlagList(0, outputs);
}
};
template <>
struct LowLevelILInstructionAccessor<LLIL_MEMORY_INTRINSIC_SSA> : public LowLevelILInstructionBase
{
LowLevelILSSARegisterOrFlagList GetOutputSSARegisterOrFlagList() const
{
return GetRawOperandAsExpr(0).GetRawOperandAsSSARegisterOrFlagList(1);
}
size_t GetDestMemoryVersion() const { return GetRawOperandAsExpr(0).GetRawOperandAsIndex(0); }
size_t GetSourceMemoryVersion() const { return GetRawOperandAsIndex(3); }
uint32_t GetIntrinsic() const { return GetRawOperandAsRegister(1); }
LowLevelILInstructionList GetParameterExprs() const
{
return GetRawOperandAsExpr(2).GetRawOperandAsExprList(0);
}
void SetDestMemoryVersion(size_t version) { GetRawOperandAsExpr(0).UpdateRawOperand(0, version); }
void SetSourceMemoryVersion(size_t version) { UpdateRawOperand(3, version); }
void SetOutputSSARegisterOrFlagList(const _STD_VECTOR<SSARegisterOrFlag>& outputs)
{
GetRawOperandAsExpr(0).UpdateRawOperandAsSSARegisterOrFlagList(1, outputs);
}
};

template <>
struct LowLevelILInstructionAccessor<LLIL_SEPARATE_PARAM_LIST_SSA> : public LowLevelILInstructionBase
Expand Down
Loading

0 comments on commit 2e3b9c9

Please sign in to comment.