Blame SOURCES/kvm-dump-add-guest-ELF-note.patch

4a2fec
From 93d31dbfbf412b8a80d364aac0ff6f5f319e831c Mon Sep 17 00:00:00 2001
4a2fec
From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= <marcandre.lureau@redhat.com>
4a2fec
Date: Mon, 27 Nov 2017 22:51:06 +0100
4a2fec
Subject: [PATCH 08/21] dump: add guest ELF note
4a2fec
MIME-Version: 1.0
4a2fec
Content-Type: text/plain; charset=UTF-8
4a2fec
Content-Transfer-Encoding: 8bit
4a2fec
4a2fec
RH-Author: Marc-André Lureau <marcandre.lureau@redhat.com>
4a2fec
Message-id: <20171127225111.24518-5-marcandre.lureau@redhat.com>
4a2fec
Patchwork-id: 77925
4a2fec
O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 4/9] dump: add guest ELF note
4a2fec
Bugzilla: 1398633
4a2fec
RH-Acked-by: Laszlo Ersek <lersek@redhat.com>
4a2fec
RH-Acked-by: Andrew Jones <drjones@redhat.com>
4a2fec
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
4a2fec
4a2fec
Read the guest ELF PT_NOTE from guest memory when fw_cfg
4a2fec
etc/vmcoreinfo entry provides the location, and write it as an
4a2fec
additional note in the dump.
4a2fec
4a2fec
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
4a2fec
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
4a2fec
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
4a2fec
4a2fec
(cherry picked from commit 903ef7349699dcd932b5981b85c1f1ebe4a4bf2a)
4a2fec
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
4a2fec
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
4a2fec
---
4a2fec
 dump.c                | 107 ++++++++++++++++++++++++++++++++++++++++++++++++++
4a2fec
 include/sysemu/dump.h |   2 +
4a2fec
 2 files changed, 109 insertions(+)
4a2fec
4a2fec
diff --git a/dump.c b/dump.c
4a2fec
index 99117ba..a4f175d 100644
4a2fec
--- a/dump.c
4a2fec
+++ b/dump.c
4a2fec
@@ -26,6 +26,8 @@
4a2fec
 #include "qapi/qmp/qerror.h"
4a2fec
 #include "qmp-commands.h"
4a2fec
 #include "qapi-event.h"
4a2fec
+#include "qemu/error-report.h"
4a2fec
+#include "hw/misc/vmcoreinfo.h"
4a2fec
 
4a2fec
 #include <zlib.h>
4a2fec
 #ifdef CONFIG_LZO
4a2fec
@@ -38,6 +40,13 @@
4a2fec
 #define ELF_MACHINE_UNAME "Unknown"
4a2fec
 #endif
4a2fec
 
4a2fec
+#define MAX_GUEST_NOTE_SIZE (1 << 20) /* 1MB should be enough */
4a2fec
+
4a2fec
+#define ELF_NOTE_SIZE(hdr_size, name_size, desc_size)   \
4a2fec
+    ((DIV_ROUND_UP((hdr_size), 4) +                     \
4a2fec
+      DIV_ROUND_UP((name_size), 4) +                    \
4a2fec
+      DIV_ROUND_UP((desc_size), 4)) * 4)
4a2fec
+
4a2fec
 uint16_t cpu_to_dump16(DumpState *s, uint16_t val)
