目錄html
@linux
online doc of Compiling for Debugging正則表達式
gcc/g++是在編譯時加入-g(注意 -g 參數要在 -o 以前,不然可能沒有調試信息)
-g分4個等級:shell
1) gdb ${你的程序} 進入gdb後,輸入run(簡寫r) ${arg1} ${arg2} … ${argN}
2) gdb --args ${你的程序} ${arg1} ${arg2} … ${argN} 進入gdb後,運行run。
3) gdb進入gdb後,輸入file ${你的程序}。而後使用set args ${arg1} ${arg2} … ${argN} 設定好你的程序參數,再運行run。數組
info 簡寫爲 i info locals :查看局部變量,能夠簡寫: i lo. info args :查看函數入參 :i ar info break : 查看斷點: i b info registers :查看寄存器的狀況 info threads :當前已知線程
allows overriding the output format used by the command
/o - octal
/x - hexadecimal
/d - decimal
/u - unsigned decimal
/t - binary
/f - floating point
/a - address
/c - char
/s - string安全
p arr[0]@len
bash
set max-value-size unlimited
多線程
ptype/pty 後跟結構體名,或結構體變量
set print pretty
backtrace :顯示棧信息(調用鏈)。簡寫爲bt。 frame x 切換到第x幀。其中x會在bt命令中顯示,從0開始。0表示棧頂。簡寫爲f。 up/down x 往棧頂/棧底移動x幀。當不輸入x時,默認爲1。
(gdb) layout src:顯示源碼窗口: la sr (gdb) layout asm:顯示彙編窗口 (gdb) layout regs:顯示寄存器窗口 (gdb) layout split:顯示源碼和彙編窗口 (gdb) layout next:顯示下一個layout窗口 (gdb) layout prev:顯示上一個layout窗口 Ctrl + L:刷新窗口 Ctrl + x,再按1:單窗口模式 Ctrl + x,再按2:雙窗口模式 Ctrl + x,再按a:退出layout,回到執行layout以前的調試窗口。
1, set substitute-path from_path to_path
,替換源碼文件路徑。當編譯機與運行程序的機器代碼路徑不一樣時,須要使用該指令替換代碼路徑,不然你沒法在gdb中看到源碼。
2, 爲靜態庫設置源碼路徑: dir pathapp
簡寫爲: comm 先查看現有的斷點,而後 comm 後跟上斷點序號,寫入這個斷點要作的事,end結束。
step
單步調試,步入當前函數。可簡寫爲snext
單步調試,步過當前函數。可簡寫爲nuntil
執行到當前循環完成。可簡寫爲ufinish
執行到當前函數返回continue
繼續運行程序到下一個斷點,或結束。可簡寫爲creturn
: 強制函數返回。能夠指定返回值jump
使當前執行的程序跳轉到某一行,或者跳轉到某個地址。因爲只會使程序跳轉而不會改變棧值,所以若跳出函數到另外的地方 會致使return出錯。另外,熟悉彙編的人都知道,程序運行時,有一個寄存器用於保存當前代碼所在的內存地址。因此,jump命令也就是改變了這個寄存器中的值。因而,你可使用「set $pc」來更改跳轉執行的地址。如: set $pc = 0x485call
調用函數。command n >printf "x is %d\n",x >c >end
set var x=10
改變當前變量x的值。也能夠這樣用:set {int}0x83040 = 10把內存地址0x83040的值強制轉換爲int並賦值爲10是指當執行到程序某一步時,程序交出控制權進入調試器。值得注意的是,break會有一些變體:tbreak,hbreak,thbreak與rbreak。tbreak與break功能相同,只是所設置的斷點在觸發一次後自動刪除。hbreak是一個硬件斷點。thbreak則既是一個臨時的硬件斷點。注意硬件斷點須要硬件支持,某些硬件可能不支持這種類型的斷點。rbreak稍微特殊一些,它會在匹配正則表達式的所有位置加上斷點,後面會有詳細講解。除去rbreak,其餘break家族的使用方法以下:函數
查看斷點: info break
, 簡寫i b
break 能夠縮寫爲 b
1) break xxx.cpp:y
。在文件 xxx.cpp 的第 y 行加入斷點。
不指定文件時候,則會以當前執行的文件做爲斷點文件。
若程序未執行,則以包含main函數的源代碼文件做爲斷點文件。
若x.cpp和y都不指定,則以當前debugger的點做爲斷點處。
2) break x.cpp:func
。在x.cpp的func函數入口處加入斷點。x.cpp能夠不提供直接使用break func。注意因爲重載(overload)的存在,所以gdb可能會詢問你但願在哪一個函數加上斷點。
3) break 0xN
。在地址N處加入斷點。N必須爲一個有效的代碼段(code segment)地址。
4) 刪除多個斷點 del 1-10
1, save break file.bp
保存斷點到 file.bp
2, source file.bp
加載斷點(so file.bp)
監視點是監視內存中某個地址,當該地址的數據被改變(或者被讀取)時,程序交出控制權進入調試器。注意監視點分爲軟件模式和硬件模式:GDB 使用軟件監視點的方式是在單步執行你的程序的同時測試變量的值,因此執行程序的速度會變慢。同時,軟件監視點僅在當前線程有效。幸運的是,32 位的 Intel x86 處理器提供了 4 個特殊的調試寄存器用來方便調試程序,GDB 可使用這些寄存器創建硬件監視點。GDB 老是會優先使用硬件監視點,由於這樣不會減慢程序的執行速度。然而,可用的(enable的)硬件監視點的個數是有限的。若是你設置了過多的硬件監視點,當程序從中斷的狀態變爲執行的狀態(例如continue,until或者finish)時,GDB 可能沒法把它們所有激活。另外,活動的硬件監視點的數量只有在試圖繼續執行程序時才能知道,也就是說,即便你設置了過多的硬件監視點,gdb在你運行程序以前也不會警告你。
設置監視點的命令有3個,watch(寫監視),rwatch(讀監視)以及awatch(讀寫監視)。他們的使用方法同樣,皆爲如下幾種:
1) (r/a)watch var
。var是一個變量名。當x的值改變/被讀取時,程序交出控制權進入調試器。
2) (r/a)watch *0xdeadbeef
。0xdeadbeef爲一個有效地址。當該地址的內容變化/被讀取時,程序交出控制權進入調試器。
3) (r/a)watch *(int *)0xdeadbeef
。0xdeadbeef爲一個有效地址。當該地址的中的int指針指向的內容變化/被讀取時,程序交出控制權進入調試器。
4) (r/a)watch -l *(int *)0xdeadbeef
。0xdeadbeef爲一個有效地址。當該地址的中的int指針指向的內容變化/被讀取,或者該地址的內容變化/被讀取時,程序交出控制權進入調試器。
注意3)和4)的區別在於,當加入-l選項後,會同時監視表達式自己以及表達式指向的內容。
注意:watch 地址的時候,要加解引用符號 *
If you watch for a change in a numerically entered address you need to dereference it, as the address itself is just a constant number which will never change. GDB refuses to create a watchpoint that watches a never-changing value
(gdb) watch 0x600850
Cannot watch constant value 0x600850.
(gdb) watch (int ) 0x600850
Watchpoint 1: (int ) 6293584
跟蹤點與上面三個斷點不一樣之處在於,它只是跟蹤記錄信息而不會中斷程序的運行。當你的程序是realtime程序,或者與其餘的程序有交互時,你可能會但願使用跟蹤點達到監視程序而又不破壞程序自身行爲的目的。與斷點相同的是,跟蹤點會保存下在跟蹤點時的一些內存信息供使用者查閱,例如數組或者對象。
另外,tracepoints能夠經過save命令保存,以方便使用者下次再次進入程序調試時不須要重設這些跟蹤點。
gdb能夠經過fork當前進程的映像,而且稍後又能夠返回到這個狀態。這個稱之爲checkpoint。
每一個檢查點是進程的一個拷貝。這樣當一個bug很難重現,而又擔憂調試過頭了又要從頭開始重現時,能夠在估計要重現這個bug以前,作一個checkpoint,這樣即便debug過頭了,也能夠從這個checkpoint開始,而不用重啓整個程序而且期待它重現這個bug。
用法:
在當前位置設置檢查點
(gdb) checkpoint
查看檢查點
(gdb) info checkpoints
回到設置的檢查點,
(gdb) restart checkpoint-id
core dump又叫核心轉儲, 當程序運行過程當中發生異常, 程序異常退出時, 由操做系統把程序當前的內存情況存儲在一個core文件中, 叫core dump. (linux中若是內存越界會收到SIGSEGV信號,而後就會core dump)
1.內存訪問越界
a) 因爲使用錯誤的下標,致使數組訪問越界
b) 搜索字符串時,依靠字符串結束符來判斷字符串是否結束,可是字符串沒有正常的使用結束符
c) 使用strcpy, strcat, sprintf, strcmp, strcasecmp等字符串操做函數,將目標字符串讀/寫爆。應該使用strncpy, strlcpy, strncat, strlcat, snprintf, strncmp, strncasecmp等函數防止讀寫越界。
2 多線程程序使用了線程不安全的函數。
3 多線程讀寫的數據未加鎖保護。對於會被多個線程同時訪問的全局數據,應該注意加鎖保護,不然很容易形成core dump
4 非法指針
a) 使用空指針
b) 隨意使用指針轉換。一個指向一段內存的指針,除非肯定這段內存原先就分配爲某種結構或類型,或者這種結構或類型的數組,不然不要將它轉換爲這種結構或類型 的指針,而應該將這段內存拷貝到一個這種結構或類型中,再訪問這個結構或類型。這是由於若是這段內存的開始地址不是按照這種結構或類型對齊的,那麼訪問它 時就很容易由於bus error而core dump.
5 堆棧溢出.不要使用大的局部變量(由於局部變量都分配在棧上),這樣容易形成堆棧溢出,破壞系統的棧和堆結構,致使出現莫名其妙的錯誤。
首先經過ulimit命 令查看一下系統是否配置支持了dump core的功能。經過ulimit -c或ulimit -a,能夠查看core file大小的配置狀況,若是爲0,則表示系統關閉了dump core。能夠經過ulimit -c unlimited來打開。若發生了段錯誤,但沒有core dump,是因爲系統禁止core文件的生成。
解決方法:
$ulimit -c unlimited (只對當前shell進程有效)
或在~/.bashrc 的最後加入: ulimit -c unlimited (一勞永逸)
gdb [exec file] [core file]
如: gdb ./test test.core
能夠產生core的c語言語句: *(char *)0 = 0;
修改文件命令:
把core文件與執行程序相同路徑
echo "core-%e-%p" > /proc/sys/kernel/core_pattern
或者:
sysctl -w kernel.core_pattern=/corefile/core-%e-%p-%t kernel.core_pattern = /corefile/core-%e-%p-%t
能夠將core文件統一輩子成到/corefile目錄下,產生的文件名爲core-命令名-pid-時間戳
如下是參數列表:
%e - insert coredumping executable name into filename 添加致使產生core的命令名 %p - insert pid into filename 添加pid(進程id) %u - insert current uid into filename 添加當前uid(用戶id) %g - insert current gid into filename 添加當前gid(用戶組id) %s - insert signal that caused the coredump into the filename 添加致使產生core的信號 %t - insert UNIX time that the coredump occurred into filename 添加core文件生成時的unix時間 %h - insert hostname where the coredump happened into filename 添加主機名
在內核中還有一個與coredump相關的設置,就是/proc/sys/kernel/core_uses_pid。若是這個文件的內容被配置成1,
那麼即便core_pattern中沒有設置%p,最後生成的core dump文件名仍會加上進程ID。
emacs :https://www.cnblogs.com/gaowengang/p/5799292.html
https://www.cnblogs.com/xsln/p/gdb_instructions1.html
彙編:https://www.cnblogs.com/zhangyachen/p/9227037.html