目錄python
調試器GDB容許查看在執行一個程序時其內部時發生了什麼,或者是程序奔潰(crashed)時它正在作什麼。
gdb經過如下四種事情來捕獲某個行爲的異常錯誤(bug):linux
gdb
命令激活。一旦啓動,他從命令行讀取命令,直到使用quit
命令讓它退出。也能夠經過使用help command
命令獲取在線幫助。gdb program #指定一個可執行程序 gdb program core #指定一個可執行程序以及core文件 gdb program pid #指定一個正在運行的程序 gdb -p pid #同上
list命令用於查看代碼,可簡寫爲l。git
list #查看上一次list中心附近的10行代碼,-5~+5 list n #查看第n行附近10行代碼,n-5~n+5 list b,e #查看b,e行範圍的代碼 list function #查看函數function附近的代碼 list file:line #查看文件file第line行附件的代碼 list file:function #查看文件file的函數function附近的代碼 list *address #地址爲address的行附近的代碼,使用info add name獲取地址
break命令用於設置斷點,可用b簡化;delete用於刪除斷點,可用d簡化。github
break n #在第n行設置斷點 break function #在函數function設置斷點,能夠是庫函數 break file:line #在文件file第line行設置斷點 break file:function #在文件file的function函數設置斷點 break n if condition #根據條件在第n行設置斷點,例如b 16 if i==10 break *address #在地址爲address的行設置斷點
每次使用break設置斷點都會分配一個斷點號,例如:shell
(gdb) b 16 Breakpoint 1 at 0x400512: file test.cc, line 16. (gdb) b 17 Breakpoint 2 at 0x40051b: file test.cc, line 17.
要刪除斷點使用可使用delete
命令:express
delete [breakpoints num] [range...] delete n #刪除n號斷點 delete m-n #刪除m-n號斷點
也可使用clear
命令,clear是基於行的,不是刪除全部斷點:ubuntu
clear n #刪除n行的全部斷點 clear function #刪除函數function的斷點 clear file:line #刪除文件file第n行的全部斷點 clear file:function #刪除文件:函數的全部斷點
print
命令print var #打印var的值 print *array@len #以{a, b, ...}格式打印動態數組 print array #以{a, b, ...}格式打印靜態數組 print file::var or print function::var #打印全局變量 #指定輸出格式: print/u[d|o|x...] ... #做爲無符號數輸出 print/t ... #二進制輸出 print/d ... #十進制輸出 print/o ... #八進制輸出 print/x ... #十六進制輸出 print/a ... #十六進制輸出 print/c ... #字符輸出 print/f ... #浮點數輸出
display
命令display var #每次執行到斷點都打印var的值
run
命令(gdb) break 20 Breakpoint 1 at 0x40056d: file test.cc, line 20. (gdb) run Starting program: /home/chenjunhan/Learning/gdb/test Breakpoint 1, main () at test.cc:20
continue
命令(gdb) b 15 Breakpoint 1 at 0x40050b: file test.cc, line 15. (gdb) b 16 Breakpoint 2 at 0x400512: file test.cc, line 16. (gdb) r Starting program: /home/chenjunhan/Learning/gdb/test Breakpoint 1, main () at test.cc:15 (gdb) continue Continuing. Breakpoint 2, main () at test.cc:16
next
命令step
命令info|i functions
next|n #不進入函數,直接執行函數並返回 step|s #進入函數,執行函數體 call|print function #任意位置直接執行函數
finish #退出正在執行的函數,自動執行剩下的代碼 return [expression] #退出正在執行的函數,後面的代碼不執行,能夠經過expression修改函數返回值
info|i frame #顯示當前函數堆棧幀信息,包括指令寄存器的值,局部變量地址及值等信息。 backtrace|bt #顯示堆棧幀層次結構 frame n|address #切換函數堆棧幀層次 up|down n #向上/下選擇n層函數堆棧幀 up-silently|down-silently n #同上,不過不打印信息
gdb可使用watch
命令設置觀察點,也就是當一個變量值發生變化時,程序會停下來。例如:數組
int a = 0; void *pthread_func(void *args) { while (1) { ++a; sleep(1); } } int main() { pthread_t tid; pthread_create(&tid, NULL, pthread_func, NULL); sleep(1000); return 0; }
使用catch|wa
觀察全局變量a:多線程
(gdb) file catch Reading symbols from catch...done. (gdb) break pthread_func Breakpoint 1 at 0x400659: file catch.c, line 11. (gdb) watch a Hardware watchpoint 2: a (gdb) r Starting program: /home/chenjunhan/Learning/gdb/catch [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". [New Thread 0x7ffff77f6700 (LWP 6578)] [Switching to Thread 0x7ffff77f6700 (LWP 6578)] Breakpoint 1, pthread_func (args=0x0) at catch.c:11 11 ++a; (gdb) continue Continuing. Hardware watchpoint 2: a Old value = 0 New value = 1 pthread_func (args=0x0) at catch.c:12 12 sleep(1); (gdb) continue Continuing. Breakpoint 1, pthread_func (args=0x0) at catch.c:11 11 ++a;
catch var #爲var設置觀察點,在run以前 catch *(type*)(address) #爲地址address指向的變量設置觀察點
info watchpoints
disable|enable|delete n
info threads #列出全部threads編號等信息,thread_create以後 watch var thread t_num #只有編號爲t_num的thread修改了var值纔會停下來
rwatch|rw var #設置只讀觀察點每次訪問var都會停下來 wwatch|aw var #設置讀寫觀察點,當發生讀取或改變變量值的行爲時,程序就會暫停住
使用gdb調試程序時,能夠用tcatch
命令設置catchpoint只觸發一次。例如:app
int main() { pid_t pid; int i = 0; for (i = 0;i < 4; ++i) { if ((pid = fork()) < 0) //fork error exit(1); else if (pid == 0) //child exit(0); } printf("Hello World\n");//parent return 0; }
使用tcatch fork
爲fork設置catchpoint
(gdb) tcatch fork Catchpoint 1 (fork) (gdb) r Starting program: /home/chenjunhan/Learning/gdb/catch Temporary catchpoint 1 (forked process 6838), 0x00007ffff7ad5ee4 in __libc_fork () at ../nptl/sysdeps/unix/sysv/linux/x86_64/../fork.c:130 130 ../nptl/sysdeps/unix/sysv/linux/x86_64/../fork.c: 沒有那個文件或目錄. (gdb) c Continuing. Hello World [Inferior 1 (process 6834) exited normally]
catch fork catch vfork catch exec
catch syscall [syscall_name|syscall_num] #例如catch syscall mmap catch syscall #爲全部系統調用設置catchpoint
backtrace full
命令(gdb) bt full #0 fun_a () at a.c:6 a = 0 #1 0x000109b0 in fun_b () at a.c:12 b = 1 #2 0x000109e4 in fun_c () at a.c:19 c = 2 #3 0x00010a18 in fun_d () at a.c:26 d = 3 #4 0x00010a4c in main () at a.c:33 var = -1
info locals
命令,打印當前函數局部變量(gdb) info locals a = 0
info proc mappings #查看內存映像信息 info files #更詳細地輸出進程的內存信息,包括引用的動態連接庫等 info target #功能同上
typedef struct student_t{ char *name; int age; } student; int main() { student s; student *ps; return 0; }
使用wathis
和ptype
命令調試,ptype能夠列出詳細的類型。
(gdb) whatis s type = student (gdb) whatis ps type = student * (gdb) ptype s type = struct student_t { char *name; int age; }
info variables var
#沒啓動gdb ps -a | grep program #查看進程id gdb program pid #調試 gdb --pid pid #同上 #啓動gdb attach pid #斷開 detach
gdb調試默認追蹤父進程,要追蹤子進程,則執行下列命令:
set follow-fork-mode child
gdb調試時,默認追蹤一個進程,使用下列命令能夠同時調試多個進程:
set detach-on-fork off #默認運行父進程,掛起其餘進程 set schedule-multiple on #父進程,子進程一塊兒運行
以後gdb默認追蹤父進程,其餘進程被掛起,使用下列命令能夠切換進程:
inferior infno #切換到子進程 info inferior #打印全部進程信息 inferior n #選擇切換調試進程
thread|_thread
查看當前線程id(gdb) thread [Current thread is 1 (Thread 0x7ffff7fcc740 (LWP 9494))] (gdb) printf "current thread:%d\n",$_thread current thread:1
info threads
查看全部線程信息(gdb) info threads Id Target Id Frame 3 Thread 0x7ffff6ff5700 (LWP 9627) "thread" 0x00007ffff78b7dfd in nanosleep () at ../sysdeps/unix/syscall-template.S:81 2 Thread 0x7ffff77f6700 (LWP 9626) "thread" 0x00007ffff78b7dfd in nanosleep () at ../sysdeps/unix/syscall-template.S:81 1 Thread 0x7ffff7fcc740 (LWP 9622) "thread" main () at thread.cc:21
thread id
gdb調試程序時,一旦程序斷住,全部線程都會中止。當調試其中一個線程時,全部線程都會開始執行。若是想調試一個線程同時其餘線程中止,可用如下命令:
set scheduler-locking on
#添加一個新的調試程序。-copies指定執行多少份,默認1 add-inferior [-copies n] [-exec program] #複製添加一個新的調試程序,infno表示調試進程編號,默認爲當前inferior clone-inferior [-copies -n] [infno] info inferior #列出全部調試的進程 maint info program-spaces #列出全部調試的進程名稱,inferior編號,進程id inferior n #切換進程
程序因爲各類異常或者bug致使在運行過程當中異常退出或者停止,而且在知足必定條件下(這裏爲何說須要知足必定的條件呢?下面會分析)會產生一個叫作core的文件。
一般狀況下,core文件會包含了程序運行時的內存,寄存器狀態,堆棧指針,內存管理信息還有各類函數調用堆棧信息等,咱們能夠理解爲是程序工做當前狀態存儲生成第一個文件,許多的程序出錯的時候都會產生一個core文件,經過工具分析這個文件,咱們能夠定位到程序異常退出的時候對應的堆棧調用等信息,找出問題所在並進行及時解決。
ubuntu默認不生成core文件,可用一下命令解決:
ulimit -c unlimited
generate-core-file #先run gcore #上面的簡寫
示例程序:
int main() { int *p = NULL; *p = 0; return 0; }
上面程序當執行*p = 0
時程序會crashed,產生core dump file,下面使用gdb進行調試:
#shell環境加載core文件 gdb test corefile #同上,gdb環境中 file test core corefile #gdb加載core file以後打印的信息 [New LWP 9672] Core was generated by `./test'. Program terminated with signal SIGSEGV, Segmentation fault. #0 0x000000000040054b in main () at test.c:8 8 *p = 0; #也可使用where命令定位錯誤位置 (gdb) where #0 0x000000000040054b in main () at test.c:8