《Debug Hacks》-看了21個Hack

im天行發表於2019-04-18

緣起

  • 雖然豆瓣上老早就標註為想看了,但20190416偶然搜到的這本書,20190417開始看了40頁左右,7個Hack,以目前的狀況要看10個才能第1遍擼完。

內容

chap1 熱身準備 19/419

Hack1、除錯是什麼

Hack2、Debug hacks的地圖 22/419

Hack3、除錯的心得 24/419

  • 復現之前
  • 復現之後
    • 確認現象
    • 確認復現率和時間
  • 分析
  • 找不出原因
    • 作者把鍋甩給硬體,哈哈---lionel
    • 找以前的同類bug

這部分內容讓我想到了,吳軍說的專業和業餘的區別

chap2 除錯前的必知必會 31/419

Hack4、獲取程式的核心轉儲 31/419

  • 啟用核心轉儲
    • 啟用 ulimit -c unlimted
    • gdb -c core.* ./a.out //core檔案 程式
    • gdb l 5--這個可以看到檔案的第幾行?在除錯core的時候?
  • 在專用目錄中生成核心轉儲
  • 使用使用者模式輔助程式自助壓縮核心轉儲檔案
    • 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,別名還有whereinfo stack簡寫成info s
    • 我主要用在除錯core的時候了
    • bt N 只顯示開頭N個幀;bt -N只顯示最後N個的幀;
    • bt full 3從外向內顯示3個棧幀,及其區域性變數。 這個就沒用過
  • 顯示變數
    • p 變數
  • 顯示暫存器
    • info registers簡稱info reg
    • p/格式 變數
      • 暫存器可使用的格式
  • 單步執行
    • nextn
    • steps,進入函式內部。書中寫錯了
    • nextistepi逐條執行彙編指令
  • 繼續執行
    • 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命令檢視現在選擇的幀。
    • 選擇幀可以使用updown命令
    • 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之前執行

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%的知識。

相關文章