[Crash-utility] [RFC 3/4] add devdump command to extract NT_VMCOREDD from ELF vmcore

Surendra Mobiya surendra at chelsio.com
Fri Apr 12 15:54:22 UTC 2019


Add new devdump command to analyze and extract hardware specific
device dumps in ELF vmcore

SYNOPSIS
  devdump [-l][-i index][-r file]

EXAMPLES
      Display the available device dumps
          crash> devdump -l
          0)  name: "cxgb4_0000:02:00.4",  file_offset: 0x278       , size: 33558464
          1)  name: "cxgb4_0000:03:00.4",  file_offset: 0x2001278   , size: 33558464

      Extract device dump at specified index
          crash> devdump -i 0 -r device_dump_0.bin
          0)  name: "cxgb4_0000:02:00.4",  file_offset: 0x278       , size: 33558464
          33558464 bytes copied from 0x278 to device_dump_0.bin

Signed-off-by: Surendra Mobiya <surendra at chelsio.com>
Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy at chelsio.com>
---
 Makefile      |   4 +--
 defs.h        |  11 ++++++
 devdump.c     | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 global_data.c |   1 +
 help.c        |  23 ++++++++++++
 memory.c      |   7 ++++
 netdump.c     |  40 +++++++++++++++++++++
 7 files changed, 194 insertions(+), 2 deletions(-)
 create mode 100644 devdump.c

diff --git a/Makefile b/Makefile
index f78da15..db72b40 100644
--- a/Makefile
+++ b/Makefile
@@ -71,7 +71,7 @@ CFILES=main.c tools.c global_data.c memory.c filesys.c help.c task.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 \
 	ramdump.c vmware_vmss.c \
-	xen_dom0.c kaslr_helper.c
+	xen_dom0.c kaslr_helper.c devdump.c
 
 SOURCE_FILES=${CFILES} ${GENERIC_HFILES} ${MCORE_HFILES} \
 	${REDHAT_CFILES} ${REDHAT_HFILES} ${UNWIND_HFILES} \
@@ -90,7 +90,7 @@ OBJECT_FILES=main.o tools.o global_data.o memory.o filesys.o help.o task.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 \
 	ramdump.o vmware_vmss.o \
-	xen_dom0.o kaslr_helper.o
+	xen_dom0.o kaslr_helper.o devdump.o
 
 MEMORY_DRIVER_FILES=memory_driver/Makefile memory_driver/crash.c memory_driver/README
 
diff --git a/defs.h b/defs.h
index 0925a46..41ce61f 100644
--- a/defs.h
+++ b/defs.h
@@ -4870,6 +4870,7 @@ void cmd_s390dbf(void);
 #endif
 void cmd_map(void);          /* kvmdump.c */
 void cmd_ipcs(void);         /* ipcs.c */
+void cmd_devdump(void);      /* devdump.c */
 
 /*
  *  main.c
@@ -5277,6 +5278,7 @@ char *format_stack_entry(struct bt_info *bt, char *, ulong, ulong);
 int in_user_stack(ulong, ulong);
 int dump_inode_page(ulong);
 ulong valid_section_nr(ulong);
+void display_memory_from_file_offset(ulonglong addr, long count, void *opt);
 
 
 /*
@@ -5444,6 +5446,7 @@ extern char *help_vtop[];
 extern char *help_waitq[];
 extern char *help_whatis[];
 extern char *help_wr[];
+extern char *help_devdump[];
 #if defined(S390) || defined(S390X)
 extern char *help_s390dbf[];
 #endif
@@ -6400,6 +6403,8 @@ void *netdump_get_prstatus_percpu(int);
 int kdump_kaslr_check(void);
 void display_vmcoredd_note(void *ptr, FILE *ofp);
 QEMUCPUState *kdump_get_qemucpustate(int);
+void kdump_device_dump_info(FILE *logfp);
+void kdump_device_dump(int index, char *outfile, FILE *ofp);
 #define PRSTATUS_NOTE (1)
 #define QEMU_NOTE     (2)
 
@@ -6447,6 +6452,12 @@ int diskdump_kaslr_check(void);
 QEMUCPUState *diskdump_get_qemucpustate(int);
 
 /*
+ * devdump.c
+ */
+void devdump_extract(void *note, ulonglong offset, char *dump_file,
+		     FILE *ofp);
+
+/*
  * makedumpfile.c
  */
 void check_flattened_format(char *file);
