linux内核调试:配置环境

目标:配置环境实现linux内核的双机调试(调试机器host,被调试机器target)
步骤:

  • 确认内核有内核调试支持(一般都有)
  • 符号文件:
    • target:下载安装自己系统内核版本的符号文件(仅调试可能不必要)
    • host:安装target对应内核版本的符号文件以备调试
  • 源代码:
    • target:下载本机内核源码压缩包,解压放在/usr/src目录下(仅调试可能不必要)
    • host: 在指定路径放上target内核的源代码以备调试(等调试知道路径后再做)
  • 串口通信
  • 修改target启动程序
  • 配置host
  • 调试及善后

内核调试支持

首先,如果对于从Ubuntu官网下载安装包而安装的系统,不需要重新编译内核。因为,Canonical(开发Ubuntu的公司)在编译时,已经开启了内核调试支持。如果想确认一下,可以查看/boot目录下的编译选项文件,比如Ubuntu 16.04 LTS版本:

1
2
3
4
5
6
7
8
9
10
:/boot$ cat config-4.8.0-36-generic | grep -i "GDB"
# CONFIG_CFG80211_INTERNAL_REGDB is not set
CONFIG_SERIAL_KGDB_NMI=y
CONFIG_GDB_SCRIPTS=y
CONFIG_HAVE_ARCH_KGDB=y
CONFIG_KGDB=y
CONFIG_KGDB_SERIAL_CONSOLE=y
# CONFIG_KGDB_TESTS is not set
CONFIG_KGDB_LOW_LEVEL_TRAP=y
CONFIG_KGDB_KDB=y

可以看到,关于KDB和KGDB的几个选项都是开启的(yes)。
如果内核不支持,请移步这里
本文实验环境如下:

Windows 10 ,VMware® Workstation 12 Pro 下开两个虚拟机
target:Linux ubuntu 4.8.0-36-generic #36~16.04.1-Ubuntu SMP
host: Linux ubuntu 4.13.0-43-generic #48~16.04.1-Ubuntu SMP

使用 uname -a 查询系统版本信息。

符号文件

准备:target内核版本符号文件

  • 推荐方法:点这里 下载所需版本符号文件(需要科学上网),拖进虚拟机直接点击即可安装。
  • 一般方法:在target里按此链接《安装符号文件》一节 操作下载符号文件(很慢,建议挂代理,可能还是慢),拷进host同一目录(/usr/lib/debug/boot)即可。

源代码

打开/etc/apt/sources.list,启用deb-src,sudo apt-get update更新

1
2
3
4
5
6
vim /etc/apt/sources.list
去掉下面这句话的注释
deb-src http://us.archive.ubuntu.com/ubuntu/ xenial main restricted

...
sudo apt-get update

搜索所有版本的source code:apt-cache search linux-source
安装指定版本的source code:sudo apt-get install linux-source-x.x.x
解压缩得到源码 :sudo tar -xvf linux-source-4.8.0.tar.bz2 (host中安放源码的路径需要调试后才知道,见7.3)

串口通信

建立host与target之间的串口连接。
虚拟机设置中移除打印机,添加串口,target为服务器,host为客户端。详见此链接《移除打印机,添加串口》一节。

修改target启动程序

需要让target在开机时候可选择进入kgdb的调试状态,首先需要修改grub文件,增加grub引导时候的菜单项。

sudo vim /etc/grub.d/40_custom

从/boot/grub/grub.cfg中复制一个菜单项(menuentry)过来,最好选正常启动的一项,
修改项名便于识别,倒数第三句增加KGDB选项:

kgdbwait kgdb8250=io,03f8,ttyS0,115200,4 kgdboc=ttyS0,115200 kgdbcon nokaslr

修改完的40_custom文件样板如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/bin/sh
exec tail -n +3 $0
# This file provides an easy way to add custom menu entries. Simply type the
# menu entries you want to add after this comment. Be careful not to change
# the 'exec tail' line above.
menuentry 'Ubuntu, kgdb, with Linux 4.8.0-36-generic' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-4.8.0-36-generic-advanced-aeac2f22-dfde-4e98-9c78-bb46f5724517' {
recordfail
load_video
gfxmode $linux_gfx_mode
insmod gzio
if [ x$grub_platform = xxen ]; then insmod xzio; insmod lzopio; fi
insmod part_msdos
insmod ext2
set root='hd0,msdos1'
if [ x$feature_platform_search_hint = xy ]; then
search --no-floppy --fs-uuid --set=root --hint-bios=hd0,msdos1 --hint-efi=hd0,msdos1 --hint-baremetal=ahci0,msdos1 aeac2f22-dfde-4e98-9c78-bb46f5724517
else
search --no-floppy --fs-uuid --set=root aeac2f22-dfde-4e98-9c78-bb46f5724517
fi
echo 'Loading Linux 4.8.0-36-generic ...'
linux /boot/vmlinuz-4.8.0-36-generic root=UUID=aeac2f22-dfde-4e98-9c78-bb46f5724517 ro find_preseed=/preseed.cfg auto noprompt priority=critical locale=en_US quiet kgdbwait kgdb8250=io,03f8,ttyS0,115200,4 kgdboc=ttyS0,115200 kgdbcon nokaslr
echo 'Loading initial ramdisk ...'
initrd /boot/initrd.img-4.8.0-36-generic
}

修改grub的配置后,需要执行sudo update-grub来更新。更新后目标机器就准备好了。
重启按住shift,进入刚才添加的menu即可进入到被调试状态。

配置host(每次重启需要重新设置)

设置串口通信的波特率

sudo stty -F /dev/ttyS0 115200

要查看是否设置成功

sudo stty -F /dev/ttyS0

调试及善后

调试前准备

此节为在host中调试,需要target以kgdb调试状态启动,记得先配置好host端口(见6)。
编写config,用source加载(直接在gdb里输入也可)

1
2
set architecture i386:x86-64:intel
target remote /dev/ttyS0

开始调试

使用gdb来调试带符号的vmlinux

1
2
sudo gdb /usr/lib/debug/boot/vmlinux-4.8.0-36-generic
(gdb) source config

善后:在host中安放target源码(接3)

(gdb) l

查找源码。本来应该显示具体的源码,但是这里只是打印出了所在文件,这是因为在这个路径下没有源码。
所以说我们就建立这个路径,然后把源码放进去:

创建路径/build/linux-hwe-eyfT8D/linux-hwe-4.8.0,将源码解压到这里

然后dir设置好目录

dir /build/linux-hwe-edge-gyUj63/linux-hwe-edge-4.10.0

单步调试

详见此链接《单步调试》。

Tips:target运行

1
sudo su && echo g > "/proc/sysrq-trigger"

进入假死,方便host下断点

参考链接
[1] : 清楚,双机环境相同 https://www.anquanke.com/post/id/105342#h2-0
[2] : 全面 http://advdbg.org/blogs/advdbg_system/articles/7147.aspx