Re: how to use crash utility to parse the binary memory dump

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



> I tested your latest patch on the sample ARM and ARM64 RAM dumps
> you sent me.
>
> As far as the patch itself is concerned, I ran into a problem
> where if crash is invoked in a directory where it does not have
> write permission, the session hangs trying to write to a bad file
> descriptor -- because of this:
>
>         fd2 = open(out_elf, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR);
>         if (!fd2) {
>                 error(INFO, "%s open error\n", out_elf);
>                 goto end1;
>         }
>
> It should be "if (fd2 < 0)".
>
Thanks. The corrected patch is attached.

> I should have been more clear w/respect to "a temporary file".
> what I was suggesting was that you do something like using
> mkstemp(3) to create a temporay file in /var/tmp, and then
> unlink() it immediately so it would only exist until the crash
> session ends.
>
Done.


> So I'm guessing that this dumpfile was taken before the "init" task was even
> created, and the kernel data structures were not fully initialized?
>
That's possible. IIRC, because of some issue with the setup, I had to
stop execution and get the ramdump before the ramdisk was mounted.

> Maybe you can try taking a RAM dump on an ARM64 machine after
> it is up and running?
>
Unfortunately I don't have access to any arm64 machines. I am not sure
when I can get one.

Thanks,
Vinayak
From 69ffbdcd8f61d2eb9e4ab3772eb5d9fe2b8b939b Mon Sep 17 00:00:00 2001
From: Vinayak Menon <vinayakm.list@xxxxxxxxx>
Date: Wed, 23 Jul 2014 11:30:40 +0530
Subject: [PATCH] raw RAM image support

Raw RAM image can be passed to crash utility in the
following format.

> crash [options] image@address... [namelist] [-o out_file]
image@address is an ordered pair where, image is the raw
RAM file representing a memory node, and address is the
physical start of the node. Multiple such ordered pairs can
be provided, which represent different memory nodes.

The raw dump is converted to kdump format.

Optionally -o can be used to specify the ELF output file
to be generated.

Signed-off-by: Vinayak Menon <vinayakm.list@xxxxxxxxx>
---
 Makefile  |   9 +-
 defs.h    |   8 ++
 help.c    |  15 ++-
 main.c    |  27 ++++-
 ramdump.c | 372 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 426 insertions(+), 5 deletions(-)
 create mode 100644 ramdump.c

diff --git a/Makefile b/Makefile
index cf3ae44..64616fc 100644
--- a/Makefile
+++ b/Makefile
@@ -68,7 +68,8 @@ CFILES=main.c tools.c global_data.c memory.c filesys.c help.c task.c \
 	netdump.c diskdump.c makedumpfile.c xendump.c unwind.c unwind_decoder.c \
 	unwind_x86_32_64.c unwind_arm.c \
 	xen_hyper.c xen_hyper_command.c xen_hyper_global_data.c \
-	xen_hyper_dump_tables.c kvmdump.c qemu.c qemu-load.c sadump.c ipcs.c
+	xen_hyper_dump_tables.c kvmdump.c qemu.c qemu-load.c sadump.c ipcs.c \
+	ramdump.c
 
 SOURCE_FILES=${CFILES} ${GENERIC_HFILES} ${MCORE_HFILES} \
 	${REDHAT_CFILES} ${REDHAT_HFILES} ${UNWIND_HFILES} \
@@ -85,7 +86,8 @@ OBJECT_FILES=main.o tools.o global_data.o memory.o filesys.o help.o task.o \
 	lkcd_x86_trace.o unwind_v1.o unwind_v2.o unwind_v3.o \
 	unwind_x86_32_64.o unwind_arm.o \
 	xen_hyper.o xen_hyper_command.o xen_hyper_global_data.o \
-	xen_hyper_dump_tables.o kvmdump.o qemu.o qemu-load.o sadump.o ipcs.o
+	xen_hyper_dump_tables.o kvmdump.o qemu.o qemu-load.o sadump.o ipcs.o \
+	ramdump.o
 
 MEMORY_DRIVER_FILES=memory_driver/Makefile memory_driver/crash.c memory_driver/README
 
