Staging
v0.8.1
https://github.com/python/cpython
Revision 958980190cd04b819d592dd6654df72cd1df3edd authored by Georg Brandl on 05 April 2009, 21:23:27 UTC, committed by Georg Brandl on 05 April 2009, 21:23:27 UTC
........
  r70869 | georg.brandl | 2009-03-31 21:14:42 +0200 (Di, 31 Mär 2009) | 1 line

  Fix-up unwanted change.
........
  r70883 | georg.brandl | 2009-03-31 22:41:08 +0200 (Di, 31 Mär 2009) | 1 line

  #1674032: return value of flag from Event.wait(). OKed by Guido.
........
  r70901 | georg.brandl | 2009-03-31 23:40:24 +0200 (Di, 31 Mär 2009) | 2 lines

  Remove warning about pending Win9x support removal.
........
  r70903 | georg.brandl | 2009-03-31 23:45:18 +0200 (Di, 31 Mär 2009) | 1 line

  #1676135: remove trailing slashes from --prefix argument.
........
  r70951 | georg.brandl | 2009-04-01 16:02:27 +0200 (Mi, 01 Apr 2009) | 1 line

  Add Maksim, who worked on several issues at the sprint.
........
  r70992 | georg.brandl | 2009-04-01 23:00:55 +0200 (Mi, 01 Apr 2009) | 1 line

  #4572: add SEEK_* values as constants in io.py.
........
  r70993 | georg.brandl | 2009-04-01 23:05:44 +0200 (Mi, 01 Apr 2009) | 1 line

  Add NEWS item.
........
  r70994 | georg.brandl | 2009-04-01 23:06:30 +0200 (Mi, 01 Apr 2009) | 1 line

  Revert accidental checkin.
........
  r71006 | georg.brandl | 2009-04-02 01:32:17 +0200 (Do, 02 Apr 2009) | 1 line

  Cache the f_locals dict of the current frame, since every access to frame.f_locals overrides its contents with the real locals which undoes modifications made by the debugging user.
........
  r71019 | georg.brandl | 2009-04-02 04:00:01 +0200 (Do, 02 Apr 2009) | 1 line

  Fix test_doctest, missed two assignments to curframe.
........
  r71024 | georg.brandl | 2009-04-02 04:47:44 +0200 (Do, 02 Apr 2009) | 4 lines

  In PyErr_GivenExceptionMatches, temporarily bump the recursion
  limit, so that in the most common case PyObject_IsSubclass will
  not raise a recursion error we have to ignore anyway.
........
1 parent 9b08e05
Raw File
Tip revision: 958980190cd04b819d592dd6654df72cd1df3edd authored by Georg Brandl on 05 April 2009, 21:23:27 UTC
Blocked revisions 70869,70883,70901,70903,70951,70992-70994,71006,71019,71024 via svnmerge
Tip revision: 9589801
dis.py
"""Disassembler of Python byte code into mnemonics."""

import sys
import types

from opcode import *
from opcode import __all__ as _opcodes_all

__all__ = ["dis","disassemble","distb","disco"] + _opcodes_all
del _opcodes_all

def dis(x=None):
    """Disassemble classes, methods, functions, or code.

    With no argument, disassemble the last traceback.

    """
    if x is None:
        distb()
        return
    if type(x) is types.InstanceType:
        x = x.__class__
    if hasattr(x, 'im_func'):
        x = x.im_func
    if hasattr(x, 'func_code'):
        x = x.func_code
    if hasattr(x, '__dict__'):
        items = x.__dict__.items()
        items.sort()
        for name, x1 in items:
            if type(x1) in (types.MethodType,
                            types.FunctionType,
                            types.CodeType,
                            types.ClassType):
                print "Disassembly of %s:" % name
                try:
                    dis(x1)
                except TypeError, msg:
                    print "Sorry:", msg
                print
    elif hasattr(x, 'co_code'):
        disassemble(x)
    elif isinstance(x, str):
        disassemble_string(x)
    else:
        raise TypeError, \
              "don't know how to disassemble %s objects" % \
              type(x).__name__

def distb(tb=None):
    """Disassemble a traceback (default: last traceback)."""
    if tb is None:
        try:
            tb = sys.last_traceback
        except AttributeError:
            raise RuntimeError, "no last traceback to disassemble"
        while tb.tb_next: tb = tb.tb_next
    disassemble(tb.tb_frame.f_code, tb.tb_lasti)

