diff --git a/README.md b/README.md index 9d2b7db..4750bf1 100644 --- a/README.md +++ b/README.md @@ -298,6 +298,26 @@ Examples (virtme-ng is started in graphical mode) ``` + - Generate a memory dump of a running instance and read 'jiffies' from the + memory dump using the drgn debugger: +```` + # Start the vng instance in debug mode + $ vng --debug + + # In a separate shell session trigger the memory dump to /tmp/vmcore.img + $ vng --dump /tmp/vmcore.img + + # Use drgn to read 'jiffies' from the memory dump: + $ echo "print(prog['jiffies'])" | drgn -q -s vmlinux -c /tmp/vmcore.img + drgn 0.0.23 (using Python 3.11.6, elfutils 0.189, with libkdumpfile) + For help, type help(drgn). + >>> import drgn + >>> from drgn import NULL, Object, cast, container_of, execscript, offsetof, reinterpret, sizeof + >>> from drgn.helpers.common import * + >>> from drgn.helpers.linux import * + >>> (volatile unsigned long)4294675464 +``` + - Run virtme-ng inside a docker container: ``` $ docker run -it ubuntu:22.04 /bin/bash diff --git a/virtme/commands/configkernel.py b/virtme/commands/configkernel.py index 716c41e..77b9313 100644 --- a/virtme/commands/configkernel.py +++ b/virtme/commands/configkernel.py @@ -154,6 +154,9 @@ def arg_fail(message): "CONFIG_UPROBES=y", "CONFIG_UPROBE_EVENTS=y", "CONFIG_DEBUG_FS=y", + "# Required to generate memory dumps for drgn", + "CONFIG_FW_CFG_SYSFS=y", + "CONFIG_FW_CFG_SYSFS_CMDLINE=y", "# Graphics support", "CONFIG_DRM=y", "CONFIG_DRM_VIRTIO_GPU=y", diff --git a/virtme_ng/run.py b/virtme_ng/run.py index 4d18ffa..769beb0 100644 --- a/virtme_ng/run.py +++ b/virtme_ng/run.py @@ -856,7 +856,9 @@ def _get_virtme_sound(self, args): self.virtme_param["sound"] = "" def _get_virtme_disable_microvm(self, args): - if args.disable_microvm: + # Automatically disable microvm in debug mode, since it seems to + # produce incomplete memory dumps. + if args.disable_microvm or args.debug: self.virtme_param["disable_microvm"] = "--disable-microvm" else: self.virtme_param["disable_microvm"] = "" @@ -951,7 +953,10 @@ def _get_virtme_qemu_opts(self, args): if args.qemu_opts is not None: qemu_args += " ".join(args.qemu_opts) if args.debug: - qemu_args += "-s -qmp tcp:localhost:3636,server,nowait" + # Enable vmcoreinfo (required by drgn memory dumps) + qemu_args += "-device vmcoreinfo " + # Enable debug mode and QMP (to trigger memory dump via `vng --dump`) + qemu_args += "-s -qmp tcp:localhost:3636,server,nowait " if qemu_args != "": self.virtme_param["qemu_opts"] = "--qemu-opts " + qemu_args else: @@ -1032,11 +1037,6 @@ def run(self, args): def dump(self, args): """Generate or analyze a crash memory dump.""" - if not os.path.isfile("vmlinux"): - arg_fail( - "vmlinux not found, try to recompile the kernel with " - + "--build-host-vmlinux (if --build-host was used)" - ) # Use QMP to generate a memory dump sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(("localhost", 3636)) @@ -1055,7 +1055,7 @@ def dump(self, args): with tempfile.NamedTemporaryFile(delete=dump_file is None) as tmp: msg = ( '{"execute":"dump-guest-memory",' - '"arguments":{"paging":false,' + '"arguments":{"paging":true,' '"protocol":"file:' + tmp.name + '"}}' "\r" )