泰晓科技 -- 聚焦 Linux - 追本溯源,见微知著!
网站地址:https://tinylab.org

基于泰晓RISC-V实验箱的Linux公开课
请稍侯

RISC-V Ftrace 实现原理(7)- RISC-V 架构总结

Song Shuai 创作于 2023/02/09

Corrector: TinyCorrect v0.1 - [codeblock] Author: sugarfillet sugarfillet@yeah.net Date: 2022/12/01 Revisor: Falcon falcon@tinylab.org Project: RISC-V Linux 内核剖析 Proposal: RISC-V ftrace 相关技术调研与分析 Sponsor: PLCT Lab, ISCAS

前言

Linux 在 RISC-V 架构的 Ftrace 特性目前已提供基本的函数跟踪(HAVE_FUNCTION_TRACER)和函数图跟踪能力(HAVE_FUNCTION_GRAPH_TRACER),但相比成熟的 x86_64 以及 arm64 还是有不少需要优化或者补充的地方。

本文以 include/linux/ftrace.h 以及 kernel/trace/ftrace.c 文件中描述的一些需要架构实现的功能或接口为基础对 ftrace 在 RISC-V 架构上已实现和待实现的功能进行整理,并对已经在上游有初步实现的功能进行背景介绍和解读。

说明

  • 本文的 Linux 版本采用 Linux v6.0

RISC-V ftrace 功能实现状态表

FunctionDescriptionRISC-V statusReferences
HAVE_FUNCTION_TRACER支持 static function tracerok10626c32e382
HAVE_FUNCTION_GRAPH_TRACER支持 static function_graph tracerok10626c32e382
prepare_ftrace_return默认的函数图跟踪函数ok 
return_to_handler函数图跟踪返回处理例程ok 
HAVE_FTRACE_MCOUNT_RECORDrecordmcount.pl 支持 RISC-V 架构的 __mcount_loc 创建oka1d2a6b4cee8
HAVE_DYNAMIC_FTRACE动态 ftrace 支持okc15ac4fd60d5 / bc1a4c3a8425
ftrace_caller动态 ftrace 实现的 mcountok 
ftrace_callftrace_caller 中调用跟踪函数的 labelok 
ftrace_make_nop替换函数入口为 nopok 
ftrace_make_call替换函数入口为对 ftrace_[regs]_caller 的调用ok 
ftrace_update_ftrace_func跟踪函数替换接口ok 
ftrace_enable_ftrace_graph_caller开启函数图跟踪ok 
ftrace_disable_ftrace_graph_caller关闭函数图跟踪ok 
ftrace_init_nopftrace_init 阶段对函数入口执行 nop 替换ok 
ftrace_need_init_nopftrace_init 阶段判断是否对函数入口执行 nop 替换ok 
HAVE_DYNAMIC_FTRACE_WITH_REGS为跟踪函数提供 pt_regs 访问okaea4c671fb98
ftrace_regs_callerREGS 版本的 ftrace_callerok 
ftrace_regs_callREGS 版本的 ftrace_callok 
ftrace_modify_call修改函数入口的跳转ok 
ARCH_SUPPORTS_FTRACE_OPS使能 ops 作为跟踪函数的第 3 个参数ok71e736a7d655
HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS提供 register_ftrace_direct[_multi] 接口wip 
HAVE_SAMPLE_FTRACE_DIRECT提供 register_ftrace_direct 接口的实例代码wip 
HAVE_SAMPLE_FTRACE_DIRECT_MULTI提供 register_ftrace_direct_multi 接口的实例代码wip 
FTRACE_GRAPH_TRAMP_ADDR独立的函数图跟踪跳板no_need 
ftrace_graph_caller独立的函数图跟踪跳板no_need 
arch_ftrace_update_trampoline动态 tramplineno 

HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS

此功能以 register_ftrace_function 函数为基础提供 register_ftrace_direct_[multi] 函数接口,使得用户可以直接编写类似于 ftrace_caller 的跳板代码 – direct_caller 来实现对目标函数的直接跟踪。HAVE_SAMPLE_FTRACE_DIRECTHAVE_SAMPLE_FTRACE_DIRECT_MULTI 则在 ./samples/ftrace/ 目录下提供 direct_caller 的示例代码。

