第10章 嵌入式linux的调试技术
一、????? 防止函數(shù)printk降低linux性能:
利用C語(yǔ)言中的編譯指令(#if、#else、#endif等)。
現(xiàn)在修改printk_demo驅(qū)動(dòng)代碼,通過(guò)編譯指令定義了一個(gè)pr_debug宏,并通過(guò)修改編譯指令的條件值來(lái)控制是否調(diào)用printk函數(shù)。如下:
# if 1//此處為1,使用printk函數(shù),為0,忽略printk函數(shù)
? #define pr_debug(x,…)? do { } while(0)
#endif
除此之外,我們還需要了解兩個(gè)知識(shí)點(diǎn):1.可變參數(shù)的宏:可變參數(shù)的宏與固定參數(shù)的宏之間的區(qū)別:可變參數(shù)的宏需要通過(guò)_VA_ARGS_宏【不支持可變參數(shù)個(gè)數(shù)為0的情況】獲取可變參數(shù)的宏的可變參數(shù)。定義可變參數(shù)宏與定義可變參數(shù)函數(shù)的方法相同,都使用3個(gè)點(diǎn)(…)來(lái)表示可變參數(shù),可變參數(shù)必須是宏和函數(shù)最后的參數(shù)。
二、????? 通過(guò)虛擬文件系統(tǒng)(/proc)進(jìn)行數(shù)據(jù)交互:
必要性:在linux文件系統(tǒng)中,/proc經(jīng)常被用來(lái)作為內(nèi)核空間進(jìn)行數(shù)據(jù)交互的工具。/proc是虛擬文件系統(tǒng),也就是說(shuō),/proc并不是真正的文件系統(tǒng),而是內(nèi)存映射。所有讀寫(xiě)/proc的操作軍事對(duì)內(nèi)存讀寫(xiě)的操作。所以讀寫(xiě)/proc文件系統(tǒng)的速度遠(yuǎn)比讀寫(xiě)/dev要快。因此,/proc文件系統(tǒng)也可作為linux驅(qū)動(dòng)與用戶空間程序交互的工具。
很多信息就是通過(guò)/proc文件系統(tǒng)由內(nèi)核空間的程序向外屆提供的。例如:當(dāng)前系統(tǒng)內(nèi)存資源就是通過(guò)/proc/meminfo文件讀取的,讀者可以使用如下命令:查看/proc/meminfo文件的內(nèi)容:Cat /proc/meminfo.我們可以通過(guò)執(zhí)行free命令看看顯示的信息是否和meminfo文件中的部分內(nèi)容相匹配。
在linux驅(qū)動(dòng)程序中可以使用內(nèi)核函數(shù)在/proc目錄中創(chuàng)建和刪除虛擬文件,也可以建立和刪除虛擬目錄。
struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,struct proc_dir_entry *parent);
name:?要?jiǎng)?chuàng)建的文件名稱;
mode:?該文件的保護(hù)掩碼;
parent:?確定文件所在目錄,如果置NULL?,則位置為/proc?下。
/*?該函數(shù)在父目錄parent?下創(chuàng)建一個(gè)目錄name* */
struct proc_dir_entry * proc_mkdir (const char *name,struct proc_dir_entry *parent);
@name :?要?jiǎng)?chuàng)建的目錄名
@parent :?這個(gè)目錄的父目錄
3.remove_proc_entry 刪除文件或目錄
/*?這個(gè)函數(shù)從proc?文件系統(tǒng)中刪除一個(gè)文件或目錄。
*?注意:1?.是通過(guò)參數(shù)name?,而不是通過(guò)創(chuàng)建時(shí)返回的指針來(lái)刪除的。
* 2?.該函數(shù)不會(huì)遞歸刪除目錄下的文件。
* 3?.data?變量保存了分配的內(nèi)存,要先釋放對(duì)應(yīng)內(nèi)存,再刪除該文件。
* */
void remove_proc_entry (const char *name,struct proc_dir_entry *parent);
@name :?要?jiǎng)h除的文件或目錄名
@parent :?所在的父目錄?
?4.create_proc_read_entry?創(chuàng)建只讀proc?文件
struct proc_dir_entry * create_proc_read_entry (const char
*name,mode_t mode,struct proc_dir_entry *parent,read_proc_t*
read_proc,void *data);
@name :?要?jiǎng)?chuàng)建的文件名
@mode :?要?jiǎng)?chuàng)建的文件的屬性 默認(rèn)0755
@parent :?這個(gè)文件的父目錄
@read_proc :?當(dāng)用戶讀這個(gè)文件時(shí),內(nèi)核調(diào)用的函數(shù)
@data :?傳給read_proc?的參數(shù)
注意:刪除虛擬文件目錄之前,要先刪除目錄中的虛擬文件。
執(zhí)行build.sh腳本文件,會(huì)將proc_demo驅(qū)動(dòng)安裝在Ubuntu Linux、開(kāi)發(fā)板或Android虛擬機(jī)上。然后執(zhí)行下面的命令查看/proc/proc_demo目錄中的內(nèi)容。
Ls –al /proc/proc_demo/bin2dec
Cat /proc/proc_demo/bin2dec
Cat /proc_demo/readonly
三、????? 調(diào)試工具:
Gdb可以跟蹤調(diào)試用戶空間的程序。
對(duì)于一個(gè)用于測(cè)試的可執(zhí)行程序(gdb_debug.c),我們可以直接運(yùn)行build.sh腳本文件,但注意加上命令參數(shù)-g,完整的編譯命令如下:
#gcc –static –g –o gdb_debug /root/drivers/debug/gdb_debug.c
現(xiàn)在使用下面的命令來(lái)調(diào)試:
Gdb gdb_debug
Gdb包含的命令:
1>???????? quit:用于退出gdb調(diào)試界面
2>???????? ?list:用于列出程序中的代碼。有三種調(diào)用格式:list:顯示上一次調(diào)用list命令輸出的最后一行后面的10行。 list-: 顯示上一次調(diào)用list命令輸出的第一行前面的10行,第一次調(diào)用list命令什么都不會(huì)顯示。list n:顯示第n行附近的10行,一般會(huì)顯示第n行前面5 行和后面4行,加上第n行,正好是10行。
3>???????? Break n:將指定行設(shè)置為斷點(diǎn),n表示行號(hào)
4>???????? Clear n:清除指定行的斷點(diǎn)。
5>???????? Tbreak n:將指定行設(shè)置為斷點(diǎn),斷點(diǎn)只能使用一次,使用完成后自動(dòng)清零。
6>???????? Cont/continue:跳過(guò)當(dāng)前斷點(diǎn)繼續(xù)執(zhí)行。[cont:跳過(guò)當(dāng)前斷點(diǎn)繼續(xù)執(zhí)行;cont n:跳過(guò)n次斷點(diǎn)繼續(xù)前行]
7>???????? Next:繼續(xù)執(zhí)行下面的語(yǔ)句,但跳過(guò)這程序。等價(jià)于step over。[同上有兩種格式next 及next n]
8>???????? Nexti:單步執(zhí)行語(yǔ)句,和next的區(qū)別:它會(huì)跟蹤到子程序的內(nèi)部,但不打印出子程序內(nèi)部的語(yǔ)句。
9>???????? Print var_name:查看變量值.
1.與GDB的區(qū)別:gdb用于PC上進(jìn)行測(cè)試,而gdbserver測(cè)試運(yùn)行于開(kāi)發(fā)板、手機(jī)、Android模擬器上。
2.在開(kāi)發(fā)板上使用gdbserver打開(kāi)測(cè)試程序,然后通過(guò)串口、有線、無(wú)線網(wǎng)絡(luò)可以在PC上進(jìn)行測(cè)試。
3.第一步:進(jìn)入Android模擬器的終端,然后進(jìn)入data/local目錄,并執(zhí)行如下命令:gdbserver :4321 ./gdb_debug啟動(dòng)gdbserver監(jiān)聽(tīng)程序。其中4321表示使用本機(jī)的4321端口號(hào)進(jìn)行監(jiān)聽(tīng)。
? 第二步:開(kāi)啟另一個(gè)Linux終端,將外部訪問(wèn)模擬器的4321端口的數(shù)據(jù)包轉(zhuǎn)發(fā)到Android模擬器內(nèi)部的4321端口:adb –s emulator-5544 forword tcp:4321[有多個(gè)Android設(shè)備時(shí)要加-s命令行參數(shù)指定具體的Android設(shè)備]。
第二個(gè)方法[映射端口]:1.進(jìn)入telent:telent localhost 5554 2.映射端口:redir add tcp:4321:4321
第三步:進(jìn)入gdb控制臺(tái):arm-none-linux-guneabi-gdb gdb_debug
第四步:連接Android模擬器:(gdb) target remote localhost:4321
??????????? 最后:輸入gdb命令進(jìn)行調(diào)試。
??????? 通過(guò)IP方式連接開(kāi)發(fā)板上的gdbserver:1.gdbserver localhost:4321 ./gdb_debug? 2.在linux終端的gdb控制臺(tái)鏈接開(kāi)發(fā)板的gdbsrever:(gdb) target remote 192.168.17.103 ./gdb_debug.
??????? 通過(guò)串口方式:對(duì)應(yīng)的應(yīng)該是:1.gdbserver /dev/s3c2410_serial0 ./gdb_debug? 2.(gdb) target remote /dev/ttyUSB0
Kgdb除了提供類似printk函數(shù)的日志輸出功能,還允許開(kāi)發(fā)人員直接在PC上通過(guò)GDB鏈接目標(biāo)設(shè)備。
Kgdb包含兩個(gè)部分:kgdb內(nèi)核和一套鏈接接口【目前支持串口tty設(shè)備鏈接和以太網(wǎng)連接】。其中串口連接需要通過(guò)內(nèi)核參數(shù)kgdboc指定要鏈接的串口tty設(shè)備:以太網(wǎng)連接通過(guò)內(nèi)核參數(shù)kgdboc指定IP和端口號(hào)。
要想用kgdb調(diào)試內(nèi)核,首先需要配置linux內(nèi)核。使用make menuconfig命令進(jìn)入Linux內(nèi)核的配置菜單。【Kernel hacking--àKGDB:kernel debugger】
???? 配置內(nèi)核參數(shù)時(shí),這些參數(shù)通知Linux內(nèi)核要如何進(jìn)行調(diào)試。假設(shè)要通過(guò)USB轉(zhuǎn)COM口數(shù)據(jù)線進(jìn)行調(diào)試,需要將kgdboc參數(shù)值折為ttyUSB0,傳輸效率為115200,一般會(huì)指定kdbwait。這些參數(shù)需要在S3C開(kāi)發(fā)板過(guò)程中按回車進(jìn)入U(xiǎn)boot模式,然后使用setenv命令設(shè)置Linux內(nèi)核的啟動(dòng)參數(shù),然后使用saveenv和rest命令保存和重新啟動(dòng)Linux內(nèi)核。
在設(shè)置完成后,主機(jī)就可以使用gdb命令像調(diào)試普通嵌入式應(yīng)用程序一樣調(diào)試Linux內(nèi)核,執(zhí)行的命令如下:
#gdb? ./vmlinux
完成后,使用如下的命令設(shè)置傳輸速率和連接也要調(diào)試的Linux內(nèi)核。
(gdb) set remoteband 115200
(gdb) target remote /dev/ttyUSB0
最后使用各種gdb命令進(jìn)行Linux內(nèi)核調(diào)試。
?
轉(zhuǎn)載于:https://www.cnblogs.com/beatrice/p/5656055.html
總結(jié)
以上是生活随笔為你收集整理的第10章 嵌入式linux的调试技术的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 闲暇处才是生活
- 下一篇: C#正则表达式提取文本中以逗号间隔的数据