@@ -485,6 +487,9 @@ xen_hyper_global_data.o: ${GENERIC_HFILES} xen_hyper_global_data.c
 xen_hyper_dump_tables.o: ${GENERIC_HFILES} xen_hyper_dump_tables.c
 	${CC} -c ${CRASH_CFLAGS} xen_hyper_dump_tables.c ${WARNING_OPTIONS} ${WARNING_ERROR}
 
+ramdump.o: ${GENERIC_HFILES} ${REDHAT_HFILES} ramdump.c
+	${CC} -c ${CRASH_CFLAGS} ramdump.c ${WARNING_OPTIONS} ${WARNING_ERROR}
+
 ${PROGRAM}: force
 	@make --no-print-directory all
 
diff --git a/defs.h b/defs.h
index 2737b10..56f6890 100644
--- a/defs.h
+++ b/defs.h
@@ -5524,6 +5524,14 @@ void dump_registers_for_qemu_mem_dump(void);
 void kdump_backup_region_init(void);
 
 /*
+ * ramdump.c
+ */
+int is_ramdump(char *pattern);
+char *ramdump_to_elf(void);
+void ramdump_elf_output_file(char *opt);
+void ramdump_cleanup(void);
+
+/*
  *  diskdump.c
  */
 int is_diskdump(char *);
