diff options
| author | Rusty Wagner <rusty.wagner@gmail.com> | 2025-12-23 13:12:02 -0700 |
|---|---|---|
| committer | Rusty Wagner <rusty.wagner@gmail.com> | 2026-05-22 16:30:56 -0400 |
| commit | 8d621c51b2797fda7b1dc22243dde611cfc04f68 (patch) | |
| tree | ba5e6a90e644d21d13e75dabcbd0cc747444443a /callingconvention.cpp | |
| parent | 08e34ac325743085911f96b62c81d9a1f2127806 (diff) | |
Refactor calling conventions to support correct representation of structures
Diffstat (limited to 'callingconvention.cpp')
| -rw-r--r-- | callingconvention.cpp | 739 |
1 files changed, 739 insertions, 0 deletions
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(¶ms[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(¶ms[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(¶ms[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(¶mArray[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(¶mArray[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(), ®s, &adjust); + + if (retOpt) + ValueLocation::FreeAPIObject(retOpt); + for (size_t i = 0; i < params.size(); i++) + ValueLocation::FreeAPIObject(¶mArray[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(¶mArray[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(¶mArray[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(), ®s, &adjust); + + if (retOpt) + ValueLocation::FreeAPIObject(retOpt); + for (size_t i = 0; i < params.size(); i++) + ValueLocation::FreeAPIObject(¶mArray[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; +} |
