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][#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.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 -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

This version

6.1.2

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.2.tar.gz (434.5 kB view details)

Uploaded Source

Built Distributions

xdis-6.1.2-py313-none-any.whl (190.1 kB view details)

Uploaded Python 3.13

xdis-6.1.2-py312-none-any.whl (190.1 kB view details)

Uploaded Python 3.12

xdis-6.1.2-py311-none-any.whl (183.1 kB view details)

Uploaded Python 3.11

xdis-6.1.2-py310-none-any.whl (208.4 kB view details)

Uploaded Python 3.10

xdis-6.1.2-py39-none-any.whl (208.4 kB view details)

Uploaded Python 3.9

xdis-6.1.2-py38-none-any.whl (208.4 kB view details)

Uploaded Python 3.8

xdis-6.1.2-py37-none-any.whl (208.4 kB view details)

Uploaded Python 3.7

xdis-6.1.2-py36-none-any.whl (208.4 kB view details)

Uploaded Python 3.6

File details

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

File metadata

  • Download URL: xdis-6.1.2.tar.gz
  • Upload date:
  • Size: 434.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.13.0

File hashes

Hashes for xdis-6.1.2.tar.gz
Algorithm Hash digest
SHA256 b297896de1498350c6c1245de6007800e74f215fd0b55f5e088d23dbac44901e
MD5 4f4203a379ed1c70a8a13ef1bee62f90
BLAKE2b-256 ca3410c4929362628081239f4b04f5ceb8b934118a0554a03b8e652bbfe41287

See more details on using hashes here.

File details

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

File metadata

  • Download URL: xdis-6.1.2-py313-none-any.whl
  • Upload date:
  • Size: 190.1 kB
  • Tags: Python 3.13
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.13.0

File hashes

Hashes for xdis-6.1.2-py313-none-any.whl
Algorithm Hash digest
SHA256 81c3f8b4d433edaa93e592e64284dbfa6bd70f1d4a7539e3838773c7cfab6891
MD5 0e6a62d6c9a34b221b945268b69d6b07
BLAKE2b-256 097ad7264db20c02fc0f11dedccf9ae9364fd0bc9fa632eaa302da373c0f32d8

See more details on using hashes here.

File details

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

File metadata

  • Download URL: xdis-6.1.2-py312-none-any.whl
  • Upload date:
  • Size: 190.1 kB
  • Tags: Python 3.12
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.13.0

File hashes

Hashes for xdis-6.1.2-py312-none-any.whl
Algorithm Hash digest
SHA256 765437dc962bf980800efbeab98cb81e9695a596ea47dcbc616ca4c3a6498891
MD5 0b2a4d964ca203626d92af82015ecd9c
BLAKE2b-256 f56182e7b0ef919646b371e370526f990f01d93bd0cf528f50a59625a510c30d

See more details on using hashes here.

File details

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

File metadata

  • Download URL: xdis-6.1.2-py311-none-any.whl
  • Upload date:
  • Size: 183.1 kB
  • Tags: Python 3.11
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.13.0

File hashes

Hashes for xdis-6.1.2-py311-none-any.whl
Algorithm Hash digest
SHA256 b17e93d49ff2ba4098fd26c38c532363cfe250be4262dec0433bc93f23bacf5a
MD5 2994cb39d128c1552127064e0ab580c2
BLAKE2b-256 a4415962b2132cb83814886b212c4658de7253d6da65b707154b663e625f5cdd

See more details on using hashes here.

File details

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

File metadata

  • Download URL: xdis-6.1.2-py310-none-any.whl
  • Upload date:
  • Size: 208.4 kB
  • Tags: Python 3.10
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.13.0

File hashes

Hashes for xdis-6.1.2-py310-none-any.whl
Algorithm Hash digest
SHA256 fb95a3ff00f04b9d2bf0c039a60e5d28654504298f8ec3aaf905470ded32a035
MD5 d4cbda24c7bad8ed740ad28cbd639f55
BLAKE2b-256 72ef6010086f81b4cb6a2e0cd3dacfee7d635403ac602639d99d4a0fefbbdf7e

See more details on using hashes here.

File details

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

File metadata

  • Download URL: xdis-6.1.2-py39-none-any.whl
  • Upload date:
  • Size: 208.4 kB
  • Tags: Python 3.9
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.13.0

File hashes

Hashes for xdis-6.1.2-py39-none-any.whl
Algorithm Hash digest
SHA256 d206b6e2f7ad35d481963798412b987aa4a7ff9175f70c0ad9931edc4fecdb55
MD5 f2f360863b945f80b49bc08c6171082f
BLAKE2b-256 ae4fc28ae4864466dade6712afb136c7faef0ccbd0eae5e99a17a30351b21b28

See more details on using hashes here.

File details

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

File metadata

  • Download URL: xdis-6.1.2-py38-none-any.whl
  • Upload date:
  • Size: 208.4 kB
  • Tags: Python 3.8
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.13.0

File hashes

Hashes for xdis-6.1.2-py38-none-any.whl
Algorithm Hash digest
SHA256 fc181c72ef494e16c5b27fd0508c3c4599ddb02a7d010161e0dd85ba0d73ee74
MD5 78bd50f68b85bedac560c3a25bbd6939
BLAKE2b-256 e13a9d8369a74dc6a62203b760ce0e9c79e08d9c55c96e38dcf315d50962500d

See more details on using hashes here.

File details

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

File metadata

  • Download URL: xdis-6.1.2-py37-none-any.whl
  • Upload date:
  • Size: 208.4 kB
  • Tags: Python 3.7
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.13.0

File hashes

Hashes for xdis-6.1.2-py37-none-any.whl
Algorithm Hash digest
SHA256 03bcd360e052487b3a42cd2ee4a3523335fd66e461d5ef84a98fd9e2fafcd95a
MD5 e733f7d60fe118c2687de0a127be0599
BLAKE2b-256 c5ae1ae2c0fb3df790fb17065263bf512054b95b9f1f55fc24555d2c90dd19de

See more details on using hashes here.

File details

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

File metadata

  • Download URL: xdis-6.1.2-py36-none-any.whl
  • Upload date:
  • Size: 208.4 kB
  • Tags: Python 3.6
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.13.0

File hashes

Hashes for xdis-6.1.2-py36-none-any.whl
Algorithm Hash digest
SHA256 537966a56f92384d4c84ce9dbd69538a7d70ca559aec7c6d7c6167b37cf0231c
MD5 d789a471faa583a382b86a101c59ab0b
BLAKE2b-256 c8359afc17354073ef3f9b8d0c63a71b3eb9f9c9e5c4c5001b50ed9212fe69bd

See more details on using hashes here.

Supported by

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