【问题标题】:Getting the current stack trace on Mac OS X在 Mac OS X 上获取当前堆栈跟踪
【发布时间】:2008-11-14 11:20:22
【问题描述】:

我正在尝试研究如何在 Mac OS X 上的 C++ 应用程序中存储并打印当前堆栈。主要问题似乎是让 dladdr 在给定主可执行文件内的地址时返回正确的符号。我怀疑这个问题实际上是一个编译选项,但我不确定。

我已经尝试过 Darwin/Leopard 的回溯代码,但它调用 dladdr 并且与我自己调用 dladdr 的代码存在相同的问题。

原帖: 目前我正在使用以下代码捕获堆栈:

int BackTrace(Addr *buffer, int max_frames)
{
    void **frame = (void **)__builtin_frame_address(0);
    void **bp = ( void **)(*frame);
    void *ip = frame[1];
    int i;

    for ( i = 0; bp && ip && i < max_frames; i++ )
    {
        *(buffer++) = ip;
        ip = bp[1];
        bp = (void**)(bp[0]);
    }

    return i;
}

这似乎工作正常。然后像这样使用 dladdr 打印我正在查看的堆栈:

Dl_info dli;
if (dladdr(Ip, &dli))
{
    ptrdiff_t       offset;
    int c = 0;

    if (dli.dli_fname && dli.dli_fbase)
    {
        offset = (ptrdiff_t)Ip - (ptrdiff_t)dli.dli_fbase;
        c = snprintf(buf, buflen, "%s+0x%x", dli.dli_fname, offset );
    }
    if (dli.dli_sname && dli.dli_saddr)
    {
        offset = (ptrdiff_t)Ip - (ptrdiff_t)dli.dli_saddr;
        c += snprintf(buf+c, buflen-c, "(%s+0x%x)", dli.dli_sname, offset );
    }

    if (c > 0)
        snprintf(buf+c, buflen-c, " [%p]", Ip);

这几乎可以工作,一些示例输出:

/Users/matthew/Library/Frameworks/Lgi.framework/Versions/A/Lgi+0x2473d(LgiStackTrace+0x5d) [0x102c73d]
/Users/matthew/Code/Lgi/LgiRes/build/Debug/LgiRes.app/Contents/MacOS/LgiRes+0x2a006(tart+0x28e72) [0x2b006]
/Users/matthew/Code/Lgi/LgiRes/build/Debug/LgiRes.app/Contents/MacOS/LgiRes+0x2f438(tart+0x2e2a4) [0x30438]
/Users/matthew/Code/Lgi/LgiRes/build/Debug/LgiRes.app/Contents/MacOS/LgiRes+0x35e9c(tart+0x34d08) [0x36e9c]
/Users/matthew/Code/Lgi/LgiRes/build/Debug/LgiRes.app/Contents/MacOS/LgiRes+0x1296(tart+0x102) [0x2296]
/Users/matthew/Code/Lgi/LgiRes/build/Debug/LgiRes.app/Contents/MacOS/LgiRes+0x11bd(tart+0x29) [0x21bd]

它为共享对象获取了正确的方法名称,但不适用于主应用程序。那些只是映射到“tart”(或“start”减去第一个字符)。

理想情况下,我想要行号以及此时的方法名称。但我会为初学者选择正确的函数/方法名称。也许在那之后拍摄行号,在 Linux 上,我听说您必须为具有自己的指令集的私有 ELF 块编写自己的解析器。听起来很吓人。

无论如何,任何人都可以整理出这段代码,以便正确获取方法名称吗?

【问题讨论】:

    标签: macos backtrace


    【解决方案1】:

    您的目标是 OS X 的哪些版本。如果您在 Mac OS X 10.5 和更高版本上运行,您可以只使用 backtrace() 和 backtrace_symbols() 库调用。它们在 execinfo.h 中定义,并且有一个带有一些示例代码的manpage

    编辑:

    您在 cmets 中提到您需要在 Tiger 上运行。您可能只在您的应用程序中包含来自 Libc 的实现。源代码可从 Apple 的开源站点获得。这是相关file的链接。

    【讨论】:

    • 我目前的目标是当前和以前的版本,即 Leopard 和 Tiger。另外,我目前在我的 Macbook 上安装了 Tiger。所以在雪豹出现之前,我的代码需要在 Tiger 上编译/运行。
    • 嗯,这些函数的源代码是开源的,所以你可以在你的应用程序中包含实现。我正在使用相关信息编辑我的答案。
    • 我查看了您发布链接的代码,它最终使用 dladdr 就像我的代码一样。这给出了相同的错误结果,因为我的可执行文件(即不是共享对象)中的任何内容都有符号“tart”。
    • 在 OS 10.6 及更高版本中,有更高级别的包装器+[NSThread callStackSymbols]
    猜你喜欢
    • 2011-08-29
    • 2010-11-07
    • 2010-10-11
    • 2015-06-15
    • 2010-09-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多