日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

nginx源码分析--使用GDB调试

發布時間:2024/1/23 编程问答 51 豆豆
生活随笔 收集整理的這篇文章主要介紹了 nginx源码分析--使用GDB调试 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在學習優秀的源代碼時是少不了源碼的跟蹤與調試,它不僅是我們解決程序bug的有效途徑,也是我們理解、學習優秀源碼的有效途徑。

本文主要介紹一些源碼調試的方法,并結合Nginx源碼進行示例。

1,利用GDB調試

? a,首先你應該熟悉GDB調試的一些基本命令(不熟悉的移步 至用GDB調試程序?,熟悉step,run,break,list,info,continue等命令)。

? b.下載nginx源碼,這里使用nginx-1.0.14,解壓文件。其中auto文件夾里包含了configure運行時的各種命令集合,src是源碼。為了利用

? ? ? GDB調試Nginx,需要在生成Nginx程序時把-g編譯選項打開。我們需要修改 auto/cc/conf文件把ngx_compile_opt="-c" 加上 -g 選項

? ? ? 變為ngx_compile_opt="-c -g",下一步執行configure命令:sudo ./configure,然后運行命令:vim objs/Makefile確認一下-g參數是否加上了。如下圖:

? ? -g編譯選項已打開,然后執行命令:sudo make .(如果之前已經執行過make,那么第二次make時需要確保能夠重新編譯,此時可以通過刷新所有源文件時間戳,間接達到重新編譯出一個新的Nginx可執行程序,命令為:find . -name "*.c" | xargs touch),好了,Nginx編譯成功。

? c.啟動nginx,在objs目錄下執行命令:sudo ./nginx,成功運行nginx后執行命令:ps -ef | grep nginx,查看nginx的master及worker進程的PID,如果對nginx工作進程2177進行gdb調試,那么可以利用gdb的-p選項。命令:gdb -p 2177.

? ? 當有多個工作進程時 調試起來比較麻煩。我們可以修改配置項,修改文件nginx.conf。加入master_process off;單進程模式 將監控進程和工作進程邏輯全部合在一個進程里。此時只有一個進程,可以方便的利用gdb進行調試。

? ? 我們知道工作進程會停留在epoll_wait處等待相應的事件發生,而這個函數調用被封裝在ngx_process_events_and_times中,于是我們在這個函數設置一個斷點: b ngx_event.c:ngx_process_events_and_times,結合gdb命令c,s,n,如圖所示:

? ??

? ? 采用命令c,使得nginx一直運行,直到遇到第一個斷點,處理事件的方法是ngx_process_events,于是我們用命令s跟蹤進去這個函數。當執行到epoll_wait函數的時候,發現進程停留在這里,不能在向下執行。這就證明了worker子進程阻塞在epoll_wait函數調用處。此時我們在另一個終端執行下列命令,以向nginx發送消息: curl -I localhost,可以看到請求已經發送,正在等待回應。

? ? 此時繼續執行命令 c即可在另一終端得到回應。此時可以通過bt命令查看單進程模式下函數調用的過程。如圖。

? ?利用curl命令。

??

? ?gdb bt

? ??

?2,利用strace、pstack調試nginx

? ? a.strace常用來跟蹤進程執行時的系統調用和所接收的信號。在Linux世界,進程不能直接訪問硬件設備,當進程需要訪問硬件設備(比如讀取磁盤問及那,接收網絡數據等等)時,必須由用戶態模塊切換至內核態模式,通過系統調用訪問硬件設備。strace可以跟蹤到一個進程產生的系統調用,包括參數,返回值,執行消耗的時間。此外命令ltrace用來查看 動態庫函數調用。

? ? b.那具體是哪個函數調用呢?在strace輸出結果中并不能找到答案,因其輸出顯示都是系統調用,要顯示程序中函數調用棧信息,就輪到pstack上場了。pstack是一個腳本工具,其核心實現就是使用了gdb以及thread apply all bt命令。

? ? ?我們在此修改nginx的配置文件nginx.conf使其為僅具有一個master進程和一個worker進程。

? ? ? 把1中修改的master_process off;注解掉加上#

? ? ? 并在配置文件上加上worker_processes 1;

? ? ? 關閉之前的nginx重新啟動nginx。利用命令:ps -ef | grep nginx查看當前存在的nginx進程,然后用strace命令的參數-p 選項跟蹤Nginx工作進程,如圖。

? ?

? ? ? ?可以看到工作進程阻塞在epoll_wait系統調用上,因為此時沒有客戶端請求,nginx就阻塞于此,在另一個終端執行curl命令:curl -I localhost,再來看strace輸出結果如圖。

? ??

? ? strace輸出的每一行記錄一次系統調用,等號左邊是系統調用名以及調用參數,等號右邊是該系統調用的返回值。

通過上面的系統調用我們可以做出如下分析:

