天天看點

GDB調試指令小結

1.啟動調試

前置條件:編譯生成執行碼時帶上 -g,如果使用Makefile,通過給CFLAGS指定-g選項,否則調試時沒有符号資訊。

gdb program //最常用的用gdb啟動程式,開始調試的方式

gdb program core //用gdb檢視core dump檔案,跟蹤程式core的原因

gdb program pid //用gdb調試已經開始運作的程式,指定pid即可

gdb attach pid //用gdb調試已經開始運作的程式,指定pid即可

2.調試指令

(1)執行指令模式

-batch選項。

比如:列印$pid程序所有線程的堆棧并退出。

gdb -ex "set pagination 0" -ex "thread apply all bt" -batch -p $pid

(2).互動模式

run         //運作程式

continue  //中斷後繼續運作到下一個斷點

step        //單步執行,進入函數

next       //單步執行

return    //函數未執行完,忽略未執行的語句,傳回。

finish     //函數執行完畢傳回。

call        //調用某一個函數 fun("1234")

(backtrace)bt //顯示棧桢

bt N              //顯示開頭N個棧桢

bt -N            //顯示最後N個棧桢

(frame)f N     //顯示第N層棧桢

list //顯示源碼

set directory  //設定gdb的工作目錄

pwd              //目前的工作目錄

(3)反複執行

continue N    //連續執行cointiue N次,一般用于避免頻繁斷點

step N

next N

3.斷點

break 函數名        //設定斷在某個函數

break 檔案名:行号 //設定斷在某一行

info break            //檢視設定的斷點資訊

break if condition //條件斷點

break 函數名 thread 線程号 //設定斷點隻斷某個線程,通過info threads 檢視線程号

delete 斷點号 斷點号... //删除一個或多個斷點

diable 斷點号 斷點号... //禁止一個或多個斷點

enable 斷點号 斷點号... //打開一個或多個斷點

command 斷點号 //斷點觸發時,執行指令,一般用于列印變量

(gdb) command 1

Type commands for breakpoint(s) 1, one per line.

End with a line saying just "end".

>print x

>end

(gdb)

4.檢測點

watch //為表達式(變量)expr設定一個觀察點。一量表達式值有變化時,馬上停住程式。

rwatch //當表達式(變量)expr被讀時,停住程式。

awatch //當表達式(變量)的值被讀或被寫時,停住程式。

info watchpoints //列出目前所設定了的所有觀察點。

經驗:觀察某個變量是否變化,被讀或者被寫,由于變量隻在某一個作用域,可以擷取變量的位址,然後觀察。

比如:觀察examined_rows變量神馬時候被修改

(1).p &examined_rows,得到位址

(2).watch *(ha_rows *) 0x7ffec8005e28,則可以觀察這個變量的變化情況。

5.檢視變量

(1)設定

set print elements N //指定列印的長度,對長字元串特别有用。

set print element 0 //輸出完整的字元串

set print pretty //設定GDB列印結構的時候,每行一個成員,并且有相應的縮進,預設是關閉的

print {type} variable

比如:

(gdb) p {ABC} 0x7fffffffe710

$2 = {val = 1.5, val2 = 10}

print xxx //列印變量

p /x xxx //16進制顯示

p str@str_len //列印字元串

info locals //列印出目前函數中所有局部變量及其值。

info args //列印出目前函數的參數名及其值。

display 變量 //自動列印變量

undisplay //取消自動列印

注意:預設編譯的時候,調試過程是看不見宏的值的,編譯時候需要給選項。-g3

6.記憶體檢視

格式: x /nfu <addr> x 是 examine 的縮寫

a.n表示要顯示的記憶體單元的個數

b.f表示顯示方式, 可取如下值

(1).x 按十六進制格式顯示變量。

(2).d 按十進制格式顯示變量。

(3).u 按十進制格式顯示無符号整型。

(4).o 按八進制格式顯示變量。

(5).t 按二進制格式顯示變量。

(6).a 按十六進制格式顯示變量。

(7).i 指令位址格式

(8).c 按字元格式顯示變量。

(9).f 按浮點數格式顯示變量。

c.u表示一個位址單元的長度

(1).b表示單位元組,

(2).h表示雙位元組,

(3).w表示四位元組,

(4).g表示八位元組

比如:x/3xh buf

