Enhanced dev command to analyze and extract hardware specific device dumps in ELF vmcore. -V list all device dumps present in vmcore -v <index> [-r file] select and display one device dump, either in human-readable format to the screen by default, or optionally copy it raw to a file Signed-off-by: Surendra Mobiya <surendra@xxxxxxxxxxx> Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@xxxxxxxxxxx> --- rfc: - Moved logic to extract device dumps from "devdump" to "dev" command. - By default, device dumps are output to screen as hexdump, if output file is not provided. defs.h | 5 ++++ dev.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- help.c | 23 ++++++++++++++++- memory.c | 10 ++++++++ netdump.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 180 insertions(+), 3 deletions(-) diff --git a/defs.h b/defs.h index 0925a46..a6a0d8a 100644 --- a/defs.h +++ b/defs.h @@ -5277,6 +5277,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, long, void *); /* @@ -5686,6 +5687,8 @@ enum { */ void dev_init(void); void dump_dev_table(void); +void devdump_extract(void *, ulonglong, char *, FILE *); +void devdump_info(void *, ulonglong, FILE *); /* * ipcs.c @@ -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 *); +void kdump_device_dump_extract(int, char *, FILE *); #define PRSTATUS_NOTE (1) #define QEMU_NOTE (2) diff --git a/dev.c b/dev.c index 24efea2..08bb010 100644 --- a/dev.c +++ b/dev.c @@ -16,6 +16,7 @@ */ #include "defs.h" +#include "vmcore.h" static void dump_blkdevs(ulong); static void dump_chrdevs(ulong); @@ -104,12 +105,13 @@ dev_init(void) void cmd_dev(void) { - int c; + int c, index = -1; + char *outputfile = NULL; ulong flags; flags = 0; - while ((c = getopt(argcnt, args, "dDpi")) != EOF) { + while ((c = getopt(argcnt, args, "dDpiVv:r:")) != EOF) { switch(c) { case 'd': @@ -137,6 +139,21 @@ cmd_dev(void) option_not_supported(c); return; + case 'V': + if (KDUMP_DUMPFILE()) + kdump_device_dump_info(fp); + else + error(WARNING, "KDUMP flag not found"); + return; + + case 'v': + index = atoi(optarg); + break; + + case 'r': + outputfile = optarg; + break; + default: argerrs++; break; @@ -146,6 +163,14 @@ cmd_dev(void) if (argerrs) cmd_usage(pc->curcmd, SYNOPSIS); + if (index >= 0) { + if (KDUMP_DUMPFILE()) + kdump_device_dump_extract(index, outputfile, fp); + else + error(WARNING, "KDUMP flag not found"); + return; + } + dump_chrdevs(flags); fprintf(fp, "\n"); dump_blkdevs(flags); @@ -4519,3 +4544,50 @@ diskio_option(ulong flags) diskio_init(); display_all_diskio(flags); } + +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; + + if (dump_file) { + tmpfp = fopen(dump_file, "w"); + if (!tmpfp) { + error(FATAL, "cannot open output file: %s\n", + dump_file); + return; + } + set_tmpfile2(tmpfp); + } + fprintf(ofp, "Device Dump: %s\n", vh->dump_name); + display_memory_from_file_offset(offset + sizeof(struct vmcoredd_header), + dump_size, dump_file); +} + +void devdump_info(void *_note, ulonglong offset, FILE *ofp) +{ + struct vmcoredd_header *vh = (struct vmcoredd_header *)_note; + char buf[BUFSIZE]; + ulong dump_size; + + if (vh->n_type != NT_VMCOREDD) + return; + + dump_size = vh->n_descsz - VMCOREDD_MAX_NAME_BYTES; + + fprintf(ofp, "0x%s ", mkstring(buf, LONG_LONG_PRLEN, LJUST | LONG_HEX, + MKSTR(offset + sizeof(struct vmcoredd_header)))); + fprintf(ofp, "%s ", mkstring(buf, LONG_PRLEN, LJUST | LONG_DEC, + MKSTR(dump_size))); + fprintf(ofp, "%s\n", mkstring(buf, VMCOREDD_MAX_NAME_BYTES, LJUST, + (char *)vh->dump_name)); +} diff --git a/help.c b/help.c index 47058ed..e9bf1b9 100644 --- a/help.c +++ b/help.c @@ -3207,7 +3207,7 @@ NULL char *help_dev[] = { "dev", "device data", -"[-i | -p | -d | -D]", +"[-i | -p | -d | -D | -V ] [-v index [-r file]]", " If no argument is entered, this command dumps character and block", " device data.\n", " -i display I/O port usage; on 2.4 kernels, also display I/O memory usage.", @@ -3222,6 +3222,11 @@ char *help_dev[] = { " If the device driver uses blk-mq interface, this field", " shows N/A(MQ). If not available, this column is not shown.", " -D same as -d, but filter out disks with no in-progress I/O requests.", +" -V list all device dumps present in vmcore", +" -v <index> [-r file] select and display one device dump, either in", +" human-readable format to the screen by default,", +" or optionally copy it raw to a file", + "\nEXAMPLES", " Display character and block device data:\n", " %s> dev", @@ -3353,6 +3358,22 @@ char *help_dev[] = { " 8 ffff81012dc77000 sdb ffff81012d8b5740 0 0 0 0", " 8 ffff81012d8d0c00 sdc ffff81012d8ae9c0 0 0 0 0", +"\n Display the available device dumps:\n", +" %s> dev -V", +" INDEX OFFSET SIZE NAME", +" 0 0x240 33558464 cxgb4_0000:02:00.4", +" 1 0x2001240 33558464 cxgb4_0000:03:00.4", + +"\n Extract device dump at specified index to file:\n", +" %s> dev -v 0 -r device_dump_0.bin", +" Device Dump: cxgb4_0000:02:00.4", +" 33558464 bytes copied from 0x240 to device_dump_0.bin", + +"\n Format and display device dump output to screen using rd command:\n", +" %s> rd -f 0x240 -32 8", +" 240: 040b69e2 00000038 000e0001 00675fd4 .i..8........_g.", +" 250: 00000000 21600047 00000000 00000000 ....G.`!........", + NULL }; diff --git a/memory.c b/memory.c index ab561b3..1395413 100644 --- a/memory.c +++ b/memory.c @@ -1793,6 +1793,16 @@ 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 *file) +{ + if (file) + display_memory(addr, count, DISPLAY_RAW, FILEADDR, file); + else + display_memory(addr, count, DISPLAY_64 | ASCII_ENDLINE | HEXADECIMAL, + FILEADDR, file); +} + /* * 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..cd950e4 100644 --- a/netdump.c +++ b/netdump.c @@ -5082,3 +5082,72 @@ kdump_get_qemucpustate(int cpu) return (QEMUCPUState *)nd->nt_qemu_percpu[cpu]; } #endif + +static void * +get_kdump_device_dump_offset(void) +{ + void *elf_base; + + 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 NULL; + } + + return elf_base; +} + +/* + * extract hardware specific device dumps from coredump. + */ +void +kdump_device_dump_extract(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; + } + + elf_base = get_kdump_device_dump_offset(); + if (!elf_base) + return; + + 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) +{ + ulonglong offset; + char buf[BUFSIZE]; + void *elf_base; + ulong i; + + fprintf(fp, "%s ", mkstring(buf, INT_PRLEN, LJUST, "INDEX")); + fprintf(fp, "%s ", mkstring(buf, LONG_LONG_PRLEN, LJUST, "OFFSET")); + fprintf(fp, " %s ", mkstring(buf, LONG_PRLEN, LJUST, "SIZE")); + fprintf(fp, "%s\n", mkstring(buf, VMCOREDD_MAX_NAME_BYTES, LJUST, + "NAME")); + + elf_base = get_kdump_device_dump_offset(); + if (!elf_base) + return; + + for (i = 0; i < nd->num_vmcoredd_notes; i++) { + fprintf(fp, "%s ", mkstring(buf, INT_PRLEN, LJUST | INT_DEC, + MKSTR(i))); + offset = nd->nt_vmcoredd_array[i] - elf_base; + devdump_info(nd->nt_vmcoredd_array[i], offset, ofp); + } +} -- 2.21.0 -- Crash-utility mailing list Crash-utility@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/crash-utility