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

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

一、一般来说,段错误就是指访问的内存超出了系统分配给这个程序的内存空间,通常这个值是由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:~/project$ ulimit -c
0
sdd@sdd-desktop:~/project$ ulimit -c 1000
sdd@sdd-desktop:~/project$ ulimit -c
1000
sdd@sdd-desktop:~/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()函数将该信号和自己的处理函数关联。
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>

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 <core文件上限>][-d <数据节区大小>] [-f <文件大小>][-m <内存大小>][-n <文件数目>][-p <缓冲区大小>] [-s <堆叠大小>][-t <CPU时间>][-u <程序数目>][-v <虚拟内存大小>] 

补充说明:ulimitshell内建指令,可用来控制shell执行程序的资源。 

参  数: 

-a  显示目前资源限制的设定。  

-c <core文件上限 设定core文件的最大值,单位为区块。  

-d <数据节区大小 程序数据节区的最大值,单位为KB  

-f <文件大小shell所能建立的最大文件,单位为区块。  

-H  设定资源的硬性限制,也就是管理员所设下的限制。  

-m <内存大小 指定可使用内存的上限,单位为KB  

-n <文件数目 指定同一时间最多可开启的文件数。  

-p <缓冲区大小 指定管道缓冲区的大小,单位512字节。  

-s <堆叠大小 指定堆叠的上限,单位为KB  

-S  设定资源的弹性限制。  

-t <CPU时间 指定CPU使用时间的上限,单位为秒。  

-u <程序数目 用户最多可开启的程序数目。 

-v <虚拟内存大小 指定可使用的虚拟内存上限,单位为KB

 

http://hi.baidu.com/gruceelee/blog/item/8ba58dce376db08bc8176815.html

 

我搜这个解决办法主要是我在编程中程序出现了段错误,而我并不知道到底是哪里出了错,我找了我出现段错误的程序进行如上方法调试。

程序不如例程高深,是一个将字符串中数字串输出并找出最大数字串计算其字符个数,然后输出。

 


  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值