如何在 Linux 内核系统崩溃时记录(复制)内核日志消息

如何在 Linux 内核系统崩溃时记录(复制)内核日志消息

我通过以下方式启用日志记录到控制台:

$ 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]

相关内容