def disassemble(co, lasti=-1):
    """Disassemble a code object."""
    code = co.co_code
    labels = findlabels(code)
    linestarts = dict(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
            print "%3d" % linestarts[i],
        else:
            print '   ',

        if i == lasti: print '-->',
        else: print '   ',
        if i in labels: print '>>',
        else: print '  ',
        print repr(i).rjust(4),
        print opname[op].ljust(20),
        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*65536L
            print repr(oparg).rjust(5),
            if op in hasconst:
                print '(' + repr(co.co_consts[oparg]) + ')',
            elif op in hasname:
                print '(' + co.co_names[oparg] + ')',
            elif op in hasjrel:
                print '(to ' + repr(i + oparg) + ')',
            elif op in haslocal:
                print '(' + co.co_varnames[oparg] + ')',
            elif op in hascompare:
                print '(' + cmp_op[oparg] + ')',
            elif op in hasfree:
                if free is None:
                    free = co.co_cellvars + co.co_freevars
                print '(' + free[oparg] + ')',
        print

def disassemble_string(code, lasti=-1, varnames=None, names=None,
                       constants=None):
    labels = findlabels(code)
    n = len(code)
    i = 0
    while i < n:
        c = code[i]
        op = ord(c)
        if i == lasti: print '-->',
        else: print '   ',
        if i in labels: print '>>',
        else: print '  ',
        print repr(i).rjust(4),
        print opname[op].ljust(15),
        i = i+1
        if op >= HAVE_ARGUMENT:
            oparg = ord(code[i]) + ord(code[i+1])*256
            i = i+2
            print repr(oparg).rjust(5),
            if op in hasconst:
                if constants:
                    print '(' + repr(constants[oparg]) + ')',
                else:
                    print '(%d)'%oparg,
            elif op in hasname:
                if names is not None:
                    print '(' + names[oparg] + ')',
                else:
                    print '(%d)'%oparg,
            elif op in hasjrel:
                print '(to ' + repr(i + oparg) + ')',
            elif op in haslocal:
                if varnames:
                    print '(' + varnames[oparg] + ')',
                else:
                    print '(%d)' % oparg,
            elif op in hascompare:
                print '(' + cmp_op[oparg] + ')',
        print

disco = disassemble                     # XXX For backwards compatibility

def findlabels(code):
    """Detect all offsets in a byte code which are jump targets.

    Return the list of offsets.

    """
    labels = []
    n = len(code)
    i = 0
    while i < n:
        c = code[i]
        op = ord(c)
        i = i+1
        if op >= HAVE_ARGUMENT:
            oparg = ord(code[i]) + ord(code[i+1])*256
            i = i+2
            label = -1
            if op in hasjrel:
                label = i+oparg
            elif op in hasjabs:
                label = oparg
            if label >= 0:
                if label not in labels:
                    labels.append(label)
    return labels

def findlinestarts(code):
    """Find the offsets in a byte code which are start of lines in the source.

    Generate pairs (offset, lineno) as described in Python/compile.c.

    """
    byte_increments = [ord(c) for c in code.co_lnotab[0::2]]
    line_increments = [ord(c) for c in code.co_lnotab[1::2]]

    lastlineno = None
    lineno = code.co_firstlineno
    addr = 0
    for byte_incr, line_incr in zip(byte_increments, line_increments):
        if byte_incr:
            if lineno != lastlineno:
                yield (addr, lineno)
                lastlineno = lineno
            addr += byte_incr
        lineno += line_incr
    if lineno != lastlineno:
        yield (addr, lineno)

def _test():
    """Simple test program to disassemble a file."""
    if sys.argv[1:]:
        if sys.argv[2:]:
            sys.stderr.write("usage: python dis.py [-|file]\n")
            sys.exit(2)
        fn = sys.argv[1]
        if not fn or fn == "-":
            fn = None
    else:
        fn = None
    if fn is None:
        f = sys.stdin
    else:
        f = open(fn)
    source = f.read()
    if fn is not None:
        f.close()
    else:
        fn = "<stdin>"
    code = compile(source, fn, "exec")
    dis(code)

if __name__ == "__main__":
    _test()
back to top