讓被調使得程序可以在指定的地方停住,斷點可以是條件表達式
當程序停住時,可以檢查此程序發生的事,並追蹤上文
動態的改變程序的執行環境
調式內核和應用程序時調試的命令是相同的
基本命令
list命令(縮寫l):列出代碼
list ,顯示程序第linenum行周圍的源代碼
list ,顯示函數名為function的函數源程序
list,顯示當前行前後的源程序
list -,顯示當前行前面的源程序
run命令:運行程序
程序運行參數
set args:指定運行時的參數,如set args 10 20 30
show args:查看設置好的運行參數
運行環境
path:設定程序的運行路徑
how paths:查看程序的運行路徑
set environment varname[=value]:設置環境變量,如set env USER=baohua;
show environment[varname]:查看環境變量
工作目錄
cd:相當於shell的cd命令
pwd:顯示當前所在的目錄
程序的輸入輸出
info terminal:顯示程序用到的終端的模式
run>outfile:重定向控制程序輸出
tty:指定輸入的終端設備,如tty/dev/ttyS1
break命令
break:在進入指定函數時停住
break:指定行號停住
break+offset/break-offset:當前 行號的前面或者後面offset行停住
break filename:linenum:在源文件filename的linenum行處停住
break filename:function:在源文件filename的function函數處停住
break*address:在程序運行的內存地址處停住
break:break命令沒有參數時,表示在下一條指令處停住
beak…if:…可以是上述的break、break+offset/break-offset中的參數,condition表示條件,在條件成立時停住
例如:在循環體中,可以設置break if i=100,表示當i為100時停住程序
info:查看斷點,如info breakpoints
、info break
(n表示斷點號)
單步命令
step:單步跟蹤,如果有函數調用,則進入該函數(進入該函數的前提是,此函數被編譯有debug信息),默認一條條執行,加上count,執行後面count指令然後停止
next:單步跟蹤,有函數則跳過,不加count,一條條執行,加上count則執行後面count條之後停住
set step-mode:set step-mode on用於打開step-mode模式
在進行step時,若跨過某沒有調試信息的函數,程序的執行會在該函數的第一條指令處停住,而不會跳過整個函數,這樣可以查看該函數的機器指令
finish:運行程序,直到當前函數完成返回,並打印函數返回時的堆棧地址、返回值及參數值等信息
until(縮寫為u):一直在循環體內執行單步而退步出來是一件令人煩惱的事情,用until命令可以運行程序直到退出循環體
stepi(縮寫為si)和nexti(縮寫為ni):這兩個命裡用於單步跟蹤一條機器指令,step和next時C語言級別的命令
運行display/i $pc命令之後,單步跟蹤會在大廚程序代買的同時打出機器指令,即匯編代碼
continue命令:當程序被停住後,可以用continue命令(縮寫為c,fg命令同continue命令)恢復程序的執行直到程序結束,或到達下一個斷點
命令格式為:continue/c/fg [ignore-count],ignore-count表示忽略其後多少次斷點
例如:假設設置了函數斷點add(),並觀察i,則在continue過程中,每次遇到add()函數或者i發生變化,程序就會停住
print命令:再掉是程序時,當程序被停住時,可以使用print命令(縮寫為p),或是同義命令inspect來查看當前程序的運行數據
命令格式:print print / 其中是表達式,也是被調試的程序總的表達式,時輸出的格式,比如,如果表達式按十六進制輸出,則時/x
表達式中,有幾種GDB所支持的操作符,他們可以用在任何一種語言中
@:是一個和數組有關的操作符
:: :指定一個在文件或是函數中的變量
{}:表示一個指向內存地址的類型為type的對象
例1:演示了查看sum[]數組的值的過程
當需要查看一段連續內存空間的值時,可以使用GDB的@操作符,@的左邊是第一個內存地址,@的右邊是想查看內存的長度
例2:動態申請內存
輸出格式:
x:十六進制
d:十進制
u:按十六進制,顯示無符號整型
o:八進制
t:二進制
a:十六進制
c:字符格式
f:浮點數格式
display命令:設置一些自動顯示的變量,當程序停住時,或是單步跟蹤時,這些變量會自動顯示
修改變量:print 變量=值
當GDB的print查看程序運行時的數據時,每個print都會被GDB記錄下來。GDB會以1,1,2,$3。。。這樣的方式為每一個print命令編號,可以用這個編號訪問前面的表達式
watch命令:觀察某個表達式(變量也是一種表達式)的值是否有了變化,有則馬上停止運行
watch:為表達式expr設置一個觀察點,一旦這個表達式發生了變化則停止運行
rwatch:當表達式(變量)被讀時,停止程序執行
awatch:當表達式(變量)的值被讀或者被寫時,停止運行
info watchpoints:列出當前所設置的所有觀察點
examine命令:查看內存地址中的值
語法:x/
[code]**//例1:** (gdb) print sum $2 = {133, 155, 0, 0, 0 ,0 ,0 ,0 ,0 ,0} (gdb) next Breakpoint 1, main () at gdb-example.c:25 25 sum[i] = add(array1[i], array2[i]): (gdb) next 23 for(i = 0; i< 10; i++) (gdb) print sum $3 = ({133, 155, 143, 0, 0 ,0 ,0 ,0 ,0 ,0} //例2: int *array = (int *) malloc (len * sizeof(int)); 在GDB調試過程中個,這樣實現這個動態數組的值: p *array@len //例3: main() { void *p = malloc(16); while(1); } //用如下命令來修改p指向的內存 (gdb) set *(unsigned char *)p='h' (gdb) set *(unsigned char *)p='e' (gdb) set *(unsigned char *)p='l' (gdb) set *(unsigned char *)p='l' (gdb) set *(unsigned char *)p='e' //查看結果 (gdb) x/s p 0x804b008 "hello" //查看函數func反匯編代碼 (gdb) disassemble func Dump of assembler code for function func: 0x8048450 <func>: push %ebp 0x8048451 <func+1> mov %esp,%ebp ...
內核緩沖區是一個環形緩沖區(Ring Buffer),如果消息過多,則會將之前的消息沖刷掉
[code]static char __log_buf[__LOG_BUF_LEN] __aligned(LOG_ALIGN);printk()的8個消息級別,分別是0~7,級別越低(數值越大),消息越不重要,0級時緊急事件級,7級時調試級
#define KERN_EMERG “<0>”:緊急事件,一般是系統崩潰前的提示信息
#define KERN_ALERT “<1>”:必須立即采取行動
#define KERN_CRIT “<2>”:臨界狀態,通常涉及嚴重的硬件或軟件操作失敗
#define KERN_ERR “<3>”:用於報告錯誤狀態,設備驅動程序會經常調用KERN_ERR來報告來自硬件的問題
#define KERN_WARNING “<4>”:對可能出現問題的情況進行警告,這類情況通常不會對系統造成嚴重的問題
#define KERN_NOTICE “<5>”:有必要進行提示的正常情形,許多與安全相關的狀況用這個級別進行匯報
#define KERN_INFO “<6>”:內核提示信息,很多驅動程序在啟動的時候,用這個級別打印他們找到的硬件信息
#define KERN_DEBUG “<7>”:用於調試
通過/proc/sys/kernel/printk文件可以調節printk()的輸出等級,該文件有4個等級
控制台日志級別:當前的打印級別,優先級高於該值的信息將被打印紙控制台
默認的信息日志級別:將用該優先級來打印沒有優先級前綴的消息,也就是直接寫printk(“xxx”)而不帶打印級別的情況下,會用該級別打印
最低的控制台日志級別:控制台日志級別可被設置的最小值(一般都是1)
默認的控制台日志級別:控制台日志級別的默認值
例5:Ubuntu上的輸出級別
[code]//例5:Ubuntu上的輸出級別 $ cat /proc/sys/kernel/printk 4 4 1 7顯示內核打印信息方法
通過dmesg命令,如果使用dmesg -c命令,則不僅會顯示__log_buf,還會清除該緩沖區的內容
使用cat /proc/kmsg 命令,/proc/kmsg是一個“永無休止的文件”,因此,cat /porc/kmsg的進程只能通過“Ctrl+C”或kill終止
設備驅動中的調試函數
pr_debug(),pr_info()
使用pr_xxx()族API的好處是,可以在文件開頭通過pr_fmt()定義一個打印格式
例6:在kernel/watchdog.c的最開頭通過如下定義可以保證之後watchdog.c調用的所有pr_xxx()打印的消息都自動帶有“NMI watchdog: ”的前綴
dev_debug():如dev_dbg()、dev_err()、dev_info()等
使用dev_xxx()族API打印的時候,設備名稱會被自動加到打印消息的前頭
打印的附加信息,例7
func:輸出printk()調用所在的函數名LINE:輸出其所在的代碼行
FILE:輸出源代碼命令名
[code]//pr_debug()與pr_info()定義 #ifdef DEBUG #define pr_debug(fmt,arg...) \ printk(KERN_DEBUG fmt,##arg) #else static inline int __attribute__ ((format (printf,1,2))) pr_debug(cost char * fmt, ...) { return 0; } #endif #define pr_infor(fmt,arg ...) \ printk(KERN_INFO fmt, ##arg)
[code]//例6: #define pr_fmt(fmt) "NMI watchdog: " fmt #include <linux/mm.h> #include <linux/cpu.h> #include <linux/nmi.h> ... //例7: printk(KERN_ERR "Assertion failed! %s,%s,%s,line=%d", #expr, __FILE__, __func__, LINE);
為了在內核的drivers/serial下的控制台驅動初始化之前支持打印,可以選擇上述兩個配置項,另外需要在bootargs中設置earlyprintk的選項
“/proc”下的絕大多數文件是只讀的,以顯示內核信息為主,也不都是只讀,如修改/proc/sys/kernel/printk以改變printk()的打印級別
Linux系統的許多命令本身都是通過分析”/proc”下的文件來完成的,如ps、top等,例如,free命令通過分析/proc/meminfo文件的到可用內存信息
panic()定義在kernel/panic.c中,會導致內核崩潰,並打開Oops
[code]#define BUG() do { \ printk("BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__"); \ panic("BUG!"); }while(0)BUG_ON():時BUG()的變體,只有當括號內的條件成立的時候,才拋出Oops
WARN_ON():在括號裡的條件成立的時候,內核會拋出棧回溯,但是不會panic(),這通常用於內核拋出一個警告,暗示某種不太合理的事情發生了