Debugging Python scripts (backtraces, variables) with LLDB

Hello,

I’ve searched for information wether it is possible to debug a python script using LLDB, and haven’t found anything so far.

Specifically I’m interested in an LLDB counterpart to what GDB provides (the two main pages being https://wiki.python.org/moin/DebuggingWithGdb and http://fedoraproject.org/wiki/Features/EasierPythonDebugging ).

So python stack traces, python values, etc.

I assume this is not implemented, but are there any plans, or is it even feasible to implement?

Regards, Alex.

Nothing of this sort has been done to my knowledge, and I haven't heard of any plans to do so either.

It should certainly be possible, you just need to grub the C stack and recognize the pattern of a Python stack frame in it and where said frame stashes away the arguments & locals, and then re-present it as a Python frame. The SB API's should make that fairly straight forward.

It looks like the Python work in gdb is based on a generic "frame filter" concept in the gdb Python API's. That's something Greg and I talked about when working on gdb way back, and has been a future goal for lldb from the start, but it hasn't ever gotten beyond discussion to date. We already have the notion of a "thread provider" which allows the Mach Kernel plugin to present its activations as threads in lldb. You could do much the same thing in lldb, where a thread would have the native unwind based stack frame and then pluggable StackFrame provider that would show different representations of the stack.

If anybody is interested in taking on such a project, that would be very cool.

Jim

Thanks for replying, it's good to know what the status is at least, as well as how it's done in GDB.

Hello,

It's been a while since I asked this question on the mailing list ( 2~ years ago).

I am interested in what would be the current best way for implementing interleaved / mixed-mode Python backtraces when debugging the CPython interpreter.

So if I run lldb -- python /path/to/my/script, set a breakpoint somewhere in the C code, and then do "bt", I would see a list of both C stack frames and Python stack frames, and if I do "frame select x" for a python frame, I could inspect the Python locals for instance.

Last time I asked, Jim mentioned using a custom "thread provider". Would this still be the way to go?

I also saw mentions of Java / Go support in the VCS log, but the support was removed due to no maintainers, so I don't know if that would also be the best way of doing it for Python.

I would appreciate, if someone could point me to some relevant code that does something similar to what I'm asking, so I could use it as a base point for exploration.

Many thanks.

Not strictly related to LLDB but you might find this interesting: https://blogs.dropbox.com/tech/2018/11/crash-reporting-in-desktop-python-applications

Not sure how much it will help you, but on Windows if you’re using MS Visual Studio, their debugger does this. You can seamlessly step between managed and native code and see Python callstacks interspersed with native callstacks. It’s all open source but it’s quite a lot of code to dig through, and unless you have a Windows machien, you won’t be able to play around with it anyway.

https://github.com/Microsoft/PTVS/tree/master/Python/Product

Thanks. That’s useful info that covers the “squishing” of C frames into Python frames.

The link to the slides at the end also mentions two other useful projects for walking the stack, py-spy and pyflame.

Having said that, I’m more interested on the “lldb” side of things.

Thanks for the link. I’m aware that VS provides that functionality (although I forgot that it was open-source).

My aim would be to implement something similar in LLDB though.

lldb does have an affordance for synthetic threads, but at present, those have to be memory threads, and once you have the 0th frame, they are backtraced just like ordinary threads. So they are a start but don't provide a way to make up synthetic frames within a thread. So I don't think that they do what you want exactly.

Recently, Kuba added the notion of a "frame recognizer" that can detect certain frames and alter their presentation. The first use is adding variables to a frame - mostly to provide argument values to known functions for which you don't have debug information.
You could use that directly, recognizing the python "push a new stack frame" function and adding the Python locals as new variables. The problem you will run into here is that we don't have a Python type system, so you'd have to represent these variables as C types.

In my original notion of the frame recognizers, I thought we would have more the directives like: "hide the next X frames", and "redirect the source info for this frame" and "change the language of this frame". Then the higher layer frame printing code would follow the recognizer directives to produce a mixed stack frame. There isn't any support for this in what Kuba did, but I think the framework he put in place could be extended along these lines to do the sort of thing you are thinking of.

Jim