• Stars
    star
    223
  • Rank 177,608 (Top 4 %)
  • Language
    Python
  • License
    GNU General Publi...
  • Created over 8 years ago
  • Updated about 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Python cross-version bytecode library and disassembler

CircleCI PyPI Installs Latest Version Supported Python Versions

packagestatus

xdis

A Cross-Python bytecode disassembler, bytecode/wordcode and magic-number manipulation library/package.

Introduction

The Python dis module allows you to disassemble bytecode from the same version of Python that you are running on. But what about bytecode from different versions?

That's what this package is for. It can "marshal load" Python bytecodes from different versions of Python. The command-line routine pydisasm will show disassembly output using the most modern Python disassembly conventions in a variety of user-specified formats. Some of these formats like extended and extended-format are the most advanced of any Python disassembler I know of because they can show expression-tree on operarators. See the [Disasembler Example][#disasembler-example] below.

Also, if you need to modify and write bytecode, the routines here can be of help. There are routines to pack and unpack the read-only tuples in Python's Code type. For interoperability between Python 2 and 3 we provide our own versions of the Code type, and we provide routines to reduce the tedium in writing a bytecode file.

This package also has an extensive knowledge of Python bytecode magic numbers, including Pypy and others, and how to translate from sys.sys_info major, minor, and release numbers to the corresponding magic value.

