Skip to main content

Python cross-version byte-code disassembler and marshal routines

Project description

CircleCI PyPI Installs Latest Version Supported Python Versions

Packaging Status

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 operators. See the Disassembler 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 the changes over the years to Python CodeType, provide our own versions of the Code Type to allow interoperability, 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, bytecode-level analyzer, or 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.13. 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 python-3.6-to-3.10 for Python versions from 3.6 to 3.10 . The master branch handles Python 3.11 and later.

Installation

The standard Python routine:

$ pip install -e .  # or pip install -e .[dev] to include testing package

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 -S -F extended bytecode_3.8/pydisasm-example.pyc
# pydisasm version 6.1.1.dev0
# Python bytecode 3.8.0 (3413)
# Disassembled from Python 3.11.8 (main, Feb 14 2024, 04:47:01) [GCC 13.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) ; TOS = 0
               2 LOAD_CONST           (None) ; TOS = None
               4 IMPORT_NAME          (sys) ; TOS = import_module(sys)
               6 STORE_NAME           (sys) ; sys = import_module(sys)

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

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

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

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

             # power_of_two = major & (major - 1)
 10:          52 LOAD_NAME            (major) ; TOS = major
              54 LOAD_NAME            (major) ; TOS = major
              56 LOAD_CONST           (1) ; TOS = 1
              58 BINARY_SUBTRACT      TOS = major - (1)
              60 BINARY_AND           TOS = 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) ; TOS = power_of_two
              66 LOAD_CONST           ((2, 4)) ; TOS = (2, 4)
              68 COMPARE_OP           (in) ; TOS = power_of_two in ((2, 4))
              70 POP_JUMP_IF_FALSE    (to 80)

             # print("Is small power of two")
 12:          72 LOAD_NAME            (print) ; TOS = print
              74 LOAD_CONST           ("Is small power of two") ; TOS = "Is small power of two"
              76 CALL_FUNCTION        (1 positional argument) ; TOS = print("Is small power of two")
              78 POP_TOP
         >>   80 LOAD_CONST           (None) ; TOS = 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

Release history Release notifications | RSS feed

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

xdis-6.1.4.tar.gz (437.5 kB view details)

Uploaded Source

Built Distributions

xdis-6.1.4-py313-none-any.whl (188.3 kB view details)

Uploaded Python 3.13

xdis-6.1.4-py312-none-any.whl (188.3 kB view details)

Uploaded Python 3.12

xdis-6.1.4-py311-none-any.whl (181.3 kB view details)

Uploaded Python 3.11

xdis-6.1.4-py310-none-any.whl (224.1 kB view details)

Uploaded Python 3.10

xdis-6.1.4-py39-none-any.whl (224.1 kB view details)

Uploaded Python 3.9

xdis-6.1.4-py38-none-any.whl (224.1 kB view details)

Uploaded Python 3.8

xdis-6.1.4-py37-none-any.whl (224.1 kB view details)

Uploaded Python 3.7

xdis-6.1.4-py36-none-any.whl (224.1 kB view details)

Uploaded Python 3.6

xdis-6.1.4-py35-none-any.whl (222.9 kB view details)

Uploaded Python 3.5

xdis-6.1.4-py34-none-any.whl (222.9 kB view details)

Uploaded Python 3.4

File details

Details for the file xdis-6.1.4.tar.gz.

File metadata

  • Download URL: xdis-6.1.4.tar.gz
  • Upload date:
  • Size: 437.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.3

File hashes

Hashes for xdis-6.1.4.tar.gz
Algorithm Hash digest
SHA256 6e749661ac114c7b66edf4bd200e95066963c14ea039119651eb081a8da08ce6
MD5 c218709bb4dc1fa0864453e2cec1eae4
BLAKE2b-256 c594de880a3be7219203bcc81769613d950614e446990ab48dea9d33477f7848

See more details on using hashes here.

File details

Details for the file xdis-6.1.4-py313-none-any.whl.

File metadata

  • Download URL: xdis-6.1.4-py313-none-any.whl
  • Upload date:
  • Size: 188.3 kB
  • Tags: Python 3.13
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.3

File hashes

Hashes for xdis-6.1.4-py313-none-any.whl
Algorithm Hash digest
SHA256 fac7b8e67c070102ba534f2630a39498afefe5bfc7d27741518f2b2b27c0d207
MD5 eaabba9ffc6f6cdef9d78323808856a9
BLAKE2b-256 8ef5b6933dbd5da1f8e42c6cc704dff4551e458fd7075649bd503267f5c20a96

See more details on using hashes here.

File details

Details for the file xdis-6.1.4-py312-none-any.whl.

File metadata

  • Download URL: xdis-6.1.4-py312-none-any.whl
  • Upload date:
  • Size: 188.3 kB
  • Tags: Python 3.12
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.3

File hashes

Hashes for xdis-6.1.4-py312-none-any.whl
Algorithm Hash digest
SHA256 b58ddf1698d9c22e573c7c97b7d1917162ceddc5c14b5a12c8d5042b3d3fb803
MD5 bd5c24703c4cc0d594c04b3f914fe636
BLAKE2b-256 5c61d6ce5daf33ac21c8a9809d6ca5cf63acca5c2f3bd0bba56f90c76f2b538f

See more details on using hashes here.

File details

Details for the file xdis-6.1.4-py311-none-any.whl.

