Bill
Bill

Reputation: 45466

Can I tell LLDB to remove the active breakpoint?

When LLDB triggers breakpoint X, is there a command that will disable or remove X and then continue?

Upvotes: 3

Views: 1561

Answers (2)

Rik Renich
Rik Renich

Reputation: 916

Here is Jason's python 2 code as python 3 code:

# import this into lldb with a command like
# command script import disthis.py

import lldb

def disthis(debugger, command, *args):
    """Usage: disthis
Disables the breakpoint the currently selected thread is stopped at."""

    target = None
    thread = None

    if len(args) == 2:
        # Old lldb invocation style
        result = args[0]
        if debugger and debugger.GetSelectedTarget() and debugger.GetSelectedTarget().GetProcess():
            target = debugger.GetSelectedTarget()
            process = target.GetProcess()
            thread = process.GetSelectedThread()
    elif len(args) == 3:
        # New (2015 & later) lldb invocation style where we're given the execution context
        exe_ctx = args[0]
        result = args[1]
        target = exe_ctx.GetTarget()
        thread = exe_ctx.GetThread()
    else:
        print("Unknown python function invocation from lldb.")
        return

    if thread == None:
        print(result, "error: process is not paused, or has not been started yet.", file=result)
        result.SetStatus (lldb.eReturnStatusFailed)
        return

    if thread.GetStopReason() != lldb.eStopReasonBreakpoint:
        print(result, "error: not stopped at a breakpoint.", file=result)
        result.SetStatus (lldb.eReturnStatusFailed)
        return

    if thread.GetStopReasonDataCount() != 2:
        print(result, "error: Unexpected number of StopReasonData returned, expected 2, got %d" % thread.GetStopReasonDataCount(), file=result)
        result.SetStatus (lldb.eReturnStatusFailed)
        return

    break_num = thread.GetStopReasonDataAtIndex(0)
    location_num = thread.GetStopReasonDataAtIndex(1)

    if break_num == 0 or location_num == 0:
        print(result, "error: Got invalid breakpoint number or location number", file=result)
        result.SetStatus (lldb.eReturnStatusFailed)
        return

    bkpt = target.FindBreakpointByID (break_num)
    if location_num > bkpt.GetNumLocations():
        print(result, "error: Invalid location number", file=result)
        result.SetStatus (lldb.eReturnStatusFailed)
        return

    bkpt_loc = bkpt.GetLocationAtIndex(location_num - 1)
    if bkpt_loc.IsValid() != True:
        print(result, "error: Got invalid BreakpointLocation", file=result)
        result.SetStatus (lldb.eReturnStatusFailed)
        return

    bkpt_loc.SetEnabled(False)
    print("Breakpoint %d.%d disabled." % (break_num, location_num), file=result)
    return


def __lldb_init_module (debugger, dict):
    debugger.HandleCommand('command script add -f %s.disthis disthis' % __name__)

Please note that I only changed the print statements. I have only tested success and the error for not at a breakpoint.

Upvotes: 0

Jason Molenda
Jason Molenda

Reputation: 15425

That's an interesting idea. There's no built in command to do this in lldb but it would be easy to implement as a user-defined command written in Python. SBThread::GetStopReason() will be eStopReasonBreakpoint if that thread stopped because of a breakpoint. SBThread::GetStopReasonDataCount() will return 2 -- indicating that the breakpoint id and location id are available. SBThread::GetStopReasonDataAtIndex(0) will give you the breakpoint ID, SBThread::GetStopReasonDataAtIndex(1) will give you the location ID. (a single user-specified breakpoint may resolve to multiple locations. e.g. an inlined function, or a function name that occurs in multiple libraries in a single program.)

Here's a quick & dirty example of a python command that does this. I put this in ~/lldb where I save my lldb user-defined commands and then in my ~/.lldbinit file I have a line like command script import ~/lldb/disthis.py.

In use, it looks like this:

% lldb a.out
(lldb) target create "a.out"
Current executable set to 'a.out' (x86_64).
(lldb) br s -n main
Breakpoint 1: where = a.out`main + 15 at a.c:4, address = 0x0000000100000f4f
(lldb) r
Process 67487 launched: '/private/tmp/a.out' (x86_64)
Process 67487 stopped
* thread #1: tid = 0x290c51, 0x0000000100000f4f a.out`main + 15 at a.c:4, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
    #0: 0x0000000100000f4f a.out`main + 15 at a.c:4
   1    #include <stdio.h>
   2    int main()
   3    {
-> 4        puts ("HI");
   5        puts ("HI");
   6    }
(lldb) com scr imp ~/lldb/disthis.py
(lldb) disthis
Breakpoint 1.1 disabled.
(lldb) br li
Current breakpoints:
1: name = 'main', locations = 1
  1.1: where = a.out`main + 15 at a.c:4, address = 0x0000000100000f4f, unresolved, hit count = 1  Options: disabled 

(lldb) 

Pretty straightforward.

# import this into lldb with a command like
# command script import disthis.py

import lldb

def disthis(debugger, command, *args):
    """Usage: disthis
Disables the breakpoint the currently selected thread is stopped at."""

    target = None
    thread = None

    if len(args) == 2:
        # Old lldb invocation style
        result = args[0]
        if debugger and debugger.GetSelectedTarget() and debugger.GetSelectedTarget().GetProcess():
            target = debugger.GetSelectedTarget()
            process = target.GetProcess()
            thread = process.GetSelectedThread()
    elif len(args) == 3:
        # New (2015 & later) lldb invocation style where we're given the execution context
        exe_ctx = args[0]
        result = args[1]
        target = exe_ctx.GetTarget()
        thread = exe_ctx.GetThread()
    else:
        print "Unknown python function invocation from lldb."
        return

    if thread == None:
        print >>result, "error: process is not paused, or has not been started yet."
        result.SetStatus (lldb.eReturnStatusFailed)
        return

    if thread.GetStopReason() != lldb.eStopReasonBreakpoint:
        print >>result, "error: not stopped at a breakpoint."
        result.SetStatus (lldb.eReturnStatusFailed)
        return

    if thread.GetStopReasonDataCount() != 2:
        print >>result, "error: Unexpected number of StopReasonData returned, expected 2, got %d" % thread.GetStopReasonDataCount()
        result.SetStatus (lldb.eReturnStatusFailed)
        return

    break_num = thread.GetStopReasonDataAtIndex(0)
    location_num = thread.GetStopReasonDataAtIndex(1)

    if break_num == 0 or location_num == 0:
        print >>result, "error: Got invalid breakpoint number or location number"
        result.SetStatus (lldb.eReturnStatusFailed)
        return

    bkpt = target.FindBreakpointByID (break_num)
    if location_num > bkpt.GetNumLocations():
        print >>result, "error: Invalid location number"
        result.SetStatus (lldb.eReturnStatusFailed)
        return

    bkpt_loc = bkpt.GetLocationAtIndex(location_num - 1)
    if bkpt_loc.IsValid() != True:
        print >>result, "error: Got invalid BreakpointLocation"
        result.SetStatus (lldb.eReturnStatusFailed)
        return

    bkpt_loc.SetEnabled(False)
    print >>result, "Breakpoint %d.%d disabled." % (break_num, location_num)
    return


def __lldb_init_module (debugger, dict):
    debugger.HandleCommand('command script add -f %s.disthis disthis' % __name__)

Upvotes: 4

Related Questions