表示從記憶體位址buf讀取内容,3表示三個機關,x表示按十六進制顯示,h表示以雙位元組為一個機關。

7.多線程調試

info threads //檢視線程

thread thread_no //切換到線程号

thread apply all command //所有線程都執行指令列印棧桢

比如:thread apply all bt //所有線程都列印棧桢

(1)線程鎖

show scheduler-locking

set scheduler-locking on

set scheduler-locking off

預設是off,當程式繼續運作的時候如果有斷點,那麼就把所有的線程都停下來,直到你指定某個線程繼續執行(thread thread_no apply continue).

但是如果直接在目前線程執行continue的話,預設是會啟動所有線程。這種模式有一種副作用,如果多個線程都斷在同一個函數,這時候調試會出問題。

這個時候需要打開線程鎖,但打開線程鎖,意味着其它線程不能運作了。

(2)non-stop模式(7.0以後的版本支援)

set target-async 1

set pagination off

set non-stop on

gdb啟動了不停模式,除了斷點有關的線程會被停下來,其他線程會執行。

8.信号量

(1).singal 發送信号

假定你的程式已将一個專用的 SIGINT(鍵盤輸入,或CTRL-C;信号2)信号處理程式設定成采取某個清理動作,

要想測試該信号處理程式,你可以設定一個斷點并使用如下指令:

(gdb) signal 2

(2).handle 攔截信号

Handle指令可控制信号的處理,他有兩個參數,一個是信号名,另一個是接受到信号時該作什麼。幾種可能的參數是:

* nostop 接收到信号時,不要将它發送給程式,也不要停止程式。

* stop 接受到信号時停止程式的執行,進而允許程式調試;顯示一條表示已接受到信号的消息(禁止使用消息除外)

* print 接受到信号時顯示一條消息

* noprint 接受到信号時不要顯示消息(而且隐含着不停止程式運作)

* pass 将信号發送給程式,進而允許你的程式去處理它、停止運作或采取别的動作。

* nopass 停止程式運作,但不要将信号發送給程式。

handle SIGPIPE stop print //截獲SIGPIPE信号,程式停止并列印資訊

handle SIGUSR1 nostop noprint //忽略SIGUSR1信号

9.生産環境使用GDB場景

核心轉儲(coredump)

(1).配置産生core檔案

前置條件:確定系統配置的core file size足夠,一般設定成unlimited

ulimit -c unlimited

配置corefile的參數:

echo 2 > /proc/sys/fs/suid_dumpable [程式中切換使用者,也要産生corefile]

mkdir /tmp/corefiles

chmod 777 /tmp/corefiles

echo "/tmp/corefiles/core">/proc/sys/kernel/core_pattern //配置core檔案産生的目錄為/tmp/corefiles

echo "1" > /proc/sys/kernel/core_uses_pid

kill -sigsegv pid  //模拟異常記憶體通路信号

注意:

a.確定配置的目錄有足夠的磁盤空間,否則産生core檔案可能不完整。

b.對于mysqld而言,要保證正确産生core-file,需要加上--core-file,預設這個參數是不打開的。

c.kill -9 pid 是不能産生core檔案的,因為SIGKILL信号不能被捕獲。

(2).使用core檔案

gdb /usr/mysql/bin/mysqld core.24556

(3).dump已經運作程序的狀态資訊

gdb attach pid

(gdb) generate-core-file

調試完畢後,通過detach指令退出。

另外,通過gcore pid 指令也可以dump core檔案,生成在目前目錄下。

(4).列印線程資訊

pstack pid

pt-pmp -p pid

pstack和pt-pmp都可以列印線程的資訊,但是pt-pmp會對同類堆棧的線程做聚合彙總,相對于pstack功能更強大,顯示也更友好。

(5).altert日志

這裡主要針對mysqld問題排查,mysqld異常crash後,有時候在alter日志中可以看到最後crash線程的堆棧,但是一般隻有函數名或一串二進制位址,無法定位到具體是crash到哪一行,通過addr2line可以解這個問題。

比如:alter日志中記錄crash時的位址是0x64bd60,通過如下指令,可以定位到具體是哪一行

addr2line -e /usr/mysql/bin/mysqld 0x64bd60

/home/admin/131_20160715135613566_11155487_code/rpm_workspace/sql/sql_parse.cc:3067

參考文檔

https://www.percona.com/blog/2011/08/26/getting-mysql-core-file-on-linux/