summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--binaryninjaapi.h275
-rw-r--r--binaryninjacore.h240
-rw-r--r--binaryview.cpp20
-rw-r--r--callingconvention.cpp739
-rw-r--r--demangler/gnu3/demangled_type_node.cpp2
-rw-r--r--demangler/msvc/demangle_msvc.cpp4
-rw-r--r--examples/mlil_parser/src/mlil_parser.cpp5
-rw-r--r--function.cpp169
-rw-r--r--highlevelilinstruction.cpp20
-rw-r--r--highlevelilinstruction.h6
-rw-r--r--lang/c/pseudoc.cpp26
-rw-r--r--lang/rust/pseudorust.cpp18
-rw-r--r--lang/rust/rusttypes.cpp43
-rw-r--r--mediumlevelilinstruction.cpp121
-rw-r--r--mediumlevelilinstruction.h50
-rw-r--r--objectivec/objc.cpp6
-rw-r--r--plugins/pdb-ng/src/symbol_parser.rs11
-rw-r--r--plugins/warp/src/convert.rs2
-rw-r--r--plugins/workflow_swift/src/demangler/function_type.rs43
-rw-r--r--plugins/workflow_swift/src/demangler/type_reconstruction.rs6
-rw-r--r--python/architecture.py10
-rw-r--r--python/binaryview.py18
-rw-r--r--python/callingconvention.py968
-rw-r--r--python/examples/pseudo_python.py25
-rw-r--r--python/function.py200
-rw-r--r--python/highlevelil.py42
-rw-r--r--python/mediumlevelil.py262
-rw-r--r--python/platform.py12
-rw-r--r--python/types.py394
-rw-r--r--python/variable.py238
-rw-r--r--rust/src/binary_view.rs35
-rw-r--r--rust/src/calling_convention.rs120
-rw-r--r--rust/src/confidence.rs17
-rw-r--r--rust/src/disassembly.rs5
-rw-r--r--rust/src/ffi.rs13
-rw-r--r--rust/src/function.rs121
-rw-r--r--rust/src/high_level_il/instruction.rs10
-rw-r--r--rust/src/high_level_il/lift.rs14
-rw-r--r--rust/src/medium_level_il/instruction.rs55
-rw-r--r--rust/src/medium_level_il/lift.rs38
-rw-r--r--rust/src/medium_level_il/operation.rs51
-rw-r--r--rust/src/types.rs396
-rw-r--r--rust/src/variable.rs51
-rw-r--r--type.cpp499
-rw-r--r--view/kernelcache/core/Utility.cpp2
-rw-r--r--view/sharedcache/core/Utility.cpp2
46 files changed, 4747 insertions, 657 deletions
diff --git a/binaryninjaapi.h b/binaryninjaapi.h
index 88d43f4e..1029d33b 100644
--- a/binaryninjaapi.h
+++ b/binaryninjaapi.h
@@ -5520,6 +5520,8 @@ namespace BinaryNinja {
class TypeArchive;
class MemoryMap;
struct HighLevelILInstruction;
+ struct FunctionParameter;
+ struct ReturnValue;
class QueryMetadataException : public ExceptionWithStackTrace
{
@@ -8253,6 +8255,9 @@ namespace BinaryNinja {
void SetUserGlobalPointerValue(const Confidence<RegisterValue>& value);
std::optional<std::pair<std::string, BNStringType>> StringifyUnicodeData(Architecture* arch, const DataBuffer& buffer, bool nullTerminates = true, bool allowShortStrings = false);
+
+ std::vector<FunctionParameter> DerefParameterNamedTypeRefs(const std::vector<FunctionParameter>& params);
+ ReturnValue DerefReturnValueNamedTypeRefs(const ReturnValue& returnValue);
};
/*! MemoryMap provides access to the system-level memory map describing how a BinaryView is loaded into memory.
@@ -10591,6 +10596,10 @@ namespace BinaryNinja {
uint64_t ToIdentifier() const;
static Variable FromIdentifier(uint64_t id);
+
+ static Variable Register(uint32_t reg);
+ static Variable Flag(uint32_t flag);
+ static Variable StackOffset(int64_t offset);
};
struct VariableReferenceSource
@@ -10599,21 +10608,105 @@ namespace BinaryNinja {
ILReferenceSource source;
};
+ struct ValueLocationComponent
+ {
+ Variable variable;
+ int64_t offset = 0;
+ std::optional<uint64_t> size;
+
+ ValueLocationComponent() = default;
+ ValueLocationComponent(Variable var, int64_t ofs = 0, std::optional<uint64_t> sz = std::nullopt) :
+ variable(var), offset(ofs), size(sz)
+ {}
+
+ ValueLocationComponent RemapVariables(const std::function<Variable(Variable)>& remap) const;
+
+ bool operator==(const ValueLocationComponent& component) const;
+ bool operator!=(const ValueLocationComponent& component) const;
+
+ static ValueLocationComponent FromAPIObject(const BNValueLocationComponent* loc);
+ BNValueLocationComponent ToAPIObject() const;
+
+ std::string ToString(Architecture* arch) const;
+ };
+
+ struct ValueLocation
+ {
+ std::vector<ValueLocationComponent> components;
+ bool indirect = false;
+ std::optional<Variable> returnedPointer;
+
+ ValueLocation() {}
+ ValueLocation(Variable var, bool indir = false, std::optional<Variable> retPtr = std::nullopt) :
+ components {var}, indirect(indir), returnedPointer(retPtr)
+ {}
+ ValueLocation(const std::vector<ValueLocationComponent>& components, bool indir = false,
+ std::optional<Variable> retPtr = std::nullopt) :
+ components(components), indirect(indir), returnedPointer(retPtr)
+ {}
+ ValueLocation(std::vector<ValueLocationComponent>&& components, bool indir = false,
+ std::optional<Variable> retPtr = std::nullopt) :
+ components(std::move(components)), indirect(indir), returnedPointer(retPtr)
+ {}
+
+ std::optional<Variable> GetVariableForReturnValue() const;
+ std::optional<Variable> GetVariableForParameter(size_t idx) const;
+ ValueLocation RemapVariables(const std::function<Variable(Variable)>& remap) const;
+ void ForEachVariable(const std::function<void(Variable var, bool indirect)>& func) const;
+ bool ContainsVariable(Variable var) const;
+ bool IsValid() const { return !components.empty(); }
+
+ bool operator==(const ValueLocation& loc) const;
+ bool operator!=(const ValueLocation& loc) const;
+
+ static ValueLocation FromAPIObject(const BNValueLocation* loc);
+ BNValueLocation ToAPIObject() const;
+ static void FreeAPIObject(BNValueLocation* loc);
+
+ static std::optional<ValueLocation> Parse(const std::string& str, Architecture* arch, std::string& error);
+ std::string ToString(Architecture* arch) const;
+ };
+
struct FunctionParameter
{
std::string name;
Confidence<Ref<Type>> type;
- bool defaultLocation;
- Variable location;
+ BNValueLocationSource locationSource;
+ ValueLocation location;
FunctionParameter() = default;
- FunctionParameter(const std::string& name, Confidence<Ref<Type>> type): name(name), type(type), defaultLocation(true)
+ FunctionParameter(const std::string& name, Confidence<Ref<Type>> type): name(name), type(type), locationSource(DefaultLocationSource)
{}
- FunctionParameter(const std::string& name, const Confidence<Ref<Type>>& type, bool defaultLocation,
- const Variable& location):
- name(name), type(type), defaultLocation(defaultLocation), location(location)
+ FunctionParameter(const std::string& name, const Confidence<Ref<Type>>& type, BNValueLocationSource source,
+ const ValueLocation& location) :
+ name(name), type(type), locationSource(source), location(location)
{}
+
+ static FunctionParameter FromAPIObject(const BNFunctionParameter* param);
+ BNFunctionParameter ToAPIObject() const;
+ static void FreeAPIObject(BNFunctionParameter* param);
+ };
+
+ struct ReturnValue
+ {
+ Confidence<Ref<Type>> type;
+ bool defaultLocation = true;
+ Confidence<ValueLocation> location;
+
+ ReturnValue(Type* ty) : type(ty) {}
+ ReturnValue(Ref<Type> ty) : type(ty) {}
+ ReturnValue(const Confidence<Ref<Type>>& ty) : type(ty) {}
+ ReturnValue(const Confidence<Ref<Type>>& ty, bool defaultLoc, const Confidence<ValueLocation>& loc) :
+ type(ty), defaultLocation(defaultLoc), location(loc) {};
+ ReturnValue() = default;
+
+ bool operator==(const ReturnValue& nt) const;
+ bool operator!=(const ReturnValue& nt) const;
+
+ static ReturnValue FromAPIObject(const BNReturnValue* returnValue);
+ BNReturnValue ToAPIObject() const;
+ static void FreeAPIObject(BNReturnValue* returnValue);
};
class FieldResolutionInfo : public CoreRefCountObject<BNFieldResolutionInfo, BNNewFieldResolutionInfoReference, BNFreeFieldResolutionInfo>
@@ -10763,6 +10856,22 @@ namespace BinaryNinja {
*/
Confidence<Ref<Type>> GetChildType() const;
+ /*! Get the return value type and location for this Type if one exists
+
+ \return The return value type and location
+ */
+ ReturnValue GetReturnValue() const;
+
+ /*! Whether the return value is in the default location
+ */
+ bool IsReturnValueDefaultLocation() const;
+
+ /*! Get the return value location for this Type
+
+ \return The return value location
+ */
+ Confidence<ValueLocation> GetReturnValueLocation() const;
+
/*! For Function Types, get the calling convention
\return The CallingConvention
@@ -11012,14 +11121,14 @@ namespace BinaryNinja {
auto functionType = Type::FunctionType(retType, cc, params);
\endcode
- \param returnValue Return value Type
+ \param returnValue Return value type and location
\param callingConvention Calling convention for the function
\param params list of FunctionParameter s
\param varArg Whether this function has variadic arguments, default false
\param stackAdjust Stack adjustment for this function, default 0
\return The created function types
*/
- static Ref<Type> FunctionType(const Confidence<Ref<Type>>& returnValue,
+ static Ref<Type> FunctionType(const ReturnValue& returnValue,
const Confidence<Ref<CallingConvention>>& callingConvention, const std::vector<FunctionParameter>& params,
const Confidence<bool>& varArg = Confidence<bool>(false, 0),
const Confidence<int64_t>& stackAdjust = Confidence<int64_t>(0, 0));
@@ -11040,23 +11149,21 @@ namespace BinaryNinja {
auto functionType = Type::FunctionType(retType, cc, params);
\endcode
- \param returnValue Return value Type
+ \param returnValue Return value type and location
\param callingConvention Calling convention for the function
\param params list of FunctionParameters
\param varArg Whether this function has variadic arguments, default false
\param stackAdjust Stack adjustment for this function, default 0
- \param regStackAdjust Register stack adjustmemt
- \param returnRegs Return registers
+ \param regStackAdjust Register stack adjustmemt
\return The created function types
*/
- static Ref<Type> FunctionType(const Confidence<Ref<Type>>& returnValue,
+ static Ref<Type> FunctionType(const ReturnValue& returnValue,
const Confidence<Ref<CallingConvention>>& callingConvention,
const std::vector<FunctionParameter>& params,
const Confidence<bool>& hasVariableArguments,
const Confidence<bool>& canReturn,
const Confidence<int64_t>& stackAdjust,
const std::map<uint32_t, Confidence<int32_t>>& regStackAdjust = std::map<uint32_t, Confidence<int32_t>>(),
- const Confidence<std::vector<uint32_t>>& returnRegs = Confidence<std::vector<uint32_t>>(std::vector<uint32_t>(), 0),
BNNameType ft = NoNameType,
const Confidence<bool>& pure = Confidence<bool>(false, 0));
static Ref<Type> VarArgsType();
@@ -11253,6 +11360,9 @@ namespace BinaryNinja {
void SetIntegerTypeDisplayType(BNIntegerDisplayType displayType);
Confidence<Ref<Type>> GetChildType() const;
+ ReturnValue GetReturnValue() const;
+ bool IsReturnValueDefaultLocation() const;
+ Confidence<ValueLocation> GetReturnValueLocation() const;
Confidence<Ref<CallingConvention>> GetCallingConvention() const;
BNCallingConventionName GetCallingConventionName() const;
std::vector<FunctionParameter> GetParameters() const;
@@ -11272,6 +11382,9 @@ namespace BinaryNinja {
TypeBuilder& SetConst(const Confidence<bool>& cnst);
TypeBuilder& SetVolatile(const Confidence<bool>& vltl);
TypeBuilder& SetChildType(const Confidence<Ref<Type>>& child);
+ TypeBuilder& SetReturnValue(const ReturnValue& rv);
+ TypeBuilder& SetIsReturnValueDefaultLocation(bool defaultLocation);
+ TypeBuilder& SetReturnValueLocation(const Confidence<ValueLocation>& location);
TypeBuilder& SetCallingConvention(const Confidence<Ref<CallingConvention>>& cc);
TypeBuilder& SetCallingConventionName(BNCallingConventionName cc);
TypeBuilder& SetSigned(const Confidence<bool>& vltl);
@@ -11367,18 +11480,17 @@ namespace BinaryNinja {
uint64_t originalFragmentOffsetBytes, size_t originalFragmentWidthBytes, BNEndianness endianness,
size_t fragmentStartBit, size_t fragmentWidthBits, size_t fragmentTruncatedStartBits, size_t wrapBit = 0);
static TypeBuilder ArrayType(const Confidence<Ref<Type>>& type, uint64_t elem);
- static TypeBuilder FunctionType(const Confidence<Ref<Type>>& returnValue,
+ static TypeBuilder FunctionType(const ReturnValue& returnValue,
const Confidence<Ref<CallingConvention>>& callingConvention, const std::vector<FunctionParameter>& params,
const Confidence<bool>& varArg = Confidence<bool>(false, 0),
const Confidence<int64_t>& stackAdjust = Confidence<int64_t>(0, 0));
- static TypeBuilder FunctionType(const Confidence<Ref<Type>>& returnValue,
+ static TypeBuilder FunctionType(const ReturnValue& returnValue,
const Confidence<Ref<CallingConvention>>& callingConvention,
const std::vector<FunctionParameter>& params,
const Confidence<bool>& hasVariableArguments,
const Confidence<bool>& canReturn,
const Confidence<int64_t>& stackAdjust,
const std::map<uint32_t, Confidence<int32_t>>& regStackAdjust = std::map<uint32_t, Confidence<int32_t>>(),
- const Confidence<std::vector<uint32_t>>& returnRegs = Confidence<std::vector<uint32_t>>(std::vector<uint32_t>(), 0),
BNNameType ft = NoNameType,
const Confidence<bool>& pure = Confidence<bool>(false, 0));
static TypeBuilder VarArgsType();
@@ -13276,9 +13388,13 @@ namespace BinaryNinja {
Ref<Type> GetType() const;
Confidence<Ref<Type>> GetReturnType() const;
+ ReturnValue GetReturnValue() const;
+ bool IsReturnValueDefaultLocation() const;
+ Confidence<ValueLocation> GetReturnValueLocation() const;
Confidence<std::vector<uint32_t>> GetReturnRegisters() const;
Confidence<Ref<CallingConvention>> GetCallingConvention() const;
Confidence<std::vector<Variable>> GetParameterVariables() const;
+ Confidence<std::vector<ValueLocation>> GetParameterLocations() const;
Confidence<bool> HasVariableArguments() const;
Confidence<int64_t> GetStackAdjustment() const;
std::map<uint32_t, Confidence<int32_t>> GetRegisterStackAdjustments() const;
@@ -13286,9 +13402,11 @@ namespace BinaryNinja {
void SetAutoType(Type* type);
void SetAutoReturnType(const Confidence<Ref<Type>>& type);
- void SetAutoReturnRegisters(const Confidence<std::vector<uint32_t>>& returnRegs);
+ void SetAutoReturnValue(const ReturnValue& rv);
+ void SetAutoIsReturnValueDefaultLocation(bool defaultLocation);
+ void SetAutoReturnValueLocation(const Confidence<ValueLocation>& location);
void SetAutoCallingConvention(const Confidence<Ref<CallingConvention>>& convention);
- void SetAutoParameterVariables(const Confidence<std::vector<Variable>>& vars);
+ void SetAutoParameterLocations(const Confidence<std::vector<ValueLocation>>& locations);
void SetAutoHasVariableArguments(const Confidence<bool>& varArgs);
void SetAutoCanReturn(const Confidence<bool>& returns);
void SetAutoPure(const Confidence<bool>& pure);
@@ -13298,9 +13416,11 @@ namespace BinaryNinja {
void SetUserType(Type* type);
void SetReturnType(const Confidence<Ref<Type>>& type);
- void SetReturnRegisters(const Confidence<std::vector<uint32_t>>& returnRegs);
+ void SetReturnValue(const ReturnValue& rv);
+ void SetIsReturnValueDefaultLocation(bool defaultLocation);
+ void SetReturnValueLocation(const Confidence<ValueLocation>& location);
void SetCallingConvention(const Confidence<Ref<CallingConvention>>& convention);
- void SetParameterVariables(const Confidence<std::vector<Variable>>& vars);
+ void SetParameterLocations(const Confidence<std::vector<ValueLocation>>& locations);
void SetHasVariableArguments(const Confidence<bool>& varArgs);
void SetCanReturn(const Confidence<bool>& returns);
void SetPure(const Confidence<bool>& pure);
@@ -15696,8 +15816,16 @@ namespace BinaryNinja {
ExprId VarSplitSSA(size_t size, const SSAVariable& high, const SSAVariable& low,
const ILSourceLocation& loc = ILSourceLocation());
ExprId VarOutputSSA(size_t size, const SSAVariable& dest, const ILSourceLocation& loc = ILSourceLocation());
+ ExprId VarOutputSSAField(size_t size, const Variable& dest, size_t newVersion, size_t prevVersion,
+ uint64_t offset, const ILSourceLocation& loc = ILSourceLocation());
+ ExprId VarOutputAliased(size_t size, const Variable& dest, size_t newMemVersion, size_t prevMemVersion,
+ const ILSourceLocation& loc = ILSourceLocation());
+ ExprId VarOutputAliasedField(size_t size, const Variable& dest, size_t newMemVersion, size_t prevMemVersion,
+ uint64_t offset, const ILSourceLocation& loc = ILSourceLocation());
ExprId AddressOf(const Variable& var, const ILSourceLocation& loc = ILSourceLocation());
ExprId AddressOfField(const Variable& var, uint64_t offset, const ILSourceLocation& loc = ILSourceLocation());
+ ExprId PassByRef(size_t size, ExprId src, const ILSourceLocation& loc = ILSourceLocation());
+ ExprId ReturnByRef(size_t size, 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());
ExprId ExternPointer(
@@ -15783,6 +15911,9 @@ namespace BinaryNinja {
ExprId SeparateParamList(const std::vector<ExprId>& params, const ILSourceLocation& loc = ILSourceLocation());
ExprId SharedParamSlot(const std::vector<ExprId>& params, const ILSourceLocation& loc = ILSourceLocation());
ExprId VarOutput(size_t size, const Variable& var, const ILSourceLocation& loc = ILSourceLocation());
+ ExprId VarOutputField(size_t size, const Variable& dest, uint64_t offset,
+ const ILSourceLocation& loc = ILSourceLocation());
+ ExprId StoreOutput(size_t size, ExprId dest, const ILSourceLocation& loc = ILSourceLocation());
ExprId Return(const std::vector<ExprId>& sources, const ILSourceLocation& loc = ILSourceLocation());
ExprId NoReturn(const ILSourceLocation& loc = ILSourceLocation());
ExprId CompareEqual(size_t size, ExprId left, ExprId right, const ILSourceLocation& loc = ILSourceLocation());
@@ -15849,6 +15980,7 @@ namespace BinaryNinja {
size_t size, ExprId a, ExprId b, const ILSourceLocation& loc = ILSourceLocation());
ExprId FloatCompareOrdered(size_t size, ExprId a, ExprId b, const ILSourceLocation& loc = ILSourceLocation());
ExprId FloatCompareUnordered(size_t size, ExprId a, ExprId b, const ILSourceLocation& loc = ILSourceLocation());
+ ExprId BlockToExpand(const std::vector<ExprId>& sources, const ILSourceLocation& loc = ILSourceLocation());
ExprId Goto(BNMediumLevelILLabel& label, const ILSourceLocation& loc = ILSourceLocation());
ExprId If(ExprId operand, BNMediumLevelILLabel& t, BNMediumLevelILLabel& f,
@@ -16093,6 +16225,8 @@ namespace BinaryNinja {
ExprId DerefFieldSSA(size_t size, ExprId src, size_t srcMemVersion, uint64_t offset, size_t memberIndex,
const ILSourceLocation& loc = ILSourceLocation());
ExprId AddressOf(ExprId src, const ILSourceLocation& loc = ILSourceLocation());
+ ExprId PassByRef(size_t size, ExprId src, const ILSourceLocation& loc = ILSourceLocation());
+ ExprId ReturnByRef(size_t size, 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());
ExprId ExternPointer(
@@ -17795,7 +17929,22 @@ namespace BinaryNinja {
};
/*!
- \ingroup callingconvention
+ \ingroup callingconvention
+ */
+ struct CallLayout
+ {
+ std::vector<ValueLocation> parameters;
+ std::optional<ValueLocation> returnValue;
+ int64_t stackAdjustment = 0;
+ std::map<uint32_t, int32_t> registerStackAdjustments;
+
+ static CallLayout FromAPIObject(BNCallLayout* layout);
+ BNCallLayout ToAPIObject() const;
+ static void FreeAPIObject(BNCallLayout* layout);
+ };
+
+ /*!
+ \ingroup callingconvention
*/
class CallingConvention :
public CoreRefCountObject<BNCallingConvention, BNNewCallingConventionReference, BNFreeCallingConvention>
@@ -17835,7 +17984,32 @@ namespace BinaryNinja {
static void GetParameterVariableForIncomingVariableCallback(
void* ctxt, const BNVariable* var, BNFunction* func, BNVariable* result);
- public:
+ static bool IsReturnTypeRegisterCompatibleCallback(void* ctxt, BNBinaryView* view, BNType* type);
+ static void GetIndirectReturnValueLocationCallback(void* ctxt, BNVariable* outVar);
+ static bool GetReturnedIndirectReturnValuePointerCallback(void* ctxt, BNVariable* outVar);
+
+ static bool IsArgumentTypeRegisterCompatibleCallback(void* ctxt, BNBinaryView* view, BNType* type);
+ static bool IsNonRegisterArgumentIndirectCallback(void* ctxt, BNBinaryView* view, BNType* type);
+ static bool AreStackArgumentsNaturallyAlignedCallback(void* ctxt);
+
+ static void GetCallLayoutCallback(void* ctxt, BNBinaryView* view, BNReturnValue* returnValue,
+ BNFunctionParameter* params, size_t paramCount, bool hasPermittedRegs, uint32_t* permittedRegs,
+ size_t permittedRegCount, BNCallLayout* result);
+ static void FreeCallLayoutCallback(void* ctxt, BNCallLayout* layout);
+ static void GetReturnValueLocationCallback(
+ void* ctxt, BNBinaryView* view, BNReturnValue* returnValue, BNValueLocation* outLocation);
+ static void FreeValueLocationCallback(void* ctxt, BNValueLocation* location);
+ static BNValueLocation* GetParameterLocationsCallback(void* ctxt, BNBinaryView* view,
+ BNValueLocation* returnValue, BNFunctionParameter* params, size_t paramCount, bool hasPermittedRegs,
+ uint32_t* permittedRegs, size_t permittedRegCount, size_t* outLocationCount);
+ static void FreeParameterLocationsCallback(void* ctxt, BNValueLocation* locations, size_t count);
+ static int64_t GetStackAdjustmentForLocationsCallback(void* ctxt, BNBinaryView* view,
+ BNValueLocation* returnValue, BNValueLocation* locations, BNType** types, size_t paramCount);
+ static size_t GetRegisterStackAdjustmentsCallback(void* ctxt, BNBinaryView* view, BNValueLocation* returnValue,
+ BNValueLocation* params, size_t paramCount, uint32_t** outRegs, int32_t** outAdjust);
+ static void FreeRegisterStackAdjustmentsCallback(void* ctxt, uint32_t* regs, int32_t* adjust, size_t count);
+
+ public:
Ref<Architecture> GetArchitecture() const;
std::string GetName() const;
@@ -17876,6 +18050,42 @@ namespace BinaryNinja {
virtual Variable GetIncomingVariableForParameterVariable(const Variable& var, Function* func);
virtual Variable GetParameterVariableForIncomingVariable(const Variable& var, Function* func);
+
+ virtual bool IsReturnTypeRegisterCompatible(BinaryView* view, Type* type);
+ bool DefaultIsReturnTypeRegisterCompatible(Type* type);
+ virtual Variable GetIndirectReturnValueLocation();
+ Variable GetDefaultIndirectReturnValueLocation();
+ virtual std::optional<Variable> GetReturnedIndirectReturnValuePointer();
+
+ virtual bool IsArgumentTypeRegisterCompatible(BinaryView* view, Type* type);
+ bool DefaultIsArgumentTypeRegisterCompatible(Type* type);
+ virtual bool IsNonRegisterArgumentIndirect(BinaryView* view, Type* type);
+ virtual bool AreStackArgumentsNaturallyAligned();
+
+ virtual CallLayout GetCallLayout(BinaryView* view, const ReturnValue& returnValue,
+ const std::vector<FunctionParameter>& params,
+ const std::optional<std::set<uint32_t>>& permittedRegs = std::nullopt);
+ virtual ValueLocation GetReturnValueLocation(BinaryView* view, const ReturnValue& returnValue);
+ virtual std::vector<ValueLocation> GetParameterLocations(BinaryView* view,
+ const std::optional<ValueLocation>& returnValue, const std::vector<FunctionParameter>& params,
+ const std::optional<std::set<uint32_t>>& permittedRegs = std::nullopt);
+ virtual int64_t GetStackAdjustmentForLocations(BinaryView* view,
+ const std::optional<ValueLocation>& returnValue, const std::vector<ValueLocation>& locations,
+ const std::vector<Ref<Type>>& types);
+ virtual std::map<uint32_t, int32_t> GetRegisterStackAdjustments(BinaryView* view,
+ const std::optional<ValueLocation>& returnValue, const std::vector<ValueLocation>& params);
+
+ CallLayout GetDefaultCallLayout(BinaryView* view, const ReturnValue& returnValue,
+ const std::vector<FunctionParameter>& params,
+ const std::optional<std::set<uint32_t>>& permittedRegs = std::nullopt);
+ ValueLocation GetDefaultReturnValueLocation(BinaryView* view, const ReturnValue& returnValue);
+ std::vector<ValueLocation> GetDefaultParameterLocations(BinaryView* view,
+ const std::optional<ValueLocation>& returnValue, const std::vector<FunctionParameter>& params,
+ const std::optional<std::set<uint32_t>>& permittedRegs = std::nullopt);
+ int64_t GetDefaultStackAdjustmentForLocations(const std::optional<ValueLocation>& returnValue,
+ const std::vector<ValueLocation>& locations, const std::vector<Ref<Type>>& types);
+ std::map<uint32_t, int32_t> GetDefaultRegisterStackAdjustments(
+ const std::optional<ValueLocation>& returnValue, const std::vector<ValueLocation>& params);
};
/*!
@@ -17910,6 +18120,27 @@ namespace BinaryNinja {
virtual Variable GetIncomingVariableForParameterVariable(const Variable& var, Function* func) override;
virtual Variable GetParameterVariableForIncomingVariable(const Variable& var, Function* func) override;
+
+ virtual bool IsReturnTypeRegisterCompatible(BinaryView* view, Type* type) override;
+ virtual Variable GetIndirectReturnValueLocation() override;
+ virtual std::optional<Variable> GetReturnedIndirectReturnValuePointer() override;
+
+ virtual bool IsArgumentTypeRegisterCompatible(BinaryView* view, Type* type) override;
+ virtual bool IsNonRegisterArgumentIndirect(BinaryView* view, Type* type) override;
+ virtual bool AreStackArgumentsNaturallyAligned() override;
+
+ virtual CallLayout GetCallLayout(BinaryView* view, const ReturnValue& returnValue,
+ const std::vector<FunctionParameter>& params,
+ const std::optional<std::set<uint32_t>>& permittedRegs = std::nullopt) override;
+ virtual ValueLocation GetReturnValueLocation(BinaryView* view, const ReturnValue& returnValue) override;
+ virtual std::vector<ValueLocation> GetParameterLocations(BinaryView* view,
+ const std::optional<ValueLocation>& returnValue, const std::vector<FunctionParameter>& params,
+ const std::optional<std::set<uint32_t>>& permittedRegs = std::nullopt) override;
+ virtual int64_t GetStackAdjustmentForLocations(BinaryView* view,
+ const std::optional<ValueLocation>& returnValue, const std::vector<ValueLocation>& locations,
+ const std::vector<Ref<Type>>& types) override;
+ virtual std::map<uint32_t, int32_t> GetRegisterStackAdjustments(BinaryView* view,
+ const std::optional<ValueLocation>& returnValue, const std::vector<ValueLocation>& params) override;
};
/*!
diff --git a/binaryninjacore.h b/binaryninjacore.h
index 8a970276..fd356b41 100644
--- a/binaryninjacore.h
+++ b/binaryninjacore.h
@@ -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 168
+#define BN_CURRENT_CORE_ABI_VERSION 169
// 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 168
+#define BN_MINIMUM_CORE_ABI_VERSION 169
#ifdef __GNUC__
#ifdef BINARYNINJACORE_LIBRARY
@@ -506,6 +506,7 @@ extern "C"
BaseStructureNameToken = 37,
BaseStructureSeparatorToken = 38,
BraceToken = 39,
+ ValueLocationToken = 40,
// The following are output by the analysis system automatically, these should
// not be used directly by the architecture plugins
CodeSymbolToken = 64,
@@ -1154,6 +1155,9 @@ extern "C"
// Cue for use-def heuristics to follow through simple copies (e.g., register windowing for Xtensa)
ILTransparentCopy = 0x1000,
+
+ // Instruction is defining an implicit trait of the calling convention
+ MLILCallingConventionImplicit = 0x2000
};
BN_ENUM(uint8_t, BNIntrinsicClass)
@@ -1239,6 +1243,8 @@ extern "C"
StackFrameOffset,
ReturnAddressValue,
ImportedAddressValue,
+ ResultPointerValue,
+ ParameterPointerValue,
// The following are only valid in BNPossibleValueSet
SignedRangeValue,
@@ -1383,6 +1389,8 @@ extern "C"
MLIL_VAR_SPLIT, // Not valid in SSA form (see MLIL_VAR_SPLIT_SSA)
MLIL_ADDRESS_OF,
MLIL_ADDRESS_OF_FIELD,
+ MLIL_PASS_BY_REF,
+ MLIL_RETURN_BY_REF,
MLIL_CONST,
MLIL_CONST_DATA,
MLIL_CONST_PTR,
@@ -1430,6 +1438,8 @@ extern "C"
MLIL_SHARED_PARAM_SLOT, // Only valid within the MLIL_CALL_PARAM, MLIL_CALL_PARAM_SSA, or
// MLIL_SEPARATE_PARAM_LIST instructions inside untyped call variants
MLIL_VAR_OUTPUT, // Only valid within MLIL_CALL, MLIL_SYSCALL, MLIL_TAILCALL family instructions
+ MLIL_VAR_OUTPUT_FIELD, // Only valid within MLIL_CALL, MLIL_SYSCALL, MLIL_TAILCALL family instructions
+ MLIL_STORE_OUTPUT, // Only valid within MLIL_CALL, MLIL_SYSCALL, MLIL_TAILCALL family instructions
MLIL_RET,
MLIL_NORET,
MLIL_IF,
@@ -1507,6 +1517,9 @@ extern "C"
MLIL_CALL_OUTPUT_SSA, // Only valid within the MLIL_CALL_SSA or MLIL_SYSCALL_SSA, MLIL_TAILCALL_SSA family
// instructions
MLIL_VAR_OUTPUT_SSA, // Only valid within the MLIL_CALL_OUTPUT_SSA instruction
+ MLIL_VAR_OUTPUT_SSA_FIELD, // Only valid within the MLIL_CALL_OUTPUT_SSA instruction
+ MLIL_VAR_OUTPUT_ALIASED, // Only valid within the MLIL_CALL_OUTPUT_SSA instruction
+ MLIL_VAR_OUTPUT_ALIASED_FIELD, // Only valid within the MLIL_CALL_OUTPUT_SSA instruction
MLIL_MEMORY_INTRINSIC_OUTPUT_SSA, // Only valid within the MLIL_MEMORY_INTRINSIC_SSA instruction
MLIL_LOAD_SSA,
MLIL_LOAD_STRUCT_SSA,
@@ -1516,7 +1529,9 @@ extern "C"
MLIL_MEMORY_INTRINSIC_SSA,
MLIL_FREE_VAR_SLOT_SSA,
MLIL_VAR_PHI,
- MLIL_MEM_PHI
+ MLIL_MEM_PHI,
+
+ MLIL_BLOCK_TO_EXPAND // Must be expanded by a future workflow step, used temporarily to insert instructions
};
typedef struct BNMediumLevelILInstruction
@@ -1540,7 +1555,9 @@ extern "C"
{
StackVariableSourceType,
RegisterVariableSourceType,
- FlagVariableSourceType
+ FlagVariableSourceType,
+ CompositeReturnValueSourceType,
+ CompositeParameterSourceType
};
typedef struct BNVariable
@@ -1582,6 +1599,8 @@ extern "C"
HLIL_DEREF,
HLIL_DEREF_FIELD,
HLIL_ADDRESS_OF,
+ HLIL_PASS_BY_REF,
+ HLIL_RETURN_BY_REF,
HLIL_CONST,
HLIL_CONST_DATA,
HLIL_CONST_PTR,
@@ -2626,15 +2645,74 @@ extern "C"
uint8_t confidence;
} BNRegisterSetWithConfidence;
+ typedef struct BNValueLocationComponent
+ {
+ BNVariable variable;
+ int64_t offset;
+ bool sizeValid;
+ uint64_t size;
+ } BNValueLocationComponent;
+
+ typedef struct BNValueLocation
+ {
+ size_t count;
+ BNValueLocationComponent* components;
+ bool indirect;
+ bool returnedPointerValid;
+ BNVariable returnedPointer;
+ } BNValueLocation;
+
+ typedef struct BNValueLocationWithConfidence
+ {
+ BNValueLocation location;
+ uint8_t confidence;
+ } BNValueLocationWithConfidence;
+
+ typedef struct BNValueLocationListWithConfidence
+ {
+ BNValueLocation* locations;
+ size_t count;
+ uint8_t confidence;
+ } BNValueLocationListWithConfidence;
+
+ BN_ENUM(uint8_t, BNValueLocationSource)
+ {
+ DefaultLocationSource,
+ PassByValueLocationSource,
+ PassByReferenceLocationSource,
+ CustomLocationSource
+ };
+
typedef struct BNFunctionParameter
{
char* name;
BNType* type;
uint8_t typeConfidence;
- bool defaultLocation;
- BNVariable location;
+ BNValueLocationSource locationSource;
+ BNValueLocation location;
} BNFunctionParameter;
+ typedef struct BNReturnValue
+ {
+ BNType* type;
+ uint8_t typeConfidence;
+ bool defaultLocation;
+ BNValueLocation location;
+ uint8_t locationConfidence;
+ } BNReturnValue;
+
+ typedef struct BNCallLayout
+ {
+ BNValueLocation* parameters;
+ size_t parameterCount;
+ bool returnValueValid;
+ BNValueLocation returnValue;
+ int64_t stackAdjustment;
+ uint32_t* registerStackAdjustmentRegisters;
+ int32_t* registerStackAdjustmentAmounts;
+ size_t registerStackAdjustmentCount;
+ } BNCallLayout;
+
typedef struct BNQualifiedNameAndType
{
BNQualifiedName name;
@@ -2881,12 +2959,37 @@ extern "C"
void (*getIncomingRegisterValue)(void* ctxt, uint32_t reg, BNFunction* func, BNRegisterValue* result);
void (*getIncomingFlagValue)(void* ctxt, uint32_t flag, BNFunction* func, BNRegisterValue* result);
+ bool (*isReturnTypeRegisterCompatible)(void* ctxt, BNBinaryView* view, BNType* type);
+ void (*getIndirectReturnValueLocation)(void* ctxt, BNVariable* outVar);
+ bool (*getReturnedIndirectReturnValuePointer)(void* ctxt, BNVariable* outVar);
+
+ bool (*isArgumentTypeRegisterCompatible)(void* ctxt, BNBinaryView* view, BNType* type);
+ bool (*isNonRegisterArgumentIndirect)(void* ctxt, BNBinaryView* view, BNType* type);
+ bool (*areStackArgumentsNaturallyAligned)(void* ctxt);
+
void (*getIncomingVariableForParameterVariable)(
void* ctxt, const BNVariable* var, BNFunction* func, BNVariable* result);
void (*getParameterVariableForIncomingVariable)(
void* ctxt, const BNVariable* var, BNFunction* func, BNVariable* result);
bool (*areArgumentRegistersUsedForVarArgs)(void* ctxt);
+
+ void (*getCallLayout)(void* ctxt, BNBinaryView* view, BNReturnValue* returnValue, BNFunctionParameter* params,
+ size_t paramCount, bool hasPermittedRegs, uint32_t* permittedRegs, size_t permittedRegCount,
+ BNCallLayout* result);
+ void (*freeCallLayout)(void* ctxt, BNCallLayout* layout);
+ void (*getReturnValueLocation)(
+ void* ctxt, BNBinaryView* view, BNReturnValue* returnValue, BNValueLocation* outLocation);
+ void (*freeValueLocation)(void* ctxt, BNValueLocation* location);
+ BNValueLocation* (*getParameterLocations)(void* ctxt, BNBinaryView* view, BNValueLocation* returnValue,
+ BNFunctionParameter* params, size_t paramCount, bool hasPermittedRegs, uint32_t* permittedRegs,
+ size_t permittedRegCount, size_t* outLocationCount);
+ void (*freeParameterLocations)(void* ctxt, BNValueLocation* locations, size_t count);
+ int64_t (*getStackAdjustmentForLocations)(void* ctxt, BNBinaryView* view, BNValueLocation* returnValue,
+ BNValueLocation* locations, BNType** types, size_t paramCount);
+ size_t (*getRegisterStackAdjustments)(void* ctxt, BNBinaryView* view, BNValueLocation* returnValue,
+ BNValueLocation* params, size_t paramCount, uint32_t** outRegs, int32_t** outAdjust);
+ void (*freeRegisterStackAdjustments)(void* ctxt, uint32_t* regs, int32_t* adjust, size_t count);
} BNCustomCallingConvention;
typedef struct BNVariableNameAndType
@@ -5273,10 +5376,19 @@ extern "C"
BINARYNINJACOREAPI BNType* BNGetFunctionType(BNFunction* func);
BINARYNINJACOREAPI BNTypeWithConfidence BNGetFunctionReturnType(BNFunction* func);
+ BINARYNINJACOREAPI BNReturnValue BNGetFunctionReturnValue(BNFunction* func);
+ BINARYNINJACOREAPI void BNFreeReturnValue(BNReturnValue* ret);
+ BINARYNINJACOREAPI bool BNIsFunctionReturnValueDefaultLocation(BNFunction* func);
+ BINARYNINJACOREAPI BNValueLocationWithConfidence BNGetFunctionReturnValueLocation(BNFunction* func);
BINARYNINJACOREAPI BNRegisterSetWithConfidence BNGetFunctionReturnRegisters(BNFunction* func);
BINARYNINJACOREAPI BNCallingConventionWithConfidence BNGetFunctionCallingConvention(BNFunction* func);
BINARYNINJACOREAPI BNParameterVariablesWithConfidence BNGetFunctionParameterVariables(BNFunction* func);
BINARYNINJACOREAPI void BNFreeParameterVariables(BNParameterVariablesWithConfidence* vars);
+ BINARYNINJACOREAPI BNValueLocationListWithConfidence BNGetFunctionParameterLocations(BNFunction* func);
+ BINARYNINJACOREAPI void BNFreeParameterLocations(BNValueLocationListWithConfidence* locations);
+ BINARYNINJACOREAPI bool BNGetValueLocationVariableForReturnValue(const BNValueLocation* location, BNVariable* var);
+ BINARYNINJACOREAPI bool BNGetValueLocationVariableForParameter(
+ const BNValueLocation* location, BNVariable* var, size_t idx);
BINARYNINJACOREAPI BNBoolWithConfidence BNFunctionHasVariableArguments(BNFunction* func);
BINARYNINJACOREAPI BNOffsetWithConfidence BNGetFunctionStackAdjustment(BNFunction* func);
BINARYNINJACOREAPI BNRegisterStackAdjustment* BNGetFunctionRegisterStackAdjustments(
@@ -5286,11 +5398,14 @@ extern "C"
BINARYNINJACOREAPI void BNFreeRegisterSet(BNRegisterSetWithConfidence* regs);
BINARYNINJACOREAPI void BNSetAutoFunctionReturnType(BNFunction* func, BNTypeWithConfidence* type);
- BINARYNINJACOREAPI void BNSetAutoFunctionReturnRegisters(BNFunction* func, BNRegisterSetWithConfidence* regs);
+ BINARYNINJACOREAPI void BNSetAutoIsFunctionReturnValueDefaultLocation(BNFunction* func, bool defaultLocation);
+ BINARYNINJACOREAPI void BNSetAutoFunctionReturnValueLocation(
+ BNFunction* func, BNValueLocationWithConfidence* location);
+ BINARYNINJACOREAPI void BNSetAutoFunctionReturnValue(BNFunction* func, BNReturnValue* returnValue);
BINARYNINJACOREAPI void BNSetAutoFunctionCallingConvention(
BNFunction* func, BNCallingConventionWithConfidence* convention);
- BINARYNINJACOREAPI void BNSetAutoFunctionParameterVariables(
- BNFunction* func, BNParameterVariablesWithConfidence* vars);
+ BINARYNINJACOREAPI void BNSetAutoFunctionParameterLocations(
+ BNFunction* func, BNValueLocationListWithConfidence* locations);
BINARYNINJACOREAPI void BNSetAutoFunctionHasVariableArguments(BNFunction* func, BNBoolWithConfidence* varArgs);
BINARYNINJACOREAPI void BNSetAutoFunctionCanReturn(BNFunction* func, BNBoolWithConfidence* returns);
BINARYNINJACOREAPI void BNSetAutoFunctionPure(BNFunction* func, BNBoolWithConfidence* pure);
@@ -5300,11 +5415,14 @@ extern "C"
BINARYNINJACOREAPI void BNSetAutoFunctionClobberedRegisters(BNFunction* func, BNRegisterSetWithConfidence* regs);
BINARYNINJACOREAPI void BNSetUserFunctionReturnType(BNFunction* func, BNTypeWithConfidence* type);
- BINARYNINJACOREAPI void BNSetUserFunctionReturnRegisters(BNFunction* func, BNRegisterSetWithConfidence* regs);
+ BINARYNINJACOREAPI void BNSetUserIsFunctionReturnValueDefaultLocation(BNFunction* func, bool defaultLocation);
+ BINARYNINJACOREAPI void BNSetUserFunctionReturnValueLocation(
+ BNFunction* func, BNValueLocationWithConfidence* location);
+ BINARYNINJACOREAPI void BNSetUserFunctionReturnValue(BNFunction* func, BNReturnValue* returnValue);
BINARYNINJACOREAPI void BNSetUserFunctionCallingConvention(
BNFunction* func, BNCallingConventionWithConfidence* convention);
- BINARYNINJACOREAPI void BNSetUserFunctionParameterVariables(
- BNFunction* func, BNParameterVariablesWithConfidence* vars);
+ BINARYNINJACOREAPI void BNSetUserFunctionParameterLocations(
+ BNFunction* func, BNValueLocationListWithConfidence* locations);
BINARYNINJACOREAPI void BNSetUserFunctionHasVariableArguments(BNFunction* func, BNBoolWithConfidence* varArgs);
BINARYNINJACOREAPI void BNSetUserFunctionCanReturn(BNFunction* func, BNBoolWithConfidence* returns);
BINARYNINJACOREAPI void BNSetUserFunctionPure(BNFunction* func, BNBoolWithConfidence* pure);
@@ -7047,11 +7165,11 @@ extern "C"
uint64_t originalFragmentOffsetBytes, size_t originalFragmentWidthBytes, BNEndianness endianness,
size_t fragmentStartBit, size_t fragmentWidthBits, size_t fragmentTruncatedStartBits, size_t wrapBit);
BINARYNINJACOREAPI BNType* BNCreateArrayType(const BNTypeWithConfidence* const type, uint64_t elem);
- BINARYNINJACOREAPI BNType* BNCreateFunctionType(BNTypeWithConfidence* returnValue, BNCallingConventionWithConfidence* callingConvention,
- BNFunctionParameter* params, size_t paramCount, BNBoolWithConfidence* varArg,
- BNBoolWithConfidence* canReturn, BNOffsetWithConfidence* stackAdjust,
- uint32_t* regStackAdjustRegs, BNOffsetWithConfidence* regStackAdjustValues, size_t regStackAdjustCount,
- BNRegisterSetWithConfidence* returnRegs, BNNameType ft, BNBoolWithConfidence* pure);
+ BINARYNINJACOREAPI BNType* BNCreateFunctionType(BNReturnValue* returnValue,
+ BNCallingConventionWithConfidence* callingConvention, BNFunctionParameter* params, size_t paramCount,
+ BNBoolWithConfidence* varArg, BNBoolWithConfidence* canReturn, BNOffsetWithConfidence* stackAdjust,
+ uint32_t* regStackAdjustRegs, BNOffsetWithConfidence* regStackAdjustValues, size_t regStackAdjustCount,
+ BNNameType ft, BNBoolWithConfidence* pure);
BINARYNINJACOREAPI BNType* BNCreateVarArgsType();
BINARYNINJACOREAPI BNType* BNCreateValueType(const char* value);
BINARYNINJACOREAPI char* BNGetNameTypeString(BNNameType classFunctionType);
@@ -7087,11 +7205,11 @@ extern "C"
uint64_t originalFragmentOffsetBytes, size_t originalFragmentWidthBytes, BNEndianness endianness,
size_t fragmentStartBit, size_t fragmentWidthBits, size_t fragmentTruncatedStartBits, size_t wrapBit);
BINARYNINJACOREAPI BNTypeBuilder* BNCreateArrayTypeBuilder(const BNTypeWithConfidence* const type, uint64_t elem);
- BINARYNINJACOREAPI BNTypeBuilder* BNCreateFunctionTypeBuilder(BNTypeWithConfidence* returnValue, BNCallingConventionWithConfidence* callingConvention,
- BNFunctionParameter* params, size_t paramCount, BNBoolWithConfidence* varArg,
- BNBoolWithConfidence* canReturn, BNOffsetWithConfidence* stackAdjust,
+ BINARYNINJACOREAPI BNTypeBuilder* BNCreateFunctionTypeBuilder(BNReturnValue* returnValue,
+ BNCallingConventionWithConfidence* callingConvention, BNFunctionParameter* params, size_t paramCount,
+ BNBoolWithConfidence* varArg, BNBoolWithConfidence* canReturn, BNOffsetWithConfidence* stackAdjust,
uint32_t* regStackAdjustRegs, BNOffsetWithConfidence* regStackAdjustValues, size_t regStackAdjustCount,
- BNRegisterSetWithConfidence* returnRegs, BNNameType ft, BNBoolWithConfidence* pure);
+ BNNameType ft, BNBoolWithConfidence* pure);
BINARYNINJACOREAPI BNTypeBuilder* BNCreateVarArgsTypeBuilder();
BINARYNINJACOREAPI BNTypeBuilder* BNCreateValueTypeBuilder(const char* value);
BINARYNINJACOREAPI BNType* BNFinalizeTypeBuilder(BNTypeBuilder* type);
@@ -7110,6 +7228,14 @@ extern "C"
BINARYNINJACOREAPI BNBoolWithConfidence BNIsTypeVolatile(BNType* type);
BINARYNINJACOREAPI bool BNIsTypeFloatingPoint(BNType* type);
BINARYNINJACOREAPI BNTypeWithConfidence BNGetChildType(BNType* type);
+ BINARYNINJACOREAPI BNReturnValue BNGetTypeReturnValue(BNType* type);
+ BINARYNINJACOREAPI bool BNIsTypeReturnValueDefaultLocation(BNType* type);
+ BINARYNINJACOREAPI BNValueLocationWithConfidence BNGetTypeReturnValueLocation(BNType* type);
+ BINARYNINJACOREAPI bool BNParseValueLocation(
+ const char* str, BNArchitecture* arch, BNValueLocation* location, char** error);
+ BINARYNINJACOREAPI char* BNValueLocationToString(BNValueLocation* location, BNArchitecture* arch);
+ BINARYNINJACOREAPI char* BNValueLocationComponentToString(BNValueLocationComponent* component, BNArchitecture* arch);
+ BINARYNINJACOREAPI void BNFreeValueLocation(BNValueLocation* location);
BINARYNINJACOREAPI BNCallingConventionWithConfidence BNGetTypeCallingConvention(BNType* type);
BINARYNINJACOREAPI BNCallingConventionName BNGetTypeCallingConventionName(BNType* type);
BINARYNINJACOREAPI BNFunctionParameter* BNGetTypeParameters(BNType* type, size_t* count);
@@ -7185,6 +7311,9 @@ extern "C"
BINARYNINJACOREAPI BNBoolWithConfidence BNIsTypeBuilderVolatile(BNTypeBuilder* type);
BINARYNINJACOREAPI bool BNIsTypeBuilderFloatingPoint(BNTypeBuilder* type);
BINARYNINJACOREAPI BNTypeWithConfidence BNGetTypeBuilderChildType(BNTypeBuilder* type);
+ BINARYNINJACOREAPI BNReturnValue BNGetTypeBuilderReturnValue(BNTypeBuilder* type);
+ BINARYNINJACOREAPI bool BNIsTypeBuilderReturnValueDefaultLocation(BNTypeBuilder* type);
+ BINARYNINJACOREAPI BNValueLocationWithConfidence BNGetTypeBuilderReturnValueLocation(BNTypeBuilder* type);
BINARYNINJACOREAPI BNCallingConventionWithConfidence BNGetTypeBuilderCallingConvention(BNTypeBuilder* type);
BINARYNINJACOREAPI BNCallingConventionName BNGetTypeBuilderCallingConventionName(BNTypeBuilder* type);
BINARYNINJACOREAPI BNFunctionParameter* BNGetTypeBuilderParameters(BNTypeBuilder* type, size_t* count);
@@ -7223,6 +7352,10 @@ extern "C"
BINARYNINJACOREAPI void BNTypeBuilderSetVolatile(BNTypeBuilder* type, BNBoolWithConfidence* vltl);
BINARYNINJACOREAPI void BNTypeBuilderSetSigned(BNTypeBuilder* type, BNBoolWithConfidence* sign);
BINARYNINJACOREAPI void BNTypeBuilderSetChildType(BNTypeBuilder* type, BNTypeWithConfidence* child);
+ BINARYNINJACOREAPI void BNTypeBuilderSetReturnValue(BNTypeBuilder* type, BNReturnValue* rv);
+ BINARYNINJACOREAPI void BNTypeBuilderSetIsReturnValueDefaultLocation(BNTypeBuilder* type, bool defaultLocation);
+ BINARYNINJACOREAPI void BNTypeBuilderSetReturnValueLocation(
+ BNTypeBuilder* type, BNValueLocationWithConfidence* location);
BINARYNINJACOREAPI void BNTypeBuilderSetCallingConvention(BNTypeBuilder* type, BNCallingConventionWithConfidence* cc);
BINARYNINJACOREAPI void BNTypeBuilderSetCallingConventionName(BNTypeBuilder* type, BNCallingConventionName cc);
BINARYNINJACOREAPI BNOffsetWithConfidence BNGetTypeBuilderStackAdjustment(BNTypeBuilder* type);
@@ -7630,21 +7763,51 @@ extern "C"
BNCallingConvention* cc, uint32_t reg, BNFunction* func);
BINARYNINJACOREAPI BNRegisterValue BNGetIncomingFlagValue(BNCallingConvention* cc, uint32_t reg, BNFunction* func);
- BINARYNINJACOREAPI BNVariable* BNGetVariablesForParametersDefaultPermittedArgs(
- BNCallingConvention* cc, const BNFunctionParameter* params, size_t paramCount, size_t* count);
- BINARYNINJACOREAPI BNVariable* BNGetVariablesForParameters(BNCallingConvention* cc,
- const BNFunctionParameter* params, size_t paramCount, const uint32_t* permittedArgs, size_t permittedArgCount,
- size_t* count);
+ BINARYNINJACOREAPI BNCallLayout BNGetCallLayout(BNCallingConvention* cc, BNBinaryView* view,
+ const BNReturnValue* returnValue, const BNFunctionParameter* params, size_t paramCount,
+ const uint32_t* permittedRegs, size_t permittedRegCount);
+ BINARYNINJACOREAPI BNCallLayout BNGetCallLayoutDefaultPermittedArgs(BNCallingConvention* cc, BNBinaryView* view,
+ const BNReturnValue* returnValue, const BNFunctionParameter* params, size_t paramCount);
+ BINARYNINJACOREAPI BNCallLayout BNGetDefaultCallLayout(BNCallingConvention* cc, BNBinaryView* view,
+ const BNReturnValue* returnValue, const BNFunctionParameter* params, size_t paramCount,
+ const uint32_t* permittedRegs, size_t permittedRegCount);
+ BINARYNINJACOREAPI BNCallLayout BNGetDefaultCallLayoutDefaultPermittedArgs(BNCallingConvention* cc,
+ BNBinaryView* view, const BNReturnValue* returnValue, const BNFunctionParameter* params, size_t paramCount);
+ BINARYNINJACOREAPI void BNFreeCallLayout(BNCallLayout* layout);
+ BINARYNINJACOREAPI BNValueLocation BNGetReturnValueLocation(
+ BNCallingConvention* cc, BNBinaryView* view, BNReturnValue* returnValue);
+ BINARYNINJACOREAPI BNValueLocation BNGetDefaultReturnValueLocation(
+ BNCallingConvention* cc, BNBinaryView* view, BNReturnValue* returnValue);
+ BINARYNINJACOREAPI BNValueLocation* BNGetParameterLocations(BNCallingConvention* cc, BNBinaryView* view,
+ BNValueLocation* returnValue, BNFunctionParameter* params, size_t paramCount, const uint32_t* permittedRegs,
+ size_t permittedRegCount, size_t* outCount);
+ BINARYNINJACOREAPI BNValueLocation* BNGetParameterLocationsDefaultPermittedArgs(BNCallingConvention* cc,
+ BNBinaryView* view, BNValueLocation* returnValue, BNFunctionParameter* params, size_t paramCount,
+ size_t* outCount);
+ BINARYNINJACOREAPI BNValueLocation* BNGetDefaultParameterLocations(BNCallingConvention* cc, BNBinaryView* view,
+ BNValueLocation* returnValue, BNFunctionParameter* params, size_t paramCount, const uint32_t* permittedRegs,
+ size_t permittedRegCount, size_t* outCount);
+ BINARYNINJACOREAPI BNValueLocation* BNGetDefaultParameterLocationsDefaultPermittedArgs(BNCallingConvention* cc,
+ BNBinaryView* view, BNValueLocation* returnValue, BNFunctionParameter* params, size_t paramCount,
+ size_t* outCount);
+ BINARYNINJACOREAPI void BNFreeValueLocationList(BNValueLocation* locations, size_t count);
+
BINARYNINJACOREAPI BNVariable* BNGetParameterOrderingForVariables(
BNCallingConvention* cc, const BNVariable* paramVars, const BNType** paramTypes,
size_t paramCount, size_t* count);
- BINARYNINJACOREAPI int64_t BNGetStackAdjustmentForVariables(
- BNCallingConvention* cc, const BNVariable* paramVars, const BNType** paramTypes,
- size_t paramCount);
- BINARYNINJACOREAPI size_t BNGetRegisterStackAdjustments(
- BNCallingConvention* cc, const uint32_t* returnRegs, size_t returnRegCount, BNType* returnType,
- const BNVariable* params, size_t paramCount, const BNType** types, size_t typeCount,
- uint32_t** resultRegisters, uint32_t** resultAdjustments);
+ BINARYNINJACOREAPI int64_t BNGetStackAdjustmentForLocations(BNCallingConvention* cc, BNBinaryView* view,
+ BNValueLocation* returnValue, const BNValueLocation* paramLocations, const BNType** paramTypes,
+ size_t paramCount);
+ BINARYNINJACOREAPI int64_t BNGetDefaultStackAdjustmentForLocations(BNCallingConvention* cc,
+ BNValueLocation* returnValue, const BNValueLocation* paramLocations, const BNType** paramTypes,
+ size_t paramCount);
+ BINARYNINJACOREAPI size_t BNGetCallingConventionRegisterStackAdjustments(BNCallingConvention* cc,
+ BNBinaryView* view, BNValueLocation* returnValue, BNValueLocation* params, size_t paramCount,
+ uint32_t** outRegs, int32_t** outAdjust);
+ BINARYNINJACOREAPI size_t BNGetCallingConventionDefaultRegisterStackAdjustments(BNCallingConvention* cc,
+ BNValueLocation* returnValue, BNValueLocation* params, size_t paramCount, uint32_t** outRegs,
+ int32_t** outAdjust);
+ BINARYNINJACOREAPI void BNFreeCallingConventionRegisterStackAdjustments(uint32_t* regs, int32_t* adjust);
BINARYNINJACOREAPI BNVariable BNGetIncomingVariableForParameterVariable(
BNCallingConvention* cc, const BNVariable* var, BNFunction* func);
@@ -7655,6 +7818,17 @@ extern "C"
BINARYNINJACOREAPI BNVariable BNGetDefaultParameterVariableForIncomingVariable(
BNCallingConvention* cc, const BNVariable* var);
+ BINARYNINJACOREAPI bool BNIsReturnTypeRegisterCompatible(BNCallingConvention* cc, BNBinaryView* view, BNType* type);
+ BINARYNINJACOREAPI bool BNDefaultIsReturnTypeRegisterCompatible(BNCallingConvention* cc, BNType* type);
+ BINARYNINJACOREAPI BNVariable BNGetIndirectReturnValueLocation(BNCallingConvention* cc);
+ BINARYNINJACOREAPI BNVariable BNGetDefaultIndirectReturnValueLocation(BNCallingConvention* cc);
+ BINARYNINJACOREAPI bool BNGetReturnedIndirectReturnValuePointer(BNCallingConvention* cc, BNVariable* outVar);
+ BINARYNINJACOREAPI bool BNIsArgumentTypeRegisterCompatible(
+ BNCallingConvention* cc, BNBinaryView* view, BNType* type);
+ BINARYNINJACOREAPI bool BNDefaultIsArgumentTypeRegisterCompatible(BNCallingConvention* cc, BNType* type);
+ BINARYNINJACOREAPI bool BNIsNonRegisterArgumentIndirect(BNCallingConvention* cc, BNBinaryView* view, BNType* type);
+ BINARYNINJACOREAPI bool BNAreStackArgumentsNaturallyAligned(BNCallingConvention* cc);
+
BINARYNINJACOREAPI BNCallingConvention* BNGetArchitectureDefaultCallingConvention(BNArchitecture* arch);
BINARYNINJACOREAPI BNCallingConvention* BNGetArchitectureCdeclCallingConvention(BNArchitecture* arch);
BINARYNINJACOREAPI BNCallingConvention* BNGetArchitectureStdcallCallingConvention(BNArchitecture* arch);
diff --git a/binaryview.cpp b/binaryview.cpp
index 6c4312c0..da6f5b0f 100644
--- a/binaryview.cpp
+++ b/binaryview.cpp
@@ -5847,6 +5847,26 @@ Ref<Relocation> BinaryView::GetNextRelocation(uint64_t addr, uint64_t maxAddr)
}
+vector<FunctionParameter> BinaryView::DerefParameterNamedTypeRefs(const vector<FunctionParameter>& params)
+{
+ vector<FunctionParameter> result;
+ result.reserve(params.size());
+ for (auto& i : params)
+ result.emplace_back(i.name, i.type->DerefNamedTypeReference(this)->WithConfidence(i.type.GetConfidence()),
+ i.locationSource, i.location);
+ return result;
+}
+
+
+ReturnValue BinaryView::DerefReturnValueNamedTypeRefs(const ReturnValue& returnValue)
+{
+ ReturnValue result = returnValue;
+ if (result.type.GetValue())
+ result.type.SetValue(result.type->DerefNamedTypeReference(this));
+ return result;
+}
+
+
Relocation::Relocation(BNRelocation* reloc)
{
m_object = reloc;
diff --git a/callingconvention.cpp b/callingconvention.cpp
index b7ee5bbe..66b814f1 100644
--- a/callingconvention.cpp
+++ b/callingconvention.cpp
@@ -24,6 +24,61 @@ using namespace std;
using namespace BinaryNinja;
+CallLayout CallLayout::FromAPIObject(BNCallLayout* layout)
+{
+ CallLayout result;
+ result.parameters.reserve(layout->parameterCount);
+ for (size_t i = 0; i < layout->parameterCount; i++)
+ result.parameters.push_back(ValueLocation::FromAPIObject(&layout->parameters[i]));
+ if (layout->returnValueValid)
+ result.returnValue = ValueLocation::FromAPIObject(&layout->returnValue);
+ result.stackAdjustment = layout->stackAdjustment;
+ for (size_t i = 0; i < layout->registerStackAdjustmentCount; i++)
+ {
+ result.registerStackAdjustments[layout->registerStackAdjustmentRegisters[i]] =
+ layout->registerStackAdjustmentAmounts[i];
+ }
+ return result;
+}
+
+
+BNCallLayout CallLayout::ToAPIObject() const
+{
+ BNCallLayout result;
+ result.parameters = new BNValueLocation[parameters.size()];
+ result.parameterCount = parameters.size();
+ for (size_t i = 0; i < parameters.size(); i++)
+ result.parameters[i] = parameters[i].ToAPIObject();
+ result.returnValue = returnValue.value_or(ValueLocation()).ToAPIObject();
+ result.returnValueValid = returnValue.has_value();
+ result.stackAdjustment = stackAdjustment;
+
+ result.registerStackAdjustmentCount = registerStackAdjustments.size();
+ result.registerStackAdjustmentRegisters = new uint32_t[registerStackAdjustments.size()];
+ result.registerStackAdjustmentAmounts = new int32_t[registerStackAdjustments.size()];
+ size_t i = 0;
+ for (auto [reg, adjust] : registerStackAdjustments)
+ {
+ result.registerStackAdjustmentRegisters[i] = reg;
+ result.registerStackAdjustmentAmounts[i] = adjust;
+ i++;
+ }
+
+ return result;
+}
+
+
+void CallLayout::FreeAPIObject(BNCallLayout* layout)
+{
+ for (size_t i = 0; i < layout->parameterCount; i++)
+ ValueLocation::FreeAPIObject(&layout->parameters[i]);
+ delete[] layout->parameters;
+ ValueLocation::FreeAPIObject(&layout->returnValue);
+ delete[] layout->registerStackAdjustmentRegisters;
+ delete[] layout->registerStackAdjustmentAmounts;
+}
+
+
CallingConvention::CallingConvention(BNCallingConvention* cc)
{
m_object = cc;
@@ -56,6 +111,21 @@ CallingConvention::CallingConvention(Architecture* arch, const string& name)
cc.getIncomingFlagValue = GetIncomingFlagValueCallback;
cc.getIncomingVariableForParameterVariable = GetIncomingVariableForParameterVariableCallback;
cc.getParameterVariableForIncomingVariable = GetParameterVariableForIncomingVariableCallback;
+ cc.isReturnTypeRegisterCompatible = IsReturnTypeRegisterCompatibleCallback;
+ cc.getIndirectReturnValueLocation = GetIndirectReturnValueLocationCallback;
+ cc.getReturnedIndirectReturnValuePointer = GetReturnedIndirectReturnValuePointerCallback;
+ cc.isArgumentTypeRegisterCompatible = IsArgumentTypeRegisterCompatibleCallback;
+ cc.isNonRegisterArgumentIndirect = IsNonRegisterArgumentIndirectCallback;
+ cc.areStackArgumentsNaturallyAligned = AreStackArgumentsNaturallyAlignedCallback;
+ cc.getCallLayout = GetCallLayoutCallback;
+ cc.freeCallLayout = FreeCallLayoutCallback;
+ cc.getReturnValueLocation = GetReturnValueLocationCallback;
+ cc.freeValueLocation = FreeValueLocationCallback;
+ cc.getParameterLocations = GetParameterLocationsCallback;
+ cc.freeParameterLocations = FreeParameterLocationsCallback;
+ cc.getStackAdjustmentForLocations = GetStackAdjustmentForLocationsCallback;
+ cc.getRegisterStackAdjustments = GetRegisterStackAdjustmentsCallback;
+ cc.freeRegisterStackAdjustments = FreeRegisterStackAdjustmentsCallback;
AddRefForRegistration();
m_object = BNCreateCallingConvention(arch->GetObject(), name.c_str(), &cc);
@@ -273,6 +343,222 @@ void CallingConvention::GetParameterVariableForIncomingVariableCallback(
}
+bool CallingConvention::IsReturnTypeRegisterCompatibleCallback(void* ctxt, BNBinaryView* view, BNType* type)
+{
+ CallbackRef<CallingConvention> cc(ctxt);
+ Ref<BinaryView> viewObj;
+ if (view)
+ viewObj = new BinaryView(BNNewViewReference(view));
+ Ref<Type> typeObj;
+ if (type)
+ typeObj = new Type(BNNewTypeReference(type));
+ return cc->IsReturnTypeRegisterCompatible(viewObj, typeObj);
+}
+
+
+void CallingConvention::GetIndirectReturnValueLocationCallback(void* ctxt, BNVariable* outVar)
+{
+ CallbackRef<CallingConvention> cc(ctxt);
+ *outVar = cc->GetIndirectReturnValueLocation();
+}
+
+
+bool CallingConvention::GetReturnedIndirectReturnValuePointerCallback(void* ctxt, BNVariable* outVar)
+{
+ CallbackRef<CallingConvention> cc(ctxt);
+ auto var = cc->GetReturnedIndirectReturnValuePointer();
+ if (var.has_value())
+ *outVar = var.value();
+ return var.has_value();
+}
+
+
+bool CallingConvention::IsArgumentTypeRegisterCompatibleCallback(void* ctxt, BNBinaryView* view, BNType* type)
+{
+ CallbackRef<CallingConvention> cc(ctxt);
+ Ref<BinaryView> viewObj;
+ if (view)
+ viewObj = new BinaryView(BNNewViewReference(view));
+ Ref<Type> typeObj;
+ if (type)
+ typeObj = new Type(BNNewTypeReference(type));
+ return cc->IsArgumentTypeRegisterCompatible(viewObj, typeObj);
+}
+
+
+bool CallingConvention::IsNonRegisterArgumentIndirectCallback(void* ctxt, BNBinaryView* view, BNType* type)
+{
+ CallbackRef<CallingConvention> cc(ctxt);
+ Ref<BinaryView> viewObj;
+ if (view)
+ viewObj = new BinaryView(BNNewViewReference(view));
+ Ref<Type> typeObj;
+ if (type)
+ typeObj = new Type(BNNewTypeReference(type));
+ return cc->IsNonRegisterArgumentIndirect(viewObj, typeObj);
+}
+
+
+bool CallingConvention::AreStackArgumentsNaturallyAlignedCallback(void* ctxt)
+{
+ CallbackRef<CallingConvention> cc(ctxt);
+ return cc->AreStackArgumentsNaturallyAligned();
+}
+
+
+void CallingConvention::GetCallLayoutCallback(void* ctxt, BNBinaryView* view, BNReturnValue* returnValue,
+ BNFunctionParameter* params, size_t paramCount, bool hasPermittedRegs, uint32_t* permittedRegs,
+ size_t permittedRegCount, BNCallLayout* result)
+{
+ CallbackRef<CallingConvention> cc(ctxt);
+ Ref<BinaryView> viewObj;
+ if (view)
+ viewObj = new BinaryView(BNNewViewReference(view));
+ auto ret = ReturnValue::FromAPIObject(returnValue);
+ vector<FunctionParameter> paramObjs;
+ paramObjs.reserve(paramCount);
+ for (size_t i = 0; i < paramCount; i++)
+ paramObjs.push_back(FunctionParameter::FromAPIObject(&params[i]));
+ optional<set<uint32_t>> regOpt;
+ if (hasPermittedRegs)
+ {
+ set<uint32_t> regs;
+ for (size_t i = 0; i < permittedRegCount; i++)
+ regs.insert(permittedRegs[i]);
+ regOpt = regs;
+ }
+
+ auto layout = cc->GetCallLayout(viewObj, ret, paramObjs, regOpt);
+ *result = layout.ToAPIObject();
+}
+
+
+void CallingConvention::FreeCallLayoutCallback(void*, BNCallLayout* layout)
+{
+ CallLayout::FreeAPIObject(layout);
+}
+
+
+void CallingConvention::GetReturnValueLocationCallback(
+ void* ctxt, BNBinaryView* view, BNReturnValue* returnValue, BNValueLocation* outLocation)
+{
+ CallbackRef<CallingConvention> cc(ctxt);
+ Ref<BinaryView> viewObj;
+ if (view)
+ viewObj = new BinaryView(BNNewViewReference(view));
+ ReturnValue ret = ReturnValue::FromAPIObject(returnValue);
+ ValueLocation location = cc->GetReturnValueLocation(viewObj, ret);
+ *outLocation = location.ToAPIObject();
+}
+
+
+void CallingConvention::FreeValueLocationCallback(void*, BNValueLocation* location)
+{
+ ValueLocation::FreeAPIObject(location);
+}
+
+
+BNValueLocation* CallingConvention::GetParameterLocationsCallback(void* ctxt, BNBinaryView* view,
+ BNValueLocation* returnValue, BNFunctionParameter* params, size_t paramCount, bool hasPermittedRegs,
+ uint32_t* permittedRegs, size_t permittedRegCount, size_t* outLocationCount)
+{
+ CallbackRef<CallingConvention> cc(ctxt);
+ Ref<BinaryView> viewObj;
+ if (view)
+ viewObj = new BinaryView(BNNewViewReference(view));
+ std::optional<ValueLocation> ret;
+ if (returnValue)
+ ret = ValueLocation::FromAPIObject(returnValue);
+ vector<FunctionParameter> paramObjs;
+ paramObjs.reserve(paramCount);
+ for (size_t i = 0; i < paramCount; i++)
+ paramObjs.push_back(FunctionParameter::FromAPIObject(&params[i]));
+ optional<set<uint32_t>> regOpt;
+ if (hasPermittedRegs)
+ {
+ set<uint32_t> regs;
+ for (size_t i = 0; i < permittedRegCount; i++)
+ regs.insert(permittedRegs[i]);
+ regOpt = regs;
+ }
+
+ vector<ValueLocation> locations = cc->GetParameterLocations(viewObj, ret, paramObjs, regOpt);
+
+ *outLocationCount = locations.size();
+ BNValueLocation* result = new BNValueLocation[locations.size()];
+ for (size_t i = 0; i < locations.size(); i++)
+ result[i] = locations[i].ToAPIObject();
+ return result;
+}
+
+
+void CallingConvention::FreeParameterLocationsCallback(void*, BNValueLocation* locations, size_t count)
+{
+ for (size_t i = 0; i < count; i++)
+ ValueLocation::FreeAPIObject(&locations[i]);
+ delete[] locations;
+}
+
+
+int64_t CallingConvention::GetStackAdjustmentForLocationsCallback(void* ctxt, BNBinaryView* view,
+ BNValueLocation* returnValue, BNValueLocation* locations, BNType** types, size_t paramCount)
+{
+ CallbackRef<CallingConvention> cc(ctxt);
+ Ref<BinaryView> viewObj;
+ if (view)
+ viewObj = new BinaryView(BNNewViewReference(view));
+ std::optional<ValueLocation> ret;
+ if (returnValue)
+ ret = ValueLocation::FromAPIObject(returnValue);
+ vector<ValueLocation> locationObjs;
+ locationObjs.reserve(paramCount);
+ for (size_t i = 0; i < paramCount; i++)
+ locationObjs.push_back(ValueLocation::FromAPIObject(&locations[i]));
+ vector<Ref<Type>> typeObjs;
+ typeObjs.reserve(paramCount);
+ for (size_t i = 0; i < paramCount; i++)
+ typeObjs.push_back(new Type(BNNewTypeReference(types[i])));
+
+ return cc->GetStackAdjustmentForLocations(viewObj, ret, locationObjs, typeObjs);
+}
+
+
+size_t CallingConvention::GetRegisterStackAdjustmentsCallback(void* ctxt, BNBinaryView* view,
+ BNValueLocation* returnValue, BNValueLocation* params, size_t paramCount, uint32_t** outRegs, int32_t** outAdjust)
+{
+ CallbackRef<CallingConvention> cc(ctxt);
+ Ref<BinaryView> viewObj;
+ if (view)
+ viewObj = new BinaryView(BNNewViewReference(view));
+ std::optional<ValueLocation> ret;
+ if (returnValue)
+ ret = ValueLocation::FromAPIObject(returnValue);
+ vector<ValueLocation> paramObjs;
+ paramObjs.reserve(paramCount);
+ for (size_t i = 0; i < paramCount; i++)
+ paramObjs.push_back(ValueLocation::FromAPIObject(&params[i]));
+
+ auto result = cc->GetRegisterStackAdjustments(viewObj, ret, paramObjs);
+
+ *outRegs = new uint32_t[result.size()];
+ *outAdjust = new int32_t[result.size()];
+ size_t i = 0;
+ for (auto it = result.begin(); it != result.end(); ++it, ++i)
+ {
+ (*outRegs)[i] = it->first;
+ (*outAdjust)[i] = it->second;
+ }
+ return result.size();
+}
+
+
+void CallingConvention::FreeRegisterStackAdjustmentsCallback(void*, uint32_t* regs, int32_t* adjust, size_t)
+{
+ delete[] regs;
+ delete[] adjust;
+}
+
+
Ref<Architecture> CallingConvention::GetArchitecture() const
{
return new CoreArchitecture(BNGetCallingConventionArchitecture(m_object));
@@ -410,6 +696,255 @@ Variable CallingConvention::GetParameterVariableForIncomingVariable(const Variab
}
+bool CallingConvention::IsReturnTypeRegisterCompatible(BinaryView*, Type* type)
+{
+ return DefaultIsReturnTypeRegisterCompatible(type);
+}
+
+
+bool CallingConvention::DefaultIsReturnTypeRegisterCompatible(Type* type)
+{
+ return BNDefaultIsReturnTypeRegisterCompatible(m_object, type ? type->GetObject() : nullptr);
+}
+
+
+Variable CallingConvention::GetIndirectReturnValueLocation()
+{
+ return GetDefaultIndirectReturnValueLocation();
+}
+
+
+Variable CallingConvention::GetDefaultIndirectReturnValueLocation()
+{
+ return BNGetDefaultIndirectReturnValueLocation(m_object);
+}
+
+
+std::optional<Variable> CallingConvention::GetReturnedIndirectReturnValuePointer()
+{
+ return std::nullopt;
+}
+
+
+bool CallingConvention::IsArgumentTypeRegisterCompatible(BinaryView*, Type* type)
+{
+ return DefaultIsArgumentTypeRegisterCompatible(type);
+}
+
+
+bool CallingConvention::DefaultIsArgumentTypeRegisterCompatible(Type* type)
+{
+ return BNDefaultIsArgumentTypeRegisterCompatible(m_object, type ? type->GetObject() : nullptr);
+}
+
+
+bool CallingConvention::IsNonRegisterArgumentIndirect(BinaryView*, Type*)
+{
+ return false;
+}
+
+
+bool CallingConvention::AreStackArgumentsNaturallyAligned()
+{
+ return false;
+}
+
+
+CallLayout CallingConvention::GetCallLayout(BinaryView* view, const ReturnValue& returnValue,
+ const vector<FunctionParameter>& params, const optional<set<uint32_t>>& permittedRegs)
+{
+ return GetDefaultCallLayout(view, returnValue, params, permittedRegs);
+}
+
+
+ValueLocation CallingConvention::GetReturnValueLocation(BinaryView* view, const ReturnValue& returnValue)
+{
+ return GetDefaultReturnValueLocation(view, returnValue);
+}
+
+
+vector<ValueLocation> CallingConvention::GetParameterLocations(BinaryView* view,
+ const optional<ValueLocation>& returnValue, const vector<FunctionParameter>& params,
+ const optional<set<uint32_t>>& permittedRegs)
+{
+ return GetDefaultParameterLocations(view, returnValue, params, permittedRegs);
+}
+
+
+int64_t CallingConvention::GetStackAdjustmentForLocations(BinaryView*, const std::optional<ValueLocation>& returnValue,
+ const std::vector<ValueLocation>& locations, const std::vector<Ref<Type>>& types)
+{
+ return GetDefaultStackAdjustmentForLocations(returnValue, locations, types);
+}
+
+
+std::map<uint32_t, int32_t> CallingConvention::GetRegisterStackAdjustments(
+ BinaryView*, const std::optional<ValueLocation>& returnValue, const std::vector<ValueLocation>& params)
+{
+ return GetDefaultRegisterStackAdjustments(returnValue, params);
+}
+
+
+CallLayout CallingConvention::GetDefaultCallLayout(BinaryView* view, const ReturnValue& returnValue,
+ const vector<FunctionParameter>& params, const optional<set<uint32_t>>& permittedRegs)
+{
+ BNReturnValue ret = returnValue.ToAPIObject();
+ BNFunctionParameter* paramArray = new BNFunctionParameter[params.size()];
+ for (size_t i = 0; i < params.size(); i++)
+ paramArray[i] = params[i].ToAPIObject();
+
+ BNCallLayout layout;
+ if (permittedRegs.has_value())
+ {
+ uint32_t* regs = new uint32_t[permittedRegs->size()];
+ size_t i = 0;
+ for (auto reg : *permittedRegs)
+ regs[i++] = reg;
+ layout = BNGetDefaultCallLayout(
+ m_object, view ? view->GetObject() : nullptr, &ret, paramArray, params.size(), regs, permittedRegs->size());
+ delete[] regs;
+ }
+ else
+ {
+ layout = BNGetDefaultCallLayoutDefaultPermittedArgs(
+ m_object, view ? view->GetObject() : nullptr, &ret, paramArray, params.size());
+ }
+
+ ReturnValue::FreeAPIObject(&ret);
+ for (size_t i = 0; i < params.size(); i++)
+ FunctionParameter::FreeAPIObject(&paramArray[i]);
+ delete[] paramArray;
+
+ CallLayout result = CallLayout::FromAPIObject(&layout);
+ BNFreeCallLayout(&layout);
+ return result;
+}
+
+
+ValueLocation CallingConvention::GetDefaultReturnValueLocation(BinaryView* view, const ReturnValue& returnValue)
+{
+ BNReturnValue ret = returnValue.ToAPIObject();
+ BNValueLocation location = BNGetDefaultReturnValueLocation(m_object, view ? view->GetObject() : nullptr, &ret);
+ ReturnValue::FreeAPIObject(&ret);
+
+ ValueLocation result = ValueLocation::FromAPIObject(&location);
+ BNFreeValueLocation(&location);
+ return result;
+}
+
+
+vector<ValueLocation> CallingConvention::GetDefaultParameterLocations(BinaryView* view,
+ const optional<ValueLocation>& returnValue, const vector<FunctionParameter>& params,
+ const optional<set<uint32_t>>& permittedRegs)
+{
+ BNValueLocation* retOpt = nullptr;
+ BNValueLocation ret;
+ if (returnValue.has_value())
+ {
+ ret = returnValue->ToAPIObject();
+ retOpt = &ret;
+ }
+ BNFunctionParameter* paramArray = new BNFunctionParameter[params.size()];
+ for (size_t i = 0; i < params.size(); i++)
+ paramArray[i] = params[i].ToAPIObject();
+
+ size_t locationCount = 0;
+ BNValueLocation* locations;
+ if (permittedRegs.has_value())
+ {
+ uint32_t* regs = new uint32_t[permittedRegs->size()];
+ size_t i = 0;
+ for (auto reg : *permittedRegs)
+ regs[i++] = reg;
+ locations = BNGetDefaultParameterLocations(m_object, view ? view->GetObject() : nullptr, retOpt, paramArray,
+ params.size(), regs, permittedRegs->size(), &locationCount);
+ delete[] regs;
+ }
+ else
+ {
+ locations = BNGetDefaultParameterLocationsDefaultPermittedArgs(
+ m_object, view ? view->GetObject() : nullptr, retOpt, paramArray, params.size(), &locationCount);
+ }
+
+ if (retOpt)
+ ValueLocation::FreeAPIObject(retOpt);
+ for (size_t i = 0; i < params.size(); i++)
+ FunctionParameter::FreeAPIObject(&paramArray[i]);
+ delete[] paramArray;
+
+ vector<ValueLocation> result;
+ result.reserve(locationCount);
+ for (size_t i = 0; i < locationCount; i++)
+ result.push_back(ValueLocation::FromAPIObject(&locations[i]));
+ BNFreeValueLocationList(locations, locationCount);
+ return result;
+}
+
+
+int64_t CallingConvention::GetDefaultStackAdjustmentForLocations(const std::optional<ValueLocation>& returnValue,
+ const std::vector<ValueLocation>& locations, const std::vector<Ref<Type>>& types)
+{
+ BNValueLocation* retOpt = nullptr;
+ BNValueLocation ret;
+ if (returnValue.has_value())
+ {
+ ret = returnValue->ToAPIObject();
+ retOpt = &ret;
+ }
+ size_t count = locations.size();
+ if (types.size() < count)
+ count = types.size();
+ BNValueLocation* locationArray = new BNValueLocation[count];
+ for (size_t i = 0; i < count; i++)
+ locationArray[i] = locations[i].ToAPIObject();
+ const BNType** typeArray = new const BNType*[count];
+ for (size_t i = 0; i < count; i++)
+ typeArray[i] = types[i] ? types[i]->GetObject() : nullptr;
+
+ int64_t result = BNGetDefaultStackAdjustmentForLocations(m_object, retOpt, locationArray, typeArray, count);
+ if (retOpt)
+ ValueLocation::FreeAPIObject(retOpt);
+ for (size_t i = 0; i < count; i++)
+ ValueLocation::FreeAPIObject(&locationArray[i]);
+ delete[] locationArray;
+ delete[] typeArray;
+ return result;
+}
+
+
+std::map<uint32_t, int32_t> CallingConvention::GetDefaultRegisterStackAdjustments(
+ const std::optional<ValueLocation>& returnValue, const std::vector<ValueLocation>& params)
+{
+ BNValueLocation* retOpt = nullptr;
+ BNValueLocation ret;
+ if (returnValue.has_value())
+ {
+ ret = returnValue->ToAPIObject();
+ retOpt = &ret;
+ }
+ BNValueLocation* paramArray = new BNValueLocation[params.size()];
+ for (size_t i = 0; i < params.size(); i++)
+ paramArray[i] = params[i].ToAPIObject();
+
+ uint32_t* regs = nullptr;
+ int32_t* adjust = nullptr;
+ size_t count = BNGetCallingConventionDefaultRegisterStackAdjustments(
+ m_object, retOpt, paramArray, params.size(), &regs, &adjust);
+
+ if (retOpt)
+ ValueLocation::FreeAPIObject(retOpt);
+ for (size_t i = 0; i < params.size(); i++)
+ ValueLocation::FreeAPIObject(&paramArray[i]);
+ delete[] paramArray;
+
+ map<uint32_t, int32_t> result;
+ for (size_t i = 0; i < count; i++)
+ result[regs[i]] = adjust[i];
+ BNFreeCallingConventionRegisterStackAdjustments(regs, adjust);
+ return result;
+}
+
+
CoreCallingConvention::CoreCallingConvention(BNCallingConvention* cc) : CallingConvention(cc) {}
@@ -566,3 +1101,207 @@ Variable CoreCallingConvention::GetParameterVariableForIncomingVariable(const Va
{
return BNGetParameterVariableForIncomingVariable(m_object, &var, func ? func->GetObject() : nullptr);
}
+
+
+bool CoreCallingConvention::IsReturnTypeRegisterCompatible(BinaryView* view, Type* type)
+{
+ return BNIsReturnTypeRegisterCompatible(
+ m_object, view ? view->GetObject() : nullptr, type ? type->GetObject() : nullptr);
+}
+
+
+Variable CoreCallingConvention::GetIndirectReturnValueLocation()
+{
+ return BNGetIndirectReturnValueLocation(m_object);
+}
+
+
+std::optional<Variable> CoreCallingConvention::GetReturnedIndirectReturnValuePointer()
+{
+ BNVariable var;
+ if (BNGetReturnedIndirectReturnValuePointer(m_object, &var))
+ return var;
+ return std::nullopt;
+}
+
+
+bool CoreCallingConvention::IsArgumentTypeRegisterCompatible(BinaryView* view, Type* type)
+{
+ return BNIsArgumentTypeRegisterCompatible(
+ m_object, view ? view->GetObject() : nullptr, type ? type->GetObject() : nullptr);
+}
+
+
+bool CoreCallingConvention::IsNonRegisterArgumentIndirect(BinaryView* view, Type* type)
+{
+ return BNIsNonRegisterArgumentIndirect(
+ m_object, view ? view->GetObject() : nullptr, type ? type->GetObject() : nullptr);
+}
+
+
+bool CoreCallingConvention::AreStackArgumentsNaturallyAligned()
+{
+ return BNAreStackArgumentsNaturallyAligned(m_object);
+}
+
+
+CallLayout CoreCallingConvention::GetCallLayout(BinaryView* view, const ReturnValue& returnValue,
+ const vector<FunctionParameter>& params, const optional<set<uint32_t>>& permittedRegs)
+{
+ BNReturnValue ret = returnValue.ToAPIObject();
+ BNFunctionParameter* paramArray = new BNFunctionParameter[params.size()];
+ for (size_t i = 0; i < params.size(); i++)
+ paramArray[i] = params[i].ToAPIObject();
+
+ BNCallLayout layout;
+ if (permittedRegs.has_value())
+ {
+ uint32_t* regs = new uint32_t[permittedRegs->size()];
+ size_t i = 0;
+ for (auto reg : *permittedRegs)
+ regs[i++] = reg;
+ layout = BNGetCallLayout(
+ m_object, view ? view->GetObject() : nullptr, &ret, paramArray, params.size(), regs, permittedRegs->size());
+ delete[] regs;
+ }
+ else
+ {
+ layout = BNGetCallLayoutDefaultPermittedArgs(
+ m_object, view ? view->GetObject() : nullptr, &ret, paramArray, params.size());
+ }
+
+ ReturnValue::FreeAPIObject(&ret);
+ for (size_t i = 0; i < params.size(); i++)
+ FunctionParameter::FreeAPIObject(&paramArray[i]);
+ delete[] paramArray;
+
+ CallLayout result = CallLayout::FromAPIObject(&layout);
+ BNFreeCallLayout(&layout);
+ return result;
+}
+
+
+ValueLocation CoreCallingConvention::GetReturnValueLocation(BinaryView* view, const ReturnValue& returnValue)
+{
+ BNReturnValue ret = returnValue.ToAPIObject();
+ BNValueLocation location = BNGetReturnValueLocation(m_object, view ? view->GetObject() : nullptr, &ret);
+ ReturnValue::FreeAPIObject(&ret);
+
+ ValueLocation result = ValueLocation::FromAPIObject(&location);
+ BNFreeValueLocation(&location);
+ return result;
+}
+
+
+vector<ValueLocation> CoreCallingConvention::GetParameterLocations(BinaryView* view,
+ const optional<ValueLocation>& returnValue, const vector<FunctionParameter>& params,
+ const optional<set<uint32_t>>& permittedRegs)
+{
+ BNValueLocation* retOpt = nullptr;
+ BNValueLocation ret;
+ if (returnValue.has_value())
+ {
+ ret = returnValue->ToAPIObject();
+ retOpt = &ret;
+ }
+ BNFunctionParameter* paramArray = new BNFunctionParameter[params.size()];
+ for (size_t i = 0; i < params.size(); i++)
+ paramArray[i] = params[i].ToAPIObject();
+
+ size_t locationCount = 0;
+ BNValueLocation* locations;
+ if (permittedRegs.has_value())
+ {
+ uint32_t* regs = new uint32_t[permittedRegs->size()];
+ size_t i = 0;
+ for (auto reg : *permittedRegs)
+ regs[i++] = reg;
+ locations = BNGetParameterLocations(m_object, view ? view->GetObject() : nullptr, retOpt, paramArray,
+ params.size(), regs, permittedRegs->size(), &locationCount);
+ delete[] regs;
+ }
+ else
+ {
+ locations = BNGetParameterLocationsDefaultPermittedArgs(
+ m_object, view ? view->GetObject() : nullptr, retOpt, paramArray, params.size(), &locationCount);
+ }
+
+ if (retOpt)
+ ValueLocation::FreeAPIObject(retOpt);
+ for (size_t i = 0; i < params.size(); i++)
+ FunctionParameter::FreeAPIObject(&paramArray[i]);
+ delete[] paramArray;
+
+ vector<ValueLocation> result;
+ result.reserve(locationCount);
+ for (size_t i = 0; i < locationCount; i++)
+ result.push_back(ValueLocation::FromAPIObject(&locations[i]));
+ BNFreeValueLocationList(locations, locationCount);
+ return result;
+}
+
+
+int64_t CoreCallingConvention::GetStackAdjustmentForLocations(BinaryView* view,
+ const std::optional<ValueLocation>& returnValue, const std::vector<ValueLocation>& locations,
+ const std::vector<Ref<Type>>& types)
+{
+ BNValueLocation* retOpt = nullptr;
+ BNValueLocation ret;
+ if (returnValue.has_value())
+ {
+ ret = returnValue->ToAPIObject();
+ retOpt = &ret;
+ }
+ size_t count = locations.size();
+ if (types.size() < count)
+ count = types.size();
+ BNValueLocation* locationArray = new BNValueLocation[count];
+ for (size_t i = 0; i < count; i++)
+ locationArray[i] = locations[i].ToAPIObject();
+ const BNType** typeArray = new const BNType*[count];
+ for (size_t i = 0; i < count; i++)
+ typeArray[i] = types[i] ? types[i]->GetObject() : nullptr;
+
+ int64_t result = BNGetStackAdjustmentForLocations(
+ m_object, view ? view->GetObject() : nullptr, retOpt, locationArray, typeArray, count);
+ if (retOpt)
+ ValueLocation::FreeAPIObject(retOpt);
+ for (size_t i = 0; i < count; i++)
+ ValueLocation::FreeAPIObject(&locationArray[i]);
+ delete[] locationArray;
+ delete[] typeArray;
+ return result;
+}
+
+
+std::map<uint32_t, int32_t> CoreCallingConvention::GetRegisterStackAdjustments(
+ BinaryView* view, const std::optional<ValueLocation>& returnValue, const std::vector<ValueLocation>& params)
+{
+ BNValueLocation* retOpt = nullptr;
+ BNValueLocation ret;
+ if (returnValue.has_value())
+ {
+ ret = returnValue->ToAPIObject();
+ retOpt = &ret;
+ }
+ BNValueLocation* paramArray = new BNValueLocation[params.size()];
+ for (size_t i = 0; i < params.size(); i++)
+ paramArray[i] = params[i].ToAPIObject();
+
+ uint32_t* regs = nullptr;
+ int32_t* adjust = nullptr;
+ size_t count = BNGetCallingConventionRegisterStackAdjustments(
+ m_object, view ? view->GetObject() : nullptr, retOpt, paramArray, params.size(), &regs, &adjust);
+
+ if (retOpt)
+ ValueLocation::FreeAPIObject(retOpt);
+ for (size_t i = 0; i < params.size(); i++)
+ ValueLocation::FreeAPIObject(&paramArray[i]);
+ delete[] paramArray;
+
+ map<uint32_t, int32_t> result;
+ for (size_t i = 0; i < count; i++)
+ result[regs[i]] = adjust[i];
+ BNFreeCallingConventionRegisterStackAdjustments(regs, adjust);
+ return result;
+}
diff --git a/demangler/gnu3/demangled_type_node.cpp b/demangler/gnu3/demangled_type_node.cpp
index 89bfb2fa..a52f9ef8 100644
--- a/demangler/gnu3/demangled_type_node.cpp
+++ b/demangler/gnu3/demangled_type_node.cpp
@@ -502,7 +502,7 @@ Ref<Type> DemangledTypeNode::Finalize() const
for (auto& p : m_params)
{
Ref<Type> pType = p.type ? p.type->Finalize() : Ref<Type>(Type::VoidType());
- finalParams.push_back({p.name, pType, true, Variable()});
+ finalParams.push_back({p.name, pType, DefaultLocationSource, Variable()});
}
TypeBuilder tb = TypeBuilder::FunctionType(retType->WithConfidence(m_returnTypeConfidence), nullptr, finalParams);
tb.SetConst(m_const);
diff --git a/demangler/msvc/demangle_msvc.cpp b/demangler/msvc/demangle_msvc.cpp
index 0489c341..412ed960 100644
--- a/demangler/msvc/demangle_msvc.cpp
+++ b/demangler/msvc/demangle_msvc.cpp
@@ -732,7 +732,7 @@ void Demangle::DemangleVariableList(vector<FunctionParameter>& paramList, Backre
}
vt.name = name.GetString();
vt.type = type.Finalize();
- vt.defaultLocation = true;
+ vt.locationSource = DefaultLocationSource;
paramList.push_back(vt);
m_logger->LogDebug("Argument %zu: '%s' - '%s'\n", i, vt.type->GetString().c_str(), reader.GetRaw());
@@ -1607,7 +1607,7 @@ TypeBuilder Demangle::DemangleFunction(BNNameType classFunctionType, bool pointe
QualifiedName thisName = m_varName;
if (thisName.size() > 0)
thisName.erase(thisName.end() - 1);
- params.push_back(FunctionParameter("this", Type::PointerType(m_arch, Type::NamedType(thisName, Type::VoidType())), true, {}));
+ params.push_back(FunctionParameter("this", Type::PointerType(m_arch, Type::NamedType(thisName, Type::VoidType())), DefaultLocationSource, {}));
}
DemangleVariableList(params, m_backrefList);
diff --git a/examples/mlil_parser/src/mlil_parser.cpp b/examples/mlil_parser/src/mlil_parser.cpp
index 11fabdaa..7236eff8 100644
--- a/examples/mlil_parser/src/mlil_parser.cpp
+++ b/examples/mlil_parser/src/mlil_parser.cpp
@@ -99,6 +99,8 @@ static void PrintOperation(BNMediumLevelILOperation operation)
ENUM_PRINTER(MLIL_SEPARATE_PARAM_LIST)
ENUM_PRINTER(MLIL_SHARED_PARAM_SLOT)
ENUM_PRINTER(MLIL_VAR_OUTPUT)
+ ENUM_PRINTER(MLIL_VAR_OUTPUT_FIELD)
+ ENUM_PRINTER(MLIL_STORE_OUTPUT)
ENUM_PRINTER(MLIL_BP)
ENUM_PRINTER(MLIL_TRAP)
ENUM_PRINTER(MLIL_UNDEF)
@@ -122,6 +124,9 @@ static void PrintOperation(BNMediumLevelILOperation operation)
ENUM_PRINTER(MLIL_CALL_PARAM_SSA)
ENUM_PRINTER(MLIL_CALL_OUTPUT_SSA)
ENUM_PRINTER(MLIL_VAR_OUTPUT_SSA)
+ ENUM_PRINTER(MLIL_VAR_OUTPUT_SSA_FIELD)
+ ENUM_PRINTER(MLIL_VAR_OUTPUT_ALIASED)
+ ENUM_PRINTER(MLIL_VAR_OUTPUT_ALIASED_FIELD)
ENUM_PRINTER(MLIL_LOAD_SSA)
ENUM_PRINTER(MLIL_LOAD_STRUCT_SSA)
ENUM_PRINTER(MLIL_STORE_SSA)
diff --git a/function.cpp b/function.cpp
index 094a50db..bd7003e0 100644
--- a/function.cpp
+++ b/function.cpp
@@ -41,6 +41,24 @@ Variable Variable::FromIdentifier(uint64_t id)
}
+Variable Variable::Register(uint32_t reg)
+{
+ return Variable(RegisterVariableSourceType, reg);
+}
+
+
+Variable Variable::Flag(uint32_t flag)
+{
+ return Variable(FlagVariableSourceType, flag);
+}
+
+
+Variable Variable::StackOffset(int64_t offset)
+{
+ return Variable(StackVariableSourceType, offset);
+}
+
+
RegisterValue::RegisterValue() : state(UndeterminedValue), value(0), offset(0), size(0) {}
@@ -63,6 +81,12 @@ bool RegisterValue::operator==(const RegisterValue& a) const
case StackFrameOffset:
return (state == StackFrameOffset) && (a.value == value);
+ case ResultPointerValue:
+ return (state == ResultPointerValue) && (a.value == value);
+
+ case ParameterPointerValue:
+ return (state == ParameterPointerValue) && (a.value == value) && (a.offset == offset);
+
case UndeterminedValue:
return state == UndeterminedValue;
@@ -729,6 +753,30 @@ Confidence<Ref<Type>> Function::GetReturnType() const
}
+ReturnValue Function::GetReturnValue() const
+{
+ BNReturnValue ret = BNGetFunctionReturnValue(m_object);
+ ReturnValue result = ReturnValue::FromAPIObject(&ret);
+ BNFreeReturnValue(&ret);
+ return result;
+}
+
+
+bool Function::IsReturnValueDefaultLocation() const
+{
+ return BNIsFunctionReturnValueDefaultLocation(m_object);
+}
+
+
+Confidence<ValueLocation> Function::GetReturnValueLocation() const
+{
+ auto location = BNGetFunctionReturnValueLocation(m_object);
+ Confidence<ValueLocation> result(ValueLocation::FromAPIObject(&location.location), location.confidence);
+ BNFreeValueLocation(&location.location);
+ return result;
+}
+
+
Confidence<vector<uint32_t>> Function::GetReturnRegisters() const
{
BNRegisterSetWithConfidence regs = BNGetFunctionReturnRegisters(m_object);
@@ -763,6 +811,19 @@ Confidence<vector<Variable>> Function::GetParameterVariables() const
}
+Confidence<vector<ValueLocation>> Function::GetParameterLocations() const
+{
+ BNValueLocationListWithConfidence locations = BNGetFunctionParameterLocations(m_object);
+ vector<ValueLocation> locationList;
+ locationList.reserve(locations.count);
+ for (size_t i = 0; i < locations.count; i++)
+ locationList.push_back(ValueLocation::FromAPIObject(&locations.locations[i]));
+ Confidence<vector<ValueLocation>> result(locationList, locations.confidence);
+ BNFreeParameterLocations(&locations);
+ return result;
+}
+
+
Confidence<bool> Function::HasVariableArguments() const
{
BNBoolWithConfidence bc = BNFunctionHasVariableArguments(m_object);
@@ -817,16 +878,27 @@ void Function::SetAutoReturnType(const Confidence<Ref<Type>>& type)
}
-void Function::SetAutoReturnRegisters(const Confidence<std::vector<uint32_t>>& returnRegs)
+void Function::SetAutoReturnValue(const ReturnValue& rv)
{
- BNRegisterSetWithConfidence regs;
- regs.regs = new uint32_t[returnRegs.GetValue().size()];
- regs.count = returnRegs.GetValue().size();
- for (size_t i = 0; i < regs.count; i++)
- regs.regs[i] = returnRegs.GetValue()[i];
- regs.confidence = returnRegs.GetConfidence();
- BNSetAutoFunctionReturnRegisters(m_object, &regs);
- delete[] regs.regs;
+ BNReturnValue ret = rv.ToAPIObject();
+ BNSetAutoFunctionReturnValue(m_object, &ret);
+ ReturnValue::FreeAPIObject(&ret);
+}
+
+
+void Function::SetAutoIsReturnValueDefaultLocation(bool defaultLocation)
+{
+ BNSetAutoIsFunctionReturnValueDefaultLocation(m_object, defaultLocation);
+}
+
+
+void Function::SetAutoReturnValueLocation(const Confidence<ValueLocation>& location)
+{
+ BNValueLocationWithConfidence loc;
+ loc.location = location->ToAPIObject();
+ loc.confidence = location.GetConfidence();
+ BNSetAutoFunctionReturnValueLocation(m_object, &loc);
+ ValueLocation::FreeAPIObject(&loc.location);
}
@@ -839,22 +911,21 @@ void Function::SetAutoCallingConvention(const Confidence<Ref<CallingConvention>>
}
-void Function::SetAutoParameterVariables(const Confidence<vector<Variable>>& vars)
+void Function::SetAutoParameterLocations(const Confidence<std::vector<ValueLocation>>& locations)
{
- BNParameterVariablesWithConfidence varConf;
- varConf.vars = new BNVariable[vars->size()];
- varConf.count = vars->size();
+ BNValueLocationListWithConfidence varConf;
+ varConf.locations = new BNValueLocation[locations->size()];
+ varConf.count = locations->size();
size_t i = 0;
- for (auto it = vars->begin(); it != vars->end(); ++it, ++i)
- {
- varConf.vars[i].type = it->type;
- varConf.vars[i].index = it->index;
- varConf.vars[i].storage = it->storage;
- }
- varConf.confidence = vars.GetConfidence();
+ for (auto it = locations->begin(); it != locations->end(); ++it, ++i)
+ varConf.locations[i] = it->ToAPIObject();
+ varConf.confidence = locations.GetConfidence();
- BNSetAutoFunctionParameterVariables(m_object, &varConf);
- delete[] varConf.vars;
+ BNSetAutoFunctionParameterLocations(m_object, &varConf);
+
+ for (i = 0; i < locations->size(); i++)
+ ValueLocation::FreeAPIObject(&varConf.locations[i]);
+ delete[] varConf.locations;
}
@@ -946,16 +1017,27 @@ void Function::SetReturnType(const Confidence<Ref<Type>>& type)
}
-void Function::SetReturnRegisters(const Confidence<std::vector<uint32_t>>& returnRegs)
+void Function::SetReturnValue(const ReturnValue& rv)
{
- BNRegisterSetWithConfidence regs;
- regs.regs = new uint32_t[returnRegs.GetValue().size()];
- regs.count = returnRegs.GetValue().size();
- for (size_t i = 0; i < regs.count; i++)
- regs.regs[i] = returnRegs.GetValue()[i];
- regs.confidence = returnRegs.GetConfidence();
- BNSetUserFunctionReturnRegisters(m_object, &regs);
- delete[] regs.regs;
+ BNReturnValue ret = rv.ToAPIObject();
+ BNSetUserFunctionReturnValue(m_object, &ret);
+ ReturnValue::FreeAPIObject(&ret);
+}
+
+
+void Function::SetIsReturnValueDefaultLocation(bool defaultLocation)
+{
+ BNSetUserIsFunctionReturnValueDefaultLocation(m_object, defaultLocation);
+}
+
+
+void Function::SetReturnValueLocation(const Confidence<ValueLocation>& location)
+{
+ BNValueLocationWithConfidence loc;
+ loc.location = location->ToAPIObject();
+ loc.confidence = location.GetConfidence();
+ BNSetUserFunctionReturnValueLocation(m_object, &loc);
+ ValueLocation::FreeAPIObject(&loc.location);
}
@@ -968,22 +1050,21 @@ void Function::SetCallingConvention(const Confidence<Ref<CallingConvention>>& co
}
-void Function::SetParameterVariables(const Confidence<vector<Variable>>& vars)
+void Function::SetParameterLocations(const Confidence<std::vector<ValueLocation>>& locations)
{
- BNParameterVariablesWithConfidence varConf;
- varConf.vars = new BNVariable[vars->size()];
- varConf.count = vars->size();
+ BNValueLocationListWithConfidence varConf;
+ varConf.locations = new BNValueLocation[locations->size()];
+ varConf.count = locations->size();
size_t i = 0;
- for (auto it = vars->begin(); it != vars->end(); ++it, ++i)
- {
- varConf.vars[i].type = it->type;
- varConf.vars[i].index = it->index;
- varConf.vars[i].storage = it->storage;
- }
- varConf.confidence = vars.GetConfidence();
+ for (auto it = locations->begin(); it != locations->end(); ++it, ++i)
+ varConf.locations[i] = it->ToAPIObject();
+ varConf.confidence = locations.GetConfidence();
+
+ BNSetUserFunctionParameterLocations(m_object, &varConf);
- BNSetUserFunctionParameterVariables(m_object, &varConf);
- delete[] varConf.vars;
+ for (i = 0; i < locations->size(); i++)
+ ValueLocation::FreeAPIObject(&varConf.locations[i]);
+ delete[] varConf.locations;
}
diff --git a/highlevelilinstruction.cpp b/highlevelilinstruction.cpp
index f155ce03..0ce32c27 100644
--- a/highlevelilinstruction.cpp
+++ b/highlevelilinstruction.cpp
@@ -159,6 +159,8 @@ static constexpr std::array s_instructionOperandUsage = {
OperandUsage{HLIL_DEREF, {SourceExprHighLevelOperandUsage}},
OperandUsage{HLIL_DEREF_FIELD, {SourceExprHighLevelOperandUsage, OffsetHighLevelOperandUsage, MemberIndexHighLevelOperandUsage}},
OperandUsage{HLIL_ADDRESS_OF, {SourceExprHighLevelOperandUsage}},
+ OperandUsage{HLIL_PASS_BY_REF, {SourceExprHighLevelOperandUsage}},
+ OperandUsage{HLIL_RETURN_BY_REF, {SourceExprHighLevelOperandUsage}},
OperandUsage{HLIL_CONST, {ConstantHighLevelOperandUsage}},
OperandUsage{HLIL_CONST_DATA, {ConstantDataHighLevelOperandUsage}},
OperandUsage{HLIL_CONST_PTR, {ConstantHighLevelOperandUsage}},
@@ -1275,6 +1277,8 @@ void HighLevelILInstruction::CollectSubExprs(stack<size_t>& toProcess) const
case HLIL_FLOOR:
case HLIL_CEIL:
case HLIL_FTRUNC:
+ case HLIL_PASS_BY_REF:
+ case HLIL_RETURN_BY_REF:
toProcess.push(AsOneOperand().GetSourceExpr().exprIndex);
break;
case HLIL_ADD:
@@ -1581,6 +1585,8 @@ ExprId HighLevelILInstruction::CopyTo(
case HLIL_FLOOR:
case HLIL_CEIL:
case HLIL_FTRUNC:
+ case HLIL_PASS_BY_REF:
+ case HLIL_RETURN_BY_REF:
return dest->AddExprWithLocation(operation, loc, size, subExprHandler(AsOneOperand().GetSourceExpr()));
case HLIL_ADD:
case HLIL_SUB:
@@ -2139,6 +2145,8 @@ bool HighLevelILInstruction::operator<(const HighLevelILInstruction& other) cons
case HLIL_FLOOR:
case HLIL_CEIL:
case HLIL_FTRUNC:
+ case HLIL_PASS_BY_REF:
+ case HLIL_RETURN_BY_REF:
if (size < other.size)
return true;
if (size > other.size)
@@ -2851,6 +2859,18 @@ ExprId HighLevelILFunction::AddressOf(ExprId src, const ILSourceLocation& loc)
}
+ExprId HighLevelILFunction::PassByRef(size_t size, ExprId src, const ILSourceLocation& loc)
+{
+ return AddExprWithLocation(HLIL_PASS_BY_REF, loc, size, src);
+}
+
+
+ExprId HighLevelILFunction::ReturnByRef(size_t size, ExprId src, const ILSourceLocation& loc)
+{
+ return AddExprWithLocation(HLIL_RETURN_BY_REF, loc, size, src);
+}
+
+
ExprId HighLevelILFunction::Const(size_t size, uint64_t val, const ILSourceLocation& loc)
{
return AddExprWithLocation(HLIL_CONST, loc, size, val);
diff --git a/highlevelilinstruction.h b/highlevelilinstruction.h
index 0e7fdc60..7ec5d18c 100644
--- a/highlevelilinstruction.h
+++ b/highlevelilinstruction.h
@@ -1498,6 +1498,12 @@ namespace BinaryNinja
template <>
struct HighLevelILInstructionAccessor<HLIL_FTRUNC> : public HighLevelILOneOperandInstruction
{};
+ template <>
+ struct HighLevelILInstructionAccessor<HLIL_PASS_BY_REF> : public HighLevelILOneOperandInstruction
+ {};
+ template <>
+ struct HighLevelILInstructionAccessor<HLIL_RETURN_BY_REF> : public HighLevelILOneOperandInstruction
+ {};
#undef _STD_VECTOR
#undef _STD_SET
diff --git a/lang/c/pseudoc.cpp b/lang/c/pseudoc.cpp
index 592e224f..35966230 100644
--- a/lang/c/pseudoc.cpp
+++ b/lang/c/pseudoc.cpp
@@ -1816,6 +1816,32 @@ void PseudoCFunction::GetExprTextInternal(const HighLevelILInstruction& instr, H
}();
break;
+ case HLIL_PASS_BY_REF:
+ [&]() {
+ const auto srcExpr = instr.GetSourceExpr<HLIL_PASS_BY_REF>();
+ if (srcExpr.operation == HLIL_ADDRESS_OF)
+ {
+ GetExprTextInternal(srcExpr.GetSourceExpr<HLIL_ADDRESS_OF>(), tokens, settings, precedence);
+ }
+ else
+ {
+ tokens.Append(OperationToken, "*");
+ GetExprTextInternal(srcExpr, tokens, settings, UnaryOperatorPrecedence);
+ }
+ if (statement)
+ tokens.AppendSemicolon();
+ }();
+ break;
+
+ case HLIL_RETURN_BY_REF:
+ [&]() {
+ const auto srcExpr = instr.GetSourceExpr<HLIL_RETURN_BY_REF>();
+ GetExprTextInternal(srcExpr, tokens, settings, UnaryOperatorPrecedence);
+ if (statement)
+ tokens.AppendSemicolon();
+ }();
+ break;
+
case HLIL_FCMP_E:
[&]() {
bool parens = precedence > EqualityOperatorPrecedence;
diff --git a/lang/rust/pseudorust.cpp b/lang/rust/pseudorust.cpp
index 92e9e56a..2e233550 100644
--- a/lang/rust/pseudorust.cpp
+++ b/lang/rust/pseudorust.cpp
@@ -1900,6 +1900,24 @@ void PseudoRustFunction::GetExprText(const HighLevelILInstruction& instr, HighLe
}();
break;
+ case HLIL_PASS_BY_REF:
+ [&]() {
+ const auto srcExpr = instr.GetSourceExpr<HLIL_PASS_BY_REF>();
+ GetExprText(srcExpr, tokens, settings, UnaryOperatorPrecedence);
+ if (exprType != InnerExpression)
+ tokens.AppendSemicolon();
+ }();
+ break;
+
+ case HLIL_RETURN_BY_REF:
+ [&]() {
+ const auto srcExpr = instr.GetSourceExpr<HLIL_RETURN_BY_REF>();
+ GetExprText(srcExpr, tokens, settings, UnaryOperatorPrecedence);
+ if (exprType != InnerExpression)
+ tokens.AppendSemicolon();
+ }();
+ break;
+
case HLIL_FCMP_E:
case HLIL_CMP_E:
[&]() {
diff --git a/lang/rust/rusttypes.cpp b/lang/rust/rusttypes.cpp
index 70bf3162..0d966c3a 100644
--- a/lang/rust/rusttypes.cpp
+++ b/lang/rust/rusttypes.cpp
@@ -147,12 +147,13 @@ vector<InstructionTextToken> RustTypePrinter::GetTypeTokensAfterNameInternal(
vector<InstructionTextToken> paramTokens = GetTypeTokensAfterName(params[i].type.GetValue(), platform,
params[i].type.GetCombinedConfidence(baseConfidence), type, escaping);
- if (functionHeader)
+ auto var = params[i].location.GetVariableForParameter(i);
+ if (functionHeader && var.has_value())
{
for (auto& token : paramTokens)
{
token.context = LocalVariableTokenContext;
- token.address = params[i].location.ToIdentifier();
+ token.address = var->ToIdentifier();
}
}
@@ -164,40 +165,51 @@ vector<InstructionTextToken> RustTypePrinter::GetTypeTokensAfterNameInternal(
else
{
nameToken = InstructionTextToken(ArgumentNameToken, NameList::EscapeTypeName(params[i].name, escaping), i);
- if (functionHeader)
+ if (functionHeader && var.has_value())
{
nameToken.context = LocalVariableTokenContext;
- nameToken.address = params[i].location.ToIdentifier();
+ nameToken.address = var->ToIdentifier();
}
}
tokens.push_back(nameToken);
tokens.emplace_back(TextToken, ": ");
+
+ if (params[i].locationSource == PassByReferenceLocationSource || params[i].location.indirect)
+ tokens.emplace_back(baseConfidence, OperationToken, "&");
+
tokens.insert(tokens.end(), paramTokens.begin(), paramTokens.end());
- if (!params[i].defaultLocation && platform)
+ if (params[i].locationSource == CustomLocationSource && platform && var.has_value())
{
- switch (params[i].location.type)
+ switch (var->type)
{
case RegisterVariableSourceType:
{
- string registerName = platform->GetArchitecture()->GetRegisterName((uint32_t)params[i].location.storage);
+ string registerName = platform->GetArchitecture()->GetRegisterName((uint32_t)var->storage);
tokens.emplace_back(TextToken, " @ ");
- tokens.emplace_back(RegisterToken, NameList::EscapeTypeName(registerName, escaping), params[i].location.storage);
+ tokens.emplace_back(RegisterToken, NameList::EscapeTypeName(registerName, escaping), var->storage);
break;
}
case FlagVariableSourceType:
{
- string flagName = platform->GetArchitecture()->GetFlagName((uint32_t)params[i].location.storage);
+ string flagName = platform->GetArchitecture()->GetFlagName((uint32_t)var->storage);
tokens.emplace_back(TextToken, " @ ");
- tokens.emplace_back(AnnotationToken, NameList::EscapeTypeName(flagName, escaping), params[i].location.storage);
+ tokens.emplace_back(AnnotationToken, NameList::EscapeTypeName(flagName, escaping), var->storage);
break;
}
case StackVariableSourceType:
{
tokens.emplace_back(TextToken, " @ ");
char storageStr[32];
- snprintf(storageStr, sizeof(storageStr), "%" PRIi64, params[i].location.storage);
- tokens.emplace_back(IntegerToken, storageStr, params[i].location.storage);
+ snprintf(storageStr, sizeof(storageStr), "%" PRIi64, var->storage);
+ tokens.emplace_back(IntegerToken, storageStr, var->storage);
+ break;
+ }
+ default:
+ {
+ string locationStr = params[i].location.ToString(platform->GetArchitecture());
+ tokens.emplace_back(TextToken, " @ ");
+ tokens.emplace_back(ValueLocationToken, locationStr);
break;
}
}
@@ -230,6 +242,13 @@ vector<InstructionTextToken> RustTypePrinter::GetTypeTokensAfterNameInternal(
i.context = FunctionReturnTokenContext;
}
tokens.insert(tokens.end(), retn.begin(), retn.end());
+ if (!type->GetReturnValue().defaultLocation)
+ {
+ auto location = type->GetReturnValue().location;
+ string locationStr = location->ToString(platform->GetArchitecture());
+ tokens.emplace_back(TextToken, " @ ");
+ tokens.emplace_back(location.GetCombinedConfidence(baseConfidence), ValueLocationToken, locationStr);
+ }
}
break;
}
diff --git a/mediumlevelilinstruction.cpp b/mediumlevelilinstruction.cpp
index 74b1d76f..37a102d8 100644
--- a/mediumlevelilinstruction.cpp
+++ b/mediumlevelilinstruction.cpp
@@ -170,6 +170,8 @@ static constexpr std::array s_instructionOperandUsage = {
OperandUsage{MLIL_VAR_SPLIT, {HighVariableMediumLevelOperandUsage, LowVariableMediumLevelOperandUsage}},
OperandUsage{MLIL_ADDRESS_OF, {SourceVariableMediumLevelOperandUsage}},
OperandUsage{MLIL_ADDRESS_OF_FIELD, {SourceVariableMediumLevelOperandUsage, OffsetMediumLevelOperandUsage}},
+ OperandUsage{MLIL_PASS_BY_REF, {SourceExprMediumLevelOperandUsage}},
+ OperandUsage{MLIL_RETURN_BY_REF, {SourceExprMediumLevelOperandUsage}},
OperandUsage{MLIL_CONST, {ConstantMediumLevelOperandUsage}},
OperandUsage{MLIL_CONST_DATA, {ConstantDataMediumLevelOperandUsage}},
OperandUsage{MLIL_CONST_PTR, {ConstantMediumLevelOperandUsage}},
@@ -215,6 +217,8 @@ static constexpr std::array s_instructionOperandUsage = {
OperandUsage{MLIL_SEPARATE_PARAM_LIST, {ParameterExprsMediumLevelOperandUsage}},
OperandUsage{MLIL_SHARED_PARAM_SLOT, {ParameterExprsMediumLevelOperandUsage}},
OperandUsage{MLIL_VAR_OUTPUT, {DestVariableMediumLevelOperandUsage}},
+ OperandUsage{MLIL_VAR_OUTPUT_FIELD, {DestVariableMediumLevelOperandUsage, OffsetMediumLevelOperandUsage}},
+ OperandUsage{MLIL_STORE_OUTPUT, {DestExprMediumLevelOperandUsage}},
OperandUsage{MLIL_RET, {SourceExprsMediumLevelOperandUsage}},
OperandUsage{MLIL_NORET},
OperandUsage{MLIL_IF, {ConditionExprMediumLevelOperandUsage, TrueTargetMediumLevelOperandUsage, FalseTargetMediumLevelOperandUsage}},
@@ -286,6 +290,9 @@ static constexpr std::array s_instructionOperandUsage = {
OperandUsage{MLIL_CALL_PARAM_SSA, {ParameterExprsMediumLevelOperandUsage}},
OperandUsage{MLIL_CALL_OUTPUT_SSA, {OutputSSAVariablesMediumLevelOperandUsage}},
OperandUsage{MLIL_VAR_OUTPUT_SSA, {DestSSAVariableMediumLevelOperandUsage}},
+ OperandUsage{MLIL_VAR_OUTPUT_SSA_FIELD, {DestSSAVariableMediumLevelOperandUsage, PartialSSAVariableSourceMediumLevelOperandUsage, OffsetMediumLevelOperandUsage}},
+ OperandUsage{MLIL_VAR_OUTPUT_ALIASED, {DestSSAVariableMediumLevelOperandUsage, PartialSSAVariableSourceMediumLevelOperandUsage}},
+ OperandUsage{MLIL_VAR_OUTPUT_ALIASED_FIELD, {DestSSAVariableMediumLevelOperandUsage, PartialSSAVariableSourceMediumLevelOperandUsage, OffsetMediumLevelOperandUsage}},
OperandUsage{MLIL_MEMORY_INTRINSIC_OUTPUT_SSA, {OutputSSAVariablesMediumLevelOperandUsage}},
OperandUsage{MLIL_LOAD_SSA, {SourceExprMediumLevelOperandUsage, SourceMemoryVersionMediumLevelOperandUsage}},
OperandUsage{MLIL_LOAD_STRUCT_SSA, {SourceExprMediumLevelOperandUsage, OffsetMediumLevelOperandUsage, SourceMemoryVersionMediumLevelOperandUsage}},
@@ -296,6 +303,7 @@ static constexpr std::array s_instructionOperandUsage = {
OperandUsage{MLIL_FREE_VAR_SLOT_SSA, {DestSSAVariableMediumLevelOperandUsage, PartialSSAVariableSourceMediumLevelOperandUsage}},
OperandUsage{MLIL_VAR_PHI, {DestSSAVariableMediumLevelOperandUsage, SourceSSAVariablesMediumLevelOperandUsages}},
OperandUsage{MLIL_MEM_PHI, {DestMemoryVersionMediumLevelOperandUsage, SourceMemoryVersionsMediumLevelOperandUsage}},
+ OperandUsage{MLIL_BLOCK_TO_EXPAND, {SourceExprsMediumLevelOperandUsage}},
};
VALIDATE_INSTRUCTION_ORDER(s_instructionOperandUsage);
@@ -1501,6 +1509,9 @@ void MediumLevelILInstruction::VisitExprs(bn::base::function_ref<bool(const Medi
GetDestExpr<MLIL_STORE_STRUCT_SSA>().VisitExprs(func);
GetSourceExpr<MLIL_STORE_STRUCT_SSA>().VisitExprs(func);
break;
+ case MLIL_STORE_OUTPUT:
+ GetDestExpr<MLIL_STORE_OUTPUT>().VisitExprs(func);
+ break;
case MLIL_NEG:
case MLIL_NOT:
case MLIL_SX:
@@ -1526,6 +1537,8 @@ void MediumLevelILInstruction::VisitExprs(bn::base::function_ref<bool(const Medi
case MLIL_FLOOR:
case MLIL_CEIL:
case MLIL_FTRUNC:
+ case MLIL_PASS_BY_REF:
+ case MLIL_RETURN_BY_REF:
AsOneOperand().GetSourceExpr().VisitExprs(func);
break;
case MLIL_ADD:
@@ -1593,6 +1606,10 @@ void MediumLevelILInstruction::VisitExprs(bn::base::function_ref<bool(const Medi
for (auto i : GetParameterExprs())
i.VisitExprs(func);
break;
+ case MLIL_BLOCK_TO_EXPAND:
+ for (auto i : GetSourceExprs<MLIL_BLOCK_TO_EXPAND>())
+ i.VisitExprs(func);
+ break;
default:
break;
}
@@ -1671,6 +1688,19 @@ ExprId MediumLevelILInstruction::CopyTo(MediumLevelILFunction* dest,
size, GetHighSSAVariable<MLIL_VAR_SPLIT_SSA>(), GetLowSSAVariable<MLIL_VAR_SPLIT_SSA>(), loc);
case MLIL_VAR_OUTPUT_SSA:
return dest->VarOutputSSA(size, GetDestSSAVariable<MLIL_VAR_OUTPUT_SSA>(), loc);
+ case MLIL_VAR_OUTPUT_SSA_FIELD:
+ return dest->VarOutputSSAField(size, GetDestSSAVariable<MLIL_VAR_OUTPUT_SSA_FIELD>().var,
+ GetDestSSAVariable<MLIL_VAR_OUTPUT_SSA_FIELD>().version,
+ GetSourceSSAVariable<MLIL_VAR_OUTPUT_SSA_FIELD>().version, GetOffset<MLIL_VAR_OUTPUT_SSA_FIELD>(), loc);
+ case MLIL_VAR_OUTPUT_ALIASED:
+ return dest->VarOutputAliased(size, GetDestSSAVariable<MLIL_VAR_OUTPUT_ALIASED>().var,
+ GetDestSSAVariable<MLIL_VAR_OUTPUT_ALIASED>().version,
+ GetSourceSSAVariable<MLIL_VAR_OUTPUT_ALIASED>().version, loc);
+ case MLIL_VAR_OUTPUT_ALIASED_FIELD:
+ return dest->VarOutputAliasedField(size, GetDestSSAVariable<MLIL_VAR_OUTPUT_ALIASED_FIELD>().var,
+ GetDestSSAVariable<MLIL_VAR_OUTPUT_ALIASED_FIELD>().version,
+ GetSourceSSAVariable<MLIL_VAR_OUTPUT_ALIASED_FIELD>().version,
+ GetOffset<MLIL_VAR_OUTPUT_ALIASED_FIELD>(), loc);
case MLIL_FORCE_VER:
return dest->ForceVer(size, GetDestVariable<MLIL_FORCE_VER>(), GetSourceVariable<MLIL_FORCE_VER>(), loc);
case MLIL_FORCE_VER_SSA:
@@ -1786,6 +1816,11 @@ ExprId MediumLevelILInstruction::CopyTo(MediumLevelILFunction* dest,
return dest->SharedParamSlot(params, loc);
case MLIL_VAR_OUTPUT:
return dest->VarOutput(size, GetDestVariable<MLIL_VAR_OUTPUT>(), loc);
+ case MLIL_VAR_OUTPUT_FIELD:
+ return dest->VarOutputField(
+ size, GetDestVariable<MLIL_VAR_OUTPUT_FIELD>(), GetOffset<MLIL_VAR_OUTPUT_FIELD>(), loc);
+ case MLIL_STORE_OUTPUT:
+ return dest->StoreOutput(size, subExprHandler(GetDestExpr<MLIL_STORE_OUTPUT>()), loc);
case MLIL_RET:
for (auto i : GetSourceExprs<MLIL_RET>())
params.push_back(subExprHandler(i));
@@ -1837,6 +1872,8 @@ ExprId MediumLevelILInstruction::CopyTo(MediumLevelILFunction* dest,
case MLIL_FLOOR:
case MLIL_CEIL:
case MLIL_FTRUNC:
+ case MLIL_PASS_BY_REF:
+ case MLIL_RETURN_BY_REF:
return dest->AddExprWithLocation(operation, loc, size, subExprHandler(AsOneOperand().GetSourceExpr()));
case MLIL_ADD:
case MLIL_SUB:
@@ -1960,6 +1997,10 @@ ExprId MediumLevelILInstruction::CopyTo(MediumLevelILFunction* dest,
return dest->Undefined(loc);
case MLIL_UNIMPL:
return dest->Unimplemented(loc);
+ case MLIL_BLOCK_TO_EXPAND:
+ for (auto i : GetSourceExprs<MLIL_BLOCK_TO_EXPAND>())
+ params.push_back(subExprHandler(i));
+ return dest->BlockToExpand(params, loc);
default:
throw MediumLevelILInstructionAccessException();
}
@@ -2308,6 +2349,12 @@ vector<Variable> MediumLevelILCallInstruction::GetOutputVariables() const
{
if (i.operation == MLIL_VAR_OUTPUT)
result.push_back(i.GetDestVariable<MLIL_VAR_OUTPUT>());
+ else if (i.operation == MLIL_VAR_OUTPUT_FIELD)
+ result.push_back(i.GetDestVariable<MLIL_VAR_OUTPUT_FIELD>());
+ else if (i.operation == MLIL_RETURN_BY_REF && i.GetSourceExpr<MLIL_RETURN_BY_REF>().operation == MLIL_VAR_OUTPUT)
+ result.push_back(i.GetSourceExpr<MLIL_RETURN_BY_REF>().GetDestVariable<MLIL_VAR_OUTPUT>());
+ else if (i.operation == MLIL_RETURN_BY_REF && i.GetSourceExpr<MLIL_RETURN_BY_REF>().operation == MLIL_VAR_OUTPUT_FIELD)
+ result.push_back(i.GetSourceExpr<MLIL_RETURN_BY_REF>().GetDestVariable<MLIL_VAR_OUTPUT_FIELD>());
}
return result;
}
@@ -2318,8 +2365,25 @@ vector<SSAVariable> MediumLevelILCallSSAInstruction::GetOutputSSAVariables() con
vector<SSAVariable> result;
for (auto i : GetOutputExprs())
{
- if (i.operation == MLIL_VAR_OUTPUT_SSA)
+ if (i.operation == MLIL_RETURN_BY_REF)
+ i = i.GetSourceExpr<MLIL_RETURN_BY_REF>();
+ switch (i.operation)
+ {
+ case MLIL_VAR_OUTPUT_SSA:
result.push_back(i.GetDestSSAVariable<MLIL_VAR_OUTPUT_SSA>());
+ break;
+ case MLIL_VAR_OUTPUT_SSA_FIELD:
+ result.push_back(i.GetDestSSAVariable<MLIL_VAR_OUTPUT_SSA_FIELD>());
+ break;
+ case MLIL_VAR_OUTPUT_ALIASED:
+ result.push_back(i.GetDestSSAVariable<MLIL_VAR_OUTPUT_ALIASED>());
+ break;
+ case MLIL_VAR_OUTPUT_ALIASED_FIELD:
+ result.push_back(i.GetDestSSAVariable<MLIL_VAR_OUTPUT_ALIASED_FIELD>());
+ break;
+ default:
+ break;
+ }
}
return result;
}
@@ -2525,6 +2589,30 @@ ExprId MediumLevelILFunction::VarOutputSSA(size_t size, const SSAVariable& dest,
}
+ExprId MediumLevelILFunction::VarOutputSSAField(size_t size, const Variable& dest, size_t newVersion, size_t prevVersion,
+ uint64_t offset, const ILSourceLocation& loc)
+{
+ return AddExprWithLocation(
+ MLIL_VAR_OUTPUT_SSA_FIELD, loc, size, dest.ToIdentifier(), newVersion, prevVersion, offset);
+}
+
+
+ExprId MediumLevelILFunction::VarOutputAliased(size_t size, const Variable& dest, size_t newMemVersion,
+ size_t prevMemVersion, const ILSourceLocation& loc)
+{
+ return AddExprWithLocation(
+ MLIL_VAR_OUTPUT_ALIASED, loc, size, dest.ToIdentifier(), newMemVersion, prevMemVersion);
+}
+
+
+ExprId MediumLevelILFunction::VarOutputAliasedField(size_t size, const Variable& dest, size_t newMemVersion,
+ size_t prevMemVersion, uint64_t offset, const ILSourceLocation& loc)
+{
+ return AddExprWithLocation(
+ MLIL_VAR_OUTPUT_ALIASED_FIELD, loc, size, dest.ToIdentifier(), newMemVersion, prevMemVersion, offset);
+}
+
+
ExprId MediumLevelILFunction::AddressOf(const Variable& var, const ILSourceLocation& loc)
{
return AddExprWithLocation(MLIL_ADDRESS_OF, loc, 0, var.ToIdentifier());
@@ -2537,6 +2625,18 @@ ExprId MediumLevelILFunction::AddressOfField(const Variable& var, uint64_t offse
}
+ExprId MediumLevelILFunction::PassByRef(size_t size, ExprId src, const ILSourceLocation& loc)
+{
+ return AddExprWithLocation(MLIL_PASS_BY_REF, loc, size, src);
+}
+
+
+ExprId MediumLevelILFunction::ReturnByRef(size_t size, ExprId src, const ILSourceLocation& loc)
+{
+ return AddExprWithLocation(MLIL_RETURN_BY_REF, loc, size, src);
+}
+
+
ExprId MediumLevelILFunction::Const(size_t size, uint64_t val, const ILSourceLocation& loc)
{
return AddExprWithLocation(MLIL_CONST, loc, size, val);
@@ -2931,6 +3031,19 @@ ExprId MediumLevelILFunction::VarOutput(size_t size, const Variable& var, const
}
+ExprId MediumLevelILFunction::VarOutputField(
+ size_t size, const Variable& dest, uint64_t offset, const ILSourceLocation& loc)
+{
+ return AddExprWithLocation(MLIL_VAR_OUTPUT_FIELD, loc, size, dest.ToIdentifier(), offset);
+}
+
+
+ExprId MediumLevelILFunction::StoreOutput(size_t size, ExprId dest, const ILSourceLocation& loc)
+{
+ return AddExprWithLocation(MLIL_STORE_OUTPUT, loc, size, dest);
+}
+
+
ExprId MediumLevelILFunction::Return(const vector<ExprId>& sources, const ILSourceLocation& loc)
{
return AddExprWithLocation(MLIL_RET, loc, 0, sources.size(), AddOperandList(sources));
@@ -3244,6 +3357,12 @@ ExprId MediumLevelILFunction::FloatCompareUnordered(size_t size, ExprId a, ExprI
}
+ExprId MediumLevelILFunction::BlockToExpand(const vector<ExprId>& sources, const ILSourceLocation& loc)
+{
+ return AddExprWithLocation(MLIL_BLOCK_TO_EXPAND, loc, 0, sources.size(), AddOperandList(sources));
+}
+
+
fmt::format_context::iterator fmt::formatter<MediumLevelILInstruction>::format(const MediumLevelILInstruction& obj, format_context& ctx) const
{
if (!obj.function)
diff --git a/mediumlevelilinstruction.h b/mediumlevelilinstruction.h
index c7663269..3abe363e 100644
--- a/mediumlevelilinstruction.h
+++ b/mediumlevelilinstruction.h
@@ -1237,6 +1237,32 @@ namespace BinaryNinja
void SetDestSSAVersion(size_t version) { UpdateRawOperand(1, version); }
};
template <>
+ struct MediumLevelILInstructionAccessor<MLIL_VAR_OUTPUT_SSA_FIELD> : public MediumLevelILInstructionBase
+ {
+ SSAVariable GetDestSSAVariable() const { return GetRawOperandAsSSAVariable(0); }
+ SSAVariable GetSourceSSAVariable() const { return GetRawOperandAsPartialSSAVariableSource(0); }
+ uint64_t GetOffset() const { return GetRawOperandAsInteger(3); }
+ void SetDestSSAVersion(size_t version) { UpdateRawOperand(1, version); }
+ void SetSourceSSAVersion(size_t version) { UpdateRawOperand(2, version); }
+ };
+ template <>
+ struct MediumLevelILInstructionAccessor<MLIL_VAR_OUTPUT_ALIASED> : public MediumLevelILInstructionBase
+ {
+ SSAVariable GetDestSSAVariable() const { return GetRawOperandAsSSAVariable(0); }
+ SSAVariable GetSourceSSAVariable() const { return GetRawOperandAsPartialSSAVariableSource(0); }
+ void SetDestMemoryVersion(size_t version) { UpdateRawOperand(1, version); }
+ void SetSourceMemoryVersion(size_t version) { UpdateRawOperand(2, version); }
+ };
+ template <>
+ struct MediumLevelILInstructionAccessor<MLIL_VAR_OUTPUT_ALIASED_FIELD> : public MediumLevelILInstructionBase
+ {
+ SSAVariable GetDestSSAVariable() const { return GetRawOperandAsSSAVariable(0); }
+ SSAVariable GetSourceSSAVariable() const { return GetRawOperandAsPartialSSAVariableSource(0); }
+ uint64_t GetOffset() const { return GetRawOperandAsInteger(3); }
+ void SetDestMemoryVersion(size_t version) { UpdateRawOperand(1, version); }
+ void SetSourceMemoryVersion(size_t version) { UpdateRawOperand(2, version); }
+ };
+ template <>
struct MediumLevelILInstructionAccessor<MLIL_VAR_SSA_FIELD> : public MediumLevelILInstructionBase
{
SSAVariable GetSourceSSAVariable() const { return GetRawOperandAsSSAVariable(0); }
@@ -1355,6 +1381,17 @@ namespace BinaryNinja
{
Variable GetDestVariable() const { return GetRawOperandAsVariable(0); }
};
+ template <>
+ struct MediumLevelILInstructionAccessor<MLIL_VAR_OUTPUT_FIELD> : public MediumLevelILInstructionBase
+ {
+ Variable GetDestVariable() const { return GetRawOperandAsVariable(0); }
+ uint64_t GetOffset() const { return GetRawOperandAsInteger(1); }
+ };
+ template <>
+ struct MediumLevelILInstructionAccessor<MLIL_STORE_OUTPUT> : public MediumLevelILInstructionBase
+ {
+ MediumLevelILInstruction GetDestExpr() const { return GetRawOperandAsExpr(0); }
+ };
template <>
struct MediumLevelILInstructionAccessor<MLIL_CALL_SSA> : public MediumLevelILCallSSAInstruction
@@ -1555,6 +1592,13 @@ namespace BinaryNinja
};
template <>
+ struct MediumLevelILInstructionAccessor<MLIL_BLOCK_TO_EXPAND> : public MediumLevelILInstructionBase
+ {
+ MediumLevelILInstructionList GetSourceExprs() const { return GetRawOperandAsExprList(0); }
+ void SetSourceExprs(const _STD_VECTOR<ExprId>& exprs) { UpdateRawOperandAsExprList(0, exprs); }
+ };
+
+ template <>
struct MediumLevelILInstructionAccessor<MLIL_NOP> : public MediumLevelILInstructionBase
{};
template <>
@@ -1786,6 +1830,12 @@ namespace BinaryNinja
template <>
struct MediumLevelILInstructionAccessor<MLIL_FTRUNC> : public MediumLevelILOneOperandInstruction
{};
+ template <>
+ struct MediumLevelILInstructionAccessor<MLIL_PASS_BY_REF> : public MediumLevelILOneOperandInstruction
+ {};
+ template <>
+ struct MediumLevelILInstructionAccessor<MLIL_RETURN_BY_REF> : public MediumLevelILOneOperandInstruction
+ {};
#undef _STD_VECTOR
#undef _STD_SET
diff --git a/objectivec/objc.cpp b/objectivec/objc.cpp
index 3b6a9165..6575ed51 100644
--- a/objectivec/objc.cpp
+++ b/objectivec/objc.cpp
@@ -1256,9 +1256,9 @@ bool ObjCProcessor::ApplyMethodType(Class& cls, Method& method, bool isInstanceM
cls.associatedName.IsEmpty() ?
m_types.id :
Type::PointerType(m_data->GetAddressSize(), Type::NamedType(m_data, cls.associatedName)),
- true, BinaryNinja::Variable()});
+ DefaultLocationSource, BinaryNinja::Variable()});
- params.push_back({"sel", m_types.sel, true, BinaryNinja::Variable()});
+ params.push_back({"sel", m_types.sel, DefaultLocationSource, BinaryNinja::Variable()});
for (size_t i = 3; i < typeTokens.size(); i++)
{
@@ -1268,7 +1268,7 @@ bool ObjCProcessor::ApplyMethodType(Class& cls, Method& method, bool isInstanceM
else
name = "arg";
- params.push_back({std::move(name), typeForQualifiedNameOrType(typeTokens[i]), true, BinaryNinja::Variable()});
+ params.push_back({std::move(name), typeForQualifiedNameOrType(typeTokens[i]), DefaultLocationSource, BinaryNinja::Variable()});
}
auto funcType = BinaryNinja::Type::FunctionType(retType, cc, params);
diff --git a/plugins/pdb-ng/src/symbol_parser.rs b/plugins/pdb-ng/src/symbol_parser.rs
index a4ee4a6c..125d7c88 100644
--- a/plugins/pdb-ng/src/symbol_parser.rs
+++ b/plugins/pdb-ng/src/symbol_parser.rs
@@ -961,7 +961,7 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> {
MIN_CONFIDENCE,
)),
p.name.clone(),
- p.storage.first().map(|loc| loc.location),
+ p.storage.first().map(|loc| loc.location.into()),
);
// Ignore thisptr because it's not technically part of the raw type signature
if p.name != "this" {
@@ -976,7 +976,7 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> {
MIN_CONFIDENCE,
)),
p.name.clone(),
- p.storage.first().map(|loc| loc.location),
+ p.storage.first().map(|loc| loc.location.into()),
);
// Ignore thisptr because it's not technically part of the raw type signature
if p.name != "this" {
@@ -1035,7 +1035,6 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> {
}
}
- // Now apply the default location for the params from the cc
let cc = fancy_type
.contents
.calling_convention()
@@ -1049,12 +1048,6 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> {
});
self.log(|| format!("Default calling convention: {:?}", self.default_cc));
self.log(|| format!("Result calling convention: {:?}", cc));
-
- let locations = cc.contents.variables_for_parameters(&fancy_params, None);
- for (p, new_location) in fancy_params.iter_mut().zip(locations.into_iter()) {
- p.location = Some(new_location);
- }
-
self.log(|| format!("Final params: {:#x?}", fancy_params));
// Use the new locals we've parsed to make the Real Definitely True function type
diff --git a/plugins/warp/src/convert.rs b/plugins/warp/src/convert.rs
index bacf0024..85a06314 100644
--- a/plugins/warp/src/convert.rs
+++ b/plugins/warp/src/convert.rs
@@ -27,6 +27,8 @@ pub fn bn_var_to_location(bn_variable: BNVariable) -> Option<Location> {
Some(Location::Register(reg_loc))
}
VariableSourceType::FlagVariableSourceType => None,
+ VariableSourceType::CompositeReturnValueSourceType => None,
+ VariableSourceType::CompositeParameterSourceType => None,
}
}
diff --git a/plugins/workflow_swift/src/demangler/function_type.rs b/plugins/workflow_swift/src/demangler/function_type.rs
index 908f5940..73abe23f 100644
--- a/plugins/workflow_swift/src/demangler/function_type.rs
+++ b/plugins/workflow_swift/src/demangler/function_type.rs
@@ -1,8 +1,7 @@
-use binaryninja::architecture::{ArchitectureExt, CoreArchitecture, Register};
+use binaryninja::architecture::{ArchitectureExt, CoreArchitecture};
use binaryninja::confidence::Conf;
use binaryninja::rc::Ref;
-use binaryninja::types::{FunctionParameter, Type};
-use binaryninja::variable::{Variable, VariableSourceType};
+use binaryninja::types::{FunctionParameter, Type, ValueLocation, ValueLocationSource};
use swift_demangler::{
Accessor, AccessorKind, ConstructorKind, HasFunctionSignature, HasModule, Metadata,
MetadataKind, Symbol,
@@ -29,21 +28,17 @@ impl PlatformAbi {
}
}
- fn error_location(&self) -> Option<Variable> {
- self.register_variable(self.error_reg)
+ fn error_location(&self) -> Option<ValueLocation> {
+ self.register_location(self.error_reg)
}
- fn async_context_location(&self) -> Option<Variable> {
- self.register_variable(self.async_context_reg)
+ fn async_context_location(&self) -> Option<ValueLocation> {
+ self.register_location(self.async_context_reg)
}
- fn register_variable(&self, name: &str) -> Option<Variable> {
+ fn register_location(&self, name: &str) -> Option<ValueLocation> {
let reg = self.arch.register_by_name(name)?;
- Some(Variable::new(
- VariableSourceType::RegisterVariableSourceType,
- 0,
- reg.id().0 as i64,
- ))
+ Some(ValueLocation::from_register(reg))
}
}
@@ -83,7 +78,7 @@ impl CallingConvention {
self.leading_params.push(FunctionParameter {
ty: self_ty.into(),
name: "self".to_string(),
- location: None,
+ location: ValueLocationSource::Default,
});
}
@@ -103,12 +98,12 @@ impl CallingConvention {
self.trailing_params.push(FunctionParameter {
ty: void_ptr.clone().into(),
name: "selfMetadata".to_string(),
- location: None,
+ location: ValueLocationSource::Default,
});
self.trailing_params.push(FunctionParameter {
ty: void_ptr.into(),
name: "selfWitnessTable".to_string(),
- location: None,
+ location: ValueLocationSource::Default,
});
}
@@ -144,7 +139,7 @@ impl CallingConvention {
all_params.push(FunctionParameter {
ty: error_ty.into(),
name: "error".to_string(),
- location: self.abi.as_ref().and_then(|a| a.error_location()),
+ location: self.abi.as_ref().and_then(|a| a.error_location()).into(),
});
}
@@ -153,7 +148,11 @@ impl CallingConvention {
all_params.push(FunctionParameter {
ty: ptr_ty.into(),
name: "asyncContext".to_string(),
- location: self.abi.as_ref().and_then(|a| a.async_context_location()),
+ location: self
+ .abi
+ .as_ref()
+ .and_then(|a| a.async_context_location())
+ .into(),
});
}
@@ -245,7 +244,7 @@ pub fn build_function_type(symbol: &Symbol, arch: &CoreArchitecture) -> Option<R
Some(FunctionParameter {
ty: ty.into(),
name,
- location: None,
+ location: ValueLocationSource::Default,
})
})
.collect();
@@ -288,7 +287,7 @@ fn build_accessor_type(accessor: &Accessor, arch: &CoreArchitecture) -> Option<R
let params = vec![FunctionParameter {
ty: prop_ty.into(),
name: "newValue".to_string(),
- location: None,
+ location: ValueLocationSource::Default,
}];
Some(cc.build_type(&Type::void(), params))
}
@@ -314,12 +313,12 @@ fn build_metadata_function_type(metadata: &Metadata, arch: &CoreArchitecture) ->
FunctionParameter {
ty: void_ptr.clone().into(),
name: "metadata".to_string(),
- location: None,
+ location: ValueLocationSource::Default,
},
FunctionParameter {
ty: void_ptr.clone().into(),
name: "method".to_string(),
- location: None,
+ location: ValueLocationSource::Default,
},
];
Some(Type::function(&void_ptr, params, false))
diff --git a/plugins/workflow_swift/src/demangler/type_reconstruction.rs b/plugins/workflow_swift/src/demangler/type_reconstruction.rs
index 3a3ba3e7..33e44a72 100644
--- a/plugins/workflow_swift/src/demangler/type_reconstruction.rs
+++ b/plugins/workflow_swift/src/demangler/type_reconstruction.rs
@@ -1,6 +1,8 @@
use binaryninja::architecture::{Architecture, CoreArchitecture};
use binaryninja::rc::Ref;
-use binaryninja::types::{NamedTypeReference, NamedTypeReferenceClass, QualifiedName, Type};
+use binaryninja::types::{
+ NamedTypeReference, NamedTypeReferenceClass, QualifiedName, Type, ValueLocationSource,
+};
use swift_demangler::{TypeKind, TypeRef};
pub(crate) trait TypeRefExt {
@@ -57,7 +59,7 @@ impl TypeRefExt for TypeRef<'_> {
Some(binaryninja::types::FunctionParameter {
ty: ty.into(),
name,
- location: None,
+ location: ValueLocationSource::Default,
})
})
.collect();
diff --git a/python/architecture.py b/python/architecture.py
index c11007df..f00b1cbe 100644
--- a/python/architecture.py
+++ b/python/architecture.py
@@ -1051,7 +1051,7 @@ class Architecture(metaclass=_ArchitectureMetaClass):
result = {}
try:
for i in range(0, count.value):
- obj = callingconvention.CallingConvention(handle=core.BNNewCallingConventionReference(cc[i]))
+ obj = callingconvention.CoreCallingConvention(handle=core.BNNewCallingConventionReference(cc[i]))
result[obj.name] = obj
finally:
core.BNFreeCallingConventionList(cc, count.value)
@@ -2613,7 +2613,7 @@ class Architecture(metaclass=_ArchitectureMetaClass):
cc_handle = core.BNGetArchitectureDefaultCallingConvention(self.handle)
if cc_handle is None:
return None
- return callingconvention.CallingConvention(handle=cc_handle)
+ return callingconvention.CoreCallingConvention(handle=cc_handle)
@default_calling_convention.setter
def default_calling_convention(self, cc: 'callingconvention.CallingConvention'):
@@ -2633,7 +2633,7 @@ class Architecture(metaclass=_ArchitectureMetaClass):
cc_handle = core.BNGetArchitectureCdeclCallingConvention(self.handle)
if cc_handle is None:
return None
- return callingconvention.CallingConvention(handle=cc_handle)
+ return callingconvention.CoreCallingConvention(handle=cc_handle)
@cdecl_calling_convention.setter
def cdecl_calling_convention(self, cc: 'callingconvention.CallingConvention'):
@@ -2653,7 +2653,7 @@ class Architecture(metaclass=_ArchitectureMetaClass):
cc_handle = core.BNGetArchitectureStdcallCallingConvention(self.handle)
if cc_handle is None:
return None
- return callingconvention.CallingConvention(handle=cc_handle)
+ return callingconvention.CoreCallingConvention(handle=cc_handle)
@stdcall_calling_convention.setter
def stdcall_calling_convention(self, cc: 'callingconvention.CallingConvention'):
@@ -2673,7 +2673,7 @@ class Architecture(metaclass=_ArchitectureMetaClass):
cc_handle = core.BNGetArchitectureFastcallCallingConvention(self.handle)
if cc_handle is None:
return None
- return callingconvention.CallingConvention(handle=cc_handle)
+ return callingconvention.CoreCallingConvention(handle=cc_handle)
@fastcall_calling_convention.setter
def fastcall_calling_convention(self, cc: 'callingconvention.CallingConvention'):
diff --git a/python/binaryview.py b/python/binaryview.py
index 039c94ee..5594b066 100644
--- a/python/binaryview.py
+++ b/python/binaryview.py
@@ -11047,6 +11047,24 @@ to a the type "tagRECT" found in the typelibrary "winX64common"
core.free_string(string)
return result, StringType(string_type.value)
+ def deref_parameter_named_type_references(self, params: List['_types.FunctionParameter']):
+ result = []
+ for param in params:
+ if param.type is None:
+ ty = None
+ else:
+ ty = param.type.deref_named_type_reference(self).with_confidence(param.type.confidence)
+ result.append(_types.FunctionParameter(ty, param.name, param.location, param.location_source))
+ return result
+
+ def deref_return_value_named_type_references(self, value: '_types.ReturnValue'):
+ if value.type is None:
+ ty = None
+ else:
+ ty = value.type.deref_named_type_reference(self).with_confidence(value.type.confidence)
+ return _types.ReturnValue(ty, value.location)
+
+
class BinaryReader:
"""
``class BinaryReader`` is a convenience class for reading binary data.
diff --git a/python/callingconvention.py b/python/callingconvention.py
index 94aeb699..4f17d1cf 100644
--- a/python/callingconvention.py
+++ b/python/callingconvention.py
@@ -20,7 +20,8 @@
import traceback
import ctypes
-from typing import Optional, Union
+from typing import Optional, Union, List, Dict, Tuple
+from dataclasses import dataclass
# Binary Ninja components
from . import _binaryninjacore as core
@@ -28,12 +29,62 @@ from .log import log_error_for_exception
from . import variable
from . import function
from . import architecture
+from . import types
+from . import binaryview
FunctionOrILFunction = Union["binaryninja.function.Function", "binaryninja.lowlevelil.LowLevelILFunction",
"binaryninja.mediumlevelil.MediumLevelILFunction",
"binaryninja.highlevelil.HighLevelILFunction"]
+@dataclass
+class CallLayout:
+ parameters: List['types.ValueLocation']
+ return_value: Optional['types.ValueLocation']
+ stack_adjustment: int
+ reg_stack_adjustments: Dict['architecture.RegisterIndex', int]
+
+ @staticmethod
+ def _from_core_struct(struct: core.BNCallLayout, func: Optional['function.Function'] = None) -> 'CallLayout':
+ params = []
+ if func is None:
+ arch = None
+ else:
+ arch = func.arch
+ for i in range(struct.parameterCount):
+ params.append(types.ValueLocation._from_core_struct(struct.parameters[i], arch))
+ if struct.returnValueValid:
+ return_value = types.ValueLocation._from_core_struct(struct.returnValue, arch)
+ else:
+ return_value = None
+ stack_adjust = struct.stackAdjustment
+ reg_stack_adjust = dict()
+ for i in range(struct.registerStackAdjustmentCount):
+ reg = architecture.RegisterIndex(struct.registerStackAdjustmentRegisters[i])
+ reg_stack_adjust[reg] = struct.registerStackAdjustmentAmounts[i]
+ return CallLayout(params, return_value, stack_adjust, reg_stack_adjust)
+
+ def _to_core_struct(self):
+ struct = core.BNCallLayout()
+ struct.parameters = (core.BNValueLocation * len(self.parameters))()
+ struct.parameterCount = len(self.parameters)
+ for i in range(len(self.parameters)):
+ struct.parameters[i] = self.parameters[i]._to_core_struct()
+ if self.return_value is None:
+ struct.returnValueValid = False
+ else:
+ struct.returnValue = self.return_value._to_core_struct()
+ struct.returnValueValid = True
+ struct.stackAdjustment = self.stack_adjustment
+ struct.registerStackAdjustmentRegisters = (ctypes.c_uint * len(self.reg_stack_adjustments))()
+ struct.registerStackAdjustmentAmounts = (ctypes.c_int * len(self.reg_stack_adjustments))()
+ struct.registerStackAdjustmentCount = len(self.reg_stack_adjustments)
+ for i, (reg, amount) in enumerate(self.reg_stack_adjustments.items()):
+ struct.registerStackAdjustmentRegisters[i] = reg
+ struct.registerStackAdjustmentAmounts[i] = amount
+ return struct
+
+
class CallingConvention:
name = None
caller_saved_regs = []
@@ -52,8 +103,13 @@ class CallingConvention:
float_return_reg = None
global_pointer_reg = None
implicitly_defined_regs = []
+ stack_args_naturally_aligned = False
_registered_calling_conventions = []
+ _pending_value_locations = {}
+ _pending_value_location_lists = {}
+ _pending_reg_stack_adjustment_reg_lists = {}
+ _pending_reg_stack_adjustment_amount_lists = {}
def __init__(
self, arch: Optional['architecture.Architecture'] = None, name: Optional[str] = None, handle=None,
@@ -117,111 +173,43 @@ class CallingConvention:
self._cb.getParameterVariableForIncomingVariable = self._cb.getParameterVariableForIncomingVariable.__class__(
self._get_parameter_var_for_incoming_var
)
+ self._cb.isReturnTypeRegisterCompatible = self._cb.isReturnTypeRegisterCompatible.__class__(
+ self._is_return_type_reg_compatible
+ )
+ self._cb.getIndirectReturnValueLocation = self._cb.getIndirectReturnValueLocation.__class__(
+ self._get_indirect_return_value_location
+ )
+ self._cb.getReturnedIndirectReturnValuePointer = self._cb.getReturnedIndirectReturnValuePointer.__class__(
+ self._get_returned_indirect_return_value_pointer
+ )
+ self._cb.isArgumentTypeRegisterCompatible = self._cb.isArgumentTypeRegisterCompatible.__class__(
+ self._is_arg_type_reg_compatible
+ )
+ self._cb.isNonRegisterArgumentIndirect = self._cb.isNonRegisterArgumentIndirect.__class__(
+ self._is_non_reg_arg_indirect
+ )
+ self._cb.areStackArgumentsNaturallyAligned = self._cb.areStackArgumentsNaturallyAligned.__class__(
+ self._are_stack_args_naturally_aligned
+ )
+ self._cb.getCallLayout = self._cb.getCallLayout.__class__(self._get_call_layout)
+ self._cb.freeCallLayout = self._cb.freeCallLayout.__class__(self._free_call_layout)
+ self._cb.getReturnValueLocation = self._cb.getReturnValueLocation.__class__(self._get_return_value_location)
+ self._cb.freeValueLocation = self._cb.freeValueLocation.__class__(self._free_value_location)
+ self._cb.getParameterLocations = self._cb.getParameterLocations.__class__(self._get_parameter_locations)
+ self._cb.freeParameterLocations = self._cb.freeParameterLocations.__class__(self._free_parameter_locations)
+ self._cb.getStackAdjustmentForLocations = self._cb.getStackAdjustmentForLocations.__class__(
+ self._get_stack_adjustment_for_locations
+ )
+ self._cb.getRegisterStackAdjustments = self._cb.getRegisterStackAdjustments.__class__(
+ self._get_register_stack_adjustments
+ )
+ self._cb.freeRegisterStackAdjustments = self._cb.freeRegisterStackAdjustments.__class__(
+ self._free_register_stack_adjustments
+ )
_handle = core.BNCreateCallingConvention(arch.handle, name, self._cb)
self.__class__._registered_calling_conventions.append(self)
else:
_handle = handle
- self.arch = architecture.CoreArchitecture._from_cache(core.BNGetCallingConventionArchitecture(_handle))
- self.__dict__["name"] = core.BNGetCallingConventionName(_handle)
- self.__dict__["arg_regs_share_index"] = core.BNAreArgumentRegistersSharedIndex(_handle)
- self.__dict__["arg_regs_for_varargs"] = core.BNAreArgumentRegistersUsedForVarArgs(_handle)
- self.__dict__["stack_reserved_for_arg_regs"] = core.BNIsStackReservedForArgumentRegisters(_handle)
- self.__dict__["stack_adjusted_on_return"] = core.BNIsStackAdjustedOnReturn(_handle)
- self.__dict__["eligible_for_heuristics"] = core.BNIsEligibleForHeuristics(_handle)
-
- count = ctypes.c_ulonglong()
- regs = core.BNGetCallerSavedRegisters(_handle, count)
- assert regs is not None, "core.BNGetCallerSavedRegisters returned None"
- result = []
- arch = self.arch
- for i in range(0, count.value):
- result.append(arch.get_reg_name(regs[i]))
- core.BNFreeRegisterList(regs)
- self.__dict__["caller_saved_regs"] = result
-
- count = ctypes.c_ulonglong()
- regs = core.BNGetCalleeSavedRegisters(_handle, count)
- assert regs is not None, "core.BNGetCalleeSavedRegisters returned None"
- result = []
- arch = self.arch
- for i in range(0, count.value):
- result.append(arch.get_reg_name(regs[i]))
- core.BNFreeRegisterList(regs)
- self.__dict__["callee_saved_regs"] = result
-
- count = ctypes.c_ulonglong()
- regs = core.BNGetIntegerArgumentRegisters(_handle, count)
- assert regs is not None, "core.BNGetIntegerArgumentRegisters returned None"
- result = []
- arch = self.arch
- for i in range(0, count.value):
- result.append(arch.get_reg_name(regs[i]))
- core.BNFreeRegisterList(regs)
- self.__dict__["int_arg_regs"] = result
-
- count = ctypes.c_ulonglong()
- regs = core.BNGetFloatArgumentRegisters(_handle, count)
- assert regs is not None, "core.BNGetFloatArgumentRegisters returned None"
- result = []
- arch = self.arch
- for i in range(0, count.value):
- result.append(arch.get_reg_name(regs[i]))
- core.BNFreeRegisterList(regs)
- self.__dict__["float_arg_regs"] = result
-
- count = ctypes.c_ulonglong()
- regs = core.BNGetRequiredArgumentRegisters(handle, count)
- assert regs is not None, "core.BNGetRequiredArgumentRegisters returned None"
- result = []
- arch = self.arch
- for i in range(0, count.value):
- result.append(arch.get_reg_name(regs[i]))
- core.BNFreeRegisterList(regs)
- self.__dict__["required_arg_regs"] = result
-
- count = ctypes.c_ulonglong()
- regs = core.BNGetRequiredClobberedRegisters(handle, count)
- assert regs is not None, "core.BNGetRequiredClobberedRegisters returned None"
- result = []
- arch = self.arch
- for i in range(0, count.value):
- result.append(arch.get_reg_name(regs[i]))
- core.BNFreeRegisterList(regs)
- self.__dict__["required_clobbered_regs"] = result
-
- reg = core.BNGetIntegerReturnValueRegister(_handle)
- if reg == 0xffffffff:
- self.__dict__["int_return_reg"] = None
- else:
- self.__dict__["int_return_reg"] = self.arch.get_reg_name(reg)
-
- reg = core.BNGetHighIntegerReturnValueRegister(_handle)
- if reg == 0xffffffff:
- self.__dict__["high_int_return_reg"] = None
- else:
- self.__dict__["high_int_return_reg"] = self.arch.get_reg_name(reg)
-
- reg = core.BNGetFloatReturnValueRegister(_handle)
- if reg == 0xffffffff:
- self.__dict__["float_return_reg"] = None
- else:
- self.__dict__["float_return_reg"] = self.arch.get_reg_name(reg)
-
- reg = core.BNGetGlobalPointerRegister(_handle)
- if reg == 0xffffffff:
- self.__dict__["global_pointer_reg"] = None
- else:
- self.__dict__["global_pointer_reg"] = self.arch.get_reg_name(reg)
-
- count = ctypes.c_ulonglong()
- regs = core.BNGetImplicitlyDefinedRegisters(_handle, count)
- assert regs is not None, "core.BNGetImplicitlyDefinedRegisters returned None"
- result = []
- arch = self.arch
- for i in range(0, count.value):
- result.append(arch.get_reg_name(regs[i]))
- core.BNFreeRegisterList(regs)
- self.__dict__["implicitly_defined_regs"] = result
assert _handle is not None
self.handle = _handle
self.confidence = confidence
@@ -492,9 +480,309 @@ class CallingConvention:
result[0].index = in_var[0].index
result[0].storage = in_var[0].storage
+ def _is_return_type_reg_compatible(self, ctxt, view, type):
+ try:
+ if type:
+ if view:
+ view_obj = binaryview.BinaryView(handle=core.BNNewViewReference(view))
+ else:
+ view_obj = None
+ type_obj = types.Type.create(handle=core.BNNewTypeReference(type))
+ return self.is_return_type_reg_compatible(view_obj, type_obj)
+ else:
+ return False
+ except:
+ log_error_for_exception("Unhandled Python exception in CallingConvention._is_return_type_reg_compatible")
+ return False
+
+ def _get_indirect_return_value_location(self, ctxt, out_var):
+ try:
+ out_var[0] = self.get_indirect_return_value_location().to_BNVariable()
+ except:
+ log_error_for_exception(
+ "Unhandled Python exception in CallingConvention._get_indirect_return_value_location")
+
+ def _get_returned_indirect_return_value_pointer(self, ctxt, out_var):
+ try:
+ result = self.get_returned_indirect_return_value_pointer()
+ if result is None:
+ return False
+ out_var[0] = result.to_BNVariable()
+ return True
+ except:
+ log_error_for_exception(
+ "Unhandled Python exception in CallingConvention._get_returned_indirect_return_value_pointer")
+ return False
+
+ def _is_arg_type_reg_compatible(self, ctxt, view, type):
+ try:
+ if type:
+ if view:
+ view_obj = binaryview.BinaryView(handle=core.BNNewViewReference(view))
+ else:
+ view_obj = None
+ type_obj = types.Type.create(handle=core.BNNewTypeReference(type))
+ return self.is_arg_type_reg_compatible(view_obj, type_obj)
+ else:
+ return False
+ except:
+ log_error_for_exception("Unhandled Python exception in CallingConvention._is_arg_type_reg_compatible")
+ return False
+
+ def _is_non_reg_arg_indirect(self, ctxt, view, type):
+ try:
+ if view:
+ view_obj = binaryview.BinaryView(handle=core.BNNewViewReference(view))
+ else:
+ view_obj = None
+ if type:
+ type_obj = types.Type.create(handle=core.BNNewTypeReference(type))
+ return self.is_non_reg_arg_indirect(view_obj, type_obj)
+ else:
+ return self.is_non_reg_arg_indirect(view_obj, None)
+ except:
+ log_error_for_exception("Unhandled Python exception in CallingConvention._is_non_reg_arg_indirect")
+ return False
+
+ def _are_stack_args_naturally_aligned(self, ctxt):
+ try:
+ return self.__class__.stack_args_naturally_aligned
+ except:
+ log_error_for_exception("Unhandled Python exception in CallingConvention._are_stack_args_naturally_aligned")
+ return False
+
+ def _get_call_layout(
+ self, ctxt, view, ret_value, params, param_count, has_permitted_regs, permitted_regs,
+ permitted_reg_count, out_layout
+ ):
+ try:
+ if view:
+ view_obj = binaryview.BinaryView(handle=core.BNNewViewReference(view))
+ else:
+ view_obj = None
+ if ret_value:
+ ret_value_obj = types.ReturnValue._from_core_struct(ret_value[0])
+ else:
+ ret_value_obj = None
+ param_objs = []
+ for i in range(param_count):
+ param_objs.append(types.FunctionParameter._from_core_struct(params[i]))
+ if has_permitted_regs:
+ reg_objs = []
+ for i in range(permitted_reg_count):
+ reg_objs.append(architecture.RegisterIndex(permitted_regs[i]))
+ else:
+ reg_objs = None
+ layout = self.get_call_layout(view_obj, ret_value_obj, param_objs, permitted_regs = reg_objs)
+
+ result = layout._to_core_struct()
+
+ param_ptr = ctypes.cast(result.parameters, ctypes.c_void_p)
+ self._pending_value_location_lists[param_ptr.value] = (param_ptr.value, result.parameters)
+
+ if result.returnValueValid:
+ ret_ptr = ctypes.cast(result.returnValue.components, ctypes.c_void_p)
+ self._pending_value_locations[ret_ptr.value] = (ret_ptr.value, result.returnValue)
+
+ reg_ptr = ctypes.cast(result.registerStackAdjustmentRegisters, ctypes.c_void_p)
+ self._pending_reg_stack_adjustment_reg_lists[reg_ptr.value] = (reg_ptr.value, result.registerStackAdjustmentRegisters)
+ amount_ptr = ctypes.cast(result.registerStackAdjustmentAmounts, ctypes.c_void_p)
+ self._pending_reg_stack_adjustment_amount_lists[amount_ptr.value] = (amount_ptr.value, result.registerStackAdjustmentAmounts)
+
+ out_layout[0] = result
+ except:
+ log_error_for_exception("Unhandled Python exception in CallingConvention._get_call_layout")
+ result = core.BNCallLayout()
+ result.parameterCount = 0
+ result.returnValueValid = False
+ result.stackAdjustment = 0
+ result.registerStackAdjustmentCount = 0
+ out_layout[0] = result
+
+ def _free_call_layout(self, ctxt, layout_ptr):
+ try:
+ layout = layout_ptr[0]
+ param_ptr = ctypes.cast(layout.parameters, ctypes.c_void_p)
+ if param_ptr.value is not None:
+ if param_ptr.value not in self._pending_value_location_lists:
+ raise ValueError("freeing parameter location list that wasn't allocated")
+ del self._pending_value_location_lists[param_ptr.value]
+
+ if layout.returnValueValid:
+ ret_ptr = ctypes.cast(layout.returnValue.components, ctypes.c_void_p)
+ if ret_ptr.value is not None:
+ if ret_ptr.value not in self._pending_value_locations:
+ raise ValueError("freeing return value location that wasn't allocated")
+ del self._pending_value_locations[ret_ptr.value]
+
+ reg_ptr = ctypes.cast(layout.registerStackAdjustmentRegisters, ctypes.c_void_p)
+ if reg_ptr.value is not None:
+ if reg_ptr.value not in self._pending_reg_stack_adjustment_reg_lists:
+ raise ValueError("freeing register list that wasn't allocated")
+ del self._pending_reg_stack_adjustment_reg_lists[reg_ptr.value]
+
+ amount_ptr = ctypes.cast(layout.registerStackAdjustmentAmounts, ctypes.c_void_p)
+ if amount_ptr.value is not None:
+ if amount_ptr.value not in self._pending_reg_stack_adjustment_amount_lists:
+ raise ValueError("freeing adjustment list that wasn't allocated")
+ del self._pending_reg_stack_adjustment_amount_lists[amount_ptr.value]
+ except:
+ log_error_for_exception("Unhandled Python exception in CallingConvention._free_call_layout")
+
+ def _get_return_value_location(self, ctxt, view, ret_value, out_location):
+ try:
+ if view:
+ view_obj = binaryview.BinaryView(handle=core.BNNewViewReference(view))
+ else:
+ view_obj = None
+ ret = types.ReturnValue._from_core_struct(ret_value[0])
+ location = self.get_return_value_location(view_obj, ret)
+ if location is None:
+ location = types.ValueLocation([])
+ result = location._to_core_struct()
+ result_ptr = ctypes.cast(result.components, ctypes.c_void_p)
+ self._pending_value_locations[result_ptr.value] = (result_ptr.value, result)
+ out_location[0] = result
+ except:
+ log_error_for_exception("Unhandled Python exception in CallingConvention._get_return_value_location")
+ result = core.BNValueLocation()
+ result.count = 0
+ result.components = None
+ out_location[0] = result
+
+ def _free_value_location(self, ctxt, location_ptr):
+ try:
+ location = location_ptr[0]
+ loc_ptr = ctypes.cast(location.components, ctypes.c_void_p)
+ if loc_ptr.value is not None:
+ if loc_ptr.value not in self._pending_value_locations:
+ raise ValueError("freeing value location that wasn't allocated")
+ del self._pending_value_locations[loc_ptr.value]
+ except:
+ log_error_for_exception("Unhandled Python exception in CallingConvention._free_value_location")
+
+ def _get_parameter_locations(
+ self, ctxt, view, ret_value, params, param_count, has_permitted_regs, permitted_regs, permitted_reg_count,
+ out_location_count
+ ):
+ try:
+ if view:
+ view_obj = binaryview.BinaryView(handle=core.BNNewViewReference(view))
+ else:
+ view_obj = None
+ if ret_value:
+ ret_value_obj = types.ValueLocation._from_core_struct(ret_value[0])
+ else:
+ ret_value_obj = None
+ param_objs = []
+ for i in range(param_count):
+ param_objs.append(types.FunctionParameter._from_core_struct(params[i]))
+ if has_permitted_regs:
+ reg_objs = []
+ for i in range(permitted_reg_count):
+ reg_objs.append(architecture.RegisterIndex(permitted_regs[i]))
+ else:
+ reg_objs = None
+ locations = self.get_parameter_locations(view_obj, ret_value_obj, param_objs, permitted_regs = reg_objs)
+
+ out_location_count[0] = len(locations)
+ result = (core.BNValueLocation * len(locations))()
+ for i, location in enumerate(locations):
+ result[i] = location._to_core_struct()
+
+ result_ptr = ctypes.cast(result, ctypes.c_void_p)
+ self._pending_value_location_lists[result_ptr.value] = (result_ptr.value, result)
+
+ return result_ptr.value
+ except:
+ log_error_for_exception("Unhandled Python exception in CallingConvention._get_parameter_locations")
+ out_location_count[0] = 0
+ return None
+
+ def _free_parameter_locations(self, ctxt, locations, count):
+ try:
+ location_ptr = ctypes.cast(locations, ctypes.c_void_p)
+ if location_ptr.value is not None:
+ if location_ptr.value not in self._pending_value_location_lists:
+ raise ValueError("freeing parameter location list that wasn't allocated")
+ del self._pending_value_location_lists[location_ptr.value]
+ except:
+ log_error_for_exception("Unhandled Python exception in CallingConvention._free_parameter_locations")
+
+ def _get_stack_adjustment_for_locations(self, ctxt, view, ret_value, locations, type_list, param_count):
+ try:
+ if view:
+ view_obj = binaryview.BinaryView(handle=core.BNNewViewReference(view))
+ else:
+ view_obj = None
+ if ret_value:
+ ret_value_obj = types.ValueLocation._from_core_struct(ret_value[0])
+ else:
+ ret_value_obj = None
+ params = []
+ for i in range(param_count):
+ loc = types.ValueLocation._from_core_struct(locations[i])
+ ty = types.Type.from_core_struct(type_list[i])
+ params.append((loc, ty))
+ return self.get_stack_adjustment_for_locations(view_obj, ret_value_obj, params)
+ except:
+ log_error_for_exception("Unhandled Python exception in CallingConvention._get_stack_adjustment_for_locations")
+ return 0
+
+ def _get_register_stack_adjustments(self, ctxt, view, ret_value, params, param_count, out_regs, out_adjust):
+ try:
+ if view:
+ view_obj = binaryview.BinaryView(handle=core.BNNewViewReference(view))
+ else:
+ view_obj = None
+ if ret_value:
+ ret_value_obj = types.ValueLocation._from_core_struct(ret_value[0])
+ else:
+ ret_value_obj = None
+ param_objs = []
+ for i in range(param_count):
+ param_objs.append(types.ValueLocation._from_core_struct(params[i]))
+ adjustment = self.get_register_stack_adjustments(view_obj, ret_value_obj, param_objs)
+
+ regs = (ctypes.c_uint * len(adjustment))()
+ adjust = (ctypes.c_int * len(adjustment))()
+ for i, (reg, adj) in enumerate(adjustment.items()):
+ regs[i] = int(reg)
+ adjust[i] = adj
+
+ reg_ptr = ctypes.cast(regs, ctypes.c_void_p)
+ self._pending_reg_stack_adjustment_reg_lists[reg_ptr.value] = (reg_ptr.value, regs)
+ adjust_ptr = ctypes.cast(adjust, ctypes.c_void_p)
+ self._pending_reg_stack_adjustment_amount_lists[adjust_ptr.value] = (adjust_ptr.value, adjust)
+
+ out_regs[0] = regs
+ out_adjust[0] = adjust
+ return len(adjustment)
+ except:
+ log_error_for_exception("Unhandled Python exception in CallingConvention._get_register_stack_adjustments")
+ out_regs[0] = None
+ out_adjust[0] = None
+ return 0
+
+ def _free_register_stack_adjustments(self, ctxt, regs, adjust, count):
+ try:
+ reg_ptr = ctypes.cast(regs, ctypes.c_void_p)
+ if reg_ptr.value is not None:
+ if reg_ptr.value not in self._pending_reg_stack_adjustment_reg_lists:
+ raise ValueError("freeing register list that wasn't allocated")
+ del self._pending_reg_stack_adjustment_reg_lists[reg_ptr.value]
+ adjust_ptr = ctypes.cast(adjust, ctypes.c_void_p)
+ if adjust_ptr.value is not None:
+ if adjust_ptr.value not in self._pending_reg_stack_adjustment_amount_lists:
+ raise ValueError("freeing adjustment list that wasn't allocated")
+ del self._pending_reg_stack_adjustment_amount_lists[adjust_ptr.value]
+ except:
+ log_error_for_exception("Unhandled Python exception in CallingConvention._free_register_stack_adjustments")
+
def perform_get_incoming_reg_value(
self, reg: 'architecture.RegisterName', func: 'function.Function'
) -> 'variable.RegisterValue':
+ """Deprecated, override `get_incoming_reg_value` instead."""
reg_stack = self.arch.get_reg_stack_for_reg(reg)
if reg_stack is not None:
if reg == self.arch.reg_stacks[reg_stack].stack_top_reg:
@@ -504,25 +792,335 @@ class CallingConvention:
def perform_get_incoming_flag_value(
self, flag: 'architecture.FlagName', func: 'function.Function'
) -> 'variable.RegisterValue':
+ """Deprecated, override `get_incoming_flag_value` instead."""
return variable.Undetermined()
def perform_get_incoming_var_for_parameter_var(
self, in_var: 'variable.CoreVariable', func: Optional['function.Function'] = None
) -> 'variable.CoreVariable':
+ """Deprecated, override `get_incoming_var_for_parameter_var` instead."""
out_var = core.BNGetDefaultIncomingVariableForParameterVariable(self.handle, in_var.to_BNVariable())
return variable.CoreVariable.from_BNVariable(out_var)
def perform_get_parameter_var_for_incoming_var(
self, in_var: 'variable.CoreVariable', func: Optional['function.Function'] = None
) -> 'variable.CoreVariable':
+ """Deprecated, override `get_parameter_var_for_incoming_var` instead."""
out_var = core.BNGetDefaultParameterVariableForIncomingVariable(self.handle, in_var.to_BNVariable())
return variable.CoreVariable.from_BNVariable(out_var)
+ def get_incoming_reg_value(
+ self, reg: 'architecture.RegisterName', func: 'function.Function'
+ ) -> 'variable.RegisterValue':
+ return self.perform_get_incoming_reg_value(reg, func)
+
+ def get_incoming_flag_value(
+ self, reg: 'architecture.RegisterName', func: 'function.Function'
+ ) -> 'variable.RegisterValue':
+ return self.perform_get_incoming_flag_value(reg, func)
+
+ def get_incoming_var_for_parameter_var(
+ self, in_var: 'variable.CoreVariable', func: Optional['function.Function'] = None
+ ) -> 'variable.CoreVariable':
+ return self.perform_get_incoming_var_for_parameter_var(in_var, func)
+
+ def get_parameter_var_for_incoming_var(
+ self, in_var: 'variable.CoreVariable', func: Optional['function.Function'] = None
+ ) -> 'variable.CoreVariable':
+ return self.perform_get_incoming_var_for_parameter_var(in_var, func)
+
+ def is_return_type_reg_compatible(self, view: Optional['binaryview.BinaryView'], type: 'types.Type') -> bool:
+ return self.default_is_return_type_reg_compatible(type)
+
+ def is_non_reg_arg_indirect(self, view: Optional['binaryview.BinaryView'], type: Optional['types.Type']) -> bool:
+ return False
+
+ def default_is_return_type_reg_compatible(self, type: 'types.Type') -> bool:
+ return core.BNDefaultIsReturnTypeRegisterCompatible(self.handle, type.handle)
+
+ def get_indirect_return_value_location(self) -> 'variable.CoreVariable':
+ return self.get_default_indirect_return_value_location()
+
+ def get_default_indirect_return_value_location(self) -> 'variable.CoreVariable':
+ result = core.BNGetDefaultIndirectReturnValueLocation(self.handle)
+ return variable.CoreVariable.from_BNVariable(result)
+
+ def get_returned_indirect_return_value_pointer(self) -> Optional['variable.CoreVariable']:
+ return None
+
+ def is_arg_type_reg_compatible(self, view: Optional['binaryview.BinaryView'], type: 'types.Type') -> bool:
+ return self.default_is_arg_type_reg_compatible(type)
+
+ def default_is_arg_type_reg_compatible(self, type: 'types.Type') -> bool:
+ return core.BNDefaultIsArgumentTypeRegisterCompatible(self.handle, type.handle)
+
+ def get_call_layout(
+ self, view: Optional['binaryview.BinaryView'], return_value: Optional['types.ReturnValueOrType'],
+ params: 'types.ParamsType', func: Optional['function.Function'] = None,
+ permitted_regs: Optional[List['architecture.RegisterIndex']] = None
+ ) -> 'CallLayout':
+ return self.get_default_call_layout(view, return_value, params, func, permitted_regs)
+
+ def get_default_call_layout(
+ self, view: Optional['binaryview.BinaryView'], return_value: Optional['types.ReturnValueOrType'],
+ params: 'types.ParamsType', func: Optional['function.Function'] = None,
+ permitted_regs: Optional[List['architecture.RegisterIndex']] = None
+ ) -> 'CallLayout':
+ if view is None:
+ view_obj = None
+ else:
+ view_obj = view.handle
+ if return_value is None:
+ ret = types.ReturnValue(types.Type.void())._to_core_struct()
+ elif isinstance(return_value, types.ReturnValue):
+ ret = return_value._to_core_struct()
+ else:
+ ret = types.ReturnValue(return_value)._to_core_struct()
+ param_structs, type_list = types.FunctionBuilder._to_core_struct(params)
+ if permitted_regs is None:
+ layout = core.BNGetDefaultCallLayoutDefaultPermittedArgs(self.handle, view_obj, ret, param_structs, len(params))
+ else:
+ regs = (ctypes.c_uint * len(permitted_regs))()
+ for i in range(len(permitted_regs)):
+ regs[i] = int(permitted_regs[i])
+ layout = core.BNGetDefaultCallLayout(self.handle, view_obj, ret, param_structs, len(params), regs,
+ len(permitted_regs))
+ result = CallLayout._from_core_struct(layout, func)
+ core.BNFreeCallLayout(layout)
+ return result
+
+ def get_return_value_location(
+ self, view: Optional['binaryview.BinaryView'], return_value: 'types.ReturnValueOrType'
+ ) -> Optional['types.ValueLocation']:
+ return self.get_default_return_value_location(view, return_value)
+
+ def get_default_return_value_location(
+ self, view: Optional['binaryview.BinaryView'], return_value: 'types.ReturnValueOrType'
+ ) -> Optional['types.ValueLocation']:
+ if view is None:
+ view_obj = None
+ else:
+ view_obj = view.handle
+ if return_value is None:
+ ret = types.ReturnValue(types.Type.void())._to_core_struct()
+ elif isinstance(return_value, types.ReturnValue):
+ ret = return_value._to_core_struct()
+ else:
+ ret = types.ReturnValue(return_value)._to_core_struct()
+ location = core.BNGetDefaultReturnValueLocation(self.handle, view_obj, ret)
+ if location.count == 0:
+ result = None
+ else:
+ result = types.ValueLocation._from_core_struct(location)
+ core.BNFreeValueLocation(location)
+ return result
+
+ def get_parameter_locations(
+ self, view: Optional['binaryview.BinaryView'], return_value: Optional['types.ValueLocation'],
+ params: 'types.ParamsType', arch: Optional['architecture.Architecture'] = None,
+ permitted_regs: Optional[List['architecture.RegisterIndex']] = None
+ ) -> List['types.ValueLocation']:
+ return self.get_default_parameter_locations(view, return_value, params, arch, permitted_regs)
+
+ def get_default_parameter_locations(
+ self, view: Optional['binaryview.BinaryView'], return_value: Optional['types.ValueLocation'],
+ params: 'types.ParamsType', arch: Optional['architecture.Architecture'] = None,
+ permitted_regs: Optional[List['architecture.RegisterIndex']] = None
+ ) -> List['types.ValueLocation']:
+ if view is None:
+ view_obj = None
+ else:
+ view_obj = view.handle
+ if return_value is None:
+ ret = None
+ else:
+ ret = return_value._to_core_struct()
+ param_structs, type_list = types.FunctionBuilder._to_core_struct(params)
+ count = ctypes.c_ulonglong()
+ if permitted_regs is None:
+ locations = core.BNGetDefaultParameterLocationsDefaultPermittedArgs(self.handle, view_obj, ret, param_structs,
+ len(params), count)
+ else:
+ regs = (ctypes.c_uint * len(permitted_regs))()
+ for i in range(len(permitted_regs)):
+ regs[i] = int(permitted_regs[i])
+ locations = core.BNGetDefaultParameterLocations(self.handle, view_obj, ret, param_structs, len(params), regs,
+ len(permitted_regs), count)
+ result = []
+ for i in range(count.value):
+ result.append(types.ValueLocation._from_core_struct(locations[i], arch))
+ core.BNFreeValueLocationList(locations, count.value)
+ return result
+
+ def get_stack_adjustment_for_locations(
+ self, view: Optional['binaryview.BinaryView'], return_value: Optional['types.ValueLocation'],
+ params: List[Tuple['types.ValueLocation', 'types.Type']]
+ ):
+ return self.get_default_stack_adjustment_for_locations(return_value, params)
+
+ def get_default_stack_adjustment_for_locations(
+ self, return_value: Optional['types.ValueLocation'],
+ params: List[Tuple['types.ValueLocation', 'types.Type']]
+ ):
+ if return_value is None:
+ ret = None
+ else:
+ ret = return_value._to_core_struct()
+ locations = (core.BNValueLocation * len(params))()
+ type_list = (ctypes.POINTER(core.BNType) * len(params))()
+ for i, (loc, ty) in enumerate(params):
+ locations[i] = loc._to_core_struct()
+ type_list[i] = ty.handle
+ return core.BNGetDefaultStackAdjustmentForLocations(self.handle, ret, locations, type_list, len(params))
+
+ def get_register_stack_adjustments(
+ self, view: Optional['binaryview.BinaryView'], return_value: Optional['types.ValueLocation'],
+ params: List['types.ValueLocation']
+ ) -> Dict['architecture.RegisterIndex', int]:
+ return self.get_default_register_stack_adjustments(return_value, params)
+
+ def get_default_register_stack_adjustments(
+ self, return_value: Optional['types.ValueLocation'], params: List['types.ValueLocation']
+ ) -> Dict['architecture.RegisterIndex', int]:
+ if return_value is None:
+ ret = None
+ else:
+ ret = return_value._to_core_struct()
+ locations = (core.BNValueLocation * len(params))()
+ for i, loc in enumerate(params):
+ locations[i] = loc._to_core_struct()
+ out_regs = ctypes.POINTER(ctypes.c_uint)()
+ out_adjust = ctypes.POINTER(ctypes.c_int)()
+ count = core.BNGetCallingConventionDefaultRegisterStackAdjustments(self.handle, ret, locations, len(params),
+ out_regs, out_adjust)
+
+ result = {}
+ for i in range(count):
+ result[architecture.RegisterIndex(out_regs[i])] = out_adjust[i]
+
+ core.BNFreeCallingConventionRegisterStackAdjustments(out_regs, out_adjust)
+ return result
+
def with_confidence(self, confidence: int) -> 'CallingConvention':
return CallingConvention(
self.arch, handle=core.BNNewCallingConventionReference(self.handle), confidence=confidence
)
+ @property
+ def arch(self) -> 'architecture.Architecture':
+ return self._arch
+
+ @arch.setter
+ def arch(self, value: 'architecture.Architecture') -> None:
+ self._arch = value
+
+
+class CoreCallingConvention(CallingConvention):
+ def __init__(self, handle, confidence: int = core.max_confidence):
+ super().__init__(handle=handle, confidence=confidence)
+
+ self.arch = architecture.CoreArchitecture._from_cache(core.BNGetCallingConventionArchitecture(handle))
+ self.__dict__["name"] = core.BNGetCallingConventionName(handle)
+ self.__dict__["arg_regs_share_index"] = core.BNAreArgumentRegistersSharedIndex(handle)
+ self.__dict__["arg_regs_for_varargs"] = core.BNAreArgumentRegistersUsedForVarArgs(handle)
+ self.__dict__["stack_reserved_for_arg_regs"] = core.BNIsStackReservedForArgumentRegisters(handle)
+ self.__dict__["stack_adjusted_on_return"] = core.BNIsStackAdjustedOnReturn(handle)
+ self.__dict__["eligible_for_heuristics"] = core.BNIsEligibleForHeuristics(handle)
+
+ count = ctypes.c_ulonglong()
+ regs = core.BNGetCallerSavedRegisters(handle, count)
+ assert regs is not None, "core.BNGetCallerSavedRegisters returned None"
+ result = []
+ arch = self.arch
+ for i in range(0, count.value):
+ result.append(arch.get_reg_name(regs[i]))
+ core.BNFreeRegisterList(regs)
+ self.__dict__["caller_saved_regs"] = result
+
+ count = ctypes.c_ulonglong()
+ regs = core.BNGetCalleeSavedRegisters(handle, count)
+ assert regs is not None, "core.BNGetCalleeSavedRegisters returned None"
+ result = []
+ arch = self.arch
+ for i in range(0, count.value):
+ result.append(arch.get_reg_name(regs[i]))
+ core.BNFreeRegisterList(regs)
+ self.__dict__["callee_saved_regs"] = result
+
+ count = ctypes.c_ulonglong()
+ regs = core.BNGetIntegerArgumentRegisters(handle, count)
+ assert regs is not None, "core.BNGetIntegerArgumentRegisters returned None"
+ result = []
+ arch = self.arch
+ for i in range(0, count.value):
+ result.append(arch.get_reg_name(regs[i]))
+ core.BNFreeRegisterList(regs)
+ self.__dict__["int_arg_regs"] = result
+
+ count = ctypes.c_ulonglong()
+ regs = core.BNGetFloatArgumentRegisters(handle, count)
+ assert regs is not None, "core.BNGetFloatArgumentRegisters returned None"
+ result = []
+ arch = self.arch
+ for i in range(0, count.value):
+ result.append(arch.get_reg_name(regs[i]))
+ core.BNFreeRegisterList(regs)
+ self.__dict__["float_arg_regs"] = result
+
+ count = ctypes.c_ulonglong()
+ regs = core.BNGetRequiredArgumentRegisters(handle, count)
+ assert regs is not None, "core.BNGetRequiredArgumentRegisters returned None"
+ result = []
+ arch = self.arch
+ for i in range(0, count.value):
+ result.append(arch.get_reg_name(regs[i]))
+ core.BNFreeRegisterList(regs)
+ self.__dict__["required_arg_regs"] = result
+
+ count = ctypes.c_ulonglong()
+ regs = core.BNGetRequiredClobberedRegisters(handle, count)
+ assert regs is not None, "core.BNGetRequiredClobberedRegisters returned None"
+ result = []
+ arch = self.arch
+ for i in range(0, count.value):
+ result.append(arch.get_reg_name(regs[i]))
+ core.BNFreeRegisterList(regs)
+ self.__dict__["required_clobbered_regs"] = result
+
+ reg = core.BNGetIntegerReturnValueRegister(handle)
+ if reg == 0xffffffff:
+ self.__dict__["int_return_reg"] = None
+ else:
+ self.__dict__["int_return_reg"] = self.arch.get_reg_name(reg)
+
+ reg = core.BNGetHighIntegerReturnValueRegister(handle)
+ if reg == 0xffffffff:
+ self.__dict__["high_int_return_reg"] = None
+ else:
+ self.__dict__["high_int_return_reg"] = self.arch.get_reg_name(reg)
+
+ reg = core.BNGetFloatReturnValueRegister(handle)
+ if reg == 0xffffffff:
+ self.__dict__["float_return_reg"] = None
+ else:
+ self.__dict__["float_return_reg"] = self.arch.get_reg_name(reg)
+
+ reg = core.BNGetGlobalPointerRegister(handle)
+ if reg == 0xffffffff:
+ self.__dict__["global_pointer_reg"] = None
+ else:
+ self.__dict__["global_pointer_reg"] = self.arch.get_reg_name(reg)
+
+ count = ctypes.c_ulonglong()
+ regs = core.BNGetImplicitlyDefinedRegisters(handle, count)
+ assert regs is not None, "core.BNGetImplicitlyDefinedRegisters returned None"
+ result = []
+ arch = self.arch
+ for i in range(0, count.value):
+ result.append(arch.get_reg_name(regs[i]))
+ core.BNFreeRegisterList(regs)
+ self.__dict__["implicitly_defined_regs"] = result
+
def get_incoming_reg_value(
self, reg: 'architecture.RegisterType', func: 'function.Function'
) -> 'variable.RegisterValue':
@@ -546,7 +1144,7 @@ class CallingConvention:
)
def get_incoming_var_for_parameter_var(
- self, in_var: 'variable.CoreVariable', func: FunctionOrILFunction
+ self, in_var: 'variable.CoreVariable', func: FunctionOrILFunction = None
) -> 'variable.Variable':
in_buf = in_var.to_BNVariable()
if func is None:
@@ -557,7 +1155,7 @@ class CallingConvention:
return variable.Variable.from_BNVariable(func, out_var)
def get_parameter_var_for_incoming_var(
- self, in_var: 'variable.CoreVariable', func: FunctionOrILFunction
+ self, in_var: 'variable.CoreVariable', func: FunctionOrILFunction = None
) -> 'variable.Variable':
in_buf = in_var.to_BNVariable()
if func is None:
@@ -567,10 +1165,160 @@ class CallingConvention:
out_var = core.BNGetParameterVariableForIncomingVariable(self.handle, in_buf, func_obj)
return variable.Variable.from_BNVariable(func, out_var)
- @property
- def arch(self) -> 'architecture.Architecture':
- return self._arch
+ def is_return_type_reg_compatible(self, view: Optional['binaryview.BinaryView'], type: 'types.Type') -> bool:
+ if view is None:
+ view_obj = None
+ else:
+ view_obj = view.handle
+ return core.BNIsReturnTypeRegisterCompatible(self.handle, view_obj, type.handle)
- @arch.setter
- def arch(self, value: 'architecture.Architecture') -> None:
- self._arch = value
+ def get_indirect_return_value_location(self) -> 'variable.CoreVariable':
+ result = core.BNGetIndirectReturnValueLocation(self.handle)
+ return variable.CoreVariable.from_BNVariable(result)
+
+ def get_returned_indirect_return_value_pointer(self) -> Optional['variable.CoreVariable']:
+ var = core.BNVariable()
+ if core.BNGetReturnedIndirectReturnValuePointer(self.handle, var):
+ return variable.CoreVariable.from_BNVariable(var)
+ return None
+
+ def is_arg_type_reg_compatible(self, view: Optional['binaryview.BinaryView'], type: 'types.Type') -> bool:
+ if view is None:
+ view_obj = None
+ else:
+ view_obj = view.handle
+ return core.BNIsArgumentTypeRegisterCompatible(self.handle, view_obj, type.handle)
+
+ def is_non_reg_arg_indirect(self, view: Optional['binaryview.BinaryView'], type: Optional['types.Type']) -> bool:
+ if view is None:
+ view_obj = None
+ else:
+ view_obj = view.handle
+ if type is None:
+ return core.BNIsNonRegisterArgumentIndirect(self.handle, view_obj, None)
+ else:
+ return core.BNIsNonRegisterArgumentIndirect(self.handle, view_obj, type.handle)
+
+ def get_call_layout(
+ self, view: Optional['binaryview.BinaryView'], return_value: Optional['types.ReturnValueOrType'],
+ params: 'types.ParamsType', func: Optional['function.Function'] = None,
+ permitted_regs: Optional[List['architecture.RegisterIndex']] = None
+ ) -> 'CallLayout':
+ if view is None:
+ view_obj = None
+ else:
+ view_obj = view.handle
+ if return_value is None:
+ ret = types.ReturnValue(types.Type.void())._to_core_struct()
+ elif isinstance(return_value, types.ReturnValue):
+ ret = return_value._to_core_struct()
+ else:
+ ret = types.ReturnValue(return_value)._to_core_struct()
+ param_structs, type_list = types.FunctionBuilder._to_core_struct(params)
+ if permitted_regs is None:
+ layout = core.BNGetCallLayoutDefaultPermittedArgs(self.handle, view_obj, ret, param_structs, len(params))
+ else:
+ regs = (ctypes.c_uint * len(permitted_regs))()
+ for i in range(len(permitted_regs)):
+ regs[i] = int(permitted_regs[i])
+ layout = core.BNGetCallLayout(self.handle, view_obj, ret, param_structs, len(params), regs, len(permitted_regs))
+ result = CallLayout._from_core_struct(layout, func)
+ core.BNFreeCallLayout(layout)
+ return result
+
+ def get_return_value_location(
+ self, view: Optional['binaryview.BinaryView'], return_value: 'types.ReturnValueOrType'
+ ) -> Optional['types.ValueLocation']:
+ if view is None:
+ view_obj = None
+ else:
+ view_obj = view.handle
+ if return_value is None:
+ ret = types.ReturnValue(types.Type.void())._to_core_struct()
+ elif isinstance(return_value, types.ReturnValue):
+ ret = return_value._to_core_struct()
+ else:
+ ret = types.ReturnValue(return_value)._to_core_struct()
+ location = core.BNGetReturnValueLocation(self.handle, view_obj, ret)
+ if location.count == 0:
+ result = None
+ else:
+ result = types.ValueLocation._from_core_struct(location)
+ core.BNFreeValueLocation(location)
+ return result
+
+ def get_parameter_locations(
+ self, view: Optional['binaryview.BinaryView'], return_value: Optional['types.ValueLocation'],
+ params: 'types.ParamsType', arch: Optional['architecture.Architecture'] = None,
+ permitted_regs: Optional[List['architecture.RegisterIndex']] = None
+ ) -> List['types.ValueLocation']:
+ if view is None:
+ view_obj = None
+ else:
+ view_obj = view.handle
+ if return_value is None:
+ ret = None
+ else:
+ ret = return_value._to_core_struct()
+ param_structs, type_list = types.FunctionBuilder._to_core_struct(params)
+ count = ctypes.c_ulonglong()
+ if permitted_regs is None:
+ locations = core.BNGetParameterLocationsDefaultPermittedArgs(self.handle, view_obj, ret, param_structs,
+ len(params), count)
+ else:
+ regs = (ctypes.c_uint * len(permitted_regs))()
+ for i in range(len(permitted_regs)):
+ regs[i] = int(permitted_regs[i])
+ locations = core.BNGetParameterLocations(self.handle, view_obj, ret, param_structs, len(params), regs,
+ len(permitted_regs), count)
+ result = []
+ for i in range(count.value):
+ result.append(types.ValueLocation._from_core_struct(locations[i], arch))
+ core.BNFreeValueLocationList(locations, count.value)
+ return result
+
+ def get_stack_adjustment_for_locations(
+ self, view: Optional['binaryview.BinaryView'], return_value: Optional['types.ValueLocation'],
+ params: List[Tuple['types.ValueLocation', 'types.Type']]
+ ):
+ if view is None:
+ view_obj = None
+ else:
+ view_obj = view.handle
+ if return_value is None:
+ ret = None
+ else:
+ ret = return_value._to_core_struct()
+ locations = (core.BNValueLocation * len(params))()
+ type_list = (ctypes.POINTER(core.BNType) * len(params))()
+ for i, (loc, ty) in enumerate(params):
+ locations[i] = loc._to_core_struct()
+ type_list[i] = ty.handle
+ return core.BNGetStackAdjustmentForLocations(self.handle, view_obj, ret, locations, type_list, len(params))
+
+ def get_register_stack_adjustments(
+ self, view: Optional['binaryview.BinaryView'], return_value: Optional['types.ValueLocation'],
+ params: List['types.ValueLocation']
+ ) -> Dict['architecture.RegisterIndex', int]:
+ if view is None:
+ view_obj = None
+ else:
+ view_obj = view.handle
+ if return_value is None:
+ ret = None
+ else:
+ ret = return_value._to_core_struct()
+ locations = (core.BNValueLocation * len(params))()
+ for i, loc in enumerate(params):
+ locations[i] = loc._to_core_struct()
+ out_regs = ctypes.POINTER(ctypes.c_uint)()
+ out_adjust = ctypes.POINTER(ctypes.c_int)()
+ count = core.BNGetCallingConventionRegisterStackAdjustments(self.handle, view_obj, ret, locations, len(params),
+ out_regs, out_adjust)
+
+ result = {}
+ for i in range(count):
+ result[architecture.RegisterIndex(out_regs[i])] = out_adjust[i]
+
+ core.BNFreeCallingConventionRegisterStackAdjustments(out_regs, out_adjust)
+ return result
diff --git a/python/examples/pseudo_python.py b/python/examples/pseudo_python.py
index d29d4e57..af06b461 100644
--- a/python/examples/pseudo_python.py
+++ b/python/examples/pseudo_python.py
@@ -517,6 +517,17 @@ class PseudoPythonFunction(LanguageRepresentationFunction):
OperatorPrecedence.UnaryOperatorPrecedence)
if parens:
tokens.append_close_paren()
+ elif instr.operation == HighLevelILOperation.HLIL_PASS_BY_REF:
+ if instr.src.operation == HighLevelILOperation.HLIL_ADDRESS_OF:
+ self.perform_get_expr_text(instr.src, tokens, settings,
+ OperatorPrecedence.UnaryOperatorPrecedence)
+ else:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.OperationToken, "*"))
+ self.perform_get_expr_text(instr.src, tokens, settings,
+ OperatorPrecedence.UnaryOperatorPrecedence)
+ elif instr.operation == HighLevelILOperation.HLIL_RETURN_BY_REF:
+ self.perform_get_expr_text(instr.src, tokens, settings,
+ OperatorPrecedence.UnaryOperatorPrecedence)
elif instr.operation in [HighLevelILOperation.HLIL_CMP_E, HighLevelILOperation.HLIL_FCMP_E]:
parens = precedence > OperatorPrecedence.EqualityOperatorPrecedence
if parens:
@@ -1136,23 +1147,33 @@ class PseudoPythonFunctionType(LanguageRepresentationFunctionType):
tokens.append(InstructionTextToken(InstructionTextTokenType.KeywordToken, "def "))
tokens.append(InstructionTextToken(InstructionTextTokenType.CodeSymbolToken, func.name, value=func.start))
tokens.append(InstructionTextToken(InstructionTextTokenType.BraceToken, "("))
+ params = func.type.parameters
for (i, param) in enumerate(func.type.parameters_with_all_locations):
if i > 0:
tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ", "))
+ var = param.location.variable_for_parameter(i)
tokens.append(InstructionTextToken(InstructionTextTokenType.ArgumentNameToken, param.name,
context=InstructionTextTokenContext.LocalVariableTokenContext,
- address=param.location.identifier))
+ address=var.identifier))
tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ": "))
for token in param.type.get_tokens():
token.context = InstructionTextTokenContext.LocalVariableTokenContext
- token.address = param.location.identifier
+ token.address = var.identifier
tokens.append(token)
+ if i < len(params) and params[i].location is not None:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, " @ "))
+ tokens.append(InstructionTextToken(InstructionTextTokenType.ValueLocationToken,
+ params[i].location.to_string(func.arch)))
tokens.append(InstructionTextToken(InstructionTextTokenType.BraceToken, ")"))
if func.can_return.value and func.type.return_value is not None and not isinstance(func.type.return_value, VoidType):
tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, " -> "))
for token in func.type.return_value.get_tokens():
token.context = InstructionTextTokenContext.FunctionReturnTokenContext
tokens.append(token)
+ if func.type.return_value_location is not None:
+ tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, " @ "))
+ tokens.append(InstructionTextToken(InstructionTextTokenType.ValueLocationToken,
+ func.type.return_value_location.location.to_string(func.arch)))
tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, ":"))
return [DisassemblyTextLine(tokens, func.start)]
diff --git a/python/function.py b/python/function.py
index 8c9eaf1d..900aa0de 100644
--- a/python/function.py
+++ b/python/function.py
@@ -29,7 +29,7 @@ from . import _binaryninjacore as core
from .enums import (
AnalysisSkipReason, FunctionGraphType, SymbolType, SymbolBinding, InstructionTextTokenType, HighlightStandardColor,
HighlightColorStyle, DisassemblyOption, IntegerDisplayType, FunctionAnalysisSkipOverride, FunctionUpdateType,
- BuiltinType, ExprFolding, EarlyReturn, SwitchRecovery
+ BuiltinType, ExprFolding, EarlyReturn, SwitchRecovery, VariableSourceType
)
from . import associateddatastore # Required in the main scope due to being an argument for _FunctionAssociatedDataStore
@@ -1361,8 +1361,49 @@ class Function:
core.BNSetUserFunctionReturnType(self.handle, type_conf)
@property
+ def return_value(self) -> 'types.ReturnValue':
+ """Return type and location"""
+ ret = core.BNGetFunctionReturnValue(self.handle)
+ result = types.ReturnValue._from_core_struct(ret, self.arch)
+ core.BNFreeReturnValue(ret)
+ return result
+
+ @return_value.setter
+ def return_value(self, value: 'types.ReturnValue') -> None: # type: ignore
+ ret = value._to_core_struct()
+ core.BNSetUserFunctionReturnValue(self.handle, ret)
+
+ @property
+ def return_value_location(self) -> Optional['types.ValueLocationWithConfidence']:
+ """
+ The location of the return value, or None if there isn't a return value. If the return value has been
+ specified to be placed in the default location, this will return the default location.
+ """
+ location = core.BNGetFunctionReturnValueLocation(self.handle)
+ if location.location.count == 0:
+ result = None
+ else:
+ result = types.ValueLocation._from_core_struct(location.location, self.arch).with_confidence(location.confidence)
+ core.BNFreeValueLocation(location.location)
+ return result
+
+ @return_value_location.setter
+ def return_value_location(self, value: 'types.OptionalLocation'):
+ struct = core.BNValueLocationWithConfidence()
+ location = types.ValueLocationWithConfidence.from_optional_location(value)
+ if location is None:
+ struct.location.count = 0
+ struct.confidence = 0
+ else:
+ struct.location = location.location._to_core_struct()
+ struct.confidence = location.confidence
+ core.BNSetUserIsFunctionReturnValueDefaultLocation(self.handle, value is None)
+ if value is not None:
+ core.BNSetUserFunctionReturnValueLocation(self.handle, struct)
+
+ @property
def return_regs(self) -> 'types.RegisterSet':
- """Registers that are used for the return value"""
+ """Registers that are used for the return value (read-only)"""
result = core.BNGetFunctionReturnRegisters(self.handle)
assert result is not None, "core.BNGetFunctionReturnRegisters returned None"
try:
@@ -1373,26 +1414,13 @@ class Function:
finally:
core.BNFreeRegisterSet(result)
- @return_regs.setter
- def return_regs(self, value: Union['types.RegisterSet', List['architecture.RegisterType']]) -> None: # type: ignore
- regs = core.BNRegisterSetWithConfidence()
- regs.regs = (ctypes.c_uint * len(value))()
- regs.count = len(value)
- for i in range(0, len(value)):
- regs.regs[i] = self.arch.get_reg_index(value[i])
- if isinstance(value, types.RegisterSet):
- regs.confidence = value.confidence
- else:
- regs.confidence = core.max_confidence
- core.BNSetUserFunctionReturnRegisters(self.handle, regs)
-
@property
def calling_convention(self) -> Optional['callingconvention.CallingConvention']:
"""Calling convention used by the function"""
result = core.BNGetFunctionCallingConvention(self.handle)
if not result.convention:
return None
- return callingconvention.CallingConvention(None, handle=result.convention, confidence=result.confidence)
+ return callingconvention.CoreCallingConvention(handle=result.convention, confidence=result.confidence)
@calling_convention.setter
def calling_convention(self, value: Optional['callingconvention.CallingConvention']) -> None:
@@ -1424,20 +1452,60 @@ class Function:
var_list = []
else:
var_list = list(value)
- var_conf = core.BNParameterVariablesWithConfidence()
- var_conf.vars = (core.BNVariable * len(var_list))()
- var_conf.count = len(var_list)
- for i in range(0, len(var_list)):
- var_conf.vars[i].type = var_list[i].source_type
- var_conf.vars[i].index = var_list[i].index
- var_conf.vars[i].storage = var_list[i].storage
+ locations = []
+ for i in range(len(var_list)):
+ if (var_list[i].source_type != VariableSourceType.RegisterVariableSourceType and
+ var_list[i].source_type != VariableSourceType.StackVariableSourceType and
+ var_list[i].source_type != VariableSourceType.FlagVariableSourceType):
+ raise ValueError(f"Parameter {i} is a composite variable. Use parameter_locations instead.")
+ locations.append(types.ValueLocation([types.ValueLocationComponent(var_list[i])]))
if value is None:
- var_conf.confidence = 0
- elif isinstance(value, types.RegisterSet):
- var_conf.confidence = value.confidence
+ conf = 0
+ elif isinstance(value, variable.ParameterVariables):
+ conf = value.confidence
else:
- var_conf.confidence = core.max_confidence
- core.BNSetUserFunctionParameterVariables(self.handle, var_conf)
+ conf = core.max_confidence
+ self.parameter_locations = variable.ParameterLocations(locations, conf, self)
+
+ @property
+ def parameter_locations(self) -> 'variable.ParameterLocations':
+ """List of locations for the incoming function parameters"""
+ result = core.BNGetFunctionParameterLocations(self.handle)
+ location_list = []
+ for i in range(0, result.count):
+ location_list.append(types.ValueLocation._from_core_struct(result.locations[i], self.arch))
+ confidence = result.confidence
+ core.BNFreeParameterLocations(result)
+ return variable.ParameterLocations(location_list, confidence, self)
+
+ @parameter_locations.setter
+ def parameter_locations(
+ self, value: Optional[Union[List[Union['types.ValueLocation', 'variable.CoreVariable']],
+ 'variable.CoreVariable', 'variable.ParameterLocations']]
+ ) -> None: # type: ignore
+ if value is None:
+ location_list = []
+ elif isinstance(value, variable.CoreVariable):
+ location_list = [value]
+ elif isinstance(value, variable.ParameterLocations):
+ location_list = value.locations
+ else:
+ location_list = list(value)
+ location_conf = core.BNValueLocationListWithConfidence()
+ location_conf.locations = (core.BNValueLocation * len(location_list))()
+ location_conf.count = len(location_list)
+ for i in range(0, len(location_list)):
+ if isinstance(location_list[i], types.ValueLocation):
+ location_conf.locations[i] = location_list[i]._to_core_struct()
+ else:
+ location_conf.locations[i] = types.ValueLocation([types.ValueLocationComponent(location_list[i])])._to_core_struct()
+ if value is None:
+ location_conf.confidence = 0
+ elif isinstance(value, variable.ParameterLocations):
+ location_conf.confidence = value.confidence
+ else:
+ location_conf.confidence = core.max_confidence
+ core.BNSetUserFunctionParameterLocations(self.handle, location_conf)
@property
def has_variable_arguments(self) -> 'types.BoolWithConfidence':
@@ -2477,18 +2545,18 @@ class Function:
type_conf.confidence = value.confidence
core.BNSetAutoFunctionReturnType(self.handle, type_conf)
- def set_auto_return_regs(self, value: Union['types.RegisterSet', List['architecture.RegisterType']]) -> None:
- regs = core.BNRegisterSetWithConfidence()
- regs.regs = (ctypes.c_uint * len(value))()
- regs.count = len(value)
-
- for i in range(0, len(value)):
- regs.regs[i] = self.arch.get_reg_index(value[i])
- if isinstance(value, types.RegisterSet):
- regs.confidence = value.confidence
+ def set_auto_return_value_location(self, value: 'types.OptionalLocation'):
+ struct = core.BNValueLocationWithConfidence()
+ location = types.ValueLocationWithConfidence.from_optional_location(value)
+ if location is None:
+ struct.location.count = 0
+ struct.confidence = 0
else:
- regs.confidence = core.max_confidence
- core.BNSetAutoFunctionReturnRegisters(self.handle, regs)
+ struct.location = location.location._to_core_struct()
+ struct.confidence = location.confidence
+ core.BNSetAutoIsFunctionReturnValueDefaultLocation(self.handle, value is None)
+ if value is not None:
+ core.BNSetAutoFunctionReturnValueLocation(self.handle, struct)
def set_auto_calling_convention(self, value: 'callingconvention.CallingConvention') -> None:
conv_conf = core.BNCallingConventionWithConfidence()
@@ -2501,30 +2569,58 @@ class Function:
core.BNSetAutoFunctionCallingConvention(self.handle, conv_conf)
def set_auto_parameter_vars(
- self, value: Optional[Union[List['variable.Variable'], 'variable.Variable', 'variable.ParameterVariables']]
+ self, value: Optional[Union[List['variable.CoreVariable'], 'variable.CoreVariable', 'variable.ParameterVariables']]
) -> None:
if value is None:
var_list = []
- elif isinstance(value, variable.Variable):
+ elif isinstance(value, variable.CoreVariable):
var_list = [value]
elif isinstance(value, variable.ParameterVariables):
var_list = value.vars
else:
var_list = list(value)
- var_conf = core.BNParameterVariablesWithConfidence()
- var_conf.vars = (core.BNVariable * len(var_list))()
- var_conf.count = len(var_list)
- for i in range(0, len(var_list)):
- var_conf.vars[i].type = var_list[i].source_type
- var_conf.vars[i].index = var_list[i].index
- var_conf.vars[i].storage = var_list[i].storage
+ locations = []
+ for i in range(len(var_list)):
+ if (var_list[i].source_type != VariableSourceType.RegisterVariableSourceType and
+ var_list[i].source_type != VariableSourceType.StackVariableSourceType and
+ var_list[i].source_type != VariableSourceType.FlagVariableSourceType):
+ raise ValueError(f"Parameter {i} is a composite variable. Use set_auto_parameter_locations instead.")
+ locations.append(types.ValueLocation([types.ValueLocationComponent(var_list[i])]))
+ if value is None:
+ conf = 0
+ elif isinstance(value, variable.ParameterVariables):
+ conf = value.confidence
+ else:
+ conf = core.max_confidence
+ self.set_auto_parameter_locations(variable.ParameterLocations(locations, conf, self))
+
+ def set_auto_parameter_locations(
+ self, value: Optional[Union[List[Union['variable.CoreVariable', 'types.ValueLocation']],
+ 'variable.CoreVariable', 'types.ValueLocation', 'variable.ParameterLocations']]
+ ) -> None:
+ if value is None:
+ location_list = []
+ elif isinstance(value, variable.CoreVariable):
+ location_list = [value]
+ elif isinstance(value, variable.ParameterLocations):
+ location_list = value.locations
+ else:
+ location_list = list(value)
+ location_conf = core.BNValueLocationListWithConfidence()
+ location_conf.locations = (core.BNValueLocation * len(location_list))()
+ location_conf.count = len(location_list)
+ for i in range(0, len(location_list)):
+ if isinstance(location_list[i], types.ValueLocation):
+ location_conf.locations[i] = location_list[i]._to_core_struct()
+ else:
+ location_conf.locations[i] = types.ValueLocation([types.ValueLocationComponent(location_list[i])])._to_core_struct()
if value is None:
- var_conf.confidence = 0
+ location_conf.confidence = 0
elif isinstance(value, variable.ParameterVariables):
- var_conf.confidence = value.confidence
+ location_conf.confidence = value.confidence
else:
- var_conf.confidence = core.max_confidence
- core.BNSetAutoFunctionParameterVariables(self.handle, var_conf)
+ location_conf.confidence = core.max_confidence
+ core.BNSetAutoFunctionParameterLocations(self.handle, location_conf)
def set_auto_has_variable_arguments(self, value: Union[bool, 'types.BoolWithConfidence']) -> None:
bc = core.BNBoolWithConfidence()
diff --git a/python/highlevelil.py b/python/highlevelil.py
index bb1f6129..4c81f687 100644
--- a/python/highlevelil.py
+++ b/python/highlevelil.py
@@ -210,7 +210,11 @@ class HighLevelILInstruction(BaseILInstruction):
], HighLevelILOperation.HLIL_DEREF_FIELD_SSA: [
("src", "expr"), ("src_memory", "int"), ("offset", "int"),
("member_index", "member_index")
- ], HighLevelILOperation.HLIL_ADDRESS_OF: [("src", "expr")], HighLevelILOperation.HLIL_CONST: [
+ ], HighLevelILOperation.HLIL_ADDRESS_OF: [("src", "expr")], HighLevelILOperation.HLIL_PASS_BY_REF: [
+ ("src", "expr")
+ ], HighLevelILOperation.HLIL_RETURN_BY_REF: [
+ ("src", "expr")
+ ], HighLevelILOperation.HLIL_CONST: [
("constant", "int")
], HighLevelILOperation.HLIL_CONST_PTR: [("constant", "int")], HighLevelILOperation.HLIL_EXTERN_PTR: [
("constant", "int"), ("offset", "int")
@@ -1744,6 +1748,16 @@ class HighLevelILAddressOf(HighLevelILUnaryBase):
@dataclass(frozen=True, repr=False, eq=False)
+class HighLevelILPassByRef(HighLevelILUnaryBase):
+ pass
+
+
+@dataclass(frozen=True, repr=False, eq=False)
+class HighLevelILReturnByRef(HighLevelILUnaryBase):
+ pass
+
+
+@dataclass(frozen=True, repr=False, eq=False)
class HighLevelILConst(HighLevelILInstruction, Constant):
@property
def constant(self) -> int:
@@ -2429,6 +2443,8 @@ ILInstruction = {
HighLevelILOperation.HLIL_DEREF_FIELD_SSA:
HighLevelILDerefFieldSsa, # ("src", "expr"), ("src_memory", "int"), ("offset", "int"), ("member_index", "member_index"),
HighLevelILOperation.HLIL_ADDRESS_OF: HighLevelILAddressOf, # ("src", "expr"),
+ HighLevelILOperation.HLIL_PASS_BY_REF: HighLevelILPassByRef, # ("src", "expr"),
+ HighLevelILOperation.HLIL_RETURN_BY_REF: HighLevelILReturnByRef, # ("src", "expr"),
HighLevelILOperation.HLIL_CONST: HighLevelILConst, # ("constant", "int"),
HighLevelILOperation.HLIL_CONST_PTR: HighLevelILConstPtr, # ("constant", "int"),
HighLevelILOperation.HLIL_EXTERN_PTR: HighLevelILExternPtr, # ("constant", "int"), ("offset", "int"),
@@ -3380,6 +3396,30 @@ class HighLevelILFunction:
"""
return self.expr(HighLevelILOperation.HLIL_ADDRESS_OF, src, size=0, source_location=loc)
+ def pass_by_ref(self, size: int, src: ExpressionIndex, loc: Optional['ILSourceLocation'] = None) -> ExpressionIndex:
+ """
+ ``pass_by_ref`` indicates that ``value`` is being passed by reference to a call with a pointer size of ``size``
+
+ :param int size: the size of the pointer in bytes
+ :param ExpressionIndex src: the expression containing the reference being passed
+ :param ILSourceLocation loc: location of returned expression
+ :return: The expression ``ref *src``
+ :rtype: ExpressionIndex
+ """
+ return self.expr(HighLevelILOperation.HLIL_PASS_BY_REF, src, size, source_location=loc)
+
+ def return_by_ref(self, size: int, dest: ExpressionIndex, loc: Optional['ILSourceLocation'] = None) -> ExpressionIndex:
+ """
+ ``return_by_ref`` indicates that ``dest`` is being returned by passing a reference to a call
+
+ :param int size: the size of the value in bytes
+ :param ExpressionIndex dest: the expression containing the target of the return value
+ :param ILSourceLocation loc: location of returned expression
+ :return: The expression ``ref dest``
+ :rtype: ExpressionIndex
+ """
+ return self.expr(HighLevelILOperation.HLIL_RETURN_BY_REF, dest, size, source_location=loc)
+
def const(self, size: int, value: int, loc: Optional['ILSourceLocation'] = None) -> ExpressionIndex:
"""
``const`` returns an expression for the constant integer ``value`` of size ``size``
diff --git a/python/mediumlevelil.py b/python/mediumlevelil.py
index 1a42fe27..155a3751 100644
--- a/python/mediumlevelil.py
+++ b/python/mediumlevelil.py
@@ -219,7 +219,11 @@ class MediumLevelILInstruction(BaseILInstruction):
MediumLevelILOperation.MLIL_VAR: [("src", "var")], MediumLevelILOperation.MLIL_VAR_FIELD: [
("src", "var"), ("offset", "int")
], MediumLevelILOperation.MLIL_VAR_SPLIT: [("high", "var"), ("low", "var")],
- MediumLevelILOperation.MLIL_ADDRESS_OF: [("src", "var")], MediumLevelILOperation.MLIL_ADDRESS_OF_FIELD: [
+ MediumLevelILOperation.MLIL_ADDRESS_OF: [("src", "var")], MediumLevelILOperation.MLIL_PASS_BY_REF: [
+ ("src", "expr")
+ ], MediumLevelILOperation.MLIL_RETURN_BY_REF: [
+ ("src", "expr")
+ ], MediumLevelILOperation.MLIL_ADDRESS_OF_FIELD: [
("src", "var"), ("offset", "int")
], MediumLevelILOperation.MLIL_CONST: [("constant", "int")], MediumLevelILOperation.MLIL_CONST_PTR: [
("constant", "int")
@@ -279,9 +283,15 @@ class MediumLevelILInstruction(BaseILInstruction):
("params", "expr_list")
], MediumLevelILOperation.MLIL_VAR_OUTPUT: [
("dest", "var")
+ ], MediumLevelILOperation.MLIL_VAR_OUTPUT_FIELD: [
+ ("dest", "var"), ("offset", "int")
+ ], MediumLevelILOperation.MLIL_STORE_OUTPUT: [
+ ("dest", "expr")
], MediumLevelILOperation.MLIL_RET: [
("src", "expr_list")
- ], MediumLevelILOperation.MLIL_NORET: [], MediumLevelILOperation.MLIL_IF: [
+ ], MediumLevelILOperation.MLIL_BLOCK_TO_EXPAND: [
+ ("src", "expr_list")
+ ], MediumLevelILOperation.MLIL_NORET: [], MediumLevelILOperation.MLIL_IF: [
("condition", "expr"), ("true", "int"), ("false", "int")
], MediumLevelILOperation.MLIL_GOTO: [("dest", "int")], MediumLevelILOperation.MLIL_CMP_E: [
("left", "expr"), ("right", "expr")
@@ -377,6 +387,12 @@ class MediumLevelILInstruction(BaseILInstruction):
("high", "var_ssa"), ("low", "var_ssa")
], MediumLevelILOperation.MLIL_VAR_OUTPUT_SSA: [
("dest", "var_ssa")
+ ], MediumLevelILOperation.MLIL_VAR_OUTPUT_SSA_FIELD: [
+ ("dest", "var_ssa_dest_and_src"), ("prev", "var_ssa_dest_and_src"), ("offset", "int")
+ ], MediumLevelILOperation.MLIL_VAR_OUTPUT_ALIASED: [
+ ("dest", "var_ssa_dest_and_src"), ("prev", "var_ssa_dest_and_src")
+ ], MediumLevelILOperation.MLIL_VAR_OUTPUT_ALIASED_FIELD: [
+ ("dest", "var_ssa_dest_and_src"), ("prev", "var_ssa_dest_and_src"), ("offset", "int")
], MediumLevelILOperation.MLIL_CALL_SSA: [
("output", "expr"), ("output_dest_memory", "int"), ("dest", "expr"),
("params", "expr_list"), ("src_memory", "int")
@@ -1158,13 +1174,25 @@ class MediumLevelILInstruction(BaseILInstruction):
return result
def _var_written_for_function_call_output(self) -> Optional[variable.Variable]:
+ if isinstance(self, MediumLevelILReturnByRef):
+ return self.src._var_written_for_function_call_output()
if isinstance(self, MediumLevelILVarOutput):
return self.dest
+ if isinstance(self, MediumLevelILVarOutputField):
+ return self.dest
return None
def _ssa_var_written_for_function_call_output(self) -> Optional[SSAVariable]:
+ if isinstance(self, MediumLevelILReturnByRef):
+ return self.src._ssa_var_written_for_function_call_output()
if isinstance(self, MediumLevelILVarOutputSsa):
return self.dest
+ if isinstance(self, MediumLevelILVarOutputSsaField):
+ return self.dest
+ if isinstance(self, MediumLevelILVarOutputAliased):
+ return self.dest
+ if isinstance(self, MediumLevelILVarOutputAliasedField):
+ return self.dest
return None
@@ -1324,6 +1352,16 @@ class MediumLevelILAddressOf(MediumLevelILInstruction):
@dataclass(frozen=True, repr=False, eq=False)
+class MediumLevelILPassByRef(MediumLevelILUnaryBase):
+ pass
+
+
+@dataclass(frozen=True, repr=False, eq=False)
+class MediumLevelILReturnByRef(MediumLevelILUnaryBase):
+ pass
+
+
+@dataclass(frozen=True, repr=False, eq=False)
class MediumLevelILConst(MediumLevelILConstBase):
@property
def constant(self) -> int:
@@ -1503,6 +1541,37 @@ class MediumLevelILVarOutput(MediumLevelILInstruction, RegisterStack):
@dataclass(frozen=True, repr=False, eq=False)
+class MediumLevelILVarOutputField(MediumLevelILInstruction, SetVar):
+ @property
+ def dest(self) -> variable.Variable:
+ return self._get_var(0)
+
+ @property
+ def offset(self) -> int:
+ return self._get_int(1)
+
+ @property
+ def detailed_operands(self) -> List[Tuple[str, MediumLevelILOperandType, str]]:
+ return [
+ ('dest', self.dest, 'Variable'),
+ ('offset', self.offset, 'int')
+ ]
+
+
+@dataclass(frozen=True, repr=False, eq=False)
+class MediumLevelILStoreOutput(MediumLevelILInstruction, Store):
+ @property
+ def dest(self) -> MediumLevelILInstruction:
+ return self._get_expr(0)
+
+ @property
+ def detailed_operands(self) -> List[Tuple[str, MediumLevelILOperandType, str]]:
+ return [
+ ("dest", self.dest, "MediumLevelILInstruction"),
+ ]
+
+
+@dataclass(frozen=True, repr=False, eq=False)
class MediumLevelILRet(MediumLevelILInstruction, Return):
@property
def src(self) -> List[MediumLevelILInstruction]:
@@ -1667,6 +1736,94 @@ class MediumLevelILVarOutputSsa(MediumLevelILInstruction, SSAVariableInstruction
@dataclass(frozen=True, repr=False, eq=False)
+class MediumLevelILVarOutputSsaField(MediumLevelILInstruction, SetVar, SSA):
+ @property
+ def dest(self) -> SSAVariable:
+ return self._get_var_ssa_dest_and_src(0, 1)
+
+ @property
+ def prev(self) -> SSAVariable:
+ return self._get_var_ssa_dest_and_src(0, 2)
+
+ @property
+ def offset(self) -> int:
+ return self._get_int(3)
+
+ @property
+ def detailed_operands(self) -> List[Tuple[str, MediumLevelILOperandType, str]]:
+ return [
+ ('dest', self.dest, 'SSAVariable'),
+ ('prev', self.prev, 'SSAVariable'),
+ ('offset', self.offset, 'int')
+ ]
+
+ @property
+ def vars_read(self) -> List[SSAVariable]:
+ return [self.prev] # type: ignore # we're guaranteed not to return non-SSAVariables here
+
+ @property
+ def vars_written(self) -> List[SSAVariable]:
+ return [self.dest]
+
+
+@dataclass(frozen=True, repr=False, eq=False)
+class MediumLevelILVarOutputAliased(MediumLevelILInstruction, SetVar, SSA):
+ @property
+ def dest(self) -> SSAVariable:
+ return self._get_var_ssa_dest_and_src(0, 1)
+
+ @property
+ def prev(self) -> SSAVariable:
+ return self._get_var_ssa_dest_and_src(0, 2)
+
+ @property
+ def detailed_operands(self) -> List[Tuple[str, MediumLevelILOperandType, str]]:
+ return [
+ ('dest', self.dest, 'SSAVariable'),
+ ('prev', self.prev, 'SSAVariable')
+ ]
+
+ @property
+ def vars_read(self) -> List[Union[variable.Variable, SSAVariable]]:
+ return []
+
+ @property
+ def vars_written(self) -> List[SSAVariable]:
+ return [self.dest]
+
+
+@dataclass(frozen=True, repr=False, eq=False)
+class MediumLevelILVarOutputAliasedField(MediumLevelILInstruction, SetVar, SSA):
+ @property
+ def dest(self) -> SSAVariable:
+ return self._get_var_ssa_dest_and_src(0, 1)
+
+ @property
+ def prev(self) -> SSAVariable:
+ return self._get_var_ssa_dest_and_src(0, 2)
+
+ @property
+ def offset(self) -> int:
+ return self._get_int(3)
+
+ @property
+ def detailed_operands(self) -> List[Tuple[str, MediumLevelILOperandType, str]]:
+ return [
+ ('dest', self.dest, 'SSAVariable'),
+ ('prev', self.prev, 'SSAVariable'),
+ ('offset', self.offset, 'int')
+ ]
+
+ @property
+ def vars_read(self) -> List[SSAVariable]:
+ return [self.prev] # type: ignore # we're guaranteed not to return non-SSAVariables here
+
+ @property
+ def vars_written(self) -> List[SSAVariable]:
+ return [self.dest]
+
+
+@dataclass(frozen=True, repr=False, eq=False)
class MediumLevelILVarAliased(MediumLevelILInstruction, SSA, AliasedVariableInstruction):
@property
def src(self) -> SSAVariable:
@@ -3230,6 +3387,15 @@ class MediumLevelILForceVerSsa(MediumLevelILInstruction, SSA):
def src(self) -> SSAVariable:
return self._get_var_ssa(2, 3)
+@dataclass(frozen=True, repr=False, eq=False)
+class MediumLevelILBlockToExpand(MediumLevelILInstruction):
+ @property
+ def exprs(self) -> List[MediumLevelILInstruction]:
+ return self._get_expr_list(0, 1)
+
+ @property
+ def detailed_operands(self) -> List[Tuple[str, MediumLevelILOperandType, str]]:
+ return [("exprs", self.exprs, "List[MediumLevelILInstruction]")]
ILInstruction = {
@@ -3241,6 +3407,8 @@ ILInstruction = {
MediumLevelILOperation.MLIL_LOAD: MediumLevelILLoad, # [("src", "expr")],
MediumLevelILOperation.MLIL_VAR: MediumLevelILVar, # [("src", "var")],
MediumLevelILOperation.MLIL_ADDRESS_OF: MediumLevelILAddressOf, # [("src", "var")],
+ MediumLevelILOperation.MLIL_PASS_BY_REF: MediumLevelILPassByRef, # [("src", "expr")],
+ MediumLevelILOperation.MLIL_RETURN_BY_REF: MediumLevelILReturnByRef, # [("src", "expr")],
MediumLevelILOperation.MLIL_CONST: MediumLevelILConst, # [("constant", "int")],
MediumLevelILOperation.MLIL_CONST_PTR: MediumLevelILConstPtr, # [("constant", "int")],
MediumLevelILOperation.MLIL_FLOAT_CONST: MediumLevelILFloatConst, # [("constant", "float")],
@@ -3285,6 +3453,8 @@ ILInstruction = {
MediumLevelILOperation.MLIL_SEPARATE_PARAM_LIST: MediumLevelILSeparateParamList, # [("src", "expr_list")],
MediumLevelILOperation.MLIL_SHARED_PARAM_SLOT: MediumLevelILSharedParamSlot, # [("src", "expr_list")],
MediumLevelILOperation.MLIL_VAR_OUTPUT: MediumLevelILVarOutput, # [("dest", "var")],
+ MediumLevelILOperation.MLIL_VAR_OUTPUT_FIELD: MediumLevelILVarOutputField, # [("dest", "var"), ("offset", "int")],
+ MediumLevelILOperation.MLIL_STORE_OUTPUT: MediumLevelILStoreOutput, # [("dest", "expr")],
MediumLevelILOperation.MLIL_RET: MediumLevelILRet, # [("src", "expr_list")],
MediumLevelILOperation.MLIL_GOTO: MediumLevelILGoto, # [("dest", "int")],
MediumLevelILOperation.MLIL_BOOL_TO_INT: MediumLevelILBoolToInt, # [("src", "expr")],
@@ -3305,6 +3475,12 @@ ILInstruction = {
MediumLevelILOperation.MLIL_VAR_SSA: MediumLevelILVarSsa, # [("src", "var_ssa")],
MediumLevelILOperation.MLIL_VAR_ALIASED: MediumLevelILVarAliased, # [("src", "var_ssa")],
MediumLevelILOperation.MLIL_VAR_OUTPUT_SSA: MediumLevelILVarOutputSsa, # [("dest", "var_ssa")],
+ MediumLevelILOperation.MLIL_VAR_OUTPUT_SSA_FIELD:
+ MediumLevelILVarOutputSsaField, # [("prev", "var_ssa_dest_and_src"), ("offset", "int")],
+ MediumLevelILOperation.MLIL_VAR_OUTPUT_ALIASED:
+ MediumLevelILVarOutputAliased, # [("prev", "var_ssa_dest_and_src")],
+ MediumLevelILOperation.MLIL_VAR_OUTPUT_ALIASED_FIELD:
+ MediumLevelILVarOutputAliasedField, # [("prev", "var_ssa_dest_and_src"), ("offset", "int")],
MediumLevelILOperation.MLIL_CMP_E: MediumLevelILCmpE, # [("left", "expr"), ("right", "expr")],
MediumLevelILOperation.MLIL_CMP_NE: MediumLevelILCmpNe, # [("left", "expr"), ("right", "expr")],
MediumLevelILOperation.MLIL_CMP_SLT: MediumLevelILCmpSlt, # [("left", "expr"), ("right", "expr")],
@@ -3399,6 +3575,7 @@ ILInstruction = {
MediumLevelILOperation.MLIL_ASSERT_SSA: MediumLevelILAssertSsa,
MediumLevelILOperation.MLIL_FORCE_VER: MediumLevelILForceVer,
MediumLevelILOperation.MLIL_FORCE_VER_SSA: MediumLevelILForceVerSsa,
+ MediumLevelILOperation.MLIL_BLOCK_TO_EXPAND: MediumLevelILBlockToExpand, # [("exprs", "expr_list")],
}
@@ -3857,6 +4034,9 @@ class MediumLevelILFunction:
if expr.operation == MediumLevelILOperation.MLIL_VAR_OUTPUT:
expr: MediumLevelILVarOutput
return dest.var_output(expr.size, expr.dest, loc)
+ if expr.operation == MediumLevelILOperation.MLIL_VAR_OUTPUT_FIELD:
+ expr: MediumLevelILVarOutputField
+ return dest.var_output_field(expr.size, expr.dest, expr.offset, loc)
if expr.operation == MediumLevelILOperation.MLIL_FORCE_VER:
expr: MediumLevelILForceVer
return dest.force_ver(expr.size, expr.dest, expr.src, loc)
@@ -3937,6 +4117,9 @@ class MediumLevelILFunction:
if expr.operation == MediumLevelILOperation.MLIL_STORE_STRUCT:
expr: MediumLevelILStoreStruct
return dest.store_struct(expr.size, sub_expr_handler(expr.dest), expr.offset, sub_expr_handler(expr.src), loc)
+ if expr.operation == MediumLevelILOperation.MLIL_STORE_OUTPUT:
+ expr: MediumLevelILStoreOutput
+ return dest.store_output(expr.size, sub_expr_handler(expr.dest), loc)
if expr.operation == MediumLevelILOperation.MLIL_LOAD:
expr: MediumLevelILLoad
return dest.load(expr.size, sub_expr_handler(expr.src), loc)
@@ -3964,7 +4147,9 @@ class MediumLevelILFunction:
MediumLevelILOperation.MLIL_ROUND_TO_INT,
MediumLevelILOperation.MLIL_FLOOR,
MediumLevelILOperation.MLIL_CEIL,
- MediumLevelILOperation.MLIL_FTRUNC
+ MediumLevelILOperation.MLIL_FTRUNC,
+ MediumLevelILOperation.MLIL_PASS_BY_REF,
+ MediumLevelILOperation.MLIL_RETURN_BY_REF
]:
expr: MediumLevelILUnaryBase
return dest.expr(expr.operation, sub_expr_handler(expr.src), size=expr.size, source_location=loc)
@@ -4097,6 +4282,10 @@ class MediumLevelILFunction:
if expr.operation == MediumLevelILOperation.MLIL_UNIMPL:
expr: MediumLevelILUnimpl
return dest.unimplemented(loc)
+ if expr.operation == MediumLevelILOperation.MLIL_BLOCK_TO_EXPAND:
+ expr: MediumLevelILBlockToExpand
+ params = [sub_expr_handler(src) for src in expr.src]
+ return dest.block_to_expand(params, loc)
raise NotImplementedError(f"unknown expr operation {expr.operation} in copy_expr_to")
new_index = do_copy(expr, dest, sub_expr_handler)
@@ -4410,6 +4599,20 @@ class MediumLevelILFunction:
"""
return self.expr(MediumLevelILOperation.MLIL_STORE_STRUCT, dest, offset, src, size=size, source_location=loc)
+ def store_output(
+ self, size: int, dest: ExpressionIndex, loc: Optional['ILSourceLocation'] = None
+ ) -> ExpressionIndex:
+ """
+ ``store_output`` Outputs ``size`` bytes to expression ``dest`` as the result of a call
+
+ :param int size: number of bytes to write
+ :param ExpressionIndex dest: the expression to write to
+ :param ILSourceLocation loc: location of returned expression
+ :return: The expression ``[dest].size``
+ :rtype: ExpressionIndex
+ """
+ return self.expr(MediumLevelILOperation.MLIL_STORE_OUTPUT, dest, size=size, source_location=loc)
+
def var(self, size: int, src: 'variable.CoreVariable', loc: Optional['ILSourceLocation'] = None) -> ExpressionIndex:
"""
``var`` returns the variable ``src`` of size ``size``
@@ -4454,7 +4657,7 @@ class MediumLevelILFunction:
def var_output(self, size: int, dest: 'variable.CoreVariable', loc: Optional['ILSourceLocation'] = None) -> ExpressionIndex:
"""
- ``var`` returns the output variable ``dest`` of size ``size``
+ ``var_output`` returns the output variable ``dest`` of size ``size``
:param int size: the size of the variable in bytes
:param Variable dest: the variable being written
@@ -4464,6 +4667,21 @@ class MediumLevelILFunction:
"""
return self.expr(MediumLevelILOperation.MLIL_VAR_OUTPUT, dest.identifier, size=size, source_location=loc)
+ def var_output_field(
+ self, size: int, dest: 'variable.CoreVariable', offset: int, loc: Optional['ILSourceLocation'] = None
+ ) -> ExpressionIndex:
+ """
+ ``var_output_field`` returns the output field at offset ``offset`` from variable ``dest`` of size ``size``
+
+ :param int size: the size of the field in bytes
+ :param Variable dest: the variable being written
+ :param int offset: offset of field in the variable
+ :param ILSourceLocation loc: location of returned expression
+ :return: The expression ``var:offset.size``
+ :rtype: ExpressionIndex
+ """
+ return self.expr(MediumLevelILOperation.MLIL_VAR_OUTPUT_FIELD, dest.identifier, offset, size=size, source_location=loc)
+
def assert_expr(
self,
size: int,
@@ -4516,6 +4734,30 @@ class MediumLevelILFunction:
"""
return self.expr(MediumLevelILOperation.MLIL_ADDRESS_OF, var.identifier, size=0, source_location=loc)
+ def pass_by_ref(self, size: int, value: ExpressionIndex, loc: Optional['ILSourceLocation'] = None) -> ExpressionIndex:
+ """
+ ``pass_by_ref`` indicates that ``value`` is being passed by reference to a call with a pointer size of ``size``
+
+ :param int size: the size of the pointer in bytes
+ :param ExpressionIndex value: the expression containing the reference being passed
+ :param ILSourceLocation loc: location of returned expression
+ :return: The expression ``ref *value``
+ :rtype: ExpressionIndex
+ """
+ return self.expr(MediumLevelILOperation.MLIL_PASS_BY_REF, value, size=size, source_location=loc)
+
+ def return_by_ref(self, size: int, dest: ExpressionIndex, loc: Optional['ILSourceLocation'] = None) -> ExpressionIndex:
+ """
+ ``return_by_ref`` indicates that ``dest`` is being returned by passing a reference to a call
+
+ :param int size: the size of the value in bytes
+ :param ExpressionIndex dest: the expression containing the target of the return value
+ :param ILSourceLocation loc: location of returned expression
+ :return: The expression ``ref dest``
+ :rtype: ExpressionIndex
+ """
+ return self.expr(MediumLevelILOperation.MLIL_RETURN_BY_REF, dest, size=size, source_location=loc)
+
def address_of_field(self, var: 'variable.CoreVariable', offset: int, loc: Optional['ILSourceLocation'] = None) -> ExpressionIndex:
"""
``address_of_field`` takes the address of ``var`` at the offset ``offset``
@@ -5956,6 +6198,18 @@ class MediumLevelILFunction:
"""
return self.expr(MediumLevelILOperation.MLIL_FCMP_UO, a, b, size=size, source_location=loc)
+ def block_to_expand(self, exprs: List[ExpressionIndex], loc: Optional['ILSourceLocation'] = None) -> ExpressionIndex:
+ """
+ ``block_to_expand`` returns an expression to expand into multiple expressions. This expression must
+ be expanded by a future workflow step and is used temporarily to insert instructions.
+
+ :param List[ExpressionIndex] exprs: list of expressions
+ :param ILSourceLocation loc: location of returned expression
+ :return: The expression ``{ exprs... }``
+ :rtype: ExpressionIndex
+ """
+ return self.expr(MediumLevelILOperation.MLIL_BLOCK_TO_EXPAND, len(exprs), self.add_operand_list(exprs), size=0, source_location=loc)
+
def goto(
self, label: MediumLevelILLabel, loc: Optional['ILSourceLocation'] = None
) -> ExpressionIndex:
diff --git a/python/platform.py b/python/platform.py
index beaf5d75..2e8ad846 100644
--- a/python/platform.py
+++ b/python/platform.py
@@ -401,7 +401,7 @@ class Platform(metaclass=_PlatformMetaClass):
result = core.BNGetPlatformDefaultCallingConvention(self.handle)
if result is None:
return None
- return callingconvention.CallingConvention(handle=result)
+ return callingconvention.CoreCallingConvention(handle=result)
@default_calling_convention.setter
def default_calling_convention(self, value):
@@ -415,7 +415,7 @@ class Platform(metaclass=_PlatformMetaClass):
result = core.BNGetPlatformCdeclCallingConvention(self.handle)
if result is None:
return None
- return callingconvention.CallingConvention(handle=result)
+ return callingconvention.CoreCallingConvention(handle=result)
@cdecl_calling_convention.setter
def cdecl_calling_convention(self, value):
@@ -432,7 +432,7 @@ class Platform(metaclass=_PlatformMetaClass):
result = core.BNGetPlatformStdcallCallingConvention(self.handle)
if result is None:
return None
- return callingconvention.CallingConvention(handle=result)
+ return callingconvention.CoreCallingConvention(handle=result)
@stdcall_calling_convention.setter
def stdcall_calling_convention(self, value):
@@ -449,7 +449,7 @@ class Platform(metaclass=_PlatformMetaClass):
result = core.BNGetPlatformFastcallCallingConvention(self.handle)
if result is None:
return None
- return callingconvention.CallingConvention(handle=result)
+ return callingconvention.CoreCallingConvention(handle=result)
@fastcall_calling_convention.setter
def fastcall_calling_convention(self, value):
@@ -466,7 +466,7 @@ class Platform(metaclass=_PlatformMetaClass):
result = core.BNGetPlatformSystemCallConvention(self.handle)
if result is None:
return None
- return callingconvention.CallingConvention(handle=result)
+ return callingconvention.CoreCallingConvention(handle=result)
@system_call_convention.setter
def system_call_convention(self, value):
@@ -488,7 +488,7 @@ class Platform(metaclass=_PlatformMetaClass):
assert cc is not None, "core.BNGetPlatformCallingConventions returned None"
result = []
for i in range(0, count.value):
- result.append(callingconvention.CallingConvention(handle=core.BNNewCallingConventionReference(cc[i])))
+ result.append(callingconvention.CoreCallingConvention(handle=core.BNNewCallingConventionReference(cc[i])))
core.BNFreeCallingConventionList(cc, count.value)
return result
diff --git a/python/types.py b/python/types.py
index 80c70e14..04ec5e78 100644
--- a/python/types.py
+++ b/python/types.py
@@ -28,7 +28,7 @@ import uuid
from . import _binaryninjacore as core
from .enums import (
InlineDuringAnalysis, StructureVariant, SymbolType, SymbolBinding, TypeClass, NamedTypeReferenceClass,
- ReferenceType, VariableSourceType,
+ ReferenceType, VariableSourceType, ValueLocationSource,
TypeReferenceType, MemberAccess, MemberScope, TypeDefinitionLineType,
TokenEscapingType,
NameType, PointerSuffix, PointerBaseType,
@@ -39,6 +39,7 @@ from . import function as _function
from . import variable
from . import architecture
from . import binaryview
+from . import function
from . import platform as _platform
from . import typecontainer
from . import typelibrary
@@ -51,11 +52,13 @@ ParamsType = Union[List['Type'], List['FunctionParameter'], List[Tuple[str, 'Typ
MembersType = Union[List['StructureMember'], List['Type'], List[Tuple['Type', str]]]
EnumMembersType = Union[List[Tuple[str, int]], List[str], List['EnumerationMember']]
SomeType = Union['TypeBuilder', 'Type']
+ReturnValueOrType = Union['TypeBuilder', 'Type', 'ReturnValue']
TypeContainerType = Union['binaryview.BinaryView', 'typelibrary.TypeLibrary']
NameSpaceType = Optional[Union[str, List[str], 'NameSpace']]
TypeParserResult = typeparser.TypeParserResult
BasicTypeParserResult = typeparser.BasicTypeParserResult
ResolveMemberCallback = Callable[['NamedTypeReferenceType', 'StructureType', int, int, int, 'StructureMember'], None]
+OptionalLocation = Optional[Union['ValueLocation', 'ValueLocationWithConfidence', 'variable.CoreVariable']]
# The following are needed to prevent the type checker from getting
# confused as we have member functions in `Type` named the same thing
_int = int
@@ -437,22 +440,229 @@ class Symbol(CoreSymbol):
@dataclass
+class ValueLocationComponent:
+ var: 'variable.CoreVariable'
+ offset: int = 0
+ size: Optional[int] = None
+
+ @staticmethod
+ def _from_core_struct(struct: core.BNValueLocationComponent, arch: Optional['architecture.Architecture'] = None):
+ if arch is None:
+ var = variable.CoreVariable.from_BNVariable(struct.variable)
+ else:
+ var = variable.ArchitectureVariable.from_BNVariable(arch, struct.variable)
+ offset = struct.offset
+ size = None
+ if struct.sizeValid:
+ size = struct.size
+ return ValueLocationComponent(var, offset, size)
+
+ def _to_core_struct(self) -> core.BNValueLocationComponent:
+ struct = core.BNValueLocationComponent()
+ struct.variable = self.var.to_BNVariable()
+ struct.offset = self.offset
+ struct.sizeValid = self.size is not None
+ if self.size is not None:
+ struct.size = self.size
+ return struct
+
+ def to_string(self, arch: Optional['architecture.Architecture']):
+ if arch is None:
+ if isinstance(self.var, variable.ArchitectureVariable):
+ arch = self.var.arch
+ elif isinstance(self.var, variable.Variable):
+ arch = self.var.function.arch
+ if arch is None:
+ return f"{repr(self.var)} offset {hex(self.offset)} size {repr(self.size)}"
+ struct = self._to_core_struct()
+ return core.BNValueLocationComponentToString(struct, arch.handle)
+
+ def __str__(self):
+ return self.to_string(None)
+
+ def __repr__(self):
+ return f"<component {self.to_string(None)}>"
+
+
+@dataclass
+class ValueLocation:
+ components: List['ValueLocationComponent']
+ indirect: bool = False
+ returned_pointer: Optional['variable.CoreVariable'] = None
+
+ @staticmethod
+ def _from_core_struct(struct: core.BNValueLocation, arch: Optional['architecture.Architecture'] = None):
+ components = []
+ for i in range(struct.count):
+ components.append(ValueLocationComponent._from_core_struct(struct.components[i], arch))
+ indirect = struct.indirect
+ returned_pointer = None
+ if struct.returnedPointerValid:
+ if arch is None:
+ returned_pointer = variable.CoreVariable.from_BNVariable(struct.returnedPointer)
+ else:
+ returned_pointer = variable.ArchitectureVariable.from_BNVariable(arch, struct.returnedPointer)
+ return ValueLocation(components, indirect, returned_pointer)
+
+ def _to_core_struct(self) -> core.BNValueLocation:
+ struct = core.BNValueLocation()
+ struct.count = len(self.components)
+ components = (core.BNValueLocationComponent * len(self.components))()
+ for i in range(len(self.components)):
+ components[i] = self.components[i]._to_core_struct()
+ struct.components = components
+ struct.indirect = self.indirect
+ struct.returnedPointerValid = self.returned_pointer is not None
+ if self.returned_pointer is not None:
+ struct.returnedPointer = self.returned_pointer.to_BNVariable()
+ return struct
+
+ def with_confidence(self, confidence: int) -> 'ValueLocationWithConfidence':
+ return ValueLocationWithConfidence(self, confidence)
+
+ def variable_for_parameter(self, idx: int) -> Optional['variable.CoreVariable']:
+ struct = self._to_core_struct()
+ var = core.BNVariable()
+ if core.BNGetValueLocationVariableForParameter(struct, var, idx):
+ return variable.CoreVariable.from_BNVariable(var)
+ return None
+
+ @staticmethod
+ def parse(string: str, arch: 'architecture.Architecture') -> 'ValueLocation':
+ struct = core.BNValueLocation()
+ error = ctypes.c_char_p()
+ if not core.BNParseValueLocation(string, arch.handle, struct, error):
+ assert error.value is not None, "core.BNParseValueLocation returned 'error' set to None"
+ error_str = error.value.decode("utf-8")
+ core.free_string(error)
+ raise SyntaxError(error_str)
+ result = ValueLocation._from_core_struct(struct, arch)
+ core.BNFreeValueLocation(struct)
+ return result
+
+ def to_string(self, arch: Optional['architecture.Architecture']):
+ if arch is None:
+ for component in self.components:
+ if isinstance(component.var, variable.ArchitectureVariable):
+ arch = component.var.arch
+ break
+ if isinstance(component.var, variable.Variable):
+ arch = component.var.function.arch
+ break
+ if arch is None:
+ if self.indirect:
+ indirect = " indirect"
+ else:
+ indirect = ""
+ if self.returned_pointer is None:
+ ret_ptr = ""
+ else:
+ ret_ptr = f" returned ptr {repr(self.returned_pointer)}"
+ return f"{repr(self.components)}{indirect}{ret_ptr}"
+ struct = self._to_core_struct()
+ return core.BNValueLocationToString(struct, arch.handle)
+
+ def __str__(self):
+ return self.to_string(None)
+
+ def __repr__(self):
+ return f"<value location {self.to_string(None)}>"
+
+
+@dataclass
+class ValueLocationWithConfidence:
+ location: 'ValueLocation'
+ confidence: int = core.max_confidence
+
+ @staticmethod
+ def from_optional_location(location: OptionalLocation) -> Optional['ValueLocationWithConfidence']:
+ if isinstance(location, ValueLocation):
+ return location.with_confidence(core.max_confidence)
+ elif isinstance(location, ValueLocationWithConfidence):
+ return location
+ elif location is not None:
+ return ValueLocation([ValueLocationComponent(location)]).with_confidence(core.max_confidence)
+ return None
+
+ def __repr__(self):
+ return f"<value location {self.location.to_string(None)} confidence {self.confidence}>"
+
+
+@dataclass
+class ReturnValue:
+ type: SomeType
+ location: Optional['ValueLocationWithConfidence']
+
+ def __init__(self, ty: SomeType, location: OptionalLocation = None):
+ self.type = ty.immutable_copy()
+ self.location = ValueLocationWithConfidence.from_optional_location(location)
+
+ @staticmethod
+ def _from_core_struct(struct: core.BNReturnValue, arch: Optional['architecture.Architecture'] = None):
+ ty = Type.from_core_struct(struct.type).with_confidence(struct.typeConfidence)
+ if struct.defaultLocation:
+ location = None
+ else:
+ location = ValueLocation._from_core_struct(struct.location, arch).with_confidence(struct.locationConfidence)
+ return ReturnValue(ty, location)
+
+ def _to_core_struct(self) -> core.BNReturnValue:
+ struct = core.BNReturnValue()
+ ic = self.type.immutable_copy()
+ struct.type = ic.handle
+ struct.typeConfidence = ic.confidence
+ struct.defaultLocation = self.location is None
+ if self.location is None:
+ struct.location.count = 0
+ struct.locationConfidence = 0
+ else:
+ struct.location = self.location.location._to_core_struct()
+ struct.locationConfidence = self.location.confidence
+ return struct
+
+
+@dataclass
class FunctionParameter:
type: SomeType
name: str = ""
- location: Optional['variable.VariableNameAndType'] = None
+ location_source: ValueLocationSource = ValueLocationSource.DefaultLocationSource
+ location: Optional['ValueLocation'] = None
+
+ def __init__(self, type: SomeType, name: str = "", location: OptionalLocation = None, source: Optional['ValueLocationSource'] = None):
+ self.type = type
+ self.name = name
+ location = ValueLocationWithConfidence.from_optional_location(location)
+ if location is not None:
+ self.location = location.location
+ self.location_source = ValueLocationSource.CustomLocationSource
+ else:
+ self.location = None
+ self.location_source = ValueLocationSource.DefaultLocationSource
+ if source is not None:
+ self.location_source = source
def __repr__(self):
ic = self.type.immutable_copy()
- if (self.location is not None) and (self.location.name != self.name):
- return f"{ic.get_string_before_name()} {self.name}{ic.get_string_after_name()} @ {self.location.name}"
+ if (self.location is not None) and (str(self.location) != self.name):
+ return f"{ic.get_string_before_name()} {self.name}{ic.get_string_after_name()} @ {self.location}"
return f"{ic.get_string_before_name()} {self.name}{ic.get_string_after_name()}"
def immutable_copy(self) -> 'FunctionParameter':
- return FunctionParameter(self.type.immutable_copy(), self.name, self.location)
+ return FunctionParameter(self.type.immutable_copy(), self.name, self.location, self.location_source)
def mutable_copy(self) -> 'FunctionParameter':
- return FunctionParameter(self.type.mutable_copy(), self.name, self.location)
+ return FunctionParameter(self.type.mutable_copy(), self.name, self.location, self.location_source)
+
+ @staticmethod
+ def _from_core_struct(struct: 'core.BNFunctionParameter', arch: Optional['architecture.Architecture'] = None) -> 'FunctionParameter':
+ name = struct.name
+ ty = Type.from_core_struct(struct.type).with_confidence(struct.typeConfidence)
+ source = ValueLocationSource(struct.locationSource)
+ if source == ValueLocationSource.CustomLocationSource:
+ location = ValueLocation._from_core_struct(struct.location, arch)
+ else:
+ location = None
+ return FunctionParameter(ty, name, location, source)
@dataclass(frozen=True)
@@ -760,7 +970,7 @@ class TypeBuilder:
@staticmethod
def function(
- ret: Optional[SomeType] = None, params: Optional[ParamsType] = None,
+ ret: Optional[ReturnValueOrType] = None, params: Optional[ParamsType] = None,
calling_convention: Optional['callingconvention.CallingConvention'] = None,
variable_arguments: Optional[BoolWithConfidenceType] = None,
stack_adjust: Optional[OffsetWithConfidenceType] = None
@@ -1231,20 +1441,22 @@ class ArrayBuilder(TypeBuilder):
class FunctionBuilder(TypeBuilder):
@classmethod
def create(
- cls, return_type: Optional[SomeType] = None,
+ cls, return_type: Optional[ReturnValueOrType] = None,
calling_convention: Optional['callingconvention.CallingConvention'] = None, params: Optional[ParamsType] = None,
var_args: Optional[BoolWithConfidenceType] = None, stack_adjust: Optional[OffsetWithConfidenceType] = None,
platform: Optional['_platform.Platform'] = None, confidence: int = core.max_confidence,
can_return: Optional[BoolWithConfidence] = None, reg_stack_adjust: Optional[Dict['architecture.RegisterName', OffsetWithConfidenceType]] = None,
- return_regs: Optional[Union['RegisterSet', List['architecture.RegisterType']]] = None,
name_type: 'NameType' = NameType.NoNameType,
pure: Optional[BoolWithConfidence] = None
) -> 'FunctionBuilder':
param_buf, type_list = FunctionBuilder._to_core_struct(params)
if return_type is None:
- ret_conf = Type.void()
+ ret = ReturnValue(Type.void())
+ elif isinstance(return_type, ReturnValue):
+ ret = return_type
else:
- ret_conf = return_type.immutable_copy()
+ ret = ReturnValue(return_type)
+ ret_conf = ret._to_core_struct()
conv_conf = core.BNCallingConventionWithConfidence()
if calling_convention is None:
@@ -1264,18 +1476,6 @@ class FunctionBuilder(TypeBuilder):
reg_stack_adjust_values[i].value = adjust.value
reg_stack_adjust_values[i].confidence = adjust.confidence
- return_regs_set = core.BNRegisterSetWithConfidence()
- if return_regs is None or platform is None:
- return_regs_set.count = 0
- return_regs_set.confidence = 0
- else:
- return_regs_set.count = len(return_regs)
- return_regs_set.confidence = 255
- return_regs_set.regs = (ctypes.c_uint32 * len(return_regs))()
-
- for i, reg in enumerate(return_regs):
- return_regs_set[i] = platform.arch.get_reg_index(reg)
-
if var_args is None:
vararg_conf = BoolWithConfidence.get_core_struct(False, 0)
else:
@@ -1298,9 +1498,9 @@ class FunctionBuilder(TypeBuilder):
if params is None:
params = []
handle = core.BNCreateFunctionTypeBuilder(
- ret_conf._to_core_struct(), conv_conf, param_buf, len(params), vararg_conf, can_return_conf, stack_adjust_conf,
+ ret_conf, conv_conf, param_buf, len(params), vararg_conf, can_return_conf, stack_adjust_conf,
reg_stack_adjust_regs, reg_stack_adjust_values, len(reg_stack_adjust),
- return_regs_set, name_type, pure_conf
+ name_type, pure_conf
)
assert handle is not None, "BNCreateFunctionTypeBuilder returned None"
return cls(handle, platform, confidence)
@@ -1317,6 +1517,31 @@ class FunctionBuilder(TypeBuilder):
def return_value(self, value: SomeType) -> None:
self.child = value
+ @property
+ def return_value_location(self) -> Optional[ValueLocationWithConfidence]:
+ location = core.BNGetTypeBuilderReturnValueLocation(self._handle)
+ if self.platform is None:
+ arch = None
+ else:
+ arch = self.platform.arch
+ result = ValueLocation._from_core_struct(location.location, arch).with_confidence(location.confidence)
+ core.BNFreeValueLocation(location.location)
+ return result
+
+ @return_value_location.setter
+ def return_value_location(self, value: OptionalLocation):
+ struct = core.BNValueLocationWithConfidence()
+ location = ValueLocationWithConfidence.from_optional_location(value)
+ if location is None:
+ struct.location.count = 0
+ struct.confidence = 0
+ else:
+ struct.location = location.location._to_core_struct()
+ struct.confidence = location.confidence
+ core.BNTypeBuilderSetIsReturnValueDefaultLocation(self._handle, value is None)
+ if value is not None:
+ core.BNTypeBuilderSetReturnValueLocation(self._handle, struct)
+
def append(self, type: Union[SomeType, FunctionParameter], name: str = ""):
if isinstance(type, FunctionParameter):
self.parameters = [*self.parameters, type]
@@ -1326,7 +1551,7 @@ class FunctionBuilder(TypeBuilder):
@property
def calling_convention(self) -> 'callingconvention.CallingConvention':
cc = core.BNGetTypeBuilderCallingConvention(self._handle)
- return callingconvention.CallingConvention(handle=core.BNNewCallingConventionReference(cc.convention))
+ return callingconvention.CoreCallingConvention(handle=core.BNNewCallingConventionReference(cc.convention))
@property
def can_return(self) -> BoolWithConfidence:
@@ -1366,24 +1591,21 @@ class FunctionBuilder(TypeBuilder):
count = ctypes.c_ulonglong()
params = core.BNGetTypeBuilderParameters(self._handle, count)
assert params is not None, "core.BNGetTypeBuilderParameters returned None"
+ if self.platform is None:
+ arch = None
+ else:
+ arch = self.platform.arch
result = []
for i in range(0, count.value):
param_type = Type.create(
core.BNNewTypeReference(params[i].type), platform=self.platform, confidence=params[i].typeConfidence
)
- if params[i].defaultLocation:
- param_location = None
+ source = ValueLocationSource(params[i].locationSource)
+ if source == ValueLocationSource.CustomLocationSource:
+ param_location = ValueLocation._from_core_struct(params[i].location, arch)
else:
- name = params[i].name
- if (params[i].location.type
- == VariableSourceType.RegisterVariableSourceType) and (self.platform is not None):
- name = self.platform.arch.get_reg_name(params[i].location.storage)
- elif params[i].location.type == VariableSourceType.StackVariableSourceType:
- name = "arg_%x" % params[i].location.storage
- param_location = variable.VariableNameAndType(
- params[i].location.type, params[i].location.index, params[i].location.storage, name, param_type
- )
- result.append(FunctionParameter(param_type, params[i].name, param_location))
+ param_location = None
+ result.append(FunctionParameter(param_type, params[i].name, param_location, source))
core.BNFreeTypeParameterList(params, count.value)
return result
@@ -1411,7 +1633,8 @@ class FunctionBuilder(TypeBuilder):
core_param.name = ""
core_param.type = param.handle
core_param.typeConfidence = param.confidence
- core_param.defaultLocation = True
+ core_param.locationSource = int(ValueLocationSource.DefaultLocationSource)
+ core_param.location.count = 0
elif isinstance(param, FunctionParameter):
assert param.type is not None, "Attempting to construct function parameter without properly constructed type"
param_type = param.type.immutable_copy()
@@ -1419,13 +1642,16 @@ class FunctionBuilder(TypeBuilder):
core_param.name = param.name
core_param.type = param_type.handle
core_param.typeConfidence = param_type.confidence
+ core_param.locationSource = int(param.location_source)
if param.location is None:
- core_param.defaultLocation = True
+ core_param.location.count = 0
else:
- core_param.defaultLocation = False
- core_param.location.type = param.location.source_type
- core_param.location.index = param.location.index
- core_param.location.storage = param.location.storage
+ if isinstance(param.location, ValueLocation):
+ core_param.location = param.location._to_core_struct()
+ elif isinstance(param.location, variable.CoreVariable):
+ core_param.location = ValueLocation([ValueLocationComponent(param.location)])._to_core_struct()
+ else:
+ raise ValueError(f"Conversion from unsupported parameter location type {type(param.location)}")
elif isinstance(param, tuple):
name, _type = param
if not isinstance(name, str) or not isinstance(_type, (Type, TypeBuilder)):
@@ -1435,7 +1661,8 @@ class FunctionBuilder(TypeBuilder):
core_param.name = name
core_param.type = _type.handle
core_param.typeConfidence = _type.confidence
- core_param.defaultLocation = True
+ core_param.locationSource = int(ValueLocationSource.DefaultLocationSource)
+ core_param.location.count = 0
else:
raise ValueError(f"Conversion from unsupported function parameter type {type(param)}")
return param_buf, type_list
@@ -2556,7 +2783,7 @@ class Type:
@staticmethod
def function(
- ret: Optional['Type'] = None, params: Optional[ParamsType] = None,
+ ret: Optional[Union['Type', 'ReturnValue']] = None, params: Optional[ParamsType] = None,
calling_convention: Optional['callingconvention.CallingConvention'] = None,
variable_arguments: BoolWithConfidenceType = False,
stack_adjust: OffsetWithConfidence = OffsetWithConfidence(0)
@@ -3227,18 +3454,19 @@ class ArrayType(Type):
class FunctionType(Type):
@classmethod
def create(
- cls, ret: Optional[Type] = None, params: Optional[ParamsType] = None,
+ cls, ret: Optional[Union[Type, ReturnValue]] = None, params: Optional[ParamsType] = None,
calling_convention: Optional['callingconvention.CallingConvention'] = None,
variable_arguments: BoolWithConfidenceType = BoolWithConfidence(False),
stack_adjust: OffsetWithConfidence = OffsetWithConfidence(0), platform: Optional['_platform.Platform'] = None,
confidence: int = core.max_confidence,
can_return: Union[BoolWithConfidence, bool] = True, reg_stack_adjust: Optional[Dict['architecture.RegisterName', OffsetWithConfidenceType]] = None,
- return_regs: Optional[Union['RegisterSet', List['architecture.RegisterType']]] = None,
name_type: 'NameType' = NameType.NoNameType,
pure: Union[BoolWithConfidence, bool] = False
) -> 'FunctionType':
if ret is None:
- ret = VoidType.create()
+ ret = ReturnValue(VoidType.create())
+ elif not isinstance(ret, ReturnValue):
+ ret = ReturnValue(ret)
if params is None:
params = []
param_buf, type_list = FunctionBuilder._to_core_struct(params)
@@ -3272,18 +3500,6 @@ class FunctionType(Type):
reg_stack_adjust_values[i].value = adjust.value
reg_stack_adjust_values[i].confidence = adjust.confidence
- return_regs_set = core.BNRegisterSetWithConfidence()
- if return_regs is None or platform is None:
- return_regs_set.count = 0
- return_regs_set.confidence = 0
- else:
- return_regs_set.count = len(return_regs)
- return_regs_set.confidence = 255
- return_regs_set.regs = (ctypes.c_uint32 * len(return_regs))()
-
- for i, reg in enumerate(return_regs):
- return_regs_set[i] = platform.arch.get_reg_index(reg)
-
_can_return = BoolWithConfidence.get_core_struct(can_return)
_pure = BoolWithConfidence.get_core_struct(pure)
if params is None:
@@ -3291,7 +3507,7 @@ class FunctionType(Type):
func_type = core.BNCreateFunctionType(
ret_conf, conv_conf, param_buf, len(params), _variable_arguments, _can_return, _stack_adjust,
reg_stack_adjust_regs, reg_stack_adjust_values, len(reg_stack_adjust),
- return_regs_set, name_type, _pure
+ name_type, _pure
)
assert func_type is not None, f"core.BNCreateFunctionType returned None {ret_conf} {conv_conf} {param_buf} {_variable_arguments} {_stack_adjust}"
@@ -3312,12 +3528,26 @@ class FunctionType(Type):
return Type.create(result.type, platform=self._platform, confidence=result.confidence)
@property
+ def return_value_location(self) -> Optional[ValueLocationWithConfidence]:
+ """Return value location (read-only)"""
+ if core.BNIsTypeReturnValueDefaultLocation(self._handle):
+ return None
+ location = core.BNGetTypeReturnValueLocation(self._handle)
+ if self._platform is None:
+ arch = None
+ else:
+ arch = self._platform.arch
+ result = ValueLocation._from_core_struct(location.location, arch).with_confidence(location.confidence)
+ core.BNFreeValueLocation(location.location)
+ return result
+
+ @property
def calling_convention(self) -> Optional[callingconvention.CallingConvention]:
"""Calling convention (read-only)"""
result = core.BNGetTypeCallingConvention(self._handle)
if not result.convention:
return None
- return callingconvention.CallingConvention(None, handle=result.convention, confidence=result.confidence)
+ return callingconvention.CoreCallingConvention(handle=result.convention, confidence=result.confidence)
@property
def parameters(self) -> List[FunctionParameter]:
@@ -3325,24 +3555,21 @@ class FunctionType(Type):
count = ctypes.c_ulonglong()
params = core.BNGetTypeParameters(self._handle, count)
assert params is not None, "core.BNGetTypeParameters returned None"
+ if self._platform is None:
+ arch = None
+ else:
+ arch = self._platform.arch
result = []
for i in range(0, count.value):
param_type = Type.create(
core.BNNewTypeReference(params[i].type), platform=self._platform, confidence=params[i].typeConfidence
)
- if params[i].defaultLocation:
- param_location = None
+ source = ValueLocationSource(params[i].locationSource)
+ if source == ValueLocationSource.CustomLocationSource:
+ param_location = ValueLocation._from_core_struct(params[i].location, arch)
else:
- name = params[i].name
- if (params[i].location.type
- == VariableSourceType.RegisterVariableSourceType) and (self._platform is not None):
- name = self._platform.arch.get_reg_name(params[i].location.storage)
- elif params[i].location.type == VariableSourceType.StackVariableSourceType:
- name = "arg_%x" % params[i].location.storage
- param_location = variable.VariableNameAndType(
- params[i].location.type, params[i].location.index, params[i].location.storage, name, param_type
- )
- result.append(FunctionParameter(param_type, params[i].name, param_location))
+ param_location = None
+ result.append(FunctionParameter(param_type, params[i].name, param_location, source))
core.BNFreeTypeParameterList(params, count.value)
return result
@@ -3352,21 +3579,18 @@ class FunctionType(Type):
count = ctypes.c_ulonglong()
params = core.BNGetTypeParameters(self._handle, count)
assert params is not None, "core.BNGetTypeParameters returned None"
+ if self._platform is None:
+ arch = None
+ else:
+ arch = self._platform.arch
result = []
for i in range(0, count.value):
param_type = Type.create(
core.BNNewTypeReference(params[i].type), platform=self._platform, confidence=params[i].typeConfidence
)
- name = params[i].name
- if (params[i].location.type
- == VariableSourceType.RegisterVariableSourceType) and (self._platform is not None):
- name = self._platform.arch.get_reg_name(params[i].location.storage)
- elif params[i].location.type == VariableSourceType.StackVariableSourceType:
- name = "arg_%x" % params[i].location.storage
- param_location = variable.VariableNameAndType(
- params[i].location.type, params[i].location.index, params[i].location.storage, name, param_type
- )
- result.append(FunctionParameter(param_type, params[i].name, param_location))
+ source = ValueLocationSource(params[i].locationSource)
+ param_location = ValueLocation._from_core_struct(params[i].location, arch)
+ result.append(FunctionParameter(param_type, params[i].name, param_location, source))
core.BNFreeTypeParameterList(params, count.value)
return result
diff --git a/python/variable.py b/python/variable.py
index 878c1cc7..b4861571 100644
--- a/python/variable.py
+++ b/python/variable.py
@@ -27,6 +27,7 @@ import binaryninja
from . import _binaryninjacore as core
from . import databuffer
from . import decorators
+from . import types
from .enums import RegisterValueType, VariableSourceType, DeadStoreElimination, FunctionGraphType, BuiltinType
FunctionOrILFunction = Union["binaryninja.function.Function", "binaryninja.lowlevelil.LowLevelILFunction",
@@ -111,6 +112,10 @@ class RegisterValue:
return ConstantPointerRegisterValue(reg_value.value, confidence=confidence)
elif reg_value.state == RegisterValueType.StackFrameOffset:
return StackFrameOffsetRegisterValue(reg_value.value, confidence=confidence)
+ elif reg_value.state == RegisterValueType.ResultPointerValue:
+ return ResultPointerRegisterValue(reg_value.value, confidence=confidence)
+ elif reg_value.state == RegisterValueType.ParameterPointerValue:
+ return ParameterPointerRegisterValue(reg_value.value, reg_value.offset, confidence=confidence)
elif reg_value.state == RegisterValueType.ImportedAddressValue:
return ImportedAddressRegisterValue(reg_value.value, confidence=confidence)
elif reg_value.state == RegisterValueType.UndeterminedValue:
@@ -197,6 +202,23 @@ class StackFrameOffsetRegisterValue(RegisterValue):
@dataclass(frozen=True, eq=False)
+class ResultPointerRegisterValue(RegisterValue):
+ offset: int = 0
+ type: RegisterValueType = RegisterValueType.ResultPointerValue
+
+ def __repr__(self):
+ return f"<result ptr offset {self.value:#x}>"
+
+@dataclass(frozen=True, eq=False)
+class ParameterPointerRegisterValue(RegisterValue):
+ offset: int = 0
+ type: RegisterValueType = RegisterValueType.ParameterPointerValue
+
+ def __repr__(self):
+ return f"<parameter {self.value} ptr offset {self.offset:#x}>"
+
+
+@dataclass(frozen=True, eq=False)
class ExternalPointerRegisterValue(RegisterValue):
type: RegisterValueType = RegisterValueType.ExternalPointerValue
@@ -287,6 +309,11 @@ class PossibleValueSet:
self._value = value.value
elif value.state == RegisterValueType.StackFrameOffset:
self._offset = value.value
+ elif value.state == RegisterValueType.ResultPointerValue:
+ self._offset = value.value
+ elif value.state == RegisterValueType.ParameterPointerValue:
+ self._value = value.value
+ self._offset = value.offset
elif value.state & RegisterValueType.ConstantDataValue == RegisterValueType.ConstantDataValue:
self._value = value.value
self._size = value.size
@@ -334,6 +361,10 @@ class PossibleValueSet:
return f"<const ptr {self.value:#x}>"
if self._type == RegisterValueType.StackFrameOffset:
return f"<stack frame offset {self._offset:#x}>"
+ if self._type == RegisterValueType.ResultPointerValue:
+ return f"<result ptr offset {self._offset:#x}>"
+ if self._type == RegisterValueType.ParameterPointerValue:
+ return f"<parameter {self._value} ptr offset {self._offset:#x}>"
if self._type == RegisterValueType.ConstantDataZeroExtendValue:
return f"<const data {{zx.{self._size}({self.value:#x})}}>"
if self._type == RegisterValueType.ConstantDataSignExtendValue:
@@ -364,7 +395,7 @@ class PossibleValueSet:
if not isinstance(other, int):
return NotImplemented
#Initial implementation only checks numbers, no set logic
- if self.type == RegisterValueType.StackFrameOffset:
+ if self.type in [RegisterValueType.StackFrameOffset, RegisterValueType.ResultPointerValue, RegisterValueType.ParameterPointerValue]:
return NotImplemented
if self.type in [RegisterValueType.SignedRangeValue, RegisterValueType.UnsignedRangeValue]:
for rng in self.ranges:
@@ -395,6 +426,10 @@ class PossibleValueSet:
return self.value == other.value
elif self.type == RegisterValueType.StackFrameOffset:
return self.offset == other.offset
+ elif self.type == RegisterValueType.ResultPointerValue:
+ return self.offset == other.offset
+ elif self.type == RegisterValueType.ParameterPointerValue:
+ return self.value == other.value and self.offset == other.offset
elif self.type & RegisterValueType.ConstantDataValue == RegisterValueType.ConstantDataValue:
return self.value == other.value and self._size == other._size
elif self.type in [RegisterValueType.SignedRangeValue, RegisterValueType.UnsignedRangeValue]:
@@ -423,6 +458,11 @@ class PossibleValueSet:
result.value = self.value
elif self.type == RegisterValueType.StackFrameOffset:
result.offset = self.offset
+ elif self.type == RegisterValueType.ResultPointerValue:
+ result.value = self.offset
+ elif self.type == RegisterValueType.ParameterPointerValue:
+ result.value = self.value
+ result.offset = self.offset
elif self.type & RegisterValueType.ConstantDataValue == RegisterValueType.ConstantDataValue:
result.value = self.value
result.size = self.size
@@ -559,6 +599,39 @@ class PossibleValueSet:
return result
@staticmethod
+ def result_pointer(offset: int) -> 'PossibleValueSet':
+ """
+ Create a PossibleValueSet object for a pointer to the return value when the return value
+ is stored at an unknown location in memory. This is typically used for calling conventions
+ that pass in a pointer to the storage location for the return value.
+
+ :param int offset: Integer value of the offset
+ :rtype: PossibleValueSet
+ """
+ result = PossibleValueSet()
+ result._type = RegisterValueType.ResultPointerValue
+ result._value = offset
+ return result
+
+ @staticmethod
+ def parameter_pointer(idx: int, offset: int) -> 'PossibleValueSet':
+ """
+ Create a PossibleValueSet object for a pointer to a parameter when the parameter is
+ stored at an unknown location in memory. This is typically used for calling conventions
+ that pass in a pointer to the storage location for parameters (usually larger than
+ can be held in a register).
+
+ :param int idx: Index of the parameter
+ :param int offset: Integer value of the offset
+ :rtype: PossibleValueSet
+ """
+ result = PossibleValueSet()
+ result._type = RegisterValueType.ParameterPointerValue
+ result._value = idx
+ result._offset = offset
+ return result
+
+ @staticmethod
def signed_range_value(ranges: List[ValueRange]) -> 'PossibleValueSet':
"""
Create a PossibleValueSet object for a signed range of values.
@@ -846,6 +919,18 @@ class CoreVariable:
var = core.BNFromVariableIdentifier(identifier)
return cls(var.type, var.index, var.storage)
+ @classmethod
+ def reg(cls, reg: int):
+ return cls(VariableSourceType.RegisterVariableSourceType, 0, int(reg))
+
+ @classmethod
+ def flag(cls, flag: int):
+ return cls(VariableSourceType.FlagVariableSourceType, 0, int(flag))
+
+ @classmethod
+ def stack_offset(cls, offset: int):
+ return cls(VariableSourceType.StackVariableSourceType, 0, int(offset))
+
@dataclass(frozen=True, order=True)
class VariableNameAndType(CoreVariable):
@@ -872,6 +957,110 @@ class VariableNameAndType(CoreVariable):
return cls(var.type, var.index, var.storage, name, type)
+class ArchitectureVariable(CoreVariable):
+ """
+ ``class ArchitectureVariable`` is a wrapper around :py:meth:`CoreVariable` that
+ is bound to an architecture (for register/flag naming) but not a function. This
+ is typically used in calling conventions for specifying value locations. Calling
+ conventions can be used outside functions to resolve type information, so only
+ an architecture is required.
+ """
+ def __init__(
+ self, arch: 'binaryninja.architecture.Architecture', source_type: VariableSourceType, index: int,
+ storage: int
+ ):
+ super(ArchitectureVariable, self).__init__(int(source_type), index, storage)
+ self._arch = arch
+
+ @property
+ def arch(self) -> 'binaryninja.architecture.Architecture':
+ return self._arch
+
+ @classmethod
+ def reg(cls, arch: 'binaryninja.architecture.Architecture', reg: Union[str, int]):
+ if isinstance(reg, str):
+ if reg not in arch.regs:
+ raise ValueError(f"Invalid register name: {reg}")
+ reg = arch.regs[reg].index
+ return cls(arch, VariableSourceType.RegisterVariableSourceType, 0, int(reg))
+
+ @classmethod
+ def flag(cls, arch: 'binaryninja.architecture.Architecture', flag: Union[str, int]):
+ if isinstance(flag, str):
+ flag = arch.get_flag_by_name(flag)
+ return cls(arch, VariableSourceType.FlagVariableSourceType, 0, int(flag))
+
+ @classmethod
+ def stack_offset(cls, arch: 'binaryninja.architecture.Architecture', offset: int):
+ return cls(arch, VariableSourceType.StackVariableSourceType, 0, int(offset))
+
+ @property
+ def name(self) -> str:
+ if self.source_type == VariableSourceType.RegisterVariableSourceType:
+ return str(self._arch.get_reg_name(binaryninja.architecture.RegisterIndex(self.storage)))
+ if self.source_type == VariableSourceType.FlagVariableSourceType:
+ return str(self._arch.get_flag_name(binaryninja.architecture.FlagIndex(self.storage)))
+ return hex(self.storage)
+
+ @classmethod
+ def from_core_variable(cls, arch: 'binaryninja.architecture.Architecture', var: CoreVariable):
+ return cls(arch, var.source_type, var.index, var.storage)
+
+ @classmethod
+ def from_BNVariable(cls, arch: 'binaryninja.architecture.Architecture', var: core.BNVariable):
+ return cls(arch, var.type, var.index, var.storage)
+
+ @classmethod
+ def from_identifier(cls, arch: 'binaryninja.architecture.Architecture', identifier: int):
+ var = core.BNFromVariableIdentifier(identifier)
+ return cls(arch, VariableSourceType(var.type), var.index, var.storage)
+
+ def _sort_key(self):
+ if self._arch is None:
+ arch_key = ""
+ else:
+ arch_key = self._arch.name
+ return arch_key, self._source_type, self.index, self.storage
+
+ def __repr__(self):
+ if self.source_type == VariableSourceType.StackVariableSourceType:
+ return f"<var @ stack offset {self.storage:#x}>"
+ return f"<var @ {self.name}>"
+
+ def __eq__(self, other):
+ if not isinstance(other, self.__class__):
+ return NotImplemented
+ return super().__eq__(other) and (self._arch == other._arch)
+
+ def __ne__(self, other):
+ if not isinstance(other, self.__class__):
+ return NotImplemented
+ return not (self == other)
+
+ def __lt__(self, other):
+ if not isinstance(other, self.__class__):
+ return NotImplemented
+ return self._sort_key() < other._sort_key()
+
+ def __gt__(self, other):
+ if not isinstance(other, self.__class__):
+ return NotImplemented
+ return self._sort_key() > other._sort_key()
+
+ def __le__(self, other):
+ if not isinstance(other, self.__class__):
+ return NotImplemented
+ return self._sort_key() <= other._sort_key()
+
+ def __ge__(self, other):
+ if not isinstance(other, self.__class__):
+ return NotImplemented
+ return self._sort_key() >= other._sort_key()
+
+ def __hash__(self):
+ return hash((self._arch, super().__hash__()))
+
+
class Variable(CoreVariable):
"""
``class Variable`` represents variables in Binary Ninja. Variables are resolved
@@ -1151,6 +1340,53 @@ class ParameterVariables:
return self._func
+@decorators.passive
+class ParameterLocations:
+ def __init__(
+ self, location_list: List['types.ValueLocation'], confidence: int = core.max_confidence,
+ func: Optional['binaryninja.function.Function'] = None
+ ):
+ self._locations = location_list
+ self._confidence = confidence
+ self._func = func
+
+ def __repr__(self):
+ return f"<ParameterLocations: {str(self._locations)}>"
+
+ def __len__(self):
+ return len(self._vars)
+
+ def __iter__(self) -> Generator['types.ValueLocation', None, None]:
+ for location in self._locations:
+ yield location
+
+ def __eq__(self, other) -> bool:
+ return (self._locations, self._confidence, self._func) == (other._locations, other._confidence, other._func)
+
+ def __getitem__(self, idx) -> 'types.ValueLocation':
+ return self._locations[idx]
+
+ def __setitem__(self, idx: int, value: 'types.ValueLocation'):
+ self._locations[idx] = value
+ if self._func is not None:
+ self._func.parameter_locations = self
+
+ def with_confidence(self, confidence: int) -> 'ParameterLocations':
+ return ParameterLocations(list(self._locations), confidence, self._func)
+
+ @property
+ def locations(self) -> List['types.ValueLocation']:
+ return self._locations
+
+ @property
+ def confidence(self) -> int:
+ return self._confidence
+
+ @property
+ def function(self) -> Optional['binaryninja.function.Function']:
+ return self._func
+
+
@dataclass(frozen=True, order=True)
class AddressRange:
start: int # Inclusive starting address
diff --git a/rust/src/binary_view.rs b/rust/src/binary_view.rs
index 8d49e55e..c455635a 100644
--- a/rust/src/binary_view.rs
+++ b/rust/src/binary_view.rs
@@ -51,8 +51,9 @@ use crate::string::*;
use crate::symbol::{Symbol, SymbolType};
use crate::tags::{Tag, TagReference, TagType};
use crate::types::{
- NamedTypeReference, QualifiedName, QualifiedNameAndType, QualifiedNameTypeAndId, Type,
- TypeArchive, TypeArchiveId, TypeContainer, TypeLibrary,
+ FunctionParameter, NamedTypeReference, QualifiedName, QualifiedNameAndType,
+ QualifiedNameTypeAndId, ReturnValue, Type, TypeArchive, TypeArchiveId, TypeContainer,
+ TypeLibrary,
};
use crate::variable::DataVariable;
use crate::workflow::Workflow;
@@ -2964,6 +2965,36 @@ impl BinaryView {
let path_str = unsafe { BnString::into_string(result) };
Some(PathBuf::from(path_str))
}
+
+ pub fn deref_return_value_named_type_references(
+ &self,
+ return_value: &ReturnValue,
+ ) -> ReturnValue {
+ ReturnValue {
+ ty: Conf::new(
+ return_value.ty.contents.deref_named_type_reference(self),
+ return_value.ty.confidence,
+ ),
+ location: return_value.location.clone(),
+ }
+ }
+
+ pub fn deref_parameter_named_type_references(
+ &self,
+ params: &[FunctionParameter],
+ ) -> Vec<FunctionParameter> {
+ params
+ .iter()
+ .map(|param| FunctionParameter {
+ ty: Conf::new(
+ param.ty.contents.deref_named_type_reference(self),
+ param.ty.confidence,
+ ),
+ name: param.name.clone(),
+ location: param.location.clone(),
+ })
+ .collect()
+ }
}
impl BinaryViewBase for BinaryView {
diff --git a/rust/src/calling_convention.rs b/rust/src/calling_convention.rs
index a2c4fd94..f91e9803 100644
--- a/rust/src/calling_convention.rs
+++ b/rust/src/calling_convention.rs
@@ -15,6 +15,7 @@
//! Contains and provides information about different systems' calling conventions to analysis.
use std::borrow::Borrow;
+use std::collections::BTreeMap;
use std::ffi::c_void;
use std::fmt::{Debug, Formatter};
use std::hash::{Hash, Hasher};
@@ -25,10 +26,11 @@ use binaryninjacore_sys::*;
use crate::architecture::{
Architecture, ArchitectureExt, CoreArchitecture, CoreRegister, Register, RegisterId,
};
-use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable};
+use crate::binary_view::BinaryView;
+use crate::ffi::slice_from_raw_parts;
+use crate::rc::{CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable};
use crate::string::*;
-use crate::types::FunctionParameter;
-use crate::variable::Variable;
+use crate::types::{FunctionParameter, ReturnValue, ValueLocation};
// TODO
// force valid registers once Arch has _from_id methods
// CallingConvention impl
@@ -465,6 +467,23 @@ where
getParameterVariableForIncomingVariable: Some(cb_incoming_param_for_var::<C>),
areArgumentRegistersUsedForVarArgs: Some(cb_are_argument_registers_used_for_var_args::<C>),
+
+ isReturnTypeRegisterCompatible: None,
+ getIndirectReturnValueLocation: None,
+ getReturnedIndirectReturnValuePointer: None,
+ isArgumentTypeRegisterCompatible: None,
+ isNonRegisterArgumentIndirect: None,
+ areStackArgumentsNaturallyAligned: None,
+
+ getCallLayout: None,
+ freeCallLayout: None,
+ getReturnValueLocation: None,
+ freeValueLocation: None,
+ getParameterLocations: None,
+ freeParameterLocations: None,
+ getStackAdjustmentForLocations: None,
+ getRegisterStackAdjustments: None,
+ freeRegisterStackAdjustments: None,
};
unsafe {
@@ -514,46 +533,63 @@ impl CoreCallingConvention {
unsafe { BnString::into_string(BNGetCallingConventionName(self.handle)) }
}
- pub fn variables_for_parameters(
+ pub fn call_layout(
&self,
+ view: &BinaryView,
+ return_value: impl Into<ReturnValue>,
params: &[FunctionParameter],
permitted_registers: Option<&[CoreRegister]>,
- ) -> Vec<Variable> {
- let mut count: usize = 0;
+ ) -> CallLayout {
+ let raw_return_value = ReturnValue::into_rust_raw(return_value.into());
let raw_params: Vec<BNFunctionParameter> = params
.iter()
.cloned()
.map(FunctionParameter::into_raw)
.collect();
- let raw_vars_ptr: *mut BNVariable = if let Some(permitted_args) = permitted_registers {
+ let raw_layout: BNCallLayout = if let Some(permitted_args) = permitted_registers {
let permitted_regs = permitted_args.iter().map(|r| r.id().0).collect::<Vec<_>>();
unsafe {
- BNGetVariablesForParameters(
+ BNGetCallLayout(
self.handle,
+ view.handle,
+ &raw_return_value,
raw_params.as_ptr(),
raw_params.len(),
permitted_regs.as_ptr(),
permitted_regs.len(),
- &mut count,
)
}
} else {
unsafe {
- BNGetVariablesForParametersDefaultPermittedArgs(
+ BNGetCallLayoutDefaultPermittedArgs(
self.handle,
+ view.handle,
+ &raw_return_value,
raw_params.as_ptr(),
raw_params.len(),
- &mut count,
)
}
};
- for raw_param in raw_params {
- FunctionParameter::free_raw(raw_param);
- }
+ ReturnValue::free_rust_raw(raw_return_value);
+ CallLayout::from_owned_core_raw(raw_layout)
+ }
- unsafe { Array::<Variable>::new(raw_vars_ptr, count, ()) }.to_vec()
+ pub fn return_value_location(
+ &self,
+ view: &BinaryView,
+ return_value: impl Into<ReturnValue>,
+ ) -> ValueLocation {
+ let mut raw_return_value = ReturnValue::into_rust_raw(return_value.into());
+ let mut raw_location =
+ unsafe { BNGetReturnValueLocation(self.handle, view.handle, &mut raw_return_value) };
+ ReturnValue::free_rust_raw(raw_return_value);
+ let result = ValueLocation::from_raw(&raw_location);
+ unsafe {
+ BNFreeValueLocation(&mut raw_location);
+ }
+ result
}
}
@@ -1020,3 +1056,57 @@ impl<A: Architecture> CallingConvention for ConventionBuilder<A> {
unsafe impl<A: Architecture> Send for ConventionBuilder<A> {}
unsafe impl<A: Architecture> Sync for ConventionBuilder<A> {}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct CallLayout {
+ pub parameters: Vec<ValueLocation>,
+ pub return_value: Option<ValueLocation>,
+ pub stack_adjustment: i64,
+ pub register_stack_adjustments: BTreeMap<RegisterId, i32>,
+}
+
+impl CallLayout {
+ pub(crate) fn from_raw(value: &BNCallLayout) -> Self {
+ let raw_params = unsafe { slice_from_raw_parts(value.parameters, value.parameterCount) };
+ let parameters = raw_params.iter().map(ValueLocation::from_raw).collect();
+ let return_value = if value.returnValueValid {
+ Some(ValueLocation::from_raw(&value.returnValue))
+ } else {
+ None
+ };
+ let raw_regs = unsafe {
+ slice_from_raw_parts(
+ value.registerStackAdjustmentRegisters,
+ value.registerStackAdjustmentCount,
+ )
+ };
+ let raw_amounts = unsafe {
+ slice_from_raw_parts(
+ value.registerStackAdjustmentAmounts,
+ value.registerStackAdjustmentCount,
+ )
+ };
+ let mut register_stack_adjustments = BTreeMap::new();
+ for i in 0..value.registerStackAdjustmentCount {
+ register_stack_adjustments.insert(RegisterId(raw_regs[i]), raw_amounts[i]);
+ }
+ Self {
+ parameters,
+ return_value,
+ stack_adjustment: value.stackAdjustment,
+ register_stack_adjustments,
+ }
+ }
+
+ /// Take ownership over an "owned" **core allocated** value. Do not call this for a rust allocated value.
+ pub(crate) fn from_owned_core_raw(mut value: BNCallLayout) -> Self {
+ let owned = Self::from_raw(&value);
+ Self::free_core_raw(&mut value);
+ owned
+ }
+
+ /// Free a CORE ALLOCATED value. Do not use this with [Self::into_rust_raw] values.
+ pub(crate) fn free_core_raw(value: &mut BNCallLayout) {
+ unsafe { BNFreeCallLayout(value) }
+ }
+}
diff --git a/rust/src/confidence.rs b/rust/src/confidence.rs
index f8745180..31ce7582 100644
--- a/rust/src/confidence.rs
+++ b/rust/src/confidence.rs
@@ -3,11 +3,11 @@
use crate::architecture::{Architecture, CoreArchitecture};
use crate::calling_convention::CoreCallingConvention;
use crate::rc::{Ref, RefCountable};
-use crate::types::Type;
+use crate::types::{Type, ValueLocation};
use binaryninjacore_sys::{
BNBoolWithConfidence, BNCallingConventionWithConfidence, BNGetCallingConventionArchitecture,
BNInlineDuringAnalysis, BNInlineDuringAnalysisWithConfidence, BNOffsetWithConfidence,
- BNTypeWithConfidence,
+ BNTypeWithConfidence, BNValueLocation, BNValueLocationWithConfidence,
};
use std::fmt;
use std::fmt::{Debug, Display, Formatter};
@@ -225,6 +225,19 @@ impl Conf<Ref<Type>> {
}
}
+impl Conf<ValueLocation> {
+ pub(crate) fn into_rust_raw(value: Self) -> BNValueLocationWithConfidence {
+ BNValueLocationWithConfidence {
+ location: ValueLocation::into_rust_raw(&value.contents),
+ confidence: value.confidence,
+ }
+ }
+
+ pub(crate) fn free_rust_raw(value: BNValueLocationWithConfidence) {
+ ValueLocation::free_rust_raw(value.location);
+ }
+}
+
impl Conf<Ref<CoreCallingConvention>> {
pub(crate) fn from_raw(value: &BNCallingConventionWithConfidence) -> Self {
let arch = unsafe {
diff --git a/rust/src/disassembly.rs b/rust/src/disassembly.rs
index cb9bf6a1..718c7737 100644
--- a/rust/src/disassembly.rs
+++ b/rust/src/disassembly.rs
@@ -506,6 +506,7 @@ pub enum InstructionTextTokenKind {
// TODO: Explain what this is
hash: Option<u64>,
},
+ ValueLocation,
CodeSymbol {
// Target address of the symbol
value: u64,
@@ -700,6 +701,7 @@ impl InstructionTextTokenKind {
hash => Some(hash),
},
},
+ BNInstructionTextTokenType::ValueLocationToken => Self::ValueLocation,
BNInstructionTextTokenType::CodeSymbolToken => Self::CodeSymbol {
value: value.value,
size: value.size,
@@ -914,6 +916,9 @@ impl From<InstructionTextTokenKind> for BNInstructionTextTokenType {
BNInstructionTextTokenType::BaseStructureSeparatorToken
}
InstructionTextTokenKind::Brace { .. } => BNInstructionTextTokenType::BraceToken,
+ InstructionTextTokenKind::ValueLocation => {
+ BNInstructionTextTokenType::ValueLocationToken
+ }
InstructionTextTokenKind::CodeSymbol { .. } => {
BNInstructionTextTokenType::CodeSymbolToken
}
diff --git a/rust/src/ffi.rs b/rust/src/ffi.rs
index 45d142bf..aaa4851e 100644
--- a/rust/src/ffi.rs
+++ b/rust/src/ffi.rs
@@ -31,6 +31,19 @@ pub(crate) fn time_from_bn(timestamp: u64) -> SystemTime {
UNIX_EPOCH + m
}
+pub(crate) unsafe fn slice_from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] {
+ if len == 0 {
+ // C can and will pass null pointers for data in the case of zero length arrays.
+ // According to the documentation of std::slice::from_raw_parts, data must be
+ // non-null and properly aligned. To avoid creating unsound slices, return an
+ // empty slice directly on any zero-length array, avoiding the unsound call
+ // to std::slice::from_raw_parts.
+ &[]
+ } else {
+ unsafe { std::slice::from_raw_parts(data, len) }
+ }
+}
+
#[macro_export]
macro_rules! ffi_span {
($name:expr, $bv:expr) => {{
diff --git a/rust/src/function.rs b/rust/src/function.rs
index 320382de..6a62946f 100644
--- a/rust/src/function.rs
+++ b/rust/src/function.rs
@@ -21,6 +21,7 @@ use crate::{
calling_convention::CoreCallingConvention,
component::Component,
disassembly::{DisassemblySettings, DisassemblyTextLine},
+ ffi::slice_from_raw_parts,
flowgraph::FlowGraph,
medium_level_il::FunctionGraphType,
platform::Platform,
@@ -28,7 +29,7 @@ use crate::{
string::*,
symbol::{Binding, Symbol},
tags::{Tag, TagReference, TagType},
- types::{IntegerDisplayType, QualifiedName, Type},
+ types::{IntegerDisplayType, QualifiedName, ReturnValue, Type, ValueLocation},
};
use crate::{data_buffer::DataBuffer, disassembly::InstructionTextToken, rc::*};
pub use binaryninjacore_sys::BNAnalysisSkipReason as AnalysisSkipReason;
@@ -657,6 +658,11 @@ impl Function {
Conf::<Ref<Type>>::from_owned_raw(raw_return_type)
}
+ pub fn return_value(&self) -> ReturnValue {
+ let raw_return_value = unsafe { BNGetFunctionReturnValue(self.handle) };
+ ReturnValue::from_owned_core_raw(raw_return_value)
+ }
+
pub fn set_auto_return_type<'a, C>(&self, return_type: C)
where
C: Into<Conf<&'a Type>>,
@@ -665,6 +671,22 @@ impl Function {
unsafe { BNSetAutoFunctionReturnType(self.handle, &mut raw_return_type) }
}
+ pub fn set_auto_is_return_value_default_location(&self, is_default: bool) {
+ unsafe { BNSetAutoIsFunctionReturnValueDefaultLocation(self.handle, is_default) }
+ }
+
+ pub fn set_auto_return_value_location(&self, location: impl Into<Conf<ValueLocation>>) {
+ let mut raw_location = Conf::<ValueLocation>::into_rust_raw(location.into());
+ unsafe { BNSetAutoFunctionReturnValueLocation(self.handle, &mut raw_location) };
+ Conf::<ValueLocation>::free_rust_raw(raw_location);
+ }
+
+ pub fn set_auto_return_value(&self, return_value: impl Into<ReturnValue>) {
+ let mut raw_return_value = ReturnValue::into_rust_raw(return_value.into());
+ unsafe { BNSetAutoFunctionReturnValue(self.handle, &mut raw_return_value) }
+ ReturnValue::free_rust_raw(raw_return_value);
+ }
+
pub fn set_user_return_type<'a, C>(&self, return_type: C)
where
C: Into<Conf<&'a Type>>,
@@ -673,6 +695,22 @@ impl Function {
unsafe { BNSetUserFunctionReturnType(self.handle, &mut raw_return_type) }
}
+ pub fn set_user_is_return_value_default_location(&self, is_default: bool) {
+ unsafe { BNSetUserIsFunctionReturnValueDefaultLocation(self.handle, is_default) }
+ }
+
+ pub fn set_user_return_value_location(&self, location: impl Into<Conf<ValueLocation>>) {
+ let mut raw_location = Conf::<ValueLocation>::into_rust_raw(location.into());
+ unsafe { BNSetUserFunctionReturnValueLocation(self.handle, &mut raw_location) };
+ Conf::<ValueLocation>::free_rust_raw(raw_location);
+ }
+
+ pub fn set_user_return_value(&self, return_value: impl Into<ReturnValue>) {
+ let mut raw_return_value = ReturnValue::into_rust_raw(return_value.into());
+ unsafe { BNSetUserFunctionReturnValue(self.handle, &mut raw_return_value) }
+ ReturnValue::free_rust_raw(raw_return_value);
+ }
+
pub fn function_type(&self) -> Ref<Type> {
unsafe { Type::ref_from_raw(BNGetFunctionType(self.handle)) }
}
@@ -1017,38 +1055,65 @@ impl Function {
}
}
- pub fn set_user_parameter_variables<I>(&self, values: I, confidence: u8)
+ pub fn parameter_locations(&self) -> Conf<Vec<ValueLocation>> {
+ unsafe {
+ let mut raw_locations = BNGetFunctionParameterLocations(self.handle);
+ let raw_location_list =
+ slice_from_raw_parts(raw_locations.locations, raw_locations.count);
+ let locations: Vec<ValueLocation> = raw_location_list
+ .iter()
+ .map(ValueLocation::from_raw)
+ .collect();
+ let confidence = raw_locations.confidence;
+ BNFreeParameterLocations(&mut raw_locations);
+ Conf::new(locations, confidence)
+ }
+ }
+
+ pub fn set_user_parameter_locations<I>(&self, values: I, confidence: u8)
where
- I: IntoIterator<Item = Variable>,
+ I: IntoIterator<Item = ValueLocation>,
{
- let vars: Vec<BNVariable> = values.into_iter().map(Into::into).collect();
+ let locations: Vec<BNValueLocation> = values
+ .into_iter()
+ .map(|location| ValueLocation::into_rust_raw(&location.into()))
+ .collect();
unsafe {
- BNSetUserFunctionParameterVariables(
+ BNSetUserFunctionParameterLocations(
self.handle,
- &mut BNParameterVariablesWithConfidence {
- vars: vars.as_ptr() as *mut _,
- count: vars.len(),
+ &mut BNValueLocationListWithConfidence {
+ locations: locations.as_ptr() as *mut _,
+ count: locations.len(),
confidence,
},
)
}
+ locations
+ .into_iter()
+ .for_each(|location| ValueLocation::free_rust_raw(location.into()));
}
- pub fn set_auto_parameter_variables<I>(&self, values: I, confidence: u8)
+ pub fn set_auto_parameter_locations<I>(&self, values: I, confidence: u8)
where
- I: IntoIterator<Item = Variable>,
+ I: IntoIterator<Item = ValueLocation>,
{
- let vars: Vec<BNVariable> = values.into_iter().map(Into::into).collect();
+ let locations: Vec<BNValueLocation> = values
+ .into_iter()
+ .map(|location| ValueLocation::into_rust_raw(&location.into()))
+ .collect();
unsafe {
- BNSetAutoFunctionParameterVariables(
+ BNSetAutoFunctionParameterLocations(
self.handle,
- &mut BNParameterVariablesWithConfidence {
- vars: vars.as_ptr() as *mut _,
- count: vars.len(),
+ &mut BNValueLocationListWithConfidence {
+ locations: locations.as_ptr() as *mut _,
+ count: locations.len(),
confidence,
},
)
}
+ locations
+ .into_iter()
+ .for_each(|location| ValueLocation::free_rust_raw(location.into()));
}
pub fn parameter_at(
@@ -2536,32 +2601,6 @@ impl Function {
Conf::new(regs, result.confidence)
}
- pub fn set_user_return_registers<I>(&self, values: I, confidence: u8)
- where
- I: IntoIterator<Item = CoreRegister>,
- {
- let mut regs: Box<[u32]> = values.into_iter().map(|reg| reg.id().0).collect();
- let mut regs = BNRegisterSetWithConfidence {
- regs: regs.as_mut_ptr(),
- count: regs.len(),
- confidence,
- };
- unsafe { BNSetUserFunctionReturnRegisters(self.handle, &mut regs) }
- }
-
- pub fn set_auto_return_registers<I>(&self, values: I, confidence: u8)
- where
- I: IntoIterator<Item = CoreRegister>,
- {
- let mut regs: Box<[u32]> = values.into_iter().map(|reg| reg.id().0).collect();
- let mut regs = BNRegisterSetWithConfidence {
- regs: regs.as_mut_ptr(),
- count: regs.len(),
- confidence,
- };
- unsafe { BNSetAutoFunctionReturnRegisters(self.handle, &mut regs) }
- }
-
/// Flow graph of unresolved stack adjustments
pub fn unresolved_stack_adjustment_graph(&self) -> Option<Ref<FlowGraph>> {
let graph = unsafe { BNGetUnresolvedStackAdjustmentGraph(self.handle) };
diff --git a/rust/src/high_level_il/instruction.rs b/rust/src/high_level_il/instruction.rs
index 80be2a16..98839cae 100644
--- a/rust/src/high_level_il/instruction.rs
+++ b/rust/src/high_level_il/instruction.rs
@@ -400,6 +400,12 @@ impl HighLevelILInstruction {
HLIL_ADDRESS_OF => Op::AddressOf(UnaryOp {
src: HighLevelExpressionIndex::from(op.operands[0]),
}),
+ HLIL_PASS_BY_REF => Op::PassByRef(UnaryOp {
+ src: HighLevelExpressionIndex::from(op.operands[0]),
+ }),
+ HLIL_RETURN_BY_REF => Op::ReturnByRef(UnaryOp {
+ src: HighLevelExpressionIndex::from(op.operands[0]),
+ }),
HLIL_NEG => Op::Neg(UnaryOp {
src: HighLevelExpressionIndex::from(op.operands[0]),
}),
@@ -784,6 +790,8 @@ impl HighLevelILInstruction {
Deref(op) => Lifted::Deref(self.lift_unary_op(op)),
AddressOf(op) => Lifted::AddressOf(self.lift_unary_op(op)),
+ PassByRef(op) => Lifted::PassByRef(self.lift_unary_op(op)),
+ ReturnByRef(op) => Lifted::ReturnByRef(self.lift_unary_op(op)),
Neg(op) => Lifted::Neg(self.lift_unary_op(op)),
Not(op) => Lifted::Not(self.lift_unary_op(op)),
Sx(op) => Lifted::Sx(self.lift_unary_op(op)),
@@ -1161,6 +1169,8 @@ pub enum HighLevelILInstructionKind {
ConstData(ConstData),
Deref(UnaryOp),
AddressOf(UnaryOp),
+ PassByRef(UnaryOp),
+ ReturnByRef(UnaryOp),
Neg(UnaryOp),
Not(UnaryOp),
Sx(UnaryOp),
diff --git a/rust/src/high_level_il/lift.rs b/rust/src/high_level_il/lift.rs
index ab04f44b..e2ce3686 100644
--- a/rust/src/high_level_il/lift.rs
+++ b/rust/src/high_level_il/lift.rs
@@ -112,6 +112,8 @@ pub enum HighLevelILLiftedInstructionKind {
ConstData(LiftedConstData),
Deref(LiftedUnaryOp),
AddressOf(LiftedUnaryOp),
+ PassByRef(LiftedUnaryOp),
+ ReturnByRef(LiftedUnaryOp),
Neg(LiftedUnaryOp),
Not(LiftedUnaryOp),
Sx(LiftedUnaryOp),
@@ -240,6 +242,8 @@ impl HighLevelILLiftedInstruction {
ConstData(_) => "ConstData",
Deref(_) => "Deref",
AddressOf(_) => "AddressOf",
+ PassByRef(_) => "PassByRef",
+ ReturnByRef(_) => "ReturnByRef",
Neg(_) => "Neg",
Not(_) => "Not",
Sx(_) => "Sx",
@@ -360,10 +364,12 @@ impl HighLevelILLiftedInstruction {
"constant_data",
Operand::ConstantData(op.constant_data.clone()),
)],
- Deref(op) | AddressOf(op) | Neg(op) | Not(op) | Sx(op) | Zx(op) | LowPart(op)
- | BoolToInt(op) | UnimplMem(op) | Fsqrt(op) | Fneg(op) | Fabs(op) | FloatToInt(op)
- | IntToFloat(op) | FloatConv(op) | RoundToInt(op) | Floor(op) | Ceil(op)
- | Ftrunc(op) => vec![("src", Operand::Expr(*op.src.clone()))],
+ Deref(op) | AddressOf(op) | PassByRef(op) | ReturnByRef(op) | Neg(op) | Not(op)
+ | Sx(op) | Zx(op) | LowPart(op) | BoolToInt(op) | UnimplMem(op) | Fsqrt(op)
+ | Fneg(op) | Fabs(op) | FloatToInt(op) | IntToFloat(op) | FloatConv(op)
+ | RoundToInt(op) | Floor(op) | Ceil(op) | Ftrunc(op) => {
+ vec![("src", Operand::Expr(*op.src.clone()))]
+ }
DerefFieldSsa(op) => vec![
("src", Operand::Expr(*op.src.clone())),
("src_memory", Operand::Int(op.src_memory)),
diff --git a/rust/src/medium_level_il/instruction.rs b/rust/src/medium_level_il/instruction.rs
index a223f21e..41f2bbe4 100644
--- a/rust/src/medium_level_il/instruction.rs
+++ b/rust/src/medium_level_il/instruction.rs
@@ -654,9 +654,22 @@ impl MediumLevelILInstruction {
MLIL_VAR_OUTPUT => Op::VarOutput(VarOutput {
dest: get_var(op.operands[0]),
}),
+ MLIL_VAR_OUTPUT_FIELD => Op::VarOutputField(VarOutputField {
+ dest: get_var(op.operands[0]),
+ offset: op.operands[1],
+ }),
+ MLIL_STORE_OUTPUT => Op::StoreOutput(StoreOutput {
+ dest: MediumLevelExpressionIndex::from(op.operands[0]),
+ }),
MLIL_ADDRESS_OF => Op::AddressOf(Var {
src: get_var(op.operands[0]),
}),
+ MLIL_PASS_BY_REF => Op::PassByRef(UnaryOp {
+ src: MediumLevelExpressionIndex::from(op.operands[0] as usize),
+ }),
+ MLIL_RETURN_BY_REF => Op::ReturnByRef(UnaryOp {
+ src: MediumLevelExpressionIndex::from(op.operands[0] as usize),
+ }),
MLIL_VAR_FIELD => Op::VarField(Field {
src: get_var(op.operands[0]),
offset: op.operands[1],
@@ -682,9 +695,27 @@ impl MediumLevelILInstruction {
MLIL_VAR_OUTPUT_SSA => Op::VarOutputSsa(VarOutputSsa {
dest: get_var_ssa(op.operands[0], op.operands[1] as usize),
}),
+ MLIL_VAR_OUTPUT_SSA_FIELD => Op::VarOutputSsaField(VarOutputSsaField {
+ dest: get_var_ssa(op.operands[0], op.operands[1] as usize),
+ prev: get_var_ssa(op.operands[0], op.operands[2] as usize),
+ offset: op.operands[3],
+ }),
+ MLIL_VAR_OUTPUT_ALIASED => Op::VarOutputAliased(VarOutputAliased {
+ dest: get_var_ssa(op.operands[0], op.operands[1] as usize),
+ prev: get_var_ssa(op.operands[0], op.operands[2] as usize),
+ }),
+ MLIL_VAR_OUTPUT_ALIASED_FIELD => Op::VarOutputAliasedField(VarOutputAliasedField {
+ dest: get_var_ssa(op.operands[0], op.operands[1] as usize),
+ prev: get_var_ssa(op.operands[0], op.operands[2] as usize),
+ offset: op.operands[3],
+ }),
MLIL_TRAP => Op::Trap(Trap {
vector: op.operands[0],
}),
+ MLIL_BLOCK_TO_EXPAND => Op::BlockToExpand(BlockToExpand {
+ num_operands: op.operands[0] as usize,
+ first_operand: op.operands[1] as usize,
+ }),
};
Self {
@@ -1121,7 +1152,13 @@ impl MediumLevelILInstruction {
}),
Var(op) => Lifted::Var(op),
VarOutput(op) => Lifted::VarOutput(op),
+ VarOutputField(op) => Lifted::VarOutputField(op),
+ StoreOutput(op) => Lifted::StoreOutput(LiftedStoreOutput {
+ dest: self.lift_operand(op.dest),
+ }),
AddressOf(op) => Lifted::AddressOf(op),
+ PassByRef(op) => Lifted::PassByRef(self.lift_unary_op(op)),
+ ReturnByRef(op) => Lifted::ReturnByRef(self.lift_unary_op(op)),
VarField(op) => Lifted::VarField(op),
AddressOfField(op) => Lifted::AddressOfField(op),
VarSsa(op) => Lifted::VarSsa(op),
@@ -1129,7 +1166,17 @@ impl MediumLevelILInstruction {
VarSsaField(op) => Lifted::VarSsaField(op),
VarAliasedField(op) => Lifted::VarAliasedField(op),
VarOutputSsa(op) => Lifted::VarOutputSsa(op),
+ VarOutputSsaField(op) => Lifted::VarOutputSsaField(op),
+ VarOutputAliased(op) => Lifted::VarOutputAliased(op),
+ VarOutputAliasedField(op) => Lifted::VarOutputAliasedField(op),
Trap(op) => Lifted::Trap(op),
+ BlockToExpand(_op) => Lifted::BlockToExpand(LiftedBlockToExpand {
+ exprs: self
+ .get_expr_list(0)
+ .iter()
+ .map(|expr| expr.lift())
+ .collect(),
+ }),
};
MediumLevelILLiftedInstruction {
@@ -1823,6 +1870,8 @@ pub enum MediumLevelILInstructionKind {
SeparateParamList(SeparateParamList),
SharedParamSlot(SharedParamSlot),
VarOutput(VarOutput),
+ VarOutputField(VarOutputField),
+ StoreOutput(StoreOutput),
Neg(UnaryOp),
Not(UnaryOp),
Sx(UnaryOp),
@@ -1847,6 +1896,8 @@ pub enum MediumLevelILInstructionKind {
Ret(Ret),
Var(Var),
AddressOf(Var),
+ PassByRef(UnaryOp),
+ ReturnByRef(UnaryOp),
VarField(Field),
AddressOfField(Field),
VarSsa(VarSsa),
@@ -1854,7 +1905,11 @@ pub enum MediumLevelILInstructionKind {
VarSsaField(VarSsaField),
VarAliasedField(VarSsaField),
VarOutputSsa(VarOutputSsa),
+ VarOutputSsaField(VarOutputSsaField),
+ VarOutputAliased(VarOutputAliased),
+ VarOutputAliasedField(VarOutputAliasedField),
Trap(Trap),
+ BlockToExpand(BlockToExpand),
// A placeholder for instructions that the Rust bindings do not yet support.
// Distinct from `Unimpl` as that is a valid instruction.
NotYetImplemented,
diff --git a/rust/src/medium_level_il/lift.rs b/rust/src/medium_level_il/lift.rs
index 58ea8a13..aee8139f 100644
--- a/rust/src/medium_level_il/lift.rs
+++ b/rust/src/medium_level_il/lift.rs
@@ -176,7 +176,11 @@ pub enum MediumLevelILLiftedInstructionKind {
Ret(LiftedRet),
Var(Var),
VarOutput(VarOutput),
+ VarOutputField(VarOutputField),
+ StoreOutput(LiftedStoreOutput),
AddressOf(Var),
+ PassByRef(LiftedUnaryOp),
+ ReturnByRef(LiftedUnaryOp),
VarField(Field),
AddressOfField(Field),
VarSsa(VarSsa),
@@ -184,7 +188,11 @@ pub enum MediumLevelILLiftedInstructionKind {
VarSsaField(VarSsaField),
VarAliasedField(VarSsaField),
VarOutputSsa(VarOutputSsa),
+ VarOutputSsaField(VarOutputSsaField),
+ VarOutputAliased(VarOutputAliased),
+ VarOutputAliasedField(VarOutputAliasedField),
Trap(Trap),
+ BlockToExpand(LiftedBlockToExpand),
// A placeholder for instructions that the Rust bindings do not yet support.
// Distinct from `Unimpl` as that is a valid instruction.
NotYetImplemented,
@@ -301,6 +309,8 @@ impl MediumLevelILLiftedInstruction {
SeparateParamList(_) => "SeparateParamList",
SharedParamSlot(_) => "SharedParamSlot",
VarOutput(_) => "VarOutput",
+ VarOutputField(_) => "VarOutputField",
+ StoreOutput(_) => "StoreOutput",
Neg(_) => "Neg",
Not(_) => "Not",
Sx(_) => "Sx",
@@ -325,6 +335,8 @@ impl MediumLevelILLiftedInstruction {
Ret(_) => "Ret",
Var(_) => "Var",
AddressOf(_) => "AddressOf",
+ PassByRef(_) => "PassByRef",
+ ReturnByRef(_) => "ReturnByRef",
VarField(_) => "VarField",
AddressOfField(_) => "AddressOfField",
VarSsa(_) => "VarSsa",
@@ -332,7 +344,11 @@ impl MediumLevelILLiftedInstruction {
VarSsaField(_) => "VarSsaField",
VarAliasedField(_) => "VarAliasedField",
VarOutputSsa(_) => "VarOutputSsa",
+ VarOutputSsaField(_) => "VarOutputSsaField",
+ VarOutputAliased(_) => "VarOutputAliased",
+ VarOutputAliasedField(_) => "VarOutputAliasedField",
Trap(_) => "Trap",
+ BlockToExpand(_) => "BlockToExpand",
}
}
@@ -549,6 +565,13 @@ impl MediumLevelILLiftedInstruction {
SharedParamSlot(op) => vec![("params", Operand::ExprList(op.params.clone()))],
Var(op) | AddressOf(op) => vec![("src", Operand::Var(op.src))],
VarOutput(op) => vec![("dest", Operand::Var(op.dest))],
+ VarOutputField(op) => vec![
+ ("dest", Operand::Var(op.dest)),
+ ("offset", Operand::Int(op.offset)),
+ ],
+ StoreOutput(op) => vec![("dest", Operand::Expr(*op.dest.clone()))],
+ PassByRef(op) => vec![("src", Operand::Expr(*op.src.clone()))],
+ ReturnByRef(op) => vec![("src", Operand::Expr(*op.src.clone()))],
VarField(op) | AddressOfField(op) => vec![
("src", Operand::Var(op.src)),
("offset", Operand::Int(op.offset)),
@@ -559,7 +582,22 @@ impl MediumLevelILLiftedInstruction {
("offset", Operand::Int(op.offset)),
],
VarOutputSsa(op) => vec![("dest", Operand::VarSsa(op.dest))],
+ VarOutputSsaField(op) => vec![
+ ("dest", Operand::VarSsa(op.dest)),
+ ("prev", Operand::VarSsa(op.prev)),
+ ("offset", Operand::Int(op.offset)),
+ ],
+ VarOutputAliased(op) => vec![
+ ("dest", Operand::VarSsa(op.dest)),
+ ("prev", Operand::VarSsa(op.prev)),
+ ],
+ VarOutputAliasedField(op) => vec![
+ ("dest", Operand::VarSsa(op.dest)),
+ ("prev", Operand::VarSsa(op.prev)),
+ ("offset", Operand::Int(op.offset)),
+ ],
Trap(op) => vec![("vector", Operand::Int(op.vector))],
+ BlockToExpand(op) => vec![("exprs", Operand::ExprList(op.exprs.clone()))],
}
}
}
diff --git a/rust/src/medium_level_il/operation.rs b/rust/src/medium_level_il/operation.rs
index a9a791b0..1886b3d0 100644
--- a/rust/src/medium_level_il/operation.rs
+++ b/rust/src/medium_level_il/operation.rs
@@ -641,6 +641,23 @@ pub struct VarOutput {
pub dest: Variable,
}
+// VAR_OUTPUT_FIELD
+#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
+pub struct VarOutputField {
+ pub dest: Variable,
+ pub offset: u64,
+}
+
+// STORE_OUTPUT
+#[derive(Debug, Copy, Clone)]
+pub struct StoreOutput {
+ pub dest: MediumLevelExpressionIndex,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedStoreOutput {
+ pub dest: Box<MediumLevelILLiftedInstruction>,
+}
+
// VAR_FIELD, ADDRESS_OF_FIELD
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
pub struct Field {
@@ -667,8 +684,42 @@ pub struct VarOutputSsa {
pub dest: SSAVariable,
}
+// VAR_OUTPUT_SSA_FIELD
+#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
+pub struct VarOutputSsaField {
+ pub dest: SSAVariable,
+ pub prev: SSAVariable,
+ pub offset: u64,
+}
+
+// VAR_OUTPUT_ALIASED
+#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
+pub struct VarOutputAliased {
+ pub dest: SSAVariable,
+ pub prev: SSAVariable,
+}
+
+// VAR_OUTPUT_ALIASED_FIELD
+#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
+pub struct VarOutputAliasedField {
+ pub dest: SSAVariable,
+ pub prev: SSAVariable,
+ pub offset: u64,
+}
+
// TRAP
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
pub struct Trap {
pub vector: u64,
}
+
+// BLOCK_TO_EXPAND
+#[derive(Debug, Copy, Clone)]
+pub struct BlockToExpand {
+ pub first_operand: usize,
+ pub num_operands: usize,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedBlockToExpand {
+ pub exprs: Vec<MediumLevelILLiftedInstruction>,
+}
diff --git a/rust/src/types.rs b/rust/src/types.rs
index e6c16f6b..a7ec517e 100644
--- a/rust/src/types.rs
+++ b/rust/src/types.rs
@@ -35,7 +35,7 @@ pub mod structure;
use binaryninjacore_sys::*;
use crate::{
- architecture::Architecture,
+ architecture::{Architecture, Register, RegisterId},
binary_view::BinaryView,
calling_convention::CoreCallingConvention,
rc::*,
@@ -449,12 +449,12 @@ impl TypeBuilder {
// TODO: Deprecate this for a FunctionBuilder (along with the Type variant?)
/// NOTE: This is likely to be deprecated and removed in favor of a function type builder, please
/// use [`Type::function`] where possible.
- pub fn function<'a, T: Into<Conf<&'a Type>>>(
- return_type: T,
+ pub fn function<'a, T: Into<ReturnValue>>(
+ return_value: T,
parameters: Vec<FunctionParameter>,
variable_arguments: bool,
) -> Self {
- let mut owned_raw_return_type = Conf::<&Type>::into_raw(return_type.into());
+ let mut owned_raw_return_value = ReturnValue::into_rust_raw(return_value.into());
let mut variable_arguments = Conf::new(variable_arguments, MAX_CONFIDENCE).into();
let mut can_return = Conf::new(true, MIN_CONFIDENCE).into();
let mut pure = Conf::new(false, MIN_CONFIDENCE).into();
@@ -473,15 +473,9 @@ impl TypeBuilder {
let reg_stack_adjust_regs = std::ptr::null_mut();
let reg_stack_adjust_values = std::ptr::null_mut();
- let mut return_regs: BNRegisterSetWithConfidence = BNRegisterSetWithConfidence {
- regs: std::ptr::null_mut(),
- count: 0,
- confidence: 0,
- };
-
let result = unsafe {
Self::from_raw(BNCreateFunctionTypeBuilder(
- &mut owned_raw_return_type,
+ &mut owned_raw_return_value,
&mut raw_calling_convention,
raw_parameters.as_mut_ptr(),
raw_parameters.len(),
@@ -491,7 +485,6 @@ impl TypeBuilder {
reg_stack_adjust_regs,
reg_stack_adjust_values,
0,
- &mut return_regs,
BNNameType::NoNameType,
&mut pure,
))
@@ -509,16 +502,16 @@ impl TypeBuilder {
/// use [`Type::function_with_opts`] where possible.
pub fn function_with_opts<
'a,
- T: Into<Conf<&'a Type>>,
+ T: Into<ReturnValue>,
C: Into<Conf<Ref<CoreCallingConvention>>>,
>(
- return_type: T,
+ return_value: T,
parameters: &[FunctionParameter],
variable_arguments: bool,
calling_convention: C,
stack_adjust: Conf<i64>,
) -> Self {
- let mut owned_raw_return_type = Conf::<&Type>::into_raw(return_type.into());
+ let mut owned_raw_return_value = ReturnValue::into_rust_raw(return_value.into());
let mut variable_arguments = Conf::new(variable_arguments, MAX_CONFIDENCE).into();
let mut can_return = Conf::new(true, MIN_CONFIDENCE).into();
let mut pure = Conf::new(false, MIN_CONFIDENCE).into();
@@ -537,15 +530,9 @@ impl TypeBuilder {
let reg_stack_adjust_regs = std::ptr::null_mut();
let reg_stack_adjust_values = std::ptr::null_mut();
- let mut return_regs: BNRegisterSetWithConfidence = BNRegisterSetWithConfidence {
- regs: std::ptr::null_mut(),
- count: 0,
- confidence: 0,
- };
-
let result = unsafe {
Self::from_raw(BNCreateFunctionTypeBuilder(
- &mut owned_raw_return_type,
+ &mut owned_raw_return_value,
&mut owned_raw_calling_convention,
raw_parameters.as_mut_ptr(),
raw_parameters.len(),
@@ -555,7 +542,6 @@ impl TypeBuilder {
reg_stack_adjust_regs,
reg_stack_adjust_values,
0,
- &mut return_regs,
BNNameType::NoNameType,
&mut pure,
))
@@ -943,12 +929,12 @@ impl Type {
}
// TODO: FunctionBuilder
- pub fn function<'a, T: Into<Conf<&'a Type>>>(
- return_type: T,
+ pub fn function<'a, T: Into<ReturnValue>>(
+ return_value: T,
parameters: Vec<FunctionParameter>,
variable_arguments: bool,
) -> Ref<Self> {
- let mut owned_raw_return_type = Conf::<&Type>::into_raw(return_type.into());
+ let mut owned_raw_return_value = ReturnValue::into_rust_raw(return_value.into());
let mut variable_arguments = Conf::new(variable_arguments, MAX_CONFIDENCE).into();
let mut can_return = Conf::new(true, MIN_CONFIDENCE).into();
let mut pure = Conf::new(false, MIN_CONFIDENCE).into();
@@ -967,15 +953,9 @@ impl Type {
let reg_stack_adjust_regs = std::ptr::null_mut();
let reg_stack_adjust_values = std::ptr::null_mut();
- let mut return_regs: BNRegisterSetWithConfidence = BNRegisterSetWithConfidence {
- regs: std::ptr::null_mut(),
- count: 0,
- confidence: 0,
- };
-
let result = unsafe {
Self::ref_from_raw(BNCreateFunctionType(
- &mut owned_raw_return_type,
+ &mut owned_raw_return_value,
&mut raw_calling_convention,
raw_parameters.as_mut_ptr(),
raw_parameters.len(),
@@ -985,12 +965,12 @@ impl Type {
reg_stack_adjust_regs,
reg_stack_adjust_values,
0,
- &mut return_regs,
BNNameType::NoNameType,
&mut pure,
))
};
+ ReturnValue::free_rust_raw(owned_raw_return_value);
for raw_param in raw_parameters {
FunctionParameter::free_raw(raw_param);
}
@@ -1001,16 +981,16 @@ impl Type {
// TODO: FunctionBuilder
pub fn function_with_opts<
'a,
- T: Into<Conf<&'a Type>>,
+ T: Into<ReturnValue>,
C: Into<Conf<Ref<CoreCallingConvention>>>,
>(
- return_type: T,
+ return_value: T,
parameters: &[FunctionParameter],
variable_arguments: bool,
calling_convention: C,
stack_adjust: Conf<i64>,
) -> Ref<Self> {
- let mut owned_raw_return_type = Conf::<&Type>::into_raw(return_type.into());
+ let mut owned_raw_return_value = ReturnValue::into_rust_raw(return_value.into());
let mut variable_arguments = Conf::new(variable_arguments, MAX_CONFIDENCE).into();
let mut can_return = Conf::new(true, MIN_CONFIDENCE).into();
let mut pure = Conf::new(false, MIN_CONFIDENCE).into();
@@ -1029,15 +1009,9 @@ impl Type {
let reg_stack_adjust_regs = std::ptr::null_mut();
let reg_stack_adjust_values = std::ptr::null_mut();
- let mut return_regs: BNRegisterSetWithConfidence = BNRegisterSetWithConfidence {
- regs: std::ptr::null_mut(),
- count: 0,
- confidence: 0,
- };
-
let result = unsafe {
Self::ref_from_raw(BNCreateFunctionType(
- &mut owned_raw_return_type,
+ &mut owned_raw_return_value,
&mut owned_raw_calling_convention,
raw_parameters.as_mut_ptr(),
raw_parameters.len(),
@@ -1047,12 +1021,12 @@ impl Type {
reg_stack_adjust_regs,
reg_stack_adjust_values,
0,
- &mut return_regs,
BNNameType::NoNameType,
&mut pure,
))
};
+ ReturnValue::free_rust_raw(owned_raw_return_value);
for raw_param in raw_parameters {
FunctionParameter::free_raw(raw_param);
}
@@ -1110,6 +1084,10 @@ impl Type {
QualifiedName::free_raw(raw_name);
type_id
}
+
+ pub fn deref_named_type_reference(&self, view: &BinaryView) -> Ref<Type> {
+ unsafe { Self::ref_from_raw(BNDerefNamedTypeReference(view.handle, self.handle)) }
+ }
}
impl Display for Type {
@@ -1207,10 +1185,285 @@ unsafe impl CoreArrayProviderInner for Type {
}
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
+pub struct ValueLocationComponent {
+ pub variable: Variable,
+ pub offset: i64,
+ pub size: Option<u64>,
+}
+
+impl ValueLocationComponent {
+ pub(crate) fn from_raw(value: &BNValueLocationComponent) -> Self {
+ let variable = Variable::from(&value.variable);
+ let size = if value.sizeValid {
+ Some(value.size)
+ } else {
+ None
+ };
+ Self {
+ variable,
+ offset: value.offset,
+ size,
+ }
+ }
+
+ pub(crate) fn into_raw(value: &Self) -> BNValueLocationComponent {
+ BNValueLocationComponent {
+ variable: value.variable.into(),
+ offset: value.offset,
+ sizeValid: value.size.is_some(),
+ size: value.size.unwrap_or(0),
+ }
+ }
+}
+
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
+pub struct ValueLocation {
+ pub components: Vec<ValueLocationComponent>,
+ pub indirect: bool,
+ pub returned_pointer: Option<Variable>,
+}
+
+impl ValueLocation {
+ pub fn from_variable(var: Variable) -> Self {
+ Self {
+ components: vec![ValueLocationComponent {
+ variable: var,
+ offset: 0,
+ size: None,
+ }],
+ indirect: false,
+ returned_pointer: None,
+ }
+ }
+
+ pub fn from_register(reg: impl Register) -> Self {
+ Self::from_variable(Variable::from_register(reg))
+ }
+
+ pub fn from_register_id(reg: RegisterId) -> Self {
+ Self::from_variable(Variable::from_register_id(reg))
+ }
+
+ pub fn from_stack_offset(offset: i64) -> Self {
+ Self::from_variable(Variable::from_stack_offset(offset))
+ }
+
+ pub fn is_valid(&self) -> bool {
+ !self.components.is_empty()
+ }
+
+ pub fn variable_for_return_value(&self) -> Option<Variable> {
+ let value_raw = Self::into_rust_raw(&self);
+ let mut var_raw = BNVariable::default();
+ let valid = unsafe { BNGetValueLocationVariableForReturnValue(&value_raw, &mut var_raw) };
+ Self::free_rust_raw(value_raw);
+ if valid {
+ Some(var_raw.into())
+ } else {
+ None
+ }
+ }
+
+ pub fn variable_for_parameter(&self, idx: usize) -> Option<Variable> {
+ let value_raw = Self::into_rust_raw(&self);
+ let mut var_raw = BNVariable::default();
+ let valid =
+ unsafe { BNGetValueLocationVariableForParameter(&value_raw, &mut var_raw, idx) };
+ Self::free_rust_raw(value_raw);
+ if valid {
+ Some(var_raw.into())
+ } else {
+ None
+ }
+ }
+
+ pub(crate) fn from_raw(loc: &BNValueLocation) -> Self {
+ let components_raw: &[BNValueLocationComponent] =
+ unsafe { crate::ffi::slice_from_raw_parts(loc.components, loc.count) };
+ Self {
+ components: components_raw
+ .iter()
+ .map(|component| ValueLocationComponent::from_raw(component))
+ .collect(),
+ indirect: loc.indirect,
+ returned_pointer: if loc.returnedPointerValid {
+ Some(Variable::from(&loc.returnedPointer))
+ } else {
+ None
+ },
+ }
+ }
+
+ pub fn into_rust_raw(value: &Self) -> BNValueLocation {
+ let components: Box<[BNValueLocationComponent]> = value
+ .components
+ .iter()
+ .map(|component| ValueLocationComponent::into_raw(component))
+ .collect();
+ BNValueLocation {
+ count: components.len(),
+ components: Box::leak(components).as_mut_ptr(),
+ indirect: value.indirect,
+ returnedPointerValid: value.returned_pointer.is_some(),
+ returnedPointer: if let Some(ptr) = value.returned_pointer {
+ ptr.into()
+ } else {
+ Variable::new(VariableSourceType::RegisterVariableSourceType, 0, 0).into()
+ },
+ }
+ }
+
+ /// Free a RUST ALLOCATED possible value set. Do not use this with CORE ALLOCATED values.
+ pub fn free_rust_raw(value: BNValueLocation) {
+ let raw_components =
+ unsafe { std::slice::from_raw_parts_mut(value.components, value.count) };
+ let _ = unsafe { Box::from_raw(raw_components) };
+ }
+}
+
+impl Into<ValueLocation> for Variable {
+ fn into(self) -> ValueLocation {
+ ValueLocation {
+ components: vec![ValueLocationComponent {
+ variable: self,
+ offset: 0,
+ size: None,
+ }],
+ indirect: false,
+ returned_pointer: None,
+ }
+ }
+}
+
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
+pub struct ReturnValue {
+ pub ty: Conf<Ref<Type>>,
+ pub location: Option<Conf<ValueLocation>>,
+}
+
+impl ReturnValue {
+ pub(crate) fn from_raw(value: &BNReturnValue) -> Self {
+ Self {
+ ty: Conf::new(
+ unsafe { Type::from_raw(value.type_).to_owned() },
+ value.typeConfidence,
+ ),
+ location: match value.defaultLocation {
+ false => Some(Conf::new(
+ ValueLocation::from_raw(&value.location),
+ value.locationConfidence,
+ )),
+ true => None,
+ },
+ }
+ }
+
+ /// Take ownership over an "owned" **core allocated** value. Do not call this for a rust allocated value.
+ pub(crate) fn from_owned_core_raw(mut value: BNReturnValue) -> Self {
+ let owned = Self::from_raw(&value);
+ Self::free_core_raw(&mut value);
+ owned
+ }
+
+ pub(crate) fn into_rust_raw(value: Self) -> BNReturnValue {
+ BNReturnValue {
+ type_: unsafe { Ref::into_raw(value.ty.contents) }.handle,
+ typeConfidence: value.ty.confidence,
+ defaultLocation: value.location.is_none(),
+ location: ValueLocation::into_rust_raw(
+ value
+ .location
+ .as_ref()
+ .map(|v| &v.contents)
+ .unwrap_or(&ValueLocation {
+ components: Vec::new(),
+ indirect: false,
+ returned_pointer: None,
+ }),
+ ),
+ locationConfidence: value.location.as_ref().map(|v| v.confidence).unwrap_or(0),
+ }
+ }
+
+ /// Free a CORE ALLOCATED possible value set. Do not use this with [Self::into_rust_raw] values.
+ pub(crate) fn free_core_raw(value: &mut BNReturnValue) {
+ unsafe { BNFreeReturnValue(value) }
+ }
+
+ /// Free a RUST ALLOCATED possible value set. Do not use this with CORE ALLOCATED values.
+ pub(crate) fn free_rust_raw(value: BNReturnValue) {
+ let _ = unsafe { Type::ref_from_raw(value.type_) };
+ ValueLocation::free_rust_raw(value.location);
+ }
+}
+
+impl Into<ReturnValue> for Ref<Type> {
+ fn into(self) -> ReturnValue {
+ ReturnValue {
+ ty: self.into(),
+ location: None,
+ }
+ }
+}
+
+impl Into<ReturnValue> for &Ref<Type> {
+ fn into(self) -> ReturnValue {
+ ReturnValue {
+ ty: self.clone().into(),
+ location: None,
+ }
+ }
+}
+
+impl Into<ReturnValue> for &Type {
+ fn into(self) -> ReturnValue {
+ ReturnValue {
+ ty: self.to_owned().into(),
+ location: None,
+ }
+ }
+}
+
+impl Into<ReturnValue> for Conf<Ref<Type>> {
+ fn into(self) -> ReturnValue {
+ ReturnValue {
+ ty: self,
+ location: None,
+ }
+ }
+}
+
+impl Into<ReturnValue> for &Conf<Ref<Type>> {
+ fn into(self) -> ReturnValue {
+ ReturnValue {
+ ty: self.clone(),
+ location: None,
+ }
+ }
+}
+
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
+pub enum ValueLocationSource {
+ Default,
+ PassByValue,
+ PassByReference,
+ Custom(ValueLocation),
+}
+
+impl From<Option<ValueLocation>> for ValueLocationSource {
+ fn from(loc: Option<ValueLocation>) -> Self {
+ match loc {
+ Some(loc) => ValueLocationSource::Custom(loc),
+ None => ValueLocationSource::Default,
+ }
+ }
+}
+
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct FunctionParameter {
pub ty: Conf<Ref<Type>>,
pub name: String,
- pub location: Option<Variable>,
+ pub location: ValueLocationSource,
}
impl FunctionParameter {
@@ -1218,13 +1471,7 @@ impl FunctionParameter {
// TODO: I copied this from the original `from_raw` function.
// TODO: So this actually needs to be audited later.
let name = if value.name.is_null() {
- if value.location.type_ == VariableSourceType::RegisterVariableSourceType {
- format!("reg_{}", value.location.storage)
- } else if value.location.type_ == VariableSourceType::StackVariableSourceType {
- format!("arg_{}", value.location.storage)
- } else {
- String::new()
- }
+ String::new()
} else {
raw_to_string(value.name as *const _).unwrap()
};
@@ -1235,9 +1482,17 @@ impl FunctionParameter {
value.typeConfidence,
),
name,
- location: match value.defaultLocation {
- false => Some(Variable::from(value.location)),
- true => None,
+ location: match value.locationSource {
+ BNValueLocationSource::DefaultLocationSource => ValueLocationSource::Default,
+ BNValueLocationSource::PassByValueLocationSource => {
+ ValueLocationSource::PassByValue
+ }
+ BNValueLocationSource::PassByReferenceLocationSource => {
+ ValueLocationSource::PassByReference
+ }
+ BNValueLocationSource::CustomLocationSource => {
+ ValueLocationSource::Custom(ValueLocation::from_raw(&value.location))
+ }
},
}
}
@@ -1255,21 +1510,42 @@ impl FunctionParameter {
name: BnString::into_raw(bn_name),
type_: unsafe { Ref::into_raw(value.ty.contents) }.handle,
typeConfidence: value.ty.confidence,
- defaultLocation: value.location.is_none(),
- location: value.location.map(Into::into).unwrap_or_default(),
+ locationSource: match value.location {
+ ValueLocationSource::Default => BNValueLocationSource::DefaultLocationSource,
+ ValueLocationSource::PassByValue => {
+ BNValueLocationSource::PassByValueLocationSource
+ }
+ ValueLocationSource::PassByReference => {
+ BNValueLocationSource::PassByReferenceLocationSource
+ }
+ ValueLocationSource::Custom(_) => BNValueLocationSource::CustomLocationSource,
+ },
+ location: match &value.location {
+ ValueLocationSource::Custom(loc) => ValueLocation::into_rust_raw(loc),
+ _ => ValueLocation::into_rust_raw(&ValueLocation {
+ components: Vec::new(),
+ indirect: false,
+ returned_pointer: None,
+ }),
+ },
}
}
pub(crate) fn free_raw(value: BNFunctionParameter) {
unsafe { BnString::free_raw(value.name) };
let _ = unsafe { Type::ref_from_raw(value.type_) };
+ ValueLocation::free_rust_raw(value.location);
}
- pub fn new<T: Into<Conf<Ref<Type>>>>(ty: T, name: String, location: Option<Variable>) -> Self {
+ pub fn new<T: Into<Conf<Ref<Type>>>>(
+ ty: T,
+ name: String,
+ location: impl Into<ValueLocationSource>,
+ ) -> Self {
Self {
ty: ty.into(),
name,
- location,
+ location: location.into(),
}
}
}
diff --git a/rust/src/variable.rs b/rust/src/variable.rs
index f9384b5d..1eefc9a8 100644
--- a/rust/src/variable.rs
+++ b/rust/src/variable.rs
@@ -1,6 +1,6 @@
#![allow(unused)]
-use crate::architecture::{Architecture, CoreArchitecture, CoreRegister, RegisterId};
+use crate::architecture::{Architecture, CoreArchitecture, CoreRegister, Register, RegisterId};
use crate::confidence::Conf;
use crate::function::{Function, Location};
use crate::rc::{CoreArrayProvider, CoreArrayProviderInner, Ref};
@@ -405,6 +405,30 @@ impl Variable {
unsafe { BNFromVariableIdentifier(ident) }.into()
}
+ pub fn from_register(reg: impl Register) -> Self {
+ Self {
+ ty: VariableSourceType::RegisterVariableSourceType,
+ index: 0,
+ storage: reg.id().0 as i64,
+ }
+ }
+
+ pub fn from_register_id(reg: RegisterId) -> Self {
+ Self {
+ ty: VariableSourceType::RegisterVariableSourceType,
+ index: 0,
+ storage: reg.0 as i64,
+ }
+ }
+
+ pub fn from_stack_offset(offset: i64) -> Self {
+ Self {
+ ty: VariableSourceType::StackVariableSourceType,
+ index: 0,
+ storage: offset,
+ }
+ }
+
pub fn to_identifier(&self) -> u64 {
let raw = BNVariable::from(*self);
unsafe { BNToVariableIdentifier(&raw) }
@@ -417,6 +441,8 @@ impl Variable {
}
VariableSourceType::StackVariableSourceType => None,
VariableSourceType::FlagVariableSourceType => None,
+ VariableSourceType::CompositeReturnValueSourceType => None,
+ VariableSourceType::CompositeParameterSourceType => None,
}
}
}
@@ -674,6 +700,13 @@ pub enum PossibleValueSet {
StackFrameOffset {
value: i64,
},
+ ResultPointer {
+ offset: i64,
+ },
+ ParameterPointer {
+ index: u64,
+ offset: i64,
+ },
ReturnAddressValue,
ImportedAddressValue {
value: i64,
@@ -730,6 +763,13 @@ impl PossibleValueSet {
offset: value.offset,
},
RegisterValueType::StackFrameOffset => Self::StackFrameOffset { value: value.value },
+ RegisterValueType::ResultPointerValue => Self::ResultPointer {
+ offset: value.value,
+ },
+ RegisterValueType::ParameterPointerValue => Self::ParameterPointer {
+ index: value.value as u64,
+ offset: value.offset,
+ },
RegisterValueType::ReturnAddressValue => Self::ReturnAddressValue,
RegisterValueType::ImportedAddressValue => {
Self::ImportedAddressValue { value: value.value }
@@ -815,6 +855,13 @@ impl PossibleValueSet {
PossibleValueSet::StackFrameOffset { value } => {
raw.value = value;
}
+ PossibleValueSet::ResultPointer { offset } => {
+ raw.value = offset;
+ }
+ PossibleValueSet::ParameterPointer { index, offset } => {
+ raw.value = index as i64;
+ raw.offset = offset;
+ }
PossibleValueSet::ReturnAddressValue => {}
PossibleValueSet::ImportedAddressValue { value } => {
raw.value = value;
@@ -910,6 +957,8 @@ impl PossibleValueSet {
RegisterValueType::ExternalPointerValue
}
PossibleValueSet::StackFrameOffset { .. } => RegisterValueType::StackFrameOffset,
+ PossibleValueSet::ResultPointer { .. } => RegisterValueType::ResultPointerValue,
+ PossibleValueSet::ParameterPointer { .. } => RegisterValueType::ParameterPointerValue,
PossibleValueSet::ReturnAddressValue => RegisterValueType::ReturnAddressValue,
PossibleValueSet::ImportedAddressValue { .. } => {
RegisterValueType::ImportedAddressValue
diff --git a/type.cpp b/type.cpp
index 3ae1ed21..ff4f8eb0 100644
--- a/type.cpp
+++ b/type.cpp
@@ -534,6 +534,272 @@ BaseStructure::BaseStructure(Type* _type, uint64_t _offset)
}
+ValueLocationComponent ValueLocationComponent::RemapVariables(const std::function<Variable(Variable)>& remap) const
+{
+ return {remap(variable), offset, size};
+}
+
+
+bool ValueLocationComponent::operator==(const ValueLocationComponent& component) const
+{
+ return variable == component.variable && offset == component.offset && size == component.size;
+}
+
+
+bool ValueLocationComponent::operator!=(const ValueLocationComponent& component) const
+{
+ return !(*this == component);
+}
+
+
+ValueLocationComponent ValueLocationComponent::FromAPIObject(const BNValueLocationComponent* loc)
+{
+ return {Variable(loc->variable.type, loc->variable.index, loc->variable.storage), loc->offset,
+ loc->sizeValid ? std::optional<uint64_t>(loc->size) : std::nullopt};
+}
+
+
+BNValueLocationComponent ValueLocationComponent::ToAPIObject() const
+{
+ BNValueLocationComponent result;
+ result.variable.type = variable.type;
+ result.variable.index = variable.index;
+ result.variable.storage = variable.storage;
+ result.offset = offset;
+ result.sizeValid = size.has_value();
+ result.size = size.value_or(0);
+ return result;
+}
+
+
+std::string ValueLocationComponent::ToString(Architecture* arch) const
+{
+ auto componentRaw = ToAPIObject();
+ char* str = BNValueLocationComponentToString(&componentRaw, arch->GetObject());
+ string result = str;
+ BNFreeString(str);
+ return result;
+}
+
+
+std::optional<Variable> ValueLocation::GetVariableForReturnValue() const
+{
+ BNValueLocation loc = ToAPIObject();
+ BNVariable var;
+ bool valid = BNGetValueLocationVariableForReturnValue(&loc, &var);
+ FreeAPIObject(&loc);
+ if (valid)
+ return var;
+ return std::nullopt;
+}
+
+
+std::optional<Variable> ValueLocation::GetVariableForParameter(size_t idx) const
+{
+ BNValueLocation loc = ToAPIObject();
+ BNVariable var;
+ bool valid = BNGetValueLocationVariableForParameter(&loc, &var, idx);
+ FreeAPIObject(&loc);
+ if (valid)
+ return var;
+ return std::nullopt;
+}
+
+
+ValueLocation ValueLocation::RemapVariables(const std::function<Variable(Variable)>& remap) const
+{
+ vector<ValueLocationComponent> result;
+ result.reserve(components.size());
+ for (auto& i : components)
+ result.push_back(i.RemapVariables(remap));
+ if (returnedPointer.has_value())
+ return {result, indirect, remap(returnedPointer.value())};
+ return {result, indirect};
+}
+
+
+void ValueLocation::ForEachVariable(const std::function<void(Variable var, bool indirect)>& func) const
+{
+ for (auto& i : components)
+ func(i.variable, indirect);
+}
+
+
+bool ValueLocation::ContainsVariable(Variable var) const
+{
+ for (auto& i : components)
+ if (i.variable == var)
+ return true;
+ return false;
+}
+
+
+bool ValueLocation::operator==(const ValueLocation& loc) const
+{
+ return components == loc.components && indirect == loc.indirect
+ && (!indirect || returnedPointer == loc.returnedPointer);
+}
+
+
+bool ValueLocation::operator!=(const ValueLocation& loc) const
+{
+ return !(*this == loc);
+}
+
+
+ValueLocation ValueLocation::FromAPIObject(const BNValueLocation* loc)
+{
+ ValueLocation result;
+ result.components.reserve(loc->count);
+ for (size_t i = 0; i < loc->count; i++)
+ result.components.push_back(ValueLocationComponent::FromAPIObject(&loc->components[i]));
+ result.indirect = loc->indirect;
+ if (loc->returnedPointerValid)
+ {
+ result.returnedPointer =
+ Variable(loc->returnedPointer.type, loc->returnedPointer.index, loc->returnedPointer.storage);
+ }
+ return result;
+}
+
+
+BNValueLocation ValueLocation::ToAPIObject() const
+{
+ BNValueLocation result;
+ result.count = components.size();
+ result.components = new BNValueLocationComponent[components.size()];
+ for (size_t i = 0; i < components.size(); i++)
+ result.components[i] = components[i].ToAPIObject();
+ result.indirect = indirect;
+ result.returnedPointerValid = returnedPointer.has_value();
+ if (returnedPointer.has_value())
+ {
+ result.returnedPointer.type = returnedPointer->type;
+ result.returnedPointer.index = returnedPointer->index;
+ result.returnedPointer.storage = returnedPointer->storage;
+ }
+ else
+ {
+ result.returnedPointer.type = RegisterVariableSourceType;
+ result.returnedPointer.index = 0;
+ result.returnedPointer.storage = 0;
+ }
+ return result;
+}
+
+
+void ValueLocation::FreeAPIObject(BNValueLocation* loc)
+{
+ delete[] loc->components;
+}
+
+
+std::optional<ValueLocation> ValueLocation::Parse(const std::string& str, Architecture* arch, std::string& error)
+{
+ BNValueLocation locationRaw;
+ char* errorRaw;
+ if (BNParseValueLocation(str.c_str(), arch->GetObject(), &locationRaw, &errorRaw))
+ {
+ auto location = FromAPIObject(&locationRaw);
+ BNFreeValueLocation(&locationRaw);
+ return location;
+ }
+
+ error = errorRaw;
+ BNFreeString(errorRaw);
+ return std::nullopt;
+}
+
+
+std::string ValueLocation::ToString(Architecture* arch) const
+{
+ auto locationRaw = ToAPIObject();
+ char* str = BNValueLocationToString(&locationRaw, arch->GetObject());
+ FreeAPIObject(&locationRaw);
+ string result = str;
+ BNFreeString(str);
+ return result;
+}
+
+
+bool ReturnValue::operator==(const ReturnValue& nt) const
+{
+ if (type != nt.type)
+ return false;
+ if (defaultLocation != nt.defaultLocation)
+ return false;
+ if (defaultLocation)
+ return true;
+ return location == nt.location;
+}
+
+
+bool ReturnValue::operator!=(const ReturnValue& nt) const
+{
+ return !((*this) == nt);
+}
+
+
+ReturnValue ReturnValue::FromAPIObject(const BNReturnValue* returnValue)
+{
+ ReturnValue result;
+ result.type = Confidence<Ref<Type>>(
+ returnValue->type ? new Type(BNNewTypeReference(returnValue->type)) : nullptr, returnValue->typeConfidence);
+ result.defaultLocation = returnValue->defaultLocation;
+ result.location = Confidence<ValueLocation>(
+ ValueLocation::FromAPIObject(&returnValue->location), returnValue->locationConfidence);
+ return result;
+}
+
+
+BNReturnValue ReturnValue::ToAPIObject() const
+{
+ BNReturnValue result;
+ result.type = type.GetValue() ? type.GetValue()->GetObject() : nullptr;
+ result.typeConfidence = type.GetConfidence();
+ result.defaultLocation = defaultLocation;
+ result.location = location->ToAPIObject();
+ result.locationConfidence = location.GetConfidence();
+ return result;
+}
+
+
+void ReturnValue::FreeAPIObject(BNReturnValue* returnValue)
+{
+ ValueLocation::FreeAPIObject(&returnValue->location);
+}
+
+
+FunctionParameter FunctionParameter::FromAPIObject(const BNFunctionParameter* param)
+{
+ FunctionParameter result;
+ result.name = param->name;
+ result.type =
+ Confidence<Ref<Type>>(param->type ? new Type(BNNewTypeReference(param->type)) : nullptr, param->typeConfidence);
+ result.locationSource = param->locationSource;
+ result.location = ValueLocation::FromAPIObject(&param->location);
+ return result;
+}
+
+
+BNFunctionParameter FunctionParameter::ToAPIObject() const
+{
+ BNFunctionParameter result;
+ result.name = (char*)name.c_str();
+ result.type = type->GetObject();
+ result.typeConfidence = type.GetConfidence();
+ result.locationSource = locationSource;
+ result.location = location.ToAPIObject();
+ return result;
+}
+
+
+void FunctionParameter::FreeAPIObject(BNFunctionParameter* param)
+{
+ ValueLocation::FreeAPIObject(&param->location);
+}
+
+
Type::Type(BNType* type)
{
m_object = type;
@@ -599,6 +865,30 @@ Confidence<Ref<Type>> Type::GetChildType() const
}
+ReturnValue Type::GetReturnValue() const
+{
+ BNReturnValue ret = BNGetTypeReturnValue(m_object);
+ ReturnValue result = ReturnValue::FromAPIObject(&ret);
+ BNFreeReturnValue(&ret);
+ return result;
+}
+
+
+bool Type::IsReturnValueDefaultLocation() const
+{
+ return BNIsTypeReturnValueDefaultLocation(m_object);
+}
+
+
+Confidence<ValueLocation> Type::GetReturnValueLocation() const
+{
+ BNValueLocationWithConfidence location = BNGetTypeReturnValueLocation(m_object);
+ Confidence<ValueLocation> result(ValueLocation::FromAPIObject(&location.location), location.confidence);
+ BNFreeValueLocation(&location.location);
+ return result;
+}
+
+
Confidence<Ref<CallingConvention>> Type::GetCallingConvention() const
{
BNCallingConventionWithConfidence cc = BNGetTypeCallingConvention(m_object);
@@ -622,16 +912,7 @@ vector<FunctionParameter> Type::GetParameters() const
vector<FunctionParameter> result;
result.reserve(count);
for (size_t i = 0; i < count; i++)
- {
- FunctionParameter param;
- param.name = types[i].name;
- param.type = Confidence<Ref<Type>>(new Type(BNNewTypeReference(types[i].type)), types[i].typeConfidence);
- param.defaultLocation = types[i].defaultLocation;
- param.location.type = types[i].location.type;
- param.location.index = types[i].location.index;
- param.location.storage = types[i].location.storage;
- result.push_back(param);
- }
+ result.push_back(FunctionParameter::FromAPIObject(&types[i]));
BNFreeTypeParameterList(types, count);
return result;
@@ -1067,13 +1348,11 @@ Ref<Type> Type::ArrayType(const Confidence<Ref<Type>>& type, uint64_t elem)
}
-Ref<Type> Type::FunctionType(const Confidence<Ref<Type>>& returnValue,
- const Confidence<Ref<CallingConvention>>& callingConvention, const std::vector<FunctionParameter>& params,
- const Confidence<bool>& varArg, const Confidence<int64_t>& stackAdjust)
+Ref<Type> Type::FunctionType(const ReturnValue& returnValue,
+ const Confidence<Ref<CallingConvention>>& callingConvention, const std::vector<FunctionParameter>& params,
+ const Confidence<bool>& varArg, const Confidence<int64_t>& stackAdjust)
{
- BNTypeWithConfidence returnValueConf;
- returnValueConf.type = returnValue->GetObject();
- returnValueConf.confidence = returnValue.GetConfidence();
+ BNReturnValue ret = returnValue.ToAPIObject();
BNCallingConventionWithConfidence callingConventionConf;
callingConventionConf.convention = callingConvention.GetValue() ? callingConvention->GetObject() : nullptr;
@@ -1081,15 +1360,7 @@ Ref<Type> Type::FunctionType(const Confidence<Ref<Type>>& returnValue,
BNFunctionParameter* paramArray = new BNFunctionParameter[params.size()];
for (size_t i = 0; i < params.size(); i++)
- {
- paramArray[i].name = (char*)params[i].name.c_str();
- paramArray[i].type = params[i].type->GetObject();
- paramArray[i].typeConfidence = params[i].type.GetConfidence();
- paramArray[i].defaultLocation = params[i].defaultLocation;
- paramArray[i].location.type = params[i].location.type;
- paramArray[i].location.index = params[i].location.index;
- paramArray[i].location.storage = params[i].location.storage;
- }
+ paramArray[i] = params[i].ToAPIObject();
BNBoolWithConfidence varArgConf;
varArgConf.value = varArg.GetValue();
@@ -1103,37 +1374,33 @@ Ref<Type> Type::FunctionType(const Confidence<Ref<Type>>& returnValue,
stackAdjustConf.value = stackAdjust.GetValue();
stackAdjustConf.confidence = stackAdjust.GetConfidence();
- BNRegisterSetWithConfidence returnRegsConf;
- returnRegsConf.regs = nullptr;
- returnRegsConf.count = 0;
- returnRegsConf.confidence = 0;
-
BNBoolWithConfidence pureConf;
pureConf.value = false;
pureConf.confidence = 0;
Type* type = new Type(BNCreateFunctionType(
- &returnValueConf, &callingConventionConf, paramArray, params.size(), &varArgConf,
- &canReturnConf, &stackAdjustConf, nullptr, nullptr, 0, &returnRegsConf, NoNameType, &pureConf));
+ &ret, &callingConventionConf, paramArray, params.size(), &varArgConf,
+ &canReturnConf, &stackAdjustConf, nullptr, nullptr, 0, NoNameType, &pureConf));
+
+ ReturnValue::FreeAPIObject(&ret);
+ for (size_t i = 0; i < params.size(); i++)
+ FunctionParameter::FreeAPIObject(&paramArray[i]);
delete[] paramArray;
return type;
}
-Ref<Type> Type::FunctionType(const Confidence<Ref<Type>>& returnValue,
+Ref<Type> Type::FunctionType(const ReturnValue& returnValue,
const Confidence<Ref<CallingConvention>>& callingConvention,
const std::vector<FunctionParameter>& params,
const Confidence<bool>& hasVariableArguments,
const Confidence<bool>& canReturn,
const Confidence<int64_t>& stackAdjust,
const std::map<uint32_t, Confidence<int32_t>>& regStackAdjust,
- const Confidence<std::vector<uint32_t>>& returnRegs,
BNNameType ft,
const Confidence<bool>& pure)
{
- BNTypeWithConfidence returnValueConf;
- returnValueConf.type = returnValue->GetObject();
- returnValueConf.confidence = returnValue.GetConfidence();
+ BNReturnValue ret = returnValue.ToAPIObject();
BNCallingConventionWithConfidence callingConventionConf;
callingConventionConf.convention = callingConvention.GetValue() ? callingConvention->GetObject() : nullptr;
@@ -1141,15 +1408,7 @@ Ref<Type> Type::FunctionType(const Confidence<Ref<Type>>& returnValue,
BNFunctionParameter* paramArray = new BNFunctionParameter[params.size()];
for (size_t i = 0; i < params.size(); i++)
- {
- paramArray[i].name = (char*)params[i].name.c_str();
- paramArray[i].type = params[i].type->GetObject();
- paramArray[i].typeConfidence = params[i].type.GetConfidence();
- paramArray[i].defaultLocation = params[i].defaultLocation;
- paramArray[i].location.type = params[i].location.type;
- paramArray[i].location.index = params[i].location.index;
- paramArray[i].location.storage = params[i].location.storage;
- }
+ paramArray[i] = params[i].ToAPIObject();
BNBoolWithConfidence varArgConf;
varArgConf.value = hasVariableArguments.GetValue();
@@ -1174,21 +1433,18 @@ Ref<Type> Type::FunctionType(const Confidence<Ref<Type>>& returnValue,
i ++;
}
- std::vector<uint32_t> returnRegsRegs = returnRegs.GetValue();
-
- BNRegisterSetWithConfidence returnRegsConf;
- returnRegsConf.regs = returnRegsRegs.data();
- returnRegsConf.count = returnRegs->size();
- returnRegsConf.confidence = returnRegs.GetConfidence();
-
BNBoolWithConfidence pureConf;
pureConf.value = pure.GetValue();
pureConf.confidence = pure.GetConfidence();
Type* type = new Type(BNCreateFunctionType(
- &returnValueConf, &callingConventionConf, paramArray, params.size(), &varArgConf,
+ &ret, &callingConventionConf, paramArray, params.size(), &varArgConf,
&canReturnConf, &stackAdjustConf, regStackAdjustRegs.data(),
- regStackAdjustValues.data(), regStackAdjust.size(), &returnRegsConf, NoNameType, &pureConf));
+ regStackAdjustValues.data(), regStackAdjust.size(), NoNameType, &pureConf));
+
+ ReturnValue::FreeAPIObject(&ret);
+ for (i = 0; i < params.size(); i++)
+ FunctionParameter::FreeAPIObject(&paramArray[i]);
delete[] paramArray;
return type;
}
@@ -1666,6 +1922,30 @@ Confidence<Ref<Type>> TypeBuilder::GetChildType() const
}
+ReturnValue TypeBuilder::GetReturnValue() const
+{
+ BNReturnValue ret = BNGetTypeBuilderReturnValue(m_object);
+ ReturnValue result = ReturnValue::FromAPIObject(&ret);
+ BNFreeReturnValue(&ret);
+ return result;
+}
+
+
+bool TypeBuilder::IsReturnValueDefaultLocation() const
+{
+ return BNIsTypeBuilderReturnValueDefaultLocation(m_object);
+}
+
+
+Confidence<ValueLocation> TypeBuilder::GetReturnValueLocation() const
+{
+ BNValueLocationWithConfidence location = BNGetTypeBuilderReturnValueLocation(m_object);
+ Confidence<ValueLocation> result(ValueLocation::FromAPIObject(&location.location), location.confidence);
+ BNFreeValueLocation(&location.location);
+ return result;
+}
+
+
TypeBuilder& TypeBuilder::SetChildType(const Confidence<Ref<Type>>& child)
{
BNTypeWithConfidence childType;
@@ -1676,6 +1956,32 @@ TypeBuilder& TypeBuilder::SetChildType(const Confidence<Ref<Type>>& child)
}
+TypeBuilder& TypeBuilder::SetReturnValue(const ReturnValue& rv)
+{
+ BNReturnValue ret = rv.ToAPIObject();
+ BNTypeBuilderSetReturnValue(m_object, &ret);
+ ReturnValue::FreeAPIObject(&ret);
+ return *this;
+}
+
+
+TypeBuilder& TypeBuilder::SetIsReturnValueDefaultLocation(bool defaultLocation)
+{
+ BNTypeBuilderSetIsReturnValueDefaultLocation(m_object, defaultLocation);
+ return *this;
+}
+
+
+TypeBuilder& TypeBuilder::SetReturnValueLocation(const Confidence<ValueLocation>& location)
+{
+ BNValueLocationWithConfidence loc;
+ loc.location = location->ToAPIObject();
+ loc.confidence = location.GetConfidence();
+ BNTypeBuilderSetReturnValueLocation(m_object, &loc);
+ return *this;
+}
+
+
TypeBuilder& TypeBuilder::SetCallingConvention(const Confidence<Ref<CallingConvention>>& cc)
{
BNCallingConventionWithConfidence ccwc;
@@ -1716,16 +2022,7 @@ vector<FunctionParameter> TypeBuilder::GetParameters() const
vector<FunctionParameter> result;
result.reserve(count);
for (size_t i = 0; i < count; i++)
- {
- FunctionParameter param;
- param.name = types[i].name;
- param.type = Confidence<Ref<Type>>(new Type(BNNewTypeReference(types[i].type)), types[i].typeConfidence);
- param.defaultLocation = types[i].defaultLocation;
- param.location.type = types[i].location.type;
- param.location.index = types[i].location.index;
- param.location.storage = types[i].location.storage;
- result.push_back(param);
- }
+ result.push_back(FunctionParameter::FromAPIObject(&types[i]));
BNFreeTypeParameterList(types, count);
return result;
@@ -2099,26 +2396,25 @@ static BNFunctionParameter* GetParamArray(const std::vector<FunctionParameter>&
{
BNFunctionParameter* paramArray = new BNFunctionParameter[params.size()];
for (size_t i = 0; i < params.size(); i++)
- {
- paramArray[i].name = (char*)params[i].name.c_str();
- paramArray[i].type = params[i].type->GetObject();
- paramArray[i].typeConfidence = params[i].type.GetConfidence();
- paramArray[i].defaultLocation = params[i].defaultLocation;
- paramArray[i].location.type = params[i].location.type;
- paramArray[i].location.index = params[i].location.index;
- paramArray[i].location.storage = params[i].location.storage;
- }
+ paramArray[i] = params[i].ToAPIObject();
count = params.size();
return paramArray;
}
-TypeBuilder TypeBuilder::FunctionType(const Confidence<Ref<Type>>& returnValue,
+
+static void FreeParamArray(BNFunctionParameter* params, size_t count)
+{
+ for (size_t i = 0; i < count; i++)
+ FunctionParameter::FreeAPIObject(&params[i]);
+ delete[] params;
+}
+
+
+TypeBuilder TypeBuilder::FunctionType(const ReturnValue& returnValue,
const Confidence<Ref<CallingConvention>>& callingConvention, const std::vector<FunctionParameter>& params,
const Confidence<bool>& varArg, const Confidence<int64_t>& stackAdjust)
{
- BNTypeWithConfidence returnValueConf;
- returnValueConf.type = returnValue->GetObject();
- returnValueConf.confidence = returnValue.GetConfidence();
+ BNReturnValue ret = returnValue.ToAPIObject();
BNCallingConventionWithConfidence callingConventionConf;
callingConventionConf.convention = callingConvention.GetValue() ? callingConvention->GetObject() : nullptr;
@@ -2139,53 +2435,36 @@ TypeBuilder TypeBuilder::FunctionType(const Confidence<Ref<Type>>& returnValue,
canReturnConf.value = true;
canReturnConf.confidence = 0;
- BNRegisterSetWithConfidence returnRegsConf;
- returnRegsConf.regs = nullptr;
- returnRegsConf.count = 0;
- returnRegsConf.confidence = 0;
-
BNBoolWithConfidence pureConf;
pureConf.value = false;
pureConf.confidence = 0;
- TypeBuilder type(BNCreateFunctionTypeBuilder(
- &returnValueConf, &callingConventionConf, paramArray, paramCount, &varArgConf,
- &canReturnConf, &stackAdjustConf, nullptr, nullptr, 0, &returnRegsConf, NoNameType, &pureConf));
- delete[] paramArray;
+ TypeBuilder type(BNCreateFunctionTypeBuilder(&ret, &callingConventionConf, paramArray, paramCount, &varArgConf,
+ &canReturnConf, &stackAdjustConf, nullptr, nullptr, 0, NoNameType, &pureConf));
+ ReturnValue::FreeAPIObject(&ret);
+ FreeParamArray(paramArray, paramCount);
return type;
}
-TypeBuilder TypeBuilder::FunctionType(const Confidence<Ref<Type>>& returnValue,
+TypeBuilder TypeBuilder::FunctionType(const ReturnValue& returnValue,
const Confidence<Ref<CallingConvention>>& callingConvention,
const std::vector<FunctionParameter>& params,
const Confidence<bool>& hasVariableArguments,
const Confidence<bool>& canReturn,
const Confidence<int64_t>& stackAdjust,
const std::map<uint32_t, Confidence<int32_t>>& regStackAdjust,
- const Confidence<std::vector<uint32_t>>& returnRegs,
BNNameType ft,
const Confidence<bool>& pure)
{
- BNTypeWithConfidence returnValueConf;
- returnValueConf.type = returnValue->GetObject();
- returnValueConf.confidence = returnValue.GetConfidence();
+ BNReturnValue ret = returnValue.ToAPIObject();
BNCallingConventionWithConfidence callingConventionConf;
callingConventionConf.convention = callingConvention.GetValue() ? callingConvention->GetObject() : nullptr;
callingConventionConf.confidence = callingConvention.GetConfidence();
- BNFunctionParameter* paramArray = new BNFunctionParameter[params.size()];
- for (size_t i = 0; i < params.size(); i++)
- {
- paramArray[i].name = (char*)params[i].name.c_str();
- paramArray[i].type = params[i].type->GetObject();
- paramArray[i].typeConfidence = params[i].type.GetConfidence();
- paramArray[i].defaultLocation = params[i].defaultLocation;
- paramArray[i].location.type = params[i].location.type;
- paramArray[i].location.index = params[i].location.index;
- paramArray[i].location.storage = params[i].location.storage;
- }
+ size_t paramCount = 0;
+ BNFunctionParameter* paramArray = GetParamArray(params, paramCount);
BNBoolWithConfidence varArgConf;
varArgConf.value = hasVariableArguments.GetValue();
@@ -2210,22 +2489,16 @@ TypeBuilder TypeBuilder::FunctionType(const Confidence<Ref<Type>>& returnValue,
i ++;
}
- std::vector<uint32_t> returnRegsRegs = returnRegs.GetValue();
-
- BNRegisterSetWithConfidence returnRegsConf;
- returnRegsConf.regs = returnRegsRegs.data();
- returnRegsConf.count = returnRegs->size();
- returnRegsConf.confidence = returnRegs.GetConfidence();
-
BNBoolWithConfidence pureConf;
pureConf.value = pure.GetValue();
pureConf.confidence = pure.GetConfidence();
TypeBuilder type(BNCreateFunctionTypeBuilder(
- &returnValueConf, &callingConventionConf, paramArray, params.size(), &varArgConf,
+ &ret, &callingConventionConf, paramArray, paramCount, &varArgConf,
&canReturnConf, &stackAdjustConf, regStackAdjustRegs.data(),
- regStackAdjustValues.data(), regStackAdjust.size(), &returnRegsConf, NoNameType, &pureConf));
- delete[] paramArray;
+ regStackAdjustValues.data(), regStackAdjust.size(), NoNameType, &pureConf));
+ ReturnValue::FreeAPIObject(&ret);
+ FreeParamArray(paramArray, paramCount);
return type;
}
diff --git a/view/kernelcache/core/Utility.cpp b/view/kernelcache/core/Utility.cpp
index d2788faf..920d13e8 100644
--- a/view/kernelcache/core/Utility.cpp
+++ b/view/kernelcache/core/Utility.cpp
@@ -104,7 +104,7 @@ void ApplySymbol(Ref<BinaryView> view, Ref<TypeLibrary> typeLib, Ref<Symbol> sym
if (auto idType = view->GetTypeByName({"id"}))
{
- callTypeParams.emplace_back("obj", idType, true, Variable());
+ callTypeParams.emplace_back("obj", idType, DefaultLocationSource, Variable());
auto funcType = Type::FunctionType(idType, cc, callTypeParams);
func->SetUserType(funcType);
}
diff --git a/view/sharedcache/core/Utility.cpp b/view/sharedcache/core/Utility.cpp
index 591bcba5..9ae2c3b4 100644
--- a/view/sharedcache/core/Utility.cpp
+++ b/view/sharedcache/core/Utility.cpp
@@ -123,7 +123,7 @@ void ApplySymbol(Ref<BinaryView> view, Ref<TypeLibrary> typeLib, Ref<Symbol> sym
if (auto idType = view->GetTypeByName({"id"}))
{
- callTypeParams.emplace_back("obj", idType, true, Variable());
+ callTypeParams.emplace_back("obj", idType, DefaultLocationSource, Variable());
auto funcType = Type::FunctionType(idType, cc, callTypeParams);
func->SetUserType(funcType);
}