Skip to content

Commit 7e14a5e

Browse files
committed
Refactor calling conventions to support correct representation of structures
1 parent ed0f3b1 commit 7e14a5e

21 files changed

+2100
-434
lines changed

binaryninjaapi.h

Lines changed: 167 additions & 18 deletions
Large diffs are not rendered by default.

binaryninjacore.h

Lines changed: 140 additions & 30 deletions
Large diffs are not rendered by default.

callingconvention.cpp

Lines changed: 349 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,61 @@ using namespace std;
2424
using namespace BinaryNinja;
2525

2626

27+
CallLayout CallLayout::FromAPIObject(BNCallLayout* layout)
28+
{
29+
CallLayout result;
30+
result.parameters.reserve(layout->parameterCount);
31+
for (size_t i = 0; i < layout->parameterCount; i++)
32+
result.parameters.push_back(ValueLocation::FromAPIObject(&layout->parameters[i]));
33+
if (layout->returnValueValid)
34+
result.returnValue = ValueLocation::FromAPIObject(&layout->returnValue);
35+
result.stackAdjustment = layout->stackAdjustment;
36+
for (size_t i = 0; i < layout->registerStackAdjustmentCount; i++)
37+
{
38+
result.registerStackAdjustments[layout->registerStackAdjustmentRegisters[i]] =
39+
layout->registerStackAdjustmentAmounts[i];
40+
}
41+
return result;
42+
}
43+
44+
45+
BNCallLayout CallLayout::ToAPIObject() const
46+
{
47+
BNCallLayout result;
48+
result.parameters = new BNValueLocation[parameters.size()];
49+
result.parameterCount = parameters.size();
50+
for (size_t i = 0; i < parameters.size(); i++)
51+
result.parameters[i] = parameters[i].ToAPIObject();
52+
result.returnValue = returnValue.value_or(ValueLocation()).ToAPIObject();
53+
result.returnValueValid = returnValue.has_value();
54+
result.stackAdjustment = stackAdjustment;
55+
56+
result.registerStackAdjustmentCount = registerStackAdjustments.size();
57+
result.registerStackAdjustmentRegisters = new uint32_t[registerStackAdjustments.size()];
58+
result.registerStackAdjustmentAmounts = new int32_t[registerStackAdjustments.size()];
59+
size_t i = 0;
60+
for (auto [reg, adjust] : registerStackAdjustments)
61+
{
62+
result.registerStackAdjustmentRegisters[i] = reg;
63+
result.registerStackAdjustmentAmounts[i] = adjust;
64+
i++;
65+
}
66+
67+
return result;
68+
}
69+
70+
71+
void CallLayout::FreeAPIObject(BNCallLayout* layout)
72+
{
73+
for (size_t i = 0; i < layout->parameterCount; i++)
74+
ValueLocation::FreeAPIObject(&layout->parameters[i]);
75+
delete[] layout->parameters;
76+
ValueLocation::FreeAPIObject(&layout->returnValue);
77+
delete[] layout->registerStackAdjustmentRegisters;
78+
delete[] layout->registerStackAdjustmentAmounts;
79+
}
80+
81+
2782
CallingConvention::CallingConvention(BNCallingConvention* cc)
2883
{
2984
m_object = cc;
@@ -54,6 +109,12 @@ CallingConvention::CallingConvention(Architecture* arch, const string& name)
54109
cc.getIncomingFlagValue = GetIncomingFlagValueCallback;
55110
cc.getIncomingVariableForParameterVariable = GetIncomingVariableForParameterVariableCallback;
56111
cc.getParameterVariableForIncomingVariable = GetParameterVariableForIncomingVariableCallback;
112+
cc.getCallLayout = GetCallLayoutCallback;
113+
cc.freeCallLayout = FreeCallLayoutCallback;
114+
cc.getReturnValueLocation = GetReturnValueLocationCallback;
115+
cc.freeValueLocation = FreeValueLocationCallback;
116+
cc.getParameterLocations = GetParameterLocationsCallback;
117+
cc.freeParameterLocations = FreeParameterLocationsCallback;
57118

58119
AddRefForRegistration();
59120
m_object = BNCreateCallingConvention(arch->GetObject(), name.c_str(), &cc);
@@ -245,6 +306,90 @@ void CallingConvention::GetParameterVariableForIncomingVariableCallback(
245306
}
246307

247308

309+
BNCallLayout CallingConvention::GetCallLayoutCallback(void* ctxt, BNReturnValue* returnValue,
310+
BNFunctionParameter* params, size_t paramCount, bool hasPermittedRegs, uint32_t* permittedRegs,
311+
size_t permittedRegCount)
312+
{
313+
CallbackRef<CallingConvention> cc(ctxt);
314+
auto ret = ReturnValue::FromAPIObject(returnValue);
315+
vector<FunctionParameter> paramObjs;
316+
paramObjs.reserve(paramCount);
317+
for (size_t i = 0; i < paramCount; i++)
318+
paramObjs.push_back(FunctionParameter::FromAPIObject(&params[i]));
319+
optional<set<uint32_t>> regOpt;
320+
if (hasPermittedRegs)
321+
{
322+
set<uint32_t> regs;
323+
for (size_t i = 0; i < permittedRegCount; i++)
324+
regs.insert(permittedRegs[i]);
325+
regOpt = regs;
326+
}
327+
328+
auto layout = cc->GetCallLayout(ret, paramObjs, regOpt);
329+
return layout.ToAPIObject();
330+
}
331+
332+
333+
void CallingConvention::FreeCallLayoutCallback(void*, BNCallLayout* layout)
334+
{
335+
CallLayout::FreeAPIObject(layout);
336+
}
337+
338+
339+
BNValueLocation CallingConvention::GetReturnValueLocationCallback(void* ctxt, BNReturnValue* returnValue)
340+
{
341+
CallbackRef<CallingConvention> cc(ctxt);
342+
ReturnValue ret = ReturnValue::FromAPIObject(returnValue);
343+
ValueLocation location = cc->GetReturnValueLocation(ret);
344+
return location.ToAPIObject();
345+
}
346+
347+
348+
void CallingConvention::FreeValueLocationCallback(void*, BNValueLocation* location)
349+
{
350+
ValueLocation::FreeAPIObject(location);
351+
}
352+
353+
354+
BNValueLocation* CallingConvention::GetParameterLocationsCallback(void* ctxt, BNValueLocation* returnValue,
355+
BNFunctionParameter* params, size_t paramCount, bool hasPermittedRegs, uint32_t* permittedRegs,
356+
size_t permittedRegCount, size_t* outLocationCount)
357+
{
358+
CallbackRef<CallingConvention> cc(ctxt);
359+
std::optional<ValueLocation> ret;
360+
if (returnValue)
361+
ret = ValueLocation::FromAPIObject(returnValue);
362+
vector<FunctionParameter> paramObjs;
363+
paramObjs.reserve(paramCount);
364+
for (size_t i = 0; i < paramCount; i++)
365+
paramObjs.push_back(FunctionParameter::FromAPIObject(&params[i]));
366+
optional<set<uint32_t>> regOpt;
367+
if (hasPermittedRegs)
368+
{
369+
set<uint32_t> regs;
370+
for (size_t i = 0; i < permittedRegCount; i++)
371+
regs.insert(permittedRegs[i]);
372+
regOpt = regs;
373+
}
374+
375+
vector<ValueLocation> locations = cc->GetParameterLocations(ret, paramObjs, regOpt);
376+
377+
*outLocationCount = locations.size();
378+
BNValueLocation* result = new BNValueLocation[locations.size()];
379+
for (size_t i = 0; i < locations.size(); i++)
380+
result[i] = locations[i].ToAPIObject();
381+
return result;
382+
}
383+
384+
385+
void CallingConvention::FreeParameterLocationsCallback(void*, BNValueLocation* locations, size_t count)
386+
{
387+
for (size_t i = 0; i < count; i++)
388+
ValueLocation::FreeAPIObject(&locations[i]);
389+
delete[] locations;
390+
}
391+
392+
248393
Ref<Architecture> CallingConvention::GetArchitecture() const
249394
{
250395
return new CoreArchitecture(BNGetCallingConventionArchitecture(m_object));
@@ -370,6 +515,118 @@ Variable CallingConvention::GetParameterVariableForIncomingVariable(const Variab
370515
}
371516

372517

518+
CallLayout CallingConvention::GetCallLayout(const ReturnValue& returnValue, const vector<FunctionParameter>& params,
519+
const optional<set<uint32_t>>& permittedRegs)
520+
{
521+
return GetDefaultCallLayout(returnValue, params, permittedRegs);
522+
}
523+
524+
525+
ValueLocation CallingConvention::GetReturnValueLocation(const ReturnValue& returnValue)
526+
{
527+
return GetDefaultReturnValueLocation(returnValue);
528+
}
529+
530+
531+
vector<ValueLocation> CallingConvention::GetParameterLocations(const optional<ValueLocation>& returnValue,
532+
const vector<FunctionParameter>& params, const optional<set<uint32_t>>& permittedRegs)
533+
{
534+
return GetDefaultParameterLocations(returnValue, params, permittedRegs);
535+
}
536+
537+
538+
CallLayout CallingConvention::GetDefaultCallLayout(const ReturnValue& returnValue,
539+
const vector<FunctionParameter>& params, const optional<set<uint32_t>>& permittedRegs)
540+
{
541+
BNReturnValue ret = returnValue.ToAPIObject();
542+
BNFunctionParameter* paramArray = new BNFunctionParameter[params.size()];
543+
for (size_t i = 0; i < params.size(); i++)
544+
paramArray[i] = params[i].ToAPIObject();
545+
546+
BNCallLayout layout;
547+
if (permittedRegs.has_value())
548+
{
549+
uint32_t* regs = new uint32_t[permittedRegs->size()];
550+
size_t i = 0;
551+
for (auto reg : *permittedRegs)
552+
regs[i++] = reg;
553+
layout = BNGetDefaultCallLayout(m_object, &ret, paramArray, params.size(), regs, permittedRegs->size());
554+
delete[] regs;
555+
}
556+
else
557+
{
558+
layout = BNGetDefaultCallLayoutDefaultPermittedArgs(m_object, &ret, paramArray, params.size());
559+
}
560+
561+
ReturnValue::FreeAPIObject(&ret);
562+
for (size_t i = 0; i < params.size(); i++)
563+
FunctionParameter::FreeAPIObject(&paramArray[i]);
564+
delete[] paramArray;
565+
566+
CallLayout result = CallLayout::FromAPIObject(&layout);
567+
BNFreeCallLayout(&layout);
568+
return result;
569+
}
570+
571+
572+
ValueLocation CallingConvention::GetDefaultReturnValueLocation(const ReturnValue& returnValue)
573+
{
574+
BNReturnValue ret = returnValue.ToAPIObject();
575+
BNValueLocation location = BNGetDefaultReturnValueLocation(m_object, &ret);
576+
ReturnValue::FreeAPIObject(&ret);
577+
578+
ValueLocation result = ValueLocation::FromAPIObject(&location);
579+
BNFreeValueLocation(&location);
580+
return result;
581+
}
582+
583+
584+
vector<ValueLocation> CallingConvention::GetDefaultParameterLocations(const optional<ValueLocation>& returnValue,
585+
const vector<FunctionParameter>& params, const optional<set<uint32_t>>& permittedRegs)
586+
{
587+
BNValueLocation* retOpt = nullptr;
588+
BNValueLocation ret;
589+
if (returnValue.has_value())
590+
{
591+
ret = returnValue->ToAPIObject();
592+
retOpt = &ret;
593+
}
594+
BNFunctionParameter* paramArray = new BNFunctionParameter[params.size()];
595+
for (size_t i = 0; i < params.size(); i++)
596+
paramArray[i] = params[i].ToAPIObject();
597+
598+
size_t locationCount = 0;
599+
BNValueLocation* locations;
600+
if (permittedRegs.has_value())
601+
{
602+
uint32_t* regs = new uint32_t[permittedRegs->size()];
603+
size_t i = 0;
604+
for (auto reg : *permittedRegs)
605+
regs[i++] = reg;
606+
locations = BNGetDefaultParameterLocations(
607+
m_object, retOpt, paramArray, params.size(), regs, permittedRegs->size(), &locationCount);
608+
}
609+
else
610+
{
611+
locations = BNGetDefaultParameterLocationsDefaultPermittedArgs(
612+
m_object, retOpt, paramArray, params.size(), &locationCount);
613+
}
614+
615+
if (retOpt)
616+
ValueLocation::FreeAPIObject(retOpt);
617+
for (size_t i = 0; i < params.size(); i++)
618+
FunctionParameter::FreeAPIObject(&paramArray[i]);
619+
delete[] paramArray;
620+
621+
vector<ValueLocation> result;
622+
result.reserve(locationCount);
623+
for (size_t i = 0; i < locationCount; i++)
624+
result.push_back(ValueLocation::FromAPIObject(&locations[i]));
625+
BNFreeValueLocationList(locations, locationCount);
626+
return result;
627+
}
628+
629+
373630
CoreCallingConvention::CoreCallingConvention(BNCallingConvention* cc) : CallingConvention(cc) {}
374631

375632

@@ -504,3 +761,95 @@ Variable CoreCallingConvention::GetParameterVariableForIncomingVariable(const Va
504761
{
505762
return BNGetParameterVariableForIncomingVariable(m_object, &var, func ? func->GetObject() : nullptr);
506763
}
764+
765+
766+
CallLayout CoreCallingConvention::GetCallLayout(const ReturnValue& returnValue, const vector<FunctionParameter>& params,
767+
const optional<set<uint32_t>>& permittedRegs)
768+
{
769+
BNReturnValue ret = returnValue.ToAPIObject();
770+
BNFunctionParameter* paramArray = new BNFunctionParameter[params.size()];
771+
for (size_t i = 0; i < params.size(); i++)
772+
paramArray[i] = params[i].ToAPIObject();
773+
774+
BNCallLayout layout;
775+
if (permittedRegs.has_value())
776+
{
777+
uint32_t* regs = new uint32_t[permittedRegs->size()];
778+
size_t i = 0;
779+
for (auto reg : *permittedRegs)
780+
regs[i++] = reg;
781+
layout = BNGetCallLayout(m_object, &ret, paramArray, params.size(), regs, permittedRegs->size());
782+
delete[] regs;
783+
}
784+
else
785+
{
786+
layout = BNGetCallLayoutDefaultPermittedArgs(m_object, &ret, paramArray, params.size());
787+
}
788+
789+
ReturnValue::FreeAPIObject(&ret);
790+
for (size_t i = 0; i < params.size(); i++)
791+
FunctionParameter::FreeAPIObject(&paramArray[i]);
792+
delete[] paramArray;
793+
794+
CallLayout result = CallLayout::FromAPIObject(&layout);
795+
BNFreeCallLayout(&layout);
796+
return result;
797+
}
798+
799+
800+
ValueLocation CoreCallingConvention::GetReturnValueLocation(const ReturnValue& returnValue)
801+
{
802+
BNReturnValue ret = returnValue.ToAPIObject();
803+
BNValueLocation location = BNGetReturnValueLocation(m_object, &ret);
804+
ReturnValue::FreeAPIObject(&ret);
805+
806+
ValueLocation result = ValueLocation::FromAPIObject(&location);
807+
BNFreeValueLocation(&location);
808+
return result;
809+
}
810+
811+
812+
vector<ValueLocation> CoreCallingConvention::GetParameterLocations(const optional<ValueLocation>& returnValue,
813+
const vector<FunctionParameter>& params, const optional<set<uint32_t>>& permittedRegs)
814+
{
815+
BNValueLocation* retOpt = nullptr;
816+
BNValueLocation ret;
817+
if (returnValue.has_value())
818+
{
819+
ret = returnValue->ToAPIObject();
820+
retOpt = &ret;
821+
}
822+
BNFunctionParameter* paramArray = new BNFunctionParameter[params.size()];
823+
for (size_t i = 0; i < params.size(); i++)
824+
paramArray[i] = params[i].ToAPIObject();
825+
826+
size_t locationCount = 0;
827+
BNValueLocation* locations;
828+
if (permittedRegs.has_value())
829+
{
830+
uint32_t* regs = new uint32_t[permittedRegs->size()];
831+
size_t i = 0;
832+
for (auto reg : *permittedRegs)
833+
regs[i++] = reg;
834+
locations = BNGetParameterLocations(
835+
m_object, retOpt, paramArray, params.size(), regs, permittedRegs->size(), &locationCount);
836+
}
837+
else
838+
{
839+
locations =
840+
BNGetParameterLocationsDefaultPermittedArgs(m_object, retOpt, paramArray, params.size(), &locationCount);
841+
}
842+
843+
if (retOpt)
844+
ValueLocation::FreeAPIObject(retOpt);
845+
for (size_t i = 0; i < params.size(); i++)
846+
FunctionParameter::FreeAPIObject(&paramArray[i]);
847+
delete[] paramArray;
848+
849+
vector<ValueLocation> result;
850+
result.reserve(locationCount);
851+
for (size_t i = 0; i < locationCount; i++)
852+
result.push_back(ValueLocation::FromAPIObject(&locations[i]));
853+
BNFreeValueLocationList(locations, locationCount);
854+
return result;
855+
}

0 commit comments

Comments
 (0)