zoukankan      html  css  js  c++  java
  • trace、perf、eBPF使用

    内核文档:
    https://www.kernel.org/doc/html/latest/trace/ftrace.html
    https://www.kernel.org/doc/html/latest/trace/kprobetrace.html
    https://www.kernel.org/doc/html/latest/trace/uprobetracer.html
    https://www.kernel.org/doc/html/latest/trace/tracepoints.html
    https://www.kernel.org/doc/html/latest/trace/events.html
    https://www.kernel.org/doc/html/latest/trace/events-kmem.html
    https://www.kernel.org/doc/html/latest/trace/mmiotrace.html
    https://www.kernel.org/doc/html/latest/bpf/index.html#
    https://github.com/iovisor/bpftrace
    https://github.com/iovisor/bpftrace/blob/master/docs/reference_guide.md
    https://github.com/iovisor/bcc
    https://github.com/iovisor/bcc/blob/master/docs/tutorial.md

    ftrace

    • 获取某个进程调用sys_open的调用栈
      运行要trace的程序,然后在调用open之前挺住,接着执行下面的命令,最后接着执行程序
      echo function_graph > /sys/kernel/debug/tracing/current_tracer
      echo *sys_open > /sys/kernel/debug/tracing/set_graph_function
      #echo 1 > /sys/kernel/debug/tracing/options/funcgraph-tail
      echo <pid> > /sys/kernel/debug/tracing/set_ftrace_pid
      echo 0 > /sys/kernel/debug/tracing/tracing_on
      echo > /sys/kernel/debug/tracing/trace
      echo 3 > /proc/sys/vm/drop_caches
      echo 1 > /sys/kernel/debug/tracing/tracing_on
      
      然后执行下面的命令导出trace:
      echo 0 > /sys/kernel/debug/tracing/tracing_on
      cat /sys/kernel/debug/tracing/trace > trace.log
      
      对于function_graph抓到的调用栈,可以使用内核提供的vim插件来阅读:Documentation/trace/function-graph-fold.vim
      用法: vim trace.log -S Documentation/trace/function-graph-fold.vim

    trace-cmd

    • 抓取某个进程调用sys_open的调用栈
      sudo trace-cmd record -p function_graph -g *sys_open -P <pid>
      可以先让进程在调用open之前停住,用sleep或者getchar,执行上面的命令后,再继续执行
      最后执行下面的命令导出trace:
      trace-cmd report > trace.log

    kprobe

    • 打印open时的文件名
      echo 'p:myprobe do_sys_open file=+0(%si):string' > kprobe_events
      可以通过format查看log的输出格式:
      root@ubuntu:/sys/kernel/debug/tracing# cat events/kprobes/my_probe/format
      name: my_probe
      ID: 2072
      format:
          field:unsigned short common_type;       offset:0;       size:2; signed:0;
          field:unsigned char common_flags;       offset:2;       size:1; signed:0;
          field:unsigned char common_preempt_count;       offset:3;       size:1; signed:0;
          field:int common_pid;   offset:4;       size:4; signed:1;
      
          field:unsigned long __probe_ip; offset:8;       size:8; signed:0;
          field:__data_loc char[] file;   offset:16;      size:4; signed:1;
      
      print fmt: "(%lx) file=\"%s\"", REC->__probe_ip, __get_str(file)
      
      可以通过filter设置过滤条件:
      echo 'file=="setproxy.sh"' > events/kprobes/my_probe/filter
      使能:
      echo 1 > events/kprobes/my_probe/enable
      下面是输出的log:
      cat trace 或者 cat trace_pipe
      cat-753     [001] ....  3406.761327: my_probe: (do_sys_open+0x0/0x80) file="setproxy.sh"
      
      可以在输出log的时候,打印open的调用栈:
      echo 1 > options/stacktrace
      可以从trace中看到如下的log:
               cat-772     [000] ....  3650.530789: my_probe: (do_sys_open+0x0/0x80) file="setproxy.sh"
               cat-772     [000] ....  3650.530980: <stack trace>
      => do_sys_open
      => do_syscall_64
      => entry_SYSCALL_64_after_hwframe
      
      对于不同的体系架构,进行函数调用时使用的传参规则并不相同,所以在使用kprobe提取函数参数时使用的方式也不
      相同,为了解决这一问题,内核引入了一个patch:a1303af5d79eb13a658633a9fb0ce3aed0f7decf解决了这一问题,
      使用argX来代表参数,比如上面的这个file=+0(%si):string可以替换为file=+0($arg2):string,因为
      filename是第2个参数,这里参数编号 是从1开始的。关于参数的解析可以参考内核代码:
      kernel\trace\trace_probe.c:parse_probe_arg
      下面是常见的处理器的函数传参规则:
    体系架构 参数1 参数2 参数3 参数4 参数5 参数6 参数7 参数8 参数9
    x86 stack
    x86_64 rdi rsi rdx rcx r8 r9 stack
    arm r0 r1 r2 r3 stack
    arm64 x0 x1 x2 x3 x4 x5 x6 x7 stack

    uprobe

    bpftrace

    • 使用kprobe打印函数入口参数:
    bpftrace -e 'kprobe:shmem_user_xattr_handler_set {printf("filename = %s, value = %s size = %d flag = %x\n", str(arg3), str(arg4), arg5, sarg0)}''
    
    Attaching 1 probe...
    filename = shmem_backend_file, value = ./memory_backend.img size = 20 flag = 1
    filename = shmem_backend_file, value =  size = 0 flag = 0
    

    需要注意的是,arg从0开始,对于存放在栈里的参数,可以使用sarg来提取,函数原型:

    static int shmem_user_xattr_handler_set(const struct xattr_handler *handler,
    >------->------->------->-------   struct dentry *unused, struct inode *inode,
    >------->------->------->-------   const char *name, const void *value,
    >------->------->------->-------   size_t size, int flags)
    
    #include <linux/mm.h>
    
    kprobe:shmem_writepage
    {
            printf("Page: 0x%x, Index: 0x%x\n", arg0, ((struct page *)arg0)->index);
    }
    

    perf

  • 相关阅读:
    坐标转换convertRect
    error this is not a media message!!!
    嵌入式-第一季-第4课
    嵌入式-第一季-第2课
    嵌入式-第一季-第3课
    嵌入式-第一季-第1课
    web-15. 事件与函数
    web-14. 表达式与程序流程
    web-13. 数组和字符串
    数据-第5课-线性表的本质
  • 原文地址:https://www.cnblogs.com/pengdonglin137/p/15533392.html
Copyright © 2011-2022 走看看