tracepoint你真的了解吗?

前言

很惭愧,搞了这么久的linux开发,之前测试无论是用ftrace还是perf也好,都没有认真的去了解tracepoint的实现,这次正好

开发的代码中需要设计一个tracepoint,便于后期调试使用,所以趁此机会,了解下tracepoint在内核里面的编写。

你真的知道trace的原理吗?

这里大致介绍下tracepoint的大致原理,和kprobe相比,tracepoint是一个安静的乖孩子,只有在内核里面编写好才能使用

而kprobe不一样,可动可静,是一个活力十足的假小子,tracepoint实现是基于hooks的思想,function trace是利用gcc编译器初期

在函数的入口就被放置一个probe点,也俗称打桩,这个probe点就会跟踪调用这个函数的各种信息,例如进程,地址,栈信息等,

并将追踪的信息保存到一个环形队列中去,如果用户希望读取这些内核,就会通过debugfs形式来访问,所以有时候我在想是不是可以

写一个程序,去专门监控trace环形队列占用的内存情况(有点跑偏了),下面从网上找的一张图介绍下这个trace的调用流程。

去实现一个tracepoint

实现一个tracepoint是很简单的事,尤其是有经验的内核开发同学,你只需要看下Documentation/trace/相关文档介绍,在看看

内核里面任何一个tracepoint的实现patch, 基本就可以照葫芦画瓢去弄了,至少我在写tracepoint的时候就是这么弄的,很有意思。

step1: 实现一个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实现了,但是怎么编译和在代码中添加,又有很多规则需要注意

step2: 加入到makefile中去

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 "); return ret; } return 0; }
void cleanup_module(void) {
  printk("failed
");
} 

int init_module(void); void cleanup_module(void); MODULE_LICENSE("GPLv2");
是时候好好总结下自己走过的路。
原文地址:https://www.cnblogs.com/haoxing990/p/14672590.html