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.

推荐答案

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
   ...

C++相关问答推荐

如何通过Zephyr(Devicetree)在PR Pico上设置UTE 1?

使用SWI—Prolog的qsave_program生成二进制文件有什么好处?'

如何在C中从函数返回指向数组的指针?

C:fopen是如何实现二进制模式和文本模式的?

为什么I2C会发送错误的数据?

向上强制转换C中的数值类型总是可逆的吗?

将宏值传递给ARM链接器,该链接器将变量放置在特定位置

GCC不顾-fno-Builtin-SINCOS旗帜向SINCOS发出呼唤

变量的作用域是否在C中的循环未定义行为或实现定义行为的参数中初始化?

不使用任何预定义的C函数进行逐位运算

为什么GCC-O1优化破解了这个代码,为了一个GameBoy高级只读存储器而修改了VRAM的循环?

为什么我的旧式&q;函数在传递浮点数时会打印2?

为什么GCC 13没有显示正确的二进制表示法?

如何编写postgresql支持函数

计算时出现奇怪的计算错误;N Select K;在C中

C Makefile - 如何避免重复提及文件名

是什么阻止编译器优化手写的 memcmp()?

在 C23 之前如何对空指针使用nullptr?

Codewars Kata 掷骰子的不稳定行为

计算 e^x 很好.但不是 x 的罪