调试特定子进程

问题描述 投票:0回答:2

我有一个Python脚本,它启动几个外部程序作为子进程并使用管道与它们通信。该系统运行在Linux上。我想调试其中一个子进程,一个特定的可执行程序。如何将 gdb 附加到它?我尝试了多种方法,但没有任何效果。

  1. 使用
    set follow-fork-mode child
    在 gdb 下运行 python。不起作用,因为这不是唯一的孩子。第一个孩子被调试,而不是我想要的。
  2. 使用
    set detach-on-fork off
    在 gdb 下运行 python。不可行,因为这不是唯一的孩子。我需要手动告诉 gdb 继续调试父进程,直到启动感兴趣的程序。理论上可行,但是手工操作太多容易出错。如果所有这些手动工作都可以自动化,这是一个可行的方法。
  3. 将有问题的可执行文件替换为在 gdb 下运行原始可执行文件的脚本。由于管道的原因不起作用。 gdb 的输入和/或输出被重定向到管道。显然我需要他们去航站楼。

我怎样才能做到这一点?

python gdb
2个回答
1
投票

我怎样才能做到这一点?

您可以使用

gdb -p $pid
附加进程,而无需从 GDB 启动它。您可能需要禁用 YAMA 才能正常工作。

如果您的进程在有机会附加之前崩溃了,此答案显示了调试此类进程的一种方法。

更新:

不幸的是,插入代码并重建程序会改变行为。

在这种情况下,

mv $exe $exe.real
,并在其位置放置一个包装器可执行文件。包装纸应该是这样的:

#include <unistd.h>

int main(int argc, char *argv[])
{
  char argv0[PATH_MAX];
  volatile int spin = 1;

  strcpy(argv0, argv[0]);
  strcat(argv0, ".real");

  while (spin) sleep(1);
  execvp(argv0, argv);  // Should not return

  abort();  // Unreachable
}

将GDB附加到包装器,设置

spin = 0
并继续调试
$exe.real


0
投票

为了解决这个问题,我在traceexec 0.4.0中添加了调试器启动器功能:https://github.com/kxxt/tracexec/releases/tag/v0.4.0

基本上,此解决方案会在 execve{,at} 系统调用的系统调用退出停止后停止进程,并将 gdb 附加到它们。

假设我们有以下两个简单的程序 a 和 b:

fn main() {
    println!("Hello from A!");
}
use std::io::stdin;
use std::io::Read;

fn main() {
  println!("Hello from B!");
  let mut input = String::new();
  stdin().read_to_string(&mut input).unwrap();
  println!("Stdin: {}", input);
}

以及执行它们的脚本。 (我这里使用的是shell脚本,但是这里使用python/perl脚本也没关系。)

./a --complex-arguments-here | ./b --other --complex --arguments --here

在安装了display和konsole的Linux系统上,以下命令使用shell脚本启动tracexec tui:

tracexec tui -t -b sysexit:in-filename:/a -b sysexit:in-filename:/b --default-external-command "konsole -e gdb -ex cont -ex cont -p {{PID}}" -- ./shell-script

然后在 TUI 中,gdb 可以附加到命中管理器中的 a 和 b。

如果上面的文字不清楚,可以在这里观看视频:https://github.com/kxxt/tracexec/assets/18085551/72c755a5-0f2f-4bf9-beb9-98c8d6b5e5fd

完整代码可在 https://github.com/kxxt/tracexec/tree/main/demonstration/gdb-launcher

© www.soinside.com 2019 - 2024. All rights reserved.