Linux 获取导致信号处理程序中出现分段错误的寄存器

Linux 获取导致信号处理程序中出现分段错误的寄存器,linux,x86,segmentation-fault,signal-handling,sigaction,Linux,X86,Segmentation Fault,Signal Handling,Sigaction,我知道: 当安装带有sigaction和sa_sigaction的SIGSEGV信号处理程序(而不是sa_处理程序)时,信号处理程序接收一个siginfo_t*,其中si_addr是故障发生的地址 使用ucontext\u t我们可以检查寄存器的值,例如指令指针,尽管不是以独立于平台的方式() 我的问题:我们还可以知道是哪个寄存器导致了故障吗?考虑到我们没有内存到内存的移动,这应该只有一个寄存器(毕竟,也只有一个si_addr)。当然,我可以检查所有寄存器并搜索si_addr,但可能有多

我知道:

  • 当安装带有
    sigaction
    sa_sigaction
    SIGSEGV
    信号处理程序(而不是
    sa_处理程序
    )时,信号处理程序接收一个
    siginfo_t*
    ,其中
    si_addr
    是故障发生的地址

  • 使用
    ucontext\u t
    我们可以检查寄存器的值,例如指令指针,尽管不是以独立于平台的方式()


我的问题:我们还可以知道是哪个寄存器导致了故障吗?考虑到我们没有内存到内存的移动,这应该只有一个寄存器(毕竟,也只有一个
si_addr
)。当然,我可以检查所有寄存器并搜索
si_addr
,但可能有多个匹配项


我非常乐意使用与平台无关的解决方案。

加载/存储地址可能不在任何单个寄存器中;它可能是像
[rdi+rax*4+100]
之类的寻址模式的结果

除了像普通人一样在调试器下运行程序以首先捕获错误之外,没有简单的解决方案可以打印完整调试器的功能。或者,如果您需要调试其他系统上发生的崩溃,可以让它生成一个coredump供您脱机分析


Linux内核选择转储从错误代码地址开始的指令字节(或者实际上在上下文中在它之前),以及所有寄存器的内容。可以在事后从crashlog进行反汇编以查看故障指令,同时查看寄存器内容,而无需在内核中包含反汇编程序。请参阅,以了解Linux的功能示例,以及手动将其分离而不是使用
decodecode

“我们还可以知道是哪个寄存器导致了故障吗?”-on-segfault的arch I程序都不存储导致故障的寄存器。因此,除了解码导致segfault的指令之外,你别无选择。@Tsyvarev是的,这正是我所担心的,这不会很好,特别是对于像x86这样的大型指令集……地址也可能根本不在寄存器中,但编码在指令中;e、 g.
movl%eax,var
。为了挑剔,这里有一些指令可以实现内存对内存的移动:
movs*
push/pop mem
,例如。@NateEldredge对此表示感谢。你描述的这两种情况(变量和mem对mem)在我的案例中没有发生,但它们确实与彼得的评论一起表明了为什么我不可能做我想做的事情。我想知道是否有可能创建一个像复制收集器那样的垃圾收集方案,它不复制任何东西,而是保护旧的半空间,并且在segfaults上复制指向上面的节点。优点是划分GC时间,这样就不会出现明显的暂停。(我知道还有其他GC方案也能做到这一点,这只是一个想法。)啊,这就是你想要注册的原因。有些道理。但是,是的,一个异常/单独进入内核的成本将是一个阻碍,特别是在熔毁+幽灵缓解将其降低一个数量级左右的情况下。在每个对象的基础上,而不是在每个页面上,您将支付比软页面错误更高的成本,因此,是的,性能将是不切实际的。感谢您解释为什么这是不可能的。您提到的关于调试的内容对我来说不太有用(请参阅上面评论中的用例),但它将来可能会对其他人有所帮助。