diff --git a/help.c b/help.c
index e1f265a..a35ba9c 100644
--- a/help.c
+++ b/help.c
@@ -47,8 +47,9 @@ char *program_usage_info[] = {
     "",
     "USAGE:",
     "",
-    "  crash [OPTION]... NAMELIST MEMORY-IMAGE  (dumpfile form)",
-    "  crash [OPTION]... [NAMELIST]             (live system form)",
+    "  crash [OPTION]... NAMELIST MEMORY-IMAGE  		(dumpfile form)",
+    "  crash [OPTION]... NAMELIST MEMORY-IMAGE@ADDRESS...	(dumpfile form)",
+    "  crash [OPTION]... [NAMELIST]             		(live system form)",
     "",
     "OPTIONS:",
     "",
@@ -69,6 +70,11 @@ char *program_usage_info[] = {
     "    /dev/mem will be used; but if the kernel has been configured with ",
     "    CONFIG_STRICT_DEVMEM, then /proc/kcore will be used.  It is permissible",
     "    to explicitly enter /dev/crash, /dev/mem or /proc/kcore.",
+    "    @ADDRESS is used along with MEMORY-IMAGE when the dumpfile is a raw dump",
+    "    which needs a conversion to kernel core dump format. If -o option is not",
+    "    used, the kdump ELF file is created in /var/tmp/ and is unlinked on crash",
+    "    exit. Multiple MEMORY-IMAGE@ADDRESS ordered pairs can be used, each",
+    "    representing a memory node. ADDRESS is the physical start address of the node",
     "",
     "  mapfile",
     "    If the NAMELIST file is not the same kernel that is running",
@@ -139,6 +145,11 @@ char *program_usage_info[] = {
     "    architecture-specific option/pairs should only be required in",
     "    very rare circumstances:",
     "",
+    "  -o file",
+    "  Can be used with the MEMORY-IMAGE@ADDRESS format, to specify",
+    "  the path and name of the kdump ELF generated. The file thus generated",
+    "  will not be unlinked on crash exit, and can used as kdump input to crash.",
+    "",
     "    X86_64:",
     "      phys_base=<physical-address>",
     "      irq_eframe_link=<value>",
diff --git a/main.c b/main.c
index b0524d2..e948529 100644
--- a/main.c
+++ b/main.c
@@ -86,7 +86,7 @@ main(int argc, char **argv)
 	 */
 	opterr = 0;
 	optind = 0;
-	while((c = getopt_long(argc, argv, "Lkgh::e:i:sSvc:d:tfp:m:x",
+	while((c = getopt_long(argc, argv, "Lkgh::e:i:sSvc:d:tfp:m:xo:",
        		long_options, &option_index)) != -1) {
 		switch (c)
 		{
@@ -387,6 +387,10 @@ main(int argc, char **argv)
 			pc->flags |= PRELOAD_EXTENSIONS;
 			break;
 
+		case 'o':
+			ramdump_elf_output_file(optarg);
+			break;
+
 		default:
 			error(INFO, "invalid option: %s\n",
 				argv[optind-1]);
@@ -402,6 +406,26 @@ main(int argc, char **argv)
 	 */
 	while (argv[optind]) {
 
+		if (is_ramdump(argv[optind])) {
+			if (pc->flags & MEMORY_SOURCES) {
+				error(INFO,
+					"too many dumpfile arguments\n");
+					program_usage(SHORT_FORM);
+			}
+			pc->dumpfile = ramdump_to_elf();
+			if (is_kdump(pc->dumpfile, KDUMP_LOCAL)) {
+				pc->flags |= KDUMP;
+				pc->readmem = read_kdump;
+				pc->writemem = write_kdump;
+			} else {
+				error(INFO, "malformed ELF file: %s\n",
+					pc->dumpfile);
+				program_usage(SHORT_FORM);
+			}
+			optind++;
+			continue;
+		}
+
 		if (is_remote_daemon(argv[optind])) {
                 	if (pc->flags & DUMPFILE_TYPES) {
 				error(INFO, 
@@ -1699,6 +1723,7 @@ clean_exit(int status)
 	if (pc->cleanup && file_exists(pc->cleanup, NULL))
 		unlink(pc->cleanup);
 
+	ramdump_cleanup();
 	exit(status);
 }
 
diff --git a/ramdump.c b/ramdump.c
new file mode 100644
index 0000000..f20e356
--- /dev/null
+++ b/ramdump.c
@@ -0,0 +1,372 @@
+/*
+ * ramdump.c - core analysis suite
+ *
+ * Copyright (c) 2014 Vinayak Menon <vinayakm.list@xxxxxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Author: Vinayak Menon <vinayakm.list@xxxxxxxxx>
+ */
+
+#define _LARGEFILE64_SOURCE 1  /* stat64() */
+#include "defs.h"
+#include <libelf.h>
+
+struct ramdump_def {
+	char *path;
+	ulong start_paddr;
+};
+
+static struct ramdump_def *ramdump;
+static int nodes;
+static char *user_elf;
+static char *pattern;
+static char elf_default[] = "/var/tmp/ramdump_elfXXXXXX";
+
+static void alloc_elf_header(char *e, ushort e_machine)
+{
+	switch (e_machine) {
+	case EM_ARM:
+	{
+		Elf32_Ehdr *ehdr = (Elf32_Ehdr *)e;
+		memcpy(ehdr->e_ident, ELFMAG, SELFMAG);
+		ehdr->e_ident[EI_CLASS] = ELFCLASS32;
+		ehdr->e_ident[EI_DATA] = ELFDATA2LSB;
+		ehdr->e_ident[EI_VERSION] = EV_CURRENT;
+		ehdr->e_ident[EI_OSABI] = ELFOSABI_LINUX;
+		ehdr->e_ident[EI_ABIVERSION] = 0;
+		memset(ehdr->e_ident+EI_PAD,
+			0, EI_NIDENT-EI_PAD);
+		ehdr->e_type = ET_CORE;
+		ehdr->e_machine = EM_ARM;
+		ehdr->e_version = EV_CURRENT;
+		ehdr->e_shentsize = 0x0;
+		ehdr->e_shnum = 0x0;
+		ehdr->e_shoff = 0x0;
+		ehdr->e_shstrndx = 0x0;
+		ehdr->e_phnum = 1 + nodes;
+		ehdr->e_entry = 0;
+		ehdr->e_phoff = sizeof(Elf32_Ehdr);
+		ehdr->e_flags = 0;
+		ehdr->e_ehsize = sizeof(Elf32_Ehdr);
+		ehdr->e_phentsize = sizeof(Elf32_Phdr);
+		break;
+	}
+	case EM_AARCH64:
+	{
+		Elf64_Ehdr *ehdr = (Elf64_Ehdr *)e;
+		memcpy(ehdr->e_ident, ELFMAG, SELFMAG);
+		ehdr->e_ident[EI_CLASS] = ELFCLASS64;
+		ehdr->e_ident[EI_DATA] = ELFDATA2LSB;
+		ehdr->e_ident[EI_VERSION] = EV_CURRENT;
+		ehdr->e_ident[EI_OSABI] = ELFOSABI_LINUX;
+		ehdr->e_ident[EI_ABIVERSION] = 0;
+		memset(ehdr->e_ident+EI_PAD, 0,
+			EI_NIDENT-EI_PAD);
+		ehdr->e_type = ET_CORE;
+		ehdr->e_machine = EM_AARCH64;
+		ehdr->e_version = EV_CURRENT;
+		ehdr->e_entry = 0;
+		ehdr->e_phoff = sizeof(Elf64_Ehdr);
+		ehdr->e_shoff = 0;
+		ehdr->e_flags = 0;
+		ehdr->e_ehsize = sizeof(Elf64_Ehdr);
+		ehdr->e_phentsize = sizeof(Elf64_Phdr);
+		ehdr->e_phnum = 1 + nodes;
+		ehdr->e_shentsize = 0;
+		ehdr->e_shnum = 0;
+		ehdr->e_shstrndx = 0;
+		break;
+	}
+	};
+}
+
+static int alloc_program_headers(char *e, ushort e_machine)
+{
+	unsigned int i;
+	struct stat64 st;
+	struct ramdump_def *r = ramdump;
+
+	switch (e_machine) {
+	case EM_ARM:
+	{
+		Elf32_Phdr *phdr = (Elf32_Phdr *)e;
+		for (i = 0; i < nodes; i++, phdr++) {
+			phdr[i].p_type = PT_LOAD;
+			if (0 > stat64(r[i].path, &st)) {
+				error(INFO, "ramdump stat failed\n");
+				return -1;
+			}
+			phdr[i].p_filesz = st.st_size;
+			phdr[i].p_memsz = phdr[i].p_filesz;
+			/*
+			 * Yet to find a way to use PTOV,
+			 * as machdep_init is yet to be
+			 * invoked.
+			 */
+			phdr[i].p_vaddr = 0;
+			phdr[i].p_paddr = r[i].start_paddr;
+			phdr[i].p_flags = PF_R | PF_W | PF_X;
+			phdr[i].p_align = 0;
+		}
+		break;
+	}
+	case EM_AARCH64:
+	{
+		Elf64_Phdr *phdr = (Elf64_Phdr *)e;
+		for (i = 0; i < nodes; i++, phdr++) {
+			phdr[i].p_type = PT_LOAD;
+			if (0 > stat64(r[i].path, &st)) {
+				error(INFO, "ramdump stat failed\n");
+				return -1;
+			}
+			phdr[i].p_filesz = st.st_size;
+			phdr[i].p_memsz = phdr[i].p_filesz;
+			phdr[i].p_vaddr = 0;
+			phdr[i].p_paddr = r[i].start_paddr;
+			phdr[i].p_flags = PF_R | PF_W | PF_X;
+			phdr[i].p_align = 0;
+		}
+		break;
+	}
+	};
+
+	return 0;
+}
+
+static char *write_elf(ushort e_machine, void *load, char *e_head,
+	size_t data_offset)
+{
+#define CPY_BUF_SZ 4096
+	int fd1, fd2, i, err = 1;
+	char *buf;
+	char *out_elf;
+	size_t rd, len, offset;
+	struct ramdump_def *r = ramdump;
+
+	buf = (char *)GETBUF(CPY_BUF_SZ);
+
+	offset = data_offset;
+
+	if (user_elf) {
+		fd2 = open(user_elf, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR);
+		if (fd2 < 0) {
+			error(INFO, "%s open error, %s\n", user_elf, strerror(errno));
+			goto end1;
+		}
+		out_elf = user_elf;
+	} else {
+		fd2 = mkstemp(elf_default);
+		if (fd2 < 0) {
+			error(INFO, "%s open error, %s\n", elf_default, strerror(errno));
+			goto end1;
+		}
+		out_elf = elf_default;
+	}
+
+	error(NOTE, "Creating kdump ELF %s\n", out_elf);
+
+	while (offset > 0) {
+		len = write(fd2, e_head + (data_offset - offset), offset);
+		if (len < 0) {
+			error(INFO, "ramdump write error, %s\n", strerror(errno));
+			goto end;
+		}
+		offset -= len;
+	}
+
+	for (i = 0; i < nodes; i++) {
+		if (e_machine == EM_ARM)
+			offset = ((Elf32_Phdr *)load)[i].p_offset;
+		else if (e_machine == EM_AARCH64)
+			offset = ((Elf64_Phdr *)load)[i].p_offset;
+
+		fd1 = open(r[i].path, O_RDONLY, S_IRUSR);
+		if (fd1 < 0) {
+			error(INFO, "%s open error, %s\n", r[i].path, strerror(errno));
+			goto end;
+		}
+
+		lseek(fd2, (off_t)offset, SEEK_SET);
+		while ((rd = read(fd1, buf, CPY_BUF_SZ)) > 0) {
+			if (write(fd2, buf, rd) != rd) {
+				error(INFO, "%s write error, %s\n", r[i].path, strerror(errno));
+				close(fd1);
+				goto end;
+			}
+		}
+		close(fd1);
+	}
+
+	err = 0;
+end:
+	close(fd2);
+end1:
+	FREEBUF(buf);
+	return err ? NULL : out_elf;
+}
+
+static void alloc_notes(char *e_head, ushort e_machine)
+{
+	/* Nothing filled in as of now */
+	switch (e_machine) {
+	case EM_ARM:
+	{
+		Elf32_Phdr *notes = (Elf32_Phdr *)e_head;
+		notes->p_type = PT_NOTE;
+		notes->p_offset = 0;
+		notes->p_vaddr = 0;
+		notes->p_paddr = 0;
+		notes->p_filesz = 0;
+		notes->p_memsz = 0;
+		notes->p_flags = 0;
+		notes->p_align = 0;
+		break;
+	}
+	case EM_AARCH64:
+	{
+		Elf64_Phdr *notes = (Elf64_Phdr *)e_head;
+		notes->p_type = PT_NOTE;
+		notes->p_offset = 0;
+		notes->p_vaddr = 0;
+		notes->p_paddr = 0;
+		notes->p_filesz = 0;
+		notes->p_memsz = 0;
+		notes->p_flags = 0;
+		notes->p_align = 0;
+		break;
+	}
+	};
+}
+
+char *ramdump_to_elf(void)
+{
+	int i;
+	char *e_head, *ptr, *e_file = NULL;
+	ushort e_machine = 0;
+	size_t offset, data_offset;
+	size_t l_offset32, l_offset64;
+	size_t szelfhdr = 0, szpghdr = 0;
+	Elf64_Phdr *notes64, *load64;
+	Elf32_Phdr *load32, *notes32;
+
+	if (machine_type("ARM")) {
+		e_machine = EM_ARM;
+		szelfhdr = sizeof(Elf32_Ehdr);
+		szpghdr = sizeof(Elf32_Phdr);
+	} else if (machine_type("ARM64")) {
+		e_machine = EM_AARCH64;
+		szelfhdr = sizeof(Elf64_Ehdr);
+		szpghdr = sizeof(Elf64_Phdr);
+	} else {
+		error(INFO, "unknown machine type\n");
+		return NULL;
+	}
+
+	e_head = (char *)GETBUF(szelfhdr +
+		nodes * szpghdr + PAGESIZE() * 2);
+	ptr = e_head;
+	offset = 0;
+
+	error(NOTE, "Converting ramdump to kdump\n");
+	alloc_elf_header(ptr, e_machine);
+
+	ptr += szelfhdr;
+	offset += szelfhdr;
+
+	notes32 = (Elf32_Phdr *)ptr;
+	notes64 = (Elf64_Phdr *)ptr;
+
+	alloc_notes(ptr, e_machine);
+
+	offset += szpghdr;
+	ptr += szpghdr;
+
+	load32 = (Elf32_Phdr *)ptr;
+	load64 = (Elf64_Phdr *)ptr;
+
+	if (alloc_program_headers(ptr, e_machine))
+		goto end;
+
+	offset += szpghdr * nodes;
+	ptr += szpghdr * nodes;
+
+	/* Empty note */
+	notes32->p_offset = offset;
+	notes64->p_offset = offset;
+
+	l_offset32 = offset;
+	l_offset64 = offset;
+
+	data_offset = offset;
+
+	switch (e_machine) {
+	case EM_ARM:
+		for (i = 0; i < nodes; i++) {
+			load32[i].p_offset = l_offset32;
+			l_offset32 += load32[i].p_filesz;
+		}
+		break;
+	case EM_AARCH64:
+		for (i = 0; i < nodes; i++) {
+			load64[i].p_offset = l_offset64;
+			l_offset64 += load64[i].p_filesz;
+		}
+		break;
+	}
+
+	e_file = write_elf(e_machine, load32, e_head, data_offset);
+end:
+	FREEBUF(e_head);
+	FREEBUF(pattern);
+	free(ramdump);
+	return e_file;
+}
+
+int is_ramdump(char *p)
+{
+	char *x = NULL, *y = NULL, *pat;
+	size_t len;
+
+	if (nodes || !strchr(p, '@'))
+		return 0;
+
+	len = strlen(p);
+	pattern = (char *)GETBUF(len + 1);
+	strlcpy(pattern, p, len + 1);
+
+	pat = pattern;
+	while ((pat = strtok_r(pat, ",", &x))) {
+		if ((pat = strtok_r(pat, "@", &y))) {
+			nodes++;
+			ramdump = realloc(ramdump, sizeof(struct ramdump_def) * nodes);
+			if (!ramdump)
+				error(FATAL, "realloc failure\n");
+			ramdump[nodes - 1].path = pat;
+			pat = strtok_r(NULL, "@", &y);
+			ramdump[nodes - 1].start_paddr = strtoul(pat, NULL, 0);
+		}
+		pat = NULL;
+	}
+
+	return nodes;
+}
+
+void ramdump_elf_output_file(char *opt)
+{
+	user_elf = opt;
+}
+
+void ramdump_cleanup(void)
+{
+	if (!user_elf)
+		unlink(elf_default);
+}
-- 
1.9.1

diff --git a/defs.h b/defs.h
index d528246..56f6890 100644
--- a/defs.h
+++ b/defs.h
@@ -5529,6 +5529,7 @@ void kdump_backup_region_init(void);
 int is_ramdump(char *pattern);
 char *ramdump_to_elf(void);
 void ramdump_elf_output_file(char *opt);
+void ramdump_cleanup(void);
 
 /*
  *  diskdump.c
diff --git a/help.c b/help.c
index 00843aa..a35ba9c 100644
--- a/help.c
+++ b/help.c
@@ -47,9 +47,9 @@ char *program_usage_info[] = {
     "",
     "USAGE:",
     "",
-    "  crash [OPTION]... NAMELIST MEMORY-IMAGE  (dumpfile form)",
-    "  crash [OPTION]... NAMELIST MEMORY-IMAGE@ADDRESS...  (dumpfile form)",
-    "  crash [OPTION]... [NAMELIST]             (live system form)",
+    "  crash [OPTION]... NAMELIST MEMORY-IMAGE  		(dumpfile form)",
+    "  crash [OPTION]... NAMELIST MEMORY-IMAGE@ADDRESS...	(dumpfile form)",
+    "  crash [OPTION]... [NAMELIST]             		(live system form)",
     "",
     "OPTIONS:",
     "",
@@ -71,9 +71,10 @@ char *program_usage_info[] = {
     "    CONFIG_STRICT_DEVMEM, then /proc/kcore will be used.  It is permissible",
     "    to explicitly enter /dev/crash, /dev/mem or /proc/kcore.",
     "    @ADDRESS is used along with MEMORY-IMAGE when the dumpfile is a raw dump",
-    "    which needs a conversion to kernel core dump format. Multiple",
-    "    MEMORY-IMAGE@ADDRESS ordered pairs can be used, each representing a",
-    "    memory node. ADDRESS is the physical start address of the node",
+    "    which needs a conversion to kernel core dump format. If -o option is not",
+    "    used, the kdump ELF file is created in /var/tmp/ and is unlinked on crash",
+    "    exit. Multiple MEMORY-IMAGE@ADDRESS ordered pairs can be used, each",
+    "    representing a memory node. ADDRESS is the physical start address of the node",
     "",
     "  mapfile",
     "    If the NAMELIST file is not the same kernel that is running",
@@ -145,8 +146,9 @@ char *program_usage_info[] = {
     "    very rare circumstances:",
     "",
     "  -o file",
-    "  Can be used when the MEMORY-IMAGE@ADDRESS format is used, to specify",
-    "  the path and name of the kdump ELF generated.",
+    "  Can be used with the MEMORY-IMAGE@ADDRESS format, to specify",
+    "  the path and name of the kdump ELF generated. The file thus generated",
+    "  will not be unlinked on crash exit, and can used as kdump input to crash.",
     "",
     "    X86_64:",
     "      phys_base=<physical-address>",
diff --git a/main.c b/main.c
index 0bd6575..e948529 100644
--- a/main.c
+++ b/main.c
@@ -1723,6 +1723,7 @@ clean_exit(int status)
 	if (pc->cleanup && file_exists(pc->cleanup, NULL))
 		unlink(pc->cleanup);
 
+	ramdump_cleanup();
 	exit(status);
 }
 
diff --git a/ramdump.c b/ramdump.c
index a09af7b..f20e356 100644
--- a/ramdump.c
+++ b/ramdump.c
@@ -20,8 +20,6 @@
 #include "defs.h"
 #include <libelf.h>
 
-#define ELF_DEFAULT_FILE "ramdump_elf"
-
 struct ramdump_def {
 	char *path;
 	ulong start_paddr;
@@ -31,6 +29,7 @@ static struct ramdump_def *ramdump;
 static int nodes;
 static char *user_elf;
 static char *pattern;
+static char elf_default[] = "/var/tmp/ramdump_elfXXXXXX";
 
 static void alloc_elf_header(char *e, ushort e_machine)
 {
@@ -149,29 +148,36 @@ static char *write_elf(ushort e_machine, void *load, char *e_head,
 #define CPY_BUF_SZ 4096
 	int fd1, fd2, i, err = 1;
 	char *buf;
-	char *out_elf = ELF_DEFAULT_FILE;
+	char *out_elf;
 	size_t rd, len, offset;
 	struct ramdump_def *r = ramdump;
 
 	buf = (char *)GETBUF(CPY_BUF_SZ);
 
-	if (user_elf)
-		out_elf = user_elf;
-
-	error(NOTE, "Creating kdump ELF %s\n", out_elf);
-
 	offset = data_offset;
 
-	fd2 = open(out_elf, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR);
-	if (!fd2) {
-		error(INFO, "%s open error\n", out_elf);
-		goto end1;
+	if (user_elf) {
+		fd2 = open(user_elf, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR);
+		if (fd2 < 0) {
+			error(INFO, "%s open error, %s\n", user_elf, strerror(errno));
+			goto end1;
+		}
+		out_elf = user_elf;
+	} else {
+		fd2 = mkstemp(elf_default);
+		if (fd2 < 0) {
+			error(INFO, "%s open error, %s\n", elf_default, strerror(errno));
+			goto end1;
+		}
+		out_elf = elf_default;
 	}
 
+	error(NOTE, "Creating kdump ELF %s\n", out_elf);
+
 	while (offset > 0) {
 		len = write(fd2, e_head + (data_offset - offset), offset);
 		if (len < 0) {
-			error(INFO, "ramdump write error\n");
+			error(INFO, "ramdump write error, %s\n", strerror(errno));
 			goto end;
 		}
 		offset -= len;
@@ -184,15 +190,15 @@ static char *write_elf(ushort e_machine, void *load, char *e_head,
 			offset = ((Elf64_Phdr *)load)[i].p_offset;
 
 		fd1 = open(r[i].path, O_RDONLY, S_IRUSR);
-		if (!fd1) {
-			error(INFO, "%s open error\n", r[i].path);
+		if (fd1 < 0) {
+			error(INFO, "%s open error, %s\n", r[i].path, strerror(errno));
 			goto end;
 		}
 
 		lseek(fd2, (off_t)offset, SEEK_SET);
 		while ((rd = read(fd1, buf, CPY_BUF_SZ)) > 0) {
 			if (write(fd2, buf, rd) != rd) {
-				error(INFO, "%s write error\n", r[i].path);
+				error(INFO, "%s write error, %s\n", r[i].path, strerror(errno));
 				close(fd1);
 				goto end;
 			}
@@ -358,3 +364,9 @@ void ramdump_elf_output_file(char *opt)
 {
 	user_elf = opt;
 }
+
+void ramdump_cleanup(void)
+{
+	if (!user_elf)
+		unlink(elf_default);
+}
--
Crash-utility mailing list
Crash-utility@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/crash-utility

[Index of Archives]     [Fedora Development]     [Fedora Desktop]     [Fedora SELinux]     [Yosemite News]     [KDE Users]     [Fedora Tools]

 

Powered by Linux