5

我最近从 Mac OS X 10.7 升级到 10.9。由于 OS X 不再支持 gdb,我通过 macports 安装了 GNU gdb。在能够使用它之前,我必须按照这里的描述对其进行代码设计。现在我可以使用 gdb 作为调试器,但是在附加到进程时设置断点时遇到问题。我给你举个例子。我拿了这个示例 C 代码

#include <unistd.h>
#include <stdio.h>

void f() {
    printf("f()\n");
}

int main() {
    printf("sleeping 30 seconds...\n");
    sleep(30);
    printf("invoking f()\n");
    f();
}

并编译它

gcc -g a.c

如果我现在尝试通过做调试

gdb a.out

并在 gdb 中运行它,结果如下(如预期的那样)

GNU gdb (GDB) 7.6
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-apple-darwin13.0.0".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /private/tmp/a.out...Reading symbols from /private/tmp/a.out.dSYM/Contents/Resources/DWARF/a.out...done.
done.
(gdb) break f
Breakpoint 1 at 0x100000ee0: file a.c, line 5.
(gdb) r
Starting program: /private/tmp/a.out
sleeping 30 seconds...
invoking f()

Breakpoint 1, f () at a.c:5
5               printf("f()\n");
(gdb) c
Continuing.
f()
[Inferior 1 (process 78776) exited with code 012]
(gdb)

所以我所做的就是打开 gdb,在函数 f() 处设置断点,运行程序,然后在 f() 内停止时简单地发出 continue 命令。如果我现在执行相同操作但附加到已运行的进程,则无法设置断点,并且在发出 continue 命令以使进程在附加后继续时也会出错。结果如下:

GNU gdb (GDB) 7.6
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-apple-darwin13.0.0".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
(gdb) attach 78794
Attaching to process 78794
Reading symbols from /private/tmp/a.out...Reading symbols from /private/tmp/a.out.dSYM/Contents/Resources/DWARF/a.out...done.
done.
0x00007fff8516da3a in ?? ()
(gdb) break f
Cannot access memory at address 0x100000edc
(gdb) c
Continuing.
warning: Mach error at "darwin-nat.c:726" in function "void darwin_resume_thread(struct inferior *, darwin_thread_t *, int, int)": (os/kern) failure (0x5)
[Inferior 1 (process 78794) exited normally]
(gdb)

因此,首先在附加时,gdb 没有提供有关代码中当前位置的任何信息(0x00007fff8516da3a in ?? ()),这可能没问题,因为我很可能在进程处于 sleep() 函数时停止了该进程.

但是,当我尝试在 f() 处设置断点时,出现“无法访问内存”错误,并且断点显然没有设置。事实上,当我发出 continue 命令时,该过程会照常继续并终止,而不会在 f() 处停止。

此外,在尝试继续时,我还会收到此“Mach error at [...] (os/kern) failure (0x5)”。即使使用设置断点也不起作用

(gdb) break a.c:5
Cannot access memory at address 0x100000edc

我也尝试搜索网络和stackoverflow,但我没有找到这个问题的答案。任何帮助表示赞赏。

4

2 回答 2

2

我找到了一个(不太令人满意)的解决方案。使用 MacPorts,我安装了苹果版的 GDB:

sudo port install gdb-apple

这个版本的 GDB 能够附加到进程并正确设置断点,即使在 Eclipse CDT 中也是如此。我发现的唯一缺陷是,在 Eclipse 中,我需要在附加到进程之前设置断点。如果我尝试在已附加的情况下设置断点,则该过程将失败。我不知道为什么。

我希望这个答案可以帮助某人,如果你们中的任何人找到更好的解决方案,我会很高兴知道。

于 2014-02-05T06:59:01.327 回答
0

这实际上是上游 GDB 中的一个错误(缺少功能)。

我一直在阅读它的源代码以了解它在 macOS 上的工作原理以及“附加到正在运行的进程”的代码路径从不调用ptrace(PT_ATTACHEXC, ...),这会将传递给被跟踪进程的信号重新路由到 GDB 使用的异常端口。

ptrace(PT_SIGEXC)在生成孩子时确实会调用,这解释了为什么它在这种情况下工作。

于 2017-05-19T21:37:45.260 回答