这几天更新了 qemu, 然后在进行 gdb 调试的时候, 发现断点断不住了.
之前都是正常的, 从来没有出现过这种情况啊. 继续分析下看看是哪里出现的异常.
难道是 gdb 或者 QEMU 出现 BUG 了, 我们先看下断点的位置是否正确.
gdb 是直接读取 vmlinux 中的符号的加载地址去添加断点的, 那么 0xffffffff81aa1800
应该就是 vmlinux
中 schedule 的函数地址
#objdump -d ./vmlinux| grep ":"
ffffffff81aa1800 <schedule>:
可以看到没有问题, 但是为什么没有断到呢, 难道当前内核镜像中的地址不是这个么?
# cat /proc/kallsyms | grep -E " schedule$"
ffffffffb0ca1800 T schedule
schedule 在 vmlinux 镜像中的符号地址(ffffffff81aa1800)与 qemu 启动的内核中虚拟地址(ffffffffb0ca1800)不一样, 貌似发现问题所在了. 所以 gdb 根据 vmlinux 中的地址插入断点, 其实插入的位置并不是我们想要的, 这也就解释了为什么断点断不到.
可以看到两个地址刚好差了一个偏移 0x2f200000L.
这让我们想到了什么? 地址随机化?
内核启用 kaslr 这项特性之后, 内核启动时会随机化内核的各个 section 的虚拟地址(VA), 导致 gdb 断点设置在错误的虚拟地址上, 内核执行时就不会触发这些断点。
新版本的 qemu 竟然已经支持了地址随机化, 好事情.
最直接了当的方法(也是官方提供的方法) 是关闭地址随机化,
nokaslr
现在可以看到我们断点成功了, 内核的符号也没有偏移.
我们找到内核加载的起始地址, 这个一般是 _text
符号的地址.
# echo 0x$(cat /proc/kallsyms | egrep -e "T _text$" | awk '{print $1}')
# cat /proc/kallsyms | grep -E " _text$"
ffffffff9ee00000 T _text
# cat /proc/kallsyms | grep -E " schedule$"
ffffffff9f8a1800 T schedule
此时 KASLR 的偏移量为 0xffffffff9ee00000 - 0xffffffff81000000 = 0x1de00000L
然后通过 add-symbol-file 将 vmlinux 的起始地址指定到 0xffffffff9ee00000 位置处.
add-symbol-file ./vmlinux 0xffffffff9ee00000
可以看到断点断到了实际位置.
但是由于开启 KASLR 之后内核各个段的地址都是分别映射的, 这段我们只重新指定了内核代码段的位置.
objdump -h ./vmlinux | grep -E " .text| .data "
0 .text 00e010f1 ffffffff81000000 0000000001000000 00200000 2**12
11 .data 0014c540 ffffffff82400000 0000000002400000 01600000 2**13
之前算出来 KASLR 的偏移是 0x1de00000L, .data 在 vmlinux 中的地址为 0xffffffff82400000, 加上偏移后实际的加载地址就是 0xffffffffa0200000. 这个地址就是 init_stack 的地址
使用 add-symbol-file 指定其他段(比如 data) 的地址.
# add-symbol-file ./vmlinux 0xffffffff9ee00000 -s .data 0xffffffffa0200000
add symbol table from file "./vmlinux" at
.text_addr = 0xffffffff9ee00000
.data_addr = 0xffffffffa0200000
(y or n) y
Reading symbols from ./vmlinux...done.
但是如此读取后, 再去读取数据段的值, 依旧失败, gdb 还是寻找错误的地址.
我们在 StackOverFlow 中找到了类似的例子, GDB can’t load kernel symbol correctly with KASLR enabled
这个感觉应该是 gdb 的问题, 记录在此, 等待问题解决后, 更新
gdb-qemu-cant-put-break-point-on-kernel-function-kernel
gdb-kernel-debugging
Using kgdb, kdb and the kernel debugger internals
Commands to specify files