我正在增强在 Linux 上运行的应用程序,以便在进程或线程接收到终端信号(例如 SIGSEGV、SIGABRT)时发出回溯。
backtrace(3)
该代码使用、backtrace_symbols(3)
、运行良好,dladdr(3)
为abi::__cxa_demangle
回溯生成有用的信息。
除此之外,在尝试生成源文件名和行号时,我发现addr2line
当我使用 提供的地址发送可执行文件时效果很好,但是最近,只要符号位于共享对象中,backtrace(3)
它就很容易生成??:0
。看来backtrace
和朋友举报的地址受到了ASLR的影响。这个问题影响了我的大部分(如果不是全部)堆栈跟踪,目前正在减少 forking 的价值addr2line
。
对于我来说,在如何解决它并获取文件和行号方面,互联网结果开始变得稀疏。但我最近已经足够了解内存映射如何工作来解决以下问题:
backtrace_symbols(3)
为我提供了一个包含共享对象路径的字符串(dladdr(3)
也在 中提供了这一点dli_fname
),我可以nm
与此共享对象一起使用来查找backtrace_symbols
也提供的符号,当我在共享对象中添加此地址和偏移量时,并将其发送给addr2line -e <sharedobjectpath>
它,正确地生成文件和行号。/proc/<pid>/maps
我可以在共享对象路径中查找r-xp
映射地址,并从 和 报告的地址中减去该值,backtrace(3)
该值提供了与上面共享对象完全相同的地址。- 我也许能够(仍然没有测试过,但有预感)通过 直接获取共享对象映射地址
dladdr1(3)
,这将允许我跳过访问/proc/<pid>/maps
.
不管怎样,这里我似乎需要分叉addr2line
才能获取文件和行号,这有点痛苦(并且需要数百毫秒),但它似乎是必要的,而不需要将其libbfd
作为依赖项引入我的应用程序。
更新:我没有仔细观察,现在我意识到从 找到的地址与的值/proc/<pid>/maps
相同。这样就解决了。根本不需要抬头。dli_fbase
dladdr(3)
/proc/<pid>/maps
有没有更干净或更直接的方法来做到这一点?我希望我的第三个要点可以让我只 fork addr2line
。 (编辑: 可以给个地址吗忽略我对 的引用/proc/<pid>/maps
。)第二个项目符号已经表明我可以阅读问题是(如果第三个项目符号被证明不可行)是否存在与从我的程序/proc/<pid>/maps
以获得我需要的叉子,这只是更糟一点;尽管扫描相当大的内存映射输出需要大量工作,但它的执行速度肯定比后续调用addr2line
.访问相关的任何安全/访问/安全问题跑步/proc/<pid>/maps
?呢addr2line
?