技术标签: ftrace
1.Ftrace实现原理
1.1.Ftrace function tracer footstone: -pg
当CONFIG_FUNCTION_TRACER打开时,编译时会增加-pg编译选项,gcc会在每个函数的入口处增加对mcount的调用。
ftrace 支持动态trace,即可以跟踪内核和模块中任意的全局函数。它利用了gcc的-pg编译选项,在每个函数的开始增加一个stub,这样在需要的时候可以控制函数跳转到指定的代码中去执行。使用 -pg 选项会在编译得到的内核映像中加入大量的调试信息。一般情况下,只是在开发测试阶段激活 ftrace 支持,以调试内核,修复 bug 。最终用于发行版的内核则会关闭 -pg 选项,也就无法使用 ftrace。
对于动态ftrace,有一个很重要的工作就是记录这些被-pg影响的函数,通过读文件/sys/kernel/debug/tracing/available_filter_functions来查看哪些函数是支持trace的。
1 #include <stdio.h>
2
3 int main()
4 {
>> 5 int a = 0;
6 return 0;
7 }
当用户打开 ftrace 功能时,ftrace 将这些 nop 指令动态替换为 ftrace_caller,该函数将调用用户注册的 trace 函数。其具体的实现在相应 arch 的汇编代码中,以 x86 为例,在 entry_32.s 中:
内核代码编译:
scripts/Makefile.build:
201 ifdef CONFIG_FTRACE_MCOUNT_RECORD
202 ifndef CC_USING_RECORD_MCOUNT
203 # compiler will not generate __mcount_loc use recordmcount or recordmcount.pl
204 ifdef BUILD_C_RECORDMCOUNT
205 ifeq ("$(origin RECORDMCOUNT_WARN)", "command line")
206 RECORDMCOUNT_FLAGS = -w
207 endif
208 # Due to recursion, we must skip empty.o.
209 # The empty.o file is created in the make process in order to determine
210 # the target endianness and word size. It is made before all other C
211 # files, including recordmcount.
212 sub_cmd_record_mcount = \
213 if [ $(@) != "scripts/mod/empty.o" ]; then \
214 $(objtree)/scripts/recordmcount $(RECORDMCOUNT_FLAGS) "$(@)"; \
215 fi;
216 recordmcount_source := $(srctree)/scripts/recordmcount.c \
217 $(srctree)/scripts/recordmcount.h
218 else
219 sub_cmd_record_mcount = set -e ; perl $(srctree)/scripts/recordmcount.pl "$(ARCH)" \
220 "$(if $(CONFIG_CPU_BIG_ENDIAN),big,little)" \
221 "$(if $(CONFIG_64BIT),64,32)" \
222 "$(OBJDUMP)" "$(OBJCOPY)" "$(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS)" \
223 "$(LD) $(KBUILD_LDFLAGS)" "$(NM)" "$(RM)" "$(MV)" \
224 "$(if $(part-of-module),1,0)" "$(@)";
225 recordmcount_source := $(srctree)/scripts/recordmcount.pl
226 endif # BUILD_C_RECORDMCOUNT
227 cmd_record_mcount = \
228 if [ "$(findstring $(CC_FLAGS_FTRACE),$(_c_flags))" = \
229 "$(CC_FLAGS_FTRACE)" ]; then \
230 $(sub_cmd_record_mcount) \
231 fi;
232 endif # CC_USING_RECORD_MCOUNT
233 endif # CONFIG_FTRACE_MCOUNT_RECORD
279 define rule_cc_o_c
280 $(call echo-cmd,checksrc) $(cmd_checksrc) \
281 $(call cmd_and_fixdep,cc_o_c) \
282 $(cmd_checkdoc) \
283 $(call echo-cmd,objtool) $(cmd_objtool) \
284 $(cmd_modversions_c) \
285 $(call echo-cmd,record_mcount) $(cmd_record_mcount)
286 endef
301 # Built-in and composite module parts
302 $(obj)/%.o: $(src)/%.c $(recordmcount_source) $(objtool_dep) FORCE
303 $(call cmd,force_checksrc)
304 $(call if_changed_rule,cc_o_c)
include/asm-generic/vmlinux.lds.h :
112 #ifdef CONFIG_FTRACE_MCOUNT_RECORD
113 #define MCOUNT_REC() . = ALIGN(8); \
114 __start_mcount_loc = .; \
115 KEEP(*(__mcount_loc)) \
116 __stop_mcount_loc = .;
117 #else
118 #define MCOUNT_REC()
119 #endif
最终内核的链接脚本include/asm-generic/vmlinux.lds.h将__mcount_loc段的内容放在.init.data段中,并且通过__start_mcount_loc和__stop_mcount_loc两个全局符号来访问。
1.2.ftrace初始化
gcc的-pg 选项在每个函数开始处增加了一条callq指令,它和对应的retq据统计会带来13%的性能开销,因此在内核的初始化阶段将这些callq指令全部修改为5 Byte的NOP指令: 66 66 66 66 90H,同时将这些指令的地址记录下来。
scripts/recordmcount.pl过滤了kernel/trace/ftrace.o,没有为其增加__mcount_loc段,所以ftrace代码不会修改其自身的代码。ftrace_init在start_kernel中调用,早于kernel_init,此时不会有其它Core正在执行代码,因此也不用担心修改指令导致其它Core出现crash(系统运行时修改指令就要麻烦很多:被修改的指令正在其它Core上执行,5个字节的指令有可能跨两个cache line)。由于ftrace_init执行时间较早,所以.initcall中的初始化函数都是可以被trace的(在cmdline中增加"ftrace_filter="参数来指定要trace的函数)。
6159 void __init ftrace_init(void)
6160 {
6161 extern unsigned long __start_mcount_loc[];
6162 extern unsigned long __stop_mcount_loc[];
6163 unsigned long count, flags;
6164 int ret;
6165
6166 local_irq_save(flags);
6167 ret = ftrace_dyn_arch_init();
6168 local_irq_restore(flags);
6171
6172 count = __stop_mcount_loc - __start_mcount_loc;
6180
6181 last_ftrace_enabled = ftrace_enabled = 1;
6182
6183 ret = ftrace_process_locs(NULL,
6184 __start_mcount_loc,
6185 __stop_mcount_loc);
6186
6187 set_ftrace_early_filters();
6188
6189 return;
6190 failed:
6191 ftrace_disabled = 1;
6192 }
在ftrace_process_locs函数中,内核为__start_mcount_loc和__stop_mcount_loc之间的每个地址都创建一个struct dyn_ftrace结构,其中ip记录着函数开始的stub地址,ftrace_code_disable函数会将这个地址的内容替换为nop指令,这样在没有trace时,系统的性能几乎没有影响。
当用户打开 ftrace 功能时,ftrace 将这些 nop 指令动态替换为 ftrace_caller,该函数将调用用户注册的 trace 函数。其具体的实现在相应 arch 的汇编代码中,以 x86 为例,在 entry_32.s 中:
当开始trace时,内核根据函数名找到ip,将该地址处的nop指令修改为call指令,以控制其跳转到指定的位置。
以 MIPS 为例:arch/mips/kernel/ftrace.c
代码:
refer to
event实际上描述的是一种同步的处理事件,可以简单地理解为,不同的进程之间可以利用一些特殊的处理来等待其他进程处理完毕在event类同步处理时,多个进程将拥有用一个event实例,当调用wait()方法是将进入到阻塞状态,同时会设置阻塞标记为“False”,(待阻塞标记为“True"后才会接触阻塞状态),此时另外一个进程可以继续工作,并且通过set()方法将阻塞标记设置为“True”,这样之前...
需要打开中文文件名的链接,例如 http://www.abc.com/站点说明/文件1.txt 用英文名字文件可以打开: http://www.abc.com/zhandianshuoming/wenjian1.txt 但是用 http://www.abc.com/站点说明/文件1.txt 就无法访问,怎么解决? ---------------------------------
两个有效方法解决edge浏览器主页篡改_edge浏览器主页被篡改
2019独角兽企业重金招聘Python工程师标准>>> ...
谨在《无感无刷直流电机之电调设计全攻略》文章基础上做补充电调开发难易排序:低压低速小负载有感电调 --- 高压高速大负载无感电调要注意的事项:内转子还是外转子电机、mos管选型、mos管限流电阻选取、mos管栅极驱动器选择、高低压分离、大电压回路、布局(寄生电感)、电流采样电阻功率、电流放大电路(差压取观测点)、ad直接采样的时间选取、硬件过零检测的滤波电容和分压电阻选择、电压比较器的供..._无感电调原理
前记: 我最初想将这些总结写到私密笔记本里,自己知道就好,不发表在博客,因为我怕,各种怕。没错,我一直都处在这些“怕”中。这或许是小时候生活在惧怕中的缘故。小时候特别怕严厉的父亲,幼小的心灵面对“阴森恐怖”的父亲(长大发现父亲还是很尊重我的想法),如果你还有抗争的想法,那就说明你的父亲还不够具有威慑力。这直接导致以下结果:1)主见不强。别人说去哪吃饭,我说随便;别人叫我点菜_研究生三年具体干嘛
尝试方法一:采用v-if,当列表请求成功后,再渲染swiper。结果依然不能正常渲染尝试方法二:采用nextTick,当页面加载完成后,再渲染swiper结果还是不能正常渲染尝试方法三:采用定时器在nextTick中加一个200的定时器,结果可以正常渲染了!!! onMounted(() => { nextTick(() => { setTimeout(()=>{ _swiper动态改变数据重新渲染页面
思路:求次小生成树和最小生成树。#include#include#includeusing namespace std;const int inf=1<<30;const int maxn=111;int ans1,ans2;int dis[maxn];int map[maxn][maxn];int iToj[maxn][maxn];int vis[maxn];int u_举例说明最小生成树不唯一
(1)使用Swiper中的属性var mySwiper = new Swiper('.swiper-container', { observer: true,//修改swiper自己或子元素时,自动初始化swiper observeParents: true,//修改swiper的父元素时,自动初始化swiper })(2)可能是因为页面图片太多导致图片未加载完,就把Swiper组件初始化了,所以导致图片显示不全或者..._swiper动态加载数据没有加载全部
本法重点是驱动与版本的选择!!!如果不知道驱动与版本请认真看教程选择正确的版本镜像进行烧录。创作快乐!!!_atlas200dk
package edu.uci.ics.crawler4j.url;import java.net.MalformedURLException;import java.net.URI;import java.net.URISyntaxException;import java.net.URL;import java.net.URLDecoder;import java.net.URLEncoder..._canonicalize
做了不少qp,BC渗透了,通宵了2个晚上干了几个盘子,简略的说下过程,做一下总结。首先说一下qp, 以我的渗透成功案例来说的话首先信息收集必不可少的,qp的特点是什么呢?他的后台会在服务器域名的后面以不同的端口形式架设 如图:关于端口可以发现,基础东西你们都懂。切入点:在app里面抓包,查找邮箱,充值的地方寻找sql注入或者意见反馈的位置XSS有一种情况是抓包显示127.0.0.1的抓不到包的情况,这种情况多于大盘子,它不一定走的是TCP UDP协议。可以参考T-ice表哥说的 P.._bc漏洞