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);
+}