python interface breakpoint commands and expression results

I’ve been working on a script to store and fetch stack traces for gcd and I’ve got it working if I set the symbolic breakpoints manually, but if I set the breakpoints in the script, one of my breakpoints never hits and the command attached to it behaves weirdly:

This is the function to make the breakpoints in the script

def set_dispatch_breakpoints(debugger, command, result, dict):
debugger.HandleCommand(‘breakpoint set -F dispatch_async’)
breakpointcount =
debugger.HandleCommand(“breakpoint command add -s command {index} -o ‘store_stack -a $arg2’”.format(index=breakpointcount))
debugger.HandleCommand(‘breakpoint set -F _dispatch_call_block_and_release’)
breakpointcount =
lldb.debugger.HandleCommand(“breakpoint command add -s command {index} -o ‘print_stack -a $arg1’”.format(index=breakpointcount))

The breakpoints get made (using a debugging command on a breakpoint in main to call set_dispatch_breakpoints)

(lldb) b
breakpoint list --full
Current breakpoints:
1: file =‘main.m’, line = 27, locations = 1, resolved = 1

1.1: where = BlockStack`main + 22 at main.m:27, address = 0x0000000100001c36, resolved, hit count = 1

2: name = ‘dispatch_async’, locations = 1, resolved = 1
Breakpoint commands:
store_stack -a $arg2

2.1: where = libdispatch.dylib`dispatch_async, address = 0x00007fff89753cb5, resolved, hit count = 0

3: name = ‘_dispatch_call_block_and_release’, locations = 1, resolved = 1
Breakpoint commands:
print_stack -a $arg1

3.1: where = libdispatch.dylib`_dispatch_call_block_and_release, address = 0x00007fff89751a74, resolved, hit count = 0

and the second break point gets called and the expression looking up the functions argument memory address description works as expected. The third breakpoint never hits, but it’s debug command does. The debug command that hits for the third breakpoint resolves a garbage memory address and once it returns the debugger becomes unresponsive.

This is all on xcode 4.5 on lion

Doug Russell

A quick note about how you are setting your breakpoints in your “set_dispatch_breakpoints” function: you can use the SBTarget API so you don’t have to get the count in order to guess at the breakpoint ID. There is a global named “” that contains a link to the currently selected target, so the breakpoint can be set using the API. We still don’t have a way to set the breakpoint command through the SBBreakpoint API, so the function can be simplified to:

def set_dispatch_breakpoints(debugger, command, result, dict):
bp =‘dispatch_async’)
debugger.HandleCommand(“breakpoint command add -s command {index} -o ‘store_stack -a $arg2’”.format(index=bp.GetID()))
bp =’_dispatch_call_block_and_release’)
lldb.debugger.HandleCommand(“breakpoint command add -s command {index} -o ‘print_stack -a $arg1’”.format(index=bp.GetID()))

The “bp” objects are lldb.SBBreakpoint objects (do a “help(lldb.SBBreakpoint)” in the python interactive interpreter to get help on that class (and any other class or object in python!)) so you can get their breakpoint ID using “bp.GetID()”.

Another thing to note in the “lldbutil.print_stacktrace” function: you don’t need to make up the following arrays:

mods = get_module_names(thread)
funcs = get_function_names(thread)
symbols = get_symbol_names(thread)
files = get_filenames(thread)
lines = get_line_numbers(thread)
addrs = get_pc_addresses(thread)

The following are equivalent in your loop:

mods[i] → frame.module
funcs[i] → frame.function
symbols[i] → frame.symbol
files[i] → frame.line_entry.file.fullpath
lines[i] → frame.line_entry.line
addrs[i] → frame.addr

All symbol context (module, file, function, block, file + line, symbol) are all cached in the frame objects and only created once so they are very efficient.

I am not sure what is going on in your script yet, but I will take a look and get back to you.

Greg Clayton