Commit d23bfa91 authored by Marc-André Lureau's avatar Marc-André Lureau Committed by Michael S. Tsirkin
Browse files

scripts/dump-guest-memory.py: add vmcoreinfo



Add a vmcoreinfo ELF note in the dump if vmcoreinfo device has the
memory location details.

Signed-off-by: default avatarMarc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: default avatarMichael S. Tsirkin <mst@redhat.com>
Signed-off-by: default avatarMichael S. Tsirkin <mst@redhat.com>
parent 9ada575b
Loading
Loading
Loading
Loading
+61 −0
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@ the COPYING file in the top-level directory.
"""

import ctypes
import struct

UINTPTR_T = gdb.lookup_type("uintptr_t")

@@ -45,6 +46,17 @@ EM_S390 = 22
EM_AARCH = 183
EM_X86_64 = 62

VMCOREINFO_FORMAT_ELF = 1

def le16_to_cpu(val):
    return struct.unpack("<H", struct.pack("=H", val))[0]

def le32_to_cpu(val):
    return struct.unpack("<I", struct.pack("=I", val))[0]

def le64_to_cpu(val):
    return struct.unpack("<Q", struct.pack("=Q", val))[0]

class ELF(object):
    """Representation of a ELF file."""

@@ -120,6 +132,25 @@ class ELF(object):
        self.segments[0].p_filesz += ctypes.sizeof(note)
        self.segments[0].p_memsz += ctypes.sizeof(note)


    def add_vmcoreinfo_note(self, vmcoreinfo):
        """Adds a vmcoreinfo note to the ELF dump."""
        # compute the header size, and copy that many bytes from the note
        header = get_arch_note(self.endianness, 0, 0)
        ctypes.memmove(ctypes.pointer(header),
                       vmcoreinfo, ctypes.sizeof(header))
        if header.n_descsz > 1 << 20:
            print('warning: invalid vmcoreinfo size')
            return
        # now get the full note
        note = get_arch_note(self.endianness,
                             header.n_namesz - 1, header.n_descsz)
        ctypes.memmove(ctypes.pointer(note), vmcoreinfo, ctypes.sizeof(note))

        self.notes.append(note)
        self.segments[0].p_filesz += ctypes.sizeof(note)
        self.segments[0].p_memsz += ctypes.sizeof(note)

    def add_segment(self, p_type, p_paddr, p_size):
        """Adds a segment to the elf."""

@@ -505,6 +536,35 @@ shape and this command should mostly work."""
                cur += chunk_size
                left -= chunk_size

    def phys_memory_read(self, addr, size):
        qemu_core = gdb.inferiors()[0]
        for block in self.guest_phys_blocks:
            if block["target_start"] <= addr \
               and addr + size <= block["target_end"]:
                haddr = block["host_addr"] + (addr - block["target_start"])
                return qemu_core.read_memory(haddr, size)
        return None

    def add_vmcoreinfo(self):
        if not gdb.parse_and_eval("vmcoreinfo_find()") \
           or not gdb.parse_and_eval("vmcoreinfo_find()->has_vmcoreinfo"):
            return

        fmt = gdb.parse_and_eval("vmcoreinfo_find()->vmcoreinfo.guest_format")
        addr = gdb.parse_and_eval("vmcoreinfo_find()->vmcoreinfo.paddr")
        size = gdb.parse_and_eval("vmcoreinfo_find()->vmcoreinfo.size")

        fmt = le16_to_cpu(fmt)
        addr = le64_to_cpu(addr)
        size = le32_to_cpu(size)

        if fmt != VMCOREINFO_FORMAT_ELF:
            return

        vmcoreinfo = self.phys_memory_read(addr, size)
        if vmcoreinfo:
            self.elf.add_vmcoreinfo_note(vmcoreinfo.tobytes())

    def invoke(self, args, from_tty):
        """Handles command invocation from gdb."""

@@ -518,6 +578,7 @@ shape and this command should mostly work."""

        self.elf = ELF(argv[1])
        self.guest_phys_blocks = get_guest_phys_blocks()
        self.add_vmcoreinfo()

        with open(argv[0], "wb") as vmcore:
            self.dump_init(vmcore)