今天又研究了一下,还有其他功能 , GDB尤其在你调别人的程序的时候,更有有助于你更快的理解别人的程序 。
0,可以显示出堆栈的调用的情况:backtrace ,简写bt , 还有命令down和up
比如函数调用如下:
main.c
|-------------|
|
DownloadMessFromLDAP()
|_____________
|
dosearch()
|___
|__
print_entry()
比如step into 到print_entry()函数里面去了,
(gdb) bt
#0 print_entry (ld=0x804bec0, entry=0x804c5f8, attrsonly=0, UserList=0x804b2e0, GroupList=0x804b2f0) at ldapsearch.c:610
#1 0x4002f48a in dosearch (ld=0x804bec0, base=0x0, scope=2, filtpatt=0x0, value=0x40031a85 "(sAMAccountName=*)", attrs=0x0, attrsonly=0,
sctrls=0x0, cctrls=0x0, timeout=0x0, sizelimit=-1, UserList=0x804b2e0, GroupList=0x804b2f0) at ldapsearch.c:498
#2 0x4002f248 in DownloadMessFromLDAP (dn=0x8049f20 "cn=Administrator,cn=Users,dc=linux,dc=sercomm,dc=com", password=0x8049f10 "1", UserList=0x804b2e0, GroupList=0x804b2f0) at ldapsearch.c:381
#3 0x08049aa4 in main () at main.c:35
#4 0x40049917 in __libc_start_main () from /lib/libc.so.6
这个时候会看到函数调用的情况 。
(gdb)up 跳到上一级函数
#1 0x4002f48a in dosearch (ld=0x804bec0, base=0x0, scope=2, filtpatt=0x0, value=0x40031a85 "(sAMAccountName=*)", attrs=0x0, attrsonly=0,
sctrls=0x0, cctrls=0x0, timeout=0x0, sizelimit=-1, UserList=0x804b2e0, GroupList=0x804b2f0) at ldapsearch.c:498
498 print_entry( ld, msg, attrsonly,UserList,GroupList);
(gdb)down 又回到print_entry 函数里面去了
print_entry (ld=0x804bec0, entry=0x804c5f8, attrsonly=0, UserList=0x804b2e0, GroupList=0x804b2f0) at ldapsearch.c:610
610 if(strcmp(a,"sAMAccountName") && strcmp(a,"memberOf") && strcmp(a,"objectClass"))
.,
1,利用ptype 可以马上查处某个变量的类型。
Breakpoint 2, dosearch (ld=0x804bec0, base=0x0, scope=2, filtpatt=0x0, value=0x40031a85 "(sAMAccountName=*)", attrs=0x0, attrsonly=0,
sctrls=0x0, cctrls=0x0, timeout=0x0, sizelimit=-1, UserList=0x804b2e0, GroupList=0x804b2f0) at ldapsearch.c:413
413 assert(UserList);
(gdb) ptype UserList
type = struct {
ADSUserDnode *front;
ADSUserDnode *currptr;
int size;
} *
(gdb)
在你还不太了解他人程序的时候,可以边调边看 , 想看代码 ,用list 命令 ,会列出附近的10行代码
(gdb)list
(gdb) list
408 LDAPMessage *res, *msg;
409 ber_int_t msgid;
410
411
412
413 assert(UserList);
414 assert(GroupList);
415
416
417 printL("have into %s",__FUNCTION__);
2,利用finish和return ,帮忙进行测试 ,finish可以在跳到一个函数里面的时候, 继续执行,返回这个函数的返回值 。 return 可以人工的返回一个值 , 这样就可以测试 各种返回值了。
比如:
你用step 进入了一个child() ,如果你用finish 命令 , 会看出child()的返回值, 当然你可以用return 10 就return 10这个值, 这样,可以很直观的看到程序的流程 。
3,利用watch可以监测某个变量是否被改动了, 被哪段程序改动了。 (乍碰到一个别人的bug , 不知道怎么下手, 可以试试,象我们CGI就烦死了, 经常会出错 , 有的时候你就需要知道 某个关键的 全局变量 被谁改动了, 当然你可以在source 里面search ,但是那里是死的啊!这里可是活的, 反映出真正的运行流程 )
比如一个rc 变量 ,你不知道程序中哪个段代码改了它 ,
注意gdb里面的上下文的概念 。 只有程序run起来 main.c 里面才会看到DownloadMessFromLDAP(),
dosearch()
print_entry()
所以 这样:
gdb main
(gdb) break DownloadMessFromLDAP (或干脆break main 好了, 这样
(gdb) run 这个时候才会建立上下文呢!
(gdb) watch rc
(gdb) continue
(gdb) watch rc
Hardware watchpoint 2: rc
(gdb) continue
Continuing.
Hardware watchpoint 2: rc
Hardware watchpoint 2: rc
Hardware watchpoint 2: rc
Hardware watchpoint 2: rc
Hardware watchpoint 2: rc
Hardware watchpoint 2: rc
Hardware watchpoint 2: rc
Hardware watchpoint 2: rc
Old value = -1073743536
New value = 0
DownloadMessFromLDAP (dn=0x8049f20 "cn=Administrator,cn=Users,dc=linux,dc=sercomm,dc=com", password=0x8049f10 "1", UserList=0x804b2e0,
GroupList=0x804b2f0) at ldapsearch.c:253
253 if( rc != LDAP_SUCCESS ) {
这样可以直接找到 修改rc的地方。
这样才有点象调试程序的样子了。 ^_^
文章转自 http://zhanglinbao.bokee.com/2942572.html