Skip to content

Commit b104c24

Browse files
committed
Refactor calling conventions to support correct representation of structures
1 parent b1246d8 commit b104c24

25 files changed

Lines changed: 2842 additions & 478 deletions

binaryninjaapi.h

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

binaryninjacore.h

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

callingconvention.cpp

Lines changed: 696 additions & 0 deletions
Large diffs are not rendered by default.

function.cpp

Lines changed: 125 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,24 @@ Variable Variable::FromIdentifier(uint64_t id)
4141
}
4242

4343

44+
Variable Variable::Register(uint32_t reg)
45+
{
46+
return Variable(RegisterVariableSourceType, reg);
47+
}
48+
49+
50+
Variable Variable::Flag(uint32_t flag)
51+
{
52+
return Variable(FlagVariableSourceType, flag);
53+
}
54+
55+
56+
Variable Variable::StackOffset(int64_t offset)
57+
{
58+
return Variable(StackVariableSourceType, offset);
59+
}
60+
61+
4462
RegisterValue::RegisterValue() : state(UndeterminedValue), value(0), offset(0), size(0) {}
4563

4664

@@ -63,6 +81,12 @@ bool RegisterValue::operator==(const RegisterValue& a) const
6381
case StackFrameOffset:
6482
return (state == StackFrameOffset) && (a.value == value);
6583

84+
case ResultPointerValue:
85+
return (state == ResultPointerValue) && (a.value == value);
86+
87+
case ParameterPointerValue:
88+
return (state == ParameterPointerValue) && (a.value == value) && (a.offset == offset);
89+
6690
case UndeterminedValue:
6791
return state == UndeterminedValue;
6892

@@ -729,6 +753,30 @@ Confidence<Ref<Type>> Function::GetReturnType() const
729753
}
730754

731755

756+
ReturnValue Function::GetReturnValue() const
757+
{
758+
BNReturnValue ret = BNGetFunctionReturnValue(m_object);
759+
ReturnValue result = ReturnValue::FromAPIObject(&ret);
760+
BNFreeReturnValue(&ret);
761+
return result;
762+
}
763+
764+
765+
bool Function::IsReturnValueDefaultLocation() const
766+
{
767+
return BNIsFunctionReturnValueDefaultLocation(m_object);
768+
}
769+
770+
771+
Confidence<ValueLocation> Function::GetReturnValueLocation() const
772+
{
773+
auto location = BNGetFunctionReturnValueLocation(m_object);
774+
Confidence<ValueLocation> result(ValueLocation::FromAPIObject(&location.location), location.confidence);
775+
BNFreeValueLocation(&location.location);
776+
return result;
777+
}
778+
779+
732780
Confidence<vector<uint32_t>> Function::GetReturnRegisters() const
733781
{
734782
BNRegisterSetWithConfidence regs = BNGetFunctionReturnRegisters(m_object);
@@ -763,6 +811,19 @@ Confidence<vector<Variable>> Function::GetParameterVariables() const
763811
}
764812

765813

814+
Confidence<vector<ValueLocation>> Function::GetParameterLocations() const
815+
{
816+
BNValueLocationListWithConfidence locations = BNGetFunctionParameterLocations(m_object);
817+
vector<ValueLocation> locationList;
818+
locationList.reserve(locations.count);
819+
for (size_t i = 0; i < locations.count; i++)
820+
locationList.push_back(ValueLocation::FromAPIObject(&locations.locations[i]));
821+
Confidence<vector<ValueLocation>> result(locationList, locations.confidence);
822+
BNFreeParameterLocations(&locations);
823+
return result;
824+
}
825+
826+
766827
Confidence<bool> Function::HasVariableArguments() const
767828
{
768829
BNBoolWithConfidence bc = BNFunctionHasVariableArguments(m_object);
@@ -817,16 +878,27 @@ void Function::SetAutoReturnType(const Confidence<Ref<Type>>& type)
817878
}
818879

819880

