我通过以下方式启用日志记录到控制台:
$ dmesg --console-level 7
$ dmesg --console-on
我通过以下方式生成了系统崩溃:
$echo c > /proc/sysrq-trigger
我确实在 Linux 控制台(虚拟控制台)中获得了崩溃堆栈跟踪,如下所示:
[ 7.952685] sysrq: Trigger a crash
[ 7.952850] Kernel panic - not syncing: sysrq triggered crash
[ 7.953098] CPU: 0 PID: 71 Comm: linuxrc Not tainted 5.19.0-rc2 #1
[ 7.953259] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.14.0-2 04/01/2014
[ 7.953655] Call Trace:
[ 7.954133] <TASK>
[ 7.954332] dump_stack_lvl+0x34/0x44
[ 7.954651] panic+0x102/0x27b
[ 7.954756] ? _printk+0x53/0x6a
[ 7.954847] sysrq_handle_crash+0x11/0x20
[ 7.954953] __handle_sysrq.cold+0x43/0x11b
[ 7.955065] write_sysrq_trigger+0x1f/0x30
[ 7.955167] proc_reg_write+0x4c/0x90
[ 7.955267] vfs_write+0xb4/0x290
[ 7.955362] ksys_write+0x5a/0xd0
[ 7.955453] do_syscall_64+0x3b/0x90
[ 7.955553] entry_SYSCALL_64_after_hwframe+0x46/0xb0
[ 7.955773] RIP: 0033:0x4a8531
[ 7.955999] Code: e0 ff ff ff f7 d8 64 89 02 48 c7 c0 ff ff ff ff eb b3 0f 1f 80 00 00 00 00 8b 05 d2 26 1e 00 85 c0 75 16 b8 01 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 57 c3 66 0f 1f 44 00 00 8
[ 7.956427] RSP: 002b:00007ffde8168508 EFLAGS: 00000246 ORIG_RAX: 0000000000000001
[ 7.956625] RAX: ffffffffffffffda RBX: 000000000101a8a0 RCX: 00000000004a8531
[ 7.956787] RDX: 0000000000000002 RSI: 00000000010201e0 RDI: 0000000000000001
[ 7.956949] RBP: 0000000000000001 R08: fefefefefefefeff R09: fefefefefefeff62
[ 7.957113] R10: 00000000000001b6 R11: 0000000000000246 R12: 00000000010201e0
[ 7.957275] R13: 0000000000000002 R14: 00007ffde8168701 R15: 00007ffde8168578
[ 7.957467] </TASK>
[ 7.957806] Kernel Offset: 0x34a00000 from 0xffffffff81000000 (relocation range: 0xffffffff80000000-0xffffffffbfffffff)
[ 7.958215] ---[ end Kernel panic - not syncing: sysrq triggered crash ]---
而当时Linux系统崩溃了,键盘被冻结了,我该如何复制堆栈跟踪呢?
顺便问一下,有没有其他方法可以在内核恐慌的情况下记录堆栈跟踪?在 /etc/rsyslog.d/50-default.conf 中,我通过以下方式禁用了缓存(因此始终写入磁盘):
*.*;auth,authpriv.none /var/log/syslog*
但是,重新启动后,我仍然没有找到崩溃的日志消息。
答案1
对于虚拟机来说,这非常简单。只需向虚拟机添加另一个串行控制台即可。例如使用 libvirt,类似:
<serial type='file'>
<source path='/var/lib/libvirt/consoles/vm-name.log'/>
<target type='isa-serial' port='1'>
<model name='isa-serial'/>
</target>
</serial>
您还需要将 VM 的内核配置为使用 VM 的虚拟 tty 和串行端口作为控制台。例如在 /etc/default/grub 中:
GRUB_CMDLINE_LINUX="text console=tty0 console=ttyS1,115200n8"
进入控制台的任何内容都将保存在主机上的日志文件中...但请注意,每次虚拟机重新启动时,它都会被覆盖(而不是附加)。当然,您可以在虚拟机关闭时旋转/mv/cp/etc 日志文件。
顺便说一句,可以配置更多控制台 - 您可以使用第三个控制台进行串行控制台登录(另一个虚拟串行端口或真正的直通串行端口)。您需要在虚拟机中的串行端口上运行 getty,并使用终端程序连接到它,就像minicom
在主机上运行一样(或者在通过的情况下通过零调制解调器电缆连接的终端/笔记本电脑/其他机器) -通过)..
对于物理机来说,就更难了。如果附近有另一台机器(始终处于开启状态),您可以使用真正的串行端口,使用零调制解调器电缆连接机器,并让另一台机器不断记录该串行端口上通过的任何内容。这是一个相当典型的内核调试设置(或者在几乎每个人开始使用虚拟机之前曾经是)。
另一种可能是有时可行但不可靠的方法是将 syslogd 配置为将 kern.* 消息远程记录到另一台计算机。这在任何给定时刻是否有效取决于内核中到底发生了什么崩溃。如果网络仍然正常并且有一些 syslog udp 数据包可以出去,那就没问题。只需查看远程计算机上相应的系统日志文件即可。
我的一些机器上配置了 rsyslog 来执行此操作。特别是,我家庭网络上的两台机器称为kali
(顺便说一句,这不是运行 Kali Linux,而是运行 Debian...并且自 90 年代中期以来就已经这样做了,早在 Kali Linux 存在之前。我使用的是印度神作为我当时的主机命名方案,当然,从那时起,硬件和操作系统都不断升级了很多次。)和ganesh
(还有 Debian)互相发送 kern 消息。
加内什有:
if $fromhost-ip == '127.0.0.1' and $syslogfacility-text == 'kern' then @kali
卡利有:
if $fromhost-ip == '127.0.0.1' and $syslogfacility-text == 'kern' then @ganesh
答案2
请参阅我在 stackoverflow 中的回答。 https://stackoverflow.com/a/72870750/10818184[如何使用decode_stacktrace.sh?][1]