qemu 抓取linux kernel vmcore

一、背景

在qemu调试linux kernel时 有时我们会遇到dump 情况,这时可以通过gdb 方式连接分析dump, 但实际中我们用得更多的是离线dump 分析,分析的文件通常是vmcore(linux kernel panic 生成的coredump文件)或者ramdump(类似高通平台提供的抓取手机的整个内存空间);这里我将介绍如何利用qemu 抓取vmcore, 以及后续利用crash 工具离线分析异常的方法。

二、qemu monitor建立连接

1、qemu 抓取vmcore 需要建立连接,server端连接建立

qemu-system-aarch64 \-monitor telnet:127.0.0.1:5554,server,nowait \-machine virt,virtualization=true,gic-version=3 \-nographic \-m size=2048M \-cpu cortex-a72 \-smp 2 \ -kernel Image \-drive format=raw,file=rootfs.img \-append "root=/dev/vda rw "

对比前面的qemu 启动linux kernel, 这里需要增加指令:

-monitor telnet:127.0.0.1:5554,server,nowait

monitor通过telnet端口5554 建立server连接;

2、qemu monitor telnet client连接

geek@geek-virtual-machine:~/workspace/linux/qemu$ telnet 127.0.0.1 5554

qemu monitor中也有一些指令用来查看qemu运行的linux kernel 状态,这里不详细展开,有兴趣的可以自行搜索(比如热插拔增加一个device, 执行info roms查看 qemu运行的信息,抓取寄存器等)

对于抓取vmcore,我们唯一需要关心的是指令dump-guest-memory

dump-guest-memory [-p] [-d] [-z|-l|-s|-w] filename [begin length] -- dump guest memory into file 'filename'.-p: do paging to get guest's memory mapping.-d: return immediately (do not wait for completion).-z: dump in kdump-compressed format, with zlib compression.-l: dump in kdump-compressed format, with lzo compression.-s: dump in kdump-compressed format, with snappy compression.-w: dump in Windows crashdump format (can be used instead of ELF-dump converting),for Windows x64 guests with vmcoreinfo driver only.begin: the starting physical address.length: the memory size, in bytes.

通常使用 dump-guest-memory filename 或 dump-guest-memory -z filename 指令会抓取qemu中linux kernel的vmcore,一个是不压缩,一个是zlib压缩格式, 后续就可以利用这个vmcore来进行kernel panic 离线分析;

三、qemu vmcore抓取

1、如何生成vmcore

先用最简单的命令行触发一个panic: echo c > /proc/sysrq-trigger

~ # echo c > /proc/sysrq-trigger 
[  142.419430] sysrq: Trigger a crash
[  142.419886] Kernel panic - not syncing: sysrq triggered crash
[  142.420293] CPU: 0 PID: 143 Comm: sh Tainted: G                 N 6.6.1-g3cba94c761ec-dirty #15
[  142.420642] Hardware name: linux,dummy-virt (DT)
[  142.420985] Call trace:
[  142.421120]  dump_backtrace+0x90/0xe8
[  142.421412]  show_stack+0x18/0x24
[  142.421673]  dump_stack_lvl+0x48/0x60
[  142.422098]  dump_stack+0x1c/0x28
[  142.422434]  panic+0x39c/0x3f0
[  142.422744]  sysrq_reset_seq_param_set+0x0/0x10c
[  142.423099]  __handle_sysrq+0x154/0x294
[  142.423427]  write_sysrq_trigger+0x80/0xcc
[  142.423731]  proc_reg_write+0x108/0x16c
[  142.423990]  vfs_write+0x158/0x45c
[  142.424218]  ksys_write+0xd0/0x180
[  142.424425]  __arm64_sys_write+0x44/0x58
[  142.424651]  invoke_syscall+0x60/0x184
[  142.424887]  el0_svc_common.constprop.0+0x78/0x13c
[  142.425132]  do_el0_svc+0x30/0x40
[  142.425351]  el0_svc+0x38/0x70
[  142.425559]  el0t_64_sync_handler+0x120/0x12c
[  142.425816]  el0t_64_sync+0x190/0x194
[  142.426441] SMP: stopping secondary CPUs
[  142.427057] Kernel Offset: disabled
[  142.427264] CPU features: 0x1,00000200,3c020000,1000421b
[  142.427700] Memory Limit: none
[  142.428385] ---[ end Kernel panic - not syncing: sysrq triggered crash ]---

