谢欢《Linux内核tracers的实现原理与应用》课程精彩答疑

Posted 宋宝华

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了谢欢《Linux内核tracers的实现原理与应用》课程精彩答疑相关的知识,希望对你有一定的参考价值。

作者简介

谢欢,大家可以叫我Jeff, 我目前就职于某国际知名linux发行版开源公司, 热衷于linux内核。我平时把linux内核源码当小说一样阅读学习,也一直把能给linux社区贡献更多有质量的代码而努力。

今年10月中旬,我向Linux内核社区提交了一个关于tracing 的patchset. tracing 的 Maintainer steve 和kprobe的maintainer Masami都非常感兴趣。

学员:Jeff老师,请教一下,您课程的理论和方法在arm+android环境下适用吗,实验是不是可以玩

Jeff老师:都可以玩,具体实现会跟架构不同有所区别,x86搞会了,其他的架构可以去套 

学员:function graph trace挂的第二个钩子函数 怎么返回到 parent函数的呢,这个返回值不是被覆盖了吗这块没交代 

Jeff老师:是的,这个地方没有交代,因为你会在kretprobe章节那里看到类似的逻辑,我当时是考虑从全局看不想讲两次一样的,如果想了解的话,parent被覆盖之前已经被保存了,在调用第二个钩子函数(return_to_handler)之后,会返回到parent处,代码如下:

SYM_FUNC_START(return_to_handler)

       subq  $24, %rsp 

       /* Save the return values */

       movq %rax, (%rsp)

        movq %rdx, 8(%rsp)

       movq %rbp, %rdi 

       call ftrace_return_to_handler 

       movq %rax, %rdi   <rax是ftrace_return_to_handler的返回值,也是parent的地址>

       movq 8(%rsp), %rdx

       movq (%rsp), %rax

       addq $24, %rsp

       JMP_NOSPEC rdi

Jeff老师与学员日常对话截取:

Jeff老师:其实讲解基本的使用不太费时间的,主要是讲解底层原理,确实要花不少时间,我自己也是一个刨根问底的人 

学员:基本使用网上也可以搜到一大堆教程,但是原理的东西才是难得地方。有老师带着学,我们可以事半功倍,搞懂了原理,再去使用工具,更加得心应手了 

老师如果有精力,也可以出一些内核子系统的实现讲解,就像ftrace这种讲法就挺好

Jeff老师:我是准备之后讲解block子系统的,从文件系统到多队列调度器以及块设备驱动,一个个来 

学员:jeff老师,我想打印这个函数里面的vq->last_used_index,用kprobe可以吗?

void *virtqueue_get_buf_ctx(struct virtqueue*_vq, unsigned int *len,

      void **ctx)

structvring_virtqueue *vq = to_vvq(_vq);

last_used =(vq->last_used_idx & (vq->vring.num - 1));

Jeff老师:可以,和函数参数相关的变量,直接用kprobe_event就可以

借助gdb 算偏移还算挺方便,如果你觉得麻烦,可以自己写一个kprobe模块插进去 。

学员:怎样用trace如何打出io从insert到complete中的函数栈 

Jeff老师:这个有挺多方法,就看怎么灵活运用,例如:

echo 0 > ./tracing_on 

echo 1 >./events/block/block_bio_queue/enable

echo traceon >./events/block/block_bio_queue/trigger

echo 1 >./events/block/block_rq_insert/enable

echo traceon >./events/block/block_rq_insert/trigger 

echo 1 >./events/block/block_rq_complete/enable

echo traceoff >  ./events/block/block_rq_complete/trigger

echo function >  current_tracer 

Jeff老师主动拉高学员的学习热情和讨论欲:

Jeff老师我最近想到一个idea,不再局限于跟踪函数,跟踪struct page,跟踪struct bio,跟踪struct task_struct,任何对象都可以动态跟踪,正在准备提个大补丁到社区去,看能不能合并进去。

学员甲:这个厉害了

学员乙:这个功能overhead高吗?

学员丙:比较有意思。大致原理是啥,访问内存的时候触发异常?

Jeff老师:到时候看我补丁,你会觉得简单的想哭

最新补丁进展:

https://lore.kernel.org/all/20211129164951.220511-1-xiehuan09@gmail.com/ 

学员自悟一刻:

“看到trace_event 有点晕了,我理解trace_event是不是就是一种静态的预埋的点, 当enable + filter后,输出信息到buffer中去?本身的实现和之前的ftrace其实没有关系?然后 老师说的 trace_event要多次展开, 各种unset 和define, 为何要多次呢?这里有点晕啊。

其实第一节课的内容能听懂,后面就都好懂了, 第四课的trace_event 我后来自己搜了一些文章看了一遍,再结合视频又听了一遍,能大致听懂 trace_event 的实现原理和逻辑,只是还是有刚才上面的疑问。本质上还是自己基础不扎实。

阅码场有人投稿写了trace_event的,我也搜到了,《LinuxTraceEvent - 我见过的史上最长宏定义

还是偏源码解析的,就是上来给你一坨代码,讲一遍过程,但是为何要这么做,就像老师讲的kprobe,原来是走int3,现在利用ftrace的5个nop,可以更方便使用,这个有前后关系的,其实就很好理解。

我好像悟了, TRACE_EVENT这一系列undef和define, 就是事先 给你用宏定义了好了若干个代码模板, 然后你用一个 宏定义 -TRACE_EVENT, 在经过不同模块的(子系统时),帮你生成对应逻辑的代码, 或者说,是内核约定了一个套路,各个模块 都按这个套路写, 然后帮你生成代码,说穿了就是一个静态代码生成器。

trace视频课程订阅二维码:

以上是关于谢欢《Linux内核tracers的实现原理与应用》课程精彩答疑的主要内容,如果未能解决你的问题,请参考以下文章

早鸟价今晚结束:Linux内核tracers的实现原理与应用

课程上新早鸟价:Linux内核tracers的实现原理与应用

谢欢:向linux内核引进object trace

如何选择一个Linux Tracer

如何选择一个 Linux Tracer

Linux 操作系统原理 — 内核态与用户态