如何知道程序在发生分段错误时访问哪个非法地址?

另外,程序在运行Linux的arm设备上运行,我可以在我指定的sig-seg处理程序中输出堆栈信息和寄存器值。 问题是我不能将-g选项添加到源文件中,因为由于性能降级,错误可能不会被重现。

使用-g选项编译gcc不会导致“性能降级”。 它所做的只是导致调试符号被包含在内; 它不影响优化或代码生成。

如果使用传递给sigaction()sigaction结构的sa_sigaction成员来安装SIGSEGV处理程序,则传递给处理程序的siginfo_t结构的si_addr成员将包含错误地址。

我倾向于使用valgrind表示泄漏和内存访问错误

这似乎工作http://tlug.up.ac.za/wiki/index.php/Obtaining_a_stack_trace_in_C_upon_SIGSEGV

 static void signal_segv(int signum, siginfo_t* info, void*ptr) { // info->si_addr is the illegal address } 

如果您担心在设备上加载的二进制文件上使用-g,则可能会在ARM设备上使用带有可执行文件版本的gdbserver,并在开发计算机上运行arm-gdb,可执行文件。 剥离的版本和未剥离的版本需要匹配才能做到这一点,所以这样做:

 # You may add your own optimization flags arm-gcc -g program.c -o program.debug arm-strip --strip-debug program.debug -o program # or arm-strip --strip-unneeded program.debug -o program 

您需要阅读gdb和gdbserver文档以了解如何使用它们。 这并不难,但也不像它那样精致。 主要是很容易意外地告诉gdb做一些事情,最终以为你本意做,所以它将切换到远程调试模式。

如果可能的话,您可能还想使用backtrace()函数,该函数将在崩溃时提供调用堆栈。 当C程序出现分段错误,总线错误或其他内存违规错误时,可以使用这种方式来转储堆栈,就像在高级编程语言中一样。

backtrace()在Linux和Mac OS X上均可用

如果-g选项使错误消失,那么知道它崩溃的位置不太可能有用。 它可能写入函数A中的未初始化的指针,然后函数B尝试合法地使用该内存并死亡。 内存错误是一个痛苦。