8

我正在编写一个主要针对 Linux 的面向 GUI 的调试器,但我计划将来移植到其他操作系统。因为 GUI 必须始终保持交互,所以我有几个线程处理不同的事情。

首先,我有一个“调试事件”线程,它只是循环等待 waitpid 返回并将接收到的事件传递给其他线程。我这样做是因为 waitpid 没有超时,这使得它很难与其他事件循环集成并保持响应(waitpid 可以无限期挂起!)。

到目前为止,这种策略对于 Linux 构建非常有效。最近我一直试图让我的调试器线程感知(如在被调试应用程序中的线程中,而不是调试器本身)。

所以我将 ptrace 选项设置为跟踪克隆事件并查找将高 16 位设置为PTRACE_EVENT_CLONE. 然后我PTRACE_GETEVENTMSG用来获取新线程的 TID。这一切都在我的小型测试工具应用程序中运行良好。但是由于某种原因,当我将该代码放入我的实际调试器时它失败了。(我收到“没有这样的过程”错误代码)

我想到的一件事是 Windows 有一个规则,即只有附加到应用程序的线程才能侦听调试事件。Linux 的 ptrace 有类似的限制吗?如果是这样,为什么我的代码适用于其他调试事件?

编辑:

似乎至少 waitpid 支持从不同的线程等待,手册页说:

在 Linux 2.4 之前,线程只是进程的一种特殊情况,因此一个线程不能等待另一个线程的子线程,即使后者属于同一个线程组。然而,POSIX 规定了这样的功能,从 Linux 2.4 开始,一个线程可以并且默认情况下会等待同一线程组中其他线程的子线程。

所以最多这是一个 ptrace 限制。

4

2 回答 2

5

在实现Maxine VM debugger的 Linux 特定部分时,我遇到了同样的问题(还有许多其他问题!)。您的猜测是正确的,调试器中只有一个线程可以使用 ptrace 来控制被调试者。我们通过在专用线程上对 ptrace 进行所有调用来实现这一点。您可能会发现查看 kenai.com/projects/maxine/sources/maxine/show 上的 Maxine 源中的 LinuxTask.java、linuxTask.h 和 linuxTask.c 文件很有用

于 2009-12-08T17:48:20.240 回答
4

据我所知,这是不允许的。任务不能ptrace在它没有附加的任务上使用。此外,一个任务最多可以由另一个任务跟踪,因此您不能简单地在每个线程中附加一次。我认为这是因为当一个任务附加到另一个任务时,跟踪任务成为跟踪任务的父级,每个任务只能有一个父级。

似乎应该允许多线程跟踪,因为线程是同一进程的一部分,但在实现方面,Linux 内核中的线程和进程之间实际上并没有太大区别。线程只是碰巧与另一个任务共享其大部分资源的任务。

如果您有兴趣,可以浏览内核中 ptrace 的源代码。具体看,大多数请求ptrace_check_attach都会调用它。sys_ptrace如果目标任务的父级不是当前任务,它会返回-ESRCH(听起来像你得到的错误代码)。

于 2009-07-11T02:42:51.847 回答