在x86 Linux上调试SIGBUS

Jos*_*ley 18 linux debugging bus-error sigbus

在Linux中的通用x86用户态应用程序上会导致SIGBUS(总线错误)的原因是什么?我在网上找到的所有讨论都是关于内存对齐错误,根据我的理解,它并不适用于x86.

(我的代码在Geode上运行,以防有任何相关的处理器特定怪癖.)

caf*_*caf 21

SIGBUS除了内存对齐错误之外,还有很多原因会在Linux中发生 - 例如,如果您尝试访问mmap映射文件末尾之外的区域.

您使用的是mmap共享内存区域或类似内容吗?

  • 是的,我们正在使用共享内存区域.我将在下次出现此错误时调查这种可能性.谢谢. (3认同)
  • @ v.oddou:这是匿名mmap,它没有“超出映射文件的末尾”的概念。 (3认同)

Chr*_*odd 14

如果打开未对齐的访问陷阱,您可以从未对齐的访问中获取SIGBUS,但通常在x86上关闭.如果出现某种错误,您也可以通过访问内存映射设备来获取它.

您最好的选择是使用调试器来识别故障指令(SIGBUS是同步的),并尝试查看它尝试执行的操作.

  • @Josh - 检查实际失败的指令是什么 - 如果是推送或弹出,那么你的堆栈指针已损坏。如果是其他问题,那么指令中的地址就是问题。 (2认同)

Rus*_*lan 8

x86上的SIGBUS(包括x86_64)Linux是一种罕见的野兽.它可能出现在尝试访问mmaped文件的末尾或POSIX描述的某些其他情况之后.

但是从硬件故障来看,获取SIGBUS并不容易.也就是说,来自任何指令的未对齐访问 - 无论是否是SIMD - 通常会导致SIGSEGV.堆栈溢出导致SIGSEGV.即使访问不是规范形式的地址也会导致SIGSEGV.所有这一切都归因于#GP被提出,几乎总是映射到SIGSEGV.

现在,由于CPU异常,这里有一些获取SIGBUS的方法:

  1. 启用AC位EFLAGS,然后通过任何存储器读或写指令进行未对齐访问.有关详细信息,请参阅此讨

  2. 通过堆栈指针寄存器(rsprbp)进行规范违规,生成#SS.这是GCC的一个例子(编译gcc test.c -o test -masm=intel):

int main()
{
    __asm__("mov rbp,0x400000000000000\n"
            "mov rax,[rbp]\n"
            "ud2\n");
}


Jos*_*hua 6

哦,是的,还有一种更奇怪的方式来获得 SIGBUS。

如果内核由于内存压力(必须禁用 OOM 杀手)或失败的 IO 请求而无法在代码页中分页,则 SIGBUS.


小智 6

当您在 NFS(网络文件系统)上运行二进制文件并且文件发生更改时,您可能会看到 SIGBUS。请参阅https://rachelbythebay.com/w/2018/03/15/core/


sal*_*min 5

上面简要提到了这是“失败的 IO 请求”,但我将对此进行一些扩展。

常见的情况是,当您使用 ftruncate 延迟增长文件,将其映射到内存中,开始写入数据,然后耗尽文件系统中的空间。映射文件的物理空间是在页面错误时分配的,如果没有剩余,则进程会收到 SIGBUS。

如果您需要应用程序从该错误中正确恢复,则在使用 fallocate 进行 mmap 之前显式保留空间是有意义的。在fallocate调用之后处理errno中的ENOSPC比处理信号简单得多,特别是在多线程应用程序中。