GDB调试基础操作详解【GDB调试】
- 什么是bug
- 什么是調試
- 什么是調試器
- 注意
- 啟動調試與程序執行
- 啟動調試并傳遞啟動參數
- 方式一:啟動gdb調試時添加參數
- 方式二:啟動gdb調試之后執行r之前設置參數
- 方式三:啟動gdb調試之后執行r時設置參數
- 附加到進程進行調試(調試正在運行的程序)
- 方式一:gdb attach [pid]
- 方式二:gdb --pid [pid]
- 開始執行
- 逐過程執行
- 逐語句執行
- 繼續執行
- 退出函數
- 退出調試
- detach(分離)
- q (退出)
- 斷點管理
- 在源碼某一行設置斷點
- 為函數設置斷點
- 為滿足正則表達式的函數設置斷點
- 設置條件斷點
- 設置臨時斷點
- 查看所有斷點
- 查看指定斷點
- 禁用斷點
- 啟用斷點
- 刪除指定斷點
- 刪除所有斷點
- 變量的查看與修改
- 查看函數所有參數
- 查看變量的值
- 設置字符串顯示格式
- 設置結構體顯示格式
- 設置數組顯示規則
- gdb內嵌操作
- sizeof
- strlen
- strcmp
- strcpy
- 修改變量
- 修改基本變量
- 修改字符串
- 修改結構體
- 內存的查看與修改
- 查看內存
- 查看第一個內存地址的地址及對應的值
- 查看從該地址開始的[數字]個字節的值
- 查看字符串地址對應的字符串
- 顯示從該字符串地址開始的[數字]個字節的值
- 顯示結構體[數字]個字節體在內存中的值
- 修改內存
- 寄存器的查看與修改
- 查看寄存器
- 函數參數個數 <= 6 個通過寄存器傳遞
- 函數參數個數 > 6 個通過函數棧傳遞
- 查看所有通用寄存器
- 查看所有寄存器
- 查看一個寄存器
- 修改寄存器
- 查看源碼對應的反匯編地址
- 改變程序執行流程
- 源代碼的管理、查看、搜索
- 顯示源代碼
- 向后顯示源代碼
- 向前顯示源代碼
- 顯示指定函數的源代碼
- 顯示指定類中指定函數的源代碼
- 顯示指定行的源代碼
- 設置顯示行數
- 搜索源代碼
- search 正則表達式
- forward-search 正則表達式
- reverse-search 正則表達式
- 查找源代碼的路徑
- 函數調用棧管理
- 查看棧回溯信息
- 切換棧幀
- 查看棧幀信息
什么是bug
現在指的是硬件或軟件中的故障、缺陷、錯誤等。
什么是調試
從代碼中去除bug。
什么是調試器
附加到程序,幫助審查代碼找到bug的工具。
注意
gdb調試程序,使用 makefile 編譯時需要在 CFLAGS 加上 -g 參數。
編譯完成之后會攜帶程序的調試信息,方便調試(同時程序也會變大很多)。
gdb開始調試程序之后有 reading symbols from [可執行程序名]
表示編譯之后的程序帶有調試信息,可以很方便進行調試。
啟動調試與程序執行
啟動調試并傳遞啟動參數
方式一:啟動gdb調試時添加參數
命令:gdb --args [應用程序名] [啟動參數]
舉例:gdb --args section1 1 2 "3 4"
方式二:啟動gdb調試之后執行r之前設置參數
命令:set args [啟動參數]
舉例:set args 1 2 "3 4"
方式三:啟動gdb調試之后執行r時設置參數
命令:r [啟動參數]
舉例:r 1 2 "3 4"
附加到進程進行調試(調試正在運行的程序)
方式一:gdb attach [pid]
舉例:gdb attach 198237
調試過程中,程序退出調試也會自動結束。
方式二:gdb --pid [pid]
舉例:gdb --pid 198237
調試過程中,程序退出調試也會自動結束。
開始執行
命令:r
開始執行程序,運行到第一個斷點中斷。
如果沒有設置斷點,程序會直接執行結束。
逐過程執行
命令:n
單步執行,遇到函數跳過函數。
逐語句執行
命令:s
單步執行,遇到函數進入到函數,停留到函數的第1行。
如果沒有當前執行沒有函數,則和 n 效果相同。
繼續執行
命令:c
繼續執行,直到遇到下一個斷點。
退出函數
命令:finish
如果當前執行在函數中,執行會退出當前函數,執行到調用當前函數的下一行。
退出調試
detach(分離)
從程序分離,退出調試之后對于正在執行的程序無影響。
調試正在運行的程序:(對于調試的程序運行無影響)
①:attach進來調試。
②:detach分離退出調試。
q (退出)
命令:q
會提示:退出調試程序將會被強制退出。
斷點管理
在源碼某一行設置斷點
命令:b [文件名]:[行號]
舉例:b main.cpp:38
在 main.cpp 文件的 38行設置斷點。
為函數設置斷點
命令:b [函數名]
舉例:b test_fun
在所有同名函數的第一行都設置斷點。
為滿足正則表達式的函數設置斷點
命令:rb [正則表達式]
舉例:rb work
為每個帶有work的函數都設置斷點。
設置條件斷點
命令:b [文件名]:[行號] [條件]
舉例:b main.cpp:14 if i==90 設置在main.cpp 14行,當i為90時,滿足條件設置斷點。
滿足條件設置斷點。
設置臨時斷點
命令:tb [文件名]:[行號]
舉例:tb main.cpp:14 在main.cpp 14行設置一個臨時斷點。
臨時斷點只會命中一次,一旦中斷之后,后面不會再中斷停下來。(即使是在循環中。)
中斷一次之后自動刪除。
查看所有斷點
命令:i b
查看所有斷點信息。
查看指定斷點
命令:i b 2
查看 2 號斷點的詳細信息。
禁用斷點
命令:disable [斷點編號]
舉例:disable 1
斷點存在,但是不會在該斷點命中停止。
啟用斷點
命令:enable [斷點編號]
舉例:enable 1
啟用被禁用的斷點,使程序運行到該斷點時命中停止。
刪除指定斷點
命令:delete [斷點編號]
舉例:delete 1
刪除斷點編號為 1 的斷點。
刪除所有斷點
命令:delete
刪除所有斷點。
變量的查看與修改
查看函數所有參數
命令:info args
查看變量的值
命令:p [變量名]
變量名可以是:基本類型變量、字符串、結構體、數組等。
通過字符串地址查看字符串:
命令:p (char *)[十六進制地址]
舉例:p (char *)0x555555556005
查看字符串變量的地址和字符串。
設置字符串顯示格式
命令:set print null-stop
查看時,字符串不顯示后面的\0
設置結構體顯示格式
命令:set print pretty
結構體按照定義的方式顯示,一行一個元素。
設置數組顯示規則
命令:set print array on
類似結構體按照定義的方式顯示,一行一個元素。
gdb內嵌操作
sizeof
命令:p sizeof(int)
查看 int 類型所占字節數。
test 為結構體變量。
命令:p sizeof(test)
查看結構體 test所占字節數。
strlen
name 為字符串名稱。
命令:p strlen(name)
查看字符串長度。
strcmp
name1和name2為字符串名稱
命令:p strcmp(name1, name2)
比較兩個字符串的大小。
strcpy
name是結構體p的數據成員。
命令:p strcpy(p.name, "Soft")
字符串拷貝。
修改變量
通過修改變量改變程序運行的邏輯,按照我們期望的邏輯運行。
修改基本變量
i 為定義的臨時變量。
命令:p i=5
將 i 的值改為 5。
修改字符串
name 為字符串名稱。
命令:p name="Simple"
修改結構體
age為test結構體成員。
命令:p test.age = 25
內存的查看與修改
查看內存
命令:x /選項 [任意內存地址]
查看第一個內存地址的地址及對應的值
命令: x [內存地址]
舉例:x 0x7fffffffe334
不指定選項只顯示第一個內存地址的地址及對應的值。
查看從該地址開始的[數字]個字節的值
命令:x /[數字]b [內存地址]
舉例:x /4b 0x7fffffffe334 顯示從 0x7fffffffe334 地址開始的4個字節數據。
查看字符串地址對應的字符串
命令:x /s [字符串名稱]
舉例:x /s test_str
字符串名稱本身就是字符串的地址。
顯示從該字符串地址開始的[數字]個字節的值
命令:x /10d [字符串名稱]
舉例:x /10d test_str
顯示從字符串開始地址開始10個字節的值。
顯示結構體[數字]個字節體在內存中的值
命令:x/20b &[結構體變量名稱]
舉例:x/20b &test
顯示結構體20個字節體在內存中的值。
修改內存
命令:set {[強制轉換的類型]} & [變量名] = [修改后的值]
舉例:set {int} &test.gender = 110
將 test.gender 修改為 強制轉換為int 類型的 100。
寄存器的查看與修改
沒有調試符號、程序崩潰內存遭到破壞或者已經發布的程序,程序的運行狀態和內存中的內容很難查看。
程序運行時,很多數據存儲在寄存器中,函數的參數也是通過寄存器傳遞。
查看寄存器
函數參數個數 <= 6 個通過寄存器傳遞
寄存器 函數參數 rdi 第一個參數 rsi 第二個參數 rdx 第三個參數 rcx 第四個參數 r8 第五個參數 r 第六個參數函數參數個數 > 6 個通過函數棧傳遞
查看所有通用寄存器
命令: i registers
查看所有寄存器
命令: i all-registers
查看一個寄存器
命令:i r [寄存器名字]
舉例:i r rdi
修改寄存器
查看源碼對應的反匯編地址
命令:info line [源代碼行數]
顯示源碼行數對應指令的開始地址和結束地址。
改變程序執行流程
pc/rip寄存器:保存程序下一條要執行的命令,通過修改pc寄存器來改變程序執行的流程。
命令:
set var $pc=[開始地址] [開始地址是反匯編的地址,不是源代碼的地址] set var $rip=[開始地址] [開始地址是反匯編的地址,不是源代碼的地址] p $rip=[開始地址] [開始地址是反匯編的地址,不是源代碼的地址]源代碼的管理、查看、搜索
顯示源代碼
命令:l
默認顯示10行代碼,當前執行行在第6行。
向后顯示源代碼
命令:l
已經通過 l 命令顯示10行源代碼之后,再執行 l 向后顯示10行源代碼。
向前顯示源代碼
命令:l -
已經通過 l 命令顯示10行源代碼之后,再執行 l - 向后10行顯示源代碼。
顯示指定函數的源代碼
命令:l [函數名]
舉例:l test_fun
顯示函數代碼,函數定義頭在第6行顯示。
如果有多個重名函數定義,則會顯示所有重名函數。
顯示指定類中指定函數的源代碼
命令:l [類名]::[函數名]
舉例: l test_c::test_member
命令:l [文件名]:[函數名]
舉例: l main.cpp:test_member
顯示指定行的源代碼
命令:l [文件名]:[行號]
舉例:l main.cpp:10
顯示 main.cpp 文件第 10 行源代碼。
設置顯示行數
命令:set listsize [行數]
舉例:set listsize 5
舉例:set listsize 15
搜索源代碼
search 正則表達式
命令:search [模式匹配字段]
從當前代碼行向后查找所有和字段匹配的源代碼位置。
舉例:search test
從當前代碼行向后查找所有和 test 有關的源代碼。
開始執行直接找到第一個匹配的位置,按 Enter 向后找到下一處,直到找到所有和字段匹配的代碼段。
forward-search 正則表達式
命令:forward-search [模式匹配字段]
和search功能相同。
reverse-search 正則表達式
命令:reverse-search [模式匹配字段]
從當前代碼行向前查找所有和字段匹配的源代碼位置。
舉例:reverse-search test
從當前代碼行向后查找所有和 test 有關的源代碼。
開始執行直接找到第一個匹配的位置,按 Enter 向前找到下一處,直到找到所有和字段匹配的代碼段。
查找源代碼的路徑
命令:show directories
查找到兩個路徑:
①:程序所在目錄。
②:程序運行目錄。
如果源文件所在路徑無法找到,需要添加源文件搜索路徑。
命令:directory [源文件所在路徑]
舉例: directory source2/
將 source2/ 目錄添加到查找源代碼時的源文件搜索路徑。
函數調用棧管理
棧幀:程序進行函數調用時的調用信息,包括調用參數,局部變量,寄存器等信息。
所有棧幀組成的信息稱為調用棧。
查看棧回溯信息
命令:bt
0 號棧幀在棧頂,表示當前正在執行的函數。
切換棧幀
命令:f n
舉例:f 3
切換到 3 號棧幀。
命令:f [棧幀地址]
舉例:f 0x7fffffffe2f0
切換到棧幀地址為 0x7fffffffe2f0 對應的棧幀。
切換之后可以直接通過命令查看對應該函數參數和局部變量等信息。
查看棧幀信息
命令:info f n
舉例:info f 0
查看0號棧幀的詳細信息。
包括:棧幀地址,rip寄存器,參數信息。局部變量等信息。
總結
以上是生活随笔為你收集整理的GDB调试基础操作详解【GDB调试】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: GDB调试:观察点(数据断点)【GDB调
- 下一篇: core dump 崩溃分析