然后在qemu monitor 端执行: dump-guest-memory ramdump1

或者:dump-guest-memory -z vmcore1

用 -z参数和不带参数抓取的vmcore只是一个压缩,一个不压缩,大小不同而已,对我们分析无影响

后面我们就用这个抓取到的ramdump1/vmcore1 文件进行分析,分析前我们还需要准备对应的kernel版本的vmlinux, 以及crash 工具(这个工具是redhat开发的分析kdump的免费开源工具);

2、crash工具交叉编译

1.下载crash tool
https://github.com/crash-utility/crash.git
2.编译crash, 我们分析的vmcore是arm64平台
make target=ARM64
3.根目录会生成crash工具,加到环境变量中使用即可
4. crash 还有一些externsion在目录extensions  ---本次分析vmcore暂时不涉及,可以忽略make extensions编译生成后的so,在crash中通过extend XXX.so方式加载a. trace.so 用来提取ramdump中的trace log, 分析一些疑难杂症是有用,本质就是根据trace buffer结构体提取里面的trace loghttps://github.com/fujitsu/crash-traceb.gcore.so 可以在kernel panic后的ramdump中提取指定进程的coredump,对应用端逻辑调用栈进行分析https://github.com/fujitsu/crash-gcore

crash 的指令学习可以参考下面两篇文章:

CRASH安装和调试_crash gcore-CSDN博客

四、crash加载vmcore

1、crash加载指令:

crash vmcore路径 vmlinux路径 -m vabits_actual=XX 指定虚拟地址长度(位长的设置后面会介绍)

crash  ../qemu/vmcore1 vmlinux -m vabits_actual=48

虚拟地址长度可以在.config中查看(64位平台通常的配置是48或者39):
//CONFIG_ARM64_VA_BITS_48=y CONFIG_ARM64_VA_BITS=48

2、加载遇到问题

看来这个问题已经在crash bug上有人报过了,但是问题还是没有解决(反馈者对比发现4.X 版本的内核是正常的---我自己用4.19也是正常的, 现在我用的linux6.6.1也是有问题,这个问题应该在crash arm64上存在了很久,但是没人去解决)。

[Crash-utility] [Question] crash-arm64 cannot determine VA_BITS_ACTUAL for qemu dump-guest-memory

花了些时间分析后, 发现是自动计算kimage_voffset时遇到了问题,导致后面无法进行; 由于这个在一个编译的版本上是固定值,于是我简单通过 gdb 连接,然后在内核查看变量kimage_voffset的值,最后通过crash的参数设定传入,

(gdb) p /x kimage_voffset
$3 = 0xffff80003fe00000

上面可以看到我这个版本的kimage_voffset值是0xffff80003fe00000,不清楚怎么单步调试kernel的参考我前面的文章: 无人知晓:qemu单步调试arm64 linux kernel

3、crash增加参数 kimage_voffset=XXX

重新加载vmcore, 通过gdb获取kimage_voffset的值,在crash 加载vmcore/ramdump时,arm64平台有如下几个参数可以设置:

    ARM64: //这些都是特定平台相关参数,通过 -m option=value 指定phys_offset=<physical-address>  //指定物理地址的起始kimage_voffset=<kimage_voffset-value>   //指定kimage_voofset的值max_physmem_bits=<value>                  vabits_actual=<value>     //指定虚拟地址长度,手机通常使用39位,虚拟地址空间已经到512G,足够使用,//39位相对48位,正好少一级页表,性能上有提升,同时当前的虚拟地址空间足够手机使用了--kaslr offset //kaslr指定kaslr偏移的参数,qemu调试我们通常会关闭,否则对齐vmlinux需要花些功夫//在高通平台中ocimem.bin特定offset存放,//linux ramdump parse解析的结果也有这个offset