RISC-V 当前的实现可参考 “riscv: ftrace: Add DYNAMIC_FTRACE_WITH_DIRECT_CALLS support”“samples: ftrace: Add riscv support for SAMPLE_FTRACE_DIRECT[_MULTI]”

FTRACE_GRAPH_TRAMP_ADDR

function_graph tracer 目前通过在 ftrace_[regs]_caller 的跟踪函数调用后,为默认的函数图跟踪函数 prepare_ftrace_return 设置参数并调用。如此情况下,会引入一个问题:某个目标函数没有开启函数跟踪,只开启图跟踪,则 ftrace_[regs]_caller 对跟踪函数 ftrace_stub 的参数设置和调用还是会执行。那么,能否让只开启图跟踪的函数直接去调用 prepare_ftrace_return 呢?对于此问题,思路有二:

  1. 创建一个只作函数图跟踪的跳板,通过 graph_ops->trampoline 来指定,并在执行函数入口替换时采用前者进行替换
  2. 能否直接把 prepare_ftrace_return 当作一个普通的跟踪函数,这样就可以去掉原来 ftrace_[regs]_caller 后面的对 prepare_ftrace_return 的参数设置和调用

第一个思路的答案就是 FTRACE_GRAPH_TRAMP_ADDR 以及 ftrace_graph_caller,但在 RISC-V 架构下会与现有图跟踪机制不兼容。而第二个思路就不存在兼容问题,其具体的实现,可参考 “riscv: ftrace: Add ftrace_graph_func”“riscv: ftrace: Make ftrace_caller call ftrace_graph_func”

arch_ftrace_update_trampoline

有这样一种情况:如果用 function tracer (global_ops) 来跟踪所有内核函数,再用 kprobe_ops 跟踪了某个函数 A,那么跟踪函数会被选择为 arch_ftrace_ops_list_func,此函数在 ftrace 实现原理(4)- 替换跟踪函数) 一文中提到过。

arch_ftrace_ops_list_func,执行时会遍历 ftrace_ops_list,结合 ops->func_hash 来判断是否需要对当前 ip 执行 ops->func。

那么除了 A 以外的函数执行时,首先跳转到 ftrace_caller,再调用 arch_ftrace_ops_list_func,都会匹配 kprobes_ops->func_hash,这显然是没有必要的。动态 trampoline 在 ops 注册时为其动态分配一个 trampoline,trampoline 中调用的跟踪函数即是 ops->func,这样的话,前文中的除了 A 以外的函数都会跳转到 global_ops 注册时动态分配的 trampoline,而不是默认的 ftrace_caller,并在动态 trampoline 中调用 global_ops->func,而不是 arch_ftrace_ops_list_func,这样就很好的解决了前述的问题。详细地可参考 commit f3bea49115b2 (“ftrace/x86: Add dynamic allocated trampoline for ftrace_ops”)。

>>>>> enable function tracer on all functions AND kprobes on func_A

func_A        -> ftrace_regs_caller ---\
                                        -> arch_ftrace_ops_list_func (global_ops && kprobe_ops)
func_others   -> ftrace_caller      ---/
>>>>> enable dynamic trampoline optimization

func_A        -> ftrace_regs_caller -----> arch_ftrace_ops_list_func (global_ops && kprobe_ops)

func_others   -> dynamic trampoline -----> global_ops->func

arch_ftrace_update_trampoline 就是用来在 ops 注册时,创建动态 trampoline 的架构实现。当前 RISC-V 还不支持。

小结

本文对 RISC-V 架构下 ftrace 特性的实现进行了总结,同时也指出了一些待实现的功能,并对已经在上游有初步实现的功能进行了背景介绍和解读。这里希望 HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLSFTRACE_GRAPH_TRAMP_ADDR 相关补丁能尽快合入主线,也希望动态 trampoline 功能能尽快实现。

参考资料



Read Album:

Read Related:

Read Latest: