pythonscriptinglldb

LLDB breaks on adding a breakpoint using python


I want a LLDB breakpoint callback to add another breakpoint on the next frame in the callstack.

For this I have a file trace_mvp.py with the following code:

import lldb

def syscall_callback(frame: lldb.SBFrame, bp_loc, internal_dict):
    print("[+] Entering syscall_callback")
    thread = frame.GetThread()

    # print backtrace for debug
    for frame in thread.get_thread_frames():
        print(frame)

    # address of the next frame
    next_frame_pc = thread.get_thread_frames()[1].GetPC()
   
    print("[+] Add breakpoint at : ", hex(next_frame_pc))
    target = thread.GetProcess().GetTarget()
    bp = target.BreakpointCreateByAddress(next_frame_pc)
    bp.SetScriptCallbackFunction("trace_mvp.bp_callback")
    print(bp)


def bp_callback(frame: lldb.SBFrame, bp_loc, internal_dict):
    print("[+] Hello from bp_callback")

def __lldb_init_module(debugger, internal_dict):
    debugger.HandleCommand('breakpoint set -n write')
    debugger.HandleCommand('breakpoint command add -s python -F trace_mvp.syscall_callback')
    debugger.HandleCommand('run')  

This code adds a breakpoint on all write syscall. Then, at each stop it is supposed to add another breakpoint on the frame above in the stack, and print a message when it reaches it.

On the side I have a small Python file with a single print

print("Hello world")

In the terminal I run

# in bash
lldb python hello_world.py
# inside LLDB
command script import trace_mvp.py

On running the syscall_callback the breakpoint is added to the right address (here 0x101328b74) but LLDB still raises an error

Breakpoint 1: 137 locations.
Process 8128 launched: '/Users/macm1/.venv/bin/python' (arm64)
14 locations added to breakpoint 1
frame #0: 0x0000000188f758ec libsystem_kernel.dylib`write
frame #1: 0x0000000101328b74 libpython3.11.dylib`_Py_write_impl + 128
[rest of the stack]
[+] Add breakpoint at :  0x101328b74
SBBreakpoint: id = 2, address = libpython3.11.dylib[0x0000000000174b74], locations = 1
Traceback (most recent call last):
  File "<string>", line 8, in lldb_autogen_python_bp_callback_func__0
KeyError: 'lldb_autogen_python_bp_callback_func__1'
Process 8128 stopped

When I set the wrong function name on purpose, the error is not raised.

Am I doing something wrong or is it a bug from LLDB?

I'm running on macOS 15.1 with LLDB lldb-1600.0.39.109


Solution

  • That's a bug in how lldb manages setting up and tearing down the state of the individual Python interpreters (since lldb supports more than one Debugger at a time and each debugger has an isolated interpreter, we have to do state swapping to the right interpreter context)

    If you are so motivated, please file a bug with lldb's issues page:

    https://github.com/llvm/llvm-project/issues

    Note, if what you are trying to do is have one breakpoint trigger stepping back out of the function that it stopped in and then doing something, you can also do that by having the first breakpoint queue up a "scripted step" that does the step out and gather information. That's sometimes more convenient since lldb will manage the details of the execution control for you.

    There's an example that does that in the FinishPrintAndContinue plan in the scripted_step.py examples here:
    https://github.com/llvm/llvm-project/blob/main/lldb/examples/python/scripted_step.py

    The top of that file has some docs describing how these work. You can also use these plans directly from Python with SBThread.StepUsingScriptedThreadPlan.