使用信号处理程序获取段错误的行号

时间:2015-02-28 19:23:09

标签: c

我在远程计算机上运行程序,我只能使用stdout进行交互。我在程序的某个地方有一个段错误,我试图弄清楚在哪里。是否有可能为sigsegv编写一个信号处理程序,它给出了行号和发生它的文件?

1 个答案:

答案 0 :(得分:3)

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

  1. SIGSEGVSIGBUS或您认为致命信号使用sigaction()的任何内容注册处理程序,并传递sa.sa_flags = SA_SIGINFO。使用sa_sigaction而非sa_handler struct 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。)
  4. (顺便说一下,我刚从另一个问题中回忆起context信号处理程序参数。:)

    上述方法的一个限制是,它可能不会为您提供库中崩溃的行号 - 特别是如果它们在随机地址中加载。

    另一种方法是使用backtrace(3),这可以在glibc和其他一些libc中使用。有点hackish,但你可以把你从它获得的地址(作为字符串)写到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)也可以用来获取图书馆内的行号。