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