summaryrefslogtreecommitdiff
path: root/python/function.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/function.py')
-rw-r--r--python/function.py200
1 files changed, 148 insertions, 52 deletions
diff --git a/python/function.py b/python/function.py
index 8c9eaf1d..900aa0de 100644
--- a/python/function.py
+++ b/python/function.py
@@ -29,7 +29,7 @@ from . import _binaryninjacore as core
from .enums import (
AnalysisSkipReason, FunctionGraphType, SymbolType, SymbolBinding, InstructionTextTokenType, HighlightStandardColor,
HighlightColorStyle, DisassemblyOption, IntegerDisplayType, FunctionAnalysisSkipOverride, FunctionUpdateType,
- BuiltinType, ExprFolding, EarlyReturn, SwitchRecovery
+ BuiltinType, ExprFolding, EarlyReturn, SwitchRecovery, VariableSourceType
)
from . import associateddatastore # Required in the main scope due to being an argument for _FunctionAssociatedDataStore
@@ -1361,8 +1361,49 @@ class Function:
core.BNSetUserFunctionReturnType(self.handle, type_conf)
@property
+ def return_value(self) -> 'types.ReturnValue':
+ """Return type and location"""
+ ret = core.BNGetFunctionReturnValue(self.handle)
+ result = types.ReturnValue._from_core_struct(ret, self.arch)
+ core.BNFreeReturnValue(ret)
+ return result
+
+ @return_value.setter
+ def return_value(self, value: 'types.ReturnValue') -> None: # type: ignore
+ ret = value._to_core_struct()
+ core.BNSetUserFunctionReturnValue(self.handle, ret)
+
+ @property
+ def return_value_location(self) -> Optional['types.ValueLocationWithConfidence']:
+ """
+ The location of the return value, or None if there isn't a return value. If the return value has been
+ specified to be placed in the default location, this will return the default location.
+ """
+ location = core.BNGetFunctionReturnValueLocation(self.handle)
+ if location.location.count == 0:
+ result = None
+ else:
+ result = types.ValueLocation._from_core_struct(location.location, self.arch).with_confidence(location.confidence)
+ core.BNFreeValueLocation(location.location)
+ return result
+
+ @return_value_location.setter
+ def return_value_location(self, value: 'types.OptionalLocation'):
+ struct = core.BNValueLocationWithConfidence()
+ location = types.ValueLocationWithConfidence.from_optional_location(value)
+ if location is None:
+ struct.location.count = 0
+ struct.confidence = 0
+ else:
+ struct.location = location.location._to_core_struct()
+ struct.confidence = location.confidence
+ core.BNSetUserIsFunctionReturnValueDefaultLocation(self.handle, value is None)
+ if value is not None:
+ core.BNSetUserFunctionReturnValueLocation(self.handle, struct)
+
+ @property
def return_regs(self) -> 'types.RegisterSet':
- """Registers that are used for the return value"""
+ """Registers that are used for the return value (read-only)"""
result = core.BNGetFunctionReturnRegisters(self.handle)
assert result is not None, "core.BNGetFunctionReturnRegisters returned None"
try:
@@ -1373,26 +1414,13 @@ class Function:
finally:
core.BNFreeRegisterSet(result)
- @return_regs.setter
- def return_regs(self, value: Union['types.RegisterSet', List['architecture.RegisterType']]) -> None: # type: ignore
- regs = core.BNRegisterSetWithConfidence()
- regs.regs = (ctypes.c_uint * len(value))()
- regs.count = len(value)
- for i in range(0, len(value)):
- regs.regs[i] = self.arch.get_reg_index(value[i])
- if isinstance(value, types.RegisterSet):
- regs.confidence = value.confidence
- else:
- regs.confidence = core.max_confidence
- core.BNSetUserFunctionReturnRegisters(self.handle, regs)
-
@property
def calling_convention(self) -> Optional['callingconvention.CallingConvention']:
"""Calling convention used by the function"""
result = core.BNGetFunctionCallingConvention(self.handle)
if not result.convention:
return None
- return callingconvention.CallingConvention(None, handle=result.convention, confidence=result.confidence)
+ return callingconvention.CoreCallingConvention(handle=result.convention, confidence=result.confidence)
@calling_convention.setter
def calling_convention(self, value: Optional['callingconvention.CallingConvention']) -> None:
@@ -1424,20 +1452,60 @@ class Function:
var_list = []
else:
var_list = list(value)
- var_conf = core.BNParameterVariablesWithConfidence()
- var_conf.vars = (core.BNVariable * len(var_list))()
- var_conf.count = len(var_list)
- for i in range(0, len(var_list)):
- var_conf.vars[i].type = var_list[i].source_type
- var_conf.vars[i].index = var_list[i].index
- var_conf.vars[i].storage = var_list[i].storage
+ locations = []
+ for i in range(len(var_list)):
+ if (var_list[i].source_type != VariableSourceType.RegisterVariableSourceType and
+ var_list[i].source_type != VariableSourceType.StackVariableSourceType and
+ var_list[i].source_type != VariableSourceType.FlagVariableSourceType):
+ raise ValueError(f"Parameter {i} is a composite variable. Use parameter_locations instead.")
+ locations.append(types.ValueLocation([types.ValueLocationComponent(var_list[i])]))
if value is None:
- var_conf.confidence = 0
- elif isinstance(value, types.RegisterSet):
- var_conf.confidence = value.confidence
+ conf = 0
+ elif isinstance(value, variable.ParameterVariables):
+ conf = value.confidence
else:
- var_conf.confidence = core.max_confidence
- core.BNSetUserFunctionParameterVariables(self.handle, var_conf)
+ conf = core.max_confidence
+ self.parameter_locations = variable.ParameterLocations(locations, conf, self)
+
+ @property
+ def parameter_locations(self) -> 'variable.ParameterLocations':
+ """List of locations for the incoming function parameters"""
+ result = core.BNGetFunctionParameterLocations(self.handle)
+ location_list = []
+ for i in range(0, result.count):
+ location_list.append(types.ValueLocation._from_core_struct(result.locations[i], self.arch))
+ confidence = result.confidence
+ core.BNFreeParameterLocations(result)
+ return variable.ParameterLocations(location_list, confidence, self)
+
+ @parameter_locations.setter
+ def parameter_locations(
+ self, value: Optional[Union[List[Union['types.ValueLocation', 'variable.CoreVariable']],
+ 'variable.CoreVariable', 'variable.ParameterLocations']]
+ ) -> None: # type: ignore
+ if value is None:
+ location_list = []
+ elif isinstance(value, variable.CoreVariable):
+ location_list = [value]
+ elif isinstance(value, variable.ParameterLocations):
+ location_list = value.locations
+ else:
+ location_list = list(value)
+ location_conf = core.BNValueLocationListWithConfidence()
+ location_conf.locations = (core.BNValueLocation * len(location_list))()
+ location_conf.count = len(location_list)
+ for i in range(0, len(location_list)):
+ if isinstance(location_list[i], types.ValueLocation):
+ location_conf.locations[i] = location_list[i]._to_core_struct()
+ else:
+ location_conf.locations[i] = types.ValueLocation([types.ValueLocationComponent(location_list[i])])._to_core_struct()
+ if value is None:
+ location_conf.confidence = 0
+ elif isinstance(value, variable.ParameterLocations):
+ location_conf.confidence = value.confidence
+ else:
+ location_conf.confidence = core.max_confidence
+ core.BNSetUserFunctionParameterLocations(self.handle, location_conf)
@property
def has_variable_arguments(self) -> 'types.BoolWithConfidence':
@@ -2477,18 +2545,18 @@ class Function:
type_conf.confidence = value.confidence
core.BNSetAutoFunctionReturnType(self.handle, type_conf)
- def set_auto_return_regs(self, value: Union['types.RegisterSet', List['architecture.RegisterType']]) -> None:
- regs = core.BNRegisterSetWithConfidence()
- regs.regs = (ctypes.c_uint * len(value))()
- regs.count = len(value)
-
- for i in range(0, len(value)):
- regs.regs[i] = self.arch.get_reg_index(value[i])
- if isinstance(value, types.RegisterSet):
- regs.confidence = value.confidence
+ def set_auto_return_value_location(self, value: 'types.OptionalLocation'):
+ struct = core.BNValueLocationWithConfidence()
+ location = types.ValueLocationWithConfidence.from_optional_location(value)
+ if location is None:
+ struct.location.count = 0
+ struct.confidence = 0
else:
- regs.confidence = core.max_confidence
- core.BNSetAutoFunctionReturnRegisters(self.handle, regs)
+ struct.location = location.location._to_core_struct()
+ struct.confidence = location.confidence
+ core.BNSetAutoIsFunctionReturnValueDefaultLocation(self.handle, value is None)
+ if value is not None:
+ core.BNSetAutoFunctionReturnValueLocation(self.handle, struct)
def set_auto_calling_convention(self, value: 'callingconvention.CallingConvention') -> None:
conv_conf = core.BNCallingConventionWithConfidence()
@@ -2501,30 +2569,58 @@ class Function:
core.BNSetAutoFunctionCallingConvention(self.handle, conv_conf)
def set_auto_parameter_vars(
- self, value: Optional[Union[List['variable.Variable'], 'variable.Variable', 'variable.ParameterVariables']]
+ self, value: Optional[Union[List['variable.CoreVariable'], 'variable.CoreVariable', 'variable.ParameterVariables']]
) -> None:
if value is None:
var_list = []
- elif isinstance(value, variable.Variable):
+ elif isinstance(value, variable.CoreVariable):
var_list = [value]
elif isinstance(value, variable.ParameterVariables):
var_list = value.vars
else:
var_list = list(value)
- var_conf = core.BNParameterVariablesWithConfidence()
- var_conf.vars = (core.BNVariable * len(var_list))()
- var_conf.count = len(var_list)
- for i in range(0, len(var_list)):
- var_conf.vars[i].type = var_list[i].source_type
- var_conf.vars[i].index = var_list[i].index
- var_conf.vars[i].storage = var_list[i].storage
+ locations = []
+ for i in range(len(var_list)):
+ if (var_list[i].source_type != VariableSourceType.RegisterVariableSourceType and
+ var_list[i].source_type != VariableSourceType.StackVariableSourceType and
+ var_list[i].source_type != VariableSourceType.FlagVariableSourceType):
+ raise ValueError(f"Parameter {i} is a composite variable. Use set_auto_parameter_locations instead.")
+ locations.append(types.ValueLocation([types.ValueLocationComponent(var_list[i])]))
+ if value is None:
+ conf = 0
+ elif isinstance(value, variable.ParameterVariables):
+ conf = value.confidence
+ else:
+ conf = core.max_confidence
+ self.set_auto_parameter_locations(variable.ParameterLocations(locations, conf, self))
+
+ def set_auto_parameter_locations(
+ self, value: Optional[Union[List[Union['variable.CoreVariable', 'types.ValueLocation']],
+ 'variable.CoreVariable', 'types.ValueLocation', 'variable.ParameterLocations']]
+ ) -> None:
+ if value is None:
+ location_list = []
+ elif isinstance(value, variable.CoreVariable):
+ location_list = [value]
+ elif isinstance(value, variable.ParameterLocations):
+ location_list = value.locations
+ else:
+ location_list = list(value)
+ location_conf = core.BNValueLocationListWithConfidence()
+ location_conf.locations = (core.BNValueLocation * len(location_list))()
+ location_conf.count = len(location_list)
+ for i in range(0, len(location_list)):
+ if isinstance(location_list[i], types.ValueLocation):
+ location_conf.locations[i] = location_list[i]._to_core_struct()
+ else:
+ location_conf.locations[i] = types.ValueLocation([types.ValueLocationComponent(location_list[i])])._to_core_struct()
if value is None:
- var_conf.confidence = 0
+ location_conf.confidence = 0
elif isinstance(value, variable.ParameterVariables):
- var_conf.confidence = value.confidence
+ location_conf.confidence = value.confidence
else:
- var_conf.confidence = core.max_confidence
- core.BNSetAutoFunctionParameterVariables(self.handle, var_conf)
+ location_conf.confidence = core.max_confidence
+ core.BNSetAutoFunctionParameterLocations(self.handle, location_conf)
def set_auto_has_variable_arguments(self, value: Union[bool, 'types.BoolWithConfidence']) -> None:
bc = core.BNBoolWithConfidence()