def trace(self, *args, **kwargs): """ Given args and kwargs, call the Python function and get its symbolic representation. A dictionary of shadowed symbolic variables is maintained: self.s_vars : {id(obj) : sym_var} Contains all symbolic variables traced during function execution, indexed by the id of the corresponding Python object. Additionally, self.s_inputs and self.s_outputs are lists of symbolic arguments and results, respectively. """ # clean args and kwargs c_args, c_kwargs = clean_int_args(*args, **kwargs) # call the Context results = self.context.call(self.pyfn, c_args, c_kwargs) # get a tuple of the symbolic inputs # but avoid 'self' and 'cls' bound arguments callargs = utils.orderedcallargs(self.pyfn, *c_args, **c_kwargs) all_args = utils.flat_from_doc(callargs) if (inspect.ismethod(self.pyfn) or (len(all_args) > 0 and type(all_args[0]) is type)): all_args = all_args[1:] self.s_inputs = tuple([self.s_vars[id(a)] for a in all_args]) # get a tuple of the symbolic outputs self.s_outputs = tuple( [self.s_vars[id(r)] for r in utils.as_seq(results)]) # update variable names where possible for name, arg in callargs.iteritems(): if self.s_vars.get(id(arg), None) in self.s_inputs: self.s_vars[name] = self.s_vars[id(arg)] return results
def call(self, args, kwargs): if not isinstance(args, tuple): raise TypeError('vm.call: args must be tuple', args) if not isinstance(kwargs, dict): raise TypeError('vm.call: kwargs must be dict', kwargs) func = self.func if isinstance(func, type) and issubclass(func, BaseException): # XXX not shadowing exception creation, because exceptions # do not have func_code. Is this OK? can we do better? return func(*args, **kwargs) func_code = self.func.func_code self._myglobals = {} self._locals = [] for name in func_code.co_names: #print 'name', name try: self._myglobals[name] = func.func_globals[name] except KeyError: try: self._myglobals[name] = __builtin__.__getattribute__(name) except AttributeError: #print 'WARNING: name lookup failed', name pass # get function arguments argspec = inspect.getargspec(func) # match function arguments to passed parameters callargs = orderedcallargs(func, *args, **kwargs) # named args => locals self._locals.extend(callargs[arg] for arg in argspec.args) # *args => locals if argspec.varargs: self._locals.append(callargs[argspec.varargs]) # **kwargs => locals if argspec.keywords: self._locals.append(callargs[argspec.keywords]) # other vars => locals no_unbound_args = len(func_code.co_varnames) - len(self._locals) self._locals.extend([Unassigned] * no_unbound_args) # shadow arguments for val in flat_from_doc(callargs): if id(val) not in self.watcher: self.add_shadow(val) self.code_iter = itercode(func_code.co_code) jmp = None while not hasattr(self, 'rval'): try: i, op, arg = self.code_iter.send(jmp) except StopIteration: break name = opcode.opname[op] # method names can't have '+' in them name = {'SLICE+0': 'SLICE_PLUS_0', 'SLICE+1': 'SLICE_PLUS_1', 'SLICE+2': 'SLICE_PLUS_2', 'SLICE+3': 'SLICE_PLUS_3', 'STORE_SLICE+0': 'STORE_SLICE_PLUS_0', 'STORE_SLICE+1': 'STORE_SLICE_PLUS_1', 'STORE_SLICE+2': 'STORE_SLICE_PLUS_2', 'STORE_SLICE+3': 'STORE_SLICE_PLUS_3', }.get(name, name) if self.print_ops: print 'OP: ', i, name if self.print_stack: print self.stack try: op_method = getattr(self, 'op_' + name) except AttributeError: raise AttributeError('FrameVM does not have a method defined ' 'for \'op_{0}\''.format(name)) except: raise jmp = op_method(i, op, arg) return self.rval
def call(self, args, kwargs): if not isinstance(args, tuple): raise TypeError('vm.call: args must be tuple', args) if not isinstance(kwargs, dict): raise TypeError('vm.call: kwargs must be dict', kwargs) func = self.func if isinstance(func, type) and issubclass(func, BaseException): # XXX not shadowing exception creation, because exceptions # do not have func_code. Is this OK? can we do better? return func(*args, **kwargs) func_code = self.func.func_code self._myglobals = {} self._locals = [] for name in func_code.co_names: #print 'name', name try: self._myglobals[name] = func.func_globals[name] except KeyError: try: self._myglobals[name] = __builtin__.__getattribute__(name) except AttributeError: #print 'WARNING: name lookup failed', name pass # get function arguments argspec = inspect.getargspec(func) # match function arguments to passed parameters callargs = orderedcallargs(func, *args, **kwargs) # named args => locals self._locals.extend(callargs[arg] for arg in argspec.args) # *args => locals if argspec.varargs: self._locals.append(callargs[argspec.varargs]) # **kwargs => locals if argspec.keywords: self._locals.append(callargs[argspec.keywords]) # other vars => locals no_unbound_args = len(func_code.co_varnames) - len(self._locals) self._locals.extend([Unassigned] * no_unbound_args) # shadow arguments for val in flat_from_doc(callargs): if id(val) not in self.watcher: self.add_shadow(val) self.code_iter = itercode(func_code.co_code) jmp = None while not hasattr(self, 'rval'): try: i, op, arg = self.code_iter.send(jmp) except StopIteration: break name = opcode.opname[op] # method names can't have '+' in them name = { 'SLICE+0': 'SLICE_PLUS_0', 'SLICE+1': 'SLICE_PLUS_1', 'SLICE+2': 'SLICE_PLUS_2', 'SLICE+3': 'SLICE_PLUS_3', 'STORE_SLICE+0': 'STORE_SLICE_PLUS_0', 'STORE_SLICE+1': 'STORE_SLICE_PLUS_1', 'STORE_SLICE+2': 'STORE_SLICE_PLUS_2', 'STORE_SLICE+3': 'STORE_SLICE_PLUS_3', }.get(name, name) if self.print_ops: print 'OP: ', i, name if self.print_stack: print self.stack try: op_method = getattr(self, 'op_' + name) except AttributeError: raise AttributeError('FrameVM does not have a method defined ' 'for \'op_{0}\''.format(name)) except: raise jmp = op_method(i, op, arg) return self.rval