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(a)chelsio.com>
Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy(a)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(a)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