So if you want to write a cross-version assembler, or a bytecode-level optimizer this package may also be useful. In addition to the kinds of instruction categorization that dis` offers, we have additional categories for things that would be useful in such a bytecode assembler, optimizer, or decompiler.

The programs here accept bytecodes from Python version 1.0 to 3.11 or so. The code requires Python 2.4 or later and has been tested on Python running lots of Python versions.

When installing, except for the most recent versions of Python, use the Python egg or wheel that matches that version, e.g. xdis-6.0.2-py3.3.egg, xdis-6.0.2-py33-none-any.whl. Of course for versions that pre-date wheel's, like Python 2.6, you will have to use eggs.

To install older versions for from source in git use the branch python-2.4-to-2.7 for Python versions from 2.4 to 2.7, python-3.1-to-3.2 for Python versions from 3.1 to 3.2, python-3.3-to-3.5 for Python versions from 3.3 to 3.5. The master branch handles Python 3.6 and later.

Installation

The standard Python routine:

$ pip install -e .
$ pip install -r requirements-dev.txt

A GNU makefile is also provided so make install (possibly as root or sudo) will do the steps above.

Disassembler Example

The cross-version disassembler that is packaged here, can produce assembly listing that are superior to those typically found in Python's dis module. Here is an example:

pydisasm --show-source -F extended bytecode_3.8/pydisasm-example.pyc
byte-compiling simple_source/pydisasm-example.py to bytecode_3.8/pydisasm-example.py.pyc
/src/external-vcs/github/rocky/python-xdis/test
# pydisasm version 6.1.0.dev0
# Python bytecode 3.8.0 (3413)
# Disassembled from Python 3.8.17 (default, Jun 21 2023, 08:20:16)
# [GCC 12.2.0]
# Timestamp in code: 1693155156 (2023-08-27 12:52:36)
# Source code size mod 2**32: 320 bytes
# Method Name:       <module>
# Filename:          simple_source/pydisasm-example.py
# Argument count:    0
# Position-only argument count: 0
# Keyword-only arguments: 0
# Number of locals:  0
# Stack size:        3
# Flags:             0x00000040 (NOFREE)
# First Line:        4
# Constants:
#    0: 0
#    1: None
#    2: ('version_info',)
#    3: 1
#    4: (2, 4)
#    5: 'Is small power of two'
# Names:
#    0: sys
#    1: version_info
#    2: print
#    3: version
#    4: len
#    5: major
#    6: power_of_two
             # import sys
  4:           0 LOAD_CONST           (0)
               2 LOAD_CONST           (None)
               4 IMPORT_NAME          (sys)
               6 STORE_NAME           (sys) | sys = import(sys)

             # from sys import version_info
  5:           8 LOAD_CONST           (0)
              10 LOAD_CONST           (('version_info',))
              12 IMPORT_NAME          (sys)
              14 IMPORT_FROM          (version_info)
              16 STORE_NAME           (version_info) | version_info = import(version_info)
              18 POP_TOP

             # print(sys.version)
  7:          20 LOAD_NAME            (print)
              22 LOAD_NAME            (sys)
              24 LOAD_ATTR            (version) | sys.version
              26 CALL_FUNCTION        (1 positional argument) | print(sys.version)
              28 POP_TOP

             # print(len(version_info))
  8:          30 LOAD_NAME            (print)
              32 LOAD_NAME            (len)
              34 LOAD_NAME            (version_info)
              36 CALL_FUNCTION        (1 positional argument) | len(version_info)
              38 CALL_FUNCTION        (1 positional argument) | print(len(version_info))
              40 POP_TOP

             # major = sys.version_info[0]
  9:          42 LOAD_NAME            (sys)
              44 LOAD_ATTR            (version_info) | sys.version_info
              46 LOAD_CONST           (0)
              48 BINARY_SUBSCR        sys.version_info[0]
              50 STORE_NAME           (major) | major = sys.version_info[0]

             # power_of_two = major & (major - 1)
 10:          52 LOAD_NAME            (major)
              54 LOAD_NAME            (major)
              56 LOAD_CONST           (1)
              58 BINARY_SUBTRACT      major - 1
              60 BINARY_AND           major & (major - 1)
              62 STORE_NAME           (power_of_two) | power_of_two = major & (major - 1)

             # if power_of_two in (2, 4):
 11:          64 LOAD_NAME            (power_of_two)
              66 LOAD_CONST           ((2, 4))
              68 COMPARE_OP           (in) | power_of_two in (2, 4)
              70 POP_JUMP_IF_FALSE    (to 80)

             # print("Is small power of two")
 12:          72 LOAD_NAME            (print)
              74 LOAD_CONST           ('Is small power of two')
              76 CALL_FUNCTION        (1 positional argument) | print('Is small power of two')
              78 POP_TOP
         >>   80 LOAD_CONST           (None)
              82 RETURN_VALUE         return None

Note in the above that some operand interpretation is done on items that are in the stack. For example in

24 LOAD_ATTR            (version) | sys.version

from the instruction see that sys.version is the resolved attribute that is loaded.

Similarly in:

68 COMPARE_OP           (in) | power_of_two in (2, 4)

we see that we can resolve the two arguments of the in operation. Finally in some CALL_FUNCTIONS we can figure out the name of the function and arguments passed to it.

Testing

$ make check

A GNU makefile has been added to smooth over setting running the right command, and running tests from fastest to slowest.

If you have remake installed, you can see the list of all tasks including tests via remake --tasks.

Usage

Run

$ ./bin/pydisasm -h

for usage help.

As a drop-in replacement for dis

xdis also provides some support as a drop in replacement for the the Python library dis module. This is may be desirable when you want to use the improved API from Python 3.4 or later from an earlier Python version.

For example:

>>> # works in Python 2 and 3
>>> import xdis.std as dis
>>> [x.opname for x in dis.Bytecode('a = 10')]
['LOAD_CONST', 'STORE_NAME', 'LOAD_CONST', 'RETURN_VALUE']

There may some small differences in output produced for formatted disassembly or how we show compiler flags. We expect you'll find the xdis output more informative though.

See Also

More Repositories

1

python-uncompyle6

A cross-version Python bytecode decompiler
Python
3,298
star
2

python-decompile3

Python decompiler for 3.7-3.8 Stripped down from uncompyle6 so we can refactor and start to fix up some long-standing problems
Python
900
star
3

remake

Enhanced GNU Make - tracing, error reporting, debugging, profiling and more
C
776
star
4

zshdb

gdb-like "trepan" debugger for zsh
Shell
288
star
5

elisp-bytecode

Let's document Emacs Lisp Bytecode (Lisp Assembly Program) instructions
Emacs Lisp
178
star
6

python3-trepan

A gdb-like Python3 Debugger in the Trepan family
Python
137
star
7

python-xasm

Python cross version bytecode/wordcode assembler
Python
88
star
8

python2-trepan

A gdb-like Python 2.x Debugger in the Trepan family
Python
88
star
9

rb-trepanning

Ruby MRI 2.1.5, 1.9.3 or 1.9.2 debugger. See also rbx-trepanning
Ruby
73
star
10

python-control-flow

Control-Flow, Dominator Tree, and dot output from Python bytecode
Python
47
star
11

python-spark

An Earley-Algorithm Context-free grammar Parser Toolkit
Python
44
star
12

libcdio-paranoia

CD paranoia on top of libcdio
C
43
star
13

go-fish

A simple go REPL building on top of the go-interactive expression evaluator
Go
41
star
14

columnize

Arrange an array aligned in columns vertically or horizontally.
Ruby
37
star
15

Perl-Devel-Trepan

Perl port of trepanning debugger
Perl
35
star
16

kshdb

Korn Shell (93v- 2014-12-24 or greater) Debugger
Shell
33
star
17

ssa-interp

A Go SSA Debugger and Interpreter
Go
31
star
18

emacs-load-relative

Relative loads for Emacs Lisp files. Adds functions __FILE__ and load-relative and require-relative.
Emacs Lisp
29
star
19

emacs-test-simple

Unit tests for GNU emacs that work interactively and in batch
Emacs Lisp
27
star
20

elisp-decompile

Emacs Lisp Decompiler
Python
26
star
21

pydb

Older python debugger (please use python-trepan2 instead)
Python
23
star
22

shell-term-background

POSIX shell scripts to figure out if a terminal has a dark or light background
Shell
23
star
23

rb-threadframe

Frame introspection in Ruby 2.1.5, 1.9.3 and 1.9.2
C
17
star
24

trepan-xpy

Debugger in the Trepan family for x-python
Python
16
star
25

pycolumnize

Python module to align a simple (not nested) list in columns. Adapted from the routine of the same name inside cmd.py
Python
15
star
26

trepanjs

A more gdb-like debugger for nodejs. In style of the trepan family of debuggers.
JavaScript
15
star
27

elisp-earley

Earley parser in Emacs Lisp
Emacs Lisp
15
star
28

rbx-trepanning

Ruby debugger for Rubinius 2.0x. See also rb-trepanning
Ruby
14
star
29

ipython-trepan

Add ipython magic to call python trepan
Python
12
star
30

emacs-loc-changes

Emacs package to help users and programs keep track of positions even after buffer changes.
Emacs Lisp
10
star
31

go-play

Automatically exported from code.google.com/p/go-play
JavaScript
9
star
32

pycdio

Python interface to the libcdio - the CD Input and Control library
Python
9
star
33

trepan-ni

A more gdb-like (v8) node-inspect (v8), in the trepan debugger family
JavaScript
7
star
34

solc-lsp

LSP functions for solidity using solc's AST
TypeScript
7
star
35

python2ruby

A real hacky way to convert between Python and Ruby
Emacs Lisp
7
star
36

vcdimager

GNU VCDImager
C
7
star
37

pytest-trepan

pytest plugin to invoke the trepan debugger
Python
6
star
38

emacs-test-unit

Simple Emacs Test/Unit framework (but see also emacs-test-simple)
Emacs Lisp
6
star
39

go-eval

Fork of 0xfaded/go-eval before API change that broke ssa-interp. This is temporary until ssa-interp is fixed properly.
Go
6
star
40

solc-vscode

Microsoft LSP functions VSCode extension for Solidity
TypeScript
6
star
41

p5-Term-ReadLine-Perl5

A Perl5 implementation GNU Readline
Perl
5
star
42

rocky.github.com

Rocky's talks
JavaScript
5
star
43

rbx-require-relative

Ruby 1.9's require_relative for rubinius and MRI 1.8. Compatibility on 1.9..2
Ruby
5
star
44

linecache

Read and cache Ruby source-code file information
Ruby
4
star
45

go-gnureadline

Go bindings for GNU Readline
Go
4
star
46

python-loctraceback

Python 3.6 API traceback module adding in fragment decomplation info for more precise location information
Python
3
star
47

rbx-tracer

set_trace_func for Rubinius
Ruby
3
star
48

rb-lpsolve

Ruby bindings for lpsolve 5.5.10
C
3
star
49

gjchaitin

Two years circa 1982 I knew GJChaitin
TeX
3
star
50

pytracer

Automatically exported from code.google.com/p/pytracer
Python
3
star
51

Perl-Array-Columnize

Display Arrays in nice columns. Port of Ruby Columnize
Perl
3
star
52

rb-parsetree19

C Extension to support ParseTree for Ruby 1.9
Ruby
3
star
53

rb-trace

Ruby trace hook enhancements
Ruby
3
star
54

solidity-language-server

TypeScript
3
star
55

bashdb

Bash debugger (code imported from sourceforge)
Shell
3
star
56

decompile-2.4

Python decompiler for Python 1.5-2.4 (for historical archive)
Python
2
star
57

Perl-Syntax

Perl module for syntax checking a string or Perl file. Like perl -c, but with more control over output
Perl
2
star
58

go-types

Freeze save code.google.com/p/go.tools/go/types before API changed and broke go-fish
Go
2
star
59

klondike

A slightly less lame version of gnome-games klondike solitaire program
Scheme
2
star
60

rb8-trepanning

Backport of rb{,x}-trepanning to MRI 1.8 with some tolerance for MRI 1.9.2
Ruby
2
star
61

ps-watcher

Rewrite of sourceforge ps-watcher in Ruby
Ruby
2
star
62

Perl-Devel-Callsite

Get caller Perl OP address
Perl
2
star
63

go-importer

Freeze save code.google.com/p/go.tools/importer before API changed and broke go-fish
Go
2
star
64

Perl-Devel-Trepan-TTY

Remote debugging support via pseudo ttys
Perl
2
star
65

csharp-columnize

C# version of Ruby columnize
C#
1
star
66

Perl-Task-Trepan

A Perl task to get the most out of Devel::Trepan
Perl
1
star
67

um

Universal machine
Python
1
star
68

Perl-Devel-Trepan-Disassemble

Adds "disassemble" command to Perl-Devel-Trepan
Perl
1
star
69

go-gcimporter

Freeze save code.google.com/p/go.tools/go/gcimporter before API changed and broke go-fish
Go
1
star
70

ruby19-headers

Additional Ruby 1.9 headers for introspection (rb-threadframe, rb-parsetree19)
C
1
star
71

p5-lead-sentence

Find leading sentence in some text
Perl
1
star
72

python-filecache

module for Python module for reading and caching lines. This may be useful for example in a debugger where the same lines are shown many times.
Python
1
star
73

python-deparse

deparse fragments of python code (via uncompyle)
Python
1
star
74

Perl-B-CodeLines

List executable lines of a Perl program
Perl
1
star
75

p5-B-DeparseTree

Perl's B::Deparse saving OP Tree Information and text fragments accessible by OP address
Perl
1
star
76

Perl-Devel-Trepan-Shell

Adds an Interactive Shell to Devel::Trepan
Perl
1
star
77

Perl-Devel-Trepan-Psh

Devel::Trepan plugin to add an interactive shell via "psh"
Perl
1
star
78

irb-method-capture

Save module, methods and classes in irb exactly the way you entered them
Ruby
1
star
79

python-perl-translations

1
star
80

go-columnize

A Go module to format a simple (i.e. not nested) list into aligned columns.
Go
1
star
81

mult-by-constants

Code, library, and tables to search for optimal sequences of shift, adds, and subtracts to multiply by a constant.
Jupyter Notebook
1
star
82

p5-Term-ReadLine-Perl5-Demo

Shell for learning and experimenting with Term::ReadLine::Perl5
Perl
1
star
83

go-loader

fork of "experimental" loader which breaks our code too much can causes too much unappreciated reworking.
Go
1
star
84

emacs.d-modes

My customized emacs.d modes
Emacs Lisp
1
star
85

pfor

A simple server blast script
Perl
1
star
86

p5-Devel-Trepan-Deparse

Adds a "deparse" command to Devel::Trepan
Perl
1
star
87

go-astutil

Copy of golang.org/x/tools/astutil. It is a pity one has to resort to tricks like this, but one can't rely on golang.org/x/tools/astutil, what it was called before or is called now or (possibly) the API
Go
1
star
88

Perl-Device-Cdio

Perl bindings for libcdio
Perl
1
star
89

Perl-Devel-Trepan-BWProcessor

Bullwinkle Protocol Processor for Devel::Trepan - useful for front-ends controlling Devel::Trepan
Perl
1
star
90

pygtk3-pstree

GNU/Linux process tree animation in real time using PyGTK
Python
1
star