03 APR 2014
1.gdb的原理
熟悉linux的同學(xué)面試官會(huì)問(wèn)你用過(guò)gdb么?那好用過(guò),知道gdb是怎么工作的么?然后直接傻眼。。。 gdb是怎么接管一個(gè)進(jìn)程?并且能獲取這個(gè)進(jìn)程的變量、堆棧、寄存器、內(nèi)存映像等信息的呢?還可以打斷點(diǎn)執(zhí)行?這些都是gdb一些基本的功能。 很簡(jiǎn)單,ptrace,好來(lái)看看manual上這個(gè)系統(tǒng)調(diào)用的定義。
#include <sys/ptrace.h>long ptrace(enum __ptrace_request request, pid_t pid,void *addr, void *data);
簡(jiǎn)單描述:ptrace系統(tǒng)調(diào)用提供一種方法使某一父進(jìn)程(叫做"tracer")可以觀察并控制另外一個(gè)進(jìn)程(叫做"tracee")的執(zhí)行,而且還可以檢查并改變執(zhí)行tracee進(jìn)程時(shí)的內(nèi)存映像和寄存器。這個(gè)系統(tǒng)調(diào)用主要用來(lái)實(shí)現(xiàn)斷點(diǎn)調(diào)試和函數(shù)調(diào)用跟蹤( It is primarily used to implement breakpoint debugging and system call tracing)。
2.gdb將高級(jí)語(yǔ)言轉(zhuǎn)成匯編
對(duì)于c、c++這樣的語(yǔ)言,如果不注意內(nèi)存釋放經(jīng)常會(huì)出現(xiàn)“野指針”、“空指針”等,程序dump掉的時(shí)候要找清楚那地方crash了,匯編指令顯的非常重要。 比如:
程序1:
#include <stdio.h>struct foo{ int i; char a[0];};struct fool{ struct foo *henry;};int main(){ struct fool test={0}; if(test.henry->a) printf("%x/n",test.henry->a); return 0;}
程序2:
#include <stdio.h>struct foo{ int i; char *a;};struct fool{ struct foo *henry;};int main(){ struct fool test={0}; if(test.henry->a) printf("%x/n",test.henry->a); return 0;}
第一個(gè)程序不會(huì)core dump,而第二個(gè)程序core dump掉了。原因在第12行程序1訪問(wèn)的a是數(shù)組的地址,而程序2訪問(wèn)的時(shí)指針a的內(nèi)容,a為NULL
指針,訪問(wèn)其內(nèi)容當(dāng)然時(shí)非法的。你可能要問(wèn)了,你為什么知道程序1訪問(wèn)的是地址而程序2訪問(wèn)的是內(nèi)容呢? 那就需要匯編指令幫忙了。
題外話:程序2dump會(huì)產(chǎn)生core文件,如果沒(méi)有出現(xiàn)core文件,用ulimit -c unlimited命令產(chǎn)生。
[henry@localhost core]$ gdb -c core.4340 GNU gdb (GDB) Fedora 7.6.50.20130731-19.fc20Copyright (C) 2013 Free Software Foundation, Inc.License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>This is free software: you are free to change and redistribute it.There is NO WARRANTY, to the extent permitted by law. Type "show copying"and "show warranty" for details.This GDB was configured as "x86_64-redhat-linux-gnu".Type "show configuration" for configuration details.For bug reporting instructions, please see:<http://www.gnu.org/software/gdb/bugs/>.Find the GDB manual and other documentation resources online at:<http://www.gnu.org/software/gdb/documentation/>.For help, type "help".Type "apropos Word" to search for commands related to "word".[New LWP 4340]Missing separate debuginfo for the main executable fileTry: yum --enablerepo='*debug*' install /usr/lib/debug/.build-id/73/a4410588cf88e43ecdfa6825cd15160aa6ddc7Core was generated by `./struct_dump1'.Program terminated with signal SIGSEGV, Segmentation fault.#0 0x0000000000400544 in ?? ()(gdb) file struct_dump1Reading symbols from /home/henry/code/core/struct_dump1...done.(gdb) bt#0 0x0000000000400544 in main () at struct_dump1.c:12(gdb) disassemble mainDump of assembler code for function main: 0x0000000000400530 <+0>: push %rbp 0x0000000000400531 <+1>: mov %rsp,%rbp 0x0000000000400534 <+4>: sub $0x10,%rsp 0x0000000000400538 <+8>: movq $0x0,-0x10(%rbp) 0x0000000000400540 <+16>: mov -0x10(%rbp),%rax=> 0x0000000000400544 <+20>: mov 0x8(%rax),%rax 0x0000000000400548 <+24>: test %rax,%rax 0x000000000040054b <+27>: je 0x400567 <main+55> 0x000000000040054d <+29>: mov -0x10(%rbp),%rax 0x0000000000400551 <+33>: mov 0x8(%rax),%rax 0x0000000000400555 <+37>: mov %rax,%rsi 0x0000000000400558 <+40>: mov $0x400600,%edi 0x000000000040055d <+45>: mov $0x0,%eax 0x0000000000400562 <+50>: callq 0x400410 <printf@plt> 0x0000000000400567 <+55>: mov $0x0,%eax 0x000000000040056c <+60>: leaveq 0x000000000040056d <+61>: retq End of assembler dump.
上面看到程序執(zhí)行時(shí)用bt提示程序在12行dump掉了,然后轉(zhuǎn)換成匯編代碼可以看到12行執(zhí)行的時(shí)mov指令。
對(duì)于char a[0]來(lái)說(shuō),匯編代碼用了lea指令,lea 0×8(%rax), %rax
對(duì)于char *a來(lái)說(shuō),匯編代碼用了mov指令,mov 0×8(%rax), %rax
lea指令是把地址放進(jìn)去,而mov是把內(nèi)容放進(jìn)去,而
NULL指針的內(nèi)容是不能訪問(wèn)的。這就是前面提到的*a 和a[0]的不同。
1
ni
和si
是單步執(zhí)行匯編命令,和next
與step
一樣,n表示在當(dāng)前函數(shù)一步步執(zhí)行,s代表跟蹤函數(shù),可以從當(dāng)前函數(shù)跳到另一個(gè)函數(shù)。display
可以顯示一些寄存器內(nèi)容,如display /x $pc
顯示程序計(jì)數(shù)器。info reg
顯示所有寄存器內(nèi)容。
tips——關(guān)于NULL指針:
如果程序里有NULL指針,NULL指針會(huì)指向系統(tǒng)為程序分配的段地址的開始,系統(tǒng)為段開頭64k做苛刻的規(guī)定。程序中(低訪問(wèn)權(quán)限)訪問(wèn)要求高訪問(wèn)權(quán)限的這64K內(nèi)存被視作是不容許的,會(huì)引發(fā)access Volitation 錯(cuò)誤。64K內(nèi)存是一塊保留內(nèi)存(即不能被程序動(dòng)態(tài)內(nèi)存分配器分配,不能被訪問(wèn),也不能被使用),就是簡(jiǎn)單的保留,不作任何使用。2
下面的代碼是對(duì)空指針的測(cè)試:
#define NULL (void*)0int main(){ int *p1 = NULL; int *p2 = NULL; int *p3 = NULL; return 0;} 下面是用gdb測(cè)試:[henry@localhost core]$ gcc -g null_point_test.c -o null_point_test[henry@localhost core]$ gdb null_point_test GNU gdb (GDB) Fedora 7.6.50.20130731-19.fc20Copyright (C) 2013 Free Software Foundation, Inc.License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>This is free software: you are free to change and redistribute it.There is NO WARRANTY, to the extent permitted by law. Type "show copying"and "show warranty" for details.This GDB was configured as "x86_64-redhat-linux-gnu".Type "show configuration" for configuration details.For bug reporting instructions, please see:<http://www.gnu.org/software/gdb/bugs/>.Find the GDB manual and other documentation resources online at:<http://www.gnu.org/software/gdb/documentation/>.For help, type "help".Type "apropos word" to search for commands related to "word"...Reading symbols from /home/henry/code/core/null_point_test...done.(gdb) list1 #define NULL (void*)02 int main()3 {4 int *p1 = NULL;5 int *p2 = NULL;6 int *p3 = NULL;7 return 0;8 }(gdb) b 7Breakpoint 1 at 0x40050c: file null_point_test.c, line 7.(gdb) rStarting program: /home/henry/code/core/null_point_test Breakpoint 1, main () at null_point_test.c:77 return 0;Missing separate debuginfos, use: debuginfo-install glibc-2.18-12.fc20.x86_64(gdb) p &p1$1 = (int **) 0x7fffffffdf08(gdb) p &p2$2 = (int **) 0x7fffffffdf00(gdb) p &p3$3 = (int **) 0x7fffffffdef8(gdb) p &p1$4 = (int *) 0x0(gdb) p &p2$5 = (int *) 0x0(gdb) p &p3$6 = (int *) 0x0(gdb) bt#0 main () at null_point_test.c:7(gdb) p main$4 = {int ()} 0x4004f0 <main>(gdb)
可以看出gdb測(cè)試結(jié)果p1 p2 p3的內(nèi)容即null指針的地址都是
(int *) 0x0
正如上面多說(shuō)空指針指向段首,并且都指向一個(gè)內(nèi)存單元,null指針只有一個(gè)。
3.gdb調(diào)試core文件
用gdb -c core文件
命令調(diào)試core文件,調(diào)試過(guò)程種可能會(huì)總是一堆問(wèn)號(hào)的問(wèn)題,用symbol-file core文件對(duì)應(yīng)的bin文件
命令添加字符集即可。
4.gdb條件斷點(diǎn)
已經(jīng)有了斷點(diǎn)break_num將其轉(zhuǎn)化成條件斷點(diǎn):condition break_num(斷點(diǎn)編號(hào)) cond(條件)
,當(dāng)滿足條件cond時(shí),GDB才會(huì)在斷點(diǎn)break_num處暫停程序的執(zhí)行。
break break_num if cond(條件)
定義一個(gè)斷點(diǎn)并使之成為條件斷點(diǎn)。
tbreak break_num
臨時(shí)斷點(diǎn),斷點(diǎn)執(zhí)行一次后此段點(diǎn)無(wú)效。
commands breakpoint_number
可以設(shè)置執(zhí)行斷點(diǎn)breakpoint_number時(shí)執(zhí)行一段程序,有點(diǎn)批量執(zhí)行的意思,以end結(jié)束。
引用:
指針和數(shù)組的差別?
空指針保護(hù)政策?
新聞熱點(diǎn)
疑難解答
圖片精選