Skip to main content

GDB-like Debugger for x-python in the Trepan family

Project description

Abstract

This is a gdb-like debugger focusing on Python bytecode. So far as I know, this is the only debugger available specifically for Python bytecode.

However to do this, you need to use underneath x-python: a Python Interpreter written in Python.

This project builds off of a previous Python 3 debugger called trepan3k.

Example

demo

Below we'll try to break down what's going on above.

We'll invoke the a Greatest Common Divisors program gcd.py using our debugger. The source is found in test/example/gcd.py.

In this section we'll these some interesting debugger commands that are not common in Python debuggers:

  • stepi to step a bytecode instruction
  • set loglevel to show a the x-python log "info"-level log tracing.
  • info stack to show the current stack frame evaluation stack
$ trepan-xpy test/example/gcd.py 3 5
 Running x-python test/example/gcd.py with ('3', '5')
 (test/example/gcd.py:10): <module>
 -> 2 """
 (trepan-xpy)
 

Above we are stopped before we have even run the first instruction. The -> icon before 2 means we are stopped calling a new frame.

(trepan-xpy) step
(test/example/gcd.py:2): <module>
-- 2 """Greatest Common Divisor"""
@ 0: LOAD_CONST 'Greatest Common Divisor'

Ok, now we are stopped before the first instruction LOAD_CONST which will load a constant onto the evaluation stack. The icon changed from -> 2 to -- 2 which indicates we are on a line-number boundary at line 2.

The Python construct we are about to perform is setting the program's docstring. Let's see how that is implemented.

First we see that the variable __doc__ which will eventually hold the docstring isn't set:

We see here that the first part is loading this constant onto an evaluation stack.

At this point, to better see the execution progress we'll issue the command set loglevel which will show the instructions as we step along.

Like trepan3k, trepan-xpy has extensive nicely formatted help right in the debugger. Let's get the help for the set loglevel command:

(trepan-xpy) help set loglevel
set loglevel [ on | off | debug | info ]

Show loglevel PyVM logger messages. Initially logtracing is off.

However running set loglevel will turn it on and set the log level to debug.
So it's the same thing as set loglevel debug.

If you want the less verbose messages, use info. And to turn off, (except
critical errors), use off.

Examples:

     set loglevel         # turns x-python on info logging messages
     set loglevel info    # same as above
     set loglevel debug   # turn on info and debug logging messages
     set loglevel off     # turn off all logging messages except critical ones


So now lets's set that:

(trepan-xpy) set loglevel
(trepan-xpy)

A rather unique command that you won't find in most Python debuggers but is in low-level debuggers is stepi which steps and instruction. Let's use that:

(trepan-xpy) stepi
(test/example/gcd.py:2 @2): <module>
.. 2 """Greatest Common Divisor"""
@ 2: STORE_NAME 'Greatest Common Divisor') __doc__

The .. at the beginning indicates that we are on an instruction which is in between lines.

We've now loaded the docstring onto the evaluation stack with LOAD_CONST Let's see the evaluation stack with info stack:

(trepan-xpy) info stack
0: <class 'str'> 'Greatest Common Divisor'

Here we have pushed the docstring for the program but haven't yet stored that in __doc__. To see this, can use the auto-eval feature of trepan-xpy: it will automatically evaluate strings it doesn't recognize as a debugger command:

(trepan-xpy) __doc__ is None
True

Let's step the remaining instruction, STORE_NAME to complete the instructions making up line 1.

trepan-xpy) stepi
INFO:xpython.vm:L. 10  @  4: LOAD_CONST 0
(test/example/gcd.py:10 @4): <module>
-- 10 import sys
@ 4: LOAD_CONST 0

The leading -- before 10 import... indicates we are on a line boundary now. Let's see the stack now that we have run STORE_NAME:

(trepan-xpy) info stack
Evaluation stack is empty

And to see that we've stored this in __doc__ we can run eval to see its value:

(trepan-xpy) eval __doc__
"Greatest Common Divisor"

(Entering just _doc_ is the same thing as eval __doc__ when auto-evaluation is on.

Now let's step a statement (not instructions), to see how a module becomes visable.

(trepan-xpy) step
INFO:xpython.vm:       @  6: LOAD_CONST None
INFO:xpython.vm:       @  8: IMPORT_NAME (0, None) sys
INFO:xpython.vm:       @ 10: STORE_NAME (<module 'sys' (built-in)>)
INFO:xpython.vm:L. 12  @ 12: LOAD_CONST <code object check_args at 0x7f2a0a286f60, file "test/example/gcd.py", line 12>
(test/example/gcd.py:12 @12): <module>
-- 12 def check_args():
@ 12: LOAD_CONST <code object check_args at 0...est/example/gcd.py", line 12>

The INFO are initiated by the VM interpreter. As a result of the set loglevel the interpreters logger log level was increased. This in turn causes a callback is made to a formatting routine provided by the debugger to nicly colorize the information. And that is why parts of this are colorized in a terminal session. In x-python you can get the same information, just not colorized.

One thing to note is the value after the operand and in parenthesis, like after STORE NAME. Compare that line with what you'll see from a static disassembly like Python's dis or xdis version of that:

10 STORE_NAME                1 (sys)

In a static disassembler, the "1" indicates the name index in the code object. The value in parenthesis is what that name, here at index 1 is, namely sys.

In trepan-xpy and x-python however we omit the name index, 1, since that isn't of much interest. Instead we show that dynamic stack entries or operands that STORE_NAME is going to work on. In particular the object that is going to be stored in variable sys is the built-in module sys.

Now let's step another statement to see how a function becomes available:

trepan-xpy) step
INFO:xpython.vm:       @ 14: LOAD_CONST 'check_args'
INFO:xpython.vm:       @ 16: MAKE_FUNCTION (check_args) Neither defaults, keyword-only args, annotations, nor closures
INFO:xpython.vm:       @ 18: STORE_NAME (<Function check_args at 0x7fdb1d4d49f0>) check_args
INFO:xpython.vm:L. 25  @ 20: LOAD_CONST <code object gcd at 0x7fdb1d55fed0, file "test/example/gcd.py", line 25>
(test/example/gcd.py:25 @20): <module>
-- 25 def gcd(a,b):
@ 20: LOAD_CONST <code object gcd at 0x7fdb1d...est/example/gcd.py", line 25>

A difference between a dynamic language like Python and a statically compiled language like C, or Java is that there is no linking step in the complation; modules and functions are imported or created and linked as part of the execution of the code.

Notice again what's in the parenthesis after the opcode and how that differs from a static disassembly. For comparison here is what 2nd and 3rd instruction look like from pydisasm:

16 MAKE_FUNCTION             0 (Neither defaults, keyword-only args, annotations, nor closures)
18 STORE_NAME                2 (check_args)

Again, indices into a name table are dropped and in their place are the evaluation stack items. For MAKE_FUNCTION the name of the function that is created is shown; while for STORE_NAME, as before, the item that gets stored (a function object) is shown.

The rest of the screencast shows that in addition to the step (step into) and stepi (step instruction) debugger commands there is a next or step over debugger command, and a slightly buggy finish (step out) command

I don't have breakpoints hooked in yet.

But in contrast to any other Python debugger I know about, we can cause an immediate return with a value and that is shown in the screencast.

We've only show a few of the many debugger features.

Bytecode-specific commands

Here are some interesting commands not typically found in Python debuggers, like pdb

  • info blocks lets you see the block stack
  • set pc <offset> lets you set the Program counter within the frame
  • set autopc runs info pc to show the debugged program's program counter before each time the debugger's command-loop REPL is run.
  • set autostack runs info stack to show the debugged program's evaluation stack before each time the debugger's command-loop REPL is run.
  • vmstack {peek | push, pop} - inspects or modifies evaluation stack

See Also

Project details


Download files

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

Source Distribution

trepanxpy-1.1.1.tar.gz (962.4 kB view details)

Uploaded Source

Built Distributions

trepanxpy-1.1.1-py310-none-any.whl (63.7 kB view details)

Uploaded Python 3.10

trepanxpy-1.1.1-py39-none-any.whl (63.7 kB view details)

Uploaded Python 3.9

trepanxpy-1.1.1-py38-none-any.whl (63.7 kB view details)

Uploaded Python 3.8

trepanxpy-1.1.1-py37-none-any.whl (63.7 kB view details)

Uploaded Python 3.7

trepanxpy-1.1.1-py36-none-any.whl (63.7 kB view details)

Uploaded Python 3.6

File details

Details for the file trepanxpy-1.1.1.tar.gz.

File metadata

  • Download URL: trepanxpy-1.1.1.tar.gz
  • Upload date:
  • Size: 962.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.0.0 CPython/3.10.14

File hashes

Hashes for trepanxpy-1.1.1.tar.gz
Algorithm Hash digest
SHA256 ce94359404a46a67ff1a9f6195588beffe3cdb43ff8b45d6fc4828ff91a3daca
MD5 65c98a0b4ea456b759cb10752e027d6c
BLAKE2b-256 344b472526034a01ca45d5c126870cda83f8d9e78e88ac0d29bc3f863f4dbe03

See more details on using hashes here.

File details

Details for the file trepanxpy-1.1.1-py310-none-any.whl.

File metadata

  • Download URL: trepanxpy-1.1.1-py310-none-any.whl
  • Upload date:
  • Size: 63.7 kB
  • Tags: Python 3.10
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.0.0 CPython/3.10.14

File hashes

Hashes for trepanxpy-1.1.1-py310-none-any.whl
Algorithm Hash digest
SHA256 4c7cd0467499aa1b67d00e30177017eec8e54d2defb1d5801567e702aaffba4f
MD5 8d4745bff65c9e9638baf809f482c823
BLAKE2b-256 46c42b484e96631634db43b720bcdd97528099b1239683865d126cbc503e060a

See more details on using hashes here.

File details

Details for the file trepanxpy-1.1.1-py39-none-any.whl.

File metadata

  • Download URL: trepanxpy-1.1.1-py39-none-any.whl
  • Upload date:
  • Size: 63.7 kB
  • Tags: Python 3.9
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.0.0 CPython/3.10.14

File hashes

Hashes for trepanxpy-1.1.1-py39-none-any.whl
Algorithm Hash digest
SHA256 070d92f6a92571ba5b22d0fcc31fafc4818c73d9af2352fd7b9b08ca11e910fa
MD5 3a99882e35e2b2a0e3d5e4110de983a8
BLAKE2b-256 dcf6c87305b4f33a09131a9a4d07de1d329c71b7317be4c17ee4de9406067ce8

See more details on using hashes here.

File details

Details for the file trepanxpy-1.1.1-py38-none-any.whl.

File metadata

  • Download URL: trepanxpy-1.1.1-py38-none-any.whl
  • Upload date:
  • Size: 63.7 kB
  • Tags: Python 3.8
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.0.0 CPython/3.10.14

File hashes

Hashes for trepanxpy-1.1.1-py38-none-any.whl
Algorithm Hash digest
SHA256 3e8ccd36380be063d2cff3ae1ca51379b8e99df50a08997738de802bd4b4a095
MD5 5489530ef3925609590b8b78fb7e3901
BLAKE2b-256 57d44dffdca2c190c07971f0ae60834a4a9fbfa83b7d8090d0bbfcad3025048b

See more details on using hashes here.

File details

Details for the file trepanxpy-1.1.1-py37-none-any.whl.

File metadata

  • Download URL: trepanxpy-1.1.1-py37-none-any.whl
  • Upload date:
  • Size: 63.7 kB
  • Tags: Python 3.7
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.0.0 CPython/3.10.14

File hashes

Hashes for trepanxpy-1.1.1-py37-none-any.whl
Algorithm Hash digest
SHA256 32cfc8154439e8b889303233fd5721b79de88ba6316441f877c125e95994f8ea
MD5 4db476a3afb139eda259c674af11e3e3
BLAKE2b-256 caf3e651f15cd4785aa1019c1cf2aa5292349963cf055d9c08e010627272b874

See more details on using hashes here.

File details

Details for the file trepanxpy-1.1.1-py36-none-any.whl.

File metadata

  • Download URL: trepanxpy-1.1.1-py36-none-any.whl
  • Upload date:
  • Size: 63.7 kB
  • Tags: Python 3.6
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.0.0 CPython/3.10.14

File hashes

Hashes for trepanxpy-1.1.1-py36-none-any.whl
Algorithm Hash digest
SHA256 8cf2668417ac962cd114b575f7a234d5c4dec0adf4bf7a568d54c37b63a169df
MD5 2575f70c40124edebb9e080f853d6c78
BLAKE2b-256 cd66f78c526572ec3362113ed72ac534f4a97e3d16f2769fd3e1e14142e0aab9

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