File metadata

  • Download URL: xdis-6.1.4-py311-none-any.whl
  • Upload date:
  • Size: 181.3 kB
  • Tags: Python 3.11
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.3

File hashes

Hashes for xdis-6.1.4-py311-none-any.whl
Algorithm Hash digest
SHA256 b767726edb151ea60a081ad4acf673f5ac171882bf28dadf829110259b7646f7
MD5 240bc4b01530155ade2b3b0aa6695e95
BLAKE2b-256 f92c449ddd0499da041edf6b2ebcf1388b0ece46630819e94b2fa5710fce7ca9

See more details on using hashes here.

File details

Details for the file xdis-6.1.4-py310-none-any.whl.

File metadata

  • Download URL: xdis-6.1.4-py310-none-any.whl
  • Upload date:
  • Size: 224.1 kB
  • Tags: Python 3.10
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.3

File hashes

Hashes for xdis-6.1.4-py310-none-any.whl
Algorithm Hash digest
SHA256 fe0c07b82d4e2b9cbc28b19aa3d74ecfed8e3c9448d08fe91495d756350668f6
MD5 ca1ca163550b6a87e34a04ea00cc749a
BLAKE2b-256 c78e5988895297d6bf0464fd8fbe9eeeba9feb486cd633005100bd2cb9cbd8fe

See more details on using hashes here.

File details

Details for the file xdis-6.1.4-py39-none-any.whl.

File metadata

  • Download URL: xdis-6.1.4-py39-none-any.whl
  • Upload date:
  • Size: 224.1 kB
  • Tags: Python 3.9
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.3

File hashes

Hashes for xdis-6.1.4-py39-none-any.whl
Algorithm Hash digest
SHA256 b98fc10371a7ba3036ae5f8958ec8da3ec8c45115da2404e1fb561abeec323ac
MD5 d08d82c6a6b9df1f5af7d1817046afe7
BLAKE2b-256 a9e9dec1970a136784ebb1cf7f1381ab3cf3d2c4ae6ab0ad0f0d8bcc1e2787c7

See more details on using hashes here.

File details

Details for the file xdis-6.1.4-py38-none-any.whl.

File metadata

  • Download URL: xdis-6.1.4-py38-none-any.whl
  • Upload date:
  • Size: 224.1 kB
  • Tags: Python 3.8
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.3

File hashes

Hashes for xdis-6.1.4-py38-none-any.whl
Algorithm Hash digest
SHA256 b36dd09186eefe955347ba546735163b8e56f878c5702ec73ead4b6b45c5a309
MD5 0c691d9182345bcf0211938f6b5cb0ed
BLAKE2b-256 97cf8a46db3c71950aa7fa353203f78b9ab35870a2b2be19e2f025db31394f5a

See more details on using hashes here.

File details

Details for the file xdis-6.1.4-py37-none-any.whl.

File metadata

  • Download URL: xdis-6.1.4-py37-none-any.whl
  • Upload date:
  • Size: 224.1 kB
  • Tags: Python 3.7
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.3

File hashes

Hashes for xdis-6.1.4-py37-none-any.whl
Algorithm Hash digest
SHA256 fc929a900ba5806cbc5efa0d50b33be4b906fa03301bf5e6e2f06c8b11347d17
MD5 4ca181f3d379294c6104485faa54cc5f
BLAKE2b-256 f2be2a63f96542f5603a513bbb8f975afce9e87c184d426471a30d02e20a7324

See more details on using hashes here.

File details

Details for the file xdis-6.1.4-py36-none-any.whl.

File metadata

  • Download URL: xdis-6.1.4-py36-none-any.whl
  • Upload date:
  • Size: 224.1 kB
  • Tags: Python 3.6
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.3

File hashes

Hashes for xdis-6.1.4-py36-none-any.whl
Algorithm Hash digest
SHA256 64980c9e92e8134fc6d912af106249da2ae1209ee0cb4e127e0a6a74ee508b8f
MD5 9e806357b19a381a5f0ee80f2421fcd9
BLAKE2b-256 dbf935bb4a914439ea39392e55e2ef1825b51c78a54b89bb7375cc3ad81a4e05

See more details on using hashes here.

File details

Details for the file xdis-6.1.4-py35-none-any.whl.

File metadata

  • Download URL: xdis-6.1.4-py35-none-any.whl
  • Upload date:
  • Size: 222.9 kB
  • Tags: Python 3.5
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.3

File hashes

Hashes for xdis-6.1.4-py35-none-any.whl
Algorithm Hash digest
SHA256 2b030cbda54107a2b379f0ee76ad656b8799ebec72a3118d2d0b006c577e16f1
MD5 3ff5de25b7068ce5940d8043c92bb5b9
BLAKE2b-256 cacc3bf31c1a3e1bccf061296431c1a45b8cfbd1c66840ee86d0f7110a237656

See more details on using hashes here.

File details

Details for the file xdis-6.1.4-py34-none-any.whl.

File metadata

  • Download URL: xdis-6.1.4-py34-none-any.whl
  • Upload date:
  • Size: 222.9 kB
  • Tags: Python 3.4
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.3

File hashes

Hashes for xdis-6.1.4-py34-none-any.whl
Algorithm Hash digest
SHA256 0a6e393aa659f4003a9455a4d32c3b8a24cc02ab87863bfe17dbe43f0c29e354
MD5 9fa25deb7a43e95d057a0897235492a4
BLAKE2b-256 474363578140a59229c4a1d7439049d37e02863a7a0475be71041aa10e368988

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page