zoukankan      html  css  js  c++  java
  • stap signal && trace point

    执行  ./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

    trace point example

    http代理服务器(3-4-7层代理)-网络事件库公共组件、内核kernel驱动 摄像头驱动 tcpip网络协议栈、netfilter、bridge 好像看过!!!! 但行好事 莫问前程 --身高体重180的胖子
  • 相关阅读:
    15.Linux的文件结构
    14.管道模型
    13.ubuntu下Qt5无法使用中文的问题解决
    12.时钟与信号
    11.进程控制
    10.设备文件
    [GXOI/GZOI2019]旅行者
    [GXOI/GZOI2019]旧词
    [BJOI2019] 删数
    [BJOI2019] 光线
  • 原文地址:https://www.cnblogs.com/codestack/p/15095828.html
Copyright © 2011-2022 走看看