1 內核調試以及工具總結
內核總是那么捉摸不透, 內核也會犯錯, 但是調試卻不能像用戶空間程序那樣, 為此內核開發者為我們提供了一系列的工具和系統來支持內核的調試.
內核的調試, 其本質是內核空間與用戶空間的數據交換, 內核開發者們提供了多樣的形式來完成這一功能.
2 用戶空間與內核空間數據交換的文件系統
內核中有三個常用的偽文件系統: procfs, debugfs和sysfs.
它們都用于Linux內核和用戶空間的數據交換, 但是適用的場景有所差異:
procfs歷史最早, 最初就是用來跟內核交互的唯一方式, 用來獲取處理器、內存、設備驅動、進程等各種信息.
sysfs跟kobject框架緊密聯系, 而kobject是為設備驅動模型而存在的, 所以sysfs是為設備驅動服務的.
debugfs從名字來看就是為debug而生, 所以更加靈活.
relayfs是一個快速的轉發(relay)數據的文件系統, 它以其功能而得名. 它為那些需要從內核空間轉發大量數據到用戶空間的工具和應用提供了快速有效的轉發機制.
2.1 procfs文件系統
ProcFs介紹
procfs是比較老的一種用戶態與內核態的數據交換方式, 內核的很多數據都是通過這種方式出口給用戶的, 內核的很多參數也是通過這種方式來讓用戶方便設置的. 除了sysctl出口到/proc下的參數,procfs提供的大部分內核參數是只讀的. 實際上, 很多應用嚴重地依賴于procfs, 因此它幾乎是必不可少的組件. 前面部分的幾個例子實際上已經使用它來出口內核數據, 但是并沒有講解如何使用, 本節將講解如何使用procfs.
參考資料:
用戶空間與內核空間數據交換的方式(2)——procfs:http://www.cnblogs.com/hoys/archive/2011/04/10/2011141.html
2.2 sysfs文件系統
內核子系統或設備驅動可以直接編譯到內核, 也可以編譯成模塊, 編譯到內核, 使用前一節介紹的方法通過內核啟動參數來向它們傳遞參數, 如果編譯成模塊, 則可以通過命令行在插入模塊時傳遞參數, 或者在運行時, 通過sysfs來設置或讀取模塊數據.
Sysfs是一個基于內存的文件系統, 實際上它基于ramfs,sysfs提供了一種把內核數據結構, 它們的屬性以及屬性與數據結構的聯系開放給用戶態的方式, 它與kobject子系統緊密地結合在一起, 因此內核開發者不需要直接使用它, 而是內核的各個子系統使用它. 用戶要想使用sysfs讀取和設置內核參數, 僅需裝載sysfs就可以通過文件操作應用來讀取和設置內核通過sysfs開放給用戶的各個參數:
mkdir -p /sysfs mount -t sysfs sysfs /sysfs
注意, 不要把sysfs和sysctl混淆,sysctl是內核的一些控制參數, 其目的是方便用戶對內核的行為進行控制, 而sysfs僅僅是把內核的kobject對象的層次關系與屬性開放給用戶查看, 因此sysfs的絕大部分是只讀的, 模塊作為一個kobject也被出口到sysfs, 模塊參數則是作為模塊屬性出口的, 內核實現者為模塊的使用提供了更靈活的方式, 允許用戶設置模塊參數在sysfs的可見性并允許用戶在編寫模塊時設置這些參數在sysfs下的訪問權限, 然后用戶就可以通過sysfs來查看和設置模塊參數, 從而使得用戶能在模塊運行時控制模塊行為.
相關資料鏈接:
用戶空間與內核空間數據交換的方式(6)——模塊參數與sysfs:http://www.cnblogs.com/hoys/archive/2011/04/10/2011470.html
2.3 debugfs文件系統
內核開發者經常需要向用戶空間應用輸出一些調試信息, 在穩定的系統中可能根本不需要這些調試信息, 但是在開發過程中, 為了搞清楚內核的行為, 調試信息非常必要, printk可能是用的最多的, 但它并不是最好的, 調試信息只是在開發中用于調試, 而printk將一直輸出, 因此開發完畢后需要清除不必要的printk語句, 另外如果開發者希望用戶空間應用能夠改變內核行為時,printk就無法實現.
因此, 需要一種新的機制, 那只有在需要的時候使用, 它在需要時通過在一個虛擬文件系統中創建一個或多個文件來向用戶空間應用提供調試信息.
有幾種方式可以實現上述要求:
使用procfs, 在/proc創建文件輸出調試信息, 但是procfs對于大于一個內存頁(對于x86是4K)的輸出比較麻煩, 而且速度慢, 有時回出現一些意想不到的問題.
使用sysfs(2.6內核引入的新的虛擬文件系統), 在很多情況下, 調試信息可以存放在那里, 但是sysfs主要用于系統管理,它希望每一個文件對應內核的一個變量,如果使用它輸出復雜的數據結構或調試信息是非常困難的.
使用libfs創建一個新的文件系統, 該方法極其靈活, 開發者可以為新文件系統設置一些規則, 使用libfs使得創建新文件系統更加簡單, 但是仍然超出了一個開發者的想象.
為了使得開發者更加容易使用這樣的機制,Greg Kroah-Hartman開發了debugfs(在2.6.11中第一次引入), 它是一個虛擬文件系統, 專門用于輸出調試信息, 該文件系統非常小, 很容易使用, 可以在配置內核時選擇是否構件到內核中, 在不選擇它的情況下, 使用它提供的API的內核部分不需要做任何改動.
2.4 relayfs文件系統
relayfs是一個快速的轉發(relay)數據的文件系統, 它以其功能而得名. 它為那些需要從內核空間轉發大量數據到用戶空間的工具和應用提供了快速有效的轉發機制.
Channel是relayfs文件系統定義的一個主要概念, 每一個channel由一組內核緩存組成, 每一個CPU有一個對應于該channel的內核緩存, 每一個內核緩存用一個在relayfs文件系統中的文件文件表示, 內核使用relayfs提供的寫函數把需要轉發給用戶空間的數據快速地寫入當前CPU上的channel內核緩存, 用戶空間應用通過標準的文件I/O函數在對應的channel文件中可以快速地取得這些被轉發出的數據mmap來. 寫入到channel中的數據的格式完全取決于內核中創建channel的模塊或子系統.
relayfs的用戶空間API:
relayfs實現了四個標準的文件I/O函數,open、mmap、poll和close
注意 : 用戶態應用在使用上述 API 時必須保證已經掛載了 relayfs 文件系統, 但內核在創建和使用 channel時不需要relayfs 已經掛載. 下面命令將把 relayfs 文件系統掛載到 /mnt/relay.
2.5 seq_file
一般地, 內核通過在procfs文件系統下建立文件來向用戶空間提供輸出信息, 用戶空間可以通過任何文本閱讀應用查看該文件信息, 但是procfs有一個缺陷, 如果輸出內容大于1個內存頁, 需要多次讀,因此處理起來很難, 另外, 如果輸出太大, 速度比較慢, 有時會出現一些意想不到的情況,Alexander Viro實現了一套新的功能, 使得內核輸出大文件信息更容易, 該功能出現在2.4.15(包括2.4.15)以后的所有2.4內核以及2.6內核中, 尤其是在2.6內核中,已經大量地使用了該功能
3 printk
在內核調試技術之中, 最簡單的就是printk的使用了, 它的用法和C語言應用程序中的printf使用類似, 在應用程序中依靠的是stdio.h中的庫, 而在linux內核中沒有這個庫, 所以在linux內核中,實現了自己的一套庫函數,printk就是標準的輸出函數
4 ftrace && trace-cmd
4.1 trace && ftrace
Linux當前版本中, 功能最強大的調試、跟蹤手段. 其最基本的功能是提供了動態和靜態探測點, 用于探測內核中指定位置上的相關信息.
靜態探測點, 是在內核代碼中調用ftrace提供的相應接口實現, 稱之為靜態是因為, 是在內核代碼中寫死的, 靜態編譯到內核代碼中的, 在內核編譯后, 就不能再動態修改. 在開啟ftrace相關的內核配置選項后, 內核中已經在一些關鍵的地方設置了靜態探測點, 需要使用時, 即可查看到相應的信息.
動態探測點, 基本原理為 : 利用mcount機制, 在內核編譯時, 在每個函數入口保留數個字節, 然后在使用ftrace時, 將保留的字節替換為需要的指令, 比如跳轉到需要的執行探測操作的代碼。
ftrace的作用是幫助開發人員了解Linux內核的運行時行為, 以便進行故障調試或性能分析.
最早ftrace是一個function tracer, 僅能夠記錄內核的函數調用流程. 如今ftrace已經成為一個
framework, 采用plugin的方式支持開發人員添加更多種類的trace功能.
Ftrace由RedHat的Steve Rostedt負責維護. 到2.6.30為止, 已經支持的tracer包括 :
這里還沒有列出所有的tracer,ftrace是目前非常活躍的開發領域, 新的tracer將不斷被加入內核。
4.2 ftrace前端工具trace-cmd
trace-cmd 介紹
trace-cmd和 開源的kernelshark均是內核Ftrace的前段工具, 用于分分析核性能.
他們相當于是一個/sys/kernel/debug/tracing中文件系統接口的封裝, 為用戶提供了更加直接和方便的操作.
使用
# 收集信息 sudo trace-cmd reord subsystem:tracing # 解析結果 #sudo trace-cmd report
trace-cmd: A front-end for Ftrace:https://lwn.net/Articles/410200/
其本質就是對/sys/kernel/debug/tracing/events下各個模塊進行操作, 收集數據并解析
5 Kprobe && systemtap
5.1 內核kprobe機制
kprobe是linux內核的一個重要特性, 是一個輕量級的內核調試工具, 同時它又是其他一些更高級的內核調試工具(比如perf和systemtap)的 “基礎設施”, 4.0版本的內核中, 強大的eBPF特性也寄生于kprobe之上, 所以kprobe在內核中的地位就可見一斑了.
Kprobes提供了一個強行進入任何內核例程并從中斷處理器無干擾地收集信息的接口. 使用Kprobes可以收集處理器寄存器和全局數據結構等調試信息。開發者甚至可以使用Kprobes來修改 寄存器值和全局數據結構的值.
如何高效地調試內核?
printk是一種方法, 但是printk終歸是毫無選擇地全量輸出, 某些場景下不實用, 于是你可以試一下tracepoint, 我使能tracepoint機制的時候才輸出. 對于傻傻地放置printk來輸出信息的方式,tracepoint是個進步, 但是tracepoint只是內核在某些特定行為(比如進程切換)上部署的一些靜態錨點, 這些錨點并不一定是你需要的, 所以你仍然需要自己部署tracepoint, 重新編譯內核. 那么kprobe的出現就很有必要了, 它可以在運行的內核中動態插入探測點, 執行你預定義的操作.
它的基本工作機制是 : 用戶指定一個探測點, 并把一個用戶定義的處理函數關聯到該探測點, 當內核執行到該探測點時, 相應的關聯函數被執行,然后繼續執行正常的代碼路徑.
kprobe實現了三種類型的探測點 :kprobes,jprobes和kretprobes(也叫返回探測點).kprobes是可以被插入到內核的任何指令位置的探測點,jprobes則只能被插入到一個內核函數的入口, 而kretprobes則是在指定的內核函數返回時才被執行.
5.2 前端工具systemtap
SystemTap是監控和跟蹤運行中的Linux內核的操作的動態方法. 這句話的關鍵詞是動態, 因為SystemTap沒有使用工具構建一個特殊的內核, 而是允許您在運行時動態地安裝該工具. 它通過一個Kprobes的應用編程接口 (API) 來實現該目的.
SystemTap與一種名為DTrace的老技術相似,該技術源于Sun Solaris操作系統. 在DTrace中, 開發人員可以用D編程語言(C語言的子集, 但修改為支持跟蹤行為)編寫腳本.DTrace腳本包含許多探針和相關聯的操作, 這些操作在探針 “觸發” 時發生. 例如, 探針可以表示簡單的系統調用,也可以表示更加復雜的交互,比如執行特定的代碼行
DTrace是Solaris最引人注目的部分, 所以在其他操作系統中開發它并不奇怪.DTrace是在Common Development and Distribution License (CDDL)之下發行的, 并且被移植到FreeBSD操作系統中.
另一個非常有用的內核跟蹤工具是ProbeVue, 它是IBM為IBM AIX操作系統6.1開發的. 您可以使用ProbeVue探查系統的行為和性能, 以及提供特定進程的詳細信息. 這個工具使用一個標準的內核以動態的方式進行跟蹤.
考慮到DTrace和ProbeVue在各自的操作系統中的巨大作用, 為Linux操作系統策劃一個實現該功能的開源項目是勢不可擋的.SystemTap從2005年開始開發, 它提供與DTrace和ProbeVue類似的功能. 許多社區還進一步完善了它, 包括Red Hat、Intel、Hitachi和IBM等.
這些解決方案在功能上都是類似的, 在觸發探針時使用探針和相關聯的操作腳本.
6 kgdb && kgtp
6.1 kgdb
KDB 和 KGDB 合并, 并進入內核
KGDB是大名鼎鼎的內核調試工具, 他是由KDB和KGDB項目合并而來.
kdb是一個Linux系統的內核調試器, 它是由SGI公司開發的遵循GPL許可證的開放源碼調試工具.kdb嵌入在Linux內核中. 為內核&&驅動程序員提供調試手段. 它適合于調試內核空間的程序代碼. 譬如進行設備驅動程序調試. 內核模塊的調試等.
kgdb和kdb現在已經合并了. 對于一個正在運行的kgdb而言, 可以使用gdbmonitor命令來使用kdb命令. 比如
(gdb)gdb monitor ps -A
就可以運行kdb的ps命令了.
分析一下kdb補丁和合入主線的kdb有啥不同
kdb跟kgdb合并之后, 也可以使用kgdb的IO驅動(比如鍵盤), 但是同時也kdb也喪失了一些功能.合并之后的kdb不在支持匯編級的源碼調試. 因此它現在也是平臺獨立的.
kdump和kexec已經被移除。
從/proc/meninfo中獲取的信息比以前少了。
bt命令現在使用的是內核的backtracer,而不是kdb原來使用的反匯編。
合并之后的kdb不在具有原來的反匯編(id命令)
總結一下 :kdb和kgdb合并之后,系統中對這兩種調試方式幾乎沒有了明顯的界限,比如通過串口進行遠程訪問的時候,可以使用kgdb命令, 也可以使用kdb命令(使用gdb monitor實現)
6.2 KGTP
KGTP是一個 實時 輕量級Linux調試器 和 跟蹤器. 使用KGTP
使用KGTP不需要在Linux內核上打PATCH或者重新編譯, 只要編譯KGTP模塊并insmod就可以.
其讓Linux內核提供一個遠程GDB調試接口, 于是在本地或者遠程的主機上的GDB可以在不需要停止內核的情況下用GDB tracepoint和其他一些功能 調試 和 跟蹤Linux.
即使板子上沒有GDB而且其沒有可用的遠程接口,KGTP也可以用離線調試的功能調試內核(見http://code.google.com/p/kgtp/wiki/HOWTOCN#/sys/kernel/debug/gtpframe和離線調試)。
KGTP支持 X86-32 , X86-64 , MIPS 和 ARM 。
KGTP在Linux內核 2.6.18到upstream 上都被測試過。
而且還可以用在 Android 上(見http://code.google.com/p/kgtp/wiki/HowToUseKGTPinAndroid)
7 perf
Perf是用來進行軟件性能分析的工具。
通過它, 應用程序可以利用PMU,tracepoint和內核中的特殊計數器來進行性能統計. 它不但可以分析指定應用程序的性能問題 (per thread). 也可以用來分析內核的性能問題, 當然也可以同時分析應用代碼和內核,從而全面理解應用程序中的性能瓶頸.
最初的時候, 它叫做Performance counter, 在2.6.31中第一次亮相. 此后他成為內核開發最為活躍的一個領域. 在2.6.32中它正式改名為Performance Event, 因為perf已不再僅僅作為PMU的抽象, 而是能夠處理所有的性能相關的事件.
使用perf, 您可以分析程序運行期間發生的硬件事件,比如instructions retired,processor clock cycles等; 您也可以分析軟件事件, 比如Page Fault和進程切換。
這使得Perf擁有了眾多的性能分析能力, 舉例來說,使用Perf可以計算每個時鐘周期內的指令數, 稱為IPC,IPC偏低表明代碼沒有很好地利用CPU.
Perf還可以對程序進行函數級別的采樣, 從而了解程序的性能瓶頸究竟在哪里等等.Perf還可以替代strace, 可以添加動態內核probe點. 還可以做benchmark衡量調度器的好壞.
人們或許會稱它為進行性能分析的”瑞士軍刀”, 但我不喜歡這個比喻, 我覺得perf應該是一把世間少有的倚天劍.
金庸筆下的很多人都有對寶刀的癖好, 即便本領低微不配擁有, 但是喜歡, 便無可奈何. 我恐怕正如這些人一樣, 因此進了酒館客棧, 見到相熟或者不相熟的人, 就要興沖沖地要講講那倚天劍的故事.
8 其他Tracer工具
8.1 LTTng
LTTng是一個Linux平臺開源的跟蹤工具, 是一套軟件組件, 可允許跟蹤Linux內核和用戶程序, 并控制跟蹤會話(開始/停止跟蹤、啟動/停止事件 等等). 這些組件被綁定如下三個包 :
8.2 eBPF
extended Berkeley Packet Filter(eBPF)是一個可以在事件上運行程序的高效內核虛擬機(JIT)。它可能最終會提供 ftrace 和 perf_events 的內核編程,并強化其他的 tracer。這是 Alexei Starovoitov 目前正在開發的,還沒有完全集成,但是從4.1開始已經對一些優秀的工具有足夠的內核支持了,如塊設備I/O的延遲熱圖。可參考其主要作者 Alexei Starovoitov 的BPF slides和eBPF samples。
8.3 Ktap
ktap 在過去是一款前景很好的 tracer,它使用內核中的 lua 虛擬機處理,在沒有調試信息的情況下在嵌入式設備上運行的很好。它分為幾個步驟,并在有一段時間似乎超過了 Linux 上所有的追蹤器。然后 eBPF 開始進行內核集成,而 ktap 的集成在它可以使用 eBPF 替代它自己的虛擬機后才開始。因為 eBPF 仍將持續集成幾個月,ktap 開發者要繼續等上一段時間。我希??今年晚些時候它能重新開發。
8.4 dtrace4linux
dtrace4linux 主要是 Paul Fox 一個人在業余時間完成的,它是 Sun DTrace 的 Linux 版本。它引入矚目,還有一些 provider 可以運行,但是從某種程度上來說還不完整,更多的是一種實驗性的工具(不安全)。我認為,顧忌到許可問題,人們會小心翼翼的為 dtrace4linux 貢獻代碼:由于當年 Sun 開源DTrace 使用的是 CDDL 協議,而 dtrace4linux 也不大可能最終進入 Linux kernel。Paul 的方法很可能會使其成為一個 add-on。我很樂意看到 Linux 平臺上的 DTrace 和這個項目的完成,我認為當我加入 Netflix 后將會花些時間來協助完成這個項目。然而,我還是要繼續使用內置的 tracers,如 ftrace 和 perf_events。
8.5 OL DTrace
Oracle Linux DTrace為了將 DTrace 引入 Linux,特別是 Oracle Linux,做出了很大的努力。這些年來發布的多個版本表明了它的穩定進展。開發者們以一種對這個項目的前景看好的態度談論著改進 DTrace 測試套件。很多有用的 provider 已經完成了,如:syscall, profile, sdt, proc, sched 以及USDT。我很期待 fbt(function boundary tracing, 用于內核動態跟蹤)的完成,它是 Linux 內核上非常棒的 provider。OL DTrace 最終的成功將取決于人們對運行 Oracle Linux(為技術支持付費)有多大興趣,另一方面取決于它是否完全開源:它的內核元件是開源的,而我沒有看到它的用戶級別代碼。
8.6 sysdig
sysdig是一個使用類tcpdump語法來操作系統事件的新tracer,它使用lua提交進程。它很優秀,它見證了系統跟蹤領域的變革。它的局限性在于它只在當前進行系統調用,在提交進行時將所有事件轉儲為用戶級別。你可以使用系統調用做很多事情,然而我還是很希望它能支持跟蹤點、kprobe和uprobe。我還期待它能支持eBPF做內核摘要。目前,sysdig開發者正在增加容器支持。留意這些內容。
審核編輯:湯梓紅
-
內核
+關注
關注
3文章
1366瀏覽量
40236 -
Linux
+關注
關注
87文章
11232瀏覽量
208961 -
調試
+關注
關注
7文章
574瀏覽量
33901 -
文件系統
+關注
關注
0文章
284瀏覽量
19884 -
Sysfs
+關注
關注
0文章
15瀏覽量
6233
原文標題:8 其他Tracer工具
文章出處:【微信號:嵌入式與Linux那些事,微信公眾號:嵌入式與Linux那些事】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論