Module Name:    othersrc
Committed By:   mlelstv
Date:           Thu Dec 22 10:31:17 UTC 2016

Added Files:
        othersrc/usr.bin/guest2core: Makefile README main.c

Log Message:
Translates the dump of qemu guest memory to a NetBSD core file.
So far x86_64 only.


To generate a diff of this commit:
cvs rdiff -u -r0 -r1.1 othersrc/usr.bin/guest2core/Makefile \
    othersrc/usr.bin/guest2core/README othersrc/usr.bin/guest2core/main.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Added files:

Index: othersrc/usr.bin/guest2core/Makefile
diff -u /dev/null othersrc/usr.bin/guest2core/Makefile:1.1
--- /dev/null	Thu Dec 22 10:31:17 2016
+++ othersrc/usr.bin/guest2core/Makefile	Thu Dec 22 10:31:17 2016
@@ -0,0 +1,14 @@
+#       $NetBSD: Makefile,v 1.1 2016/12/22 10:31:17 mlelstv Exp $
+#       @(#)Makefile    8.1 (Berkeley) 6/6/93
+
+.include <bsd.own.mk>
+
+WARNS=  3
+PROG=   guest2core
+SRCS=   main.c
+MAN=
+
+LDADD+= -lelf
+DPADD+= ${LIBELF}
+
+.include <bsd.prog.mk>
Index: othersrc/usr.bin/guest2core/README
diff -u /dev/null othersrc/usr.bin/guest2core/README:1.1
--- /dev/null	Thu Dec 22 10:31:17 2016
+++ othersrc/usr.bin/guest2core/README	Thu Dec 22 10:31:17 2016
@@ -0,0 +1,20 @@
+
+This program translates the output of a qemu "dump-guest-memory"
+command into a NetBSD core dump to be analyzed by crash or gdb.
+
+So far this is for x86_64 only.
+
+The x86_64 core dump needs a single parameter, the physical address
+of the PDP to find the MMU tables to translate the phyiscal address
+core dump to virtual (KVA) addresses used by libkvm. This value
+needs to be passed to the program as an extra argument.
+
+The value is stored on the running guest in the kernel variable
+PDPpaddr. The value doesn't change between runs but between
+different kernels.
+
+You can get the value either from qemu console by looking at the
+virtual memory of the guest or by attaching a remote gdb to qemu.
+In either case you need an unstripped version of the guest kernel
+to find the virtual address of PDPpaddr.
+
Index: othersrc/usr.bin/guest2core/main.c
diff -u /dev/null othersrc/usr.bin/guest2core/main.c:1.1
--- /dev/null	Thu Dec 22 10:31:17 2016
+++ othersrc/usr.bin/guest2core/main.c	Thu Dec 22 10:31:17 2016
@@ -0,0 +1,227 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <err.h>
+
+#include <fcntl.h>
+#include <gelf.h>
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/core.h>
+#include <sys/kcore.h>
+#include <machine/kcore.h>
+
+#include <sys/mman.h>
+
+#define MID_MACHINE MID_X86_64
+
+struct chunk {
+	u_quad_t adr;	/* physical load address */
+	u_quad_t sz;	/* size */
+	off_t pos;	/* position in ELF file */
+};
+
+static int
+write_padding(int fd, size_t sz)
+{
+	static char padding[128];
+	ssize_t out = 0;
+
+	while (sz > sizeof(padding)) {
+		out += write(fd, padding, sizeof(padding));
+		sz -= sizeof(padding);
+	}
+	if (sz > 0)
+		out += write(fd, padding, sz);
+
+	printf("padding %zd\n",out);
+
+	return out;
+}
+
+static void
+write_header(int fd, int n, struct chunk *chunk, uint64_t ptd)
+{
+	struct kcore_hdr hdr;
+	struct kcore_seg seg;
+	struct cpu_kcore_hdr cpu;
+	struct phys_ram_seg phys;
+	uint64_t total;
+	int i;
+	ssize_t hdrsz;
+
+	hdrsz = 0;
+
+	hdr.c_hdrsize = ALIGN(sizeof(hdr));
+	hdr.c_seghdrsize = ALIGN(sizeof(seg));
+	hdr.c_nseg = 2;
+	CORE_SETMAGIC(hdr, KCORE_MAGIC, MID_MACHINE, 0);
+	hdrsz += write(fd, &hdr, sizeof(hdr));
+	hdrsz += write_padding(fd, hdr.c_hdrsize - sizeof(hdr));
+
+	seg.c_size = ALIGN(sizeof(cpu) + n * sizeof(phys));
+	CORE_SETMAGIC(seg, KCORESEG_MAGIC, MID_MACHINE, CORE_CPU);
+	hdrsz += write(fd, &seg, sizeof(seg));
+	hdrsz += write_padding(fd, hdr.c_seghdrsize - sizeof(seg));
+
+	cpu.ptdpaddr = ptd;
+	cpu.nmemsegs = n;
+	hdrsz += write(fd, &cpu, sizeof(cpu));
+
+	total = 0;
+	for (i=0; i<n; ++i) {
+		phys.start = chunk[i].adr;
+		phys.size = chunk[i].sz;
+		total += chunk[i].sz;
+		hdrsz += write(fd, &phys, sizeof(phys));
+	}
+	hdrsz += write_padding(fd, seg.c_size - (sizeof(cpu) + n * sizeof(phys)));
+
+	printf("total = %016jx\n",(uintmax_t) total);
+
+	seg.c_size = total;
+	CORE_SETMAGIC(seg, KCORESEG_MAGIC, MID_MACHINE, CORE_DATA);
+	hdrsz += write(fd, &seg, sizeof(seg));
+	hdrsz += write_padding(fd, hdr.c_seghdrsize - sizeof(seg));
+
+	printf("hdrsz = %zd\n", hdrsz);
+}
+
+static void
+write_pages(int fd, int n, struct chunk *chunk, int infd)
+{
+	int i;
+	void *buf;
+	u_quad_t start;
+	u_quad_t chunksz;
+	u_quad_t chunklet = 1024*1024;
+
+	for (i=0; i<n; ++i) {
+		start = 0;
+
+		printf("phys %016jx @ offset %016jx\n",
+			chunk[i].adr + start, chunk[i].pos + start);
+
+		while (start < chunk[i].sz) {
+
+			chunksz = chunk[i].sz - start;
+			if (chunksz > chunklet)
+				chunksz = chunklet;
+
+			buf = mmap(NULL, chunksz,
+				PROT_READ,
+				MAP_FILE | MAP_PRIVATE,
+				infd, chunk[i].pos + start);
+			if (buf == MAP_FAILED)
+				err(1, "mmap");
+
+			write(fd, buf, chunksz);
+
+			munmap(buf, chunksz);
+
+			start += chunksz;
+		}
+	}
+}
+
+static void
+errelf(int code, const char *mess)
+{
+	errx(code, "%s: %s", mess, elf_errmsg(-1));
+}
+
+static int
+elf_load(int fd, struct chunk out[], int num)
+{
+	Elf *e;
+	GElf_Phdr phdr;
+	int i;
+	size_t n;
+	const char *typ;
+	int nout = 0;
+
+	e = elf_begin(fd, ELF_C_READ, NULL);
+	if (e == NULL) errelf(1, "elf_begin");
+
+	if (elf_kind(e) != ELF_K_ELF)
+		errx(1, "Not an ELF object");
+
+	if ((i = gelf_getclass(e)) == ELFCLASSNONE)
+		errelf(1, "getclass");
+
+	printf("%d-bit ELF object\n", i == ELFCLASS32 ? 32 : 64);
+
+	if (elf_getphdrnum(e, &n) != 0)
+		errelf(1, "getphdrnum");
+	
+	printf("phnum %zu\n", n);
+
+	for (i=0; i<n; ++i) {
+		if (gelf_getphdr(e, i, &phdr) != &phdr)
+			errelf(1, "gelf_getphdr");
+
+		switch (phdr.p_type) {
+		case PT_NOTE: typ = "note";break;
+		case PT_LOAD: typ = "load";break;
+		default:      typ = "????";break;
+		}
+
+		printf("%d: %s %016jx %016jx %016jx %016jx @ %016jx\n",
+			i,
+			typ,
+			(uintmax_t)phdr.p_vaddr,
+			(uintmax_t)phdr.p_paddr,
+			(uintmax_t)phdr.p_memsz,
+			(uintmax_t)phdr.p_filesz,
+			(uintmax_t)phdr.p_offset);
+
+		if (phdr.p_type == PT_LOAD && phdr.p_memsz > 0 && nout < num) {
+			out[nout].adr = phdr.p_paddr;
+			out[nout].sz  = phdr.p_filesz;
+			out[nout].pos = phdr.p_offset;
+			++nout;
+		}
+	}
+
+	elf_end(e);
+
+	return nout;
+}
+
+int
+main(int argc, char *argv[])
+{
+	struct chunk C[10];
+	int n, elffd, kvmfd;
+	uint64_t ptd;
+
+	if (argc < 4)
+		errx(1, "usage: %s infile outfile ptd", argv[0]);
+
+	ptd = strtoumax(argv[3], NULL, 16);
+	printf("ptd = %016jx\n",(intmax_t)ptd);
+
+	if (elf_version(EV_CURRENT) == EV_NONE)
+		errelf(1, "elf_version");
+
+	elffd = open(argv[1], O_RDONLY, 0);
+	if (elffd == -1)
+		err(1, "open %s", argv[1]);
+
+	n = elf_load(elffd, C, 10);
+
+	printf("%d chunks\n", n);
+
+	if (n > 0) {
+		kvmfd = creat(argv[2], 0666);
+		if (kvmfd == -1)
+			err(1, "creat %s", argv[2]);
+
+		write_header(kvmfd, n, C, ptd);
+		write_pages(kvmfd, n, C, elffd);
+
+		close(kvmfd);
+	}
+
+	close(elffd);
+}

Reply via email to