|
|
9ae3a8 |
From 693375003f594a1d19acd35df19141b92a5c8822 Mon Sep 17 00:00:00 2001
|
|
|
9ae3a8 |
From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= <marcandre.lureau@redhat.com>
|
|
|
9ae3a8 |
Date: Wed, 13 Dec 2017 13:39:01 +0100
|
|
|
9ae3a8 |
Subject: [PATCH 30/41] dump: add guest ELF note
|
|
|
9ae3a8 |
MIME-Version: 1.0
|
|
|
9ae3a8 |
Content-Type: text/plain; charset=UTF-8
|
|
|
9ae3a8 |
Content-Transfer-Encoding: 8bit
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
RH-Author: Marc-André Lureau <marcandre.lureau@redhat.com>
|
|
|
9ae3a8 |
Message-id: <20171213133912.26176-31-marcandre.lureau@redhat.com>
|
|
|
9ae3a8 |
Patchwork-id: 78377
|
|
|
9ae3a8 |
O-Subject: [RHEL-7.5 qemu-kvm PATCH v3 30/41] dump: add guest ELF note
|
|
|
9ae3a8 |
Bugzilla: 1411490
|
|
|
9ae3a8 |
RH-Acked-by: Laszlo Ersek <lersek@redhat.com>
|
|
|
9ae3a8 |
RH-Acked-by: Michael S. Tsirkin <mst@redhat.com>
|
|
|
9ae3a8 |
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
Read the guest ELF PT_NOTE from guest memory when fw_cfg
|
|
|
9ae3a8 |
etc/vmcoreinfo entry provides the location, and write it as an
|
|
|
9ae3a8 |
additional note in the dump.
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
|
|
|
9ae3a8 |
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
|
|
|
9ae3a8 |
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
(cherry picked from commit 903ef7349699dcd932b5981b85c1f1ebe4a4bf2a)
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
RHEL: Minor conflicts due to "detach" mode not being backported.
|
|
|
9ae3a8 |
Replace warn_report() with error_report().
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
|
|
|
9ae3a8 |
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
|
|
|
9ae3a8 |
---
|
|
|
9ae3a8 |
dump.c | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
9ae3a8 |
include/sysemu/dump.h | 2 +
|
|
|
9ae3a8 |
2 files changed, 108 insertions(+)
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
diff --git a/dump.c b/dump.c
|
|
|
9ae3a8 |
index d629c8d..823d1ad 100644
|
|
|
9ae3a8 |
--- a/dump.c
|
|
|
9ae3a8 |
+++ b/dump.c
|
|
|
9ae3a8 |
@@ -24,6 +24,7 @@
|
|
|
9ae3a8 |
#include "sysemu/cpus.h"
|
|
|
9ae3a8 |
#include "qapi/error.h"
|
|
|
9ae3a8 |
#include "qmp-commands.h"
|
|
|
9ae3a8 |
+#include "hw/misc/vmcoreinfo.h"
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
#include <zlib.h>
|
|
|
9ae3a8 |
#ifdef CONFIG_LZO
|
|
|
9ae3a8 |
@@ -36,6 +37,13 @@
|
|
|
9ae3a8 |
#define ELF_MACHINE_UNAME "Unknown"
|
|
|
9ae3a8 |
#endif
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
+#define MAX_GUEST_NOTE_SIZE (1 << 20) /* 1MB should be enough */
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+#define ELF_NOTE_SIZE(hdr_size, name_size, desc_size) \
|
|
|
9ae3a8 |
+ ((DIV_ROUND_UP((hdr_size), 4) + \
|
|
|
9ae3a8 |
+ DIV_ROUND_UP((name_size), 4) + \
|
|
|
9ae3a8 |
+ DIV_ROUND_UP((desc_size), 4)) * 4)
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
uint16_t cpu_to_dump16(DumpState *s, uint16_t val)
|
|
|
9ae3a8 |
{
|
|
|
9ae3a8 |
if (s->dump_info.d_endian == ELFDATA2LSB) {
|
|
|
9ae3a8 |
@@ -74,6 +82,8 @@ static int dump_cleanup(DumpState *s)
|
|
|
9ae3a8 |
guest_phys_blocks_free(&s->guest_phys_blocks);
|
|
|
9ae3a8 |
memory_mapping_list_free(&s->list);
|
|
|
9ae3a8 |
close(s->fd);
|
|
|
9ae3a8 |
+ g_free(s->guest_note);
|
|
|
9ae3a8 |
+ s->guest_note = NULL;
|
|
|
9ae3a8 |
if (s->resume) {
|
|
|
9ae3a8 |
vm_start();
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
@@ -227,6 +237,19 @@ static inline int cpu_index(CPUState *cpu)
|
|
|
9ae3a8 |
return cpu->cpu_index + 1;
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
+static void write_guest_note(WriteCoreDumpFunction f, DumpState *s,
|
|
|
9ae3a8 |
+ Error **errp)
|
|
|
9ae3a8 |
+{
|
|
|
9ae3a8 |
+ int ret;
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ if (s->guest_note) {
|
|
|
9ae3a8 |
+ ret = f(s->guest_note, s->guest_note_size, s);
|
|
|
9ae3a8 |
+ if (ret < 0) {
|
|
|
9ae3a8 |
+ error_setg(errp, "dump: failed to write guest note");
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+}
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
static void write_elf64_notes(WriteCoreDumpFunction f, DumpState *s,
|
|
|
9ae3a8 |
Error **errp)
|
|
|
9ae3a8 |
{
|
|
|
9ae3a8 |
@@ -253,6 +276,8 @@ static void write_elf64_notes(WriteCoreDumpFunction f, DumpState *s,
|
|
|
9ae3a8 |
return;
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ write_guest_note(f, s, errp);
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
static void write_elf32_note(DumpState *s, Error **errp)
|
|
|
9ae3a8 |
@@ -301,6 +326,8 @@ static void write_elf32_notes(WriteCoreDumpFunction f, DumpState *s,
|
|
|
9ae3a8 |
return;
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ write_guest_note(f, s, errp);
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
static void write_elf_section(DumpState *s, int type, Error **errp)
|
|
|
9ae3a8 |
@@ -712,6 +739,44 @@ static int buf_write_note(const void *buf, size_t size, void *opaque)
|
|
|
9ae3a8 |
return 0;
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
+/*
|
|
|
9ae3a8 |
+ * This function retrieves various sizes from an elf header.
|
|
|
9ae3a8 |
+ *
|
|
|
9ae3a8 |
+ * @note has to be a valid ELF note. The return sizes are unmodified
|
|
|
9ae3a8 |
+ * (not padded or rounded up to be multiple of 4).
|
|
|
9ae3a8 |
+ */
|
|
|
9ae3a8 |
+static void get_note_sizes(DumpState *s, const void *note,
|
|
|
9ae3a8 |
+ uint64_t *note_head_size,
|
|
|
9ae3a8 |
+ uint64_t *name_size,
|
|
|
9ae3a8 |
+ uint64_t *desc_size)
|
|
|
9ae3a8 |
+{
|
|
|
9ae3a8 |
+ uint64_t note_head_sz;
|
|
|
9ae3a8 |
+ uint64_t name_sz;
|
|
|
9ae3a8 |
+ uint64_t desc_sz;
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ if (s->dump_info.d_class == ELFCLASS64) {
|
|
|
9ae3a8 |
+ const Elf64_Nhdr *hdr = note;
|
|
|
9ae3a8 |
+ note_head_sz = sizeof(Elf64_Nhdr);
|
|
|
9ae3a8 |
+ name_sz = tswap64(hdr->n_namesz);
|
|
|
9ae3a8 |
+ desc_sz = tswap64(hdr->n_descsz);
|
|
|
9ae3a8 |
+ } else {
|
|
|
9ae3a8 |
+ const Elf32_Nhdr *hdr = note;
|
|
|
9ae3a8 |
+ note_head_sz = sizeof(Elf32_Nhdr);
|
|
|
9ae3a8 |
+ name_sz = tswap32(hdr->n_namesz);
|
|
|
9ae3a8 |
+ desc_sz = tswap32(hdr->n_descsz);
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ if (note_head_size) {
|
|
|
9ae3a8 |
+ *note_head_size = note_head_sz;
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+ if (name_size) {
|
|
|
9ae3a8 |
+ *name_size = name_sz;
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+ if (desc_size) {
|
|
|
9ae3a8 |
+ *desc_size = desc_sz;
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+}
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
/* write common header, sub header and elf note to vmcore */
|
|
|
9ae3a8 |
static void create_header32(DumpState *s, Error **errp)
|
|
|
9ae3a8 |
{
|
|
|
9ae3a8 |
@@ -1493,6 +1558,7 @@ static void dump_init(DumpState *s, int fd, bool has_format,
|
|
|
9ae3a8 |
int64_t begin, int64_t length, Error **errp)
|
|
|
9ae3a8 |
{
|
|
|
9ae3a8 |
CPUArchState *env;
|
|
|
9ae3a8 |
+ VMCoreInfoState *vmci = vmcoreinfo_find();
|
|
|
9ae3a8 |
int nr_cpus;
|
|
|
9ae3a8 |
Error *err = NULL;
|
|
|
9ae3a8 |
int ret;
|
|
|
9ae3a8 |
@@ -1569,6 +1635,46 @@ static void dump_init(DumpState *s, int fd, bool has_format,
|
|
|
9ae3a8 |
goto cleanup;
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
+ /*
|
|
|
9ae3a8 |
+ * The goal of this block is to copy the guest note out of
|
|
|
9ae3a8 |
+ * the guest. Failure to do so is not fatal for dumping.
|
|
|
9ae3a8 |
+ */
|
|
|
9ae3a8 |
+ if (vmci) {
|
|
|
9ae3a8 |
+ uint64_t addr, note_head_size, name_size, desc_size;
|
|
|
9ae3a8 |
+ uint32_t size;
|
|
|
9ae3a8 |
+ uint16_t format;
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ note_head_size = s->dump_info.d_class == ELFCLASS32 ?
|
|
|
9ae3a8 |
+ sizeof(Elf32_Nhdr) : sizeof(Elf64_Nhdr);
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ format = le16_to_cpu(vmci->vmcoreinfo.guest_format);
|
|
|
9ae3a8 |
+ size = le32_to_cpu(vmci->vmcoreinfo.size);
|
|
|
9ae3a8 |
+ addr = le64_to_cpu(vmci->vmcoreinfo.paddr);
|
|
|
9ae3a8 |
+ if (!vmci->has_vmcoreinfo) {
|
|
|
9ae3a8 |
+ error_report("guest note is not present");
|
|
|
9ae3a8 |
+ } else if (size < note_head_size || size > MAX_GUEST_NOTE_SIZE) {
|
|
|
9ae3a8 |
+ error_report("guest note size is invalid: %" PRIu32, size);
|
|
|
9ae3a8 |
+ } else if (format != VMCOREINFO_FORMAT_ELF) {
|
|
|
9ae3a8 |
+ error_report("guest note format is unsupported: %" PRIu16, format);
|
|
|
9ae3a8 |
+ } else {
|
|
|
9ae3a8 |
+ s->guest_note = g_malloc(size + 1); /* +1 for adding \0 */
|
|
|
9ae3a8 |
+ cpu_physical_memory_read(addr, s->guest_note, size);
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ get_note_sizes(s, s->guest_note, NULL, &name_size, &desc_size);
|
|
|
9ae3a8 |
+ s->guest_note_size = ELF_NOTE_SIZE(note_head_size, name_size,
|
|
|
9ae3a8 |
+ desc_size);
|
|
|
9ae3a8 |
+ if (name_size > MAX_GUEST_NOTE_SIZE ||
|
|
|
9ae3a8 |
+ desc_size > MAX_GUEST_NOTE_SIZE ||
|
|
|
9ae3a8 |
+ s->guest_note_size > size) {
|
|
|
9ae3a8 |
+ error_report("Invalid guest note header");
|
|
|
9ae3a8 |
+ g_free(s->guest_note);
|
|
|
9ae3a8 |
+ s->guest_note = NULL;
|
|
|
9ae3a8 |
+ } else {
|
|
|
9ae3a8 |
+ s->note_size += s->guest_note_size;
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+ }
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
/* get memory mapping */
|
|
|
9ae3a8 |
if (paging) {
|
|
|
9ae3a8 |
qemu_get_guest_memory_mapping(&s->list, &s->guest_phys_blocks, &err;;
|
|
|
9ae3a8 |
diff --git a/include/sysemu/dump.h b/include/sysemu/dump.h
|
|
|
9ae3a8 |
index b5ebb0a..343dad4 100644
|
|
|
9ae3a8 |
--- a/include/sysemu/dump.h
|
|
|
9ae3a8 |
+++ b/include/sysemu/dump.h
|
|
|
9ae3a8 |
@@ -189,6 +189,8 @@ typedef struct DumpState {
|
|
|
9ae3a8 |
* this could be used to calculate
|
|
|
9ae3a8 |
* how much work we have
|
|
|
9ae3a8 |
* finished. */
|
|
|
9ae3a8 |
+ uint8_t *guest_note; /* ELF note content */
|
|
|
9ae3a8 |
+ size_t guest_note_size;
|
|
|
9ae3a8 |
} DumpState;
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
uint16_t cpu_to_dump16(DumpState *s, uint16_t val);
|
|
|
9ae3a8 |
--
|
|
|
9ae3a8 |
1.8.3.1
|
|
|
9ae3a8 |
|