mirror of https://github.com/crash-utility/crash
Linux 4.18 kernels introduced a new CONFIG_PROC_VMCORE_DEVICE_DUMP
configuration in commit 2724273e8fd00b512596a77ee063f49b25f36507, titled "vmcore: add API to collect hardware dump in second kernel", in which device drivers may collect a device specific snapshot of the hardware/firmware state of their underlying devices, and export the data as a kdump ELF note with type NT_VMCOREDD. This patch recognizes the new ELF note(s) in both ELF and compressed kdump vmcore dumpfiles. The "help -[nD]" option shows basic information about each note, and two new "dev" command options have been introduced. The "dev -V" option displays an indexed list of each note, showing the device name, the dumpfile offset, and the size of each note. The "dev -v index [file]" option either dumps the contents of a note to the display screen in a human-readable format, or copies the note data directly to a specified file. (surendra@chelsio.com)
This commit is contained in:
parent
dc70e6a5e0
commit
71a4f36767
4
Makefile
4
Makefile
|
@ -49,7 +49,7 @@ LDFLAGS=
|
|||
|
||||
GENERIC_HFILES=defs.h xen_hyper_defs.h xen_dom0.h
|
||||
MCORE_HFILES=va_server.h vas_crash.h
|
||||
REDHAT_HFILES=netdump.h diskdump.h makedumpfile.h xendump.h kvmdump.h qemu-load.h
|
||||
REDHAT_HFILES=netdump.h diskdump.h makedumpfile.h xendump.h kvmdump.h qemu-load.h vmcore.h
|
||||
LKCD_DUMP_HFILES=lkcd_vmdump_v1.h lkcd_vmdump_v2_v3.h lkcd_dump_v5.h \
|
||||
lkcd_dump_v7.h lkcd_dump_v8.h
|
||||
LKCD_OBSOLETE_HFILES=lkcd_fix_mem.h
|
||||
|
@ -392,7 +392,7 @@ lkcd_v8.o: ${GENERIC_HFILES} ${LKCD_DUMP_HFILES} lkcd_v8.c
|
|||
net.o: ${GENERIC_HFILES} net.c
|
||||
${CC} -c ${CRASH_CFLAGS} net.c ${WARNING_OPTIONS} ${WARNING_ERROR}
|
||||
|
||||
dev.o: ${GENERIC_HFILES} dev.c
|
||||
dev.o: ${GENERIC_HFILES} ${REDHAT_HFILES} dev.c
|
||||
${CC} -c ${CRASH_CFLAGS} dev.c ${WARNING_OPTIONS} ${WARNING_ERROR}
|
||||
|
||||
# remote.c functionality has been deprecated
|
||||
|
|
10
defs.h
10
defs.h
|
@ -148,6 +148,8 @@
|
|||
#define NR_CPUS (4096)
|
||||
#endif
|
||||
|
||||
#define NR_DEVICE_DUMPS (64)
|
||||
|
||||
/* Some architectures require memory accesses to be aligned. */
|
||||
#if defined(SPARC64)
|
||||
#define NEED_ALIGNED_MEM_ACCESS
|
||||
|
@ -5276,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, long, void *);
|
||||
|
||||
|
||||
/*
|
||||
|
@ -5685,6 +5688,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
|
||||
|
@ -6397,7 +6402,10 @@ void display_regs_from_elf_notes(int, FILE *);
|
|||
void display_ELF_note(int, int, void *, FILE *);
|
||||
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)
|
||||
|
||||
|
@ -6443,6 +6451,8 @@ void process_elf64_notes(void *, ulong);
|
|||
void dump_registers_for_compressed_kdump(void);
|
||||
int diskdump_kaslr_check(void);
|
||||
QEMUCPUState *diskdump_get_qemucpustate(int);
|
||||
void diskdump_device_dump_info(FILE *);
|
||||
void diskdump_device_dump_extract(int, char *, FILE *);
|
||||
|
||||
/*
|
||||
* makedumpfile.c
|
||||
|
|
98
dev.c
98
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,14 @@ dev_init(void)
|
|||
void
|
||||
cmd_dev(void)
|
||||
{
|
||||
int c;
|
||||
int c;
|
||||
int dd_index = -1;
|
||||
char *outputfile = NULL;
|
||||
ulong flags;
|
||||
|
||||
flags = 0;
|
||||
|
||||
while ((c = getopt(argcnt, args, "dDpi")) != EOF) {
|
||||
while ((c = getopt(argcnt, args, "dDpiVv:")) != EOF) {
|
||||
switch(c)
|
||||
{
|
||||
case 'd':
|
||||
|
@ -137,6 +140,21 @@ cmd_dev(void)
|
|||
option_not_supported(c);
|
||||
return;
|
||||
|
||||
case 'V':
|
||||
if (KDUMP_DUMPFILE())
|
||||
kdump_device_dump_info(fp);
|
||||
else if (DISKDUMP_DUMPFILE())
|
||||
diskdump_device_dump_info(fp);
|
||||
else if (ACTIVE())
|
||||
error(INFO, "-V option not supported on a live system\n");
|
||||
else
|
||||
error(INFO, "-V option not supported on this dumpfile type\n");
|
||||
return;
|
||||
|
||||
case 'v':
|
||||
dd_index = atoi(optarg);
|
||||
break;
|
||||
|
||||
default:
|
||||
argerrs++;
|
||||
break;
|
||||
|
@ -146,6 +164,29 @@ cmd_dev(void)
|
|||
if (argerrs)
|
||||
cmd_usage(pc->curcmd, SYNOPSIS);
|
||||
|
||||
while (args[optind]) {
|
||||
if (dd_index >= 0) {
|
||||
if (!outputfile)
|
||||
outputfile = args[optind];
|
||||
else
|
||||
cmd_usage(pc->curcmd, SYNOPSIS);
|
||||
} else
|
||||
cmd_usage(pc->curcmd, SYNOPSIS);
|
||||
optind++;
|
||||
}
|
||||
|
||||
if (dd_index >= 0) {
|
||||
if (KDUMP_DUMPFILE())
|
||||
kdump_device_dump_extract(dd_index, outputfile, fp);
|
||||
else if (DISKDUMP_DUMPFILE())
|
||||
diskdump_device_dump_extract(dd_index, outputfile, fp);
|
||||
else if (ACTIVE())
|
||||
error(INFO, "-v option not supported on a live system\n");
|
||||
else
|
||||
error(INFO, "-v option not supported on this dumpfile type\n");
|
||||
return;
|
||||
}
|
||||
|
||||
dump_chrdevs(flags);
|
||||
fprintf(fp, "\n");
|
||||
dump_blkdevs(flags);
|
||||
|
@ -4549,3 +4590,56 @@ 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, count;
|
||||
FILE *tmpfp;
|
||||
|
||||
if (vh->n_type != NT_VMCOREDD)
|
||||
error(FATAL, "unsupported note type: 0x%x", vh->n_type);
|
||||
|
||||
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: %s\n", vh->dump_name);
|
||||
|
||||
if (dump_file)
|
||||
count = dump_size;
|
||||
else
|
||||
count = dump_size/sizeof(uint64_t) +
|
||||
(dump_size % sizeof(uint64_t) ? 1 : 0);
|
||||
|
||||
display_memory_from_file_offset(offset + sizeof(struct vmcoredd_header),
|
||||
count, 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;
|
||||
offset += sizeof(struct vmcoredd_header);
|
||||
|
||||
fprintf(ofp, "0x%s ", mkstring(buf, LONG_LONG_PRLEN, LJUST | LONGLONG_HEX,
|
||||
MKSTR(&offset)));
|
||||
fprintf(ofp, "%s ", mkstring(buf, LONG_PRLEN, LJUST | LONG_DEC,
|
||||
MKSTR(dump_size)));
|
||||
fprintf(ofp, "%s\n", vh->dump_name);
|
||||
}
|
||||
|
|
85
diskdump.c
85
diskdump.c
|
@ -26,6 +26,7 @@
|
|||
#include "defs.h"
|
||||
#include "diskdump.h"
|
||||
#include "xen_dom0.h"
|
||||
#include "vmcore.h"
|
||||
|
||||
#define BITMAP_SECT_LEN 4096
|
||||
|
||||
|
@ -58,6 +59,8 @@ struct diskdump_data {
|
|||
void **nt_qemu_percpu;
|
||||
void **nt_qemucs_percpu;
|
||||
uint num_qemu_notes;
|
||||
void **nt_vmcoredd_array;
|
||||
uint num_vmcoredd_notes;
|
||||
|
||||
/* page cache */
|
||||
struct page_cache_hdr { /* header for each cached page */
|
||||
|
@ -279,6 +282,7 @@ process_elf32_notes(void *note_buf, unsigned long size_note)
|
|||
Elf32_Nhdr *nt;
|
||||
size_t index, len = 0;
|
||||
int num = 0;
|
||||
int vmcoredd_num = 0;
|
||||
int qemu_num = 0;
|
||||
|
||||
for (index = 0; index < size_note; index += len) {
|
||||
|
@ -304,6 +308,12 @@ process_elf32_notes(void *note_buf, unsigned long size_note)
|
|||
process_xen_note(nt->n_type, data, nt->n_descsz);
|
||||
}
|
||||
|
||||
if (nt->n_type == NT_VMCOREDD &&
|
||||
vmcoredd_num < NR_DEVICE_DUMPS) {
|
||||
dd->nt_vmcoredd_array[vmcoredd_num] = nt;
|
||||
vmcoredd_num++;
|
||||
}
|
||||
|
||||
len = roundup(len + nt->n_namesz, 4);
|
||||
len = roundup(len + nt->n_descsz, 4);
|
||||
}
|
||||
|
@ -317,6 +327,9 @@ process_elf32_notes(void *note_buf, unsigned long size_note)
|
|||
pc->flags2 |= QEMU_MEM_DUMP_COMPRESSED;
|
||||
dd->num_qemu_notes = qemu_num;
|
||||
}
|
||||
if (vmcoredd_num > 0)
|
||||
dd->num_vmcoredd_notes = vmcoredd_num;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -326,6 +339,7 @@ process_elf64_notes(void *note_buf, unsigned long size_note)
|
|||
Elf64_Nhdr *nt;
|
||||
size_t index, len = 0;
|
||||
int num = 0;
|
||||
int vmcoredd_num = 0;
|
||||
int qemu_num = 0;
|
||||
|
||||
for (index = 0; index < size_note; index += len) {
|
||||
|
@ -357,6 +371,12 @@ process_elf64_notes(void *note_buf, unsigned long size_note)
|
|||
process_xen_note(nt->n_type, data, nt->n_descsz);
|
||||
}
|
||||
|
||||
if (nt->n_type == NT_VMCOREDD &&
|
||||
vmcoredd_num < NR_DEVICE_DUMPS) {
|
||||
dd->nt_vmcoredd_array[vmcoredd_num] = nt;
|
||||
vmcoredd_num++;
|
||||
}
|
||||
|
||||
len = roundup(len + nt->n_namesz, 4);
|
||||
len = roundup(len + nt->n_descsz, 4);
|
||||
}
|
||||
|
@ -370,6 +390,9 @@ process_elf64_notes(void *note_buf, unsigned long size_note)
|
|||
pc->flags2 |= QEMU_MEM_DUMP_COMPRESSED;
|
||||
dd->num_qemu_notes = qemu_num;
|
||||
}
|
||||
if (vmcoredd_num > 0)
|
||||
dd->num_vmcoredd_notes = vmcoredd_num;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -778,6 +801,10 @@ restart:
|
|||
error(FATAL, "qemu mem dump compressed: cannot malloc pointer"
|
||||
" to QEMUCS notes\n");
|
||||
|
||||
if ((dd->nt_vmcoredd_array = malloc(NR_DEVICE_DUMPS * sizeof(void *))) == NULL)
|
||||
error(FATAL, "compressed kdump: cannot malloc array for "
|
||||
"vmcore device dump notes\n");
|
||||
|
||||
if (FLAT_FORMAT()) {
|
||||
if (!read_flattened_format(dd->dfd, offset, dd->notes_buf, size)) {
|
||||
error(INFO, "compressed kdump: cannot read notes data"
|
||||
|
@ -875,6 +902,8 @@ err:
|
|||
free(dd->nt_qemu_percpu);
|
||||
if (dd->nt_qemucs_percpu)
|
||||
free(dd->nt_qemucs_percpu);
|
||||
if (dd->nt_vmcoredd_array)
|
||||
free(dd->nt_vmcoredd_array);
|
||||
|
||||
dd->flags &= ~(DISKDUMP_LOCAL|KDUMP_CMPRS_LOCAL);
|
||||
pc->flags2 &= ~ELF_NOTES;
|
||||
|
@ -1948,6 +1977,15 @@ __diskdump_memory_dump(FILE *fp)
|
|||
dd->sub_header_kdump->size_note);
|
||||
fprintf(fp, " notes_buf: %lx\n",
|
||||
(ulong)dd->notes_buf);
|
||||
fprintf(fp, " num_vmcoredd_notes: %d\n",
|
||||
dd->num_vmcoredd_notes);
|
||||
for (i = 0; i < dd->num_vmcoredd_notes; i++) {
|
||||
fprintf(fp, " notes[%d]: %lx %s\n",
|
||||
i, (ulong)dd->nt_vmcoredd_array[i],
|
||||
dd->nt_vmcoredd_array[i] ? "(NT_VMCOREDD)" : "");
|
||||
display_vmcoredd_note(dd->nt_vmcoredd_array[i], fp);
|
||||
}
|
||||
|
||||
fprintf(fp, " num_prstatus_notes: %d\n",
|
||||
dd->num_prstatus_notes);
|
||||
for (i = 0; i < dd->num_prstatus_notes; i++) {
|
||||
|
@ -2500,3 +2538,50 @@ diskdump_get_qemucpustate(int cpu)
|
|||
return (QEMUCPUState *)dd->nt_qemucs_percpu[cpu];
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* extract hardware specific device dumps from coredump.
|
||||
*/
|
||||
void
|
||||
diskdump_device_dump_extract(int index, char *outfile, FILE *ofp)
|
||||
{
|
||||
ulonglong offset;
|
||||
|
||||
if (!dd->num_vmcoredd_notes)
|
||||
error(FATAL, "no device dumps found in this dumpfile\n");
|
||||
else if (index >= dd->num_vmcoredd_notes)
|
||||
error(FATAL, "no device dump found at index: %d", index);
|
||||
|
||||
offset = dd->sub_header_kdump->offset_note +
|
||||
((unsigned char *)dd->nt_vmcoredd_array[index] -
|
||||
dd->notes_buf);
|
||||
|
||||
devdump_extract(dd->nt_vmcoredd_array[index], offset, outfile, ofp);
|
||||
}
|
||||
|
||||
/*
|
||||
* list all hardware specific device dumps present in coredump.
|
||||
*/
|
||||
void
|
||||
diskdump_device_dump_info(FILE *ofp)
|
||||
{
|
||||
ulonglong offset;
|
||||
char buf[BUFSIZE];
|
||||
ulong i;
|
||||
|
||||
if (!dd->num_vmcoredd_notes)
|
||||
error(FATAL, "no device dumps found in this dumpfile\n");
|
||||
|
||||
fprintf(fp, "%s ", mkstring(buf, strlen("INDEX"), LJUST, "INDEX"));
|
||||
fprintf(fp, " %s ", mkstring(buf, LONG_LONG_PRLEN, LJUST, "OFFSET"));
|
||||
fprintf(fp, " %s ", mkstring(buf, LONG_PRLEN, LJUST, "SIZE"));
|
||||
fprintf(fp, "NAME\n");
|
||||
|
||||
for (i = 0; i < dd->num_vmcoredd_notes; i++) {
|
||||
fprintf(fp, "%s ", mkstring(buf, strlen("INDEX"), CENTER | INT_DEC, MKSTR(i)));
|
||||
offset = dd->sub_header_kdump->offset_note +
|
||||
((unsigned char *)dd->nt_vmcoredd_array[i] -
|
||||
dd->notes_buf);
|
||||
devdump_info(dd->nt_vmcoredd_array[i], offset, ofp);
|
||||
}
|
||||
}
|
||||
|
|
39
help.c
39
help.c
|
@ -3207,7 +3207,7 @@ NULL
|
|||
char *help_dev[] = {
|
||||
"dev",
|
||||
"device data",
|
||||
"[-i | -p | -d | -D]",
|
||||
"[-i | -p | -d | -D ] [-V | -v index [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,16 @@ 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.",
|
||||
" ",
|
||||
" If the dumpfile contains device dumps:",
|
||||
" -V display an indexed list of all device dumps present in the vmcore,",
|
||||
" showing their file offset, size and name.",
|
||||
" -v index select and display one device dump based upon an index value",
|
||||
" shown by the -V option, shown in a default human-readable format;",
|
||||
" alternatively, the \"rd -f\" option along with its various format",
|
||||
" options may be used to further tailor the output.",
|
||||
" file only used with -v, copy the device dump data to a file.",
|
||||
|
||||
"\nEXAMPLES",
|
||||
" Display character and block device data:\n",
|
||||
" %s> dev",
|
||||
|
@ -3353,6 +3363,33 @@ 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 a specified device dump to file:\n",
|
||||
" %s> dev -v 0 -r device_dump_0.bin",
|
||||
" DEVICE: cxgb4_0000:02:00.4",
|
||||
" 33558464 bytes copied from 0x240 to device_dump_0.bin",
|
||||
|
||||
"\n Format and display a device's dump data to the screen using the \"rd\" command:\n",
|
||||
" %s> rd -f 0x240 -32 8",
|
||||
" 240: 040b69e2 00000038 000e0001 00675fd4 .i..8........_g.",
|
||||
" 250: 00000000 21600047 00000000 00000000 ....G.`!........",
|
||||
|
||||
"\n Display a device's dump data to the screen using the default format:\n",
|
||||
" %s> dev -v 1",
|
||||
" DEVICE: cxgb4_0000:03:00.4",
|
||||
" 2001240: 00000038040b69e2 00af985c000e0001 .i..8.......\\...",
|
||||
" 2001250: 2150004700000000 0000000000000000 ....G.P!........",
|
||||
" 2001260: 0000000000000000 0000000000000000 ................",
|
||||
" 2001270: 0000000000000000 0002fccc00000001 ................",
|
||||
" 2001280: 00000000000027b0 0000000000000000 .'..............",
|
||||
" ...",
|
||||
|
||||
|
||||
NULL
|
||||
};
|
||||
|
||||
|
|
10
memory.c
10
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
|
||||
|
|
118
netdump.c
118
netdump.c
|
@ -1185,9 +1185,9 @@ netdump_memory_dump(FILE *fp)
|
|||
if (machine_type("ARM64"))
|
||||
netdump_print("%016lx\n"
|
||||
" CONFIG_ARM64_VA_BITS: %ld\n"
|
||||
" VA_BITS_ACTUAL: %ld\n",
|
||||
" VA_BITS_ACTUAL: %lld\n",
|
||||
nd->arch_data2, nd->arch_data2 & 0xffffffff,
|
||||
(nd->arch_data2 >> 32));
|
||||
((ulonglong)nd->arch_data2 >> 32));
|
||||
else
|
||||
netdump_print("%016lx (?)\n", nd->arch_data2);
|
||||
} else
|
||||
|
@ -1810,7 +1810,7 @@ vmcoreinfo_read_string(const char *key)
|
|||
}
|
||||
if (STREQ(key, "NUMBER(VA_BITS_ACTUAL)") && nd->arch_data2) {
|
||||
value = calloc(VADDR_PRLEN+1, sizeof(char));
|
||||
sprintf(value, "%ld", (nd->arch_data2 >> 32) & 0xffffffff);
|
||||
sprintf(value, "%lld", ((ulonglong)nd->arch_data2 >> 32) & 0xffffffff);
|
||||
pc->read_vmcoreinfo = no_vmcoreinfo;
|
||||
return value;
|
||||
}
|
||||
|
@ -1898,6 +1898,21 @@ vmcoreinfo_read_integer(const char *key, long default_value)
|
|||
return retval;
|
||||
}
|
||||
|
||||
void
|
||||
display_vmcoredd_note(void *ptr, FILE *ofp)
|
||||
{
|
||||
int sp;
|
||||
unsigned int dump_size;
|
||||
struct vmcoredd_header *vh;
|
||||
|
||||
sp = VMCORE_VALID() ? 25 : 22;
|
||||
vh = (struct vmcoredd_header *)ptr;
|
||||
|
||||
dump_size = vh->n_descsz - VMCOREDD_MAX_NAME_BYTES;
|
||||
fprintf(ofp, "%sname: \"%s\"\n", space(sp), vh->dump_name);
|
||||
fprintf(ofp, "%ssize: %u\n", space(sp), dump_size);
|
||||
}
|
||||
|
||||
/*
|
||||
* Dump a note section header -- the actual data is defined by netdump
|
||||
*/
|
||||
|
@ -2002,6 +2017,18 @@ dump_Elf32_Nhdr(Elf32_Off offset, int store)
|
|||
}
|
||||
break;
|
||||
#endif
|
||||
case NT_VMCOREDD:
|
||||
netdump_print("(NT_VMCOREDD)\n");
|
||||
if (store) {
|
||||
for (i = 0; i < NR_DEVICE_DUMPS; i++) {
|
||||
if (!nd->nt_vmcoredd_array[i]) {
|
||||
nd->nt_vmcoredd_array[i] = (void *)note;
|
||||
nd->num_vmcoredd_notes++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
xen_core = STRNEQ(buf, "XEN CORE") || STRNEQ(buf, "Xen");
|
||||
if (STRNEQ(buf, "VMCOREINFO_XEN"))
|
||||
|
@ -2092,6 +2119,9 @@ dump_Elf32_Nhdr(Elf32_Off offset, int store)
|
|||
netdump_print(" ");
|
||||
}
|
||||
lf = 0;
|
||||
} else if (note->n_type == NT_VMCOREDD) {
|
||||
if (nd->ofp)
|
||||
display_vmcoredd_note(note, nd->ofp);
|
||||
} else {
|
||||
if (nd->ofp && !XEN_CORE_DUMPFILE() && !(pc->flags2 & LIVE_DUMP)) {
|
||||
if (machine_type("X86")) {
|
||||
|
@ -2126,7 +2156,7 @@ dump_Elf32_Nhdr(Elf32_Off offset, int store)
|
|||
static size_t
|
||||
dump_Elf64_Nhdr(Elf64_Off offset, int store)
|
||||
{
|
||||
int i, lf;
|
||||
int i = 0, lf = 0;
|
||||
Elf64_Nhdr *note;
|
||||
size_t len;
|
||||
char buf[BUFSIZE];
|
||||
|
@ -2271,6 +2301,18 @@ dump_Elf64_Nhdr(Elf64_Off offset, int store)
|
|||
}
|
||||
break;
|
||||
#endif
|
||||
case NT_VMCOREDD:
|
||||
netdump_print("(NT_VMCOREDD)\n");
|
||||
if (store) {
|
||||
for (i = 0; i < NR_DEVICE_DUMPS; i++) {
|
||||
if (!nd->nt_vmcoredd_array[i]) {
|
||||
nd->nt_vmcoredd_array[i] = (void *)note;
|
||||
nd->num_vmcoredd_notes++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
xen_core = STRNEQ(buf, "XEN CORE") || STRNEQ(buf, "Xen");
|
||||
if (STRNEQ(buf, "VMCOREINFO_XEN"))
|
||||
|
@ -2364,7 +2406,10 @@ dump_Elf64_Nhdr(Elf64_Off offset, int store)
|
|||
}
|
||||
}
|
||||
|
||||
if (BITS32() && (xen_core || (note->n_type == NT_PRSTATUS) || qemuinfo)) {
|
||||
if (note->n_type == NT_VMCOREDD) {
|
||||
if (nd->ofp)
|
||||
display_vmcoredd_note(note, nd->ofp);
|
||||
} else if (BITS32() && (xen_core || (note->n_type == NT_PRSTATUS) || qemuinfo)) {
|
||||
if (nd->ofp && !XEN_CORE_DUMPFILE() && !(pc->flags2 & LIVE_DUMP)) {
|
||||
if (machine_type("X86")) {
|
||||
if (note->n_type == NT_PRSTATUS)
|
||||
|
@ -5037,3 +5082,66 @@ kdump_get_qemucpustate(int cpu)
|
|||
return (QEMUCPUState *)nd->nt_qemu_percpu[cpu];
|
||||
}
|
||||
#endif
|
||||
|
||||
static void *
|
||||
get_kdump_device_dump_offset(void)
|
||||
{
|
||||
void *elf_base = NULL;
|
||||
|
||||
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(FATAL, "no device dumps found in this dumpfile\n");
|
||||
|
||||
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 (!nd->num_vmcoredd_notes)
|
||||
error(FATAL, "no device dumps found in this dumpfile\n");
|
||||
else if (index >= nd->num_vmcoredd_notes)
|
||||
error(FATAL, "no device dump found at index: %d", index);
|
||||
|
||||
elf_base = get_kdump_device_dump_offset();
|
||||
|
||||
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;
|
||||
|
||||
if (!nd->num_vmcoredd_notes)
|
||||
error(FATAL, "no device dumps found in this dumpfile\n");
|
||||
|
||||
fprintf(fp, "%s ", mkstring(buf, strlen("INDEX"), LJUST, "INDEX"));
|
||||
fprintf(fp, " %s ", mkstring(buf, LONG_LONG_PRLEN, LJUST, "OFFSET"));
|
||||
fprintf(fp, " %s ", mkstring(buf, LONG_PRLEN, LJUST, "SIZE"));
|
||||
fprintf(fp, "NAME\n");
|
||||
|
||||
elf_base = get_kdump_device_dump_offset();
|
||||
|
||||
for (i = 0; i < nd->num_vmcoredd_notes; i++) {
|
||||
fprintf(fp, "%s ", mkstring(buf, strlen("INDEX"), CENTER | INT_DEC, MKSTR(i)));
|
||||
offset = nd->nt_vmcoredd_array[i] - elf_base;
|
||||
devdump_info(nd->nt_vmcoredd_array[i], offset, ofp);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
*/
|
||||
|
||||
#include <elf.h>
|
||||
#include "vmcore.h"
|
||||
|
||||
#define MIN_NETDUMP_ELF32_HEADER_SIZE \
|
||||
sizeof(Elf32_Ehdr)+sizeof(Elf32_Phdr)+sizeof(Elf32_Phdr)
|
||||
|
@ -81,6 +82,8 @@ struct vmcore_data {
|
|||
#define arch_data1 arch_data
|
||||
ulong phys_base;
|
||||
ulong arch_data2;
|
||||
void *nt_vmcoredd_array[NR_DEVICE_DUMPS];
|
||||
uint num_vmcoredd_notes;
|
||||
};
|
||||
|
||||
#define DUMP_ELF_INCOMPLETE 0x1 /* dumpfile is incomplete */
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* vmcore.h
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef _VMCORE_H
|
||||
#define _VMCORE_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#ifndef NT_VMCOREDD
|
||||
#define NT_VMCOREDD 0x700
|
||||
#endif
|
||||
|
||||
#define VMCOREDD_NOTE_NAME "LINUX"
|
||||
#define VMCOREDD_MAX_NAME_BYTES 44
|
||||
|
||||
struct vmcoredd_header {
|
||||
__u32 n_namesz; /* Name size */
|
||||
__u32 n_descsz; /* Content size */
|
||||
__u32 n_type; /* NT_VMCOREDD */
|
||||
__u8 name[8]; /* LINUX\0\0\0 */
|
||||
__u8 dump_name[VMCOREDD_MAX_NAME_BYTES]; /* Device dump's name */
|
||||
};
|
||||
|
||||
#endif /* _VMCORE_H */
|
Loading…
Reference in New Issue