编译内核/kdump/crash

练习题
1. 启动错误,无法正常开机
2. 为了解决1,需要crash定位,再重新编译内核,但你可能遇到编译错误
3. 正常vCPU或热插大于某值时可能出现错误,请寻找边界值,并解决cpu数限制问题
目标:虚拟机正常启动,熟悉编译内核流程和工具,解决编译过程中的各种问题,争取搞清BUG的原因。


1. 使用qemu-nbd挂载qcow2镜像
qemu-nbd工具是:QEMU Disk Network Block Device Server

modprobe nbd max_part=16 #加载 nbd 驱动
max_part 指定设备节点 /dev/nbd0p{1,2,3,4…}

lsmod|grep nbd
modinfo nbd

qemu-nbd -c /dev/nbd0 镜像 -f qcow2 #连接qemu-nbd
fdisk -l /dev/nbd0
mount /dev/nbd0p3 /mnt


2. 扩展虚拟机磁盘
1) resize
qcow2如果没有snapshot也能resize

qemu-img resize learn.qcow2 +10G

fdisk #先删除原有分区, 再重建分区, 起始cylinder 绝对不可以改,这样会破坏原分区的数据。
resize2fs #扩展逻辑卷的逻辑边界(增加或缩小未加载的文件系统的大小)

2) 插一块磁盘
qemu-img create -f qcow2 img 10G

配置文件中添加:
<disk type='file' device='disk'>
<driver name='qemu' type='qcow2' cache='none'/>
<source file='/data/img'/>
<target dev='hdb' bus='ide'/>
</disk>

分区扩展磁盘...
mkfs.ext4 /dev/vda


3. rhel2.6编译内核步骤(2.4有所不同)
make menuconfig #配置内核模块,会生成.config文件
make #根据.config,生成内核
make modules_install
make install
1. vi /etc/grub.conf -->查看是否有新的内核启动项生成。并修改default指向(0代表第一个,1代表第二个,以此类推)。
2. ls /boot -->查看是否有新的内核文件vmlinuz生成。

系统将会把vmlinuz和System.map复制到/boot目录下同时修改grub)
在2.6以前需要make bzImage make modules, 而且还需要将vmlinuz和System.map复制到/boot目录

make modules_install INSTALL_MOD_STRIP=1         #最小化安装?


4. /boot目录
1) .config文件:kernel配置文件,make时通过该文件编译所定制的内核
2) grub目录:里面存放的都是GRUB在启动时所需要的画面、配置及各阶段(stage1, stage1.5, stage 2)的文件
3) Initrd文件:(initialized RAM disk)系统启动时加载驱动模块
4) System.map:Kernel中的变量对应表
5) vmlinuz:实际系统所使用的kernel

/boot/initrd
initrd(initial ramdisk)是一个在Linux启动过程中内核使用的临时文件系统。
该文件系统为挂载真正的文件系统做准备。

vmlinuz是可引导的、压缩的内核。

内核启动被分成了两个阶段
第一阶段先执行 initrd 文件系统中的"某个文件",完成加载驱动模块等任务,
第二阶段才会执行真正的根文件系统中的 /sbin/init 进程。


5. 内核态有三种出错情况,分别是bug, oops和panic。
bug属于轻微错误,比如在spin_lock期间调用了sleep,导致潜在的死锁问题,等等。
oops代表某一用户进程出现错误,需要杀死用户进程。这时如果用户进程占用了某些信号锁,所以这些信号锁将永远不会得到释放,这会导致系统潜在的不稳定性。
panic是严重错误,代表整个系统崩溃。

例:
[ 2.053478] RIP [<ffffffff8144375b>] DSFW_rx_handle+0x1bb/0x370
ffffffff8144375b 是指令在内存中的虚拟地址
DSFW_rx_handle 是函数(symbol 名)
0x1bb/0x370 ,0x370 是这个函数编译成机器码后的长度,0x1bb是ffffffff8144375b这条指令在相对于DSFW_rx_handle 函数入口的偏移

oops:
例如[ 221.634988] [<ffffffff8103fbc7>] ? kmld_pte_lookup+0x17/0x60
0x17/0x60 ,0x60是这个函数编译成机器码后的长度,
0x17是ffffffff8103fbc7这条指令在相对于kmld_pte_lookup这个函数入口的偏移

解压vmlinuz
1) vmlinuz文件的开头部分内嵌有 gzip 解压缩代码
查找gzip压缩内容的开始头部,通过“1f 8b 08”这个签名来查找
od -t x1 -A d vmlinuz-2.6.32|grep "1f 8b 08"
0014432 48 8d 83 60 83 40 00 ff e0 1f 8b 08 00 0c 1d 26

2) 计算bizip压缩内容开始处的offset,为:14432 + 9 = 14441 (9是从0014431起到"if 8b 08"之间的字节数)

3) 解压
dd if=vmlinuz-2.6.32 bs=1 skip=14441 | zcat > vmlinux-panic

dd: 用于复制文件并对原文件的内容进行转换和格式化处理
if 代表输入文件
of 代表输出文件
bs 代表字节为单位的块大小
skip=<区块数>:一开始读取时,跳过指定的区块数;

od: 输出文件的八进制、十六进制或其它格式编码的字节,通常用于显示或查看文件中不能直接显示在终端的字符

4)查看信息
strings vmlinux-panic | grep 'Linux version'
strings vmlinux-panic | grep '/sbin/'


6. kdump+crash
kdump是系统崩溃的时候,用来转储运行内存的一个工具。
产物:内存转储文件vmcore

crash是一个用于分析内核转储文件的工具
使用crash时,要求调试内核vmlinux在编译时带有-g选项,即带有调试信息。
使用crash需要安装crash工具包和内核调试信息包:
crash
kernel-debuginfo-common
kernel-debuginfo

系统panic时调查的一般思路:
1)获得panic时的dump信息(host上执行)
virsh dump DOM_name testcore --memory-only --format kdump-zlib

2)获取虚拟机的debuginfo(打开debug开关,编译内核时生成debug)

3)使用crash进行debug,找到问题所在
将2)中编译好的vmlinux、system.map 复制到装有crash工具的host上
crash testcore vmlinux

4)修改代码,并重新编译替换内核
5)验证问题是否解决

crash工具的常用操作:
bt:打印函数调用栈,displays a task's kernel-stack backtrace,可以指定进程号bt <pid>。
log:打印系统消息缓冲区,displays the kernel log_buf contents,如log | tail -n 30。
ps:显示进程的状态,>表示活跃的进程,如ps | grep RU。
sys:显示系统概况。
kmem -i:显示内存使用信息。
dis <addr>:对给定地址进行反汇编。

 

dis -l 函数名               #显示代码行数和汇编代码

 

posted @ 2017-12-20 11:34  Hsinwang  阅读(546)  评论(0编辑  收藏  举报