crash最终启动命令: 
crash  ../qemu/vmcore1 vmlinux -m vabits_actual=48 -m kimage_voffset=0xffff80003fe00000

如上,加载vmcore成功。

五、crash中如何调试一个vmcore

echo c > /proc/sysrq-trigger 方式触发的dump, 入口在drivers/tty/sysrq.c中

实际我们在调试中,遇到panic都需要恢复调用栈及问题发生时的寄存器来进行分析;

1、如何恢复调用栈

crash> bt
PID: 143      TASK: ffff00000bc09f00  CPU: 0    COMMAND: "sh"
bt: WARNING: cannot determine starting stack frame for task ffff00000bc09f00

执行bt为什么无法恢复调用栈?panic时sp指针等信息并没有填入导致的,正如我们在使用T32调试通常也需要也个cmm放置 x0~x29, sp/lr 等信息才能正常恢复异常现场

2、如何获取panic时的寄存器信息?

通常内核发生异常时会打印当前CPU的寄存器信息,利用这个打印信息就可以,在遇到wdt或者tz卡死类问题时,肯定是无法打印出来,这时平台通常是触发fiq到trustzone, 然后在TZ中抓取EL1 的cpu寄存信息,我们这里是因为调用的panic, 这个默认也是不打印寄存器信息的。如果是触发data abort或者instuction abort等异常还是能正常打印,如:

上面是我用4.19内核echo c 触发的,4.19的实现就是通过空指针访问制造的异常(个人觉得用空指针制造的panic更方便分析)

3、获取panic时的调用栈

执行bt时,提供了 pid和触发panic的进程name信息:

PID: 143 TASK: ffff00000bc09f00 CPU: 0 COMMAND: "sh"

crash> task -x -R thread.cpu_context 143
PID: 143 TASK: ffff00000bc09f00 CPU: 0 COMMAND: "sh"
thread.cpu_context = {
x19 = 0xffff80008475af40,
x20 = 0x0,
x21 = 0xffff00000bc09f00,
x22 = 0xffff7fffb13f4000,
x23 = 0xffff800082e0e748,
x24 = 0xffff00000bd1d500,
x25 = 0xffff800085fd7850,
x26 = 0xffff80008475b338,
x27 = 0xffff800082e0e750,
x28 = 0xffff000034202748,
fp = 0xffff800085fd7740,
sp = 0xffff800085fd7740, //利用sp恢复
pc = 0xffff8000817d4390
},
利用bt恢复时,需要lr指针,sp + 8就是lr, sp中存放的是上一级的sp;不清楚可以看后面参考的链接:https://student.cs.uwaterloo.ca/~cs452/docs/rpi4b/aapcs64.pdf

crash> bt -S 0xffff800085fd7748
PID: 143      TASK: ffff00000bc09f00  CPU: 0    COMMAND: "sh"
bt: WARNING: cannot determine starting stack frame for task ffff00000bc09f00#0 [ffff800085fd7750] idle_cpu at ffff80008010a9a0#1 [ffff800085fd7780] irq_exit_rcu at ffff8000800c4a68#2 [ffff800085fd7790] arm64_preempt_schedule_irq at ffff8000817d424c#3 [ffff800085fd77b0] el1_interrupt at ffff8000817caf10#4 [ffff800085fd77d0] el1h_64_irq_handler at ffff8000817cb2c0#5 [ffff800085fd7910] el1h_64_irq at ffff800080011ae4#6 [ffff800082b361e0] (null) at f420PC: 000000000044fd4c   LR: 00000000004b7734   SP: 0000ffffd8894070X29: 0000ffffd8894070  X28: 0000000000000000  X27: 0000000000000000X26: 0000000001e57970  X25: 0000000000000002  X24: 0000000000000020X23: 0000000001e5c6a0  X22: 0000000000602000  X21: 0000000000000002X20: 0000000001e5c6a0  X19: 0000000000000001  X18: 0000000000000000X17: 0000000000403140  X16: 0000000000600020  X15: 000000000360ed96X14: 0000000000000001  X13: 0000ffffd88941b0  X12: 00000000ffffffc8X11: 00000000ffffff80  X10: 0000000000000000   X9: 0000000000000020X8: 0000000000000040   X7: 7f7f7f7f7f7f7f7f   X6: 0000000000000063X5: fffffffffffffffe   X4: 0000000000000001   X3: 0000000000601ca5X2: 0000000000000002   X1: 0000000001e5c6a0   X0: 0000000000000001ORIG_X0: 0000000000000001  SYSCALLNO: 40  PSTATE: 80000000

