gdb 设置一个函数, 出现4个断点的原因

今天在vmlinux上设置断点的时候出现4个地址, 超乎认知了, 仔细得看了一下原因

(gdb) b sched_clock
Breakpoint 1 at 0xffffffff8101cf00: sched_clock. (4 locations)
(gdb) i b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   <MULTIPLE>         
1.1                         y     0xffffffff8101cf00 in sched_clock at arch/x86/kernel/tsc.c:75
1.2                         y     0xffffffff8101d4fd in tsc_save_sched_clock_state at arch/x86/include/asm/paravirt.h:192
1.3                         y     0xffffffff8101d555 in tsc_restore_sched_clock_state at arch/x86/include/asm/paravirt.h:192
1.4                         y     0xffffffff810b5c30 in sched_clock at kernel/sched/clock.c:71

仔细得看了一下第一个断点, 正常

unsigned long long sched_clock(void)
{
    return paravirt_sched_clock();
}
(gdb) disassemble sched_clock
Dump of assembler code for function sched_clock:
   0xffffffff8101cf00 <+0>:     push   %rbp
   0xffffffff8101cf01 <+1>:     mov    %rsp,%rbp
-------------------------------------------------------------------------------
   0xffffffff8101cf04 <+4>:     callq  *0xffffffff81a463c0
-------------------------------------------------------------------------------
   0xffffffff8101cf0b <+11>:    pop    %rbp
   0xffffffff8101cf0c <+12>:    retq   
End of assembler dump.

看第二个使用的地方tsc_save_sched_clock_state

void tsc_save_sched_clock_state(void)
{
    if (!sched_clock_stable())
        return;

    cyc2ns_suspend = sched_clock();
}

(gdb) disassemble tsc_save_sched_clock_state 
Dump of assembler code for function tsc_save_sched_clock_state:
   0xffffffff8101d4f0 <+0>:     push   %rbp
   0xffffffff8101d4f1 <+1>:     mov    %rsp,%rbp
   0xffffffff8101d4f4 <+4>:     callq  0xffffffff810b5d30 <sched_clock_stable>
   0xffffffff8101d4f9 <+9>:     test   %eax,%eax
   0xffffffff8101d4fb <+11>:    je     0xffffffff8101d50b <tsc_save_sched_clock_state+27>
------------------------------------------------------------------------------
   0xffffffff8101d4fd <+13>:    callq  *0xffffffff81a463c0
------------------------------------------------------------------------------
   0xffffffff8101d504 <+20>:    mov    %rax,0xd1c935(%rip)        # 0xffffffff81d39e40 <cyc2ns_suspend>
   0xffffffff8101d50b <+27>:    pop    %rbp
   0xffffffff8101d50c <+28>:    retq   
End of assembler dump.

可以看到函数tsc_save_sched_clock_state在调用sched_clock的时候, 因为tsc_save_sched_clock_state和sched_clock在同一个c文件里面, 就直接把函数sched_clock的肉嵌入进来了, 没有直接调用sched_clock, 为了和c语言的逻辑保持一致, 所以这些地方都需要被打上断点

第三个tsc_restore_sched_clock_state和第二个是一样的

第4个的代码是这样的

unsigned long long __attribute__((weak)) sched_clock(void)
{
    return (unsigned long long)(jiffies - INITIAL_JIFFIES)
                    * (NSEC_PER_SEC / HZ);
}

是个弱符号, 但是从以前的知识来说, 弱符号在编译的时候会被强符号干掉, 在从o文件连接成elf文件的时候就没了, 为什么这个时候又出现了呢

readelf -s vmlinux |grep sched_clock\$
  9679: ffffffff819e8690    16 OBJECT  LOCAL  DEFAULT    8 __ksymtab_sched_clock
  9680: ffffffff819fc66a    12 OBJECT  LOCAL  DEFAULT   11 __kstrtab_sched_clock
  9681: ffffffff819f7ac0     8 OBJECT  LOCAL  DEFAULT   10 __kcrctab_sched_clock
 66460: ffffffff8101ce80   123 FUNC    GLOBAL DEFAULT    1 native_sched_clock
 67482: 000000003a26ed11     0 NOTYPE  GLOBAL DEFAULT  ABS __crc_sched_clock
 72418: ffffffff8101cf00    13 FUNC    GLOBAL DEFAULT    1 sched_clock

可以看到其实符号表里面只有一个sched_clock符号, 从地址上可以确定是gdb中的第一个符号, 那么这些信息存在哪里呢

一个有可能的猜想就是在debug section里面

把vmlinux的debug section去掉看看

$strip --strip-debug vmlinux.cp

gdb vmlinux.cp

(gdb) i b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0xffffffff8101cf04 <sched_clock+4>

可以只剩一个了, 所以原因是vmlinux中的debug section的信息符号了符号表的信息, 这样看起来, 在gdb vmlinux的时候, 去掉debug section的时候, 有些函数调用信息会丢失, 光依赖符号表也不准确

上一篇:SAP UI5 初学者教程之十三 - 如何添加自定义 CSS 类试读版


下一篇:IntelliJ IDEA里对Lombok插件的配置步骤