// Copyright (c) 2015-2020 Vector 35 Inc
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
#include "binaryninjaapi.h"
using namespace BinaryNinja;
using namespace std;
Variable::Variable()
{
type = RegisterVariableSourceType;
index = 0;
storage = 0;
}
Variable::Variable(BNVariableSourceType t, uint32_t i, uint64_t s)
{
type = t;
index = i;
storage = s;
}
Variable::Variable(const BNVariable& var)
{
type = var.type;
index = var.index;
storage = var.storage;
}
Variable::Variable(const Variable& var)
{
type = var.type;
index = var.index;
storage = var.storage;
}
Variable& Variable::operator=(const Variable& var)
{
type = var.type;
index = var.index;
storage = var.storage;
return *this;
}
bool Variable::operator==(const Variable& var) const
{
if (type != var.type)
return false;
if (index != var.index)
return false;
return storage == var.storage;
}
bool Variable::operator!=(const Variable& var) const
{
return !((*this) == var);
}
bool Variable::operator<(const Variable& var) const
{
return ToIdentifier() < var.ToIdentifier();
}
uint64_t Variable::ToIdentifier() const
{
return BNToVariableIdentifier(this);
}
Variable Variable::FromIdentifier(uint64_t id)
{
return BNFromVariableIdentifier(id);
}
RegisterValue::RegisterValue(): state(UndeterminedValue), value(0), offset(0)
{
}
BNRegisterValue RegisterValue::ToAPIObject()
{
BNRegisterValue result;
result.state = state;
result.value = value;
result.offset = offset;
return result;
}
Function::Function(BNFunction* func)
{
m_object = func;
m_advancedAnalysisRequests = 0;
}
Function::~Function()
{
if (m_advancedAnalysisRequests > 0)
BNReleaseAdvancedFunctionAnalysisDataMultiple(m_object, (size_t)m_advancedAnalysisRequests);
}
Ref Function::GetView() const
{
return new BinaryView(BNGetFunctionData(m_object));
}
Ref Function::GetPlatform() const
{
return new Platform(BNGetFunctionPlatform(m_object));
}
Ref Function::GetArchitecture() const
{
return new CoreArchitecture(BNGetFunctionArchitecture(m_object));
}
uint64_t Function::GetStart() const
{
return BNGetFunctionStart(m_object);
}
Ref Function::GetSymbol() const
{
return new Symbol(BNGetFunctionSymbol(m_object));
}
bool Function::WasAutomaticallyDiscovered() const
{
return BNWasFunctionAutomaticallyDiscovered(m_object);
}
Confidence Function::CanReturn() const
{
BNBoolWithConfidence bc = BNCanFunctionReturn(m_object);
return Confidence(bc.value, bc.confidence);
}
bool Function::HasExplicitlyDefinedType() const
{
return BNFunctionHasExplicitlyDefinedType(m_object);
}
bool Function::NeedsUpdate() const
{
return BNIsFunctionUpdateNeeded(m_object);
}
vector[> Function::GetBasicBlocks() const
{
size_t count;
BNBasicBlock** blocks = BNGetFunctionBasicBlockList(m_object, &count);
vector][> result;
result.reserve(count);
for (size_t i = 0; i < count; i++)
result.push_back(new BasicBlock(BNNewBasicBlockReference(blocks[i])));
BNFreeBasicBlockList(blocks, count);
return result;
}
Ref Function::GetBasicBlockAtAddress(Architecture* arch, uint64_t addr) const
{
BNBasicBlock* block = BNGetFunctionBasicBlockAtAddress(m_object, arch->GetObject(), addr);
if (!block)
return nullptr;
return new BasicBlock(block);
}
void Function::MarkRecentUse()
{
BNMarkFunctionAsRecentlyUsed(m_object);
}
string Function::GetComment() const
{
char* comment = BNGetFunctionComment(m_object);
string result = comment;
BNFreeString(comment);
return result;
}
string Function::GetCommentForAddress(uint64_t addr) const
{
char* comment = BNGetCommentForAddress(m_object, addr);
string result = comment;
BNFreeString(comment);
return result;
}
vector Function::GetCommentedAddresses() const
{
size_t count;
uint64_t* addrs = BNGetCommentedAddresses(m_object, &count);
vector result;
result.insert(result.end(), addrs, &addrs[count]);
BNFreeAddressList(addrs);
return result;
}
void Function::SetComment(const string& comment)
{
BNSetFunctionComment(m_object, comment.c_str());
}
void Function::SetCommentForAddress(uint64_t addr, const string& comment)
{
BNSetCommentForAddress(m_object, addr, comment.c_str());
}
vector Function::GetCallSites() const
{
size_t count;
BNReferenceSource* refs = BNGetFunctionCallSites(m_object, &count);
vector result;
result.reserve(count);
for (size_t i = 0; i < count; i++)
{
ReferenceSource src;
src.func = new Function(BNNewFunctionReference(refs[i].func));
src.arch = new CoreArchitecture(refs[i].arch);
src.addr = refs[i].addr;
result.push_back(src);
}
BNFreeCodeReferences(refs, count);
return result;
}
void Function::AddUserCodeReference(Architecture* fromArch, uint64_t fromAddr, uint64_t toAddr)
{
BNAddUserCodeReference(m_object, fromArch->GetObject(), fromAddr, toAddr);
}
void Function::RemoveUserCodeReference(Architecture* fromArch, uint64_t fromAddr, uint64_t toAddr)
{
BNRemoveUserCodeReference(m_object, fromArch->GetObject(), fromAddr, toAddr);
}
Ref Function::GetLowLevelIL() const
{
return new LowLevelILFunction(BNGetFunctionLowLevelIL(m_object));
}
size_t Function::GetLowLevelILForInstruction(Architecture* arch, uint64_t addr)
{
return BNGetLowLevelILForInstruction(m_object, arch->GetObject(), addr);
}
vector Function::GetLowLevelILExitsForInstruction(Architecture* arch, uint64_t addr)
{
size_t count;
size_t* exits = BNGetLowLevelILExitsForInstruction(m_object, arch->GetObject(), addr, &count);
vector result;
result.insert(result.end(), exits, &exits[count]);
BNFreeILInstructionList(exits);
return result;
}
RegisterValue RegisterValue::FromAPIObject(const BNRegisterValue& value)
{
RegisterValue result;
result.state = value.state;
result.value = value.value;
return result;
}
PossibleValueSet PossibleValueSet::FromAPIObject(BNPossibleValueSet& value)
{
PossibleValueSet result;
result.state = value.state;
result.value = value.value;
result.offset = value.offset;
if (value.state == LookupTableValue)
{
for (size_t i = 0; i < value.count; i++)
{
LookupTableEntry entry;
entry.fromValues.insert(entry.fromValues.end(), &value.table[i].fromValues[0],
&value.table[i].fromValues[value.table[i].fromCount]);
entry.toValue = value.table[i].toValue;
result.table.push_back(entry);
}
}
else if ((value.state == SignedRangeValue) || (value.state == UnsignedRangeValue))
{
for (size_t i = 0; i < value.count; i++)
result.ranges.push_back(value.ranges[i]);
}
else if ((value.state == InSetOfValues) || (value.state == NotInSetOfValues))
{
for (size_t i = 0; i < value.count; i++)
result.valueSet.insert(value.valueSet[i]);
}
BNFreePossibleValueSet(&value);
return result;
}
RegisterValue Function::GetRegisterValueAtInstruction(Architecture* arch, uint64_t addr, uint32_t reg)
{
BNRegisterValue value = BNGetRegisterValueAtInstruction(m_object, arch->GetObject(), addr, reg);
return RegisterValue::FromAPIObject(value);
}
RegisterValue Function::GetRegisterValueAfterInstruction(Architecture* arch, uint64_t addr, uint32_t reg)
{
BNRegisterValue value = BNGetRegisterValueAfterInstruction(m_object, arch->GetObject(), addr, reg);
return RegisterValue::FromAPIObject(value);
}
RegisterValue Function::GetStackContentsAtInstruction(Architecture* arch, uint64_t addr, int64_t offset, size_t size)
{
BNRegisterValue value = BNGetStackContentsAtInstruction(m_object, arch->GetObject(), addr, offset, size);
return RegisterValue::FromAPIObject(value);
}
RegisterValue Function::GetStackContentsAfterInstruction(Architecture* arch, uint64_t addr, int64_t offset, size_t size)
{
BNRegisterValue value = BNGetStackContentsAfterInstruction(m_object, arch->GetObject(), addr, offset, size);
return RegisterValue::FromAPIObject(value);
}
RegisterValue Function::GetParameterValueAtInstruction(Architecture* arch, uint64_t addr, Type* functionType, size_t i)
{
BNRegisterValue value = BNGetParameterValueAtInstruction(m_object, arch->GetObject(), addr,
functionType ? functionType->GetObject() : nullptr, i);
return RegisterValue::FromAPIObject(value);
}
RegisterValue Function::GetParameterValueAtLowLevelILInstruction(size_t instr, Type* functionType, size_t i)
{
BNRegisterValue value = BNGetParameterValueAtLowLevelILInstruction(m_object, instr,
functionType ? functionType->GetObject() : nullptr, i);
return RegisterValue::FromAPIObject(value);
}
vector Function::GetRegistersReadByInstruction(Architecture* arch, uint64_t addr)
{
size_t count;
uint32_t* regs = BNGetRegistersReadByInstruction(m_object, arch->GetObject(), addr, &count);
vector result;
result.insert(result.end(), regs, ®s[count]);
BNFreeRegisterList(regs);
return result;
}
vector Function::GetRegistersWrittenByInstruction(Architecture* arch, uint64_t addr)
{
size_t count;
uint32_t* regs = BNGetRegistersWrittenByInstruction(m_object, arch->GetObject(), addr, &count);
vector result;
result.insert(result.end(), regs, ®s[count]);
BNFreeRegisterList(regs);
return result;
}
vector Function::GetStackVariablesReferencedByInstruction(Architecture* arch, uint64_t addr)
{
size_t count;
BNStackVariableReference* refs = BNGetStackVariablesReferencedByInstruction(m_object, arch->GetObject(), addr, &count);
vector result;
result.reserve(count);
for (size_t i = 0; i < count; i++)
{
StackVariableReference ref;
ref.sourceOperand = refs[i].sourceOperand;
ref.type = Confidence][>(refs[i].type ? new Type(BNNewTypeReference(refs[i].type)) : nullptr,
refs[i].typeConfidence);
ref.name = refs[i].name;
ref.var = Variable::FromIdentifier(refs[i].varIdentifier);
ref.referencedOffset = refs[i].referencedOffset;
ref.size = refs[i].size;
result.push_back(ref);
}
BNFreeStackVariableReferenceList(refs, count);
return result;
}
vector Function::GetConstantsReferencedByInstruction(Architecture* arch, uint64_t addr)
{
size_t count;
BNConstantReference* refs = BNGetConstantsReferencedByInstruction(m_object, arch->GetObject(), addr, &count);
vector result;
result.insert(result.end(), &refs[0], &refs[count]);
BNFreeConstantReferenceList(refs);
return result;
}
Ref Function::GetLiftedIL() const
{
return new LowLevelILFunction(BNGetFunctionLiftedIL(m_object));
}
size_t Function::GetLiftedILForInstruction(Architecture* arch, uint64_t addr)
{
return BNGetLiftedILForInstruction(m_object, arch->GetObject(), addr);
}
set Function::GetLiftedILFlagUsesForDefinition(size_t i, uint32_t flag)
{
size_t count;
size_t* instrs = BNGetLiftedILFlagUsesForDefinition(m_object, i, flag, &count);
set result;
result.insert(&instrs[0], &instrs[count]);
BNFreeILInstructionList(instrs);
return result;
}
set Function::GetLiftedILFlagDefinitionsForUse(size_t i, uint32_t flag)
{
size_t count;
size_t* instrs = BNGetLiftedILFlagDefinitionsForUse(m_object, i, flag, &count);
set result;
result.insert(&instrs[0], &instrs[count]);
BNFreeILInstructionList(instrs);
return result;
}
set Function::GetFlagsReadByLiftedILInstruction(size_t i)
{
size_t count;
uint32_t* flags = BNGetFlagsReadByLiftedILInstruction(m_object, i, &count);
set result;
result.insert(&flags[0], &flags[count]);
BNFreeRegisterList(flags);
return result;
}
set Function::GetFlagsWrittenByLiftedILInstruction(size_t i)
{
size_t count;
uint32_t* flags = BNGetFlagsWrittenByLiftedILInstruction(m_object, i, &count);
set result;
result.insert(&flags[0], &flags[count]);
BNFreeRegisterList(flags);
return result;
}
Ref Function::GetMediumLevelIL() const
{
return new MediumLevelILFunction(BNGetFunctionMediumLevelIL(m_object));
}
Ref Function::GetType() const
{
return new Type(BNGetFunctionType(m_object));
}
Confidence][> Function::GetReturnType() const
{
BNTypeWithConfidence tc = BNGetFunctionReturnType(m_object);
Ref type = tc.type ? new Type(tc.type) : nullptr;
return Confidence][>(type, tc.confidence);
}
Confidence> Function::GetReturnRegisters() const
{
BNRegisterSetWithConfidence regs = BNGetFunctionReturnRegisters(m_object);
vector regList;
for (size_t i = 0; i < regs.count; i++)
regList.push_back(regs.regs[i]);
Confidence> result(regList, regs.confidence);
BNFreeRegisterSet(®s);
return result;
}
Confidence][> Function::GetCallingConvention() const
{
BNCallingConventionWithConfidence cc = BNGetFunctionCallingConvention(m_object);
Ref convention = cc.convention ? new CoreCallingConvention(cc.convention) : nullptr;
return Confidence][>(convention, cc.confidence);
}
Confidence> Function::GetParameterVariables() const
{
BNParameterVariablesWithConfidence vars = BNGetFunctionParameterVariables(m_object);
vector varList;
varList.reserve(vars.count);
for (size_t i = 0; i < vars.count; i++)
varList.emplace_back(vars.vars[i].type, vars.vars[i].index, vars.vars[i].storage);
Confidence> result(varList, vars.confidence);
BNFreeParameterVariables(&vars);
return result;
}
Confidence Function::HasVariableArguments() const
{
BNBoolWithConfidence bc = BNFunctionHasVariableArguments(m_object);
return Confidence(bc.value, bc.confidence);
}
Confidence Function::GetStackAdjustment() const
{
BNOffsetWithConfidence oc = BNGetFunctionStackAdjustment(m_object);
return Confidence(oc.value, oc.confidence);
}
map> Function::GetRegisterStackAdjustments() const
{
size_t count;
BNRegisterStackAdjustment* regStackAdjust = BNGetFunctionRegisterStackAdjustments(m_object, &count);
map> result;
for (size_t i = 0; i < count; i++)
result[regStackAdjust[i].regStack] = Confidence(regStackAdjust[i].adjustment, regStackAdjust[i].confidence);
BNFreeRegisterStackAdjustments(regStackAdjust);
return result;
}
Confidence> Function::GetClobberedRegisters() const
{
BNRegisterSetWithConfidence regs = BNGetFunctionClobberedRegisters(m_object);
set regSet;
for (size_t i = 0; i < regs.count; i++)
regSet.insert(regs.regs[i]);
Confidence> result(regSet, regs.confidence);
BNFreeRegisterSet(®s);
return result;
}
void Function::SetAutoType(Type* type)
{
BNSetFunctionAutoType(m_object, type->GetObject());
}
void Function::SetAutoReturnType(const Confidence][>& type)
{
BNTypeWithConfidence tc;
tc.type = type ? type->GetObject() : nullptr;
tc.confidence = type.GetConfidence();
BNSetAutoFunctionReturnType(m_object, &tc);
}
void Function::SetAutoReturnRegisters(const Confidence<:vector>>& returnRegs)
{
BNRegisterSetWithConfidence regs;
regs.regs = new uint32_t[returnRegs.GetValue().size()];
regs.count = returnRegs.GetValue().size();
for (size_t i = 0; i < regs.count; i++)
regs.regs[i] = returnRegs.GetValue()[i];
regs.confidence = returnRegs.GetConfidence();
BNSetAutoFunctionReturnRegisters(m_object, ®s);
delete[] regs.regs;
}
void Function::SetAutoCallingConvention(const Confidence][>& convention)
{
BNCallingConventionWithConfidence cc;
cc.convention = convention ? convention->GetObject() : nullptr;
cc.confidence = convention.GetConfidence();
BNSetAutoFunctionCallingConvention(m_object, &cc);
}
void Function::SetAutoParameterVariables(const Confidence>& vars)
{
BNParameterVariablesWithConfidence varConf;
varConf.vars = new BNVariable[vars->size()];
varConf.count = vars->size();
size_t i = 0;
for (auto it = vars->begin(); it != vars->end(); ++it, ++i)
{
varConf.vars[i].type = it->type;
varConf.vars[i].index = it->index;
varConf.vars[i].storage = it->storage;
}
varConf.confidence = vars.GetConfidence();
BNSetAutoFunctionParameterVariables(m_object, &varConf);
delete[] varConf.vars;
}
void Function::SetAutoHasVariableArguments(const Confidence& varArgs)
{
BNBoolWithConfidence bc;
bc.value = varArgs.GetValue();
bc.confidence = varArgs.GetConfidence();
BNSetAutoFunctionHasVariableArguments(m_object, &bc);
}
void Function::SetAutoCanReturn(const Confidence& returns)
{
BNBoolWithConfidence bc;
bc.value = returns.GetValue();
bc.confidence = returns.GetConfidence();
BNSetAutoFunctionCanReturn(m_object, &bc);
}
void Function::SetAutoStackAdjustment(const Confidence& stackAdjust)
{
BNOffsetWithConfidence oc;
oc.value = stackAdjust.GetValue();
oc.confidence = stackAdjust.GetConfidence();
BNSetAutoFunctionStackAdjustment(m_object, &oc);
}
void Function::SetAutoRegisterStackAdjustments(const map>& regStackAdjust)
{
BNRegisterStackAdjustment* adjust = new BNRegisterStackAdjustment[regStackAdjust.size()];
size_t i = 0;
for (auto& j : regStackAdjust)
{
adjust[i].regStack = j.first;
adjust[i].adjustment = j.second.GetValue();
adjust[i].confidence = j.second.GetConfidence();
i++;
}
BNSetAutoFunctionRegisterStackAdjustments(m_object, adjust, regStackAdjust.size());
delete[] adjust;
}
void Function::SetAutoClobberedRegisters(const Confidence<:set>>& clobbered)
{
BNRegisterSetWithConfidence regs;
regs.regs = new uint32_t[clobbered->size()];
regs.count = clobbered->size();
size_t i = 0;
for (auto it = clobbered->begin(); it != clobbered->end(); ++it, ++i)
regs.regs[i] = *it;
regs.confidence = clobbered.GetConfidence();
BNSetAutoFunctionClobberedRegisters(m_object, ®s);
delete[] regs.regs;
}
void Function::SetUserType(Type* type)
{
BNSetFunctionUserType(m_object, type->GetObject());
}
void Function::SetReturnType(const Confidence][>& type)
{
BNTypeWithConfidence tc;
tc.type = type ? type->GetObject() : nullptr;
tc.confidence = type.GetConfidence();
BNSetUserFunctionReturnType(m_object, &tc);
}
void Function::SetReturnRegisters(const Confidence<:vector>>& returnRegs)
{
BNRegisterSetWithConfidence regs;
regs.regs = new uint32_t[returnRegs.GetValue().size()];
regs.count = returnRegs.GetValue().size();
for (size_t i = 0; i < regs.count; i++)
regs.regs[i] = returnRegs.GetValue()[i];
regs.confidence = returnRegs.GetConfidence();
BNSetUserFunctionReturnRegisters(m_object, ®s);
delete[] regs.regs;
}
void Function::SetCallingConvention(const Confidence][>& convention)
{
BNCallingConventionWithConfidence cc;
cc.convention = convention ? convention->GetObject() : nullptr;
cc.confidence = convention.GetConfidence();
BNSetUserFunctionCallingConvention(m_object, &cc);
}
void Function::SetParameterVariables(const Confidence>& vars)
{
BNParameterVariablesWithConfidence varConf;
varConf.vars = new BNVariable[vars->size()];
varConf.count = vars->size();
size_t i = 0;
for (auto it = vars->begin(); it != vars->end(); ++it, ++i)
{
varConf.vars[i].type = it->type;
varConf.vars[i].index = it->index;
varConf.vars[i].storage = it->storage;
}
varConf.confidence = vars.GetConfidence();
BNSetUserFunctionParameterVariables(m_object, &varConf);
delete[] varConf.vars;
}
void Function::SetHasVariableArguments(const Confidence& varArgs)
{
BNBoolWithConfidence bc;
bc.value = varArgs.GetValue();
bc.confidence = varArgs.GetConfidence();
BNSetUserFunctionHasVariableArguments(m_object, &bc);
}
void Function::SetCanReturn(const Confidence& returns)
{
BNBoolWithConfidence bc;
bc.value = returns.GetValue();
bc.confidence = returns.GetConfidence();
BNSetUserFunctionCanReturn(m_object, &bc);
}
void Function::SetStackAdjustment(const Confidence& stackAdjust)
{
BNOffsetWithConfidence oc;
oc.value = stackAdjust.GetValue();
oc.confidence = stackAdjust.GetConfidence();
BNSetUserFunctionStackAdjustment(m_object, &oc);
}
void Function::SetRegisterStackAdjustments(const map>& regStackAdjust)
{
BNRegisterStackAdjustment* adjust = new BNRegisterStackAdjustment[regStackAdjust.size()];
size_t i = 0;
for (auto& j : regStackAdjust)
{
adjust[i].regStack = j.first;
adjust[i].adjustment = j.second.GetValue();
adjust[i].confidence = j.second.GetConfidence();
i++;
}
BNSetUserFunctionRegisterStackAdjustments(m_object, adjust, regStackAdjust.size());
delete[] adjust;
}
void Function::SetClobberedRegisters(const Confidence<:set>>& clobbered)
{
BNRegisterSetWithConfidence regs;
regs.regs = new uint32_t[clobbered->size()];
regs.count = clobbered->size();
size_t i = 0;
for (auto it = clobbered->begin(); it != clobbered->end(); ++it, ++i)
regs.regs[i] = *it;
regs.confidence = clobbered.GetConfidence();
BNSetUserFunctionClobberedRegisters(m_object, ®s);
delete[] regs.regs;
}
void Function::ApplyImportedTypes(Symbol* sym)
{
BNApplyImportedTypes(m_object, sym->GetObject());
}
void Function::ApplyAutoDiscoveredType(Type* type)
{
BNApplyAutoDiscoveredFunctionType(m_object, type->GetObject());
}
Ref Function::CreateFunctionGraph(BNFunctionGraphType type, DisassemblySettings* settings)
{
BNFlowGraph* graph = BNCreateFunctionGraph(m_object, type, settings ? settings->GetObject() : nullptr);
return new CoreFlowGraph(graph);
}
map> Function::GetStackLayout()
{
size_t count;
BNVariableNameAndType* vars = BNGetStackLayout(m_object, &count);
map> result;
for (size_t i = 0; i < count; i++)
{
VariableNameAndType var;
var.name = vars[i].name;
var.type = Confidence][>(new Type(BNNewTypeReference(vars[i].type)), vars[i].typeConfidence);
var.var = vars[i].var;
var.autoDefined = vars[i].autoDefined;
result[vars[i].var.storage].push_back(var);
}
BNFreeVariableNameAndTypeList(vars, count);
return result;
}
void Function::CreateAutoStackVariable(int64_t offset, const Confidence][>& type, const string& name)
{
BNTypeWithConfidence tc;
tc.type = type->GetObject();
tc.confidence = type.GetConfidence();
BNCreateAutoStackVariable(m_object, offset, &tc, name.c_str());
}
void Function::CreateUserStackVariable(int64_t offset, const Confidence][>& type, const string& name)
{
BNTypeWithConfidence tc;
tc.type = type->GetObject();
tc.confidence = type.GetConfidence();
BNCreateUserStackVariable(m_object, offset, &tc, name.c_str());
}
void Function::DeleteAutoStackVariable(int64_t offset)
{
BNDeleteAutoStackVariable(m_object, offset);
}
void Function::DeleteUserStackVariable(int64_t offset)
{
BNDeleteUserStackVariable(m_object, offset);
}
bool Function::GetStackVariableAtFrameOffset(Architecture* arch, uint64_t addr,
int64_t offset, VariableNameAndType& result)
{
BNVariableNameAndType var;
if (!BNGetStackVariableAtFrameOffset(m_object, arch->GetObject(), addr, offset, &var))
return false;
result.type = Confidence][>(new Type(BNNewTypeReference(var.type)), var.typeConfidence);
result.name = var.name;
result.var = var.var;
result.autoDefined = var.autoDefined;
BNFreeVariableNameAndType(&var);
return true;
}
map Function::GetVariables()
{
size_t count;
BNVariableNameAndType* vars = BNGetFunctionVariables(m_object, &count);
map result;
for (size_t i = 0; i < count; i++)
{
VariableNameAndType var;
var.name = vars[i].name;
var.type = Confidence][>(new Type(BNNewTypeReference(vars[i].type)), vars[i].typeConfidence);
var.var = vars[i].var;
var.autoDefined = vars[i].autoDefined;
result[vars[i].var] = var;
}
BNFreeVariableNameAndTypeList(vars, count);
return result;
}
void Function::CreateAutoVariable(const Variable& var, const Confidence][>& type,
const string& name, bool ignoreDisjointUses)
{
BNTypeWithConfidence tc;
tc.type = type->GetObject();
tc.confidence = type.GetConfidence();
BNCreateAutoVariable(m_object, &var, &tc, name.c_str(), ignoreDisjointUses);
}
void Function::CreateUserVariable(const Variable& var, const Confidence][>& type,
const string& name, bool ignoreDisjointUses)
{
BNTypeWithConfidence tc;
tc.type = type->GetObject();
tc.confidence = type.GetConfidence();
BNCreateUserVariable(m_object, &var, &tc, name.c_str(), ignoreDisjointUses);
}
void Function::DeleteAutoVariable(const Variable& var)
{
BNDeleteAutoVariable(m_object, &var);
}
void Function::DeleteUserVariable(const Variable& var)
{
BNDeleteUserVariable(m_object, &var);
}
Confidence][> Function::GetVariableType(const Variable& var)
{
BNTypeWithConfidence type = BNGetVariableType(m_object, &var);
if (!type.type)
return nullptr;
return Confidence][>(new Type(type.type), type.confidence);
}
string Function::GetVariableName(const Variable& var)
{
char* name = BNGetVariableName(m_object, &var);
string result = name;
BNFreeString(name);
return result;
}
void Function::SetAutoIndirectBranches(Architecture* sourceArch, uint64_t source, const std::vector& branches)
{
BNArchitectureAndAddress* branchList = new BNArchitectureAndAddress[branches.size()];
for (size_t i = 0; i < branches.size(); i++)
{
branchList[i].arch = branches[i].arch->GetObject();
branchList[i].address = branches[i].address;
}
BNSetAutoIndirectBranches(m_object, sourceArch->GetObject(), source, branchList, branches.size());
delete[] branchList;
}
void Function::SetUserIndirectBranches(Architecture* sourceArch, uint64_t source, const std::vector& branches)
{
BNArchitectureAndAddress* branchList = new BNArchitectureAndAddress[branches.size()];
for (size_t i = 0; i < branches.size(); i++)
{
branchList[i].arch = branches[i].arch->GetObject();
branchList[i].address = branches[i].address;
}
BNSetUserIndirectBranches(m_object, sourceArch->GetObject(), source, branchList, branches.size());
delete[] branchList;
}
vector Function::GetIndirectBranches()
{
size_t count;
BNIndirectBranchInfo* branches = BNGetIndirectBranches(m_object, &count);
vector result;
result.reserve(count);
for (size_t i = 0; i < count; i++)
{
IndirectBranchInfo b;
b.sourceArch = new CoreArchitecture(branches[i].sourceArch);
b.sourceAddr = branches[i].sourceAddr;
b.destArch = new CoreArchitecture(branches[i].destArch);
b.destAddr = branches[i].destAddr;
b.autoDefined = branches[i].autoDefined;
result.push_back(b);
}
BNFreeIndirectBranchList(branches);
return result;
}
vector Function::GetIndirectBranchesAt(Architecture* arch, uint64_t addr)
{
size_t count;
BNIndirectBranchInfo* branches = BNGetIndirectBranchesAt(m_object, arch->GetObject(), addr, &count);
vector result;
result.reserve(count);
for (size_t i = 0; i < count; i++)
{
IndirectBranchInfo b;
b.sourceArch = new CoreArchitecture(branches[i].sourceArch);
b.sourceAddr = branches[i].sourceAddr;
b.destArch = new CoreArchitecture(branches[i].destArch);
b.destAddr = branches[i].destAddr;
b.autoDefined = branches[i].autoDefined;
result.push_back(b);
}
BNFreeIndirectBranchList(branches);
return result;
}
void Function::SetAutoCallTypeAdjustment(Architecture* arch, uint64_t addr, const Confidence][>& adjust)
{
BNTypeWithConfidence apiObject;
apiObject.type = adjust ? adjust->GetObject() : nullptr;
apiObject.confidence = adjust.GetConfidence();
BNSetAutoCallTypeAdjustment(m_object, arch->GetObject(), addr, adjust ? &apiObject : nullptr);
}
void Function::SetAutoCallStackAdjustment(Architecture* arch, uint64_t addr, const Confidence& adjust)
{
BNSetAutoCallStackAdjustment(m_object, arch->GetObject(), addr, adjust.GetValue(), adjust.GetConfidence());
}
void Function::SetAutoCallRegisterStackAdjustment(Architecture* arch, uint64_t addr,
const map>& adjust)
{
BNRegisterStackAdjustment* values = new BNRegisterStackAdjustment[adjust.size()];
size_t i = 0;
for (auto& j : adjust)
{
values[i].regStack = j.first;
values[i].adjustment = j.second.GetValue();
values[i].confidence = j.second.GetConfidence();
i++;
}
BNSetAutoCallRegisterStackAdjustment(m_object, arch->GetObject(), addr, values, adjust.size());
delete[] values;
}
void Function::SetAutoCallRegisterStackAdjustment(Architecture* arch, uint64_t addr, uint32_t regStack,
const Confidence& adjust)
{
BNSetAutoCallRegisterStackAdjustmentForRegisterStack(m_object, arch->GetObject(), addr, regStack,
adjust.GetValue(), adjust.GetConfidence());
}
void Function::SetUserCallTypeAdjustment(Architecture* arch, uint64_t addr, const Confidence][>& adjust)
{
BNTypeWithConfidence apiObject;
apiObject.type = adjust ? adjust->GetObject() : nullptr;
apiObject.confidence = adjust.GetConfidence();
BNSetUserCallTypeAdjustment(m_object, arch->GetObject(), addr, adjust ? &apiObject : nullptr);
}
void Function::SetUserCallStackAdjustment(Architecture* arch, uint64_t addr, const Confidence& adjust)
{
BNSetUserCallStackAdjustment(m_object, arch->GetObject(), addr, adjust.GetValue(), adjust.GetConfidence());
}
void Function::SetUserCallRegisterStackAdjustment(Architecture* arch, uint64_t addr,
const map>& adjust)
{
BNRegisterStackAdjustment* values = new BNRegisterStackAdjustment[adjust.size()];
size_t i = 0;
for (auto& j : adjust)
{
values[i].regStack = j.first;
values[i].adjustment = j.second.GetValue();
values[i].confidence = j.second.GetConfidence();
i++;
}
BNSetUserCallRegisterStackAdjustment(m_object, arch->GetObject(), addr, values, adjust.size());
delete[] values;
}
void Function::SetUserCallRegisterStackAdjustment(Architecture* arch, uint64_t addr, uint32_t regStack,
const Confidence& adjust)
{
BNSetUserCallRegisterStackAdjustmentForRegisterStack(m_object, arch->GetObject(), addr, regStack,
adjust.GetValue(), adjust.GetConfidence());
}
Confidence][> Function::GetCallTypeAdjustment(Architecture* arch, uint64_t addr)
{
BNTypeWithConfidence result = BNGetCallTypeAdjustment(m_object, arch->GetObject(), addr);
return Confidence][>(result.type ? new Type(result.type) : nullptr, result.confidence);
}
Confidence Function::GetCallStackAdjustment(Architecture* arch, uint64_t addr)
{
BNOffsetWithConfidence result = BNGetCallStackAdjustment(m_object, arch->GetObject(), addr);
return Confidence(result.value, result.confidence);
}
map> Function::GetCallRegisterStackAdjustment(Architecture* arch, uint64_t addr)
{
size_t count;
BNRegisterStackAdjustment* adjust = BNGetCallRegisterStackAdjustment(m_object, arch->GetObject(), addr, &count);
map> result;
for (size_t i = 0; i < count; i++)
result[adjust[i].regStack] = Confidence(adjust[i].adjustment, adjust[i].confidence);
BNFreeRegisterStackAdjustments(adjust);
return result;
}
Confidence Function::GetCallRegisterStackAdjustment(Architecture* arch, uint64_t addr, uint32_t regStack)
{
BNRegisterStackAdjustment result = BNGetCallRegisterStackAdjustmentForRegisterStack(m_object,
arch->GetObject(), addr, regStack);
return Confidence(result.adjustment, result.confidence);
}
bool Function::IsCallInstruction(Architecture* arch, uint64_t addr)
{
return BNIsCallInstruction(m_object, arch->GetObject(), addr);
}
vector> Function::GetBlockAnnotations(Architecture* arch, uint64_t addr)
{
size_t count;
BNInstructionTextLine* lines = BNGetFunctionBlockAnnotations(m_object, arch->GetObject(), addr, &count);
vector> result;
result.reserve(count);
for (size_t i = 0; i < count; i++)
result.push_back(InstructionTextToken::ConvertInstructionTextTokenList(lines[i].tokens, lines[i].count));
BNFreeInstructionTextLines(lines, count);
return result;
}
BNIntegerDisplayType Function::GetIntegerConstantDisplayType(Architecture* arch, uint64_t instrAddr, uint64_t value,
size_t operand)
{
return BNGetIntegerConstantDisplayType(m_object, arch->GetObject(), instrAddr, value, operand);
}
void Function::SetIntegerConstantDisplayType(Architecture* arch, uint64_t instrAddr, uint64_t value, size_t operand,
BNIntegerDisplayType type)
{
BNSetIntegerConstantDisplayType(m_object, arch->GetObject(), instrAddr, value, operand, type);
}
BNHighlightColor Function::GetInstructionHighlight(Architecture* arch, uint64_t addr)
{
return BNGetInstructionHighlight(m_object, arch->GetObject(), addr);
}
void Function::SetAutoInstructionHighlight(Architecture* arch, uint64_t addr, BNHighlightColor color)
{
BNSetAutoInstructionHighlight(m_object, arch->GetObject(), addr, color);
}
void Function::SetAutoInstructionHighlight(Architecture* arch, uint64_t addr, BNHighlightStandardColor color,
uint8_t alpha)
{
BNHighlightColor hc;
hc.style = StandardHighlightColor;
hc.color = color;
hc.mixColor = NoHighlightColor;
hc.mix = 0;
hc.r = 0;
hc.g = 0;
hc.b = 0;
hc.alpha = alpha;
SetAutoInstructionHighlight(arch, addr, hc);
}
void Function::SetAutoInstructionHighlight(Architecture* arch, uint64_t addr, BNHighlightStandardColor color,
BNHighlightStandardColor mixColor, uint8_t mix, uint8_t alpha)
{
BNHighlightColor hc;
hc.style = MixedHighlightColor;
hc.color = color;
hc.mixColor = mixColor;
hc.mix = mix;
hc.r = 0;
hc.g = 0;
hc.b = 0;
hc.alpha = alpha;
SetAutoInstructionHighlight(arch, addr, hc);
}
void Function::SetAutoInstructionHighlight(Architecture* arch, uint64_t addr, uint8_t r, uint8_t g, uint8_t b,
uint8_t alpha)
{
BNHighlightColor hc;
hc.style = CustomHighlightColor;
hc.color = NoHighlightColor;
hc.mixColor = NoHighlightColor;
hc.mix = 0;
hc.r = r;
hc.g = g;
hc.b = b;
hc.alpha = alpha;
SetAutoInstructionHighlight(arch, addr, hc);
}
void Function::SetUserInstructionHighlight(Architecture* arch, uint64_t addr, BNHighlightColor color)
{
BNSetUserInstructionHighlight(m_object, arch->GetObject(), addr, color);
}
void Function::SetUserInstructionHighlight(Architecture* arch, uint64_t addr, BNHighlightStandardColor color,
uint8_t alpha)
{
BNHighlightColor hc;
hc.style = StandardHighlightColor;
hc.color = color;
hc.mixColor = NoHighlightColor;
hc.mix = 0;
hc.r = 0;
hc.g = 0;
hc.b = 0;
hc.alpha = alpha;
SetUserInstructionHighlight(arch, addr, hc);
}
void Function::SetUserInstructionHighlight(Architecture* arch, uint64_t addr, BNHighlightStandardColor color,
BNHighlightStandardColor mixColor, uint8_t mix, uint8_t alpha)
{
BNHighlightColor hc;
hc.style = MixedHighlightColor;
hc.color = color;
hc.mixColor = mixColor;
hc.mix = mix;
hc.r = 0;
hc.g = 0;
hc.b = 0;
hc.alpha = alpha;
SetUserInstructionHighlight(arch, addr, hc);
}
void Function::SetUserInstructionHighlight(Architecture* arch, uint64_t addr, uint8_t r, uint8_t g, uint8_t b,
uint8_t alpha)
{
BNHighlightColor hc;
hc.style = CustomHighlightColor;
hc.color = NoHighlightColor;
hc.mixColor = NoHighlightColor;
hc.mix = 0;
hc.r = r;
hc.g = g;
hc.b = b;
hc.alpha = alpha;
SetUserInstructionHighlight(arch, addr, hc);
}
std::vector Function::GetAllTagReferences()
{
size_t count;
BNTagReference* refs = BNGetFunctionAllTagReferences(m_object, &count);
return TagReference::ConvertAndFreeTagReferenceList(refs, count);
}
std::vector Function::GetTagReferencesOfType(Ref tagType)
{
size_t count;
BNTagReference* refs = BNGetFunctionTagReferencesOfType(m_object, tagType->GetObject(), &count);
return TagReference::ConvertAndFreeTagReferenceList(refs, count);
}
std::vector Function::GetAddressTagReferences()
{
size_t count;
BNTagReference* refs = BNGetAddressTagReferences(m_object, &count);
return TagReference::ConvertAndFreeTagReferenceList(refs, count);
}
std::vector][> Function::GetAddressTags(Architecture* arch, uint64_t addr)
{
size_t count;
BNTag** tags = BNGetAddressTags(m_object, arch->GetObject(), addr, &count);
return Tag::ConvertAndFreeTagList(tags, count);
}
std::vector][> Function::GetAddressTagsOfType(Architecture* arch, uint64_t addr, Ref tagType)
{
size_t count;
BNTag** tags = BNGetAddressTagsOfType(m_object, arch->GetObject(), addr, tagType->GetObject(), &count);
return Tag::ConvertAndFreeTagList(tags, count);
}
void Function::AddAutoAddressTag(Architecture* arch, uint64_t addr, Ref tag)
{
BNAddAutoAddressTag(m_object, arch->GetObject(), addr, tag->GetObject());
}
void Function::RemoveAutoAddressTag(Architecture* arch, uint64_t addr, Ref tag)
{
BNRemoveAutoAddressTag(m_object, arch->GetObject(), addr, tag->GetObject());
}
void Function::AddUserAddressTag(Architecture* arch, uint64_t addr, Ref tag)
{
BNAddUserAddressTag(m_object, arch->GetObject(), addr, tag->GetObject());
}
void Function::RemoveUserAddressTag(Architecture* arch, uint64_t addr, Ref tag)
{
BNRemoveUserAddressTag(m_object, arch->GetObject(), addr, tag->GetObject());
}
std::vector Function::GetFunctionTagReferences()
{
size_t count;
BNTagReference* refs = BNGetFunctionTagReferences(m_object, &count);
return TagReference::ConvertAndFreeTagReferenceList(refs, count);
}
std::vector][> Function::GetFunctionTags()
{
size_t count;
BNTag** tags = BNGetFunctionTags(m_object, &count);
return Tag::ConvertAndFreeTagList(tags, count);
}
std::vector][> Function::GetFunctionTagsOfType(Ref tagType)
{
size_t count;
BNTag** tags = BNGetFunctionTagsOfType(m_object, tagType->GetObject(), &count);
return Tag::ConvertAndFreeTagList(tags, count);
}
void Function::AddAutoFunctionTag(Ref tag)
{
BNAddAutoFunctionTag(m_object, tag->GetObject());
}
void Function::RemoveAutoFunctionTag(Ref tag)
{
BNRemoveAutoFunctionTag(m_object, tag->GetObject());
}
void Function::AddUserFunctionTag(Ref tag)
{
BNAddUserFunctionTag(m_object, tag->GetObject());
}
void Function::RemoveUserFunctionTag(Ref tag)
{
BNRemoveUserFunctionTag(m_object, tag->GetObject());
}
Ref Function::CreateAutoAddressTag(Architecture* arch, uint64_t addr, const std::string& tagTypeName, const std::string& data, bool unique)
{
Ref tagType = GetView()->GetTagType(tagTypeName);
if (!tagType)
return nullptr;
return CreateAutoAddressTag(arch, addr, tagType, data, unique);
}
Ref Function::CreateAutoAddressTag(Architecture* arch, uint64_t addr, Ref tagType, const std::string& data, bool unique)
{
if (unique)
{
auto tags = GetAddressTags(arch, addr);
for (const auto& tag : tags)
{
if (tag->GetType() == tagType && tag->GetData() == data)
return nullptr;
}
}
Ref tag = new Tag(tagType, data);
GetView()->AddTag(tag);
AddAutoAddressTag(arch, addr, tag);
return tag;
}
Ref Function::CreateUserAddressTag(Architecture* arch, uint64_t addr, const std::string& tagTypeName, const std::string& data, bool unique)
{
Ref tagType = GetView()->GetTagType(tagTypeName);
if (!tagType)
return nullptr;
return CreateUserAddressTag(arch, addr, tagType, data, unique);
}
Ref Function::CreateUserAddressTag(Architecture* arch, uint64_t addr, Ref tagType, const std::string& data, bool unique)
{
if (unique)
{
auto tags = GetAddressTags(arch, addr);
for (const auto& tag : tags)
{
if (tag->GetType() == tagType && tag->GetData() == data)
return nullptr;
}
}
Ref tag = new Tag(tagType, data);
GetView()->AddTag(tag);
AddUserAddressTag(arch, addr, tag);
return tag;
}
Ref Function::CreateAutoFunctionTag(const std::string& tagTypeName, const std::string& data, bool unique)
{
Ref tagType = GetView()->GetTagType(tagTypeName);
if (!tagType)
return nullptr;
return CreateAutoFunctionTag(tagType, data, unique);
}
Ref Function::CreateAutoFunctionTag(Ref tagType, const std::string& data, bool unique)
{
if (unique)
{
auto tags = GetFunctionTags();
for (const auto& tag : tags)
{
if (tag->GetType() == tagType && tag->GetData() == data)
return nullptr;
}
}
Ref tag = new Tag(tagType, data);
GetView()->AddTag(tag);
AddAutoFunctionTag(tag);
return tag;
}
Ref Function::CreateUserFunctionTag(const std::string& tagTypeName, const std::string& data, bool unique)
{
Ref tagType = GetView()->GetTagType(tagTypeName);
if (!tagType)
return nullptr;
return CreateUserFunctionTag(tagType, data, unique);
}
Ref Function::CreateUserFunctionTag(Ref tagType, const std::string& data, bool unique)
{
if (unique)
{
auto tags = GetFunctionTags();
for (const auto& tag : tags)
{
if (tag->GetType() == tagType && tag->GetData() == data)
return nullptr;
}
}
Ref tag = new Tag(tagType, data);
GetView()->AddTag(tag);
AddUserFunctionTag(tag);
return tag;
}
Confidence Function::GetGlobalPointerValue() const
{
BNRegisterValueWithConfidence value = BNGetFunctionGlobalPointerValue(m_object);
return Confidence(RegisterValue::FromAPIObject(value.value), value.confidence);
}
Confidence Function::GetRegisterValueAtExit(uint32_t reg) const
{
BNRegisterValueWithConfidence value = BNGetFunctionRegisterValueAtExit(m_object, reg);
return Confidence(RegisterValue::FromAPIObject(value.value), value.confidence);
}
void Function::Reanalyze()
{
BNReanalyzeFunction(m_object);
}
void Function::RequestAdvancedAnalysisData()
{
BNRequestAdvancedFunctionAnalysisData(m_object);
#ifdef WIN32
InterlockedIncrement((LONG*)&m_advancedAnalysisRequests);
#else
__sync_fetch_and_add(&m_advancedAnalysisRequests, 1);
#endif
}
void Function::ReleaseAdvancedAnalysisData()
{
BNReleaseAdvancedFunctionAnalysisData(m_object);
#ifdef WIN32
InterlockedDecrement((LONG*)&m_advancedAnalysisRequests);
#else
__sync_fetch_and_add(&m_advancedAnalysisRequests, -1);
#endif
}
map Function::GetAnalysisPerformanceInfo()
{
size_t count;
BNPerformanceInfo* info = BNGetFunctionAnalysisPerformanceInfo(m_object, &count);
map result;
for (size_t i = 0; i < count; i++)
result[info[i].name] = info[i].seconds;
BNFreeAnalysisPerformanceInfo(info, count);
return result;
}
vector Function::GetTypeTokens(DisassemblySettings* settings)
{
size_t count;
BNDisassemblyTextLine* lines = BNGetFunctionTypeTokens(m_object,
settings ? settings->GetObject() : nullptr, &count);
vector result;
result.reserve(count);
for (size_t i = 0; i < count; i++)
{
DisassemblyTextLine line;
line.addr = lines[i].addr;
line.instrIndex = lines[i].instrIndex;
line.highlight = lines[i].highlight;
line.tokens = InstructionTextToken::ConvertInstructionTextTokenList(lines[i].tokens, lines[i].count);
line.tags = Tag::ConvertTagList(lines[i].tags, lines[i].tagCount);
result.push_back(line);
}
BNFreeDisassemblyTextLines(lines, count);
return result;
}
bool Function::IsFunctionTooLarge()
{
return BNIsFunctionTooLarge(m_object);
}
bool Function::IsAnalysisSkipped()
{
return BNIsFunctionAnalysisSkipped(m_object);
}
BNAnalysisSkipReason Function::GetAnalysisSkipReason()
{
return BNGetAnalysisSkipReason(m_object);
}
BNFunctionAnalysisSkipOverride Function::GetAnalysisSkipOverride()
{
return BNGetFunctionAnalysisSkipOverride(m_object);
}
void Function::SetAnalysisSkipOverride(BNFunctionAnalysisSkipOverride skip)
{
BNSetFunctionAnalysisSkipOverride(m_object, skip);
}
Ref Function::GetUnresolvedStackAdjustmentGraph()
{
BNFlowGraph* graph = BNGetUnresolvedStackAdjustmentGraph(m_object);
if (!graph)
return nullptr;
return new CoreFlowGraph(graph);
}
void Function::RequestDebugReport(const string& name)
{
BNRequestFunctionDebugReport(m_object, name.c_str());
}
AdvancedFunctionAnalysisDataRequestor::AdvancedFunctionAnalysisDataRequestor(Function* func): m_func(func)
{
if (m_func)
m_func->RequestAdvancedAnalysisData();
}
AdvancedFunctionAnalysisDataRequestor::AdvancedFunctionAnalysisDataRequestor(const AdvancedFunctionAnalysisDataRequestor& req)
{
m_func = req.m_func;
if (m_func)
m_func->RequestAdvancedAnalysisData();
}
AdvancedFunctionAnalysisDataRequestor::~AdvancedFunctionAnalysisDataRequestor()
{
if (m_func)
m_func->ReleaseAdvancedAnalysisData();
}
AdvancedFunctionAnalysisDataRequestor& AdvancedFunctionAnalysisDataRequestor::operator=(
const AdvancedFunctionAnalysisDataRequestor& req)
{
SetFunction(req.m_func);
return *this;
}
void AdvancedFunctionAnalysisDataRequestor::SetFunction(Function* func)
{
if (m_func)
m_func->ReleaseAdvancedAnalysisData();
m_func = func;
if (m_func)
m_func->RequestAdvancedAnalysisData();
}
]