恢复到第五级,遇到一些问题,直接查看堆栈内容,在0xffff800085fd7910处出现了栈回溯问题,这是因为中断的原因,跳过这一级继续向下就可以恢复完整异常发生的调用栈,如下标红线的就是sp回溯,sp + 8就是每一级对应的lr函数,可以通过sym XXXXX查看

从0xffff800085fd7920 开始恢复调用栈,此时就是真实触发异常的调用栈

crash> bt -S 0xffff800085fd7928
PID: 143      TASK: ffff00000bc09f00  CPU: 0    COMMAND: "sh"
bt: WARNING: cannot determine starting stack frame for task ffff00000bc09f00#0 [ffff800085fd7930] __delay at ffff800081789ecc#1 [ffff800085fd7960] __const_udelay at ffff800081789fb0#2 [ffff800085fd7a20] panic at ffff8000800ba5ec#3 [ffff800085fd7ab0] sysrq_handle_crash at ffff800080bc78c8#4 [ffff800085fd7ac0] __handle_sysrq at ffff800080bc8414#5 [ffff800085fd7b40] write_sysrq_trigger at ffff800080bc8eb8#6 [ffff800085fd7b70] proc_reg_write at ffff8000804b83e8#7 [ffff800085fd7ca0] vfs_write at ffff8000803f5b84#8 [ffff800085fd7d60] ksys_write at ffff8000803f6130#9 [ffff800085fd7da0] __arm64_sys_write at ffff8000803f6224
#10 [ffff800085fd7dd0] invoke_syscall at ffff80008002ee48
#11 [ffff800085fd7e20] el0_svc_common.constprop.0 at ffff80008002efe4
#12 [ffff800085fd7e60] do_el0_svc at ffff80008002f0d8
#13 [ffff800085fd7e80] el0_svc at ffff8000817cb060
#14 [ffff800085fd7ea0] el0t_64_sync_handler at ffff8000817cb45c
#15 [ffff800085fd7fe0] el0t_64_sync at ffff800080011d48PC: 000000000044fd4c   LR: 00000000004b7734   SP: 0000ffffd8894070X29: 0000ffffd8894070  X28: 0000000000000000  X27: 0000000000000000X26: 0000000001e57970  X25: 0000000000000002  X24: 0000000000000020X23: 0000000001e5c6a0  X22: 0000000000602000  X21: 0000000000000002X20: 0000000001e5c6a0  X19: 0000000000000001  X18: 0000000000000000X17: 0000000000403140  X16: 0000000000600020  X15: 000000000360ed96X14: 0000000000000001  X13: 0000ffffd88941b0  X12: 00000000ffffffc8X11: 00000000ffffff80  X10: 0000000000000000   X9: 0000000000000020X8: 0000000000000040   X7: 7f7f7f7f7f7f7f7f   X6: 0000000000000063X5: fffffffffffffffe   X4: 0000000000000001   X3: 0000000000601ca5X2: 0000000000000002   X1: 0000000001e5c6a0   X0: 0000000000000001ORIG_X0: 0000000000000001  SYSCALLNO: 40  PSTATE: 80000000

crash的使用技巧可以参考文末部分(写得都很详细)

六、总结

1、利用qemu monitor 提取vmcore

2、利用crash 工具加载分析vmcore

参考:

CRASH安装和调试_crash gcore-CSDN博客

crash实战:手把手教你使用crash分析内核dump-CSDN博客

https://student.cs.uwaterloo.ca/~cs452/docs/rpi4b/aapcs64.pdf

https://linux.web.cern.ch/centos7/docs/rhel/Red_Hat_Enterprise_Linux-7-Kernel_Crash_Dump_Guide-en-US.pdf

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/247633.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

