Skip to main content

Overview

build status

cpython_lldb is an LLDB extension for debugging Python programs.

It may be useful for troubleshooting stuck threads and crashes in the interpreter, or external libraries. Unlike most Python debuggers, LLDB allows you to attach to a running process w/o instrumenting it in advance, or load a coredump and do a post-mortem analysis of a problem.

When analyzing the state of a Python process, normally you would only have access to the intepreter-level information: every variable would be of type PyObject*, and stack traces would only contain CPython internal calls and calls to external libraries. Unless you are a CPython developer troubleshooting some bug in the implementation of the interpreter, that is typically not very useful. This extension, however, allows you to extract the application-level information about execution of a program: print the values of variables, list the source code, display Python stack traces, etc.

While CPython itself provides a similar extension for gdb out of the box, one might still prefer to use LLDB as a debugger, e.g. on Mac OS.

cpython_lldb requires CPython to be built with debugging symbols, which is not the case for some Linux distros (most notably Arch Linux). CPython official Docker images are known to work correctly, as they are used for integration testing.

Features

cpython_lldb targets CPython 3.5+ and supports the following features:

  • pretty-priting of built-in types (int, bool, float, bytes, str, none, tuple, list, set, frozenset, dict)
  • printing of Python-level stack traces
  • printing of local variables
  • listing the source code
  • walking up and down the Python call stack

Installation

If your version of LLDB is linked against system libpython, it's recommended that you install the extension to the user site packages directory and allow it to be loaded automatically on start of a new LLDB session:

$ python -m pip install --user cpython-lldb
$ echo "command script import cpython_lldb" >> ~/.lldbinit
$ chmod +x ~/.lldbinit

Alternatively, you can install the extension to some other location on disk and tell LLDB to load it from there, e.g. ~/.lldb:

$ mkdir -p ~/.lldb/cpython_lldb
$ python -m pip install --target ~/.lldb/cpython_lldb cpython-lldb
$ echo "command script import ~/.lldb/cpython_lldb/cpython_lldb.py" >> ~/.lldbinit
$ chmod +x ~/.lldbinit

MacOS

LLDB bundled with MacOS is linked with the system version of CPython which may not even be in your PATH. To locate the right version of the interpreter, use:

$ lldb --print-script-interpreter-info

The output of the command above is a JSON with the following structure:

{
  "executable":"/Library/.../Python3.framework/Versions/3.9/bin/python3",
  "language":"python",
  "lldb-pythonpath":"/Library/.../LLDB.framework/Resources/Python",
  "prefix":"/Library/.../Python3.framework/Versions/3.9"
}

Where the value for "executable" is the CPython version that should be used to install cpython_lldb for LLDB to be able to successfully import the script:

$(lldb --print-script-interpreter-info | jq -r .executable) -m pip install cpython_lldb

Usage

Start a new LLDB session:

$ lldb /usr/bin/python

or attach to an existing CPython process:

$ lldb /usr/bin/python -p $PID

If you've followed the installation steps, the extension will now be automatically loaded on start of a new LLDB session and register some Python-specific commands:

(lldb) help
...
Current user-defined commands:
  py-bt     -- Print a Python-level call trace of the selected thread.
  py-down   -- Select a newer Python stack frame.
  py-list   -- List the source code of the Python module that is currently being executed.
  py-locals -- Print the values of local variables in the selected Python frame.
  py-up     -- Select an older Python stack frame.
For more information on any command, type 'help <command-name>'.

Pretty-printing

All known PyObject's (i.e. built-in types) are automatically pretty-printed when encountered, as if you tried to get a repr() of something in Python REPL, e.g.:

(lldb) frame variable v
(PyObject *) v = 0x0000000100793c00 42
(lldb) p v->ob_type->tp_name
(const char *) $3 = 0x000000010017d42a "int"

Stack traces

Use py-bt to print a full application-level stack trace of the current thread, e.g.:

(lldb) py-bt
Traceback (most recent call last):
  File "test.py", line 15, in <module>
    fc()
  File "test.py", line 12, in fc
    fb()
  File "test.py", line 8, in fb
    fa()
  File "test.py", line 2, in fa
    abs(1)

Walking up and down the call stack

Use py-up and py-down to select an older or a newer Python call stack frame, e.g.:

(lldb) py-up
  File "/Users/malor/src/cpython/test.py", line 6, in cb
    self.ca()
(lldb) py-up
  File "/Users/malor/src/cpython/test.py", line 20, in f_static
    c.cb()
(lldb) py-down
  File "/Users/malor/src/cpython/test.py", line 6, in cb
    self.ca()
(lldb) py-down
  File "/Users/malor/src/cpython/test.py", line 3, in ca
    abs(1)
(lldb) py-down
*** Newest frame

Printing of local variables

Use py-locals to print the values of local variables in the selected frame:

