执行 ./install/bin/staprun ./sigkill.ko 结果发现脚本执行命令刷屏了!!
debug_bin]$ ./install/bin/staprun ./sigkill.ko sig[17] SIGCHLD was sent to sh (pid:15237) by exec:ps -->:15239 uid:0 sig[17] SIGCHLD was sent to python (pid:12444) by exec:sh -->:15237 uid:0 sig[34] 0x22 was sent to wafd (pid:11041) by exec:swapper/0 -->:0 uid:0 sig[17] SIGCHLD was sent to sh (pid:15242) by exec:bp_tool -->:15243 uid:0 sig[17] SIGCHLD was sent to sh (pid:15242) by exec:awk -->:15244 uid:0 sig[17] SIGCHLD was sent to sh (pid:15240) by exec:ps -->:15241 uid:0 sig[17] SIGCHLD was sent to plat_srv (pid:3990) by exec:sh -->:15242 uid:0 sig[17] SIGCHLD was sent to python (pid:12444) by exec:sh -->:15240 uid:0 sig[17] SIGCHLD was sent to sh (pid:15245) by exec:bp_tool -->:15246 uid:0 sig[17] SIGCHLD was sent to sh (pid:15245) by exec:awk -->:15247 uid:0 sig[17] SIGCHLD was sent to plat_srv (pid:3990) by exec:sh -->:15245 uid:0 sig[17] SIGCHLD was sent to sh (pid:15248) by exec:bp_tool -->:15249 uid:0 sig[17] SIGCHLD was sent to sh (pid:15248) by exec:awk -->:15250 uid:0 sig[17] SIGCHLD was sent to plat_srv (pid:3990) by exec:sh -->:15248 uid:0 sig[17] SIGCHLD was sent to sh (pid:15251) by exec:ps -->:15252 uid:0 sig[17] SIGCHLD was sent to python (pid:12444) by exec:sh -->:15251 uid:0 sig[17] SIGCHLD was sent to sh (pid:15166) by exec:awk -->:15168 uid:0 sig[17] SIGCHLD was sent to sh (pid:15166) by exec:top -->:15167 uid:0 sig[17] SIGCHLD was sent to python (pid:7298) by exec:sh -->:15166 uid:0 sig[17] SIGCHLD was sent to sh (pid:15253) by exec:ps -->:15254 uid:0 sig[17] SIGCHLD was sent to sh (pid:15253) by exec:grep -->:15255 uid:0 sig[17] SIGCHLD was sent to sh (pid:15253) by exec:grep -->:15257 uid:0 sig[17] SIGCHLD was sent to sh (pid:15253) by exec:grep -->:15256 uid:0 sig[17] SIGCHLD was sent to python (pid:8626) by exec:sh -->:15253 uid:0 sig[17] SIGCHLD was sent to sh (pid:15258) by exec:cat -->:15264 uid:0 sig[17] SIGCHLD was sent to sh (pid:15258) by exec:head -->:15265 uid:0 sig[17] SIGCHLD was sent to sh (pid:15258) by exec:awk -->:15266 uid:0 sig[17] SIGCHLD was sent to python (pid:7298) by exec:sh -->:15258 uid:0 sig[17] SIGCHLD was sent to sh (pid:15259) by exec:ps -->:15260 uid:0
----------------------
sig[17] SIGCHLD was sent to python (pid:8626) by exec:sh -->:15278 uid:0
sig[17] SIGCHLD was sent to python (pid:6750) by exec:ethtool -->:15283 uid:0
sig[17] SIGCHLD was sent to python (pid:6750) by exec:ethtool -->:15284 uid:0
sig[17] SIGCHLD was sent to python (pid:6750) by exec:ethtool -->:15285 uid:0
sig[17] SIGCHLD was sent to python (pid:6750) by exec:ethtool -->:15286 uid:0
sig[17] SIGCHLD was sent to python (pid:6750) by exec:ethtool -->:15287 uid:0
sig[17] SIGCHLD was sent to python (pid:6750) by exec:ethtool -->:15288 uid:0
sig[17] SIGCHLD was sent to python (pid:6750) by exec:ethtool -->:15291 uid:0
sig[17] SIGCHLD was sent to python (pid:6750) by exec:ethtool -->:15289 uid:0
sig[17] SIGCHLD was sent to python (pid:6750) by exec:ethtool -->:15294 uid:0
想不通 为啥 要通过命令来获取信息, netlink 不香么!!
顺便看下 trace_event的实现,以kfree_skb为例
TRACE_EVENT(kfree_skb, TP_PROTO(struct sk_buff *skb, void *location), TP_ARGS(skb, location), TP_STRUCT__entry( __field( void *, skbaddr ) __field( void *, location ) __field( unsigned short, protocol ) ), TP_fast_assign( __entry->skbaddr = skb; __entry->location = location; __entry->protocol = ntohs(skb->protocol); ), TP_printk("skbaddr=%p protocol=%u location=%p", __entry->skbaddr, __entry->protocol, __entry->location) );
其大概意思是 将当前地址堆栈存在location 变量中;最后输出!!
来看下 trace_event的第一层展开:
#define TRACE_EVENT(name, proto, args, struct, assign, print) \ DECLARE_TRACE(name, PARAMS(proto), PARAMS(args))
#define TRACE_EVENT(name, proto, args, tstruct, assign, print) \ DECLARE_EVENT_CLASS(name, \ PARAMS(proto), \ PARAMS(args), \ PARAMS(tstruct), \ PARAMS(assign), \ PARAMS(print)); \ DEFINE_EVENT(name, name, PARAMS(proto), PARAMS(args));
根据tracepoint.h文件 主要函数为:DEFINE_EVENT 宏定义
#define DEFINE_EVENT(template, name, proto, args) \ DECLARE_TRACE(name, PARAMS(proto), PARAMS(args)) #define DECLARE_TRACE(name, proto, args) \ __DECLARE_TRACE(name, PARAMS(proto), PARAMS(args), \ cpu_online(raw_smp_processor_id()), \ PARAMS(void *__data, proto), \ PARAMS(__data, args))
#define __DECLARE_TRACE(name, proto, args, cond, data_proto, data_args) \ extern struct tracepoint __tracepoint_##name; \// tracepoint变量“__tracepoint_##name”本身 static inline void trace_##name(proto) \// tracepoint桩函数“trace_##name”的定义 { \ if (static_key_false(&__tracepoint_##name.key)) \ __DO_TRACE(&__tracepoint_##name, \ TP_PROTO(data_proto), \ TP_ARGS(data_args), \ TP_CONDITION(cond),,); \ if (IS_ENABLED(CONFIG_LOCKDEP) && (cond)) { \ rcu_read_lock_sched_notrace(); \ rcu_dereference_sched(__tracepoint_##name.funcs);\ rcu_read_unlock_sched_notrace(); \ } \ } \ __DECLARE_TRACE_RCU(name, PARAMS(proto), PARAMS(args), \ PARAMS(cond), PARAMS(data_proto), PARAMS(data_args)) \ static inline int \// tracepoint的回调函数注册函数"register_trace_##name" register_trace_##name(void (*probe)(data_proto), void *data) \ { \ return tracepoint_probe_register(&__tracepoint_##name, \ (void *)probe, data); \ } \ static inline int \ register_trace_prio_##name(void (*probe)(data_proto), void *data,\ int prio) \ { \ return tracepoint_probe_register_prio(&__tracepoint_##name, \ (void *)probe, data, prio); \ } \ static inline int \// tracepoint的回调函数反注册函数"unregister_trace_##name" unregister_trace_##name(void (*probe)(data_proto), void *data) \ { \ return tracepoint_probe_unregister(&__tracepoint_##name,\ (void *)probe, data); \ } \ static inline void \ check_trace_callback_type_##name(void (*cb)(data_proto)) \ { \ } \ static inline bool \ trace_##name##_enabled(void) \ { \ return static_key_false(&__tracepoint_##name.key); \ }
//桩函数中,逐个调用回调函数进行执行 #define __DO_TRACE(tp, proto, args, cond, prercu, postrcu) \ do { \ struct tracepoint_func *it_func_ptr; \ void *it_func; \ void *__data; \ \ if (!(cond)) \ return; \ prercu; \ rcu_read_lock_sched_notrace(); \ it_func_ptr = rcu_dereference_sched((tp)->funcs); \ if (it_func_ptr) { \ do { \ it_func = (it_func_ptr)->func; \ __data = (it_func_ptr)->data; \ ((void(*)(proto))(it_func))(args); \ } while ((++it_func_ptr)->func); \ } \ rcu_read_unlock_sched_notrace(); \ postrcu; \ } whil
TRACE_EVENT包含5个参数:(name, proto, args, struct, assign, print)
前面两个参数:proto, args,是给定义tracepoint使用的。在linux/tracepoint.h中构造tracepoint桩函数、callback regitser/unregister函数,在trace/define_trace.h中定义tracepoint变量。
后面三个参数:struct, assign, print,是给trace_event使用的。在trace/trace_events.h,构造trace_event的callback函数,注册到tracepoint。
TRACE_EVENT:
- 创建了一个tracepoint,可以放到kernel代码中;
- 创建了一个回调函数,可以被上述tracepoint调用
- 回调函数必须实现以最快的方式将传递给它的数据记录到trace ringbuffer中。
- 必须创建一个函数能解析从ringbuffer读出的数据,转换成便于用户理解的形式。
在define_trace.h中,宏TRACE_EVENT()第二次的展开:
#undef TRACE_EVENT #define TRACE_EVENT(name, proto, args, tstruct, assign, print) \ DEFINE_TRACE(name) //重新宏定义展开 #define DEFINE_TRACE(name) \ DEFINE_TRACE_FN(name, NULL, NULL); /* * We have no guarantee that gcc and the linker won't up-align the tracepoint * structures, so we create an array of pointers that will be used for iteration * on the tracepoints. */ #define DEFINE_TRACE_FN(name, reg, unreg) \ static const char __tpstrtab_##name[] \ __attribute__((section("__tracepoints_strings"))) = #name; \// 定义tracepoint变量“__tracepoint_##name”本身 struct tracepoint __tracepoint_##name \ __attribute__((section("__tracepoints"))) = \ { __tpstrtab_##name, STATIC_KEY_INIT_FALSE, reg, unreg, NULL };\// 将tracepoint变量指针"__tracepoint_ptr_##name"存放到section("__tracepoints_ptrs") static struct tracepoint * const __tracepoint_ptr_##name __used \ __attribute__((section("__tracepoints_ptrs"))) = \ &__tracepoint_##name;
在随后的trace_events.h中,宏TRACE_EVENT()又进行了多次的展开。宏定义重复多次定义多次展开
太恶心了 !! 以为很简单 结果一个宏定义都这复杂
tracepoint.h trace_events.h define_trace.h
这几个文件看的有点蒙蔽
下次要是需要写trace_point 在继续研究!! 继续打游戏
参考:Using the TRACE_EVENT() part1