算法沉淀——二分查找(leetcode真题剖析)

算法沉淀——二分查找 01.二分查找02.在排序数组中查找元素的第一个和最后一个位置03.搜索插入位置04.x 的平方根05.山脉数组的峰顶索引06.寻找峰值07.寻找旋转排序数组中的最小值08.LCR 173. 点名 二分查找&#xff08;Binary Search&#xff09;是一种在有序数组中查找特定元…

wordpress找不回密码怎么办?4种方法设置新密码

有些WordPress站长太久不登录后台了&#xff0c;所以就忘记了管理员登录密码&#xff0c;这种情况我们应该怎么找回密码呢&#xff1f;或者设置一个新密码呢&#xff1f;下面boke112百科就跟大家分享4种方法设置WordPress新密码。 方法一、登录页面的“忘记密码&#xff1f;”…

在Windows上安装与配置Apache服务并结合内网穿透工具实现公网远程访问本地内网服务

文章目录 前言1.Apache服务安装配置1.1 进入官网下载安装包1.2 Apache服务配置 2.安装cpolar内网穿透2.1 注册cpolar账号2.2 下载cpolar客户端 3. 获取远程桌面公网地址3.1 登录cpolar web ui管理界面3.2 创建公网地址 4. 固定公网地址 前言 Apache作为全球使用较高的Web服务器…

Linux服务器配置与管理(第二次实验)

实验目的及具体要求 目的 1.掌握基于命令行的文件操作 2.掌握基于命令行的目录操作 3.掌握用户账户的命令行操作 4.掌握组账户的命令行操作 5.熟悉磁盘分区操作 6.掌握调整优先级的方法 具体要求 1.掌握基于命令行的文件和目录操作 ①创建测试目录 ②创建文件 ③复…

代码随想录算法训练营DAY6 | 哈希表(1)

DAY5休息一天&#xff0c;今天重启~ 哈希表理论基础&#xff1a;代码随想录 Java hash实现 &#xff1a;java 哈希表-CSDN博客 一、LeetCode 242 有效的字母异位词 题目链接&#xff1a;242.有效的字母异位词 思路&#xff1a;设置字典 class Solution {public boolean isAnag…

设计模式:简单工厂模式

工厂设计模式属于创建型模式&#xff0c;它提供了一种创建对象的最佳方式。工厂模式提供了一种创建对象的方式&#xff0c;而无需指定要创建的具体类。工厂模式属于创建型模式&#xff0c;它在创建对象时提供了一种封装机制&#xff0c;将实际创建对象的代码与使用代码分离。 …

腾讯云幻兽帕鲁服务器创建教程,附4核16G服务器价格表

腾讯云0基础搭建帕鲁服务器4C16G14M服务器稳定无卡顿&#xff0c;先下载SteamCMD&#xff0c;并运行&#xff1b;然后下载Palserver&#xff0c;修改服务ini配置&#xff0c;启动PalServer&#xff0c;进入游戏服务器。腾讯云百科txybk.com分享腾讯云创建幻兽帕鲁服务器教程&am…

LabVIEW准分子激光器控制系统

LabVIEW准分子激光器控制系统是为了实现准分子激光光源在工业、医疗和科研领域的应用集成及其功能的扩展。系统由PC端和激光器端两部分构成&#xff0c;通过光隔离的RS232通讯连接&#xff0c;以实现稳定可靠的控制与通信。 系统主要由微控制单元&#xff08;MCU&#xff09;主…

【算法专题】动态规划综合篇

动态规划7.0 1. 最长公共子序列2. 不相交的线3. 不同的子序列4. 通配符匹配5. 正则表达式匹配6. 交错字符串7. 两个字符串的最小ASCII删除和8. 最长重复子数组 1. 最长公共子序列 题目链接 -> Leetcode -1143.最长公共子序列 Leetcode -1143.最长公共子序列 题目&#xf…

堆的概念,性质及其实现

