summaryrefslogtreecommitdiff
path: root/callingconvention.cpp
diff options
context:
space:
mode:
authorRusty Wagner <rusty.wagner@gmail.com>2025-12-23 13:12:02 -0700
committerRusty Wagner <rusty.wagner@gmail.com>2026-05-22 16:30:56 -0400
commit8d621c51b2797fda7b1dc22243dde611cfc04f68 (patch)
treeba5e6a90e644d21d13e75dabcbd0cc747444443a /callingconvention.cpp
parent08e34ac325743085911f96b62c81d9a1f2127806 (diff)
Refactor calling conventions to support correct representation of structures
Diffstat (limited to 'callingconvention.cpp')
-rw-r--r--callingconvention.cpp739
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(&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;
+}