我试图调试物理内存分配,以了解Linux内核的哪个部分在x86-64上使用memblock_alloc_range_nid以及如何使用memblock_alloc_range_nid.

我运行的是最新的Linux Kernel 5.19-rc2台从upstream 建造的,在QEMU内部有Ubuntu 20.04台.问题是无法访问功能memblock_alloc_range_nid所在的存储器地址.而其他内核函数可以很容易地进行反汇编.

以下是我的gdb个连接到QEMU虚拟机中的内容:

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

memblock_alloc_range_nid函数有什么问题?为什么无法访问其地址?似乎memblock.c中的所有功能都无法访问.

推荐答案

MargaretRoi在上述注释中所述,memblock_alloc_range_nid()__init注释.只有在启动后的内核初始化期间,才需要使用__init__head和类似宏注释的函数.内核完成初始化后,包含所有这些函数的特殊内存部分将从内存中取消映射,因为它们不再需要.

如果要调试任何此类函数,必须很早中断,例如在start_kernel()时,然后可以判断该函数或设置断点并执行continue次以命中它.

重要提示:在QEMU命令行选项中添加-S(大写),使其在启动内核之前停止并等待调试器,并在使用-append "nokaslr"禁用KASLR的情况下启动内核(如果已经指定-append,则添加nokaslr).

以下GDB脚本应该是您所需要的:

$ cat script.gdb
directory /path/to/kernel-source-dir
file /path/to/kernel-source-dir/vmlinux

target remote localhost:1234

break start_kernel
continue

启动gdb -x script.gdb(启动QEMU后),当到达start_kernel断点时,可以为memblock_alloc_range_nid再添加一个断点,然后为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++相关问答推荐

两个 lerp 函数有什么区别?

如何从 Core Foundation CFDataRef 中获取最左边的位?

从 C 中的函数返回 STR 的问题

从 struct 数组中提取变量数组

打印函数指针时不兼容的指针类型警告

是 char 空终止符是否包含在长度计数中

使用指向过去的 malloc 的指针是否定义明确?

使用 Python/C 接口而不是 Cython 是否有优势?

为什么 C 和 C++ for 循环使用 int 而不是 unsigned int?

如何在 ffmpeg 中使用硬件加速

printf 字符串,可变长度项

您是否应该始终对 C 中的数字使用“int”,即使它们是非负数?

为什么在 C 中使用宏?

为什么 SDL 和 OpenGL 相关?

C 与 C++ 编译不兼容 - 未命名类型

我应该显式转换 malloc() 的返回值吗?

如果缺少 const char* 数组初始化逗号,则生成编译器警告

C/C++ 为什么对二进制数据使用 unsigned char?

GNU99 和 C99 (Clang) 有什么区别?

Linux 上的异​​步信号处理程序是如何执行的?