1.堆的概念及结构 如果有一个关键码的集合K { &#xff0c; &#xff0c; &#xff0c;…&#xff0c; }&#xff0c;把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中&#xff0c;并满足&#xff1a; < 且 < ( > 且 > ) i 0&#xff0c;1&#x…

Java RC4加密算法

一、RC4加密算法 在密码学中&#xff0c;RC4&#xff08;来自Rivest Cipher 4的缩写&#xff09;是一种流加密算法&#xff0c;密钥长度可变。它加解密使用相同的密钥&#xff0c;因此也属于对称加密算法。 百度百科 - RC4&#xff1a;https://baike.baidu.com/item/RC4/34545…

JavaEE 网络原理

JavaEE 网络原理 文章目录 JavaEE 网络原理1. 网络互连1.1 局域网LAN1.2 广域网WAN 2. 网络通信基础2.1 IP地址2.2 端口号 3. 网络协议3.1 概念3.2 五元组3.3 协议分层3.4 TCP/IP 五层模型3.5 封装和分用 1. 网络互连 随着时代的发展&#xff0c;需要多个计算机协同工作来完成…

Docker安装RcoketMQ

1、Docker安装RcoketMQ-4.9.4 在同级文件夹创建目录config&#xff0c;并在里面创建文件broker.conf&#xff0c;文件内容如下&#xff1a; brokerClusterNameDefaultCluster brokerNamebroker-a brokerId0 deleteWhen04 fileReservedTime48 brokerRoleASYNC_MASTER flushDis…

Java项目:基于SSM框架实现的高校毕业生就业管理系统(ssm+B/S架构+源码+数据库+毕业论文)

一、项目简介 本项目是一套ssm817基于SSM框架实现的高校毕业生就业管理系统&#xff0c;主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的Java学习者。 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调…

Qlik Sense : IntervalMatch(离散匹配)

什么是IntervalMatch IntervalMatch 前缀用于创建表格以便将离散数值与一个或多个数值间隔进行匹配&#xff0c;并且任选匹配一个或多个额外关键值。 语法&#xff1a; IntervalMatch (matchfield)(loadstatement | selectstatement ) IntervalMatch (matchfield,keyfield…

Docker部署Stable-Diffusion-webui

前排提示&#xff1a;如果不想折腾&#xff0c;可直接跳到最后获取封装好的容器&#xff0c;一键运行 :D 前言 乘上AI生成的快车&#xff0c;一同看看沿途的风景。 启一个miniconda容器 docker run -itd -v 宿主机内SD项目路径:/tmp --gpus all --ipc host -p 7860:7860 con…

正则匹配 | 正则实际应用探索分享

这并不是一篇教正则基础的文章&#xff0c;其正则式不能对您进行使用后的结果负责&#xff0c;请以研究的眼光看待本篇文章。 技术就是懒人为了更好的懒才会想办法搞的东西&#xff0c;我最近因为某些原因需要频繁删除注释 我就想到通过替换的正则功能快速删除文件中的简单注…

RT-Thread: STM32 SPI使用流程

1.添加驱动 ①点开设置界面 ②勾选看门 SPI 驱动 ③点击保存 ④查看添加的驱动文件 drv_spi.c 2.打开驱动头文件定义 ①打开配置文件 ②打开定义 3.打开需要开启的SPI总线 打开 drivers 目录下的 board.h 用SPI搜索&#xff0c;找到如下文字&#xff0c;打开对应的宏。 /*-…

上门服务小程序|预约上门服务系统开发有哪些功能?

在现代快节奏的生活中&#xff0c;压力和疲劳常常困扰着我们。为了缓解这种状况&#xff0c;越来越多的人选择去按摩店进行放松。然而&#xff0c;繁忙的工作和家庭责任往往让我们无法抽出时间去按摩店。在这种情况下&#xff0c;上门按摩服务应运而生。而随着科技的发展&#…

Niushop 开源商城 v5.1.7:支持PC、手机、小程序和APP多端电商的源码

Niushop 系统是一款基于 ThinkPHP6 开发的电商系统,提供了丰富的功能和完善的商品机制。该系统支持普通商品和虚拟商品,并且针对虚拟商品还提供了完善的核销机制。同时,它也支持新时代的商业模式,如拼团、分销和多门店砍价等营销活动。 配送方式方面,Niushop 系统支持物流…