Linux下段错误的原因以及调试方法

来源:互联网 发布:orancle in优化 编辑:程序博客网 时间:2024/05/15 23:16

简而言之,产生段错误就是 访问了错误的内存段 。

一、一般来说,段错误就是指访问的内存超出了系统分配给这个程序的内存空间,通常这个值是由gdtr来保存的,

1)gdtr是一个48位的寄存器,其中的32位是保 存由它指向的gdt表,后13位保存相应于gdt的下标,最后3位包括了程序是否在内存中以及程序的在cpu中的运行级别。

2)指向的gdt是由以64位为一 个单位的表,在这张表中就保存着程序运行的代码段以及数据段的起始地址以及与此相应的段限和页面交换还有程序运行级别、内存粒度等等的信息。一旦一个程 序发生了越界访问,cpu就会产生相应的异常保护,于是segmentation fault就出现了.

二、在编程中以下几类做法容易导致段错误,基本是是 错误地使用指针引起的

1)访问系统数据区,尤其是往系统保护的内存地址写数据:最常见就是给一个指针以0地址
2)内存越界(数组越界,变量类型不一致等) 访问到不属于你的内存区域

三、解决方法

1)、利用gdb逐步查找段错误:
这种方法也是被大众所熟知并广泛采用的方法,首先我们需要一个带有调试信息的可执行程序,所以我们加上“-g -rdynamic”的参数进行编译,然后用gdb调试运行这个新编译的程序,具体步骤如下:
gcc -g -rdynamic d.c
gdb ./a.out

注:中间省略了一此信息,最后会有如下信息

(gdb) r
Starting program: /home/sdd/project/a.out

Program received signal SIGSEGV, Segmentation fault.
0x0804860c in main () at main.c:11
11 *p=1;
从上面我们可以看到出错位置在main.c文件的第11行,其实就是如此的简单。
从这里我们还发现进程是由于收到了SIGSEGV信号而结束的。通过进一步的查阅文档(man 7 signal),我们知道SIGSEGV默认handler的动作是打印”段错误”的出错信息,并产生Core文件,由此我们又产生了方法二。

2)、分析Core文件

Core文件是什么呢?
The default action of certain signals is to cause a process to terminate and produce a core dump file, a disk file containing an image of the process’s memory at the time of termination. A list of the signals which cause a process to dump core can be found in signal(7).
以上资料摘自man page(man 5 core)。 默认情况下,系统禁止了core文件的生成,使用ulimit命令开启,将系统的core文件的大小限制在512K大小,再试:
sdd@sdd-desktop:~/projectulimitc0sdd@sdddesktop: /project ulimit -c 1000
sdd@sdd-desktop:~/projectulimitc1000sdd@sdddesktop: /project ./a.out
段错误 (core dumped)
sdd@sdd-desktop:~/project$ ls
a.out core main.c

core文件终于产生了,用gdb调试一下看看吧:

sdd@sdd-desktop:~/project$ gdb ./a.out core

结果也是一招命中,非常厉害!

3)、下面是别人写得一个程序,在发生了段错误时候自动进行调试,个人感觉非常不错,所以Copy过来了,以备后用。该程序的原理就是对段错误设置自己的处理函数,在发生段错误时,会发出SIGSEGV的信号,通过signal()函数将该信号和自己的处理函数关联。

void dump(int signo)
{
char buf[1024];
char cmd[1024];
FILE *fh;

    snprintf(buf, sizeof(buf), "/proc/%d/cmdline", getpid());

if(!(fh = fopen(buf, “r”)))
exit(0);
if(!fgets(buf, sizeof(buf), fh))
exit(0);
fclose(fh);
if(buf[strlen(buf) - 1] == ’ ‘)
buf[strlen(buf) - 1] = ‘/0’;
snprintf(cmd, sizeof(cmd), “gdb %s %d”, buf, getpid());
system(cmd);

    exit(0);

}

void dummy_function (void)
{
unsigned char *ptr = 0x00;
*ptr = 0x00;
}

int main (void)
{
signal(SIGSEGV, &dump);
dummy_function ();

return 0;
}

作者还给出了一种方法,在此不引用了。帖子的地址贴出来,以备以后查看。

http://edu.codepub.com/2010/0225/20549.php

附:ulimit 命令的用法

功能说明:控制shell程序的资源。

语  法:ulimit [-aHS][-c

0 0