是否只有当调用堆栈中存在某个方法时才可以在断点处中断?

Is it possible to break on a breakpoint only when a certain method is present in the call stack?

假设我有一个方法 foo,在遍历对象的层次结构时被不同的方法调用。

是否可以在方法 foo 内部中断,只有当它被方法 bar 调用时(所以 bar 存在于调用堆栈中)?

LLDB 或 GDB 是否支持这样的用例?

在 GDB 中,您可以将调试器 command list 关联到一个断点,因此为了实现您的目的,您可以在 bar() 中放置一个断点,它使用命令列表调用 foo()foo() 中设置断点并继续。在 bar() 中的另一个断点在 其对 foo() 的调用之后将需要清除 foo().

中的断点

所以:

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()
}

当然,如果这种情况很少发生,您可以手动设置断点。

如果foo()不是直接从bar()调用,或者可能foo()是从bar()的多个地方调用,那么同样的解决方案适用;如果 bar() 在开始设置断点并在结束时清除它就足够了。

一个警告;如果应用程序是多线程的,并且可以从多个线程调用 bar()foo(),那么您将需要一个 thread specific breakpoint.

最新版本的 gdb 附带了一些用 Python 编写的便利函数,就是为了这种情况。看看$_caller_is和朋友们。 (FWIW 这个确切的用例是促使我努力将 Python 添加到 gdb 的原因......)

一个简单的用法是:

(gdb) break foo if $_any_caller_matches("bar")

如果调用堆栈在 foobar 调用之间包含更多函数,导致堆栈如下所示,

foo()
...
...
...
bar()
...
...
...
main()

您可以向 _any_caller_matches 传递一个额外的参数,它指示要检查 bar

出现的帧数
(gdb) break foo if $_any_caller_matches("bar", 10)

参考: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.

您在 lldb 中执行此操作的方法是编写一个基于 Python 的断点命令,该命令检查遇到断点的线程的堆栈,如果它不包含具有该函数的帧则继续.断点命令通过分别从函数返回 True 或 False 来告诉 lldb 是否停止。因此,一种非常简单的方法是制作一个 Python 文件 (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

假设这个文件在/tmp。然后在 lldb 中你做:

(lldb) com scr imp /tmp/break_here.py
(lldb) br s -n whatever
(lldb) br com add --python-function break_here.break_here