4a2fec
 {
4a2fec
     if (s->dump_info.d_endian == ELFDATA2LSB) {
4a2fec
@@ -76,6 +85,8 @@ static int dump_cleanup(DumpState *s)
4a2fec
     guest_phys_blocks_free(&s->guest_phys_blocks);
4a2fec
     memory_mapping_list_free(&s->list);
4a2fec
     close(s->fd);
4a2fec
+    g_free(s->guest_note);
4a2fec
+    s->guest_note = NULL;
4a2fec
     if (s->resume) {
4a2fec
         if (s->detached) {
4a2fec
             qemu_mutex_lock_iothread();
4a2fec
@@ -235,6 +246,19 @@ static inline int cpu_index(CPUState *cpu)
4a2fec
     return cpu->cpu_index + 1;
4a2fec
 }
4a2fec
 
4a2fec
+static void write_guest_note(WriteCoreDumpFunction f, DumpState *s,
4a2fec
+                             Error **errp)
4a2fec
+{
4a2fec
+    int ret;
4a2fec
+
4a2fec
+    if (s->guest_note) {
4a2fec
+        ret = f(s->guest_note, s->guest_note_size, s);
4a2fec
+        if (ret < 0) {
4a2fec
+            error_setg(errp, "dump: failed to write guest note");
4a2fec
+        }
4a2fec
+    }
4a2fec
+}
4a2fec
+
4a2fec
 static void write_elf64_notes(WriteCoreDumpFunction f, DumpState *s,
4a2fec
                               Error **errp)
4a2fec
 {
4a2fec
@@ -258,6 +282,8 @@ static void write_elf64_notes(WriteCoreDumpFunction f, DumpState *s,
4a2fec
             return;
4a2fec
         }
4a2fec
     }
4a2fec
+
4a2fec
+    write_guest_note(f, s, errp);
4a2fec
 }
4a2fec
 
4a2fec
 static void write_elf32_note(DumpState *s, Error **errp)
4a2fec
@@ -303,6 +329,8 @@ static void write_elf32_notes(WriteCoreDumpFunction f, DumpState *s,
4a2fec
             return;
4a2fec
         }
4a2fec
     }
4a2fec
+
4a2fec
+    write_guest_note(f, s, errp);
4a2fec
 }
4a2fec
 
4a2fec
 static void write_elf_section(DumpState *s, int type, Error **errp)
4a2fec
@@ -714,6 +742,44 @@ static int buf_write_note(const void *buf, size_t size, void *opaque)
4a2fec
     return 0;
4a2fec
 }
4a2fec
 
4a2fec
+/*
4a2fec
+ * This function retrieves various sizes from an elf header.
4a2fec
+ *
4a2fec
+ * @note has to be a valid ELF note. The return sizes are unmodified
4a2fec
+ * (not padded or rounded up to be multiple of 4).
4a2fec
+ */
4a2fec
+static void get_note_sizes(DumpState *s, const void *note,
4a2fec
+                           uint64_t *note_head_size,
4a2fec
+                           uint64_t *name_size,
4a2fec
+                           uint64_t *desc_size)
4a2fec
+{
4a2fec
+    uint64_t note_head_sz;
4a2fec
+    uint64_t name_sz;
4a2fec
+    uint64_t desc_sz;
4a2fec
+
4a2fec
+    if (s->dump_info.d_class == ELFCLASS64) {
4a2fec
+        const Elf64_Nhdr *hdr = note;
4a2fec
+        note_head_sz = sizeof(Elf64_Nhdr);
4a2fec
+        name_sz = tswap64(hdr->n_namesz);
4a2fec
+        desc_sz = tswap64(hdr->n_descsz);
4a2fec
+    } else {
4a2fec
+        const Elf32_Nhdr *hdr = note;
4a2fec
+        note_head_sz = sizeof(Elf32_Nhdr);
4a2fec
+        name_sz = tswap32(hdr->n_namesz);
4a2fec
+        desc_sz = tswap32(hdr->n_descsz);
4a2fec
+    }
4a2fec
+
4a2fec
+    if (note_head_size) {
4a2fec
+        *note_head_size = note_head_sz;
4a2fec
+    }
4a2fec
+    if (name_size) {
4a2fec
+        *name_size = name_sz;
4a2fec
+    }
4a2fec
+    if (desc_size) {
4a2fec
+        *desc_size = desc_sz;
4a2fec
+    }
4a2fec
+}
4a2fec
+
4a2fec
 /* write common header, sub header and elf note to vmcore */
4a2fec
 static void create_header32(DumpState *s, Error **errp)