820-
void Function::SetAutoReturnRegisters(const Confidence<std::vector<uint32_t>>& returnRegs)
881+
void Function::SetAutoReturnValue(const ReturnValue& rv)
821882
{
822-
BNRegisterSetWithConfidence regs;
823-
regs.regs = new uint32_t[returnRegs.GetValue().size()];
824-
regs.count = returnRegs.GetValue().size();
825-
for (size_t i = 0; i < regs.count; i++)
826-
regs.regs[i] = returnRegs.GetValue()[i];
827-
regs.confidence = returnRegs.GetConfidence();
828-
BNSetAutoFunctionReturnRegisters(m_object, &regs);
829-
delete[] regs.regs;
883+
BNReturnValue ret = rv.ToAPIObject();
884+
BNSetAutoFunctionReturnValue(m_object, &ret);
885+
ReturnValue::FreeAPIObject(&ret);
886+
}
887+
888+
889+
void Function::SetAutoIsReturnValueDefaultLocation(bool defaultLocation)
890+
{
891+
BNSetAutoIsFunctionReturnValueDefaultLocation(m_object, defaultLocation);
892+
}
893+
894+
895+
void Function::SetAutoReturnValueLocation(const Confidence<ValueLocation>& location)
896+
{
897+
BNValueLocationWithConfidence loc;
898+
loc.location = location->ToAPIObject();
899+
loc.confidence = location.GetConfidence();
900+
BNSetAutoFunctionReturnValueLocation(m_object, &loc);
901+
ValueLocation::FreeAPIObject(&loc.location);
830902
}
831903

832904

@@ -839,22 +911,21 @@ void Function::SetAutoCallingConvention(const Confidence<Ref<CallingConvention>>
839911
}
840912

841913

842-
void Function::SetAutoParameterVariables(const Confidence<vector<Variable>>& vars)
914+
void Function::SetAutoParameterLocations(const Confidence<std::vector<ValueLocation>>& locations)
843915
{
844-
BNParameterVariablesWithConfidence varConf;
845-
varConf.vars = new BNVariable[vars->size()];
846-
varConf.count = vars->size();
916+
BNValueLocationListWithConfidence varConf;
917+
varConf.locations = new BNValueLocation[locations->size()];
918+
varConf.count = locations->size();
847919
size_t i = 0;
848-
for (auto it = vars->begin(); it != vars->end(); ++it, ++i)
849-
{
850-
varConf.vars[i].type = it->type;
851-
varConf.vars[i].index = it->index;
852-
varConf.vars[i].storage = it->storage;
853-
}
854-
varConf.confidence = vars.GetConfidence();
920+
for (auto it = locations->begin(); it != locations->end(); ++it, ++i)
921+
varConf.locations[i] = it->ToAPIObject();
922+
varConf.confidence = locations.GetConfidence();
855923

856-
BNSetAutoFunctionParameterVariables(m_object, &varConf);
857-
delete[] varConf.vars;
924+
BNSetAutoFunctionParameterLocations(m_object, &varConf);
925+
926+
for (i = 0; i < locations->size(); i++)
927+
ValueLocation::FreeAPIObject(&varConf.locations[i]);
928+
delete[] varConf.locations;
858929
}
859930

860931

@@ -946,16 +1017,27 @@ void Function::SetReturnType(const Confidence<Ref<Type>>& type)
9461017
}
9471018

9481019

949-
void Function::SetReturnRegisters(const Confidence<std::vector<uint32_t>>& returnRegs)
1020+
void Function::SetReturnValue(const ReturnValue& rv)
9501021
{
951-
BNRegisterSetWithConfidence regs;
952-
regs.regs = new uint32_t[returnRegs.GetValue().size()];
953-
regs.count = returnRegs.GetValue().size();
954-
for (size_t i = 0; i < regs.count; i++)
955-
regs.regs[i] = returnRegs.GetValue()[i];
956-
regs.confidence = returnRegs.GetConfidence();
957-
BNSetUserFunctionReturnRegisters(m_object, &regs);
958-
delete[] regs.regs;
1022+
BNReturnValue ret = rv.ToAPIObject();
1023+
BNSetUserFunctionReturnValue(m_object, &ret);
1024+
ReturnValue::FreeAPIObject(&ret);
1025+
}
1026+
1027+
1028+
void Function::SetIsReturnValueDefaultLocation(bool defaultLocation)
1029+
{
1030+
BNSetUserIsFunctionReturnValueDefaultLocation(m_object, defaultLocation);
1031+
}
1032+
1033+
1034+
void Function::SetReturnValueLocation(const Confidence<ValueLocation>& location)
1035+
{
1036+
BNValueLocationWithConfidence loc;
1037+
loc.location = location->ToAPIObject();
1038+
loc.confidence = location.GetConfidence();
1039+
BNSetUserFunctionReturnValueLocation(m_object, &loc);
1040+
ValueLocation::FreeAPIObject(&loc.location);
9591041
}
9601042

9611043

@@ -968,22 +1050,21 @@ void Function::SetCallingConvention(const Confidence<Ref<CallingConvention>>& co
9681050
}
9691051

