def test_packing_lines(self): from bytecode.tests.long_lines_example import long_lines import dis line_starts = list(dis.findlinestarts(long_lines.__code__)) concrete = ConcreteBytecode.from_code(long_lines.__code__) as_code = concrete.to_code() self.assertEqual(line_starts, list(dis.findlinestarts(as_code)))
def trace(aFrame, aEvent, aArg): theCode = aFrame.f_code if aEvent == 'call': print len(dis.findlinestarts(theCode)) for theTuple in dis.findlinestarts(theCode): print theTuple print dis.dis(theCode) print len(theCode.co_code) raw_input() elif aEvent == 'line': pass elif aEvent == 'return': pass elif aEvent == 'exception': pass
def _get_instructions(co): code = co.co_code linestarts = dict(findlinestarts(co)) n = len(code) i = 0 extended_arg = 0 while i < n: offset = i c = code[i] op = ord(c) lineno = linestarts.get(i) argval = None i = i + 1 if op >= HAVE_ARGUMENT: oparg = ord(code[i]) + ord(code[i + 1]) * 256 + extended_arg extended_arg = 0 i = i + 2 if op == EXTENDED_ARG: extended_arg = oparg * 65536 if op in hasconst: argval = co.co_consts[oparg] elif op in hasname: argval = co.co_names[oparg] elif opname[op] == 'LOAD_FAST': argval = co.co_varnames[oparg] yield Instruction(offset, argval, opname[op], lineno)
def serialize_frames(current_frame, current_tb): for frame, lno in iter_stack(current_frame, current_tb): code = frame.f_code filename = code.co_filename or "<unspecified>" if filename == "<frozen importlib._bootstrap>": filename = os.path.join( os.path.dirname(linecache.__file__), "importlib", "_bootstrap.py", ) fn = Path(filename) if not filename.startswith("<"): fn = fn.resolve() line = None linecache.checkcache(filename) line = linecache.getline(filename, lno, frame.f_globals) line = line and line.strip() startlnos = dis.findlinestarts(code) lastlineno = list(startlnos)[-1][1] yield { "key": id(frame), "absoluteFilename": str(fn), "filename": fn.name, "function": code.co_name, "firstFunctionLineNumber": code.co_firstlineno, "lastFunctionLineNumber": lastlineno, "lineNumber": lno, "lineSource": line, "active": frame == current_frame, }
def get_offset_for_line(co, line): for (offset, l) in dis.findlinestarts(co): if l == line: return offset while l > line: break return -1
def warnAboutFunction(offender, warningString): """ Issue a warning string, identifying C{offender} as the responsible code. This function is used to deprecate some behavior of a function. It differs from L{warnings.warn} in that it is not limited to deprecating the behavior of a function currently on the call stack. @param function: The function that is being deprecated. @param warningString: The string that should be emitted by this warning. @type warningString: C{str} @since: 11.0 """ # inspect.getmodule() is attractive, but somewhat # broken in Python < 2.6. See Python bug 4845. offenderModule = sys.modules[offender.__module__] filename = inspect.getabsfile(offenderModule) lineStarts = list(findlinestarts(offender.func_code)) lastLineNo = lineStarts[-1][1] globals = offender.func_globals kwargs = dict( category=DeprecationWarning, filename=filename, lineno=lastLineNo, module=offenderModule.__name__, registry=globals.setdefault("__warningregistry__", {}), module_globals=None) if sys.version_info[:2] < (2, 5): kwargs.pop('module_globals') warn_explicit(warningString, **kwargs)
def __init__(self, py_code): import dis self.function_name = py_code.co_name self.filename = py_code.co_filename sorted_offset_lineno = list(dis.findlinestarts(py_code)) self._sorted_offsets = [ol[0] for ol in sorted_offset_lineno] self._sorted_lines = [ol[1] for ol in sorted_offset_lineno]
def build_line_to_contents(self): co = self.co firstlineno = self.firstlineno # print('----') # for instruction in self.instructions: # print(instruction) # print('----\n\n') op_offset_to_line = dict(dis.findlinestarts(co)) curr_line_index = 0 line_to_contents = {} instructions = self.instructions while instructions: instruction = instructions[0] new_line_index = op_offset_to_line.get(instruction.offset) if new_line_index is not None: if new_line_index is not None: curr_line_index = new_line_index - firstlineno lst = line_to_contents.setdefault(curr_line_index, []) lst.append(self._next_instruction_to_str(line_to_contents)) return line_to_contents
def find_lines_from_code(code, strs): linenos = {} for _, lineno in dis.findlinestarts(code): if lineno not in strs: linenos[lineno] = 1 return linenos
def lasti2lineno(code, lasti): linestarts = list(dis.findlinestarts(code)) linestarts.reverse() for i, lineno in linestarts: if lasti >= i: return lineno return 0
def lasti2lineno(code, lasti): linestarts = list(dis.findlinestarts(code)) linestarts.reverse() for (i, lineno) in linestarts: while lasti >= i: return lineno return 0
def disassemble(code: str, scope: Scope = None, arg_dict: dict = None): """ Disassembles asynchronous code into dis.dis-style bytecode instructions. """ # Similar to AsyncCodeExecutor.__init__ arg_names = list(arg_dict.keys()) if arg_dict else [] scope = scope or Scope() wrapped = wrap_code(code, args=', '.join(arg_names)) exec(compile(wrapped, '<repl>', 'exec'), scope.globals, scope.locals) func_def = scope.locals.get( '_repl_coroutine') or scope.globals['_repl_coroutine'] co = func_def.__code__ for instruction in dis._get_instructions_bytes( co.co_code, co.co_varnames, co.co_names, co.co_consts, co.co_cellvars + co.co_freevars, dict(dis.findlinestarts(co)), line_offset=0): if instruction.starts_line is not None and instruction.offset > 0: yield '' yield instruction._disassemble(4, False, 4)
def get_trace(self, frame, tb, w_code=None): frames = [] stack, current = self.get_stack(frame, tb) for i, (frame, lno) in enumerate(stack): code = frame.f_code filename = code.co_filename if filename == "<wdb>" and w_code: line = w_code else: checkcache(filename) line = getline(filename, lno, frame.f_globals) line = line and line.strip() startlnos = dis.findlinestarts(code) lastlineno = list(startlnos)[-1][1] frames.append( { "file": filename, "function": code.co_name, "flno": code.co_firstlineno, "llno": lastlineno, "lno": lno, "code": escape(line), "level": i, } ) return stack, frames, current
def disassemble(msg, msg_nocr, section, co, lasti=-1, start_line=-1, end_line=None, relative_pos=False, highlight='light', start_offset=0, end_offset=None): """Disassemble a code object.""" disassemble_bytes(msg, msg_nocr, co.co_code, lasti, co.co_firstlineno, start_line, end_line, relative_pos, co.co_varnames, co.co_names, co.co_consts, co.co_cellvars, co.co_freevars, dict(findlinestarts(co)), highlight, start_offset=start_offset, end_offset=end_offset) return
def read_code(self): extended_arg = 0 code = self.co_code n = len(code) i = 0 label = 0 lbuffer = [] line = 0 linestarts = dict(dis.findlinestarts(self)) while i < n: if i in linestarts: line = linestarts[i] op = ord(code[i]) i += 1 oparg = None if op >= HAVE_ARGUMENT: oparg = ord(code[i]) + ord(code[i + 1]) * 256 + extended_arg extended_arg = 0 i += 2 if op == EXTENDED_ARG: extended_arg = oparg * 65536 if op != EXTENDED_ARG: yield (label, op, oparg, line) else: # Yield a NOP just in case there's a jump to this label yield (label, NOP, None, line) label += 1 if op >= HAVE_ARGUMENT: label += 2
def run(self, args): """Program counter.""" mainfile = self.core.filename(None) if self.core.is_running(): curframe = self.proc.curframe if curframe: line_no = inspect.getlineno(curframe) offset = curframe.f_lasti self.msg("PC offset is %d." % offset) offset = max(offset, 0) code = curframe.f_code co_code = code.co_code disassemble_bytes(self.msg, self.msg_nocr, co_code, offset, line_no, line_no-1, line_no+1, constants=code.co_consts, cells=code.co_cellvars, varnames=code.co_varnames, freevars=code.co_freevars, linestarts=dict(findlinestarts(code)), end_offset=offset+10) pass pass else: if mainfile: part1 = "Python program '%s'" % mainfile msg = "is not currently running. " self.msg(Mmisc.wrapped_lines(part1, msg, self.settings['width'])) else: self.msg('No Python program is currently running.') pass self.msg(self.core.execution_status) pass return False
def get_trace(self, frame, tb, w_code=None): """Get a dict of the traceback for wdb.js use""" frames = [] stack, current = self.get_stack(frame, tb) for i, (frame, lno) in enumerate(stack): code = frame.f_code filename = code.co_filename if filename == '<wdb>' and w_code: line = w_code else: checkcache(filename) line = getline(filename, lno, frame.f_globals) line = line and line.strip() startlnos = dis.findlinestarts(code) lastlineno = list(startlnos)[-1][1] frames.append({ 'file': filename, 'function': code.co_name, 'flno': code.co_firstlineno, 'llno': lastlineno, 'lno': lno, 'code': line, 'level': i }) return stack, frames, current
def byte_parser(text: str): """Find the offsets in a byte code which are start of lines in the source.""" return [ lineno for code in code_objects(compile(text, '<str>', 'exec')) for _, lineno in findlinestarts(code) ]
def cut_asm(self, line, code): if line == -1: # ignore return code first = 0 last = codesize = len(code.co_code) lines = list(dis.findlinestarts(code)) for pos, (asm_line, src_line) in enumerate(lines): if line != asm_line: continue else: if asm_line == lines[-1][0]: first, last = (asm_line, codesize) else: first, last = (asm_line, lines[pos + 1][0]) break codestr = code.co_code[first:last] # Rebuild code object new_code = type(code)(code.co_argcount, code.co_nlocals, code.co_stacksize, code.co_flags, codestr, code.co_consts, code.co_names, code.co_varnames, code.co_filename, code.co_name, code.co_firstlineno, code.co_lnotab, code.co_freevars, code.co_cellvars) if self.metadebug: dis.disassemble(new_code) return new_code
def get_trace(self, frame, tb): """Get a dict of the traceback for wdb.js use""" import linecache frames = [] stack, _ = self.get_stack(frame, tb) current = 0 for i, (stack_frame, lno) in enumerate(stack): code = stack_frame.f_code filename = code.co_filename linecache.checkcache(filename) line = linecache.getline(filename, lno, stack_frame.f_globals) if not line: line = self.compile_cache.get(id(code), '') line = to_unicode_string(line, filename) line = line and line.strip() startlnos = dis.findlinestarts(code) lastlineno = list(startlnos)[-1][1] if frame == stack_frame: current = i frames.append({ 'file': filename, 'function': code.co_name, 'flno': code.co_firstlineno, 'llno': lastlineno, 'lno': lno, 'code': line, 'level': i, 'current': frame == stack_frame }) # While in exception always put the context to the top return stack, frames, current
def warnAboutFunction(offender, warningString): """ Issue a warning string, identifying C{offender} as the responsible code. This function is used to deprecate some behavior of a function. It differs from L{warnings.warn} in that it is not limited to deprecating the behavior of a function currently on the call stack. @param offender: The function that is being deprecated. @param warningString: The string that should be emitted by this warning. @type warningString: C{str} @since: 11.0 """ # inspect.getmodule() is attractive, but somewhat # broken in Python < 2.6. See Python bug 4845. offenderModule = sys.modules[offender.__module__] warn_explicit( warningString, category=DeprecationWarning, filename=inspect.getabsfile(offenderModule), lineno=max(lineNumber for _, lineNumber in findlinestarts(offender.__code__)), module=offenderModule.__name__, registry=offender.__globals__.setdefault("__warningregistry__", {}), module_globals=None, )
def build_lines_data(self, code_obj): """ Generate various line-related helper data. """ # Offset: lineno pairs, only for offsets which start line. # Locally we use list for more convenient iteration using indices linestarts = list(dis.findlinestarts(code_obj)) self.linestarts = dict(linestarts) # Plain set with offsets of first ops on line self.linestart_offsets = set(a for (a, _) in linestarts) # 'List-map' which shows line number of current op and offset of # first op on following line, given offset of op as index self.lines = lines = [] LineTuple = namedtuple('LineTuple', ['l_no', 'next']) # Iterate through available linestarts, and fill # the data for all code offsets encountered until # last linestart offset _, prev_line_no = linestarts[0] offset = 0 for start_offset, line_no in linestarts[1:]: while offset < start_offset: lines.append(LineTuple(prev_line_no, start_offset)) offset += 1 prev_line_no = line_no # Fill remaining offsets with reference to last line number # and code length as start offset of following non-existing line codelen = len(self.code) while offset < codelen: lines.append(LineTuple(prev_line_no, codelen)) offset += 1
def from_code(code, *, extended_arg=False): line_starts = dict(dis.findlinestarts(code)) # find block starts instructions = [] offset = 0 lineno = code.co_firstlineno while offset < len(code.co_code): if offset in line_starts: lineno = line_starts[offset] instr = ConcreteInstr.disassemble(lineno, code.co_code, offset) instructions.append(instr) offset += instr.size # replace jump targets with blocks if not extended_arg: extended_arg = None index = 0 while index < len(instructions): instr = instructions[index] if instr.name == 'EXTENDED_ARG' and not extended_arg: if extended_arg is not None: raise ValueError("EXTENDED_ARG followed " "by EXTENDED_ARG") extended_arg = instr.arg del instructions[index] continue if extended_arg is not None: arg = (extended_arg << 16) + instr.arg extended_arg = None instr = ConcreteInstr(instr.name, arg, lineno=instr.lineno) instructions[index] = instr index += 1 if extended_arg is not None: raise ValueError("EXTENDED_ARG at the end of the code") bytecode = ConcreteBytecode() bytecode.name = code.co_name bytecode.filename = code.co_filename bytecode.flags = code.co_flags bytecode.argcount = code.co_argcount bytecode.kwonlyargcount = code.co_kwonlyargcount bytecode._stacksize = code.co_stacksize bytecode.first_lineno = code.co_firstlineno bytecode.names = list(code.co_names) bytecode.consts = list(code.co_consts) bytecode.varnames = list(code.co_varnames) bytecode.freevars = list(code.co_freevars) bytecode.cellvars = list(code.co_cellvars) _set_docstring(bytecode, code.co_consts) bytecode[:] = instructions return bytecode
def get_trace(self, frame, tb, w_code=None): frames = [] stack, current = self.get_stack(frame, tb) for i, (frame, lno) in enumerate(stack): code = frame.f_code filename = code.co_filename if filename == '<wdb>' and w_code: line = w_code else: checkcache(filename) line = getline(filename, lno, frame.f_globals) line = line and line.strip() startlnos = dis.findlinestarts(code) lastlineno = list(startlnos)[-1][1] frames.append({ 'file': filename, 'function': code.co_name, 'flno': code.co_firstlineno, 'llno': lastlineno, 'lno': lno, 'code': escape(line), 'level': i }) return stack, frames, current
def disassemble(code: str, scope: Scope = None, arg_dict: dict = None): """ Disassembles asynchronous code into dis.dis-style bytecode instructions. """ # Similar to AsyncCodeExecutor.__init__ arg_names = list(arg_dict.keys()) if arg_dict else [] scope = scope or Scope() wrapped = wrap_code(code, args=", ".join(arg_names)) exec( compile(wrapped, "<repl>", "exec"), scope.globals, scope.locals ) # pylint: disable=exec-used func_def = scope.locals.get("_repl_coroutine") or scope.globals["_repl_coroutine"] # pylint is gonna really hate this part onwards # pylint: disable=protected-access, invalid-name co = func_def.__code__ for instruction in dis._get_instructions_bytes( co.co_code, co.co_varnames, co.co_names, co.co_consts, co.co_cellvars + co.co_freevars, dict(dis.findlinestarts(co)), line_offset=0, ): if instruction.starts_line is not None and instruction.offset > 0: yield "" yield instruction._disassemble(4, False, 4)
def demo3(): def func(): bug = True i = 0 while i < 3: print "a:", i i += 1 i = 0 while i < 3: print "b:", i if bug: raise Exception i += 1 try: func() assert False except Exception: print "! Exception" _,_,tb = sys.exc_info() tb = find_traceframe(tb, func.func_code) assert tb is not None # Start just at where the exception was raised. instraddr = max([addr for (addr,_) in dis.findlinestarts(func.func_code) if addr <= tb.tb_lasti]) # Play around. Avoid that we throw the exception again. localdict = dict(tb.tb_frame.f_locals) localdict["bug"] = False new_func = restart_func(func, instraddr=instraddr, localdict=localdict) new_func()
def jsonify_code(code): def helper(obj): if type(obj) == code_type: return jsonify_code(obj) else: return { "type": "literal", "real_type": str(type(obj)), "value": obj } # to deeply understand this object # https://late.am/post/2012/03/26/exploring-python-code-objects.html return { # TODO: consider converting to some binary format instead of JSON "type": "code", "co_code": base64.encodebytes(code.co_code).decode('ascii').replace("\n", ""), # our C++ base64 decoder does not take kindly to new lines. "co_lnotab": base64.encodebytes(code.co_lnotab).decode('ascii').replace("\n", ""), # the line number table "co_consts": list(map(helper, code.co_consts)), "co_name": code.co_name, "co_filename": code.co_filename, "co_argcount": code.co_argcount, "co_kwonlyargcount": code.co_kwonlyargcount, "co_nlocals": code.co_nlocals, "co_stacksize": code.co_stacksize, "co_names": code.co_names or None, "co_varnames": code.co_varnames or None, "co_freevars": code.co_freevars or None, "co_cellvars": code.co_cellvars or None, "lnotab": list([tuple[1], tuple[0]] for tuple in dis.findlinestarts(code)), }
def __init__( self, py_code ): import dis self.function_name = py_code.co_name self.filename = py_code.co_filename sorted_offset_lineno = list( dis.findlinestarts( py_code ) ) self._sorted_offsets = [ ol[0] for ol in sorted_offset_lineno ] self._sorted_lines = [ ol[1] for ol in sorted_offset_lineno ]
def disassemble(co, lasti=-1): """Disassemble a code object.""" # Taken from dis.disassemble, returns disassembled code instead of printing # it (the f**k python ?). # Also, unicodified. # Also, use % operator instead of string operations. # Also, one statement per line. out = StringIO() code = co.co_code labels = dis.findlabels(code) linestarts = dict(dis.findlinestarts(co)) n = len(code) i = 0 extended_arg = 0 free = None while i < n: c = code[i] op = ord(c) if i in linestarts: if i > 0: print(end=u'\n', file=out) print(u'%3d' % linestarts[i], end=u' ', file=out) else: print(u' ', end=u' ', file=out) if i == lasti: print(u'-->', end=u' ', file=out) else: print(u' ', end=u' ', file=out) if i in labels: print(u'>>', end=u' ', file=out) else: print(u' ', end=u' ', file=out) print(u'%4i' % i, end=u' ', file=out) print(u'%-20s' % dis.opname[op], end=u' ', file=out) i = i + 1 if op >= dis.HAVE_ARGUMENT: oparg = ord(code[i]) + ord(code[i + 1]) * 256 + extended_arg extended_arg = 0 i = i + 2 if op == dis.EXTENDED_ARG: extended_arg = oparg * 65536 print(u'%5i' % oparg, end=u' ', file=out) if op in dis.hasconst: print(u'(%r)' % co.co_consts[oparg], end=u' ', file=out) elif op in dis.hasname: print(u'(%s)' % co.co_names[oparg], end=u' ', file=out) elif op in dis.hasjrel: print(u'(to %r)' % (i + oparg), end=u' ', file=out) elif op in dis.haslocal: print(u'(%s)' % co.co_varnames[oparg], end=u' ', file=out) elif op in dis.hascompare: print(u'(%s)' % dis.cmp_op[oparg], end=u' ', file=out) elif op in dis.hasfree: if free is None: free = co.co_cellvars + co.co_freevars print(u'(%s)' % free[oparg], end=u' ', file=out) print(end=u'\n', file=out) return out.getvalue()
def insert_code(code_to_modify, code_to_insert, before_line): """ Insert piece of code `code_to_insert` to `code_to_modify` right inside the line `before_line` before the instruction on this line by modifying original bytecode :param code_to_modify: Code to modify :param code_to_insert: Code to insert :param before_line: Number of line for code insertion :return: boolean flag whether insertion was successful, modified code """ linestarts = dict(dis.findlinestarts(code_to_modify)) if before_line not in linestarts.values(): return False, code_to_modify offset = None for off, line_no in linestarts.items(): if line_no == before_line: offset = off break code_to_insert_list = add_jump_instruction(offset, code_to_insert) try: code_to_insert_list, new_names = \ _add_attr_values_from_insert_to_original(code_to_modify, code_to_insert, code_to_insert_list, 'co_names', dis.hasname) code_to_insert_list, new_consts = \ _add_attr_values_from_insert_to_original(code_to_modify, code_to_insert, code_to_insert_list, 'co_consts', [opmap['LOAD_CONST']]) code_to_insert_list, new_vars = \ _add_attr_values_from_insert_to_original(code_to_modify, code_to_insert, code_to_insert_list, 'co_varnames', dis.haslocal) new_bytes, all_inserted_code = _update_label_offsets(code_to_modify.co_code, offset, list(code_to_insert_list)) new_lnotab = _modify_new_lines(code_to_modify, offset, code_to_insert_list) if new_lnotab is None: return False, code_to_modify except ValueError: traceback.print_exc() return False, code_to_modify new_code = CodeType( code_to_modify.co_argcount, # integer code_to_modify.co_kwonlyargcount, # integer len(new_vars), # integer code_to_modify.co_stacksize, # integer code_to_modify.co_flags, # integer new_bytes, # bytes new_consts, # tuple new_names, # tuple new_vars, # tuple code_to_modify.co_filename, # string code_to_modify.co_name, # string code_to_modify.co_firstlineno, # integer new_lnotab, # bytes code_to_modify.co_freevars, # tuple code_to_modify.co_cellvars # tuple ) return True, new_code
def lineForInstruction(code, instruction): line = 1 for i, l in dis.findlinestarts(code): if i > instruction: break line = l return line
def lasti2lineno(code, lasti): import dis linestarts = list(dis.findlinestarts(code)) linestarts.reverse() for i, lineno in linestarts: if lasti >= i: return lineno return 0
def _find_lineno(self, op): linestarts = list(dis.findlinestarts(op.pycode)) i = bisect.bisect(linestarts, (op.bytecode_no, )) - 1 if i < 0: return -1 else: _, lineno = linestarts[i] return lineno
def lasti2lineno(code, lasti): import dis linestarts = list(dis.findlinestarts(code)) linestarts.reverse() for i, lineno in linestarts: if lasti >= i: return lineno assert False, 'Invalid instruction number: %s' % lasti
def find_lines_from_code(code, strs): """Return dict where keys are lines in the line number table.""" linenos = {} for _, lineno in dis.findlinestarts(code): if lineno not in strs: linenos[lineno] = 1 return linenos
def disassemble(msg, msg_nocr, section, co, lasti=-1, start_line=-1, end_line=None, relative_pos=False, color='light'): """Disassemble a code object.""" disassemble_bytes(msg, msg_nocr, co.co_code, lasti, co.co_firstlineno, start_line, end_line, relative_pos, co.co_varnames, co.co_names, co.co_consts, co.co_cellvars, co.co_freevars, dict(findlinestarts(co)), color) return
def disassemble(obj, co, lasti=-1, start_line=-1, end_line=None, relative_pos=False): """Disassemble a code object.""" disassemble_string(obj, co.co_code, lasti, co.co_firstlineno, start_line, end_line, relative_pos, co.co_varnames, co.co_names, co.co_consts, co.co_cellvars, co.co_freevars, dict(findlinestarts(co))) return
def check_lnotab(self, code): "Check that the lnotab byte offsets are sensible." code = dis._get_code_object(code) lnotab = list(dis.findlinestarts(code)) # Don't bother checking if the line info is sensible, because # most of the line info we can get at comes from lnotab. min_bytecode = min(t[0] for t in lnotab) max_bytecode = max(t[0] for t in lnotab) self.assertGreaterEqual(min_bytecode, 0) self.assertLess(max_bytecode, len(code.co_code))
def disassemble(msg, msg_nocr, section, co, lasti=-1, start_line=-1, end_line=None, relative_pos=False, highlight='light', start_offset=0, end_offset=None): """Disassemble a code object.""" return disassemble_bytes(msg, msg_nocr, co.co_code, lasti, co.co_firstlineno, start_line, end_line, relative_pos, co.co_varnames, co.co_names, co.co_consts, co.co_cellvars, co.co_freevars, dict(findlinestarts(co)), highlight, start_offset=start_offset, end_offset=end_offset)
def _instructions(code, lasti=-1): """Generator for code instructions""" cell_names = code.co_cellvars + code.co_freevars linestarts = OrderedDict(_dis.findlinestarts(code)) insts = _byte_instructions( code.co_code, lasti, code.co_varnames, code.co_names, code.co_consts, cell_names, linestarts) for inst in insts: yield inst
def get_offset_for_line(co, line): """ Return the offset associated with the given line in a code object. Return -1 if there is no byte code associated with this line. """ for offset, l in dis.findlinestarts(co): if l == line: return offset elif l > line: break return -1
def _mark_lineno(self): '''Fill the lineno info for all bytecode inst ''' for offset, lineno in dis.findlinestarts(self.code): if offset in self.table: self.table[offset].lineno = lineno known = -1 for inst in self: if inst.lineno >= 0: known = inst.lineno else: inst.lineno = known
def disassemble(co): """Disassemble a code object.""" lines = [] code = co.co_code labels = dis.findlabels(code) linestarts = dict(dis.findlinestarts(co)) n = len(code) i = 0 extended_arg = 0 free = None while i < n: c = code[i] op = ord(c) data = {"raw_op": op} if i in linestarts: data["line_no"] = linestarts[i] else: data["line_no"] = None if i in labels: data["in_labels"] = True else: data["in_labels"] = False data["i"] = i data["opname"] = opname[op] data["hex"] = "%02X" % op i = i + 1 if op >= HAVE_ARGUMENT: oparg = ord(code[i]) + ord(code[i + 1]) * 256 + extended_arg extended_arg = 0 data["hex"] += " %02X %02X" % (ord(code[i]), ord(code[i + 1])) i = i + 2 if op == EXTENDED_ARG: extended_arg = oparg * 65536L data["raw_arg"] = oparg if op in hasconst: data['arg'] = {"value": repr(co.co_consts[oparg]), "type": "const"} elif op in hasname: data['arg'] = {"value": co.co_names[oparg], "type": "name"} elif op in hasjrel: data['arg'] = {"value": repr(i + oparg), "type": "jump_relative"} elif op in haslocal: data['arg'] = {"value": co.co_varnames[oparg], "type": "local_name"} elif op in hascompare: data['arg'] = {"value": cmp_op[oparg], "type": "compare"} elif op in hasfree: if free is None: free = co.co_cellvars + co.co_freevars data['arg'] = {"value": cmp_op[oparg], "type": "free_variable"} lines.append(data) return json.dumps(lines)
def _mark_lineno(cls, table, code): '''Fill the lineno info for all bytecode inst ''' for offset, lineno in dis.findlinestarts(code): if offset in table: table[offset].lineno = lineno known = -1 for inst in table.values(): if inst.lineno >= 0: known = inst.lineno else: inst.lineno = known
def __init__(self, x, first_line=None, current_offset=None): self.codeobj = co = _get_code_object(x) if first_line is None: self.first_line = co.co_firstlineno self._line_offset = 0 else: self.first_line = first_line self._line_offset = first_line - co.co_firstlineno self._cell_names = co.co_cellvars + co.co_freevars self._linestarts = dict(findlinestarts(co)) self._original_object = x self.current_offset = current_offset
def dissco(co): try: code = co.co_code except AttributeError: raise TypeError("disassembly only works on objects with code components.") ret = [] labels = findlabels(code) linestarts = dict(findlinestarts(co)) print labels, linestarts n = len(code) i = 0 cur_line = 0 oparg = None arg = None extended_arg = 0 free = None while i < n: c = code[i] op = ord(c) if i in linestarts: cur_line = linestarts[i] op_name = opname[op] i += 1 if op >= HAVE_ARGUMENT: oparg = ord(code[i]) + ord(code[i + 1]) * 256 + extended_arg extended_arg = 0 i += 2 if op == EXTENDED_ARG: extended_arg = oparg * 65536L if op in hasconst: arg = co.co_consts[oparg] elif op in hasname: arg = co.co_names[oparg] elif op in hasjrel: arg = i + oparg elif op in haslocal: arg = co.co_varnames[oparg] elif op in hascompare: arg = cmp_op[oparg] elif op in hasfree: if free is None: free = co.co_cellvars + co.co_freevars arg = free[oparg] ret.append(Instruction(op, oparg, arg, cur_line)) oparg = None arg = None return ret
def next_linestart(co, offset, count=1): linestarts = dict(dis.findlinestarts(co)) code = co.co_code n = len(code) contains_cond_jump = False for op, offset in next_opcode(code, offset): if offset in linestarts: count -= 1 if 0 == count: return linestarts[offset] pass pass return -1000
def get_func_source(obj): """Get object's source code. Returns None when source can't be found. """ from inspect import findsource from dis import findlinestarts try: lines, lnum = findsource(obj) ls = list(findlinestarts(obj.func_code)) lstart = ls[0][1] lend = ls[-1][1] except (IOError, TypeError): return None return ''.join(lines[lstart-1:lend])
def iterate(): # First, get all line starts for this code object. This does not include # bodies of nested class and function definitions, as they have their # own objects. for _, lineno in dis.findlinestarts(code): yield lineno # For nested class and function definitions, their respective code objects # are constants referenced by this object. for const in code.co_consts: if isinstance(const, types.CodeType) and const.co_filename == code.co_filename: for lineno in _get_code_lines(const): yield lineno