Search code examples
clinux-kernelx86gdbqemu

Linux Kernel function memblock_alloc_range_nid is not present in the address space


I'm trying to debug physical memory allocation to understand what part of the Linux Kernel use memblock_alloc_range_nid on x86-64 and how.

I'm running the latest Linux Kernel 5.19-rc2 built from upstream with Ubuntu 20.04 inside QEMU. The problem is it's not possible to access memory address the function memblock_alloc_range_nid is located at. While other Kernel functions can be easily disassembled.

Here is what I have in my gdb connected to the QEMU VM:

(gdb) disas memblock_alloc_range_nid
Cannot access memory at address 0xffffffff831a05d1
(gdb) disas native_safe_halt
Dump of assembler code for function native_safe_halt:
#...
End of assembler dump.

What's wrong with the function memblock_alloc_range_nid? Why is it not possible to access its address? It seems all the function from memblock.c cannot be accessed.


Solution

  • As Margaret and Roi have noted in the above comments, memblock_alloc_range_nid() is annotated with __init. Functions annotated with __init, __head and similar macros are only needed during kernel initialization right after boot. After the kernel has finished initializing things, the special memory section containing all those functions is unmapped from memory since they are not needed anymore.

    If you want to debug any such function, you will have to break very early, for example at start_kernel(), then you can inspect the function or set a breakpoint and continue execution to hit it.

    Important: add -S (uppercase) to your QEMU command line options to make it stop and wait for the debugger before starting the kernel, and start the kernel with KASLR disabled using -append "nokaslr" (or adding nokaslr if you are already specifying -append).

    The following GDB script should be what you need:

    $ cat script.gdb
    directory /path/to/kernel-source-dir
    file /path/to/kernel-source-dir/vmlinux
    
    target remote localhost:1234
    
    break start_kernel
    continue
    

    Launch gdb -x script.gdb (after starting QEMU), and when you hit the start_kernel breakpoint, you can add another one for memblock_alloc_range_nid, then continue:

    0x000000000000fff0 in exception_stacks ()
    Breakpoint 1 at 0xffffffff82fbab4c
    
    Breakpoint 1, 0xffffffff82fbab4c in start_kernel ()
    (gdb) b memblock_alloc_range_nid
    Breakpoint 2 at 0xffffffff82fe2879
    (gdb) c
    Continuing.
    
    Breakpoint 2, 0xffffffff82fe2879 in memblock_alloc_range_nid ()
    (gdb) disassemble
    Dump of assembler code for function memblock_alloc_range_nid:
    => 0xffffffff82fe2879 <+0>:     push   r15
       0xffffffff82fe287b <+2>:     mov    r15,rcx
       0xffffffff82fe287e <+5>:     push   r14
       0xffffffff82fe2880 <+7>:     mov    r14,rdx
       0xffffffff82fe2883 <+10>:    push   r13
       0xffffffff82fe2885 <+12>:    mov    r13d,r9
       ...