緣起
- 雖然豆瓣上老早就標註為想看了,但20190416偶然搜到的這本書,20190417開始看了40頁左右,7個Hack,以目前的狀況要看10個才能第1遍擼完。
內容
chap1 熱身準備 19/419
Hack1、除錯是什麼
Hack2、Debug hacks的地圖 22/419
- 程式異常結束
- 程式不結束
strace
命令基本沒怎麼用過呢,soft lookup也沒有聽過
Hack3、除錯的心得 24/419
- 復現之前
- 復現之後
- 確認現象
- 確認復現率和時間
- 分析
- 找不出原因
- 作者把鍋甩給硬體,哈哈---lionel
- 找以前的同類bug
這部分內容讓我想到了,吳軍說的專業和業餘的區別。
chap2 除錯前的必知必會 31/419
Hack4、獲取程式的核心轉儲 31/419
- 啟用核心轉儲
- 啟用
ulimit -c unlimted
gdb -c core.* ./a.out
//core檔案 程式gdb l 5
--這個可以看到檔案的第幾行?在除錯core的時候?
- 啟用
- 在專用目錄中生成核心轉儲
cat /etc/sysctl.conf
修改kernel.core_pattern的值sysctrl -p
- kernel.core_pattern中可設定的格式符
- 使用使用者模式輔助程式自助壓縮核心轉儲檔案
exec gzip ->
- lionel,這個理解了,還沒好好看呢
- 啟用整個系統的核心轉儲功能
- 34/419
Hack5、偵錯程式的基本使用方法(之一) 36/419
- 準備
gcc -Wall -02 -g 原始檔
- Makefile中指定
CFLAGS = -Wall -02 -g
- 使用configure指令碼生成Makefile,
./configure CFLAGS="-Wall -02 -g"
- 構建方法通常會寫在INSTALL、README等檔案中。
- 啟動
$gdb 可執行檔名
- 設定斷點
b file.c :110
// 通過指定檔名和行號,我第一次用時,不知道- break +偏移量 【暫停位置往後3行】這2個沒用過
- break -偏移量
- break *地址
b
後面啥也不加,就會在下一行設定斷點
info break
用於檢視設定好的斷點
- 執行
run
可以簡寫成r
,然後加引數start
命令也可以? 我也用得極少
- 顯示棧幀
backtrace
簡寫bt
,別名還有where
和info stack
簡寫成info s
- 我主要用在除錯core的時候了
bt N
只顯示開頭N個幀;bt -N
只顯示最後N個的幀;bt full 3
從外向內顯示3個棧幀,及其區域性變數。 這個就沒用過
- 顯示變數
p 變數
- 顯示暫存器
info registers
簡稱info reg
p/格式 變數
- 暫存器可使用的格式
- 單步執行
next
即n
step
即s
,進入函式內部。書中寫錯了nexti
或stepi
逐條執行彙編指令
- 繼續執行
continue
簡寫為c
- 有種我之前不知道的,
c 5
表示5次遇到斷點不停止,第6次遇到斷點時才暫停執行。
- 監視點
watch <表示式>
這個使用得比較少
- 刪除斷點和監視點
delete <編號>
即d 2
或者d 2-10
- 其它斷點
- 改變變數的值
set variable <變數>=<表示式>
這個在我專案中,是有想過,但沒找到解決方案
- 生成核心轉儲檔案
generate-core-file
gcore
命令可以直接從命令列直接生成核心轉儲檔案。
Hack6、偵錯程式的基本使用方法(之二) 50/419
-
attach到程式
attach pid
上回看人家除錯的時候,就用了attach這個命令- 在gdb和程式分離時使用
detach
命令,這樣程式可以繼續執行 info proc
顯示程式資訊
-
條件斷點
break 斷點 if 條件
,舉例b iseq_compile if node==0
condition 斷點編號
-
反覆執行
ignore 斷點編號 次數
- finish命令執行完當前函式後暫停
- until命令執行完當前函式等程式碼塊後暫停,執行完迴圈後暫停
-
刪除斷點和禁用斷點
clear
刪除已定義的斷點disable
臨時禁用;enable
斷點重新啟用disable display 顯示編號
disable mem 記憶體區域
-
斷點命令
commads
可以定義在斷點中斷後自動執行的命令。
-
常用命令及省略形式(別名)
x
顯示記憶體內容info
顯示除錯物件的各種各樣的資訊list
顯示函式或行show
顯示GDB內部的功能、變數和選項
Hack7、偵錯程式的基本使用方法(之三) 57/419
- 值的歷史
- 最後的值可以用
p $
來訪問 show value
可以顯示歷史中的最後10個值。
- 最後的值可以用
- 變數
set $i=0
,隨意定義變數;p $i
- 命令歷史
show history
,命令歷史檔案們於./.gdb_history
- 初始化檔案(.gdbinit)
- 命令定義
Hack8、Intel架構的基本知識 63/419
- 位元組序
- 32位環境中的暫存器
- 64位環境中的暫存器
CPUID
指令可以檢視執行中的處理器支援的實體地址空間。
- 地址
- Linux採用(flat model)記憶體模型
- 還有一種是 分段式記憶體模型 (segment model)
- 資料型別
Hack9、除錯時必需的棧知識 70/419
- 0
- [sum.c]
- 函式呼叫和棧的關係
- 偵錯程式的backtrace
- 使用GDB操作棧幀
frame
命令檢視現在選擇的幀。- 選擇幀可以使用
up
和down
命令 i frame 1
用info命令的frame選項可以看到更詳細的棧幀資訊。
- 棧大小的限制
i proc mapping
Hack10、函式呼叫時的引數傳遞方法(x86_64篇) 79/419
- 函式引數與除錯
- 通過GDB確認
- x86_64下的呼叫
Hack11、函式呼叫時的引數傳遞方法(i386篇) 84/419
- i386下的函式呼叫
- i386中的暫存器呼叫
- gcc在函式宣告中新增
__attribute__((regparm(3)))
這種語法格式見過,好像會在main之前執行
- gcc在函式宣告中新增
Hack12、函式呼叫時的引數傳遞方法(C++篇) 87/419
- C++語言的函式呼叫
nm
命令
- 在x86_64中檢視引數
- 在i386中檢視引數
Hack13、怎樣學習組合語言 90/419
- 檢視反彙編的輸出結果
- [assemble.c]
gcc -Wall -00 assemble.c -o assemble
objdump -d --no-show-raw-insn assemble
- 設定變數的值:movl指令
- 用if語句比較變數:cmpl指令
- while語句的彙編程式碼
- 函式呼叫:call指令
- 函式指標調
- 陣列操作:movzbl指令
- 返回值設定
Hack14、從彙編程式碼查詢相應的原始碼 95/419
- 用crash反彙編
crash /boot/vmlinux-2.6.19
dis journal_commit_transaction
- 根據前後的資訊確定原始碼範圍
- [fs/jbd/commit.c]
- 確認暫存器偏移量和結構的成員
crash> struct -o transacton_t
carsh> mod -s jbd
- 確認原始碼檔名和行號
crash> dis -l journal_commit_transaction
chap3 核心除錯的準備 105/419
chap4 應用程式除錯實踐 157/419
Hack26、發生SIGSEGV,應用程式異常停止 157/419
- 0
bt 10
,如果某個地址被呼叫多次,可以懷疑,遞迴函式呼叫產生棧溢位。
- 原始碼層面的除錯
info signal
檢視gdb能夠處理的訊號列表up
命令,將棧幀向上回溯一層。
- 棧溢位導致SIGSEGV的應對方法
- 為捕獲棧溢位,需要使用備用棧,相應函式是sigaltstack(2)
Hack27、backtrace無法正確顯示 165/419
- 概要
- 偵錯程式的backtrace並非萬能鑰匙。
- 問題內容
- 某個執行緒間通訊的程式中含有bug,生成了core。
- 檢查backtrace
- 執行
bt
看不出啥有用資訊;似乎是nanosleep()
執行過程中產生了SIGSEGV。
- 執行
- 什麼是backtrace
- 偵錯程式的backtrace是根據棧裡儲存的函式返回地址來顯示的,如果bt沒用,可以理解為棧被破壞了。
- 檢視暫存器和棧
info reg
x/i 0x3b4869ac80
Hack28、陣列非法訪問導致記憶體破壞 169/419
- 陣列的錯誤操作
- 可懷疑是緩衝區溢位的情況
- 即使指定了編譯選項-g,利用GDB讀入core並顯示backtrace之後,棧幀中還是沒有顯示符號名。通常,指定-g選項後,各個棧幀都應顯示出函式名。
- 執行地址的改變
- 第1類:直接指定地址並呼叫
- 第2類:指定一塊記憶體區域,儲存了跳轉地址
- 第3類:執行ret命令,用於函式結束時返回撥用者函式
- 確定破壞跳轉地址值的位置(棧破壞)
x/30c $esp-15
p (char*)$esp-20
這兩個命令是啥意思?
- 確定破壞跳轉地址值的位置(GOT破壞)
disas 0x080483ca
// 反彙編objdump -s bufov2
Hack29、利用監視點檢測非法記憶體訪問 175/419
- 監視點何時有效?
- 監視點的設定方法
watch *0x80495a8
- 尋找問題原因
p $pc
disas
Hack30、malloc()和free()發生故障 178/419
- 錯誤使用記憶體相關庫函式引起的bug
- 利用MALLOC_CHECK_進行除錯
env MALLOC_CHECK_=1 ./membug
Hack31、應用程式停止響應(死鎖篇)181/419
- 死鎖的例子
- [astall.c]
- 停止響應時的解決方法 沒遇到過,得實踐下lionel
ps ax -L | grep astall
// -L顯示所有執行緒gdb -p
- 使用多個mutex時的除錯方法
Hack32、應用程式停止響應(死迴圈篇)186/419
- 編譯tcpdump
- 檢查包內容
- 確認不同選項下行為是否有變化
- 選擇斷點
- 單步執行確認現象
- SCTP包結構
- 確認更高的版本
chap5 實踐核心除錯 195/419
chap6 高手們的除錯技術 277/419
收穫
- 20190417看了Hack7,有一些小點不會,但80%都是用過的,後面專案中多實踐。最好自已能寫個例子,用於驗證自已不知道的命令。
- 20190418看了chap4,也是7個Hack,差不多40頁。停止響應的確認,以及watch這種用法在專案中沒怎麼用過
- 20190418又看了7個Hack,就是chap2的Hack8-14,基本上就是過一遍,沒有真的懂,前置知識可能就吸收了40%的知識。