drgn/vmtest/enter_kdump.py
Omar Sandoval d5c53099d2 vmtest.enter_kdump: use kexec(8) on non-x86-64 architectures
We can trivially call the kexec_file_load() syscall on x86-64, but it's
more complicated for other architectures. We can call the kexec utility
for those.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2023-06-29 15:21:50 -07:00

67 lines
2.0 KiB
Python

# Copyright (c) Meta Platforms, Inc. and affiliates.
# SPDX-License-Identifier: LGPL-2.1-or-later
import ctypes
import os
import re
import subprocess
from util import NORMALIZED_MACHINE_NAME, SYS
KEXEC_FILE_ON_CRASH = 2
KEXEC_FILE_NO_INITRAMFS = 4
def main():
with open("/proc/cmdline", "rb") as f:
cmdline = f.read().rstrip(b"\n")
cmdline = re.sub(rb"(^|\s)crashkernel=\S+", b"", cmdline)
# `nokaslr` is required to avoid sporadically failing to reserve space for the
# capture kernel
cmdline += b" nokaslr"
if os.getenv("KDUMP_NEEDS_NOSMP"):
# `nosmp` is required to avoid QEMU sporadically failing an internal
# assertion when using emulation.
cmdline += b" nosmp"
vmlinuz = f"/lib/modules/{os.uname().release}/vmlinuz"
# On x86-64, kexec_file_load() is supported on all kernel versions we care
# about, and it's simple enough to call ourselves. On other architectures,
# we just use kexec(8).
if NORMALIZED_MACHINE_NAME == "x86_64":
syscall = ctypes.CDLL(None, use_errno=True).syscall
syscall.restype = ctypes.c_long
with open(vmlinuz, "rb") as kernel:
if syscall(
ctypes.c_long(SYS["kexec_file_load"]),
ctypes.c_int(kernel.fileno()),
ctypes.c_int(-1),
ctypes.c_ulong(len(cmdline) + 1),
ctypes.c_char_p(cmdline + b"\0"),
ctypes.c_ulong(KEXEC_FILE_ON_CRASH | KEXEC_FILE_NO_INITRAMFS),
):
errno = ctypes.get_errno()
raise OSError(errno, os.strerror(errno))
else:
subprocess.check_call(
[
"kexec",
"--load-panic",
"--kexec-syscall-auto",
"--command-line=" + cmdline.decode(),
vmlinuz,
]
)
with open("/proc/self/comm", "w") as f:
f.write("selfdestruct")
with open("/proc/sysrq-trigger", "w") as f:
f.write("c")
if __name__ == "__main__":
main()