diff --git a/devdump.c b/devdump.c
new file mode 100644
index 0000000..2b9cbe8
--- /dev/null
+++ b/devdump.c
@@ -0,0 +1,110 @@
+/*
+ * devdump.c - device dump analysis suite
+ *
+ * Copyright (c) 2019 Chelsio Communications. All rights reserved.
+ *
+ * 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: Surendra Mobiya  <surendra at chelsio.com>
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <elf.h>
+#include "defs.h"
+#include "vmcore.h"
+
+void cmd_devdump(void)
+{
+	int opt, index = -1;
+	char *outputfile;
+	int list = 0;
+
+	outputfile = NULL;
+
+	if (argcnt == 1) {
+		error(INFO, "No arg provided");
+		return;
+	}
+
+	while ((opt = getopt(argcnt, args, "r:i:l")) != EOF) {
+		switch (opt) {
+		case 'r':
+			outputfile = optarg;
+			break;
+		case 'i':
+			index = atoi(optarg);
+			break;
+		case 'l':
+			list = 1;
+			break;
+		default:
+			argerrs++;
+			break;
+		}
+	}
+
+	if (argerrs)
+		cmd_usage(pc->curcmd, SYNOPSIS);
+
+	if (list) {
+		if (KDUMP_DUMPFILE())
+			kdump_device_dump_info(fp);
+		else
+			error(WARNING, "KDUMP flag not found");
+	} else {
+		if (index == -1) {
+			error(INFO, "Index not provided");
+			return;
+		}
+
+		if (!outputfile) {
+			error(INFO, "Output file not provided");
+			return;
+		}
+
+		if (KDUMP_DUMPFILE())
+			kdump_device_dump(index, outputfile, fp);
+		else
+			error(WARNING, "KDUMP flag not found");
+	}
+}
+
+void
+devdump_extract(void *_note, ulonglong offset, char *dump_file, FILE *ofp)
+{
+	struct vmcoredd_header *vh = (struct vmcoredd_header *)_note;
+	ulong dump_size;
+	FILE *tmpfp;
+
+	if (vh->n_type != NT_VMCOREDD) {
+		error(WARNING, "Unsupported note type 0x%x", vh->n_type);
+		return;
+	}
+
+	dump_size = vh->n_descsz - VMCOREDD_MAX_NAME_BYTES;
+	fprintf(ofp, " name: \"%s\", ", vh->dump_name);
+	fprintf(ofp, " file_offset: 0x%-10llx,",
+		offset + sizeof(struct vmcoredd_header));
+	fprintf(ofp, " size: %lu\n", dump_size);
+	if (dump_file) {
+		tmpfp = fopen(dump_file, "w");
+		if (!tmpfp) {
+			error(FATAL, "cannot open output file: %s\n",
+			      dump_file);
+			return;
+		}
+		set_tmpfile2(tmpfp);
+		display_memory_from_file_offset(offset +
+						sizeof(struct vmcoredd_header),
+						dump_size, dump_file);
+	}
+}
diff --git a/global_data.c b/global_data.c
index cbacc42..6c42209 100644
--- a/global_data.c
+++ b/global_data.c
@@ -124,6 +124,7 @@ struct command_table_entry linux_command_table[] = {
 #if defined(S390) || defined(S390X)
         {"s390dbf", cmd_s390dbf, help_s390dbf, 0},
 #endif
+	{"devdump",   cmd_devdump,   help_devdump,   0},
 	{(char *)NULL}
 };
 
diff --git a/help.c b/help.c
index 47058ed..fa5818c 100644
--- a/help.c
+++ b/help.c
@@ -7753,6 +7753,29 @@ char *help_files[] = {
 NULL               
 };
 
+char *help_devdump[] = {
+"devdump",
+"list/extract device dump",
+"[-l][-i index][-r file]",
+"  This command is used to analyze the hardware device dumps collected\n"
+"  in crash kernel.\n",
+"         -l    list all device dumps present in vmcore",
+"   -i index    Index of the device dump. Use -l command to list the device dump indices",
+"    -r file    output file name ",
+"\nEXAMPLES",
+"      Display the available device dumps",
+"          crash> devdump -l",
+"          0)  name: \"cxgb4_0000:02:00.4\",  file_offset: 0x278       , size: 33558464",
+"          1)  name: \"cxgb4_0000:03:00.4\",  file_offset: 0x2001278   , size: 33558464",
+"",
+"      Extract device dump at specified index",
+"          crash> devdump -i 0 -r device_dump_0.bin",
+"          0)  name: \"cxgb4_0000:02:00.4\",  file_offset: 0x278       , size: 33558464",
+"          33558464 bytes copied from 0x278 to device_dump_0.bin",
+" ",
+NULL
+};
+
 char *help_fuser[] = {
 "fuser",
 "file users",
diff --git a/memory.c b/memory.c
index ab561b3..34b7136 100644
--- a/memory.c
+++ b/memory.c
@@ -1793,6 +1793,13 @@ display_memory(ulonglong addr, long count, ulong flag, int memtype, void *opt)
 		fprintf(fp,"\n");
 }
 
+void
+display_memory_from_file_offset(ulonglong addr, long count, void *opt)
+{
+	display_memory(addr, count, DISPLAY_RAW | ASCII_ENDLINE | HEXADECIMAL,
+		       FILEADDR, opt);
+}
+
 /*
  *  cmd_wr() is the sister routine of cmd_rd(), used to modify the contents
  *  of memory.  Like the "rd" command, the starting address may be entered 
diff --git a/netdump.c b/netdump.c
index c4e9b3e..12e4dfc 100644
--- a/netdump.c
+++ b/netdump.c
@@ -5082,3 +5082,43 @@ kdump_get_qemucpustate(int cpu)
 	return (QEMUCPUState *)nd->nt_qemu_percpu[cpu];
 }
 #endif
+
+/*
+ * extract hardware specific device dumps from coredump.
+ */
+void
+kdump_device_dump(int index, char *outfile, FILE *ofp)
+{
+	ulonglong offset;
+	void *elf_base;
+
+	if (index >= nd->num_vmcoredd_notes) {
+		error(WARNING, "No device dump found at index: %d", index);
+		return;
+	}
+
+	if (DUMPFILE_FORMAT(nd->flags) == KDUMP_ELF64) {
+		elf_base = (void *)nd->elf64;
+	} else if (DUMPFILE_FORMAT(nd->flags) == KDUMP_ELF32) {
+		elf_base = (void *)nd->elf32;
+	} else {
+		error(WARNING, "Unsupported Dumpfile Format: 0x%x",
+		      DUMPFILE_FORMAT(nd->flags));
+		return;
+	}
+
+	fprintf(ofp, "%d) ", index);
+	offset = nd->nt_vmcoredd_array[index] - elf_base;
+	devdump_extract(nd->nt_vmcoredd_array[index], offset, outfile, ofp);
+}
+
+/*
+ * list all hardware specific device dumps present in coredump.
+ */
+void kdump_device_dump_info(FILE *ofp)
+{
+	int i;
+
+	for (i = 0; i < nd->num_vmcoredd_notes; i++)
+		kdump_device_dump(i, NULL, ofp);
+}
-- 
1.8.3.1




More information about the Crash-utility mailing list