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

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > linux >内容正文

linux

GDB调试教程:1小时玩转Linux gdb命令

發(fā)布時(shí)間:2023/11/30 linux 52 豆豆
生活随笔 收集整理的這篇文章主要介紹了 GDB调试教程:1小时玩转Linux gdb命令 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

原文鏈接:http://c.biancheng.net/gdb/

GDB 入門(mén)教程

本教程以下面的代碼為例,在 Linux 系統(tǒng)下來(lái)講解 GBD 的調(diào)試流程:

int main (void) {unsigned long long int n, sum;n = 1;sum = 0;while (n <= 100){sum = sum + n;n = n + 1;}return 0; }

將代碼保存到 ~/demo/main.c,~表示當(dāng)前用戶的主目錄,也即 home 目錄。

首先我們使用 GCC 來(lái)編譯 main.c,編譯的時(shí)候使用-g選項(xiàng),它的目的是向可執(zhí)行程序中加入調(diào)試信息,包括源代碼、符號(hào)表等,GDB 需要這些額外的信息來(lái)完成調(diào)試工作

此外還建議關(guān)閉編譯器的程序優(yōu)化選項(xiàng)。編譯器的程序優(yōu)化選項(xiàng)一般有五個(gè)級(jí)別,從 O0 ~ O4, O0 表示不優(yōu)化,從 O1 ~ O4 優(yōu)化級(jí)別越來(lái)越高,O4 最高。這樣做的目的是為了調(diào)試的時(shí)候,符號(hào)文件顯示的調(diào)試變量等能與源代碼完全對(duì)應(yīng)起來(lái)。

使用 GCC 編譯源文件:

$ cd demo $ gcc main.c -o main.out -g

打開(kāi) demo 文件夾,發(fā)現(xiàn)多了一個(gè) mian.out,說(shuō)明編譯成功。

1) 啟動(dòng) GDB 調(diào)試器

接下來(lái)啟動(dòng) GDB 并調(diào)試 main.out:

$ gdb main.out -silent Reading symbols from /home/mozhiyan/demo/main.out...done.

選項(xiàng)-silent用于屏蔽 GDB 的前導(dǎo)信息,否則它會(huì)在屏幕上打印一堆免責(zé)條款。

啟動(dòng) GDB 后,它輸出的信息表明已經(jīng)讀入了 mian.out 的符號(hào)表。接下來(lái),GDB 會(huì)顯示自己的提示符(gbd),提示并等待你輸入調(diào)試命令。

2) gdb -b 選項(xiàng):設(shè)置斷點(diǎn)

調(diào)試一個(gè)程序的時(shí)候,應(yīng)該在我們關(guān)注的地方,或者在故障點(diǎn)的前邊設(shè)置一個(gè)斷點(diǎn)(Breakpoint),讓程序執(zhí)行到這里停下來(lái),這樣我們就可以慢慢地用別的調(diào)試命令進(jìn)行觀察。

在 GDB 中,設(shè)置斷點(diǎn)的方法很多,包括在指定的內(nèi)存地址處設(shè)置斷點(diǎn)、在源代碼的某一行設(shè)置斷點(diǎn),或者在某個(gè)函數(shù)的入口處設(shè)置斷點(diǎn),等等。設(shè)置斷點(diǎn)的命令是b或者break,在這里我 們是將 main 函數(shù)的入口處作為斷點(diǎn):

(gdb) b main Breakpoint 1 at 0x4004f4: file main.c, line 5.

b 命令在執(zhí)行后返回了斷點(diǎn)的具體信息,也就是說(shuō),斷點(diǎn)(main 函數(shù)的入口位置)的內(nèi)存地址為 0x4004f4,對(duì)應(yīng)于源文件的第 5 行(也就是說(shuō),main 函數(shù)位于源文件的第 5 行)。

如果我們用內(nèi)存地址的方式來(lái)設(shè)置這個(gè)斷點(diǎn),則可以是:

b * 0x4004f4

星號(hào)*意味著是以內(nèi)存地址作為斷點(diǎn)的。

如果用源代碼行的形式設(shè)置這個(gè)斷點(diǎn),則可以是

b 5

3) gdb -r 選項(xiàng):執(zhí)行程序

一旦設(shè)置了斷點(diǎn),下一步就是用r或者run命令執(zhí)行被調(diào)試的程序,執(zhí)行后會(huì)自動(dòng)在第一個(gè)斷點(diǎn)處停下來(lái):

Starting program: /home/mozhiyan/demo/main.out [New Thread 1500.0x1e34] [New Thread 1500.0x2fb8]Thread 1 hit Breakpoint 1, main () at main.c:5 5 n = 1;

在運(yùn)行了被調(diào)試的程序后,GDB 的輸出信息顯示程序己經(jīng)啟動(dòng),下一個(gè)將要執(zhí)行的語(yǔ)句是第 5 行的n = 1;。

注意,這條語(yǔ)句并沒(méi)有執(zhí)行,而僅僅是告訴你,再繼續(xù)執(zhí)行程序的話,執(zhí)行的語(yǔ)句會(huì)是它。

4) gdb -p 選項(xiàng):打印變量的值

在當(dāng)前位置,變量 n 和 sum 己經(jīng)分配,但并沒(méi)有開(kāi)始賦值。此時(shí),這兩個(gè)變量的值會(huì)是多少呢?我們可以使用p或者print命令來(lái)分別顯示:

(gdb) p n $1 = 24 (gdb) p sum $2 = 140737488347344

GDB 的 p 命令用于打印一個(gè)表達(dá)式的值,在這里是表達(dá)式 n 和 sum。

GDB 先計(jì)算表達(dá)式的值,并把它保存在一個(gè)存儲(chǔ)區(qū)中,存儲(chǔ)區(qū)的名字用$外加數(shù)字來(lái)表示,并且這個(gè)數(shù)字會(huì)隨著調(diào)試過(guò)程的進(jìn)行而不斷遞增(這意味著存儲(chǔ)區(qū)也是不斷開(kāi)辟的)。以上,第一個(gè) p 命令執(zhí)行后,GDB 的回應(yīng)是$1 = 16,意思是表達(dá)式 n 的值保存在 $1 中,其內(nèi)容為 16。

注意,在你的計(jì)算機(jī)上,變量 n 和 sum 的當(dāng)前值可能和這里顯示的不同。這很好理解,內(nèi)存是反復(fù)使用的,當(dāng)一個(gè)程序終止后,它占用的內(nèi)存會(huì)分配給其他程序使用;當(dāng)一個(gè)變量不再使用后,它占用的內(nèi)存也會(huì)重新分配,并成為另一個(gè)變量。因?yàn)樽兞?n 和 sum 剛剛分配,還沒(méi)有往里面保存任何數(shù)值,故它們的內(nèi)容是隨機(jī)的,是其他程序或者變量用過(guò)的垃圾值。

順便說(shuō)一下,既然 $1 是 GDB 用于保存計(jì)算結(jié)果的內(nèi)部存儲(chǔ)區(qū)的名字,那么我們也可以用 p 命令來(lái)打印它:

(gdb) p $1 $3 = 24

5) gdb -n 選項(xiàng):單步調(diào)試

下面,我們將通過(guò)單步執(zhí)行程序,來(lái)看一看變量 n 和 sum 賦值后的值。調(diào)試命令n或者next用于繼續(xù)執(zhí)行源文件中的下一行。

(gdb) n 6 sum = 0;

執(zhí)行 n 命令后,實(shí)際執(zhí)行的是第 5 行n = 1;,GDB 顯示下一個(gè)即將執(zhí)行的源代碼行,也就是第 6 行的sum = 0;。

因?yàn)榇藭r(shí)己經(jīng)往變量 n 寫(xiě)入了 1,所以我們可繼續(xù)用 p 命令來(lái)觀察它現(xiàn)在的存儲(chǔ)值:

(gdb) p n $4 = 1

顯然,經(jīng)賦值后,變量 n 的值己經(jīng)變成 1。

繼續(xù)執(zhí)行下一條指令,實(shí)際執(zhí)行的是第 6 行sum = 0。執(zhí)行后,GDB 停下并顯示下一條即將執(zhí)行的源代碼行,也即第 8 行的while (n <= 100),第 7 行為空行,所以直接跳過(guò)了:

(gdb) n 8 while (n <= 100)

剛才執(zhí)行的語(yǔ)句是往變量 sum 保存數(shù)值 0,故我們可以再次用 p 命令來(lái)觀察變量 sum 現(xiàn)在的存儲(chǔ)值,可發(fā)現(xiàn)它己經(jīng)變成 0:

(gdb) p sum $5 = 0

繼續(xù)用 n 命令執(zhí)行下一個(gè)源代碼行,則將計(jì)算 while 語(yǔ)句的控制表達(dá)式,并根據(jù)該表達(dá)式的值決定是否進(jìn)入循環(huán)體,執(zhí)行后 GDB? 顯示下一條即將執(zhí)行的源代碼行是第 10 行:

(gdb) n 10 sum = sum + n;

進(jìn)入循環(huán)體之后,我們想再看看變量 n 和 sum 的當(dāng)前值。但這次使用 p 命令的方法不一樣,這次是用花括號(hào)將表達(dá)式 n 和 sum 圍住以形成一個(gè)集合。GDB 允許用這種方式來(lái)一次性地打印多個(gè)表達(dá)式的值:

(gdb) p {n, sum} $6 = {1, 0}

顯然,變量 n 和 sum 此時(shí)的值依然分別為 1 和 0。

繼續(xù)用 n 命令執(zhí)行第 10 行,執(zhí)行后 GDB 停留在即將執(zhí)行的第 11 行:

(gdb) n 11 n = n + 1;

注意,第 10 行己經(jīng)執(zhí)行完畢,但第 11 行還沒(méi)有執(zhí)行。猜猜看,變量 n 和 sum 此時(shí)的值是多少?猜測(cè)之后,用 p 命令看看結(jié)果是否如你所想:

(gdb) p {n, sum} $7 = {1, 1}

繼續(xù)用 n 命令執(zhí)行下一個(gè)源代碼行,這將執(zhí)行第 11 行的n = n + 1;,執(zhí)行后控制又回到了循環(huán)的起始處,也即第 8 行:

(gdb) n 8 while (n <= 100)

此時(shí),變量 n 和 sum 的值各自會(huì)是多少?使用 p 命令打印一下就知道了:

(gdb) p {n, sum} $8 = {2, 1}

因?yàn)楝F(xiàn)在處于一個(gè)循環(huán)體內(nèi),如果繼續(xù)用 n 命令往下執(zhí)行,則其過(guò)程與前面相比大同小異。前面己經(jīng)循環(huán)過(guò)一次,本次循環(huán)完整的調(diào)試過(guò)程如下:

(gdb) n 10 sum = sum + n; (gdb) n 11 n = n + 1; (gdb) n 8 while (n <= 100) (gdb) p {n, sum} $9 = {3, 3}

顯然,第二次循環(huán)過(guò)后,變量 n 的值為 3,變量 sum 的值也是 3。

你可能己經(jīng)發(fā)現(xiàn)了,我們現(xiàn)在進(jìn)退維谷:如果繼續(xù)用 n 命令執(zhí)行,則將陷入循環(huán),直到變量 n 的值等于 101。好在這也算不上什么大的問(wèn)題,我們可以在循環(huán)語(yǔ)句的后面設(shè)置斷點(diǎn),然后命令程序一直執(zhí)行,直至到達(dá)這個(gè)斷點(diǎn)。

6) gdb -l 選項(xiàng):列出源文件內(nèi)容

為了搞清楚 while 語(yǔ)句的下一條語(yǔ)句的行號(hào),我們需要列出源文件的內(nèi)容,這需要使用l或者list命令:

(gdb) l 3 unsigned long long int n, sum; 4 5 n = 1; 6 sum = 0; 7 8 while (n <= 100) 9 { 10 sum = sum + n; 11 n = n + 1; 12 }

l 命令默認(rèn)每次顯示 10 行源代碼,但我們關(guān)心的那一行顯然還沒(méi)有出來(lái)。為此,可繼續(xù)使用 l 命令來(lái)顯示后面的行:

(gdb) l 13 14 return 0; 15 }

好了,我們己經(jīng)知道 while 語(yǔ)句之后是 return 語(yǔ)句,它的行號(hào)是 14,現(xiàn)在就可以用 b 命令設(shè)置一個(gè)新的斷點(diǎn):

(gdb) b 14 Breakpoint 2 at 0x40051a: file main.c, line 14.

7) gdb -c 選項(xiàng):繼續(xù)執(zhí)行程序

現(xiàn)在,可以用一個(gè)新的命令c或者continue來(lái)持續(xù)執(zhí)行程序,直至遇到斷點(diǎn)或者程序結(jié)束。因?yàn)榧航?jīng)設(shè)置斷點(diǎn),故程序?qū)⒊掷m(xù)執(zhí)行,在第 14 行處停下:

(gdb) c Continuing.Breakpoint 2, main () at main.c:14 14 return 0;

非常好,既然己經(jīng)退出了 while 循環(huán),說(shuō)明累加過(guò)程己經(jīng)成功結(jié)束,變量 sum 的值就是累加結(jié)果。我們來(lái)看看它到底是多少:

(gdb) p {n, sum} $10 = {101, 5050}

顯然,變量 n 的當(dāng)前值是 101,變量 sum 的當(dāng)前值是 5050,和數(shù)學(xué)計(jì)算的結(jié)果一模 一樣。

8) gdb -q 選項(xiàng):退出調(diào)試

本次調(diào)試即將結(jié)束,我們可以先用 c 命令讓程序“跑完全程”,然后再用q或者quit結(jié)束本次調(diào)試工作,這將使得調(diào)試器 GDB 結(jié)束運(yùn)行并返回到操作系統(tǒng):

(gdb) c Continuing. [Inferior 1 (process 2814) exited normally] (gdb) q [c.biancheng.net demo]$

好了,GDB 調(diào)試過(guò)程到此結(jié)束。

總結(jié)

GDB 是非常強(qiáng)大的工具,它的用法可以寫(xiě)一本厚厚的書(shū),上述 GDB 調(diào)試教程雖然是蜻蜓點(diǎn)水、走馬觀花,但對(duì)于初學(xué)者來(lái)說(shuō)已經(jīng)足夠了,大家應(yīng)該能夠發(fā)現(xiàn) 99% 的邏輯錯(cuò)誤了。

總結(jié)

以上是生活随笔為你收集整理的GDB调试教程:1小时玩转Linux gdb命令的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。