#rpm -qa |grep gdb
下載:
安裝
#tar -zxvf
#./configure
#make
使用GDB
以彙編語言調試爲例
彙編語言實現CPUID指令
CPUID
cpuid是Intel Pentinum以上級CPU內置的一個指令(486級以下的CPU不支持),他用於識別某一類型的CPU,
它能返回CPU級別,型號,CPU步進以及CPU字串信息,從此命令也可以得到CPU的緩存和TLB信息
CPUID返回數據類型是在EAX寄存器裏定義的,而指令返回的數值則存儲在EAX,EBX,ECX和EDX寄存器中。
返回的信息分兩部分:基本信息與擴展信息。
在EAX輸入0-3參數時,它返回CPU基本信息;
而在EAX輸入0x8000000至ox800000x,他返回的是CPU擴展信息。擴展信息只包括在Pentinum4及以後的CPU上。
CPU級別 基本信息 擴展信息
486及以前的CPU 不可用 不可用
Pentium 0x1 不可用
Pentium Pro,Pentium 2 0x2 不可用
Pentium 3 0x3 不可用
Pentium 4 0x2 0x80000004
Xeon(至強) 0x2 0x80000004
代碼
cpuid.s
#cpuid.s Sample program to extract the processor Vendor ID
.section .data
output:
.ascii "The processor Vendor ID is 'xxxxxxxxxxxx'\n"
.section .text
.globl _start
_start:
movl $0, %eax
cpuid
movl $output, %edi
movl %ebx, 28(%edi)
movl %edx, 32(%edi)
movl %ecx, 36(%edi)
movl $4, %eax
movl $1, %ebx
movl $output, %ecx
movl $42, %edx
int $0x80
movl $1, %eax
movl $0, %ebx
int $0x80<strong></strong>
彙編
使用GNU彙編器
#as -o cpuid.o cpuid.s
使用GNU鏈接器
#ld -o cpuid cpuid.o
運行程序
#./cpuid
輸出
調試
爲了調試彙編語言程序,必須使用-gstabs參數重新彙編代碼
#as -gstabs -o cpuid.o cpuid.s
#ld -o cpuid cpuid.o
使用-gstabs參數在可執行文件中添加了附加信息,所以新產生的文件會大些
如果沒有必要不要使用調試信息
運行
在gdb內運行
#gdb cupid
GNU調試器啓動,把程序加載到內存,使用run命令(簡化r也可以)從gdb內運行程序
可見調試器內的運行和從命令行直接運行一樣
斷點
彙編語言中指定斷點時,必須指定對於最近的標籤的相對位置,上述代碼中只有一個標籤,所以每個斷點必須依據_start指定。
break(簡化的b)命令格式 break * label+offset
break 函數名
break 行號
break 文件名:行號
break 文件名:函數名
break +偏移量
break -偏移量
break *地址
label是被引用的源代碼中的標籤
offset是應該停止的地方距離標籤的行數
break * _start
*_start參數指定了斷點,該參數指定_start標籤後的第一條指令碼。
run或者(簡化的r)啓動程序,暫停在第一條指令碼處。
單步
使用next(簡化的n)或者step(簡化的s)命令單步調試
注意:s會步入調用的函數,類似於VS中的F11,而n類似於VS中的F10
每個next或者step命令執行下一行代碼
繼續運行
使用continue(或者c)按正常方式繼續運行,類似於VS中的F5
查看數據
info registers 查看所有寄存器的值
print (或者p) 顯示特定寄存器或者來自程序的變量值
p $eax 顯示寄存器的內容
p/格式 變量
格式
p/t 顯示爲2進制數
p/o 顯示爲8進制數
p/d 顯示爲10進制數
p/u 顯示爲無符號10進制數
p/x 顯示爲16進制數
p/a 地址
p/c 顯示爲字符
p/s 顯示爲字符串
p/f 浮點小數
p/i 顯示爲機器語言(僅在顯示內存的x命令中可用)
程序指針可以寫爲$pc或者$eip,因爲Intel IA-32架構中的程序指針名爲eip
p $pc
p $eip
x 顯示特定的內存位置內容
x/格式 地址
x命令顯示特定內存位置的值。
x命令的格式 x/nyz
n是要顯示的字段數;
y是輸出格式同之前的p
z是要顯示的字段長度:
b 字節
h 半字(2字節)
w 字(4字節)默認值
g 雙字(8字節)
例如:
x $pc
x/i $pc
此處x/i意爲顯示彙編指令
也有反彙編命令disassemble(或者disas)
格式:
disas
disas 程序計數器
disas 開始地址 結束地址
由此可見,在cpuid指令執行之前,EBX,ECX,EDX寄存器都是0,之後他們包含從廠商ID字符串來的值。
使用x命令顯示位於output變量前42個字節的內存位置的值(&符號表明是一個內存位置):
GDB的數據顯示格式:
x 按十六進制格式顯示變量。
d 按十進制格式顯示變量。
u 按十六進制格式顯示無符號整型。
o 按八進制格式顯示變量。
t 按二進制格式顯示變量。
a 按十六進制格式顯示變量。
c 按字符格式顯示變量。
f 按浮點數格式顯示變量。
查看寄存器和內存
1) info args
打印出當前函數的參數名及其值。
2)info locals
打印出當前函數中所有局部變量及其值。
3)info catch
打印出當前的函數中的異常處理信息。
4)源代碼的內存
你可以使用info line命令來查看源代碼在內存中的地址。info line後面可以跟“行號”,“函數名”,“文件名:行號”,“文件名:函
數名”,這個命令會打印出所指定的源碼在運行時的內存地址,如:
(gdb) info line tst.c:func
Line 5 of "tst.c" starts at address 0x8048456 <func+6> and ends at 0x804845d <func+13>.
5)info break
查看斷點信息。
6)info threads
看正在運行程序中的線程信息
7)info registers
查看寄存器的情況。(除了浮點寄存器)
8)info all-registers
查看所有寄存器的情況。(包括浮點寄存器)
9)info registers <regname >
查看所指定的寄存器的情況。
例如:info registers ebp
10)info frame或者i f
這個命令會打印出更爲詳細的當前棧層的信息,只不過,大多數都是運行時的內內
地址。比如:函數地址,調用函數的地址,被調用函數的地址,目前的函數是由什麼
樣的程序語言寫成的、函數參數地址及值、局部變量的地址等等
11)(gdb) disassemble func
disassemble可以查看源程序的當前執行時的機器碼,這個命令
會把目前內存中的指令dump出來
12)list
用list命令來打印程序的源代碼
13)x
可以使用examine命令(簡寫是x)來查看內存地址中的值.
x/3uh 0x54320表示,從內存地址0x54320讀取內容,h表示以雙字節爲一個單位,3表示三個單位,u表示按十六進制顯示。
x/48xw $ebp 也可以一樣顯示改寄存器或者用上述方法按寄存器的地址
參考:GDB查看棧信息
查看進程
info proc
查看棧幀
bt
backtrace
info stack
where
都是一樣的只是別名而已
bt 顯示所有棧幀
bt N 顯示開頭N個棧幀
bt -N 顯示最後N個棧幀
bt full 顯示棧幀+局部變量
bt full N N同前
監視
eatch <表達式>
<表達式>發生變化時暫停運行,此處<表達式>是常量或變量等
awatch <表達式>
<表達式>被訪問,改變時暫停運行
nwatch <表達式>
<表達式>被訪問時暫停運行
delete<編號>
刪除監視點
改變變量的值
set variable <變量><表達式>
例如:
(gdb) p options
$7=1
(gdb)set variable options=0
(gdb)print options
$8=0
GDB命令
1)單步調試:
n (next),
ni(nexti) 執行下一行(以彙編代碼爲單位)
s(step 跟n的區別,s進入到函數內)
si(stepi) 執行下一行(以彙編代碼爲單位)
u(until)執行到指定行
2)恢復操作:c(continue或者cont) 直到遇到下個斷點
3)臨時斷點: tbreak 有效期,第一次遇到
4)檢查變量:p (printf) 顯示錶達式
x 顯示內存內容
5)監視點:watch 當監視點的值發生變化時停止
6)查看棧:bt(backtrace,where) 顯示整個棧的內容。
f(frame)選擇要顯示的棧幀
do(down) 在當前調用的棧幀中選擇要顯示的棧幀
7)看已經設的斷點: ib(info break)
8)設置斷點:break(b)
break function, break line_number, break filename:line_number, break filename:function
info break 查看斷點信息。
9)刪除斷點: d(delete),delete+數值標識符(從第7點可得到) (不加參數,刪除所有斷點), clear使用跟第8點對應
10)禁用斷點:disable+數值標識符 (重新啓用 enable)
11)在單步時跳出函數:finish
12)在單步時跳出循環:until
13)條件斷點:break break-arg if (condition),例: break main if argc > 1
14)斷點命令列表(到斷點自動執行):
commands breakpoint-number 例子:commands 1
... >printf "i = %d", i
commands >end
...
end
a) 在commands 中加入silent,過濾到其他無用的輸出。
b) 最後一個commands是continue的話,自動continue。
例:comands 1
> silent
> printf "i = %d", i
> continue
> end
15)查看局部變量:info locals 得到當前棧中所有局部變量的值列表
16)設置變量:set x=12
17)GDB線程命令:
a) info threads(給出當前所有的線程信息)
b) thread 3(切換查看線程)
c) break 88 thread 3(當線程3到達源代碼行88時停止執行)
d) break 88 thread 3 if x == y
e) thread apply all bt,查看所有的線程的棧信息。
18) 您可以以進程ID作爲第二個參數,以調式一個正在運行的進程
gdb 程序名 1234
19)finish運行到函數結束
20)forward-search(或者fo) 向前搜索
21)generate-core-file(或者gcore) 生成內核轉儲
22edit 編輯文件或函數
23)directory(或者dir)插入目錄
24)list(或者l)顯示函數或者行
25)info (或者i)顯示信息
26)help (或者h)顯示幫助
注意:
1)重新編譯文件時不要退出gdb,斷點可以保存着。
2)在調試時不要開啓優化代碼的選項,不然經過了優化,設置的斷點的位置跟編譯後的位置相差可能很大。
《深入理解計算機系統(原書第2版)》
更高級的GDB調試:
GDB attach到進程
————————————————
版權聲明:本文爲CSDN博主「unix21」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/unix21/article/details/8450016