[docs]classCallable:""" Callable is a representation of a function in the binary that can be interacted with like a native python function. If you set perform_merge=True (the default), the result will be returned to you, and you can get the result state with callable.result_state. Otherwise, you can get the resulting simulation manager at callable.result_path_group. """
[docs]def__init__(self,project,addr,prototype=None,concrete_only=False,perform_merge=True,base_state=None,toc=None,cc=None,add_options=None,remove_options=None,):""" :param project: The project to operate on :param addr: The address of the function to use The following parameters are optional: :param prototype: The signature of the calls you would like to make. This really shouldn't be optional. :param concrete_only: Throw an exception if the execution splits into multiple paths :param perform_merge: Merge all result states into one at the end (only relevant if concrete_only=False) :param base_state: The state from which to do these runs :param toc: The address of the table of contents for ppc64 :param cc: The SimCC to use for a calling convention """self._project=projectself._addr=addrself._concrete_only=concrete_onlyself._perform_merge=perform_mergeself._base_state=base_stateself._toc=tocself._cc=(ccifccisnotNoneelsedefault_cc(project.arch.name,platform=project.simos.nameifproject.simosisnotNoneelseNone)(project.arch))self._deadend_addr=project.simos.return_deadendself._func_ty=prototypeself._add_options=add_optionsifadd_optionselseset()self._remove_options=remove_optionsifremove_optionselseset()self.result_path_group=Noneself.result_state=None
[docs]defset_base_state(self,state):""" Swap out the state you'd like to use to perform the call :param state: The state to use to perform the call """self._base_state=state
[docs]defperform_call(self,*args,prototype=None):prototype=SimCC.guess_prototype(args,prototypeorself._func_ty).with_arch(self._project.arch)state=self._project.factory.call_state(self._addr,*args,prototype=prototype,cc=self._cc,base_state=self._base_state,ret_addr=self._deadend_addr,toc=self._toc,add_options=self._add_options,remove_options=self._remove_options,)defstep_func(pg):pg2=pg.prune()iflen(pg2.active)>1:raiseAngrCallableMultistateError("Execution split on symbolic condition!")returnpg2caller=self._project.factory.simulation_manager(state)caller.run(step_func=step_funcifself._concrete_onlyelseNone).unstash(from_stash="deadended")caller.prune(filter_func=lambdapt:pt.addr==self._deadend_addr)iflen(caller.active)==0:raiseAngrCallableError("No paths returned from function")self.result_path_group=caller.copy()ifself._perform_merge:caller.merge()self.result_state=caller.active[0]eliflen(caller.active)==1:self.result_state=caller.active[0]
[docs]defcall_c(self,c_args):""" Call this Callable with a string of C-style arguments. :param str c_args: C-style arguments. :return: The return value from the call. :rtype: claripy.Ast """c_args=c_args.strip()ifc_args[0]!="(":c_args="("+c_argsifc_args[-1]!=")":c_args+=")"# Parse argumentscontent="int main() { func%s; }"%c_argsast=pycparser.CParser().parse(content)ifnotast.extornotisinstance(ast.ext[0],pycparser.c_ast.FuncDef):raiseAngrCallableError("Error in parsing the given C-style argument string.")ifnotast.ext[0].body.block_itemsornotisinstance(ast.ext[0].body.block_items[0],pycparser.c_ast.FuncCall):raiseAngrCallableError("Error in parsing the given C-style argument string: Cannot find the expected function call.")arg_exprs=ast.ext[0].body.block_items[0].args.exprsargs=[]forexprinarg_exprs:ifisinstance(expr,pycparser.c_ast.Constant):# stringifexpr.type=="string":args.append(expr.value[1:-1])elifexpr.type=="int":args.append(int(expr.value))else:raiseAngrCallableError("Unsupported expression type %s."%expr.type)else:raiseAngrCallableError("Unsupported expression type %s."%type(expr))returnself.__call__(*args)