03 Apr 2014html
1.gdb的原理linux
熟悉linux的同窗面試官會問你用過gdb麼?那好用過,知道gdb是怎麼工做的麼?而後直接傻眼。。。 gdb是怎麼接管一個進程?而且能獲取這個進程的變量、堆棧、寄存器、內存映像等信息的呢?還能夠打斷點執行?這些都是gdb一些基本的功能。 很簡單,ptrace,好來看看manual上這個系統調用的定義。c++
#include <sys/ptrace.h> long ptrace(enum __ptrace_request request, pid_t pid,void *addr, void *data);
簡單描述: ptrace系統調用提供一種方法使某一父進程(叫作"tracer")能夠觀察並控制另一個進程(叫作"tracee")的執行,並且還能夠檢查並改變執行tracee進程時的內存映像和寄存器。這個系統調用主要用來實現斷點調試和函數調用跟蹤( It is primarily used to implement breakpoint debugging and system call tracing)。
git
2.gdb將高級語言轉成彙編github
對於c、c++這樣的語言,若是不注意內存釋放常常會出現「野指針」、「空指針」等,程序dump掉的時候要找清楚那地方crash了,彙編指令顯的很是重要。 好比:面試
程序1:
redis
#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:
shell
#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; }
第一個程序不會core dump,而第二個程序core dump掉了。緣由在第12行程序1訪問的a是數組的地址,而程序2訪問的時指針a的內容,a爲NULL
指針,訪問其內容固然時非法的。你可能要問了,你爲何知道程序1訪問的是地址而程序2訪問的是內容呢? 那就須要彙編指令幫忙了。數組
題外話:程序2dump會產生core文件,若是沒有出現core文件,用ulimit -c unlimited命令產生。
[henry@localhost core]$ gdb -c core.4340 GNU gdb (GDB) Fedora 7.6.50.20130731-19.fc20 Copyright (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 file Try: yum --enablerepo='*debug*' install /usr/lib/debug/.build-id/73/a4410588cf88e43ecdfa6825cd15160aa6ddc7 Core was generated by `./struct_dump1'. Program terminated with signal SIGSEGV, Segmentation fault. #0 0x0000000000400544 in ?? () (gdb) file struct_dump1 Reading symbols from /home/henry/code/core/struct_dump1...done. (gdb) bt #0 0x0000000000400544 in main () at struct_dump1.c:12 (gdb) disassemble main Dump 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.
上面看到程序執行時用bt提示程序在12行dump掉了,而後轉換成彙編代碼能夠看到12行執行的時mov指令。sass
對於char a[0]來講,彙編代碼用了lea指令,lea 0×8(%rax), %rax
對於char *a來講,彙編代碼用了mov指令,mov 0×8(%rax), %rax
lea指令是把地址放進去,而mov是把內容放進去,而
NULL指針的內容是不能訪問的。這就是前面提到的*a 和a[0]的不一樣。
1
ni
和si
是單步執行彙編命令,和next
與step
同樣,n表示在當前函數一步步執行,s表明跟蹤函數,能夠從當前函數跳到另外一個函數。 display
能夠顯示一些寄存器內容,如display /x $pc
顯示程序計數器。 info reg
顯示全部寄存器內容。
tips——關於NULL指針:
若是程序裏有NULL指針,NULL指針會指向系統爲程序分配的段地址的開始,系統爲段開頭64k作苛刻的規定。程序中(低訪問權限)訪問要求高訪問權限的這64K內存被視做是不允許的,會引起Access Volitation 錯誤。64K內存是一塊保留內存(即不能被程序動態內存分配器分配,不能被訪問,也不能被使用),就是簡單的保留,不做任何使用。2
下面的代碼是對空指針的測試:
#define NULL (void*)0 int main() { int *p1 = NULL; int *p2 = NULL; int *p3 = NULL; return 0; } 下面是用gdb測試: [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.fc20 Copyright (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) list 1 #define NULL (void*)0 2 int main() 3 { 4 int *p1 = NULL; 5 int *p2 = NULL; 6 int *p3 = NULL; 7 return 0; 8 } (gdb) b 7 Breakpoint 1 at 0x40050c: file null_point_test.c, line 7. (gdb) r Starting program: /home/henry/code/core/null_point_test Breakpoint 1, main () at null_point_test.c:7 7 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測試結果p1 p2 p3的內容即null指針的地址都是
(int *) 0x0
正如上面多說空指針指向段首,而且都指向一個內存單元,null指針只有一個。
3.gdb調試core文件
用gdb -c core文件
命令調試core文件,調試過程種可能會老是一堆問號的問題,用symbol-file core文件對應的bin文件
命令添加字符集便可。
4.gdb條件斷點
已經有了斷點break_num將其轉化成條件斷點:condition break_num(斷點編號) cond(條件)
,當知足條件cond時,GDB纔會在斷點break_num處暫停程序的執行。
break break_num if cond(條件)
定義一個斷點並使之成爲條件斷點。
tbreak break_num
臨時斷點,斷點執行一次後此段點無效。
commands breakpoint_number
能夠設置執行斷點breakpoint_number時執行一段程序,有點批量執行的意思,以end結束。
引用: