Suppose I have a method foo that gets called by different methods, when going through a hierarchy of object.
Is it possible to break inside method foo, only when it was called by method bar (so bar is present in the call stack)?
Does LLDB or GDB support such a use-case?
Recent versions of gdb ship with some convenience functions written in Python for just this case. Take a look at $_caller_is and friends. (FWIW this exact use case was what motivated me to work on adding Python to gdb...)
A simple use would be:
(gdb) break foo if $_any_caller_matches("bar")
If the call stack contains more functions in between foo and bar calls resulting in a stack that looks like the following,
foo()
...
...
...
bar()
...
...
...
main()
you could pass an extra argument to _any_caller_matches which indicates the number of frames to check for the occurrence of bar
(gdb) break foo if $_any_caller_matches("bar", 10)
Reference: https://sourceware.org/gdb/current/onlinedocs/gdb/Convenience-Funs.html
$_any_caller_matches(regexp[, number_of_frames])
Returns one if any calling function’s name matches the regular expression regexp. Otherwise it returns zero.
If the optional argument number_of_frames is provided, it is the number of frames up in the stack to look. The default is 1.
This function differs from $_caller_matches in that this function checks all stack frames from the immediate caller to the frame specified by number_of_frames, whereas $_caller_matches only checks the frame specified by number_of_frames.
The way you would do this in lldb is to write a Python based breakpoint command that checks the stack of the thread that hit the breakpoint, and continues if it doesn't contain a frame with that function. The breakpoint commands tell lldb to stop or not by returning True or False respectively from the function. So a very simplistic way to do this would be to make a Python file (break_here.py):
import lldb
desired_func = "some_func"
def break_here(frame, bp_loc, dict):
thread = frame.thread
for frame in thread.frames:
if frame.name == desired_func:
return True
return False
Suppose this file is in /tmp. Then in lldb you do:
(lldb) com scr imp /tmp/break_here.py
(lldb) br s -n whatever
(lldb) br com add --python-function break_here.break_here
In GDB you can associate a debugger command list to a breakpoint, so to achieve your aim, you could place a breakpoint in bar() where it calls foo() with a command list that that sets a breakpoint in foo() and continues. A further breakpoint in bar() after its call to foo() will be required to clear the breakpoint in foo().
So:
int bar()
{
foo() ; // Add breakpoint with command list here to set breakpoint in foo()
return 0 ; // Add breakpoint command list here to clear breakpoint in foo()
}
Of course if this happens very infrequently, you could set the breakpoints manually.
If foo() is not called directly from bar() or perhaps foo() is called from multiple places in bar(), then the same solution applies; it is sufficient to set the breakpoint at the start if bar() and clear it at the end.
One caveat; if the application is multi-threaded and either bar() or foo() may be called from more than one thread, then you will need a thread specific breakpoint.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With