Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F108996927
D19253.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
11 KB
Referenced Files
None
Subscribers
None
D19253.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D19253: Add a tool to convert kernel minidump to elf coredump
Attached
Detach File
Event Timeline
Log In to Comment