4a2fec
 {
4a2fec
@@ -1492,6 +1558,7 @@ static void dump_init(DumpState *s, int fd, bool has_format,
4a2fec
                       DumpGuestMemoryFormat format, bool paging, bool has_filter,
4a2fec
                       int64_t begin, int64_t length, Error **errp)
4a2fec
 {
4a2fec
+    VMCoreInfoState *vmci = vmcoreinfo_find();
4a2fec
     CPUState *cpu;
4a2fec
     int nr_cpus;
4a2fec
     Error *err = NULL;
4a2fec
@@ -1569,6 +1636,46 @@ static void dump_init(DumpState *s, int fd, bool has_format,
4a2fec
         goto cleanup;
4a2fec
     }
4a2fec
 
4a2fec
+    /*
4a2fec
+     * The goal of this block is to copy the guest note out of
4a2fec
+     * the guest.  Failure to do so is not fatal for dumping.
4a2fec
+     */
4a2fec
+    if (vmci) {
4a2fec
+        uint64_t addr, note_head_size, name_size, desc_size;
4a2fec
+        uint32_t size;
4a2fec
+        uint16_t format;
4a2fec
+
4a2fec
+        note_head_size = s->dump_info.d_class == ELFCLASS32 ?
4a2fec
+            sizeof(Elf32_Nhdr) : sizeof(Elf64_Nhdr);
4a2fec
+
4a2fec
+        format = le16_to_cpu(vmci->vmcoreinfo.guest_format);
4a2fec
+        size = le32_to_cpu(vmci->vmcoreinfo.size);
4a2fec
+        addr = le64_to_cpu(vmci->vmcoreinfo.paddr);
4a2fec
+        if (!vmci->has_vmcoreinfo) {
4a2fec
+            warn_report("guest note is not present");
4a2fec
+        } else if (size < note_head_size || size > MAX_GUEST_NOTE_SIZE) {
4a2fec
+            warn_report("guest note size is invalid: %" PRIu32, size);
4a2fec
+        } else if (format != VMCOREINFO_FORMAT_ELF) {
4a2fec
+            warn_report("guest note format is unsupported: %" PRIu16, format);
4a2fec
+        } else {
4a2fec
+            s->guest_note = g_malloc(size + 1); /* +1 for adding \0 */
4a2fec
+            cpu_physical_memory_read(addr, s->guest_note, size);
4a2fec
+
4a2fec
+            get_note_sizes(s, s->guest_note, NULL, &name_size, &desc_size);
4a2fec
+            s->guest_note_size = ELF_NOTE_SIZE(note_head_size, name_size,
4a2fec
+                                               desc_size);
4a2fec
+            if (name_size > MAX_GUEST_NOTE_SIZE ||
4a2fec
+                desc_size > MAX_GUEST_NOTE_SIZE ||
4a2fec
+                s->guest_note_size > size) {
4a2fec
+                warn_report("Invalid guest note header");
4a2fec
+                g_free(s->guest_note);
4a2fec
+                s->guest_note = NULL;
4a2fec
+            } else {
4a2fec
+                s->note_size += s->guest_note_size;
4a2fec
+            }
4a2fec
+        }
4a2fec
+    }
4a2fec
+
4a2fec
     /* get memory mapping */
4a2fec
     if (paging) {
4a2fec
         qemu_get_guest_memory_mapping(&s->list, &s->guest_phys_blocks, &err;;
4a2fec
diff --git a/include/sysemu/dump.h b/include/sysemu/dump.h
4a2fec
index 2672a15..df43bd0 100644
4a2fec
--- a/include/sysemu/dump.h
4a2fec
+++ b/include/sysemu/dump.h
4a2fec
@@ -192,6 +192,8 @@ typedef struct DumpState {
4a2fec
                                   * this could be used to calculate
4a2fec
                                   * how much work we have
4a2fec
                                   * finished. */
4a2fec
+    uint8_t *guest_note;         /* ELF note content */
4a2fec
+    size_t guest_note_size;
4a2fec
 } DumpState;
4a2fec
 
4a2fec
 uint16_t cpu_to_dump16(DumpState *s, uint16_t val);
4a2fec
-- 
4a2fec
1.8.3.1
4a2fec