Page MenuHomeFreeBSD

D19253.diff
No OneTemporary

D19253.diff

Index: lib/libkvm/kvm.h
===================================================================
--- lib/libkvm/kvm.h
+++ lib/libkvm/kvm.h
@@ -125,6 +125,7 @@
ssize_t kvm_read2(kvm_t *, kvaddr_t, void *, size_t);
ssize_t kvm_write(kvm_t *, unsigned long, const void *, size_t);
+void *kvm_get_ehdr(kvm_t *);
typedef int kvm_walk_pages_cb_t(struct kvm_page *, void *);
int kvm_walk_pages(kvm_t *, kvm_walk_pages_cb_t *, void *);
__END_DECLS
Index: lib/libkvm/kvm.c
===================================================================
--- lib/libkvm/kvm.c
+++ lib/libkvm/kvm.c
@@ -499,3 +499,7 @@
return (kd->arch->ka_walk_pages(kd, cb, closure));
}
+
+void *kvm_get_ehdr(kvm_t *kd) {
+ return (void*)(&kd->nlehdr);
+}
Index: tools/tools/minidump_to_elf/Makefile
===================================================================
--- /dev/null
+++ tools/tools/minidump_to_elf/Makefile
@@ -0,0 +1,9 @@
+# $FreeBSD$
+
+PROG= minidump-to-elf
+SRCS= main.c
+MAN=
+LIBADD+= kvm
+LIBADD+= elf
+
+.include <bsd.prog.mk>
Index: tools/tools/minidump_to_elf/main.c
===================================================================
--- /dev/null
+++ tools/tools/minidump_to_elf/main.c
@@ -0,0 +1,274 @@
+#include <kvm.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <libelf.h>
+#include <gelf.h>
+#include <unistd.h>
+#include <err.h>
+#include <vm/vm.h>
+
+/* A range is a contiguous sets of pages in the minidump. */
+struct range_info {
+ u_long vaddr; /* Vaddr of the range. */
+ u_long off; /* Offset of range in the original core file. */
+ u_char prot; /* Protection flags of range. */
+ void* buf; /* The data inside the range to write out. */
+ size_t rangelen;/* The length of the range. */
+ size_t filelen; /* The length of the buf. */
+};
+
+struct range_info* ranges;
+int ranges_len, ranges_cap;
+
+char kvm_err[_POSIX2_LINE_MAX];
+
+void merge_ranges(void) {
+ int rin_memory, lin_memory, i, j;
+
+ for (i = 0; i < ranges_len; ++i) {
+ rin_memory = (ranges[i].off != -1);
+ for (j = 0; j < ranges_len; ++j) {
+ lin_memory = (ranges[j].off != -1);
+ if (i != j &&
+ ranges[j].vaddr + ranges[j].rangelen == ranges[i].vaddr &&
+ (lin_memory || !rin_memory) &&
+ ranges[j].prot == ranges[i].prot) {
+ ranges[j].rangelen += ranges[i].rangelen;
+ ranges[j].filelen += ranges[i].filelen;
+ if (!rin_memory && lin_memory)
+ ranges[j].off = -1;
+ ranges[i] = ranges[ranges_len-1];
+ ranges_len -= 1;
+ i -= 1;
+ break;
+ }
+ }
+ }
+}
+
+int walk_pages_cb(struct kvm_page* page, void* arg) {
+ int not_in_memory, i;
+ u_char prot;
+
+ /* NOTE: We don't care about pages that don't have a kernel vaddr. */
+ if (page->kmap_vaddr == 0)
+ return 1;
+
+ prot = 0;
+ if (page->prot & VM_PROT_READ) prot |= PF_R;
+ if (page->prot & VM_PROT_WRITE) prot |= PF_W;
+ if (page->prot & VM_PROT_EXECUTE) prot |= PF_X;
+
+ not_in_memory = (page->offset == -1);
+
+ for (i = ranges_len - 1; i >= 0; --i) {
+ if (ranges[i].vaddr == page->kmap_vaddr)
+ errx(EXIT_FAILURE, "Duplicate kernel vaddr found.");
+
+ if (ranges[i].vaddr + ranges[i].rangelen == page->kmap_vaddr &&
+ prot == ranges[i].prot) {
+
+ if (not_in_memory && ranges[i].off + 1 != 0)
+ continue;
+
+ if (not_in_memory)
+ ranges[i].off = page->offset;
+
+ ranges[i].rangelen += page->len;
+ if (ranges[i].off != -1)
+ ranges[i].filelen += page->len;
+
+ return 1;
+ }
+ }
+
+ if (ranges_len == ranges_cap) {
+ ranges_cap *= 2;
+ ranges = realloc(ranges, ranges_cap * sizeof(struct range_info));
+ }
+
+ ranges[ranges_len].vaddr = page->kmap_vaddr;
+ ranges[ranges_len].rangelen = page->len;
+ if (not_in_memory)
+ ranges[ranges_len].filelen = 0;
+ else
+ ranges[ranges_len].filelen = page->len;
+ ranges[ranges_len].off = page->offset;
+ ranges[ranges_len].prot = prot;
+
+ ranges_len += 1;
+ return 1;
+}
+
+void usage(void) {
+ errx(EXIT_FAILURE, "usage: minidump-to-elf kernel minidump [elf-output]");
+}
+
+int main(int argc, char** argv) {
+ kvm_t* kvm;
+ Elf* e;
+ GElf_Ehdr *core_header, *ehdr;
+ GElf_Phdr* phdr;
+ GElf_Shdr shdr;
+ Elf_Scn* section;
+ Elf_Data* data;
+ const char *kernel, *vmcore, *output_elf;
+ size_t cr;
+ int pagesize, elf_class, fd, i;
+
+ if (argc != 3 && argc != 4)
+ usage();
+
+ output_elf = "vmcore.elf";
+ vmcore = argv[1];
+ kernel = argv[2];
+ if (argc == 4)
+ output_elf = argv[3];
+
+ if ((kvm = kvm_open(kernel, vmcore, NULL, O_RDONLY, kvm_err)) == NULL)
+ errx(EXIT_FAILURE, "Failed to open vmcore: %s\n", kvm_err);
+
+ ranges_len = 0;
+ ranges_cap = 128;
+ ranges = calloc(ranges_cap, sizeof(struct range_info));
+
+ if (kvm_walk_pages(kvm, walk_pages_cb, NULL) == 0)
+ errx(EXIT_FAILURE, "kvm_walk_pages() failed");
+
+ merge_ranges();
+
+ if (elf_version(EV_CURRENT) == EV_NONE)
+ errx(EXIT_FAILURE, "Elf library initialization failed: %s",
+ elf_errmsg(-1));
+
+ if ((fd = open(output_elf, O_WRONLY | O_CREAT, 0777)) < 0)
+ errx(EXIT_FAILURE, "Couldn't open 'core-elf' for writing");
+
+ if ((e = elf_begin(fd, ELF_C_WRITE, NULL)) == NULL)
+ errx(EXIT_FAILURE, "elf_begin() failed: %s",
+ elf_errmsg(-1));
+
+ core_header = (GElf_Ehdr*)kvm_get_ehdr(kvm);
+ elf_class = core_header->e_ident[EI_CLASS];
+
+ if ((ehdr = gelf_newehdr(e, elf_class)) == NULL)
+ errx(EXIT_FAILURE, "gelf_newehdr() failed: %s",
+ elf_errmsg(-1));
+
+ ehdr->e_ident[EI_DATA] = core_header->e_ident[EI_DATA];
+ ehdr->e_ident[EI_CLASS] = elf_class;
+ ehdr->e_machine = core_header->e_machine;
+ ehdr->e_type = ET_CORE;
+ ehdr->e_ident[EI_OSABI] = core_header->e_ident[EI_OSABI];
+
+ /* Page size is only different for sparc64 according to man arch. */
+ pagesize = 4096;
+ if (ehdr->e_machine == EM_SPARCV9)
+ pagesize = 8192;
+
+ if ((phdr = gelf_newphdr(e, ranges_len + 1)) < 0)
+ errx(EXIT_FAILURE, "gelf_newphdr() failed: %s",
+ elf_errmsg(-1));
+
+ /* Put the ranges inside the data segment of sections. */
+ for (i = 0; i < ranges_len; ++i) {
+ ranges[i].buf = malloc(ranges[i].filelen);
+ cr = kvm_read2(kvm, ranges[i].vaddr, ranges[i].buf,
+ ranges[i].filelen);
+
+ if (cr != ranges[i].filelen)
+ errx(EXIT_FAILURE, "kvm_read2() failed");
+
+ if ((section = elf_newscn(e)) == NULL)
+ errx(EXIT_FAILURE, "elf_newscn() failed: %s",
+ elf_errmsg(-1));
+
+ if ((data = elf_newdata(section)) == NULL)
+ errx(EXIT_FAILURE, "elf_newdata() failed: %s",
+ elf_errmsg(-1));
+
+ /* Fill in the data part of the section */
+ data->d_align = pagesize;
+ data->d_off = 0LL;
+ data->d_buf= ranges[i].buf;
+ data->d_type = ELF_T_WORD;
+ data->d_size = ranges[i].filelen;
+ data->d_version = EV_CURRENT;
+
+ /* Update the section headers to have data in it. */
+ if (&shdr != gelf_getshdr(section, &shdr))
+ errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",
+ elf_errmsg(-1));
+
+ shdr.sh_name = i;
+ shdr.sh_type = SHT_PROGBITS;
+ shdr.sh_flags = SHF_OS_NONCONFORMING;
+ shdr.sh_entsize = 0;
+ shdr.sh_addr = ranges[i].vaddr;
+ if (gelf_update_shdr(section, &shdr) == 0)
+ errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s",
+ elf_errmsg(-1));
+ }
+
+ /* Update the elf file to update the offsets into the file. */
+ if (elf_update(e, ELF_C_NULL) < 0)
+ errx(EXIT_FAILURE, "elf_update() failed: %s", elf_errmsg(-1));
+
+ /*
+ * Refer to the data segments from program headers because that's
+ * where core files hold this information.
+ */
+ section = NULL;
+
+ for (i = 0; i < ranges_len; ++i) {
+ if ((section = elf_nextscn(e, section)) == NULL)
+ errx(EXIT_FAILURE, "Couldn't get all the sections");
+
+ if (phdr != gelf_getphdr(e, i, phdr))
+ errx(EXIT_FAILURE, "gelf_getphdr() failed: %s",
+ elf_errmsg(-1));
+
+ if (&shdr != gelf_getshdr(section, &shdr))
+ errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",
+ elf_errmsg(-1));
+
+ data = elf_getdata(section, NULL);
+ phdr->p_type = PT_LOAD;
+ phdr->p_flags = ranges[i].prot;
+ /* data offset is from where the section starts. */
+ phdr->p_offset = shdr.sh_offset + data->d_off;
+ phdr->p_vaddr = ranges[i].vaddr;
+ phdr->p_paddr = 0; /* Leave paddr as 0 */
+ phdr->p_filesz = ranges[i].filelen;
+ phdr->p_memsz = ranges[i].rangelen;
+ phdr->p_align = pagesize;
+ if (gelf_update_phdr(e, i, phdr) == 0)
+ errx(EXIT_FAILURE, "gelf_update_phdr() failed: %s",
+ elf_errmsg(-1));
+ }
+
+ /* Program headers header */
+ if (phdr != gelf_getphdr(e, ranges_len, phdr))
+ errx(EXIT_FAILURE, "gelf_getphdr() failed: %s",
+ elf_errmsg(-1));
+ phdr->p_type = PT_PHDR;
+ phdr->p_offset = ehdr->e_phoff;
+ phdr->p_filesz = gelf_fsize(e, ELF_T_PHDR, 1 , EV_CURRENT);
+
+ elf_flagphdr(e, ELF_C_SET, ELF_F_DIRTY);
+
+ if (elf_update(e, ELF_C_WRITE) < 0)
+ errx(EXIT_FAILURE, "elf_update() failed: %s", elf_errmsg(-1));
+
+ if (kvm_close(kvm) != 0)
+ errx(EXIT_FAILURE, "Couldn't close the vmcore \"%s\": %s",
+ vmcore, kvm_geterr(kvm));
+
+ for (i = 0; i < ranges_len; ++i)
+ free(ranges[i].buf);
+ free(ranges);
+ elf_end(e);
+ close(fd);
+}
+
Index: tools/tools/minidump_to_elf/minidump-to-elf.1
===================================================================
--- /dev/null
+++ tools/tools/minidump_to_elf/minidump-to-elf.1
@@ -0,0 +1,79 @@
+.\" Copyright 1997 John-Mark Gurney. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
+.\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd February 22, 2019
+.Dt MINIDUMP-TO-ELF 3
+.Os
+.Sh NAME
+.Nm minidump-to-elf
+.Nd convert a kernel minidump into a kernel ELF core file
+.Sh SYNOPSIS
+.Nm
+.Ar kernel
+.Ar minidump
+.Op Ar elf-output
+.Sh DESCRIPTION
+The
+.Nm
+utility takes in as input
+.Ar kernel ,
+and
+.Ar minidump
+files and produces a kernel core file in ELF format. If the optional
+.Ar elf-output
+is given then the output will be written to this file. If not,
+.Nm
+defaults to
+.Ar ./vmcore.elf .
+.Pp
+.Ar kernel
+is the kernel binary that has produced the
+.Ar minidump .
+.Pp
+.Ar minidump
+is the core dump generated by a kernel panic that is
+found by default as
+.Ar /var/crash.vmcore.# .
+.Sh EXIT STATUS
+Exit status is 0 on success, and 1 if the command
+fails if a file does not exist, is too short, fails to read properly,
+or fails to properly convert the minidump file.
+.Sh EXAMPLES
+The following is an example of a typical usage
+of the
+.Nm
+command:
+.Bd -literal -offset indent
+minidump-to-elf kernel.full /var/crash/vmcore.0 vmcore.0.elf
+minidump-to-elf kernel.full /var/crash/vmcore.0
+.Ed
+.Sh HISTORY
+The
+.Nm
+manual page first appeared in
+.Fx 13.0 .
+.Sh AUTHORS
+This manual page was written by
+.An Bora Ozarslan Aq Mt borako.ozarslan@gmail.com .

File Metadata

Mime Type
text/plain
Expires
Fri, Jan 31, 10:59 AM (11 h, 2 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
16361321
Default Alt Text
D19253.diff (11 KB)

Event Timeline