(lldb) py-locals
a = 42
args = (1, 2, 3)
b = [1, u'hello', u'\\u0442\\u0435\\u0441\\u0442']
c = ([1], 2, [[3]])
d = u'test'
e = {u'a': -1, u'b': 0, u'c': 1}
eggs = 42
kwargs = {u'foo': 'spam'}
spam = u'foobar'

Listing the source code

Use py-list to list the source code that is currently being executed in the selected Python frame, e.g.:

(lldb) py-list
    1    SOME_CONST = 42
    2
    3
    4    def fa():
   >5        abs(1)
    6        return 1
    7
    8
    9    def fb():
   10        1 + 1

The command also accepts optional start and end arguments that allow to list the source code within a specific range of lines, e.g.:

(lldb) py-list 4
    4    def fa():
   >5        abs(1)
    6        return 1
    7
    8
    9    def fb():
   10        1 + 1
   11        fa()
   12
   13
   14    def fc():

or:

(lldb) py-list 4 11
    4    def fa():
   >5        abs(1)
    6        return 1
    7
    8
    9    def fb():
   10        1 + 1
   11        fa()

Potential issues and how to solve them

CPython 2.7.x

CPython 2.7.x is not supported. There are currently no plans to support it in the future.

Missing debugging symbols

CPython debugging symbols are required. You can check if they are available as follows:

$ lldb /usr/bin/python
$ (lldb) type lookup PyObject

If debugging symbols are not available, you'll see something like:

no type was found matching 'PyObject'

Some Linux distros ship debugging symbols separately. To fix the problem on Debian / Ubuntu do:

$ sudo apt-get install python-dbg

on CentOS / Fedora / RHEL do:

$ sudo yum install python-debuginfo

Other distros, like Arch Linux, do not provide debugging symbols in the package repos. In this case, you would need to build CPython from source. Please refer to official CPython or distro docs for instructions.

Alternatively, you can use official CPython Docker images.

Broken LLDB scripting

Some Linux distros (most notably Debian Stretch) are shipped with a version of LLDB in which Python scripting triggers a segmentation fault when executing any non-trivial operation:

$ lldb
(lldb) script
Python Interactive Interpreter. To exit, type 'quit()', 'exit()' or Ctrl-D.
>>> import io
>>> Segmentation fault

It's recommended that you use the latest LLDB release from the official APT repo instead of the one shipped with your distro.

See this page for advice on troubleshooting of LLDB.

Development

Running tests

Tests currently require make and docker to be installed.

To run the tests against the latest released CPython version, do:

$ make test

To run the tests against a specific CPython (or LLDB) version, do:

$ PY_VERSION=X.Y LLDB_VERSION=Z make test

Supported CPython versions are:

  • 3.7
  • 3.8
  • 3.9
  • 3.10

Supported LLDB versions:

  • 7
  • 8
  • 9
  • 10
  • 11

Contributors

Kudos to everyone who have contributed to this project!

  • Marco Neumann

Download files

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

Source Distribution

cpython_lldb-0.3.1.tar.gz (17.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

cpython_lldb-0.3.1-py2.py3-none-any.whl (14.8 kB view details)

Uploaded Python 2Python 3

File details

Details for the file cpython_lldb-0.3.1.tar.gz.

File metadata

  • Download URL: cpython_lldb-0.3.1.tar.gz
  • Upload date:
  • Size: 17.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.4.2 CPython/3.11.3 Linux/5.15.0-1037-azure

File hashes

Hashes for cpython_lldb-0.3.1.tar.gz
Algorithm Hash digest
SHA256 58c8a8c9fd0341ca18d7679fc17997d0481e1cf6a96b7a3a82318279428ff8c3
MD5 a88f520e57da8ce0d469a4c4d699d019
BLAKE2b-256 42a53cc8bb29e42267abe909908910a76fead42c9c12723c2bc81e5ae09a57ac

See more details on using hashes here.

File details

Details for the file cpython_lldb-0.3.1-py2.py3-none-any.whl.

File metadata

  • Download URL: cpython_lldb-0.3.1-py2.py3-none-any.whl
  • Upload date:
  • Size: 14.8 kB
  • Tags: Python 2, Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.4.2 CPython/3.11.3 Linux/5.15.0-1037-azure

File hashes

Hashes for cpython_lldb-0.3.1-py2.py3-none-any.whl
Algorithm Hash digest
SHA256 a48a99d3053d17df54ac073e2ac6075e335a60f557db117621cc6a40e3a4dc32
MD5 4bcd47ea0d2bae6f4f6308a7c6ad439e
BLAKE2b-256 99718b0a19a3bf596ad4b2ba83f0a9247143ea2ed2e22e8185a030f6e720e61d

See more details on using hashes here.

Release history Release notifications | RSS feed

0.3.3

2 files

0.3.2

2 files

This release

0.3.1 This release

2 files

0.3.0

2 files

0.2.1

2 files

0.2.0

1 file

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page