很慚愧,搞了這麼久的linux開發,以前測試不管是用ftrace仍是perf也好,都沒有認真的去了解tracepoint的實現,此次正好linux
開發的代碼中須要設計一個tracepoint,便於後期調試使用,因此趁此機會,瞭解下tracepoint在內核裏面的編寫。ide
你真的知道trace的原理嗎?這裏大體介紹下tracepoint的大體原理,和kprobe相比,tracepoint是一個安靜的乖孩子,只有在內核裏面編寫好才能使用函數
而kprobe不同,可動可靜,是一個活力十足的假小子,tracepoint實現是基於hooks的思想,function trace是利用gcc編譯器初期測試
在函數的入口就被放置一個probe點,也俗稱打樁,這個probe點就會跟蹤調用這個函數的各類信息,例如進程,地址,棧信息等,debug
並將追蹤的信息保存到一個環形隊列中去,若是用戶但願讀取這些內核,就會經過debugfs形式來訪問,因此有時候我在想是否是能夠設計
寫一個程序,去專門監控trace環形隊列佔用的內存狀況(有點跑偏了),下面從網上找的一張圖介紹下這個trace的調用流程。調試
去實現一個tracepoint
實現一個tracepoint是很簡單的事,尤爲是有經驗的內核開發同窗,你只須要看下Documentation/trace/相關文檔介紹,在看看blog
內核裏面任何一個tracepoint的實現patch, 基本就能夠照葫蘆畫瓢去弄了,至少我在寫tracepoint的時候就是這麼弄的,頗有意思。隊列
咱們須要定義一個tracepint的頭文件,最好和你想要跟蹤的function所在的目錄或者相關頭文件放在一塊兒。進程
例如我這裏定義trace_myself.h文件
// trace_myself.h
#undef TRACE_SYSTEM #define TRACE_SYSTEM myself
#if !defined(__TRACE_MYSELF_H__) || defined(TRACE_HEADER_MULTI_READ)
#define __TRACE_MYSELF_H__#include <linux/tracepoint.h> // 此處是很是關鍵的地方,設計到你要追蹤的函數的的相關內容做爲參數// 爲了方便,這裏將參數設置爲unsiged short形式TRACE_EVENT(myself_tp,
TP_PROTO(unsigned short dest, unsigned short source), TP_ARGS(dest, source), // 定義兩參數名稱爲dest和source TP_STRUCT__entry( // 此處本人理解爲打樁時候分配的環形隊列時指定的做用域,說白了就是大小和attr。 __field(unsigned short, dest) __field(unsigned short, source) ), TP_fast_assign( __entry->dest = dest; // 將trace的函數的內容拷貝到環形隊列中去 __entry->source = source; ), TP_printk("dest:%d, source:%d", __entry->dest, __entry->source) // 打印你所指望的內容 ); #endif // 此處定義完成後,僅僅是類型定義成功
// 下一步咱們須要指定頭文件所在的目錄,而且定義頭文件的名稱
#undef TRACE_INCLUDE_PATH #define TRACE_INCLUDE_PATH . #define TRACE_INCLUDE_FILE trace_myself // 這就是該頭文件的名字 #include <trace/define_trace.h>
到這一步,只能算是你tracepoint function實現了,可是怎麼編譯和在代碼中添加,又有不少規則須要注意
ccflags-y += -I$(src) # needed for trace events
就是這麼簡短的一句,可是非加不可,若是不加,可定是不行的,gcc編譯的時候會查找相關頭文件,這告訴編譯器,此處的頭文件也要包含。
step3: 在trace裏的函數加入tracepoint
//此處須要知道的是trace的函數所在的文件裏必須包含CREATE_TRACE_POINTS
//而且必須在頭文件以前,雖然不理解,可是仍是的遵照
#define CREATE_TRACE_POINTS
#include "test_tp.h" #include <net/protocol.h> #include <linux/ip.h> #include <linux/udp.h> int test(unsiged short dst, unsiged short src) { dst = src + 5;// 這裏增長一個tracepoint點 trace_myself(dst, src);
return 0; } int init_module(void) { int ret = 0, dest = 5, src = 5;
ret = test(dest, src); if (ret) { printk("failed\n"); return ret; } return 0; }
void cleanup_module(void) {
printk("failed\n");
} int init_module(void); void cleanup_module(void); MODULE_LICENSE("GPLv2");