From 8d621c51b2797fda7b1dc22243dde611cfc04f68 Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Tue, 23 Dec 2025 13:12:02 -0700 Subject: Refactor calling conventions to support correct representation of structures --- binaryninjaapi.h | 275 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 253 insertions(+), 22 deletions(-) (limited to 'binaryninjaapi.h') 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& value); std::optional> StringifyUnicodeData(Architecture* arch, const DataBuffer& buffer, bool nullTerminates = true, bool allowShortStrings = false); + + std::vector DerefParameterNamedTypeRefs(const std::vector& 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 size; + + ValueLocationComponent() = default; + ValueLocationComponent(Variable var, int64_t ofs = 0, std::optional sz = std::nullopt) : + variable(var), offset(ofs), size(sz) + {} + + ValueLocationComponent RemapVariables(const std::function& 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 components; + bool indirect = false; + std::optional returnedPointer; + + ValueLocation() {} + ValueLocation(Variable var, bool indir = false, std::optional retPtr = std::nullopt) : + components {var}, indirect(indir), returnedPointer(retPtr) + {} + ValueLocation(const std::vector& components, bool indir = false, + std::optional retPtr = std::nullopt) : + components(components), indirect(indir), returnedPointer(retPtr) + {} + ValueLocation(std::vector&& components, bool indir = false, + std::optional retPtr = std::nullopt) : + components(std::move(components)), indirect(indir), returnedPointer(retPtr) + {} + + std::optional GetVariableForReturnValue() const; + std::optional GetVariableForParameter(size_t idx) const; + ValueLocation RemapVariables(const std::function& remap) const; + void ForEachVariable(const std::function& 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 Parse(const std::string& str, Architecture* arch, std::string& error); + std::string ToString(Architecture* arch) const; + }; + struct FunctionParameter { std::string name; Confidence> type; - bool defaultLocation; - Variable location; + BNValueLocationSource locationSource; + ValueLocation location; FunctionParameter() = default; - FunctionParameter(const std::string& name, Confidence> type): name(name), type(type), defaultLocation(true) + FunctionParameter(const std::string& name, Confidence> type): name(name), type(type), locationSource(DefaultLocationSource) {} - FunctionParameter(const std::string& name, const Confidence>& type, bool defaultLocation, - const Variable& location): - name(name), type(type), defaultLocation(defaultLocation), location(location) + FunctionParameter(const std::string& name, const Confidence>& 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> type; + bool defaultLocation = true; + Confidence location; + + ReturnValue(Type* ty) : type(ty) {} + ReturnValue(Ref ty) : type(ty) {} + ReturnValue(const Confidence>& ty) : type(ty) {} + ReturnValue(const Confidence>& ty, bool defaultLoc, const Confidence& 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 @@ -10763,6 +10856,22 @@ namespace BinaryNinja { */ Confidence> 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 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 FunctionType(const Confidence>& returnValue, + static Ref FunctionType(const ReturnValue& returnValue, const Confidence>& callingConvention, const std::vector& params, const Confidence& varArg = Confidence(false, 0), const Confidence& stackAdjust = Confidence(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 FunctionType(const Confidence>& returnValue, + static Ref FunctionType(const ReturnValue& returnValue, const Confidence>& callingConvention, const std::vector& params, const Confidence& hasVariableArguments, const Confidence& canReturn, const Confidence& stackAdjust, const std::map>& regStackAdjust = std::map>(), - const Confidence>& returnRegs = Confidence>(std::vector(), 0), BNNameType ft = NoNameType, const Confidence& pure = Confidence(false, 0)); static Ref VarArgsType(); @@ -11253,6 +11360,9 @@ namespace BinaryNinja { void SetIntegerTypeDisplayType(BNIntegerDisplayType displayType); Confidence> GetChildType() const; + ReturnValue GetReturnValue() const; + bool IsReturnValueDefaultLocation() const; + Confidence GetReturnValueLocation() const; Confidence> GetCallingConvention() const; BNCallingConventionName GetCallingConventionName() const; std::vector GetParameters() const; @@ -11272,6 +11382,9 @@ namespace BinaryNinja { TypeBuilder& SetConst(const Confidence& cnst); TypeBuilder& SetVolatile(const Confidence& vltl); TypeBuilder& SetChildType(const Confidence>& child); + TypeBuilder& SetReturnValue(const ReturnValue& rv); + TypeBuilder& SetIsReturnValueDefaultLocation(bool defaultLocation); + TypeBuilder& SetReturnValueLocation(const Confidence& location); TypeBuilder& SetCallingConvention(const Confidence>& cc); TypeBuilder& SetCallingConventionName(BNCallingConventionName cc); TypeBuilder& SetSigned(const Confidence& 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>& type, uint64_t elem); - static TypeBuilder FunctionType(const Confidence>& returnValue, + static TypeBuilder FunctionType(const ReturnValue& returnValue, const Confidence>& callingConvention, const std::vector& params, const Confidence& varArg = Confidence(false, 0), const Confidence& stackAdjust = Confidence(0, 0)); - static TypeBuilder FunctionType(const Confidence>& returnValue, + static TypeBuilder FunctionType(const ReturnValue& returnValue, const Confidence>& callingConvention, const std::vector& params, const Confidence& hasVariableArguments, const Confidence& canReturn, const Confidence& stackAdjust, const std::map>& regStackAdjust = std::map>(), - const Confidence>& returnRegs = Confidence>(std::vector(), 0), BNNameType ft = NoNameType, const Confidence& pure = Confidence(false, 0)); static TypeBuilder VarArgsType(); @@ -13276,9 +13388,13 @@ namespace BinaryNinja { Ref GetType() const; Confidence> GetReturnType() const; + ReturnValue GetReturnValue() const; + bool IsReturnValueDefaultLocation() const; + Confidence GetReturnValueLocation() const; Confidence> GetReturnRegisters() const; Confidence> GetCallingConvention() const; Confidence> GetParameterVariables() const; + Confidence> GetParameterLocations() const; Confidence HasVariableArguments() const; Confidence GetStackAdjustment() const; std::map> GetRegisterStackAdjustments() const; @@ -13286,9 +13402,11 @@ namespace BinaryNinja { void SetAutoType(Type* type); void SetAutoReturnType(const Confidence>& type); - void SetAutoReturnRegisters(const Confidence>& returnRegs); + void SetAutoReturnValue(const ReturnValue& rv); + void SetAutoIsReturnValueDefaultLocation(bool defaultLocation); + void SetAutoReturnValueLocation(const Confidence& location); void SetAutoCallingConvention(const Confidence>& convention); - void SetAutoParameterVariables(const Confidence>& vars); + void SetAutoParameterLocations(const Confidence>& locations); void SetAutoHasVariableArguments(const Confidence& varArgs); void SetAutoCanReturn(const Confidence& returns); void SetAutoPure(const Confidence& pure); @@ -13298,9 +13416,11 @@ namespace BinaryNinja { void SetUserType(Type* type); void SetReturnType(const Confidence>& type); - void SetReturnRegisters(const Confidence>& returnRegs); + void SetReturnValue(const ReturnValue& rv); + void SetIsReturnValueDefaultLocation(bool defaultLocation); + void SetReturnValueLocation(const Confidence& location); void SetCallingConvention(const Confidence>& convention); - void SetParameterVariables(const Confidence>& vars); + void SetParameterLocations(const Confidence>& locations); void SetHasVariableArguments(const Confidence& varArgs); void SetCanReturn(const Confidence& returns); void SetPure(const Confidence& 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& params, const ILSourceLocation& loc = ILSourceLocation()); ExprId SharedParamSlot(const std::vector& 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& 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& 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 parameters; + std::optional returnValue; + int64_t stackAdjustment = 0; + std::map registerStackAdjustments; + + static CallLayout FromAPIObject(BNCallLayout* layout); + BNCallLayout ToAPIObject() const; + static void FreeAPIObject(BNCallLayout* layout); + }; + + /*! + \ingroup callingconvention */ class CallingConvention : public CoreRefCountObject @@ -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 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 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& params, + const std::optional>& permittedRegs = std::nullopt); + virtual ValueLocation GetReturnValueLocation(BinaryView* view, const ReturnValue& returnValue); + virtual std::vector GetParameterLocations(BinaryView* view, + const std::optional& returnValue, const std::vector& params, + const std::optional>& permittedRegs = std::nullopt); + virtual int64_t GetStackAdjustmentForLocations(BinaryView* view, + const std::optional& returnValue, const std::vector& locations, + const std::vector>& types); + virtual std::map GetRegisterStackAdjustments(BinaryView* view, + const std::optional& returnValue, const std::vector& params); + + CallLayout GetDefaultCallLayout(BinaryView* view, const ReturnValue& returnValue, + const std::vector& params, + const std::optional>& permittedRegs = std::nullopt); + ValueLocation GetDefaultReturnValueLocation(BinaryView* view, const ReturnValue& returnValue); + std::vector GetDefaultParameterLocations(BinaryView* view, + const std::optional& returnValue, const std::vector& params, + const std::optional>& permittedRegs = std::nullopt); + int64_t GetDefaultStackAdjustmentForLocations(const std::optional& returnValue, + const std::vector& locations, const std::vector>& types); + std::map GetDefaultRegisterStackAdjustments( + const std::optional& returnValue, const std::vector& 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 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& params, + const std::optional>& permittedRegs = std::nullopt) override; + virtual ValueLocation GetReturnValueLocation(BinaryView* view, const ReturnValue& returnValue) override; + virtual std::vector GetParameterLocations(BinaryView* view, + const std::optional& returnValue, const std::vector& params, + const std::optional>& permittedRegs = std::nullopt) override; + virtual int64_t GetStackAdjustmentForLocations(BinaryView* view, + const std::optional& returnValue, const std::vector& locations, + const std::vector>& types) override; + virtual std::map GetRegisterStackAdjustments(BinaryView* view, + const std::optional& returnValue, const std::vector& params) override; }; /*! -- cgit v1.3.1