|
1、GDB简介
GDB(GNU Debugger)是GCC的调试工具。主要帮你完成下面四个方面的功能:
- 启动程序, 可以按照你的自定义的要求随心所欲的运行程序。
- 可让被调试的程序在你所指定的断点处停住。(断点可以是条件表达式)
- 当程序被停住时, 可以检查此时你的程序中所发生的事。
- 动态的改变你程序的执行环境。
2、gdb调试
gdb是在程序运行的结果与预期不符合的时候, 可以使用gdb进行调试。特别注意的是: 使用gdb调试需要在编译的时候加-g参数. 如果没有-g, 你将看不见程序的函数名、变量名, 所代替的全是运行时的内存地址。
gcc -g -c hello.c
gcc -o hello hello.o3、基本操作
1 启动gdb
这里测试还是使用【C-30】C语言gcc编译器和静动态库 的四个简单函数为实例。并作稍微修改如下:
main.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include &#34;head.h&#34;
int main(int argc, char *argv[])
{
printf(&#34;this is main!\n&#34;);
int i = 0;
for(i=0; i<argc; i++)
{
printf(&#34;[%d]:[%s]\n&#34;, i, argv);
}
fun1();
fun2();
printf(&#34;sum(10)==[%d]\n&#34;, sum(10));
return 0;
}sum.c
#include <stdio.h>
int sum(int len)
{
int i = 0;
int sum = 0;
for(i=0; i<len; i++)
{
sum += i;
}
return sum;
}修改之前的Makefile如下($(CC) -g -c $< $(CPPFLAGS))
src=$(wildcard ./*.c)
object=$(patsubst %.c, %.o, $(src))
target=main
CC=gcc
CPPFLAGS=-I./
$(target):$(object)
$(CC) -o $@ $^
%.o:%.c
$(CC) -g -c $< $(CPPFLAGS)
.PHONY:clean
clean:
#rm -f $(target) $(object)
rm -f $(object)
启动gdb:gdb program
program 也就是你的执行文件, 一般在当前目录下。
设置运行参数
- set args 可指定运行时参数。(如:set args 10 20 30 40 50 )
- show args 命令可以查看设置好的运行参数。
启动程序
- run:程序开始执行, 如果有断点, 停在第一个断点处
- start:程序向下执行一行。(在第一条语句处停止)
gdb ./main
(gdb) set args hello yifan,I am here
(gdb) show args
Argument list to give program being debugged when it is started is &#34;hello yifan,I am here&#34;.
(gdb) run
Starting program: /u02/wangbao/test_c/main hello yifan,I am here
this is main!
this is fun
this is fun2
this is fun2
[Inferior 1 (process 24566) exited normally]
(gdb) start
Temporary breakpoint 1 at 0x40051d: file main.c, line 6.
Starting program: /u02/wangbao/test_c/main hello yifan,I am here
Temporary breakpoint 1, main (argc=5, argv=0x7fffffffea88) at main.c:6
6 printf(&#34;this is main!\n&#34;);退出gdb,使用quit
2 显示源代码
GDB 可以打印出所调试程序的源代码,当然在程序编译时一定要加上-g的参数,把源程序信息编译到执行文件中。不然就看不到源程序了。当程序停下来以后, GDB会报告程序停在了那个文件的第几行上。你可以用list命令来打印程序的源代码, 默认打印10行, list命令的用法如下所示:
list linenum:打印第linenum行的上下文内容.
list function:显示函数名为function的函数的源程序。
list: 显示当前行后面的源程序。
list -:显示当前文件开始处的源程序。
list file:linenum: 显示file文件下第n行
list file:function: 显示file文件的函数名为function的函数的源程序 一般是打印当前行的上5行和下5行,默认是10行, 当然, 你也可以定制显示的范围, 使用下面命令可以设置一次显示源程序的行数。
- set listsize count:设置一次显示源代码的行数。
- show listsize: 查看当前listsize的设置。
(gdb) list fun1.c:1
1 #include<stdio.h>
2 void fun1()
3 {
4 printf(&#34;this is fun\n&#34;);
5 }
(gdb)
Line number 6 out of range; fun1.c has 5 lines.
(gdb) list fun1.c:fun1
1 #include<stdio.h>
2 void fun1()
3 {
4 printf(&#34;this is fun\n&#34;);
5 }
(gdb) list main
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include&#34;head.h&#34;
4 int main(int argc, char *argv[])
5 {
6 printf(&#34;this is main!\n&#34;);
7 fun1();
8 fun2();
9 return 0;
10 }
(gdb) set listsize 4
(gdb) list main
3 #include&#34;head.h&#34;
4 int main(int argc, char *argv[])
5 {
6 printf(&#34;this is main!\n&#34;);
(gdb)list 可以简写为l
3 断点操作
1 简单断点—当前文件
break 设置断点, 可以简写为b
- b 10 设置断点, 在源程序第10行
- b func 设置断点, 在func函数入口处
2 多文件设置断点---其他文件
在进入指定函数时停住:
- b filename:linenum --在源文件filename的linenum行处停住
- b filename:function --在源文件filename的function函数的入口处停住
3 查询所有断点
- info b == info break == i break == i b
4 条件断点
一般来说, 为断点设置一个条件, 我们使用if关键词, 后面跟其断点条件。设置一个条件断点:
- b test.c:8 if intValue == 5
- b linenum
- b func
- b file:linenum
- b file:func
5 维护断点
delete [range...] 删除指定的断点, 其简写命令为d。如果不指定断点号, 则表示删除所有的断点。range表示断点号的范围(如:3-7)。
- 删除某个断点: delete num
- 删除多个断点: delete num1 num2 ...
- 删除连续的多个断点: delete m-n
- 删除所有断点: delete
比删除更好的一种方法是disable停止点, disable了的停止点, GDB不会删除, 当你还需要时, enable即可, 就好像回收站一样。
- disable [range...] 使指定断点无效, 简写命令是dis。
- enable [range...] 使无效断点生效, 简写命令是ena。
6 调试代码
- run 运行程序, 可简写为r
- next 单步跟踪, 函数调用当作一条简单语句执行, 可简写为n
- step 单步跟踪, 函数调进入被调用函数体内, 可简写为s
- finish 退出进入的函数, 如果出不去, 看一下函数体中的循环中是否有断点,如果有删掉,或者设置无效
- until 在一个循环体内单步跟踪时, 这个命令可以运行程序直到退出循环体,可简写为u,如果出不去, 看一下函数体中的循环中是否有断点,如果有删掉,或者设置无效
- continue 继续运行程序, 可简写为c(若有断点则跳到下一个断点处)
2: sum = 3
(gdb) n
7 for(i=0; i<len; i++)
2: sum = 6
(gdb) until
11 return sum;
2: sum = 45
7 查看变量的值
查看运行时变量的值
- print 打印变量、字符串、表达式等的值, 可简写为p
自动显示变量的值
你可以设置一些自动显示的变量, 当程序停住时, 或是在你单步跟踪时, 这些变量会自动显示。相关的GDB命令是display。
- display 变量名
- info display -- 查看display设置的自动显示的信息。
- undisplay num(info display时显示的编号)
- delete display dnums… -- 删除自动显示, dnums意为所设置好了的自动显式的编号。如果要同时删除几个, 编号可以用空格分隔, 如果要删除一个范围内的编号, 可以用减号表示(如:2-5)
- 删除某个自动显示: undisplay num 或者delete display num
- 删除多个: delete display num1 num2
- 删除一个范围: delete display m-n
- disable display dnums… 显示无效
- enable display dnums… 显示有效
- disable和enalbe 不删除自动显示的设置, 而只是让其失效和恢复。
(gdb) print sum
$7 = 3
(gdb) print i
$8 = 2
---------------------以上是手动print,可以设置成自动显示----------------------------
(gdb) display i
1: i = 2
(gdb) next
9 sum += i;
1: i = 3
(gdb) display sum
2: sum = 3
(gdb) n
7 for(i=0; i<len; i++)
1: i = 3
2: sum = 6
(gdb) info display
Auto-display expressions now in effect:
Num Enb Expression
1: y i
2: y sum
(gdb) disable display 1
(gdb) info display
Auto-display expressions now in effect:
Num Enb Expression
1: n i
2: y sum查看修改变量的值
- ptype width --查看变量width的类型
- p width --打印变量width 的值
你可以使用set var命令来告诉GDB, width不是你GDB的参数, 而是程序的变量名, 如:set var width=47 // 将变量var值设置为47在你改变程序变量取值时, 最好都使用set var格式的GDB命令。
(gdb) r
Starting program: /u02/test_c/main
Breakpoint 5, __libc_start_main (main=0x400593 <main>, argc=1, argv=0x7fffffffeac8,
init=0x400630 <__libc_csu_init>, fini=0x4006a0 <__libc_csu_fini>,
rtld_fini=0x7ffff7de3b40 <_dl_fini>, stack_end=0x7fffffffeab8) at ../csu/libc-start.c:137
137 ../csu/libc-start.c: No such file or directory.
(gdb) ptype argc
type = int
(gdb) ptype argv
type = char **
(gdb) print argv
$10 = (char **) 0x7fffffffeac8
(gdb) print argc
$11 = 1
(gdb) print argv[0]
$12 = 0x7fffffffed04 &#34;/u02/test_c/main&#34;main函数的第一个参数就是主程序,后面才是自己的参数。
8 设置参数并显示
举例:set args yifan nihao
(gdb) set args yifan nihao
(gdb) print argc
No symbol &#34;argc&#34; in current context.
(gdb) i b
No breakpoints or watchpoints.
(gdb) b 10
Breakpoint 1 at 0x4005a2: file main.c, line 10.
(gdb) run
Starting program: /u02/wangbao/test_c/main yifan nihao
Breakpoint 1, main (argc=3, argv=0x7fffffffeaa8) at main.c:10
10 printf(&#34;this is main!\n&#34;);
(gdb) print argc
$1 = 3
(gdb) print argv
$2 = (char **) 0x7fffffffeaa8
(gdb) print argv[0]
$3 = 0x7fffffffecf8 &#34;/u02/wangbao/test_c/main&#34;
(gdb) print argv[1]
$4 = 0x7fffffffed11 &#34;yifan&#34;
(gdb) print argv[2]
$5 = 0x7fffffffed17 &#34;nihao&#34;
(gdb) print argv[3]
$6 = 0x04、debug实例
一个项目中地址切词部分需要debug,这里正好演示操作。因为是公司项目,代码部分就不粘贴了。
1 编译部分加 -g
sudo g++ -O3 -lpthread -std=c++11 -g wb_word_cut.cpp -I/u03/wb/addr_i1_cpp/addr_20/dict/include -o /u03/wang/addr_i1_cpp/addr_20/run_wb/wb_word_cut_gdb
2 开启gdb
开启gdb,并输入参数:
]$gdb wb_word_cut
(gdb) set args &#34;上海上海市松江区上海上海市松江区泗泾镇泗凤公路1500弄7号楼804&#34;3 设置断点
使用list查找要打断点的位置

设置断点

4 测试
(gdb) run
Starting program: /u03/wangbao/addr_i1_cpp/addr_20210927_15/run_wb/wb_word_cut_gdb &#34;上海上海市松江区上海上海市松江区泗泾镇泗凤公路1500弄7号楼804&#34;
[Thread debugging using libthread_db enabled]
Using host libthread_db library &#34;/lib64/libthread_db.so.1&#34;.
Breakpoint 3, RepairAddrWords (words=std::vector of length 11, capacity 13 = {...}) at fun_const.h:1039
1039 for (int j = 0; j < 5; j++) {
(gdb) i display
Auto-display expressions now in effect:
Num Enb Expression
1: y res (cannot be evaluated in the current context)
(gdb) display words
2: words = std::vector of length 11, capacity 13 = {&#34;上海市&#34;, &#34;上海市&#34;, &#34;松江区&#34;, &#34;上海&#34;, &#34;上海市&#34;, &#34;松江区&#34;, &#34;泗泾镇&#34;, &#34;泗凤公路&#34;, &#34;1500弄&#34;, &#34;7号楼&#34;, &#34;804&#34;}
(gdb) i display
Auto-display expressions now in effect:
Num Enb Expression
2: y words
1: y res (cannot be evaluated in the current context)
(gdb) n
查看效果情况:
#补全功能,上海 补全成上海市
1040 if (words[j] == u8&#34;北京&#34; || words[j] == u8&#34;天津&#34; || words[j] == u8&#34;重庆&#34; || words[j] == u8&#34;上海&#34;) {
2: words = std::vector of length 11, capacity 13 = {&#34;上海市&#34;, &#34;上海市&#34;, &#34;松江区&#34;, &#34;上海&#34;, &#34;上海市&#34;, &#34;松江区&#34;, &#34;泗泾镇&#34;, &#34;泗凤公路&#34;, &#34;1500弄&#34;, &#34;7号楼&#34;, &#34;804&#34;}
(gdb) n
1041 words[j] = words[j] + u8&#34;市&#34;;
2: words = std::vector of length 11, capacity 13 = {&#34;上海市&#34;, &#34;上海市&#34;, &#34;松江区&#34;, &#34;上海&#34;, &#34;上海市&#34;, &#34;松江区&#34;, &#34;泗泾镇&#34;, &#34;泗凤公路&#34;, &#34;1500弄&#34;, &#34;7号楼&#34;, &#34;804&#34;}
(gdb) n
1045 if (words[j] == u8&#34;广东&#34; || words[j] == u8&#34;浙江&#34; || words[j] == u8&#34;河北&#34; || words[j] == u8&#34;辽宁&#34; || words[j] == u8&#34;吉林&#34; || words[j] == u8&#34;黑龙江&#34; || words[j] == u8&#34;江苏&#34; ||
2: words = std::vector of length 11, capacity 13 = {&#34;上海市&#34;, &#34;上海市&#34;, &#34;松江区&#34;, &#34;上海市&#34;, &#34;上海市&#34;, &#34;松江区&#34;, &#34;泗泾镇&#34;, &#34;泗凤公路&#34;, &#34;1500弄&#34;, &#34;7号楼&#34;, &#34;804&#34;}
#去重功能:松江区重复的去掉:
2: words = std::vector of length 8, capacity 13 = {&#34;上海市&#34;, &#34;松江区&#34;, &#34;松江区&#34;, &#34;泗泾镇&#34;, &#34;泗凤公路&#34;, &#34;1500弄&#34;, &#34;7号楼&#34;, &#34;804&#34;}
(gdb)
1068 if (words[j] == words ||
2: words = std::vector of length 8, capacity 13 = {&#34;上海市&#34;, &#34;松江区&#34;, &#34;松江区&#34;, &#34;泗泾镇&#34;, &#34;泗凤公路&#34;, &#34;1500弄&#34;, &#34;7号楼&#34;, &#34;804&#34;}
(gdb)
1072 words.erase(words.begin() + i, words.begin() + i + 1);
2: words = std::vector of length 8, capacity 13 = {&#34;上海市&#34;, &#34;松江区&#34;, &#34;松江区&#34;, &#34;泗泾镇&#34;, &#34;泗凤公路&#34;, &#34;1500弄&#34;, &#34;7号楼&#34;, &#34;804&#34;}
(gdb)
1067 for (int i = iEnd; i > j; i--) {
2: words = std::vector of length 7, capacity 13 = {&#34;上海市&#34;, &#34;松江区&#34;, &#34;泗泾镇&#34;, &#34;泗凤公路&#34;, &#34;1500弄&#34;, &#34;7号楼&#34;, &#34;804&#34;} |
|