[博客翻译]跳过调试器中的无聊函数


原文地址:https://maskray.me/blog/2024-12-30-skipping-boring-functions-in-debuggers


在调试程序时,我们常常会遇到这样的情况:当我们使用调试器逐步执行代码(step into)进入一个函数时,如果这个函数的参数中包含了其他函数调用,即使这些函数调用非常简单且不重要(例如C++标准模板库中的函数),调试器也会逐层深入这些嵌套的函数调用。这不仅浪费时间,还容易让人分心,尤其是在处理复杂的表达式时。

GDB中的解决方案

以GDB为例,考虑下面这段简单的C++代码:


#include <cstdio> 

#include <memory> 

#include <vector> 

using namespace std; 

void foo(int i, int j) { 

  printf("%d %d\n", i, j); 

} 

int main() { 

  auto i = make_unique<int>(3); 

  vector v{1,2}; 

  foo(*i, v.back()); // step into 

} 

当我们在foo函数调用处设置断点并尝试单步执行(s命令)时,GDB首先会跳入std::vector::back()std::unique_ptr::operator*()这两个辅助函数,尽管它们与我们要调试的核心逻辑无关。虽然可以通过先执行finish命令退出当前函数,然后再继续单步执行,但这显然不够高效。

17.png

为了解决这个问题,GDB提供了一个skip命令,可以用来跳过那些匹配正则表达式的函数或文件名模式。比如,你可以通过以下命令跳过所有以std::开头的函数:


skip -rfu ^std:: 

或者,如果你想要跳过整个C++标准库的实现文件,可以使用如下命令:


skip -gfi /usr/include/c++/*/bits/* 

需要注意的是,skip命令在匹配文件名时使用了fnmatch函数,并设置了FNM_FILE_NAME标志,这意味着通配符*不会匹配斜杠字符。因此,像skip -gfi /usr/*这样的命令实际上并不会排除/usr/include/c++/14.2.1/bits/stl_vector.h等路径下的文件。

26.png

其他调试器的支持

除了GDB之外,LLDB默认情况下也会避免进入名称以std::开头的函数内部。这一行为可以通过设置来调整:


(lldb) settings show target.process.thread.step-avoid-regexp 

target.process.thread.step-avoid-regexp (regex) = ^std:: 

Visual Studio则提供了“仅我的代码”功能,它能够自动跳过系统、框架以及其他非用户编写的代码调用。此外,VS还支持“Step Into Specific”命令,允许用户选择性地进入特定的函数。

33.png

总之,合理利用调试器提供的跳过功能,可以帮助开发者更专注于核心问题,提高调试效率。