【问题标题】:Get line number of segfault using signal handler [duplicate]使用信号处理程序获取段错误的行号[重复]
【发布时间】:2015-05-01 09:24:23
【问题描述】:

我正在远程机器上运行一个程序,我只能使用标准输出与之交互。我在程序的某个地方有一个段错误,我试图找出在哪里。是否可以为 sigsegv 编写一个信号处理程序,给我行号和它发生的文件?

【问题讨论】:

  • 为什么不能在远程机器上使用 gdb 来回溯段错误?
  • 我没有对该系统的完全访问权限。我只能在那里提交我的 C 文件,它会执行二进制文件并给我输出。
  • 这将为您提供故障的地址。如果他们正在编译您的代码以包含调试信息,那么您将不得不做很多 的工作来解析 DWARF 数据以确定实际的行号。在本地构建并使用传统方法(即 gdb)进行调试会容易得多。
  • 你可以在一个简单的程序中尝试system("addr2line --help");来检查它是否在这个系统上可用,如果是,然后编写一个信号处理程序,它为信号发生的指令指针调用它。跨度>

标签: c


【解决方案1】:

这听起来像是一个可怕的调试环境,但如果让 GDB 运行真的不可行,您可以尝试以下方法(假设是 Linux):

  1. SIGSEGVSIGBUS 或任何您认为致命信号使用sigaction() 的处理程序注册一个处理程序,并传递sa.sa_flags = SA_SIGINFO。使用sa_sigaction 而不是sa_handlerstruct sigaction 成员来注册处理程序。
  2. 处理程序将收到一个void *context 参数。假设 X86_64(你必须弄清楚其他架构上指令指针对应的索引是什么),你可以通过((ucontext_t*)context)->uc_mcontext.gregs[REG_RIP] 获得触发信号的地址。
  3. 获得地址后,运行例如addr2line -Cfip -e <binary with debugging symbols> <address> 获取函数和行号。 (如果你是交叉编译,你需要使用工具链中的addr2line,它可能有一些前缀,例如arm-linux-androideabi-addr2line。)

(顺便说一句,我刚刚从另一个问题中回忆了context 信号处理程序参数。:)

上述方法的一个限制是它可能不会为您提供库内崩溃的行号——尤其是当它们以随机地址加载时。

另一种方法是使用backtrace(3),它在glibc 和其他一些libc 中可用。有点骇人听闻,但是您可以将从中获得的地址(作为字符串)写入popen("addr2line -Cfip -e <binary with debugging symbols>")/proc/self/exe 也可以在 Linux 上使用)以在stdout 上生成带有行号的回溯。 backtrace_symbols_fd() 也值得研究,虽然它不会给你行号。编译时需要-rdynamic

编辑:

似乎 GDB 使用 personality(2)ADDR_NO_RANDOMIZE 来为库启用地址空间随机化(可能需要在后面跟着一个 re-execve())。如果你真的很绝望,也许那个(或/proc/sys/kernel/randomize_va_space)也可以用来获取库中的行号。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-23
    • 1970-01-01
    • 1970-01-01
    • 2011-09-16
    相关资源
    最近更新 更多