第1章 誰編寫軟件,誰製造bug(為什麼需要本書) 1
第2章 係統性調試方法 3
2.1 為什麼要遵循結構化的過程 3
2.2 充分利用機會 3
2.3 13條黃金規則 5
2.3.1 理解需求 5
2.3.2 製造失敗 6
2.3.3 簡化測試用例 6
2.3.4 讀取恰當的錯誤消息 6
2.3.5 檢查顯而易見的問題 6
2.3.6 從解釋中分離齣事實 7
2.3.7 分而治之 7
2.3.8 工具要與bug匹配 8
2.3.9 一次隻做一項更改 9
2.3.10 保持審計跟蹤 9
2.3.11 獲得全新觀點 9
2.3.12 bug不會自己修復 9
2.3.13 用迴歸測試來檢查bug修復 10
2.4 構建一個好的工具包 10
2.4.1 工具箱 11
.2.4.2 每天運行測試,防止齣現bug 11
2.5 認清敵人——遇到bug傢族 13
2.5.1 常見bug 13
2.5.2 偶發性bug 13
2.5.3 heisenbug 13
2.5.4 隱藏在bug背後的bug 14
2.5.5 秘密bug——調試與機密性 14
2.5.6 更多讀物 15
第3章 查找根源——源代碼調試器 17
3.1 可視化程序行為 17
3.2 準備簡單的可預測的示例 18
3.3 使調試器與程序一起運行 18
3.4 學習在程序崩潰時執行棧跟蹤 21
3.5 學習使用斷點 21
3.6 學習在程序中導航 22
3.7 學習檢查數據:變量和錶達式 22
3.8 一個簡單示例的調試會話 23
第4章 修復內存問題 27
4.1 c/c++中的內存管理——功能強大但很危險 27
4.1.1 內存泄漏 27
4.1.2 內存管理的錯誤使用 28
4.1.3 緩衝區溢齣 28
4.1.4 未初始化的內存bug 28
4.2 有效的內存調試器 28
4.3 示例1:檢測內存訪問錯誤 29
4.3.1 檢測無效的寫訪問 30
4.3.2 檢測對未初始化的內存的讀取操作 30
4.3.3 檢測內存泄漏 31
4.4 示例2:對內存分配/釋放的不完整調用 31
4.5 結閤使用內存調試器和源代碼測試器 33
4.6 減少乾擾,排查錯誤 33
4.7 何時使用內存調試器 34
4.8 約束 34
4.8.1 測試用例應該有很好的代碼覆蓋率 34
4.8.2 提供更多計算機資源 35
4.8.3 可能不支持多綫程 35
4.8.4 對非標準內存處理程序的支持 35
第5章 剖析內存的使用 37
5.1 基本策略——主要步驟 37
5.2 示例:分配數組 38
5.3 第1步:查找泄漏 38
5.4 第2步:設置期望值 38
5.5 第3步:測量內存使用 39
5.5.1 使用多個輸入 39
5.5.2 在固定時間間隔停止程序 39
5.5.3 用簡單工具測量內存使用 40
5.5.4 使用top 40
5.5.5 使用windows task manager 41
5.5.6 為testmalloc選擇相關輸入值 42
5.5.7 確定機器上的內存是如何被釋放的 42
5.5.8 使用內存剖析工具 43
5.6 第4步:查明大部分內存被哪些數據結構占用瞭 44
5.7 綜閤練習——genindex示例 45
5.7.1 核實沒有大的內存泄漏 46
5.7.2 估計內存使用 46
5.7.3 測量內存使用 46
5.7.4 查找使用內存的數據結構 47
第6章 解決性能問題 51
6.1 分步查找性能bug 51
6.1.1 執行前期分析 51
6.1.2 使用簡單的時間測量方法 52
6.1.3 創建測試用例 52
6.1.4 使測試用例具有可再現性 53
6.1.5 檢查程序的正確性 53
6.1.6 創建可擴展的測試用例 53
6.1.7 排除對測試用例的乾擾 54
6.1.8 用time命令測量時可能會發生錯誤和偏差 54
6.1.9 選擇一個能夠揭示運行時間瓶頸的測試用例 55
6.1.10 算法與實現之間的差異 56
6.2 使用剖析工具 58
6.2.1 不要編寫自己的剖析工具 58
6.2.2 剖析工具的工作原理 58
6.2.3 瞭解gprof 59
6.2.4 瞭解quantify 63
6.2.5 瞭解callgrind 64
6.2.6 瞭解vtune 66
6.3 分析i/o性能 68
第7章 調試並行程序 71
7.1 用c/c++編寫並行程序 71
7.2 調試競爭條件 72
7.2.1 使用基本調試器功能來查找競爭條件 73
7.2.2 使用日誌文件來查找競爭條件 74
7.3 調試死鎖 76
7.3.1 如何確定正在運行的是哪個綫程 77
7.3.2 分析程序的綫程 78
7.4 瞭解綫程分析工具 78
7.5 異步事件和中斷處理程序 80
第8章 查找環境和編譯器問題 83
8.1 環境變更——問題的根源 83
8.1.1 環境變量 83
8.1.2 本地安裝依賴 84
8.1.3 當前工作目錄依賴 84
8.1.4 進程id依賴 84
8.2 如何查看程序正在做什麼 84
8.2.1 用top來查看進程 84
8.2.2 用ps來查找應用程序的多個進程 85
8.2.3 使用/proc/[pid]來訪問進程 85
8.2.4 使用strace跟蹤對操作係統的調用 85
8.3 編譯器和調試器也有bug 87
8.3.1 編譯器bug 87
8.3.2 調試器和編譯器兼容性問題 88
第9章 處理鏈接問題 89
9.1 鏈接器的工作原理 89
9.2 構建並鏈接對象 89
9.3 解析未定義的符號 91
9.3.1 丟失鏈接器參數 91
9.3.2 搜索丟失的符號 91
9.3.3 鏈接順序問題 92
9.3.4 c++符號和名稱改編 93
9.3.5 符號的反改編 94
9.3.6 鏈接c和c++代碼 94
9.4 具有多個定義的符號 95
9.5 信號衝突 96
9.6 識彆編譯器和鏈接器版本不匹配 96
9.6.1 係統庫不匹配 97
9.6.2 對象文件不匹配 97
9.6.3 運行時崩潰 98
9.6.4 確定編譯器版本 98
9.7 解決動態鏈接問題 100
9.7.1 鏈接或載入dll 100
9.7.2 無法找到dll文件 101
9.7.3 分析載入器問題 102
9.7.4 在dll中設置斷點 103
9.7.5 提供dll問題的錯誤消息 104
第10章 高級調試 107
10.1 在c++函數、方法和操作符中設置斷點 107
10.2 在模闆化的函數和c++類中設置斷點 109
10.3 進入c++方法 110
10.3.1 用step-into命令進入到隱式函數中 112
10.3.2 用step-out命令跳過隱式函數 112
10.3.3 利用臨時斷點跳過隱式函數 113
10.3.4 從隱式函數調用返迴 113
10.4 條件斷點和斷點命令 114
10.5 調試靜態構造/析構函數 116
10.5.1 由靜態初始化程序的順序依賴性引起的bug 117
10.5.2 識彆靜態初始化程序的棧跟蹤 118
10.5.3 在靜態初始化之前連接調試器 118
10.6 使用觀察點 119
10.7 捕捉信號 120
10.8 捕獲異常 122
10.9 讀取棧跟蹤 124
10.9.1 帶調試信息編譯的源代碼的棧跟蹤 124
10.9.2 不帶調試信息編譯的源代碼的棧跟蹤 124
10.9.3 不帶任何調試信息的幀 125
10.9.4 實際工作中的棧跟蹤 125
10.9.5 改編後的函數名稱 126
10.9.6 被破壞的棧跟蹤 126
10.9.7 核心轉儲 127
10.10 操縱正在運行的程序 128
10.10.1 修改變量 130
10.10.2 調用函數 131
10.10.3 修改函數的返迴值 132
10.10.4 中止函數調用 132
10.10.5 跳過或重復執行個彆語句 133
10.10.6 輸齣和修改內存內容 133
10.11 在沒有調試信息時進行調試 135
10.11.1 從棧讀取函數參數 137
10.11.2 讀取局部/全局變量和用戶定義的數據類型 138
10.11.3 在源代碼中查找語句的大概位置 139
10.11.4 走查匯編代碼 140
第11章 編寫可調試的代碼 143
11.1 注釋的重要性 143
11.1.1 函數簽名的注釋 144
11.1.2 對摺中辦法的注釋 144
11.1.3 為不確定的代碼加注釋 144
11.2 采用一緻的編碼風格 144
11.2.1 仔細選擇名稱 145
11.2.2 不要使用“聰明過頭”的結構 145
11.2.3 不要壓縮代碼 145
11.2.4 為復雜錶達式使用臨時變量 145
11.3 避免使用預處理器宏 146
11.3.1 使用常量或枚舉來替代宏 146
11.3.2 使用函數來替代預處理器宏 148
11.3.3 調試預處理器輸齣 149
11.3.4 使用功能更強的預處理器 150
11.4 提供更多調試函數 151
11.4.1 顯示用戶定義的數據類型 151
11.4.2 自檢查代碼 152
11.4.3 為操作符創建一個函數,以便幫助調試 153
11.5 為事後調試做準備 153
第12章 靜態檢查的作用 155
12.1 使用編譯器作為調試工具 155
12.1.1 不要認為警告是無害的 156
12.1.2 使用多個編譯器來檢查代碼 158
12.2 使用lint 158
12.3 使用靜態分析工具 158
12.3.1 瞭解靜態檢查器 158
12.3.2 將靜態檢查器檢測到的錯誤減至(接近)零 160
12.3.3 完成代碼清理後重新運行所有測試用例 160
12.4 靜態分析的高級應用 161
第13章 結束語 163
附錄a 調試命令 165
附錄b 工具資源 167
附錄c 源代碼 179
參考文獻 189
· · · · · · (
收起)