cpython-lldb


Namecpython-lldb JSON
Version 0.3.2 PyPI version JSON
download
home_pagehttps://github.com/malor/cpython-lldb
SummaryLLDB extension for debugging Python programs
upload_time2023-06-05 16:37:13
maintainer
docs_urlNone
authorRoman Podoliaka
requires_python>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*
licenseMIT
keywords debugging lldb cpython
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            Overview
========

![build status](https://github.com/malor/cpython-lldb/actions/workflows/tests.yml/badge.svg)

`cpython_lldb` is an LLDB extension for debugging Python programs.

It can be useful for troubleshooting stuck threads and crashes in the interpreter
or external libraries. Unlike most Python debuggers, LLDB allows attaching to a
running process without instrumenting it in advance, as well as loading a process
coredump to perform an offline (or post-mortem) analysis of a problem.

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

While CPython already provides a similar extension for gdb [out of the box](
https://github.com/python/cpython/blob/master/Tools/gdb/libpython.py),
LLDB might be the debugger of choice on some operating systems, e.g.
on Mac OS.

This extension requires CPython to be built with debugging symbols enabled, which
is not the case for some Linux distros (notably Arch Linux). CPython official
[Docker images](https://hub.docker.com/_/python) 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:

```shell
$ 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 and tell LLDB
to load it from there, e.g. ~/.lldb:

```shell
$ 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:
```shell
$ 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:
```shell
$(lldb --print-script-interpreter-info | jq -r .executable) -m pip install cpython_lldb
```

Usage
=====

Start a new LLDB session:

```shell
$ lldb /usr/bin/python
```

or attach to an existing CPython process:

```shell
$ 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:

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

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

```shell
no type was found matching 'PyObject'
```

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

```shell
$ sudo apt-get install python-dbg
```

on CentOS / Fedora / RHEL do:

```shell
$ 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 the official [CPython](https://devguide.python.org/setup/#compiling)
or [distro](https://wiki.archlinux.org/index.php/Debug_-_Getting_Traces) documentation for instructions.

Alternatively, you can use the official CPython [Docker images](https://hub.docker.com/_/python).


Broken LLDB scripting
---------------------

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

```shell
$ 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](https://apt.llvm.org/) instead
of the one shipped with your distro.

See this [page](https://github.com/vadimcn/vscode-lldb/wiki/Troubleshooting) for advice on troubleshooting 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


            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/malor/cpython-lldb",
    "name": "cpython-lldb",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*",
    "maintainer_email": "",
    "keywords": "debugging,lldb,cpython",
    "author": "Roman Podoliaka",
    "author_email": "roman.podoliaka@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/41/47/69577abe78979fb237c133c58332376bd0162642a34e05ec78eeca691e41/cpython_lldb-0.3.2.tar.gz",
    "platform": null,
    "description": "Overview\n========\n\n![build status](https://github.com/malor/cpython-lldb/actions/workflows/tests.yml/badge.svg)\n\n`cpython_lldb` is an LLDB extension for debugging Python programs.\n\nIt can be useful for troubleshooting stuck threads and crashes in the interpreter\nor external libraries. Unlike most Python debuggers, LLDB allows attaching to a\nrunning process without instrumenting it in advance, as well as loading a process\ncoredump to perform an offline (or post-mortem) analysis of a problem.\n\nWhen analyzing the state of a Python process, normally you would only have\naccess to *intepreter-level* information: most variables would be of type\n`PyObject*`, and stack traces would only contain CPython internal calls and\ncalls to library functions. Unless you are a CPython developer troubleshooting\nthe interpreter implementation, that is typically not very useful. This extension,\nhowever, allows you to extract *application-level* information about execution of\na program: print the values of variables, list the source code, display Python\nstack traces, etc.\n\nWhile CPython already provides a similar extension for gdb [out of the box](\nhttps://github.com/python/cpython/blob/master/Tools/gdb/libpython.py),\nLLDB might be the debugger of choice on some operating systems, e.g.\non Mac OS.\n\nThis extension requires CPython to be built with debugging symbols enabled, which\nis not the case for some Linux distros (notably Arch Linux). CPython official\n[Docker images](https://hub.docker.com/_/python) are known to work correctly, as they\nare used for integration testing.\n\n\nFeatures\n========\n\n`cpython_lldb` targets CPython 3.5+ and supports the following features:\n\n* pretty-priting of built-in types (int, bool, float, bytes, str, none, tuple, list, set, frozenset, dict)\n* printing of Python-level stack traces\n* printing of local variables\n* listing the source code\n* walking up and down the Python call stack\n\nInstallation\n============\n\nIf your version of LLDB is linked against system libpython, it's recommended\nthat you install the extension to the user site packages directory and allow\nit to be loaded automatically on start of a new LLDB session:\n\n```shell\n$ python -m pip install --user cpython-lldb\n$ echo \"command script import cpython_lldb\" >> ~/.lldbinit\n$ chmod +x ~/.lldbinit\n```\n\nAlternatively, you can install the extension to some other location and tell LLDB\nto load it from there, e.g. ~/.lldb:\n\n```shell\n$ mkdir -p ~/.lldb/cpython_lldb\n$ python -m pip install --target ~/.lldb/cpython_lldb cpython-lldb\n$ echo \"command script import ~/.lldb/cpython_lldb/cpython_lldb.py\" >> ~/.lldbinit\n$ chmod +x ~/.lldbinit\n```\n\nMacOS\n-----\nLLDB bundled with MacOS is linked with the system version of CPython which may not even\nbe in your PATH. To locate the right version of the interpreter, use:\n```shell\n$ lldb --print-script-interpreter-info\n```\nThe output of the command above is a JSON with the following structure:\n```\n{\n  \"executable\":\"/Library/.../Python3.framework/Versions/3.9/bin/python3\",\n  \"language\":\"python\",\n  \"lldb-pythonpath\":\"/Library/.../LLDB.framework/Resources/Python\",\n  \"prefix\":\"/Library/.../Python3.framework/Versions/3.9\"\n}\n```\nWhere the value for \"executable\" is the CPython version that should be used to install\n`cpython_lldb` for LLDB to be able to successfully import the script:\n```shell\n$(lldb --print-script-interpreter-info | jq -r .executable) -m pip install cpython_lldb\n```\n\nUsage\n=====\n\nStart a new LLDB session:\n\n```shell\n$ lldb /usr/bin/python\n```\n\nor attach to an existing CPython process:\n\n```shell\n$ lldb /usr/bin/python -p $PID\n```\n\nIf you've followed the installation steps, the extension will now be automatically\nloaded on start of a new LLDB session and register some Python-specific commands:\n\n```\n(lldb) help\n...\nCurrent user-defined commands:\n  py-bt     -- Print a Python-level call trace of the selected thread.\n  py-down   -- Select a newer Python stack frame.\n  py-list   -- List the source code of the Python module that is currently being executed.\n  py-locals -- Print the values of local variables in the selected Python frame.\n  py-up     -- Select an older Python stack frame.\nFor more information on any command, type 'help <command-name>'.\n```\n\nPretty-printing\n---------------\n\nAll known `PyObject`'s (i.e. built-in types) are automatically pretty-printed\nwhen encountered, as if you tried to get a `repr()` of something in Python REPL,\ne.g.:\n\n```\n(lldb) frame variable v\n(PyObject *) v = 0x0000000100793c00 42\n(lldb) p v->ob_type->tp_name\n(const char *) $3 = 0x000000010017d42a \"int\"\n```\n\nStack traces\n------------\n\nUse `py-bt` to print a full application-level stack trace of the current thread, e.g.:\n\n```\n(lldb) py-bt\nTraceback (most recent call last):\n  File \"test.py\", line 15, in <module>\n    fc()\n  File \"test.py\", line 12, in fc\n    fb()\n  File \"test.py\", line 8, in fb\n    fa()\n  File \"test.py\", line 2, in fa\n    abs(1)\n```\n\nWalking up and down the call stack\n----------------------------------\n\nUse `py-up` and `py-down` to select an older or a newer Python call stack frame, e.g.:\n\n```\n(lldb) py-up\n  File \"/Users/malor/src/cpython/test.py\", line 6, in cb\n    self.ca()\n(lldb) py-up\n  File \"/Users/malor/src/cpython/test.py\", line 20, in f_static\n    c.cb()\n(lldb) py-down\n  File \"/Users/malor/src/cpython/test.py\", line 6, in cb\n    self.ca()\n(lldb) py-down\n  File \"/Users/malor/src/cpython/test.py\", line 3, in ca\n    abs(1)\n(lldb) py-down\n*** Newest frame\n```\n\nPrinting of local variables\n---------------------------\n\nUse `py-locals` to print the values of local variables in the selected frame:\n\n```\n(lldb) py-locals\na = 42\nargs = (1, 2, 3)\nb = [1, u'hello', u'\\\\u0442\\\\u0435\\\\u0441\\\\u0442']\nc = ([1], 2, [[3]])\nd = u'test'\ne = {u'a': -1, u'b': 0, u'c': 1}\neggs = 42\nkwargs = {u'foo': 'spam'}\nspam = u'foobar'\n```\n\nListing the source code\n-----------------------\n\nUse `py-list` to list the source code that is currently being executed in the selected\nPython frame, e.g.:\n\n```\n(lldb) py-list\n    1    SOME_CONST = 42\n    2\n    3\n    4    def fa():\n   >5        abs(1)\n    6        return 1\n    7\n    8\n    9    def fb():\n   10        1 + 1\n```\n\nThe command also accepts optional `start` and `end` arguments that allow to\nlist the source code within a specific range of lines, e.g.:\n\n```\n(lldb) py-list 4\n    4    def fa():\n   >5        abs(1)\n    6        return 1\n    7\n    8\n    9    def fb():\n   10        1 + 1\n   11        fa()\n   12\n   13\n   14    def fc():\n```\n\nor:\n\n```\n(lldb) py-list 4 11\n    4    def fa():\n   >5        abs(1)\n    6        return 1\n    7\n    8\n    9    def fb():\n   10        1 + 1\n   11        fa()\n```\n\nPotential issues and how to solve them\n======================================\n\nCPython 2.7.x\n-------------\n\nCPython 2.7.x is not supported. There are currently no plans to support it in the future.\n\nMissing debugging symbols\n-------------------------\n\nCPython debugging symbols are required. You can check if they are available as follows:\n\n```shell\n$ lldb /usr/bin/python\n$ (lldb) type lookup PyObject\n```\n\nIf debugging symbols are not available, you'll see something like:\n\n```shell\nno type was found matching 'PyObject'\n```\n\nSome Linux distros ship debugging symbols separately. To fix the problem on Debian / Ubuntu do:\n\n```shell\n$ sudo apt-get install python-dbg\n```\n\non CentOS / Fedora / RHEL do:\n\n```shell\n$ sudo yum install python-debuginfo\n```\n\nOther distros, like Arch Linux, do not provide debugging symbols in the package repos. In this case,\nyou would need to build CPython from source. Please refer to the official [CPython](https://devguide.python.org/setup/#compiling)\nor [distro](https://wiki.archlinux.org/index.php/Debug_-_Getting_Traces) documentation for instructions.\n\nAlternatively, you can use the official CPython [Docker images](https://hub.docker.com/_/python).\n\n\nBroken LLDB scripting\n---------------------\n\nSome Linux distros (notably Debian Stretch) are shipped with a version of LLDB in which using Python scripting\ntriggers a segmentation fault when executing any non-trivial operation:\n\n```shell\n$ lldb\n(lldb) script\nPython Interactive Interpreter. To exit, type 'quit()', 'exit()' or Ctrl-D.\n>>> import io\n>>> Segmentation fault\n```\n\nIt's recommended that you use the latest LLDB release from the official [APT repo](https://apt.llvm.org/) instead\nof the one shipped with your distro.\n\nSee this [page](https://github.com/vadimcn/vscode-lldb/wiki/Troubleshooting) for advice on troubleshooting LLDB.\n\nDevelopment\n===========\n\nRunning tests\n-------------\n\nTests currently require `make` and `docker` to be installed.\n\nTo run the tests against the *latest* released CPython version, do:\n\n```\n$ make test\n```\n\nTo run the tests against a specific CPython (or LLDB) version, do:\n\n```\n$ PY_VERSION=X.Y LLDB_VERSION=Z make test\n```\n\nSupported CPython versions are:\n* `3.7`\n* `3.8`\n* `3.9`\n* `3.10`\n\nSupported LLDB versions:\n* `7`\n* `8`\n* `9`\n* `10`\n* `11`\n\nContributors\n============\n\nKudos to everyone who have contributed to this project!\n\n* Marco Neumann\n\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "LLDB extension for debugging Python programs",
    "version": "0.3.2",
    "project_urls": {
        "Homepage": "https://github.com/malor/cpython-lldb",
        "Repository": "https://github.com/malor/cpython-lldb"
    },
    "split_keywords": [
        "debugging",
        "lldb",
        "cpython"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "d3f7bc8840efc42efd8f0b1734cfcd38483ea76882e56eea498ca61dc0d61ce1",
                "md5": "33900fbb36b0589c6c6a17d9e5873b4e",
                "sha256": "990fc6a66134ae7e1fda1eb794a17eed3e71d1f0e77ad8b86474ca1ecdb1fc8b"
            },
            "downloads": -1,
            "filename": "cpython_lldb-0.3.2-py2.py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "33900fbb36b0589c6c6a17d9e5873b4e",
            "packagetype": "bdist_wheel",
            "python_version": "py2.py3",
            "requires_python": ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*",
            "size": 14842,
            "upload_time": "2023-06-05T16:37:12",
            "upload_time_iso_8601": "2023-06-05T16:37:12.176588Z",
            "url": "https://files.pythonhosted.org/packages/d3/f7/bc8840efc42efd8f0b1734cfcd38483ea76882e56eea498ca61dc0d61ce1/cpython_lldb-0.3.2-py2.py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "414769577abe78979fb237c133c58332376bd0162642a34e05ec78eeca691e41",
                "md5": "653e22078306cffac9884f60d76ba154",
                "sha256": "2f06e7f9cf852b6ee151ed3345429536167b891854b2fb280e6f7e12db8e4e05"
            },
            "downloads": -1,
            "filename": "cpython_lldb-0.3.2.tar.gz",
            "has_sig": false,
            "md5_digest": "653e22078306cffac9884f60d76ba154",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*",
            "size": 17393,
            "upload_time": "2023-06-05T16:37:13",
            "upload_time_iso_8601": "2023-06-05T16:37:13.951464Z",
            "url": "https://files.pythonhosted.org/packages/41/47/69577abe78979fb237c133c58332376bd0162642a34e05ec78eeca691e41/cpython_lldb-0.3.2.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-06-05 16:37:13",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "malor",
    "github_project": "cpython-lldb",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "cpython-lldb"
}
        
Elapsed time: 1.77393s