卓越飞翔博客卓越飞翔博客

卓越飞翔 - 您值得收藏的技术分享站
技术文章71531本站已运行4227

等待调试器

等待调试器

介绍

使用 gdb 或 lldb 等调试器时,通常您:

  1. 运行调试器并指定程序可执行文件的名称。
  2. 设置断点。
  3. 从调试器中运行您的程序。

但是,某些程序是通过 fork() 和 exec++() 从守护程序启动或作为管道的一部分启动。 如果程序本身是守护进程(或其他长时间运行的进程),您可以简单地将调试器附加到程序的运行进程中。 但是,如果您的程序是短暂的,那么在您将调试器附加到它之前,它早已完成执行。 需要的是一种运行程序的方法,但让它立即暂停并无限期地等待您附加调试器。

等待

c 标准库包含 raise() 函数,该函数向当前进程发送信号。 posix 定义了 sigstop 信号,该信号使程序停止并无限期地等待,直到收到 sigcont 信号(当您输入 continue 命令时调试器恰好发送该信号),这正是我们想要的。这是一个可以做到这一点的函数:

void wait_for_debugger_attach( void ) {
  fprintf( stderr,
    "%s: pid=%d: waiting for debugger to attach...n",
    me, (int)getpid()
  );
  if ( raise( sigstop ) == -1 ) {
    perror( me );
    exit( ex_oserr );
  }
}
sigstop 与调试器本身发送到进程以在遇到断点时暂停其执行的信号相同。

首先,我们打印一条包含进程 id 的消息,以便您知道将调试器附加到哪个进程。 然后我们通过引发 sigstop 等待。为了稳健起见,我们检查 raise() 的返回值:如果是 -1,则发生错误,因此通过 perror() 打印出来并退出。

变量 me 是全局变量,并在 main() 中设置为 argv[0] 的基本名称,即可执行文件的名称。

有条件等待

当然,只有在实际调试程序时才需要调用 wait_for_debugger_attach()。 有几种方法可以让你的程序知道情况是这样的:

  1. 通过命令行选项,例如 --debug。
  2. 通过文件的存在,例如 ~/.foo_debug (其中 foo 将替换为您的程序的名称)。
  3. 通过环境变量,例如 foo_debug。

其中,我最喜欢#3,因为它是最难意外完成的,因为必须在父进程的环境中设置环境变量才能被程序继承。 (您不希望生产中的程序运行然后立即无限期地等待。)

因此,在main()中,我们可以这样做:

int main( int argc, char const *argv[] ) {
  me = basename( argv[0] );
  if ( getenv( "foo_debug" ) != null )
    wait_for_debugger_attach();
  // ...
}

其中 getenv() 仅当给定的环境变量存在时才返回非 null。 (它的值,即使是空的,也没关系。)

细节

如果你想让你的程序更难意外地无限期等待,你可以检查环境变量的“肯定”值。 我们可以通过添加几个辅助函数来做到这一点:

bool str_is_any( char const *s,
                 char const *const matches[const static 2] ) {
  if ( s != null ) {
    for ( char const *const *match = matches; *match != null; ++match ) {
      if ( strcasecmp( s, *match ) == 0 )
        return true;
    }
  }
  return false;
}

bool str_is_affirmative( char const *s ) {
  static char const *const affirmatives[] = {
    "1", "t", "true", "y", "yes", null
  };
  return str_is_any( s, affirmatives );
}

如果你不知道 const static 2 在 c 中的作用,请参阅此处。 在 c++ 程序中,只需省略此即可。

然后将main()中的代码更改为:

  if ( str_is_affirmative( getenv( "FOO_DEBUG" ) ) )
    wait_for_debugger_attach();

结论

有条件地使用 sigstop 是调试以命令行以外的方式启动的程序的好方法。

卓越飞翔博客
上一篇: 如何使用golang框架进行容器化环境的性能监控?
下一篇: 返回列表
留言与评论(共有 0 条评论)
   
验证码:
隐藏边栏