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.
CodePudding user response:
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
...