Linux编程——gdb调试
2015-08-19 17:51
525 查看
上一篇文章中,我们学习了gcc编译器的使用。本文,我们就讲解 gdb 调试器(Debug)的使用,它可以帮助我们找出程序之中的错误和漏洞等等。
当程序编译完成后,它可能无法正常运行;或许程序会彻底崩溃;或许只是不能正常地运行某些功能;或许它的输出会被挂起;或许不会提示要求正常的输入。无论在何种情况下,跟踪这些问题,特别是在大的工程中,将是开发中最困难的部分,我们将学习gdb(GNU debugger)调试程序的方法,该程序是一个调试器,是用来帮助程序员寻找程序中的错误的软件。
gdb是GNU开发组织发布的一个强大的UNIX/Linux下的程序调试工具。或许,有人比较习惯图形界面方式的,像VC、BCB等IDE环境,但是在UNIX/Linux平台下做软件,gdb这个调试工具有比VC、BCB的图形化调试器更强大的功能。所谓“寸有所长,尺有所短”就是这个道理。 一般来说,gdb主要帮忙用户完成下面4个方面的功能:
启动程序,可以按照用户自定义的要求随心所欲的运行程序。
可让被调试的程序在用户所指定的调试的断点处停住 (断点可以是条件表达式)。
当程序停住时,可以检查此时程序中所发生的事。
动态地改变程序的执行环境。
从上面来看,gdb和一般的调试工具区别不大,基本上也是完成这些功能,不过在细节上,会发现gdb这个调试工具的强大。大家可能习惯了图形化的调试工具,但有时候,命令行的调试工具却有着图形化工具所不能完成的功能。
gdb.c
编译生成执行文件(Linux下):
有了以上的感性认识,下面来系统地学习一下gdb。
gdb主要调试的是C/C++的程序。要调试C/C++的程序,首先在编译时,必须要把调试信息加到可执行文件中。使用编译器(cc/gcc/g++)的 -g 参数即可。如:
如果没有-g,将看不见程序的函数名和变量名,代替它们的全是运行时的内存地址。当用-g把调试信息加入,并成功编译目标代码以后,看看如何用gdb来调试。 启动gdb的方法有以下几种:
gdb <program> program也就是执行文件,一般在当前目录下。
gdb <program> core 用gdb同时调试一个运行程序和core文件,core是程序非法执行后,core dump后产生的文件。
gdb <program> <PID> 如果程序是一个服务程序,那么可以指定这个服务程序运行时的进程ID。gdb会自动attach上去,并调试它。program应该在PATH环境变量中搜索得到。 gdb启动时,可以加上一些gdb的启动开关,详细的开关可以用gdb -help查看。下面只列举一些比较常用的参数: -symbols <file> -s <file> 从指定文件中读取符号表。 -se file
从指定文件中读取符号表信息,并把它用在可执行文件中。 -core <file> -c <file> 调试时core dump的core文件。 -directory <directory> -d <directory> 加入一个源文件的搜索路径。默认搜索路径是环境变量中PATH所定义的路径。
当程序编译完成后,它可能无法正常运行;或许程序会彻底崩溃;或许只是不能正常地运行某些功能;或许它的输出会被挂起;或许不会提示要求正常的输入。无论在何种情况下,跟踪这些问题,特别是在大的工程中,将是开发中最困难的部分,我们将学习gdb(GNU debugger)调试程序的方法,该程序是一个调试器,是用来帮助程序员寻找程序中的错误的软件。
gdb是GNU开发组织发布的一个强大的UNIX/Linux下的程序调试工具。或许,有人比较习惯图形界面方式的,像VC、BCB等IDE环境,但是在UNIX/Linux平台下做软件,gdb这个调试工具有比VC、BCB的图形化调试器更强大的功能。所谓“寸有所长,尺有所短”就是这个道理。 一般来说,gdb主要帮忙用户完成下面4个方面的功能:
启动程序,可以按照用户自定义的要求随心所欲的运行程序。
可让被调试的程序在用户所指定的调试的断点处停住 (断点可以是条件表达式)。
当程序停住时,可以检查此时程序中所发生的事。
动态地改变程序的执行环境。
从上面来看,gdb和一般的调试工具区别不大,基本上也是完成这些功能,不过在细节上,会发现gdb这个调试工具的强大。大家可能习惯了图形化的调试工具,但有时候,命令行的调试工具却有着图形化工具所不能完成的功能。
gdb.c
#include <stdio.h> int func(int n) { int sum=0,i; for(i=0; i<n; i++) { sum+=i; } return sum; } int main(void) { int i; long result = 0; for(i=1; i<=100; i++) { result += i; } printf("result[1-100] = %ld \n", result ); printf("result[1-250] = %d \n", func(250) ); }
编译生成执行文件(Linux下):
$ gcc –g gdb.c -o testgdb 使用gdb调试: $ gdb testgdb <---------- 启动gdb .......此处省略一万行 键入 l命令相当于list命令,从第一行开始列出源码: $ gdb testgdb .......此处省略一万行 (gdb) l 7 { 8 sum+=i; 9 } 10 return sum; 11 } 12 13 int main(void) 14 { 15 int i; 16 long result = 0; (gdb) 17 for(i=1; i<=100; i++) 18 { 19 result += i; 20 } 21 printf("result[1-100] = %ld \n", result ); 22 printf("result[1-250] = %d \n", func(250) ); 23 } (gdb) break 16 <-------------------- 设置断点,在源程序第16行处。 Breakpoint 1 at 0x804836a: file test.c, line 16. (gdb) break func <-------------------- 设置断点,在函数func()入口处。 Breakpoint 2 at 0x804832e: file test.c, line 5. (gdb) info break <-------------------- 查看断点信息。 Num Type Disp Enb Address What 1 breakpoint keep y 0x0804836a in main at test.c:16 2 breakpoint keep y 0x0804832e in func at test.c:5 (gdb) r <--------------------- 运行程序,run命令简写 Starting program: /home/shiyanlou/testgdb Breakpoint 1, main () at test.c:16 <---------- 在断点处停住。 16 long result = 0; (gdb) n <--------------------- 单条语句执行,next命令简写。 17 for(i=1; i<=100; i++) (gdb) n 19 result += i; (gdb) n 17 for(i=1; i<=100; i++) (gdb) n 19 result += i; (gdb) n 17 for(i=1; i<=100; i++) (gdb) c <--------------------- 继续运行程序,continue命令简写。 Continuing. result[1-100] = 5050 <----------程序输出。 Breakpoint 2, func (n=250) at test.c:5 5 int sum=0,i; (gdb) n 6 for(i=0; i<n; i++) (gdb) p I <--------------------- 打印变量i的值,print命令简写。 $1 = 1107620064 (gdb) n 8 sum+=i; (gdb) n 6 for(i=0; i<n; i++) (gdb) p sum $2 = 0 (gdb) bt <--------------------- 查看函数堆栈。 #0 func (n=250) at test.c:6 #1 0x080483b2 in main () at test.c:22 #2 0x42015574 in __libc_start_main () from /lib/tls/libc.so.6 (gdb) finish <--------------------- 退出函数。 Run till exit from #0 func (n=250) at test.c:6 0x080483b2 in main () at test.c:22 22 printf("result[1-250] = %d /n", func(250) ); Value returned is $3 = 31125 (gdb) c <--------------------- 继续运行。 Continuing. result[1-250] = 31125 Program exited with code 027. <--------程序退出,调试结束。 (gdb) q <--------------------- 退出gdb。
有了以上的感性认识,下面来系统地学习一下gdb。
gdb主要调试的是C/C++的程序。要调试C/C++的程序,首先在编译时,必须要把调试信息加到可执行文件中。使用编译器(cc/gcc/g++)的 -g 参数即可。如:
$ gcc -g hello.c -o hello $ g++ -g hello.cpp -o hello
如果没有-g,将看不见程序的函数名和变量名,代替它们的全是运行时的内存地址。当用-g把调试信息加入,并成功编译目标代码以后,看看如何用gdb来调试。 启动gdb的方法有以下几种:
gdb <program> program也就是执行文件,一般在当前目录下。
gdb <program> core 用gdb同时调试一个运行程序和core文件,core是程序非法执行后,core dump后产生的文件。
gdb <program> <PID> 如果程序是一个服务程序,那么可以指定这个服务程序运行时的进程ID。gdb会自动attach上去,并调试它。program应该在PATH环境变量中搜索得到。 gdb启动时,可以加上一些gdb的启动开关,详细的开关可以用gdb -help查看。下面只列举一些比较常用的参数: -symbols <file> -s <file> 从指定文件中读取符号表。 -se file
从指定文件中读取符号表信息,并把它用在可执行文件中。 -core <file> -c <file> 调试时core dump的core文件。 -directory <directory> -d <directory> 加入一个源文件的搜索路径。默认搜索路径是环境变量中PATH所定义的路径。
相关文章推荐
- Linux上安装Dubbo控制台
- Linux下修改Mysql最大并发连接数
- [转]Centos6.5使用yum安装mysql—配置MySQL允许远程登录
- Linux通过定时服务自动备份mysql数据库
- Linux 线程同步的三种方法
- 设置linux 可以访问外网
- centos vim 7.3 升级 + vim 简单配置文件
- Linux 内核学习之内存寻址(一) 硬件寻址
- linux系统环境下,对文件进行加密
- Linux查看日志常用命令
- Ramdisk简介以及嵌入式Linux上实现
- CentOS系统下的Hadoop集群(第3期)_VSFTP安装配置
- linux下删除乱码文件,目录
- CentOS系统下的Hadoop集群(第2期)_机器信息分布表
- linux 编辑 php 扩展
- linux
- 看 Linux kernel 應具備的首要觀念是?
- Linux系统日常管理
- Linux下fork()、vfork()、clone()和exec()的区别
- centos6.5下安装mysql,远程访问