之前写过很多kernel的gdb debug, 其实用户态也是可以调试的, 只是在共享库的动态地址上不是很好处理, 最近同事有调试系统启动过程中systemd的需求, 简单研究了一下
其实qemu kvm打断点并不区别kernel还是用户态, 都是rip的值等于某个地址或者遇到断点指令了, 所以开机的时候把断点打到systemd的main上就可以了
但是其实另外一个问题是, 用户态的地址是很多进程共享的, 这时候有可能会另一个进程也跑到了这个地址, 所以断点就需要条件断点, 用进程的pid是一个好方法,
下面是简单得步骤
第一步, 开机暂停
sudo qemu-system-x86_64 -drive file=centos7.vhd,if=virtio -vnc :11 -enable-kvm -serial mon:stdio -smp 8 -m 1024 -redir tcp:1011::22 -append "root=/dev/vda1 console=ttyS0 slub_debug=PFZ ro norandmaps" -kernel /home/shidao.ytt/alikernel/7u/arch/x86/boot/bzImage -s -S
kernel 参数 norandmaps很重要, 不然的话, 共享库的地址每次都不一样, 加了这个参数, 每次共享库的地址都是一样的, 就不用考虑共享库动态地址的问题了
第二步, 连接qemu, 打断点到systemd的main
/usr/bin/gdb vmlinux -ex 'target remote :1234' -ex 'thb start_kernel' -ex c
(gdb) add-symbol-file /usr/lib/debug/usr/lib/systemd/systemd.debug 0x0000555555573b60
这里说明一下, 因为要调试guest的systemd代码, 所以要在物理机上安装guest的systemd的debuginfo, 这个很好处理, 去centos下载debuginfo rpm安装就可以了
后面的地址0x0000555555573b60是systemd映射到进程代码段的加载地址, 这个地址如何获得, 开机一次, 去查看pid 1进程的vm映射空间就可以了, 简单一点就是gdb -p 1, info files就可以了
(gdb) thbreak *0x5555555752c0 if $lx_current().pid == 1
Hardware assisted breakpoint 2 at 0x5555555752c0: file src/core/main.c, line 1244.
简单说明, 因为systemd进程都还没起来, 所以是没有这个地址的, 所以一定需要用hardware breakpoint, 后面是条件判断, 只有pid为1的时候生效, 这个就是断点打到具体进程的利器了
c
接着跑
只要打断点的时候加入pid的条件限制, 就可以打到任意的进程了
时间: 2024-11-02 16:09:05