linux trace机制分析 - 3.ftrace原理分析

简述

默认本篇文章的读者已经了解arm、编译和简单汇编。
arm64采用fpatchable-function-entry而不是pg,这里暂不讨论,扩展了解https://zhuanlan.zhihu.com/p/104683907。

简单叙述ftrace的原理和流程,ftrace的实现依赖3个过程,分别为编译、链接重定位、系统初始化、开启追踪。

  • 编译时:内核开启CONFIG_FUNCTION_TRACER后,编译选项会增加-pg,在每个函数中打上标记;
  • 链接重定位:将编译时标记链接到处理函数;
  • 系统初始化:将函数标记替换为nop指令;
  • 开启追踪:将函数标记替换为ftrace_caller,记录信息。

编译时处理

  1. 当内核开启CONFIG_FUNCTION_TRACER时,kernel Makefile会在编译参数增加-pg。
# The arch Makefiles can override CC_FLAGS_FTRACE. We may also append it later.
ifdef CONFIG_FUNCTION_TRACER
  CC_FLAGS_FTRACE := -pg
endif
  1. 示例驱动代码
int func2(int p1, int p2)
{
        return p1+p2;
}

int func1(int p1, int p2)
{
        return func2(p1, p2);
}

static int __init hello_init(void)
{
    pr_info("hello driver init!\n");
    func1(1, 2);
    return 0;
}

static void __exit hello_exit(void)
{
    pr_info("hello driver exit\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
  1. 未开启CONFIG_FUNCTION_TRACER 时,objdump -d如下:
00000000 <func2>:
   0:   e1a0c00d        mov     ip, sp
   4:   e92dd800        push    {fp, ip, lr, pc}
   8:   e24cb004        sub     fp, ip, #4
   c:   e0800001        add     r0, r0, r1
  10:   e89da800        ldm     sp, {fp, sp, pc}

00000014 <func1>:
  14:   e1a0c00d        mov     ip, sp
  18:   e92dd800        push    {fp, ip, lr, pc}
  1c:   e24cb004        sub     fp, ip, #4
  20:   e0800001        add     r0, r0, r1
  24:   e89da800        ldm     sp, {fp, sp, pc}

Disassembly of section .init.text:

00000000 <init_module>:
   0:   e1a0c00d        mov     ip, sp
   4:   e92dd800        push    {fp, ip, lr, pc}
   8:   e24cb004        sub     fp, ip, #4
   c:   e59f0008        ldr     r0, [pc, #8]    ; 1c <init_module+0x1c>
  10:   ebfffffe        bl      0 <_printk>
  14:   e3a00000        mov     r0, #0
  18:   e89da800        ldm     sp, {fp, sp, pc}
  1c:   00000000        .word   0x00000000
  1. 开启CONFIG_FUNCTION_TRACER 时,objdump -d如下:
00000000 <func2>:
   0:   e1a0c00d        mov     ip, sp
   4:   e92dd800        push    {fp, ip, lr, pc}
   8:   e24cb004        sub     fp, ip, #4
   c:   e52de004        push    {lr}            ; (str lr, [sp, #-4]!)
  10:   ebfffffe        bl      0 <__gnu_mcount_nc>
  14:   e0800001        add     r0, r0, r1
  18:   e89da800        ldm     sp, {fp, sp, pc}

0000001c <func1>:
  1c:   e1a0c00d        mov     ip, sp
  20:   e92dd800        push    {fp, ip, lr, pc}
  24:   e24cb004        sub     fp, ip, #4
  28:   e52de004        push    {lr}            ; (str lr, [sp, #-4]!)
  2c:   ebfffffe        bl      0 <__gnu_mcount_nc>
  30:   e0800001        add     r0, r0, r1
  34:   e89da800        ldm     sp, {fp, sp, pc}

Disassembly of section .init.text:

00000000 <init_module>:
   0:   e1a0c00d        mov     ip, sp
   4:   e92dd800        push    {fp, ip, lr, pc}
   8:   e24cb004        sub     fp, ip, #4
   c:   e52de004        push    {lr}            ; (str lr, [sp, #-4]!)
  10:   ebfffffe        bl      0 <__gnu_mcount_nc>
  14:   e59f0008        ldr     r0, [pc, #8]    ; 24 <init_module+0x24>
  18:   ebfffffe        bl      0 <_printk>
  1c:   e3a00000        mov     r0, #0
  20:   e89da800        ldm     sp, {fp, sp, pc}
  24:   00000000        .word   0x00000000
  1. 对比可以发现,开启CONFIG_FUNCTION_TRACER 后,编译代码会增加bl 0 <__gnu_mcount_nc>

链接时处理

如果编译为ko,则链接时是在insmod时进行;如果是编译进内核,vmlinux就是链接后的文件,可以通过反汇编查看。
为方便展示,将上述驱动编译进内核,objdum -d vmlinux如下。

8069a694 <func1>:
8069a694:   e1a0c00d    mov ip, sp
8069a698:   e92dd830    push    {r4, r5, fp, ip, lr, pc}
8069a69c:   e24cb004    sub fp, ip, #4
8069a6a0:   e52de004    push    {lr}        ; (str lr, [sp, #-4]!)
8069a6a4:   ebe9d726    bl  80110344 <__gnu_mcount_nc>
8069a6a8:   e0050091    mul r5, r1, r0
8069a6ac:   e1a00005    mov r0, r5
8069a6b0:   ebffffe8    bl  8069a658 <func2>
8069a6b4:   e59f1014    ldr r1, [pc, #20]   ; 8069a6d0 <func1+0x3c>
8069a6b8:   e1a04000    mov r4, r0
8069a6bc:   e1a02000    mov r2, r0
8069a6c0:   e59f000c    ldr r0, [pc, #12]   ; 8069a6d4 <func1+0x40>
8069a6c4:   ebebe82d    bl  80194780 <printk>
8069a6c8:   e0850004    add r0, r5, r4
8069a6cc:   e89da830    ldm sp, {r4, r5, fp, sp, pc}

可以看到bl 0 <__gnu_mcount_nc>已经被替换为bl 80110344 <__gnu_mcount_nc>。查看__gnu_mcount_nc实现如下。

80110344 <__gnu_mcount_nc>:
80110344:   e1a0c00e    mov ip, lr
80110348:   e8bd4000    ldmfd   sp!, {lr}
8011034c:   e1a0f00c    mov pc, ip

相当于执行了一个return;

系统初始化

todo

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值