用gdb调试程序笔记: 以段错误(Segmental fault)为例

这个笔记是我以前发表在学校BBS(电子科大清水河畔)上的,同学们反应还不错,特拿到这里与大家分享。

 

笔记内容:
1.背景介绍
2.程序中常见的bug分类
3.程序调试器(如gdb)有什么用
4.段错误(Segmental fault)介绍
5.gdb调试入门

 一、背景介绍
这个笔记主要介绍开源的程序调试器(gdb)的入门知识,目的是使unix/linux环境的编程新手能够快速学会使用gdb调试程序的方法,同时也是对我使用gdb的一个经验总结。
本文假设你能使用简单的unix/linux命令并能用gcc(GNU C Compiler, GNU C 语言编译器)编译程序,当然有编程经验更好。:)
为帮助你理解和操作,我将使用我遇到过的真实事例来演示使用gdb调试有缺陷(bug)的程序过程,你看过这篇笔记后能自己动手练一下最好。

二、程序中常见的缺陷(bug)分类
程序(编译型程序,perl、python,php等脚本程序除外)中常见的bug通常分为两类: 语法错误和逻辑错误,或者编译时错误和运行是错误。
语 法错误(编译时错误)是我们在编写源代码时没有按照相关的语言规范(如ANSI C标准)导致编译时出错,编译失败。这种错误的检查和调试一般是比较简单和直接的:因为编译器(如gcc)通常会明确告诉你错误的原因和大致的范围(注意 不一定是准确的错误行)。例如下面的一个简单demo.c程序的第8行缺失了一个分号,gcc指示第10行前少了一个分号。这就是一个典型的语法错误。
geekard@geekard:~/test$ cat -n demo.c
     1    #include<stdio.h>
     2    
     3    int
     4    main(){
     5    
     6        int n;
     7    
     8        printf("the n is:%c", n)
     9        
    10        return 0;
    11    }
geekard@geekard:~/test$ gcc demo.c -o demo
demo.c: In function ‘main’:demo.c:10:
error: expected ‘;’ before ‘return’
添加了分号再编译一次,这下没有出现问题,运行程序的结果如下:
geekard@geekard:~/test$ ./demo 
the n is:6680564
另外注意这个程序中的变量n,我定义其为整型变量但并没有对其初始化赋值,这就是一个逻辑错误:编译器不会指示这个错误,只有在实际运行或测试时才能发现。
这 个小程序只是一个故意的编造,但在实际编程中无论你多高明,经验多丰富,难免会在此处犯些小错误(想想吧:当你需要编写或维护一个成千上万行的代码,这种 小概率事件就是确定事件了,:)),而通常这些错误又是那么的浅显而易于消除,但是手工“除虫”(debug),往往是效率低下且让人厌烦的,本文将就" 段错误"这个内存访问越界的错误谈谈如何使用gdb快速定位这些"段错误"的语句。

三、程序调试器(如gdb)有什么用?(参考自gdb的在线帮助手册, 可用命令:man gdb, 或 info gdb查看)

程序调试器(如gdb)的主要目的是让你能够查看正在执行的程序其内部特性(如执行流程、变量值、函数调用、堆栈等),也可以程序崩溃时刻或以前都发生了什么。
Gdb对程序的调试能力主要体现在以下四个方面(当然不止这些):  
. 启动你的程序,可以带任何影响其功能(或称行为)的参数。  
. 能够使你的程序在指定条件下在指定的地方(断点)停止运行。    
. 当你的程序在断点处停止时,你可以查看已执行的结果(如变量的值,函数之间的调用情况,执行到那一行代码,下一步该执行哪行代码)    
. 改变你的程序中,你可以实验这种改变所带来的影响(如bug消除了,或者情况变得更糟糕)

使用gdb,你可以调试C,C++,以及Modula-2语言编写的程序。

四、段错误(Segmental fault)介绍
在 用C/C++语言写程序的时侯,内存管理的绝大部分工作都是需要我们来做的。实际上,内存管理是一个比较繁琐的工作,所以像java和c#等语言采用了内 存自动回收机制,避免了内存泄漏。如果程序试图往内存地址0处写东西时,内核就会向其发送段错误信号,如果程序没有捕获该信号,默认的操作时内核终止该程 序的运行,例如我写的一个myls程序就遭遇了这种情况:
luck@geekard:~/codes/12.21$ ./myls -ld .
longlist 1, typelist 0, dirlist 1, filename .
Segmentation fault
luck@geekard:~/codes/12.21$ 

常见的段错误原因如下:
1)往受到系统保护的内存地址写数据有些内存是内核占用的或者是其他程序正在使用,为了保证系统正常工作,所以会受到系统的保护,而不能任意访问
.2)内存越界(数组越界,变量类型不一致等)
下面我以上面的myls程序出现的错误为例介绍用gdb进行调试的方法和过程。

五、gdb调试入门

  5.1 调试前的准备
我们首先要启动linux内核提供核心转储(core dump)机制:当程序中出现内存操作错误时,会发生崩溃并产生核心文件(core文件)。使用GDB可以对产生的核心文件进行分析,找出程序是在什么时候崩溃的和在崩溃之前程序都做了些什么。
首先,你的Seg

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值