很惭愧,搞了这么久的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");