?⑴.???epoll_wait返回值為1,表示有1個描述符存在可讀/寫事件,這里當然是可讀事件。
?⑵.???accept4接受該請求,返回的數字3表示socket的文件描述符。
?⑶.???epoll_ctl把accept4建立的socket套接字(注意參數3)加入到事件監聽機制里。
?⑷.???recv從發生可讀事件的socket文件描述符內讀取數據,讀取的數據存在第二個參數內,讀取了79個字節。
?⑸.???stat64判斷客戶端請求的html文件是否存在,返回值為0表示存在。
?⑹.???open/fstat64打開并獲取文件狀態信息。open文件返回的文件描述符為9,后面幾個系統調用都用到這個值。
?⑺.???writev把響應頭通過文件描述符3代表的socket套接字發給客戶端。
?⑻.???sendfile64把文件描述符9代表的響應體通過文件描述符3代表的socket套接字發給客戶端。
?⑼.???再往文件描述符4代表的日志文件內write一條日志信息。
?⑽.???recv看客戶端是否還發了其它待處理的請求/信息。
?⑾.???最后關閉文件描述符3代表的socket套接字。
??由于strace能夠提供nginx執行過程中的這些內部信息,所以在出現一些奇怪現象,比如nginx啟動失敗、響應的文件數據和預期不一致、莫名其妙

??的Segment Fault段錯誤、存在性能瓶頸(利用-T選項跟蹤各個函數的消耗時間),利用strace也許能提供一些相關幫助。最后,要退出strace跟蹤,按ctrl+c即可。

? ??

詳細介紹strace 參數:

-c 統計每一系統調用的所執行的時間,次數和出錯的次數等.
-d 輸出strace關于標準錯誤的調試信息.
-f 跟蹤由fork調用所產生的子進程.
-ff 如果提供-o filename,則所有進程的跟蹤結果輸出到相應的filename.pid中,pid是各進程的進程號.
-F 嘗試跟蹤vfork調用.在-f時,vfork不被跟蹤.
-h 輸出簡要的幫助信息.
-i 輸出系統調用的入口指針.
-q 禁止輸出關于脫離的消息.
-r 打印出相對時間關于,,每一個系統調用.
-t 在輸出中的每一行前加上時間信息.
-tt 在輸出中的每一行前加上時間信息,微秒級.
-ttt 微秒級輸出,以秒了表示時間.
-T 顯示每一調用所耗的時間.
-v 輸出所有的系統調用.一些調用關于環境變量,狀態,輸入輸出等調用由于使用頻繁,默認不輸出.
-V 輸出strace的版本信息.
-x 以十六進制形式輸出非標準字符串
-xx 所有字符串以十六進制形式輸出.
-a column
設置返回值的輸出位置.默認 為40.
-e expr
指定一個表達式,用來控制如何跟蹤.格式如下:
[qualifier=][!]value1[,value2]...
qualifier只能是 trace,abbrev,verbose,raw,signal,read,write其中之一.value是用來限定的符號或數字.默認的 qualifier是 trace.感嘆號是否定符號.例如:
-eopen等價于 -e trace=open,表示只跟蹤open調用.而-etrace!=open表示跟蹤除了open以外的其他調用.有兩個特殊的符號 all 和 none.
注意有些shell使用!來執行歷史記錄里的命令,所以要使用\\.
-e trace=set
只跟蹤指定的系統 調用.例如:-e trace=open,close,rean,write表示只跟蹤這四個系統調用.默認的為set=all.
-e trace=file
只跟蹤有關文件操作的系統調用.
-e trace=process
只跟蹤有關進程控制的系統調用.
-e trace=network
跟蹤與網絡有關的所有系統調用.
-e strace=signal
跟蹤所有與系統信號有關的 系統調用
-e trace=ipc
跟蹤所有與進程通訊有關的系統調用
-e abbrev=set
設定 strace輸出的系統調用的結果集.-v 等與 abbrev=none.默認為abbrev=all.
-e raw=set
將指 定的系統調用的參數以十六進制顯示.
-e signal=set
指定跟蹤的系統信號.默認為all.如 signal=!SIGIO(或者signal=!io),表示不跟蹤SIGIO信號.
-e read=set
輸出從指定文件中讀出 的數據.例如:
-e read=3,5
-e write=set
輸出寫入到指定文件中的數據.
-o filename
將strace的輸出寫入文件filename
-p pid
跟蹤指定的進程pid.
-s strsize
指定輸出的字符串的最大長度.默認為32.文件名一直全部輸出.
-u username
以username 的UID和GID執行被跟蹤的命令

strace 通用的完整用法:

strace -o output.txt -T -tt -e trace=all -p 10423
上面的含義是 跟蹤28979進程的所有系統調用(-e trace=all),并統計系統調用的花費時間,以及開始時間(并以可視化的時分秒格式顯示),最后將記錄結果存在
output.txt文件里面。

限制strace只跟蹤特定的系統調用:

如果你已經知道你要找什么,你可以讓strace只跟蹤一些類型的系統調用。例如,在nginx執行程序時,你需要監視的系統調用epoll_wait。

讓strace只記錄epoll_wait的調用用這個命令:

strace -f -o epoll-strace.txt -e epoll_wait -p 10423

命令strace跟蹤的是系統調用,對于nginx本身的函數調用關系無法給出更為明朗的信息,如果我們發現nginx當前運行不正常,想知道nginx當前內部到底在執行什么函數,

那么命令pstack就是一個非常方便實用的工具。pstack的使用也非常簡單,后面跟進程id即可,比如在無客戶端請求的情況下,nginx阻塞在epoll_wait系統調用處,此時

利用pstack查看到的nginx函數調用堆棧關系如下:

從main()函數到epoll_wait()函數的調用關系一目了然,和在gdb內看到的堆棧信息一樣。我們可以利用此進行分析優化等。

?

除了 1,2 還有方法 加樁調試等方法在此不再敘述。以后有機會可以介紹下特殊應用邏輯的調試。

總結

以上是生活随笔為你收集整理的nginx源码分析--使用GDB调试的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。