Search code examples
linuxkernel-moduleelfdwarf

How can I find a proper DWARF symbol for address in a Linux kernel module?


I have a kernel module with DWARF debug info. All its ELF sections have zero start addresses. Its DWARF info contains multiple overlapping code and data symbols. It also has many compilation units with zero DW_AT_low_pc address.

Is there a way to find the right DWARF symbol for a certain location in the binary file?


Solution

  • It also has many compilation units with zero DW_AT_low_pc address.

    A kernel module is just a ET_REL object file. The kernel knows how to link it in into its address space.

    The reason DW_AT_low_pcs are all 0s is because there are relocation entries that would have told the ld how to relocate them iff ld was to perform the link.

    You could examine these entries with readelf -Wr module.ko, but it's much easier to ask GDB to do so.

    Example:

    // f.c
    int foo(int x)
    {
      return x;
    }
    
    int bar(int x)
    {
      return foo(x);
    }
    
    gcc -c -g f.c -ffunction-sections
    

    Resulting f.o has everything at 0:

    nm f.o
    0000000000000000 T bar
    0000000000000000 T foo
    
    readelf -wi f.o | grep low_pc
        <1d>   DW_AT_low_pc      : 0x0
        <35>   DW_AT_low_pc      : 0x0
        <6c>   DW_AT_low_pc      : 0x0
    

    But when loaded into GDB, you can see relocated entries (because GDB knows how to apply them):

    gdb -q f.o
    Reading symbols from f.o...
    
    (gdb) p &foo
    $1 = (int (*)(int)) 0x0 <foo>
    (gdb) p &bar
    $2 = (int (*)(int)) 0xc <bar>    <<=== not 0
    
    (gdb) disas/s foo
    Dump of assembler code for function foo:
    f.c:
    2       {
       0x0000000000000000 <+0>:     push   %rbp
       0x0000000000000001 <+1>:     mov    %rsp,%rbp
       0x0000000000000004 <+4>:     mov    %edi,-0x4(%rbp)
    
    3         return x;
       0x0000000000000007 <+7>:     mov    -0x4(%rbp),%eax
    
    4       }
       0x000000000000000a <+10>:    pop    %rbp
       0x000000000000000b <+11>:    retq
    End of assembler dump.
    
    (gdb) disas/s bar
    Dump of assembler code for function bar:
    f.c:
    7       {
       0x000000000000000c <+0>:     push   %rbp
       0x000000000000000d <+1>:     mov    %rsp,%rbp
       0x0000000000000010 <+4>:     sub    $0x8,%rsp
       0x0000000000000014 <+8>:     mov    %edi,-0x4(%rbp)
    
    8         return foo(x);                                <<=== correct line
       0x0000000000000017 <+11>:    mov    -0x4(%rbp),%eax
       0x000000000000001a <+14>:    mov    %eax,%edi
       0x000000000000001c <+16>:    callq  0x21 <bar+21>
    
    9       }
       0x0000000000000021 <+21>:    leaveq
       0x0000000000000022 <+22>:    retq
    End of assembler dump.