9701052

971-
void Function::SetParameterVariables(const Confidence<vector<Variable>>& vars)
1053+
void Function::SetParameterLocations(const Confidence<std::vector<ValueLocation>>& locations)
9721054
{
973-
BNParameterVariablesWithConfidence varConf;
974-
varConf.vars = new BNVariable[vars->size()];
975-
varConf.count = vars->size();
1055+
BNValueLocationListWithConfidence varConf;
1056+
varConf.locations = new BNValueLocation[locations->size()];
1057+
varConf.count = locations->size();
9761058
size_t i = 0;
977-
for (auto it = vars->begin(); it != vars->end(); ++it, ++i)
978-
{
979-
varConf.vars[i].type = it->type;
980-
varConf.vars[i].index = it->index;
981-
varConf.vars[i].storage = it->storage;
982-
}
983-
varConf.confidence = vars.GetConfidence();
1059+
for (auto it = locations->begin(); it != locations->end(); ++it, ++i)
1060+
varConf.locations[i] = it->ToAPIObject();
1061+
varConf.confidence = locations.GetConfidence();
1062+
1063+
BNSetUserFunctionParameterLocations(m_object, &varConf);
9841064

985-
BNSetUserFunctionParameterVariables(m_object, &varConf);
986-
delete[] varConf.vars;
1065+
for (i = 0; i < locations->size(); i++)
1066+
ValueLocation::FreeAPIObject(&varConf.locations[i]);
1067+
delete[] varConf.locations;
9871068
}
9881069

9891070

lang/rust/rusttypes.cpp

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -147,12 +147,13 @@ vector<InstructionTextToken> RustTypePrinter::GetTypeTokensAfterNameInternal(
147147
vector<InstructionTextToken> paramTokens = GetTypeTokensAfterName(params[i].type.GetValue(), platform,
148148
params[i].type.GetCombinedConfidence(baseConfidence), type, escaping);
149149

150-
if (functionHeader)
150+
auto var = params[i].location.GetVariableForParameter(i);
151+
if (functionHeader && var.has_value())
151152
{
152153
for (auto& token : paramTokens)
153154
{
154155
token.context = LocalVariableTokenContext;
155-
token.address = params[i].location.ToIdentifier();
156+
token.address = var->ToIdentifier();
156157
}
157158
}
158159

@@ -164,42 +165,46 @@ vector<InstructionTextToken> RustTypePrinter::GetTypeTokensAfterNameInternal(
164165
else
165166
{
166167
nameToken = InstructionTextToken(ArgumentNameToken, NameList::EscapeTypeName(params[i].name, escaping), i);
167-
if (functionHeader)
168+
if (functionHeader && var.has_value())
168169
{
169170
nameToken.context = LocalVariableTokenContext;
170-
nameToken.address = params[i].location.ToIdentifier();
171+
nameToken.address = var->ToIdentifier();
171172
}
172173
}
173174
tokens.push_back(nameToken);
174175
tokens.emplace_back(TextToken, ": ");
175176
tokens.insert(tokens.end(), paramTokens.begin(), paramTokens.end());
176177

177-
if (!params[i].defaultLocation && platform)
178+
if (!params[i].defaultLocation && platform && var.has_value())
178179
{
179-
switch (params[i].location.type)
180+
// TODO: Emit a syntax for parameters spanning multiple storage locations
181+
switch (var->type)
180182
{
181183
case RegisterVariableSourceType:
182184
{
183-
string registerName = platform->GetArchitecture()->GetRegisterName((uint32_t)params[i].location.storage);
185+
string registerName = platform->GetArchitecture()->GetRegisterName((uint32_t)var->storage);
184186
tokens.emplace_back(TextToken, " @ ");
185-
tokens.emplace_back(RegisterToken, NameList::EscapeTypeName(registerName, escaping), params[i].location.storage);
187+
tokens.emplace_back(RegisterToken, NameList::EscapeTypeName(registerName, escaping), var->storage);
186188
break;
187189
}
188190
case FlagVariableSourceType:
189191
{
190-
string flagName = platform->GetArchitecture()->GetFlagName((uint32_t)params[i].location.storage);
192+
string flagName = platform->GetArchitecture()->GetFlagName((uint32_t)var->storage);
191193
tokens.emplace_back(TextToken, " @ ");
192-
tokens.emplace_back(AnnotationToken, NameList::EscapeTypeName(flagName, escaping), params[i].location.storage);
194+
tokens.emplace_back(AnnotationToken, NameList::EscapeTypeName(flagName, escaping), var->storage);
193195
break;
194196
}
195197
case StackVariableSourceType:
196198
{
197199
tokens.emplace_back(TextToken, " @ ");
198200
char storageStr[32];
199-
snprintf(storageStr, sizeof(storageStr), "%" PRIi64, params[i].location.storage);
200-
tokens.emplace_back(IntegerToken, storageStr, params[i].location.storage);
201+
snprintf(storageStr, sizeof(storageStr), "%" PRIi64, var->storage);
202+
tokens.emplace_back(IntegerToken, storageStr, var->storage);
201203
break;
202204
}
205+
case CompositeReturnValueSourceType:
206+
case CompositeParameterSourceType:
207+
break;
203208
}
204209
}
205210
}

mediumlevelilinstruction.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,7 @@ static constexpr std::array s_instructionOperandUsage = {
292292
OperandUsage{MLIL_FREE_VAR_SLOT_SSA, {DestSSAVariableMediumLevelOperandUsage, PartialSSAVariableSourceMediumLevelOperandUsage}},
293293
OperandUsage{MLIL_VAR_PHI, {DestSSAVariableMediumLevelOperandUsage, SourceSSAVariablesMediumLevelOperandUsages}},
294294
OperandUsage{MLIL_MEM_PHI, {DestMemoryVersionMediumLevelOperandUsage, SourceMemoryVersionsMediumLevelOperandUsage}},
295+
OperandUsage{MLIL_BLOCK_TO_EXPAND, {SourceExprsMediumLevelOperandUsage}},
295296
};
296297

297298
VALIDATE_INSTRUCTION_ORDER(s_instructionOperandUsage);
@@ -1553,6 +1554,10 @@ void MediumLevelILInstruction::VisitExprs(bn::base::function_ref<bool(const Medi
15531554
for (auto i : GetParameterExprs())
15541555
i.VisitExprs(func);
15551556
break;
1557+
case MLIL_BLOCK_TO_EXPAND:
1558+
for (auto i : GetSourceExprs<MLIL_BLOCK_TO_EXPAND>())
1559+
i.VisitExprs(func);
1560+
break;
15561561
default:
15571562
break;
15581563
}
@@ -1892,6 +1897,10 @@ ExprId MediumLevelILInstruction::CopyTo(MediumLevelILFunction* dest,
18921897
return dest->Undefined(loc);
18931898
case MLIL_UNIMPL:
18941899
return dest->Unimplemented(loc);
1900+
case MLIL_BLOCK_TO_EXPAND:
1901+
for (auto i : GetSourceExprs<MLIL_BLOCK_TO_EXPAND>())
1902+
params.push_back(subExprHandler(i));
1903+
return dest->BlockToExpand(params, loc);
18951904
default:
18961905
throw MediumLevelILInstructionAccessException();
18971906
}
@@ -3125,6 +3134,12 @@ ExprId MediumLevelILFunction::FloatCompareUnordered(size_t size, ExprId a, ExprI
31253134
}
31263135

31273136

3137+
ExprId MediumLevelILFunction::BlockToExpand(const vector<ExprId>& sources, const ILSourceLocation& loc)
3138+
{
3139+
return AddExprWithLocation(MLIL_BLOCK_TO_EXPAND, loc, 0, sources.size(), AddOperandList(sources));
3140+
}
3141+
3142+
31283143
fmt::format_context::iterator fmt::formatter<MediumLevelILInstruction>::format(const MediumLevelILInstruction& obj, format_context& ctx) const
31293144
{
31303145
if (!obj.function)

mediumlevelilinstruction.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1565,6 +1565,13 @@ namespace BinaryNinja
15651565
int64_t GetOffset() const { return GetRawOperandAsInteger(1); }
15661566
};
15671567

1568+
template <>
1569+
struct MediumLevelILInstructionAccessor<MLIL_BLOCK_TO_EXPAND> : public MediumLevelILInstructionBase
1570+
{
1571+
MediumLevelILInstructionList GetSourceExprs() const { return GetRawOperandAsExprList(0); }
1572+
void SetSourceExprs(const _STD_VECTOR<ExprId>& exprs) { UpdateRawOperandAsExprList(0, exprs); }
1573+
};
1574+
15681575
template <>
15691576
struct MediumLevelILInstructionAccessor<MLIL_NOP> : public MediumLevelILInstructionBase
15701577
{};

0 commit comments

Comments
 (0)