使用gdbwushxins fox.docx
- 文档编号:9396053
- 上传时间:2023-05-18
- 格式:DOCX
- 页数:8
- 大小:19.77KB
使用gdbwushxins fox.docx
《使用gdbwushxins fox.docx》由会员分享,可在线阅读,更多相关《使用gdbwushxins fox.docx(8页珍藏版)》请在冰点文库上搜索。
使用gdbwushxinsfox
使用gdbWuShXin'sfox
使用gdb开始近来在写网络服务器程序,涉及到了多线程,且由于网络的环境复杂的原因,常有未知情况发生,导致在程序中自行添加调试语句显得有些吃力将gdb请出山来是一个最为正确的选择使用gdb看起来是全命令行的东西,而且一启动就是一大片英文,实在让没用过的望而却步,其实真正常用的就只有那几个功能。
接下来我可能不会对这些命令进行明确的定义功能,因为有时候某些功能放在不同的地方意义就不同了,所以我只用最简单的语言来记录它们。
首先是安装,在(Debian)系的发行版Linux上,使用apt-getinstallgdb
回车等一会就行,可能有的发行版已经装好了,但有的却没有。
首先不要打开这个gdb,因为这里面的东西的确看起来挺复杂的我们要先有一个程序的源文件,假设是C语言的main.c在里面写好正确的语句后,对它进行编译,链接,也就是调用GCC,这里使用GCC的命令是gcc-omain-gmain.c
这个-g标志非常必要,意味着生成一些符号信息,用人话说就是gdb所需要的东西,没有这个东西是无法使用gdb进行调试的。
紧接着,在当前目录下就有一个名为main的可执行文件,看好当前用户是否有权限执行它之后,使用如下命令开启调试旅程:
gdb./main
紧接着,出现一大堆英文,不要慌,静静的等待它们装逼,最后会出现一个(gdb)
光标在闪烁的时候,就证明gdb加载这个程序的符号信息完毕,你可以准备执行了这时候,你只要输入一个字母r,就能让这个main程序执行起来(gdb)r
如果这个程序没有问题的话,几乎就和在外面正常运行时一样,gdb没有起到任何作用,但是一旦有任何问题的话,gdb就会暂停在那个出错的地方,而不是继续执行。
这里说的出错,不一定代表着就是程序出错或者崩溃退出,有可能是程序接收到了某个信号,信号在Linux中并不少见,这对于某些特殊用途的程序而言,看到接收到的信号十分重要,例如网络程序。
对于r这个命令除了这么孤零零的使用以外,还可以对它进行传递参数,例如你的main程序需要两个参数,你可以这样(gdb)r192.168.141.1498889
这就和在外面使用:
./main192.168.141.1498889
的效果一样第二个命令自然是,最常用的设置断点,这也是十分简单,命令就一个字母b最简单的用法就是直接接着一个数字,代表着要设置断点的地点(行),例如(gdb)b10
表示在当前的执行文件中的第十行设置一个断点,设置完了会有成功信息:
Breakpoint1at0x400556:
filemain.c,line10.
意思就是,设置了第一个断点,在内存位置0x400556地方,人类能懂得地方在main.c文件的第十行另一种情况就是,当你的程序是多个文件编译而成的时候,你如果不指定文件名,那么默认就是在当前执行的这个地方所属的文件里设定(gdb)bmain.c:
10
这就是完整的语法,十分简单,这就是设置断点最常用的方式当然,你也可以直接以函数的名字作为断点,来进行设置(gdb)bmain
但是在执行的时候,我怎么能记得住我要在哪里设置断点?
难道要背下来?
这里有几个方法可以参考一下。
首先当然就是你事先已经有一个完整的调试计划,记下在哪里设置断点自然是万事大吉但通常由于程序员的自信小宇宙,我们坚信自己的程序是完美的,所以会先执行程序,在这个过程中假设我们碰到一个错误,gdb帮我们及时停了下来,我们可以借助三个常用命令(后面写到)来帮助我们知道,自己现在身处何处,再设置断点上面说到的三个常用命令之一,二where,bt之所以放在一起,因为这两个命令的意义差不多,至少在用的时候是这样,都是显示出当前执行位置的函数栈,这对调试十分重要,所谓函数栈就是我们当前进入到哪个函数了,如果程序的函数嵌套挺深的时候,就能够用它来理清思路并且这里说的函数栈并不只限于程序员编写的函数,还包括所调用的系统函数。
(gdb)where
直接在光标处写就行,写完回车就能够看见函数栈,但是如果你的函数嵌套过深这也不是一个好办法,但聊胜于无(gdb)bt
与上方一致。
输出信息大概是这样(用我调试网络程序时收到一个SIGPIPE的情况为例)#00x00007ffff727cbc0in__write_nocancel()
at../sysdeps/unix/syscall-template.S:
81
#10x0000000000401ea6inwrite_n(handle=5,
out_buf=0x7fffffff1a10"Http/1.0200OK\r\nServer:
Wu
shxinHTTPServer\r\nContent-length:
276\r\nContent-type:
text/html\r\n\r\n",buf_len=94)
at/root/ClionProjects/httpd2/iofunc.cpp:
68
#20x0000000000402657inserve_static(client_fd=5,
filename=0x7fffffff9a80"./home.html",file_size=276)
at/root/ClionProjects/httpd2/deal_client/server_static.cpp:
37
#30x00000000004021b4indeal_client(client_fd=5)
at/root/ClionProjects/httpd2/deal_client/dealclient.cpp:
77
#40x0000000000401cacindeal_server(listen_fd=3,listen_fd_type=2)
at/root/ClionProjects/httpd2/server.cpp:
154
#50x00000000004017c4inmain(argc=3,argv=0x7fffffffe1b8)
at/root/ClionProjects/httpd2/main.cpp:
31
稍微有点长,但是还是很清楚的,每个#后面是一个栈,括号中是参数名和参数真实值。
稍微分析一下就能大概确定断点应该设置在什么地方,如果觉得栈太深,可以在某些栈的入口处设断点,好好分析,但总归函数嵌套太深就是模块化做的不好。
(比如我这个程序就是。
所以推倒重构了。
,都是泪,写程序前一定要先画好构造图,不然会越写越复杂,写的时候不要想着做更多的事,而要做好一件事。
)三个常用的最后一个就是list在你运行到某处,被gdb停下来的时候,除了使用where或者bt,总体浏览一下函数栈,还能具体的查看一下现在执行到哪行代码了(gdb)list
当然这个可能对系统函数没什么作用,因为它可能会显示:
76in../sysdeps/unix/syscall-template.S
这个时候你就需要去它的上一层中查看错误了,但正常情况下,list会将你所执行位置语句的上下几行一起显示出来。
回到最开始的r命令,现在可以知道它是让程序开始执行的命令,那么和他有相似效果,但是用处不同的另外两个命令分别是c和nc代表着continue,也就是忽略这个断点或者错误继续执行的意思(比如收到某个信号)n代表着next,也就是执行到下一条语句,然后暂停。
最后就是怎么退出gdb(gdb)q
就行了。
小结r<para1>...是运行程序c是继续运行程序n是执行下一条语句where和bt是显示函数栈list是显示当前运行语句的上下文(此上下文非操作系统概念中的上下文)q是退出gdb调试这些就是最常用的几个单线程的调试方式,没错单线程。
以上是逻辑清晰的单线程/单进程程序的调试,其实多进程/多线程的调试也是差不多的类型多进程/多线程的调试两个除了操作上有些命令不同,实质上的调试思想是差不多的,都是“变量控制”的方法。
有个命令首先要说:
attach这是用来调试多进程的命令,想要调试多进程的程序,会稍微麻烦一些,首先要启动程序(不需要加载到gdb中),启动后,在shell中用ps命令查看该进程延伸出的子进程,并且记下子进程的进程号启动gdb,并且使用attach,假设要调试的进程号是4488$gdb
...
(gdb)attach4488
#...加载符号信息
#加载完毕后,会停在有光标的状态,这时候你可以设置断点,或者选择继续
(gdb)...
当然,如果一开始只有一个进程,但是在你调试的某个过程中会有fork操作,这时候可以使用另一个命令来明确说明要继续跟踪父进程还是调试子进程(gdb)setfollow-fork-modechild
这个命令有点长,不太好记,可以抄写在某个地方,用到的时候再看(我就是如此)与之对应的自然就是setfollow-fork-modeparent多线程,也很类似两个重要的命令先说infothreads和thread<ID>infothreads是显示当前程序的所有线程信息,并且会给每个线程配上一个相应的ID,也就是第一列显示的ID,而不是后面显示的。
使用这个ID可以在调试线程之间进行切换切换的命令则是thread(gdb)infothreads
IdTargetIdFrame
*1process19515"main"main(argc=1,
argv=0x7fffffffe1f8)atmain.c:
12
...
当前线程前方会有一个*显示。
(gdb)thread2
表示切换到2号线程调试最后,关于多线程调试有一个高级一点的命令,就是如果我们在调试的时候,不希望其它线程运行而干扰到本线程的调试,可以使用(gdb)setscheduler-lockingon
这样一来就只有所调试的线程才会执行,对于这个命令的其他两个参数off和step
分别是关闭这个功能和单步执行(n)情况下才不允许其他线程运行的效果。
总结以上便是全部gdb常用的操作,记住了他们也就能满足绝大部分的调试工作了,比带图形界面的调试器更有效率。
实用当调试一个程序的时候,往往不是只看表象就能解决的,有时候需要深入到某个栈的某个变量的值,查看是否违背了原先的意义。
这时候需要的就是gdb的info功能,以及有时候需要在前序栈中进行查看,就需要frame功能的配合。
假设有一个程序:
#include<stdio.h>
#include<stdlib.h>
intfunc_2(intarg_2){
intin_func_2_1=22;
intin_func_2_2=arg_2;
returnin_func_2_1+in_func_2_2;
}
intfunc_1(intarg_1){
intin_func_1_1=11;
intin_func_1_2=arg_1;
returnfunc_2(in_func_1_1+in_func_1_2);
}
intmain(intargc,char*argv[]){
printf("Theresultis%d\n",func_1(0));
return0;
}
将这个程序编译,记得带上-g,并用gdb打开设置断点bfunc_1,bfunc_2设置完成之后,r运行,程序停在了第一个断点,也就是func_1的入口处,这时候使用bt查看一下栈的情况Breakpoint1,func_1(arg_1=0)atmain.c:
10
10intin_func_1_1=11;
(gdb)infolocals
in_func_1_1=0
in_func_1_2=0
这时候使用了infolocals,可以显示出这个函数中创建的本地变量的值,看到两个值都是零,这只是偶然而已,很有可能是其他的垃圾值。
继续使用命令n(gdb)n
11intin_func_1_2=arg_1;
(gdb)infolocal
in_func_1_1=11
in_func_1_2=0
发现执行到第11行,in_func_1_1被赋值,为11,这就是常用的调试手法,那接着使用c命令,继续运行。
(gdb)c
Continuing.
Breakpoint2,func_2(arg_2=11)atmain.c:
5
5intin_func_2_1=22;
(gdb)infolocal
in_func_2_1=32767
in_func_2_2=-134253376
(gdb)n
6intin_func_2_2=arg_2;
(gdb)infolocals
in_func_2_1=22
in_func_2_2=-134253376
(gdb)bt
#0func_2(arg_2=11)atmain.c:
6
#10x000000000040052binfunc_1(arg_1=0)atmain.c:
12
#20x0000000000400546inmain(argc=1,argv=0x7fffffffe228)atmain.c:
16
此处的infolocal和infolocals的效果一样,看来gdb也懂得程序员不容易,允许我们脑子放松一些。
还有在gdb中是可以使用Tab键的补全功能的。
此处和上方的效果一致,就不再叙述,重点是,现在我使用bt命令发现,身处三重函数栈的第0层(最顶层)之中,也就是当先的函数func_2之中,但是我现在却想要看到func_1里面的信息怎么办?
很简单,就是使用frame(gdb)frame1
#10x000000000040052binfunc_1(arg_1=0)atmain.c:
12
12returnfunc_2(in_func_1_1+in_func_1_2);
(gdb)infolocals
in_func_1_1=11
in_func_1_2=0
这样我们就回到了编号为1的栈中,且当前状态就是调用func_2的时候,此时再使用infolocals就可以看见这个栈中的各种参数了这里少了实参的查看,其实很简单:
infoargs(gdb)infoar
arg_1=0
(gdb)parg_1
$1=0
当然也可以用p直接打印了。
其实info还有很多其他功能,是很多。
可以在gdb中使用info直接查询,像这样(gdb)info
回车之后Listofinfosubcommands:
infoaddress--DescribewheresymbolSYMisstored
infoall-registers--Listofallregistersandtheircontents
infoargs--Argumentvariablesofcurrentstackframe
infoauto-load--Printcurrentstatusofauto-loadedfiles
infoauto-load-scripts--PrintthelistofautomaticallyloadedPythonscripts
infoauxv--Displaytheinferior'sauxiliaryvector
infobookmarks--Statusofuser-settablebookmarks
infobreakpoints--Statusofspecifiedbreakpoints(alluser-settable
......
---Type<return>tocontinue,orq<return>toquit---
还有很多没贴上来,可以自行查看。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 使用gdb wushxins fox 使用 gdb
![提示](https://static.bingdoc.com/images/bang_tan.gif)