引用
- Systemtap
- DebuggingProgramCrash
- Linux Kernel PANIC(三)--Soft Panic/Oops调试及实例分析
- 使用 Crash 工具分析 Linux dump 文件
- Linux 系统内核崩溃分析处理简介
- Linux Kernel Crash Book
- Analyzing Linux kernel crash dumps with crash - The one tutorial that has it all
- Collecting and analyzing Linux kernel crashes - crash
- 朴英敏: 用crash工具分析Linux内核死锁的一次实战
- linux kernel crash问题分析解决
- 在Ubuntu 18.04上编译Linux内核
- Ubuntu 切换内核
- Linux crash 调试环境搭建
- 使用Ubuntu编译Linux内核
- --------------crash 工具使用--------------------
- crash - ubunut manuals
- 系统崩溃 - crash工具介绍
- 使用crash分析linux内核崩溃转储文件vmcore
- debugging - 在內核模塊上,c addr2line
- addr2line应用
一. How to get vmlinux?
-
从官网下载
Where to get debug symbols for kernel X?
http://ddebs.ubuntu.com/pool/main/l/linux/
GPG key import
16.04 and higher
> sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys C8CAB6595FDFF622
older distributions
> sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys ECDCAD72428D7C01
Add repository config
>
codename=$(lsb_release -c | awk '{print $2}')
sudo tee /etc/apt/sources.list.d/ddebs.list << EOF
deb http://ddebs.ubuntu.com/ ${codename} main restricted universe multiverse
deb http://ddebs.ubuntu.com/ ${codename}-security main restricted universe multiverse
deb http://ddebs.ubuntu.com/ ${codename}-updates main restricted universe multiverse
deb http://ddebs.ubuntu.com/ ${codename}-proposed main restricted universe multiverse
EOF
> sudo apt-get update
> sudo apt-get install linux-image-$(uname -r)-dbgsym
---------------------------------------------------------------------------------------
vmlinux then can be found here:
/usr/lib/debug/boot/vmlinux-$(uname -r)
-
自己编译源码获取
1. 首先通过apt-get获取内核代码,当然你可以直接从kernel.org上Git获取代码.
> sudo apt-get install linux-source
2. 安装编译需要的lib
> sudo apt-get install libncurses5-dev
3. 将linux-source-4.15.0.tar.bz2解压到/usr/src/目录下
> tar -jxf /usr/src/linux-source-4.15.0/linux-source-4.15.0.tar.bz2 -C /usr/src/
4. 获取配置文件
> sudo cp /boot/config-4.15.0-88-generic /usr/src/linux-source-4.15.0/.config
----------------------------------------------------------------------------------
编译可能用到的lib:
sudo apt-get install libncurses5-dev libssl-dev
sudo apt-get install build-essential openssl
sudo apt-get install zlibc minizip
sudo apt-get install libidn11-dev libidn11
sudo apt-get install bison
sudo apt-get install flex
----------------------------------------------------------------------------------
5. 进入/usr/src/linux-source-4.15.0文件夹中,开始编译
> sudo make -j8 # 8线程编译
--------------------------------------------------------
> make mrproper # 清除编译过程产生的中间文件,就是将内核代码还原为刚解压的状态,最好每次编译前执行一下。
> make clean # 清除上次编译产生的中间文件,最好每次编译前执行一下。
> make menuconfig # 配置编译参数,编译的内核模块选择,内核剪裁需要重点研究的部分。
-----------------------------------------------------------------------------------
vmlinux路径:
/usr/src/linux-source-4.15.0
6. 如果想继续安装内核,执行:
> make INSTALL_MOD_STRIP=1 modules_install
>make install INSTALL_MOD_STRIP=1
----------
如果用下面的命令,可能会报错误:Couldn't find suitable memory target
//make modules_install # 安装内核模块,驱动等
//make install # 安装内核
一. objdump,readelf,nm,addr2line,gdb,eu-addr2line
kernel module crash:
[ 444.852297] kernel BUG at /home/vec/dev_document/linux_module_driver/kthread_test/kthread_test.c:60!
[ 444.852314] invalid opcode: 0000 [#1] SMP PTI
[ 444.852325] CPU: 3 PID: 3926 Comm: insmod Kdump: loaded Tainted: G OE 5.4.55 #1
[ 444.852332] Hardware name: ASUSTeK Computer Inc. P43SJ/P43SJ, BIOS P43SJ.308 01/06/2012
[ 444.852349] RIP: 0010:simple_init+0xf5/0x100 [kthread_test]
[ 444.852360] Code: c0 83 4d c0 48 c7 c7 8f 70 4d c0 e8 58 e0 e3 d7 48 8b 15 ae 22 00 00 48 8b 35 9f 22 00 00 48 c7 c7 d0 70 4d c0 e8 3e e0 e3 d7 <0f> 0b 66 0f 1f 84 00 00 00 00 00 66 66 66 66 90 55 48 8b 3d 73 22
========================================================================================
1. 查询RIP指定的符号地址 (如果是内核API,就换为vmlinux)
objdump:
> objdump -t kthread_test.ko | grep simple_init
--------------
0000000000000040 l F .text 00000000000000f7 simple_init
0000000000000000 l F .text.unlikely 0000000000000049 simple_init.cold
--------------
> objdump -dSlr kthread_test.ko > kthread_test.disasm //查询到所有函数及其偏移位置。
> vim kthread_test.disasm
--------------
/home/vec/dev_document/linux_module_driver/kthread_test/kthread_test.c:58
207 printk(KERN_ERR "k_data:0x%llx, v_data:0x%llx", (u64)simple_data.k_data, (u64)simple_data.v_data);
208 11b: 48 8b 15 00 00 00 00 mov 0x0(%rip),%rdx # 122 <init_module+0xe2>
209 11e: R_X86_64_PC32 simple_data+0xc
210 122: 48 8b 35 00 00 00 00 mov 0x0(%rip),%rsi # 129 <init_module+0xe9>
211 125: R_X86_64_PC32 simple_data+0x4
212 129: 48 c7 c7 00 00 00 00 mov $0x0,%rdi
213 12c: R_X86_64_32S .rodata.str1.8
214 130: e8 00 00 00 00 callq 135 <init_module+0xf5>
215 131: R_X86_64_PLT32 printk-0x4
216 /home/vec/dev_document/linux_module_driver/kthread_test/kthread_test.c:60
217
218 assert();
219 135: 0f 0b ud2
220 137: 66 0f 1f 84 00 00 00 nopw 0x0(%rax,%rax,1)
221 13e: 00 00
--------------
> objdump -S kthread_test.ko | grep simple_init
--------------
static int simple_init(void)
0000000000000000 <simple_init.cold>:
7: 48 89 05 00 00 00 00 mov %rax,0x0(%rip) # e <simple_init.cold+0xe>
e: e8 00 00 00 00 callq 13 <simple_init.cold+0x13>
20: e8 00 00 00 00 callq 25 <simple_init.cold+0x25>
25: 48 8b 05 00 00 00 00 mov 0x0(%rip),%rax # 2c <simple_init.cold+0x2c>
2c: e9 00 00 00 00 jmpq 31 <simple_init.cold+0x31>
38: e8 00 00 00 00 callq 3d <simple_init.cold+0x3d>
3d: 48 8b 0d 00 00 00 00 mov 0x0(%rip),%rcx # 44 <simple_init.cold+0x44>
注意:这里的0000000000000000是相对于 (0000000000000040 <init_module>)而言的,所以,
simple_init的地址应该是 0000000000000040 + 0000000000000000 = 0000000000000040 。
--------------
readelf:
> readelf -s kthread_test.ko | grep simple_init
--------------
32: 0000000000000040 247 FUNC LOCAL DEFAULT 3 simple_init
33: 0000000000000000 73 FUNC LOCAL DEFAULT 5 simple_init.cold
--------------
nm:
> nm kthread_test.ko | grep simple_init
--------------
0000000000000040 t simple_init
0000000000000000 t simple_init.cold
--------------
2. 计算RIP中符号+offset的地址
eg.
simple_init+0xf5 ==> 0000000000000040 + 0xf5 = 0x135
3. 查询该地址对应的c语言位置
addr2line:
> addr2line -e kthread_test.ko -f 0x135
--------------
simple_init
/home/vec/dev_document/linux_module_driver/kthread_test/kthread_test.c:60
--------------
GDB:
> gdb "$(modinfo -n kthread_test.ko)"
(gdb) list *(simple_init+0xf5)
--------------
0x175 is in simple_init (/home/vec/dev_document/linux_module_driver/kthread_test/kthread_test.c:60).
55
56
57 printk(KERN_ERR "simple_dat:0x%llx", (u64)&simple_data);
58 printk(KERN_ERR "k_data:0x%llx, v_data:0x%llx", (u64)simple_data.k_data, (u64)simple_data.v_data);
59
60 assert();
61
62 err:
63 return ret;
64 }
--------------
eu-addr2line:
> eu-addr2line -f -e <path_to_the_module> -j <section_name> <offset_in_section>
eg.
eu-addr2line -e kthread_test.ko -j .text -f 0x135
--------------
simple_init
/home/vec/dev_document/linux_module_driver/kthread_test/kthread_test.c:60:2
--------------
二. crash
crash 常用方法
1. 加载dump文件
> crash vmlinux 202009121232/dump.202009121232
2. 加载指定kernel module
crash> mod -s kthread_test /home/vec/dev_document/linux_module_driver/kthread_test/kthread_test.ko
3. 常用命令
3.1 crash> dmesg/ log -a
--------------
[ 0.000000] microcode: microcode updated early to revision 0x2f, date = 2019-02-17
[ 0.000000] Linux version 5.4.55 (root@spc) (gcc version 9.3.0 (Ubuntu 9.3.0-10ubuntu2)) #1 SMP Wed Sep 9 20:48:42 CST 2020 (Ubuntu 5.4.0-47.51-generic 5.4.55)
[ 0.000000] Command line: BOOT_IMAGE=/boot/vmlinuz-5.4.55 root=UUID=db5337a7-63f9-4023-8b30-613e5a3c3ca6 ro quiet splash crashkernel=512M-:192M vt.handoff=7
[ 0.000000] KERNEL supported cpus:
...
--------------
3.2 crash> dis -l simple_init+0xf5
--------------
/home/vec/dev_document/linux_module_driver/kthread_test/kthread_test.c: 60
0xffffffffc04d6135 <simple_init+245>: ud2
...
--------------
3.4 bt/bt -slf/bt -t/bt -c 1/bt -a (查看堆栈)
crash> bt
--------------
PID: 3926 TASK: ffff93bb6cc90000 CPU: 3 COMMAND: "insmod"
#0 [ffffa5e3c2d17930] machine_kexec at ffffffff9826fbd3
...
--------------
3.3 struct simple_data_info (要查看的struct结构)
crash> struct simple_data_info
--------------
struct simple_data_info {
struct task_struct *pth;
unsigned char *k_data;
unsigned char *v_data;
}
SIZE: 24
--------------
crash> struct simple_data_info 0xffffffffc04d83c0
--------------
struct simple_data_info {
pth = 0xffff93bb6c62ae80,
k_data = 0xffff93bb6f2c6000 "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"...,
v_data = 0xffffa5e3c081d000 "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"...
}
--------------
crash> struct simple_data_info 0xffffffffc04d83c0 -xo
--------------
struct simple_data_info {
[ffffffffc04d83c0] struct task_struct *pth;
[ffffffffc04d83c8] unsigned char *k_data;
[ffffffffc04d83d0] unsigned char *v_data;
}
SIZE: 0x18
--------------
3.4 读取内存内容 (大小是以8字节为单位)
crash> rd 0xffff93bb6f2c6000 1
--------------
ffff93bb6f2c6000: 5a5a5a5a5a5a5a5a ZZZZZZZZ
--------------
3.5 获取线程信息
crash> ps
--------------
PID PPID CPU TASK ST %MEM VSZ RSS COMM
0 0 0 ffffffff99813780 RU 0.0 0 0 [swapper/0]
0 0 1 ffff93bb763f8000 RU 0.0 0 0 [swapper/1]
0 0 2 ffff93bb763fdd00 RU 0.0 0 0 [swapper/2]
...
--------------
内核线程信息
crash> ps -k
--------------
PID PPID CPU TASK ST %MEM VSZ RSS COMM
0 0 0 ffffffff99813780 RU 0.0 0 0 [swapper/0]
0 0 1 ffff93bb763f8000 RU 0.0 0 0 [swapper/1]
...
--------------
3.6 获取内存使用信息
crash> kmem -i
--------------
PAGES TOTAL PERCENTAGE
TOTAL MEM 1982852 7.6 GB ----
FREE 1683852 6.4 GB 84% of TOTAL MEM
USED 299000 1.1 GB 15% of TOTAL MEM
SHARED 69714 272.3 MB 3% of TOTAL MEM
...
--------------
Crash命令列表
命令 | 功能 |
---|---|
* | 指针快捷健 |
alias | 命令快捷键 |
ascii | ASCII码转换和码表 |
bpf | eBPF - extended Berkeley Filter |
bt | 堆栈查看 |
btop | 地址页表转换 |
dev | 设备数据查询 |
dis | 返汇编 |
eval | 计算器 |
exit | 退出 |
extend | 命令扩展 |
files | 打开的文件查看 |
foreach | 循环查看 |
fuser | 文件使用者查看 |
gdb | 调用gdb执行命令 |
help | 帮助 |
ipcs | 查看system V IPC工具 |
irq | 查看irq数据 |
kmem | 查看Kernel内存 |
list | 查看链表 |
log | 查看系统消息缓存 |
mach | 查看平台信息 |
mod | 加载符号表 |
mount | Mount文件系统数据 |
net | 网络命令 |
p | 查看数据结构 |
ps | 查看进程状态信息 |
pte | 查看页表 |
ptob | 页表地址转换 |
ptov | 物理地址虚拟地址转换 |
rd | 查看内存 |
repeat | 重复执行 |
runq | 查看run queue上的线程 |
search | 搜索内存 |
set | 设置线程环境和Crash内部变量 |
sig | 查询线程消息 |
struct | 查询结构体 |
swap | 查看swap信息 |
sym | 符号和虚拟地址转换 |
sys | 查看系统信息 |
task | 查看task_struct和thread_thread信息 |
timer | 查看timer队列 |
tree | 查看radix树和rb树 |
union | 查看union结构体 |
vm | 查看虚拟内存 |
vtop | 虚拟地址物理地址转换 |
waitq | 查看wait queue上的进程 |
whatis | 符号表查询 |
wr | 改写内存 |
q | 退出 |
三. ubunut apport-unpack crash file
apport-unpack linux-image-5.4.55-202009121232.crash temp
--------------
root@spc:/var/crash/temp# ll
total 100
drwxr-sr-x 2 root whoopsie 4096 9月 13 10:02 ./
drwxrwsrwt 3 root whoopsie 4096 9月 13 10:02 ../
-rw-r--r-- 1 root whoopsie 5 9月 13 10:02 Architecture
-rw-r--r-- 1 root whoopsie 24 9月 13 10:02 Date
-rw-r--r-- 1 root whoopsie 12 9月 13 10:02 DistroRelease
-rw-r--r-- 1 root whoopsie 34 9月 13 10:02 Package
-rw-r--r-- 1 root whoopsie 11 9月 13 10:02 ProblemType
-rw-r--r-- 1 root whoopsie 19 9月 13 10:02 Uname
-rw-r--r-- 1 root whoopsie 68626 9月 13 10:02 VmCoreDmesg
--------------