Hello Dave, Thanks for reviewing. I've reflected your comments and this is the second version. About sample vmcores, I'll send email to you in private. Please wait for a while. Change Log v0 => v1) * Move REMOTE_DAEMON bit from pc->flags to pc->flags2; See PATCH 01. SADUMP bit is now introduced in pc->flags. * Fix the bug, I found locally, that in per_cpu_ptr(), symbol value of symbol __per_cpu_offset was directly used. Here should have dereferenced the symbol value. diffstat Makefile | 10 +- defs.h | 40 ++- kernel.c | 10 +- main.c | 19 +- memory.c | 10 + netdump.c | 2 +- sadump.c | 1558 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ sadump.h | 210 +++++++++ tools.c | 18 +- x86.c | 16 +- x86_64.c | 39 ++- 11 files changed, 1906 insertions(+), 26 deletions(-) Thanks. HATAYAMA, Daisuke
>From 98660d5831c2982038383aef143513ecc9778862 Mon Sep 17 00:00:00 2001 From: HATAYAMA Daisuke <d.hatayama@xxxxxxxxxxxxxx> Date: Thu, 15 Sep 2011 10:07:11 +0900 Subject: [PATCH 01/12] defs, main: move REMOTE_DAEMON bit from pc->flags to pc->flags2 This is a preparation for introducing new SADUMP flag bit. Now pc->flags fully uses its 64 bits. The flags relevant to MEMORY_SOURCES all belong to pc->flags so to naturally handle the SADUMP flag together with the others, it's necessary to make a space in pc->flags. Here we've chosen REMOTE_DAEMON bit. --- defs.h | 4 ++-- main.c | 7 +++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/defs.h b/defs.h index 330c341..243b5d4 100755 --- a/defs.h +++ b/defs.h @@ -142,7 +142,6 @@ struct number_option { #define MFD_RDWR (0x40ULL) #define KVMDUMP (0x80ULL) #define SILENT (0x100ULL) -#define REMOTE_DAEMON (0x200ULL) #define HASH (0x400ULL) #define SCROLL (0x800ULL) #define NO_CONSOLE (0x1000ULL) @@ -203,7 +202,7 @@ struct number_option { #define DUMPFILE() (!(pc->flags & LIVE_SYSTEM)) #define MEMORY_SOURCES (NETDUMP|KDUMP|MCLXCD|LKCD|DEVMEM|S390D|MEMMOD|DISKDUMP|XENDUMP|CRASHBUILTIN|KVMDUMP|PROC_KCORE) #define DUMPFILE_TYPES (DISKDUMP|NETDUMP|KDUMP|MCLXCD|LKCD|S390D|XENDUMP|KVMDUMP) -#define REMOTE() (pc->flags & REMOTE_DAEMON) +#define REMOTE() (pc->flags2 & REMOTE_DAEMON) #define REMOTE_ACTIVE() (pc->flags & REM_LIVE_SYSTEM) #define REMOTE_DUMPFILE() \ (pc->flags & (REM_NETDUMP|REM_MCLXCD|REM_LKCD|REM_S390D)) @@ -431,6 +430,7 @@ struct program_context { #define FLAT (0x1ULL) #define ELF_NOTES (0x2ULL) #define GET_OSRELEASE (0x4ULL) +#define REMOTE_DAEMON (0x8ULL) #define FLAT_FORMAT() (pc->flags2 & FLAT) #define ELF_NOTES_VALID() (pc->flags2 & ELF_NOTES) char *cleanup; diff --git a/main.c b/main.c index b557010..ace2a04 100755 --- a/main.c +++ b/main.c @@ -372,7 +372,7 @@ main(int argc, char **argv) "too many dumpfile/memory arguments\n"); program_usage(SHORT_FORM); } - pc->flags |= REMOTE_DAEMON; + pc->flags2 |= REMOTE_DAEMON; optind++; continue; } @@ -1081,9 +1081,6 @@ dump_program_context(void) sprintf(&buf[strlen(buf)], "%sDROP_CORE", others++ ? "|" : ""); if (pc->flags & LKCD) sprintf(&buf[strlen(buf)], "%sLKCD", others++ ? "|" : ""); - if (pc->flags & REMOTE_DAEMON) - sprintf(&buf[strlen(buf)], "%sREMOTE_DAEMON", - others++ ? "|" : ""); if (pc->flags & GDB_INIT) sprintf(&buf[strlen(buf)], "%sGDB_INIT", others++ ? "|" : ""); if (pc->flags & IN_GDB) @@ -1251,6 +1248,8 @@ dump_program_context(void) fprintf(fp, "%sELF_NOTES", others++ ? "|" : ""); if (pc->flags2 & GET_OSRELEASE) fprintf(fp, "%sGET_OSRELEASE", others++ ? "|" : ""); + if (pc->flags2 & REMOTE_DAEMON) + fprintf(fp, "%sREMOTE_DAEMON", others++ ? "|" : ""); fprintf(fp, ")\n"); fprintf(fp, " namelist: %s\n", pc->namelist); -- 1.7.4.4
>From 118f547934ceca17b639fff24f08b3f0b444efd1 Mon Sep 17 00:00:00 2001 From: HATAYAMA Daisuke <d.hatayama@xxxxxxxxxxxxxx> Date: Thu, 15 Sep 2011 10:19:29 +0900 Subject: [PATCH 02/12] defs.h: Add basic sadump related macros and flags SADUMP bit is introduced to a vacant, previous REMOTE_DAEMON bit. --- defs.h | 11 +++++++++-- 1 files changed, 9 insertions(+), 2 deletions(-) diff --git a/defs.h b/defs.h index 243b5d4..781b02f 100755 --- a/defs.h +++ b/defs.h @@ -142,6 +142,7 @@ struct number_option { #define MFD_RDWR (0x40ULL) #define KVMDUMP (0x80ULL) #define SILENT (0x100ULL) +#define SADUMP (0x200ULL) #define HASH (0x400ULL) #define SCROLL (0x800ULL) #define NO_CONSOLE (0x1000ULL) @@ -200,8 +201,8 @@ struct number_option { #define ACTIVE() (pc->flags & LIVE_SYSTEM) #define DUMPFILE() (!(pc->flags & LIVE_SYSTEM)) -#define MEMORY_SOURCES (NETDUMP|KDUMP|MCLXCD|LKCD|DEVMEM|S390D|MEMMOD|DISKDUMP|XENDUMP|CRASHBUILTIN|KVMDUMP|PROC_KCORE) -#define DUMPFILE_TYPES (DISKDUMP|NETDUMP|KDUMP|MCLXCD|LKCD|S390D|XENDUMP|KVMDUMP) +#define MEMORY_SOURCES (NETDUMP|KDUMP|MCLXCD|LKCD|DEVMEM|S390D|MEMMOD|DISKDUMP|XENDUMP|CRASHBUILTIN|KVMDUMP|PROC_KCORE|SADUMP) +#define DUMPFILE_TYPES (DISKDUMP|NETDUMP|KDUMP|MCLXCD|LKCD|S390D|XENDUMP|KVMDUMP|SADUMP) #define REMOTE() (pc->flags2 & REMOTE_DAEMON) #define REMOTE_ACTIVE() (pc->flags & REM_LIVE_SYSTEM) #define REMOTE_DUMPFILE() \ @@ -217,6 +218,7 @@ struct number_option { #define XEN_CORE_DUMPFILE() (pc->flags & XEN_CORE) #define LKCD_KERNTYPES() (pc->flags & KERNTYPES) #define KVMDUMP_DUMPFILE() (pc->flags & KVMDUMP) +#define SADUMP_DUMPFILE() (pc->flags & SADUMP) #define NETDUMP_LOCAL (0x1) /* netdump_data flags */ #define NETDUMP_REMOTE (0x2) @@ -249,6 +251,11 @@ struct number_option { #define XENDUMP_LOCAL (0x1) #define XENDUMP_VALID() (xd->flags & XENDUMP_LOCAL) +#define SADUMP_LOCAL (0x1) +#define SADUMP_DISKSET (0x2) +#define SADUMP_MEDIA (0x4) +#define SADUMP_VALID() (sd->flags & SADUMP_LOCAL) + #define CRASHDEBUG(x) (pc->debug >= (x)) #define CRASHDEBUG_SUSPEND(X) { pc->debug_save = pc->debug; pc->debug = X; } -- 1.7.4.4
>From de205a0b9aa246641e9db2d2d1ef5e9970de3f27 Mon Sep 17 00:00:00 2001 From: HATAYAMA Daisuke <d.hatayama@xxxxxxxxxxxxxx> Date: Thu, 15 Sep 2011 10:25:04 +0900 Subject: [PATCH 03/12] sadump: Add sadump core module This commit implements basic functionality for an access to sadump data, most of which is similar to other dumpfiles', in particular, diskdump's. * is_sadump() is an interface to be used in main.c, and is called some times on diskset configurations. The first call of is_sadump() calls read_dump_header() and the second and later calls on diskset configuration calls add_disk(). * read_dump_header() reads the head dumpfile, identifies its configuration and initializes internal sadump_data in a proper way: just as other dumpfiles, SADUMP_LOCAL is set to sd->flags if the dumpfile is valid. Also, SADUMP_MEDIA if on media file and SADUMP_DISKSET on diskset configuration. Shapes of head dumpfile format on the three configurations are as below. Note that diskset header exists only on diskset configuration, and media header only on media file configuration. single partition) diskset) media file) partition header partition header media header dump header diskset header partition header dump sub header dump header dump header bitmap dump sub header dump sub header dumpable bitmap bitmap bitmap (memory data) dumpable bitmap dumpable bitmap (memory data) (memory data) The second or later disks on diskset configuration has partion header only as follows: partition header (memory data) * sd->block_table is quite similar to dd->valid_pages except that the former records offset in blocks while the latter in bytes. sadump has now no compression feature, so calculation of the actual block offset can be simply done without considering page headers. --- defs.h | 12 + sadump.c | 872 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ sadump.h | 210 +++++++++++++++ 3 files changed, 1094 insertions(+), 0 deletions(-) create mode 100644 sadump.c create mode 100644 sadump.h diff --git a/defs.h b/defs.h index 781b02f..4c73750 100755 --- a/defs.h +++ b/defs.h @@ -4716,6 +4716,18 @@ struct kvm_register_set { int get_kvm_register_set(int, struct kvm_register_set *); /* + * sadump.c + */ +int is_sadump(char *); +int read_sadump(int, void *, int, ulong, physaddr_t); +int write_sadump(int, void *, int, ulong, physaddr_t); +int sadump_init(char *, FILE *); +int sadump_is_diskset(void); +ulong get_sadump_panic_task(void); +ulong get_sadump_switch_stack(ulong); +FILE *set_sadump_fp(FILE *); + +/* * qemu.c */ int qemu_init(char *); diff --git a/sadump.c b/sadump.c new file mode 100644 index 0000000..1657d3d --- /dev/null +++ b/sadump.c @@ -0,0 +1,872 @@ +/* + * sadump.h - core analysis suite + * + * Copyright (c) 2011 FUJITSU LIMITED + * + * 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: HATAYAMA Daisuke <d.hatayama@xxxxxxxxxxxxxx> + */ + +#include "defs.h" +#include "sadump.h" +#include <elf.h> + +enum { + failed = -1 +}; + +static struct sadump_data sadump_data = { 0 }; +static struct sadump_data *sd = &sadump_data; + +static int read_device(void *buf, size_t bytes, ulong *offset); +static int read_dump_header(char *file); +static int add_disk(char *file); +static int open_dump_file(char *file); +static int open_disk(char *file); +static ulong paddr_to_pfn(physaddr_t paddr); +static inline int is_set_bit(char *bitmap, ulong pfn); +static inline int page_is_ram(unsigned int nr); +static inline int page_is_dumpable(unsigned int nr); +static int lookup_diskset(ulong whole_offset, int *diskid, ulong *disk_offset); +static struct tm *efi_time_t_to_tm(const efi_time_t *e, struct tm *t); +static char * guid_to_str(efi_guid_t *guid, char *buf, size_t buflen); +static int verify_magic_number(uint32_t magicnum[DUMP_PART_HEADER_MAGICNUM_SIZE]); +static int block_table_init(void); +static ulong pfn_to_block(ulong pfn); + +struct sadump_data * +sadump_get_sadump_data(void) +{ + if (!SADUMP_VALID() || !SADUMP_DUMPFILE()) + return NULL; + + return &sadump_data; +} + +int +sadump_cleanup_sadump_data(void) +{ + int i; + + if (!SADUMP_VALID() || !SADUMP_DUMPFILE()) + return FALSE; + + if (sd->flags & SADUMP_DISKSET) { + for (i = 1; i < sd->sd_list_len; ++i) { + close(sd->sd_list[i]->dfd); + free(sd->sd_list[i]->header); + free(sd->sd_list[i]); + } + } + + close(sd->dfd); + free(sd->header); + free(sd->dump_header); + free(sd->diskset_header); + free(sd->bitmap); + free(sd->dumpable_bitmap); + free(sd->page_buf); + free(sd->block_table); + free(sd->sd_list[0]); + + memset(&sadump_data, 0, sizeof(sadump_data)); + + pc->flags2 &= ~SADUMP; + pc->dumpfile = NULL; + pc->readmem = NULL; + pc->writemem = NULL; + + return TRUE; +} + +static int +read_device(void *buf, size_t bytes, ulong *offset) +{ + if (lseek(sd->dfd, *offset, SEEK_SET) == failed) { + error(INFO, "sadump: cannot lseek dump device\n"); + return FALSE; + } + if (read(sd->dfd, buf, bytes) < bytes) { + error(INFO, "sadump: cannot read dump device\n"); + return FALSE; + } + *offset += bytes; + return TRUE; +} + +static int +read_dump_header(char *file) +{ + struct sadump_part_header *sph = NULL; + struct sadump_header *sh = NULL; + struct sadump_disk_set_header *sdh = NULL; + struct sadump_media_header *smh = NULL; + struct sadump_diskset_data *sd_list_len_0 = NULL; + size_t block_size = SADUMP_DEFAULT_BLOCK_SIZE; + ulong flags = 0; + ulong offset = 0, sub_hdr_offset, data_offset; + uint32_t smram_cpu_state_size = 0; + ulong bitmap_len, dumpable_bitmap_len; + char *bitmap = NULL, *dumpable_bitmap = NULL, *page_buf = NULL; + char guid1[33], guid2[33]; + + sph = malloc(block_size); + if (!sph) { + error(INFO, "sadump: cannot allocate partition header buffer\n"); + goto err; + } + + sdh = malloc(block_size); + if (!sdh) { + error(INFO, "sadump: cannot allocate disk set header buffer\n"); + goto err; + } + + sh = malloc(block_size); + if (!sh) { + error(INFO, "sadump: cannot allocate dump header buffer\n"); + goto err; + } + + smh = malloc(block_size); + if (!smh) { + error(INFO, "sadump: cannot allocate media header buffer\n"); + goto err; + } + +restart: + if (block_size < 0) + return FALSE; + + if (!read_device(sph, block_size, &offset)) { + error(INFO, "sadump: cannot read partition header\n"); + goto err; + } + + if (sph->signature1 != SADUMP_SIGNATURE1 || + sph->signature2 != SADUMP_SIGNATURE2) { + + flags |= SADUMP_MEDIA; + + if (CRASHDEBUG(1)) + error(INFO, "sadump: read dump device as media " + "format\n"); + + offset = 0; + + if (!read_device(smh, block_size, &offset)) { + error(INFO, "sadump: cannot read media header\n"); + goto err; + } + + if (!read_device(sph, block_size, &offset)) { + error(INFO, "sadump: cannot read partition header\n"); + goto err; + } + + if (sph->signature1 != SADUMP_SIGNATURE1 || + sph->signature2 != SADUMP_SIGNATURE2) { + if (CRASHDEBUG(1)) + error(INFO, "sadump: does not have partition " + "header\n"); + goto err; + } + + } + + if (!verify_magic_number(sph->magicnum)) { + error(INFO, "sadump: invalid magic number\n"); + goto err; + } + + if (!(flags & SADUMP_MEDIA) && sph->set_disk_set) { + uint32_t header_blocks; + size_t header_size; + + flags |= SADUMP_DISKSET; + + if (CRASHDEBUG(1)) + error(INFO, "sadump: read dump device as diskset\n"); + + if (sph->set_disk_set != 1 || + sph->set_disk_set > SADUMP_MAX_DISK_SET_NUM) { + if (CRASHDEBUG(1)) + error(INFO, "sadump: invalid disk set number: " + "%d\n", + sph->set_disk_set); + goto err; + } + + if (!read_device(&header_blocks, sizeof(uint32_t), &offset)) { + error(INFO, "sadump: cannot read disk set header " + "size\n"); + goto err; + } + + offset -= sizeof(uint32_t); + header_size = header_blocks * block_size; + + if (header_size > block_size) { + sdh = realloc(sdh, header_size); + if (!sdh) { + error(INFO, "sadump: cannot re-allocate disk " + "set buffer\n"); + goto err; + } + } + + if (!read_device(sdh, header_size, &offset)) { + error(INFO, "sadump: cannot read disk set header\n"); + goto err; + } + + } + + if (!read_device(sh, block_size, &offset)) { + error(INFO, "sadump: cannot read dump header\n"); + goto err; + } + + sub_hdr_offset = offset; + + if (strncmp(sh->signature, SADUMP_SIGNATURE, 8) != 0) { + if (CRASHDEBUG(1)) + error(INFO, "sadump: does not have dump header\n"); + goto err; + } + + if (flags & SADUMP_MEDIA) { + + if (memcmp(&sph->sadump_id, &smh->sadump_id, + sizeof(efi_guid_t)) != 0) { + if (CRASHDEBUG(1)) + error(INFO, "sadump: system ID mismatch\n" + " partition header: %s\n" + " media header: %s\n", + guid_to_str(&sph->sadump_id, guid1, sizeof(guid1)), + guid_to_str(&smh->sadump_id, guid2, sizeof(guid2))); + goto err; + } + + if (memcmp(&sph->disk_set_id, &smh->disk_set_id, + sizeof(efi_guid_t)) != 0) { + if (CRASHDEBUG(1)) + error(INFO, "sadump: disk set ID mismatch\n" + " partition header: %s\n" + " media header: %s\n", + guid_to_str(&sph->disk_set_id, guid1, sizeof(guid1)), + guid_to_str(&smh->disk_set_id, guid2, sizeof(guid2))); + goto err; + } + + if (memcmp(&sph->time_stamp, &smh->time_stamp, + sizeof(efi_guid_t)) != 0) { + struct tm tm; + if (CRASHDEBUG(1)) + error(INFO, "sadump: time stamp mismatch\n" + " partition header: %s\n" + " media header: %s\n", + strip_linefeeds(asctime + (efi_time_t_to_tm + (&sph->time_stamp, + &tm))), + strip_linefeeds(asctime + (efi_time_t_to_tm + (&smh->time_stamp, + &tm)))); + goto err; + } + + if (smh->sequential_num != 1) { + error(INFO, "sadump: first media file has sequential " + "number %d\n", smh->sequential_num); + goto err; + } + + } + + if (sh->block_size != block_size) { + block_size = sh->block_size; + offset = 0; + goto restart; + } + + if (CRASHDEBUG(1)) { + if (flags & SADUMP_MEDIA) + error(INFO, "sadump: media backup file\n"); + + else if (flags & SADUMP_DISKSET) + error(INFO, "sadump: diskset configuration with %d " + "disks\n", sdh->disk_num); + + else + error(INFO, "sadump: single partition " + "configuration\n"); + } + + flags |= SADUMP_LOCAL; + + if (sh->sub_hdr_size > 0) { + if (!read_device(&smram_cpu_state_size, sizeof(uint32_t), + &offset)) { + error(INFO, + "sadump: cannot read SMRAM CPU STATE size\n"); + goto err; + } + smram_cpu_state_size /= sh->nr_cpus; + + offset -= sizeof(uint32_t); + offset += sh->sub_hdr_size * block_size; + } + + if (!sh->bitmap_blocks) { + error(INFO, "sadump: bitmap_blocks is zero\n"); + goto err; + } + bitmap_len = block_size * sh->bitmap_blocks; + bitmap = calloc(bitmap_len, 1); + if (!bitmap) { + error(INFO, "sadump: cannot allocate memory for bitmap " + "buffer\n"); + goto err; + } + if (!read_device(bitmap, bitmap_len, &offset)) { + error(INFO, "sadump: cannot read bitmap\n"); + goto err; + } + + if (!sh->dumpable_bitmap_blocks) { + error(INFO, "sadump: dumpable_bitmap_blocks is zero\n"); + goto err; + } + dumpable_bitmap_len = block_size * sh->dumpable_bitmap_blocks; + dumpable_bitmap = calloc(dumpable_bitmap_len, 1); + if (!dumpable_bitmap) { + error(INFO, "sadump: cannot allocate memory for " + "dumpable_bitmap buffer\n"); + goto err; + } + if (!read_device(dumpable_bitmap, dumpable_bitmap_len, &offset)) { + error(INFO, "sadump: cannot read dumpable bitmap\n"); + goto err; + } + + data_offset = offset; + + page_buf = malloc(block_size); + if (!page_buf) { + error(INFO, "sadump: cannot allocate page buffer\n"); + goto err; + } + + if (flags & SADUMP_DISKSET) { + + sd_list_len_0 = malloc(sizeof(struct sadump_diskset_data)); + if (!sd_list_len_0) { + error(INFO, "sadump: cannot allocate diskset data buffer\n"); + goto err; + } + + } + + sd->filename = file; + sd->flags = flags; + + if (machine_type("X86")) + sd->machine_type = EM_386; + else if (machine_type("X86_64")) + sd->machine_type = EM_X86_64; + else { + error(INFO, "sadump: unsupported machine type: %s\n", + MACHINE_TYPE); + goto err; + } + + sd->data_offset = data_offset; + sd->block_size = block_size; + sd->block_shift = ffs(sd->block_size) - 1; + + sd->bitmap = bitmap; + sd->dumpable_bitmap = dumpable_bitmap; + + sd->sub_hdr_offset = sub_hdr_offset; + sd->smram_cpu_state_size = smram_cpu_state_size; + + sd->header = sph; + sd->dump_header = sh; + if (flags & SADUMP_DISKSET) + sd->diskset_header = sdh; + if (flags & SADUMP_MEDIA) + sd->media_header = smh; + + sd->page_buf = page_buf; + + if (flags & SADUMP_DISKSET) { + sd_list_len_0->filename = sd->filename; + sd_list_len_0->dfd = sd->dfd; + sd_list_len_0->header = sd->header; + sd_list_len_0->data_offset = sd->data_offset; + + sd->sd_list_len = 1; + sd->sd_list[0] = sd_list_len_0; + } + + if (!block_table_init()) { + error(INFO, "sadump: cannot initialize block hash table\n"); + goto err; + } + + if (!(flags & SADUMP_DISKSET)) + free(sdh); + + if (!(flags & SADUMP_MEDIA)) + free(smh); + + return TRUE; + +err: + close(sd->dfd); + + free(sph); + free(sdh); + free(sh); + free(smh); + free(bitmap); + free(dumpable_bitmap); + free(page_buf); + free(sd_list_len_0); + + return FALSE; +} + +static int +add_disk(char *file) +{ + struct sadump_part_header *ph; + struct sadump_diskset_data *this_disk; + int diskid; + char guid1[33], guid2[33]; + + diskid = sd->sd_list_len - 1; + this_disk = sd->sd_list[diskid]; + + ph = malloc(sd->block_size); + if (!ph) { + error(INFO, "sadump: cannot malloc block_size buffer\n"); + return FALSE; + } + + if (lseek(this_disk->dfd, 0, SEEK_SET) == failed) { + error(INFO, "sadump: cannot lseek dump partition header\n"); + free(ph); + return FALSE; + } + if (read(this_disk->dfd, ph, sd->block_size) < sd->block_size) { + error(INFO, "sadump: cannot read dump partition header\n"); + free(ph); + return FALSE; + } + + if (ph->signature1 != SADUMP_SIGNATURE1 || + ph->signature2 != SADUMP_SIGNATURE2) { + if (CRASHDEBUG(1)) + error(INFO, "sadump: does not have partition header\n"); + free(ph); + return FALSE; + } + + if (memcmp(&sd->header->sadump_id, &ph->sadump_id, + sizeof(efi_guid_t)) != 0) { + if (CRASHDEBUG(1)) + error(INFO, "sadump: system ID mismatch\n" + " partition header on disk #1: %s\n" + " partition header on disk #%d: %s\n", + guid_to_str(&sd->header->sadump_id, guid1, + sizeof(guid1)), + diskid+1, + guid_to_str(&ph->sadump_id, guid2, + sizeof(guid2))); + free(ph); + return FALSE; + } + + if (memcmp(&sd->header->disk_set_id, &ph->disk_set_id, sizeof(efi_guid_t)) != 0) { + if (CRASHDEBUG(1)) + error(INFO, "sadump: disk set ID mismatch\n" + " partition header on disk #1: %s\n" + " partition header on disk #%d: %s\n", + guid_to_str(&sd->header->disk_set_id, guid1, + sizeof(guid1)), + diskid+1, + guid_to_str(&ph->disk_set_id, guid2, + sizeof(guid2))); + free(ph); + return FALSE; + } + + if (memcmp(&sd->diskset_header->vol_info[diskid - 1].id, &ph->vol_id, + sizeof(efi_guid_t)) != 0) { + if (CRASHDEBUG(1)) + error(INFO, "sadump: volume ID mismatch\n" + " disk set header on disk #1: %s\n" + " partition header on disk #%d: %s\n", + guid_to_str(&sd->diskset_header->vol_info[diskid-1].id, + guid1, sizeof(guid1)), + diskid+1, + guid_to_str(&ph->vol_id, guid2, sizeof(guid2))); + free(ph); + return FALSE; + } + + if (memcmp(&sd->header->time_stamp, &ph->time_stamp, + sizeof(efi_time_t)) != 0) { + struct tm tm; + if (CRASHDEBUG(1)) + error(INFO, "sadump: time stamp mismatch\n" + " partition header on disk #1: %s\n" + " partition header on disk #%d: %s\n", + strip_linefeeds(asctime(efi_time_t_to_tm + (&sd->header->time_stamp, + &tm))), + diskid+1, + strip_linefeeds(asctime(efi_time_t_to_tm + (&ph->time_stamp, + &tm)))); + free(ph); + return FALSE; + } + + if (diskid != ph->set_disk_set - 1) { + if (CRASHDEBUG(1)) + error(INFO, "sadump: wrong disk order; " + "#%d expected but #%d given\n", + diskid+1, ph->set_disk_set); + free(ph); + return FALSE; + } + + this_disk->header = ph; + this_disk->data_offset = sd->block_size; + this_disk->filename = file; + + return TRUE; +} + +static int +open_dump_file(char *file) +{ + int fd; + + fd = open(file, O_RDONLY); + if (fd < 0) { + error(INFO, "sadump: unable to open dump file %s", file); + return FALSE; + } + + sd->dfd = fd; + + return TRUE; +} + +static int +open_disk(char *file) +{ + struct sadump_diskset_data *this_disk; + + sd->sd_list_len++; + + if (sd->sd_list_len > sd->diskset_header->disk_num) { + error(INFO, "sadump: too many diskset arguments; " + "this diskset consists of %d disks\n", + sd->diskset_header->disk_num); + return FALSE; + } + + this_disk = malloc(sizeof(struct sadump_diskset_data)); + if (!this_disk) { + if (CRASHDEBUG(1)) { + error(INFO, "sadump: cannot malloc diskset data buffer\n"); + } + return FALSE; + } + + sd->sd_list[sd->sd_list_len - 1] = this_disk; + + this_disk->dfd = open(file, O_RDONLY); + if (!this_disk->dfd) { + free(this_disk); + error(INFO, "sadump: unable to open dump file %s", file); + return FALSE; + } + + return TRUE; +} + +int is_sadump(char *file) +{ + if (SADUMP_VALID()) { + if (sd->flags & SADUMP_DISKSET) { + if (!open_disk(file) || !add_disk(file)) { + (void) sadump_cleanup_sadump_data(); + return FALSE; + } + return TRUE; + } + if (CRASHDEBUG(1)) + error(INFO, "sadump: does not support multiple file formats\n"); + (void) sadump_cleanup_sadump_data(); + return FALSE; + } + + if (!open_dump_file(file) || !read_dump_header(file)) + return FALSE; + + return TRUE; +} + +int sadump_is_diskset(void) +{ + if (!SADUMP_VALID()) + return FALSE; + + return !!(sd->flags & SADUMP_DISKSET); +} + +/* + * Translate physical address in paddr to PFN number. This means normally that + * we just shift paddr by some constant. + */ +static ulong +paddr_to_pfn(physaddr_t paddr) +{ + return paddr >> sd->block_shift; +} + +static inline int +is_set_bit(char *bitmap, ulong pfn) +{ + ulong index, bit; + + index = pfn >> 3; + bit = pfn & 7; + + return !!(bitmap[index] & (1UL << bit)); +} + +static inline int +page_is_ram(unsigned int nr) +{ + return is_set_bit(sd->bitmap, nr); +} + +static inline int +page_is_dumpable(unsigned int nr) +{ + return is_set_bit(sd->dumpable_bitmap, nr); +} + +static int +lookup_diskset(ulong whole_offset, int *diskid, ulong *disk_offset) +{ + ulong offset = whole_offset; + int i; + + for (i = 0; i < sd->sd_list_len; ++i) { + ulong used_device_i, data_offset_i, ram_size; + + used_device_i = sd->sd_list[i]->header->used_device; + data_offset_i = sd->sd_list[i]->data_offset; + + ram_size = used_device_i - data_offset_i; + + if (offset < ram_size) + break; + offset -= ram_size; + } + + if (i == sd->sd_list_len) + return FALSE; + + *diskid = i; + *disk_offset = offset; + + return TRUE; +} + +int read_sadump(int fd, void *bufptr, int cnt, ulong addr, physaddr_t paddr) +{ + physaddr_t curpaddr; + ulong pfn, page_offset, block, whole_offset, perdisk_offset; + int dfd; + + pfn = paddr_to_pfn(paddr); + + curpaddr = paddr & ~((physaddr_t)(sd->block_size-1)); + page_offset = paddr & ((physaddr_t)(sd->block_size-1)); + + if ((pfn >= sd->dump_header->max_mapnr) || !page_is_ram(pfn)) + return SEEK_ERROR; + if (!page_is_dumpable(pfn)) { + memset(bufptr, 0, cnt); + return cnt; + } + + block = pfn_to_block(pfn); + + whole_offset = block * sd->block_size; + + if (sd->flags & SADUMP_DISKSET) { + int diskid; + + if (!lookup_diskset(whole_offset, &diskid, &perdisk_offset)) + return SEEK_ERROR; + + dfd = sd->sd_list[diskid]->dfd; + perdisk_offset += sd->sd_list[diskid]->data_offset; + + } else { + dfd = sd->dfd; + perdisk_offset = whole_offset + sd->data_offset; + + } + + if (lseek(dfd, perdisk_offset, SEEK_SET) == failed) + return SEEK_ERROR; + + if (read(dfd, sd->page_buf, sd->block_size) != sd->block_size) + return READ_ERROR; + + memcpy(bufptr, sd->page_buf + page_offset, cnt); + + return cnt; +} + +int write_sadump(int fd, void *bufptr, int cnt, ulong addr, physaddr_t paddr) +{ + return 0; +} + +int sadump_init(char *unused, FILE *fptr) +{ + if (!SADUMP_VALID()) + return FALSE; + + return TRUE; +} + +ulong get_sadump_panic_task(void) +{ + return NO_TASK; +} + +ulong get_sadump_switch_stack(ulong task) +{ + return 0; +} + +static struct tm * +efi_time_t_to_tm(const efi_time_t *e, struct tm *t) +{ + time_t ti; + + memset(t, 0, sizeof(*t)); + + t->tm_sec = e->second; + t->tm_min = e->minute; + t->tm_hour = e->hour; + t->tm_mday = e->day; + t->tm_mon = e->month - 1; + t->tm_year = e->year - 1900; + + if (e->timezone != EFI_UNSPECIFIED_TIMEZONE) + t->tm_hour += e->timezone; + + else if (CRASHDEBUG(1)) + error(INFO, "sadump: timezone information is missing\n"); + + ti = mktime(t); + if (ti == (time_t)-1) + return t; + + return localtime_r(&ti, t); +} + +static char * +guid_to_str(efi_guid_t *guid, char *buf, size_t buflen) +{ + snprintf(buf, buflen, + "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + guid->data1, guid->data2, guid->data3, + guid->data4[0], guid->data4[1], guid->data4[2], + guid->data4[3], guid->data4[4], guid->data4[5], + guid->data4[6], guid->data4[7]); + + return buf; +} + +static int +verify_magic_number(uint32_t magicnum[DUMP_PART_HEADER_MAGICNUM_SIZE]) +{ + int i; + + for (i = 1; i < DUMP_PART_HEADER_MAGICNUM_SIZE; ++i) + if (magicnum[i] != (magicnum[i - 1] + 7) * 11) + return FALSE; + + return TRUE; +} + +static int block_table_init(void) +{ + ulong section, max_section, pfn; + ulong *block_table; + + max_section = divideup(sd->dump_header->max_mapnr, SADUMP_PF_SECTION_NUM); + + block_table = calloc(sizeof(ulong), max_section); + if (!block_table) { + error(INFO, "sadump: cannot allocate memory for block_table\n"); + return FALSE; + } + + for (section = 0; section < max_section; ++section) { + if (section > 0) + block_table[section] = block_table[section-1]; + for (pfn = section * SADUMP_PF_SECTION_NUM; + pfn < (section + 1) * SADUMP_PF_SECTION_NUM; + ++pfn) + if (page_is_dumpable(pfn)) + block_table[section]++; + } + + sd->block_table = block_table; + + return TRUE; +} + +static ulong pfn_to_block(ulong pfn) +{ + ulong block, section, p; + + section = pfn / SADUMP_PF_SECTION_NUM; + + if (section) + block = sd->block_table[section - 1]; + else + block = 0; + + for (p = section * SADUMP_PF_SECTION_NUM; p < pfn; ++p) + if (page_is_dumpable(p)) + block++; + + return block; +} diff --git a/sadump.h b/sadump.h new file mode 100644 index 0000000..c5e3591 --- /dev/null +++ b/sadump.h @@ -0,0 +1,210 @@ +/* + * sadump.h - core analysis suite + * + * Copyright (c) 2011 FUJITSU LIMITED + * + * 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: HATAYAMA Daisuke <d.hatayama@xxxxxxxxxxxxxx> + */ + +#include <stdint.h> +#include <stdlib.h> + +typedef struct efi_time { + uint16_t year; + uint8_t month; + uint8_t day; + uint8_t hour; + uint8_t minute; + uint8_t second; + uint8_t pad1; + uint32_t nanosecond; +#define EFI_UNSPECIFIED_TIMEZONE 2047 + int16_t timezone; + uint8_t daylight; + uint8_t pad2; +} efi_time_t; + +typedef struct { + uint32_t data1; + uint16_t data2; + uint16_t data3; + uint8_t data4[8]; +} efi_guid_t; + +struct sadump_part_header { +#define SADUMP_SIGNATURE1 0x75646173 +#define SADUMP_SIGNATURE2 0x0000706d + uint32_t signature1; /* sadu */ + uint32_t signature2; /* mp\0\0 */ + uint32_t enable; /* set sadump service */ + uint32_t reboot; /* number of seconds until reboot. 1-3600 */ + uint32_t compress; /* memory image format. */ + uint32_t recycle; /* dump device recycle */ + uint32_t label[16]; /* reserve */ + efi_guid_t sadump_id; /* system UUID */ + efi_guid_t disk_set_id; /* disk set UUID */ + efi_guid_t vol_id; /* device UUID */ + efi_time_t time_stamp; /* time stamp */ + uint32_t set_disk_set; /* device type */ +#define SADUMP_MAX_DISK_SET_NUM 16 + uint32_t reserve; /* Padding for Alignment */ + uint64_t used_device; /* used device */ +#define DUMP_PART_HEADER_MAGICNUM_SIZE 982 + uint32_t magicnum[DUMP_PART_HEADER_MAGICNUM_SIZE]; /* magic number */ +}; + +struct sadump_volume_info { + efi_guid_t id; /* volume id */ + uint64_t vol_size; /* device size */ + uint32_t status; /* device status */ + uint32_t cache_size; /* cache size */ +}; + +struct sadump_disk_set_header { + uint32_t disk_set_header_size; /* disk set header size */ + uint32_t disk_num; /* disk number */ + uint64_t disk_set_size; /* disk set size */ +#define DUMP_DEVICE_MAX 16 + struct sadump_volume_info vol_info[DUMP_DEVICE_MAX - 1]; + /* struct VOL_INFO array */ +}; + +struct sadump_header { +#define SADUMP_SIGNATURE "sadump\0\0" + char signature[8]; /* = "sadump\0\0" */ + uint32_t header_version; /* Dump header version */ + uint32_t reserve; /* Padding for Alignment */ + efi_time_t timestamp; /* Time stamp */ + uint32_t status; /* Above flags */ + uint32_t compress; /* Above flags */ + uint32_t block_size; /* Size of a block in byte */ +#define SADUMP_DEFAULT_BLOCK_SIZE 4096 + uint32_t extra_hdr_size; /* Size of host dependent + * header in blocks (reserve) + */ + uint32_t sub_hdr_size; /* Size of arch dependent header in blocks */ + uint32_t bitmap_blocks; /* Size of Memory bitmap in block */ + uint32_t dumpable_bitmap_blocks; /* Size of Memory bitmap in block */ + uint32_t max_mapnr; /* = max_mapnr */ + uint32_t total_ram_blocks; /* Size of Memory in block */ + uint32_t device_blocks; /* Number of total blocks in the dump device */ + uint32_t written_blocks; /* Number of written blocks */ + uint32_t current_cpu; /* CPU# which handles dump */ + uint32_t nr_cpus; /* Number of CPUs */ +}; + +struct sadump_apic_state { + uint64_t ApicId; /* Local Apic ID register */ + uint64_t Ldr; /* Logical Destination Register */ +}; + +struct sadump_smram_cpu_state { + uint64_t Reserved1[58]; + uint32_t GdtUpper, LdtUpper, IdtUpper; + uint32_t Reserved2[3]; + uint64_t IoEip; + uint64_t Reserved3[10]; + uint32_t Cr4; + uint32_t Reserved4[18]; + uint32_t GdtLower; + uint32_t GdtLimit; + uint32_t IdtLower; + uint32_t IdtLimit; + uint32_t LdtLower; + uint32_t LdtLimit; + uint32_t LdtInfo; + uint64_t Reserved5[6]; + uint64_t Eptp; + uint32_t EptpSetting; + uint32_t Reserved6[5]; + uint32_t Smbase; + uint32_t SmmRevisionId; + uint16_t IoInstructionRestart; + uint16_t AutoHaltRestart; + uint32_t Reserved7[6]; + uint32_t R15Lower, R15Upper, R14Lower, R14Upper; + uint32_t R13Lower, R13Upper, R12Lower, R12Upper; + uint32_t R11Lower, R11Upper, R10Lower, R10Upper; + uint32_t R9Lower, R9Upper, R8Lower, R8Upper; + uint32_t RaxLower, RaxUpper, RcxLower, RcxUpper; + uint32_t RdxLower, RdxUpper, RbxLower, RbxUpper; + uint32_t RspLower, RspUpper, RbpLower, RbpUpper; + uint32_t RsiLower, RsiUpper, RdiLower, RdiUpper; + uint32_t IoMemAddrLower, IoMemAddrUpper; + uint32_t IoMisc, Es, Cs, Ss, Ds, Fs, Gs; + uint32_t Ldtr, Tr; + uint64_t Dr7, Dr6, Rip, Ia32Efer, Rflags; + uint64_t Cr3, Cr0; +}; + +struct sadump_page_header { + uint64_t page_flags; + uint32_t size; + uint32_t flags; +}; + +struct sadump_media_header { + efi_guid_t sadump_id; // system UUID + efi_guid_t disk_set_id; // disk set UUID + efi_time_t time_stamp; /* time stamp */ + char sequential_num; // Medium sequential number + char term_cord; // Termination cord + char disk_set_header_size; // Size of original disk set header + char disks_in_use; // Number of used disks of original dump device + char reserve[4044]; // reserve feild +}; + +#define divideup(x, y) (((x) + ((y) - 1)) / (y)) + +#define SADUMP_PF_SECTION_NUM 4096 + +struct sadump_diskset_data { + char *filename; + int dfd; + struct sadump_part_header *header; + ulong data_offset; +}; + +struct sadump_data { + char *filename; + ulong flags; + int dfd; /* dumpfile file descriptor */ + int machine_type; /* machine type identifier */ + + struct sadump_part_header *header; + struct sadump_header *dump_header; + struct sadump_disk_set_header *diskset_header; + struct sadump_media_header *media_header; + + char *bitmap; + char *dumpable_bitmap; + + size_t sub_hdr_offset; + uint32_t smram_cpu_state_size; + + ulong data_offset; + int block_size; + int block_shift; + + char *page_buf; + ulong *block_table; + + int sd_list_len; + struct sadump_diskset_data *sd_list[SADUMP_MAX_DISK_SET_NUM]; +}; + +struct sadump_data *sadump_get_sadump_data(void); +int sadump_cleanup_sadump_data(void); +ulong sadump_identify_format(int *block_size); +int sadump_get_smram_cpu_state(int apicid, + struct sadump_smram_cpu_state *smram); -- 1.7.4.4
>From daf0f76e85024693f672c196d200377eb6eb4538 Mon Sep 17 00:00:00 2001 From: HATAYAMA Daisuke <d.hatayama@xxxxxxxxxxxxxx> Date: Thu, 15 Sep 2011 10:33:22 +0900 Subject: [PATCH 04/12] sadump, x86_64: set up phys_base on sadump dumpfiles sadump does not save phys_base. So some estimaton method is required. For the purpose, we here use x86_64_virt_phys_base(). We've never faced any issue so far. --- defs.h | 1 + sadump.c | 14 ++++++++++++++ x86_64.c | 17 +++++++++++++++++ 3 files changed, 32 insertions(+), 0 deletions(-) diff --git a/defs.h b/defs.h index 4c73750..c1c2fa8 100755 --- a/defs.h +++ b/defs.h @@ -4726,6 +4726,7 @@ int sadump_is_diskset(void); ulong get_sadump_panic_task(void); ulong get_sadump_switch_stack(ulong); FILE *set_sadump_fp(FILE *); +int sadump_phys_base(ulong *); /* * qemu.c diff --git a/sadump.c b/sadump.c index 1657d3d..78e0ee2 100644 --- a/sadump.c +++ b/sadump.c @@ -825,6 +825,20 @@ verify_magic_number(uint32_t magicnum[DUMP_PART_HEADER_MAGICNUM_SIZE]) return TRUE; } +/* + * sadump does not save phys_base; it must resort to another way. + */ +int sadump_phys_base(ulong *phys_base) +{ + if (SADUMP_VALID()) { + if (CRASHDEBUG(1)) + error(NOTE, "sadump: does not save phys_base.\n"); + return FALSE; + } + + return FALSE; +} + static int block_table_init(void) { ulong section, max_section, pfn; diff --git a/x86_64.c b/x86_64.c index 236288e..c8bdd3f 100755 --- a/x86_64.c +++ b/x86_64.c @@ -5677,6 +5677,23 @@ x86_64_calc_phys_base(void) return; } + if (SADUMP_DUMPFILE()) { + if (sadump_phys_base(&phys_base)) { + machdep->machspec->phys_base = phys_base; + if (CRASHDEBUG(1)) + fprintf(fp, "sadump: phys_base: %lx\n", + phys_base); + } else { + machdep->machspec->phys_base = phys_base; + if (!x86_64_virt_phys_base()) + error(WARNING, + "cannot determine physical base address:" + " defaulting to %lx\n\n", + phys_base); + } + return; + } + if ((vd = get_kdump_vmcore_data())) { for (i = 0; i < vd->num_pt_load_segments; i++) { phdr = vd->load64 + i; -- 1.7.4.4
>From c018d2d0914247c1ce6876d83f6e36c62e56bcf0 Mon Sep 17 00:00:00 2001 From: HATAYAMA Daisuke <d.hatayama@xxxxxxxxxxxxxx> Date: Thu, 15 Sep 2011 10:44:07 +0900 Subject: [PATCH 05/12] sadump, memory: Get page size on sadump dumpfiles --- defs.h | 1 + memory.c | 4 ++++ sadump.c | 5 +++++ 3 files changed, 10 insertions(+), 0 deletions(-) diff --git a/defs.h b/defs.h index c1c2fa8..a110881 100755 --- a/defs.h +++ b/defs.h @@ -4719,6 +4719,7 @@ int get_kvm_register_set(int, struct kvm_register_set *); * sadump.c */ int is_sadump(char *); +uint sadump_page_size(void); int read_sadump(int, void *, int, ulong, physaddr_t); int write_sadump(int, void *, int, ulong, physaddr_t); int sadump_init(char *, FILE *); diff --git a/memory.c b/memory.c index 4d44706..32079e1 100755 --- a/memory.c +++ b/memory.c @@ -13855,6 +13855,10 @@ memory_page_size(void) psz = s390_page_size(); break; + case SADUMP: + psz = sadump_page_size(); + break; + default: psz = 0; error(FATAL, "memory_page_size: invalid pc->flags: %lx\n", diff --git a/sadump.c b/sadump.c index 78e0ee2..0996860 100644 --- a/sadump.c +++ b/sadump.c @@ -641,6 +641,11 @@ int sadump_is_diskset(void) return !!(sd->flags & SADUMP_DISKSET); } +uint sadump_page_size(void) +{ + return sd->dump_header->block_size; +} + /* * Translate physical address in paddr to PFN number. This means normally that * we just shift paddr by some constant. -- 1.7.4.4
>From 176c25ff3acda0285c4d2aa8c12926a6fae26c1b Mon Sep 17 00:00:00 2001 From: HATAYAMA Daisuke <d.hatayama@xxxxxxxxxxxxxx> Date: Thu, 15 Sep 2011 10:47:58 +0900 Subject: [PATCH 06/12] main: Add sadump dumpfiles check On diskset configuration, multiple (two or more) dumpfiles are given as command-line arguments, and then is_sadump() is called the number of the dumpfiles times. On single partition and media backup file configurations, given dumpfile is now always only one, and then is_sadump() is assumed to be called only once. But in the future, we MIGHT support media backup format consisting of multiple files, just as multi volume format of tar command, and then the processing will be just like what's done on the diskset configuration. --- main.c | 12 ++++++++++++ 1 files changed, 12 insertions(+), 0 deletions(-) diff --git a/main.c b/main.c index ace2a04..320adf1 100755 --- a/main.c +++ b/main.c @@ -554,6 +554,18 @@ main(int argc, char **argv) pc->readmem = read_s390_dumpfile; pc->writemem = write_s390_dumpfile; + } else if (is_sadump(argv[optind])) { + if ((pc->flags & MEMORY_SOURCES) && + !sadump_is_diskset()) { + error(INFO, + "too many dumpfile arguments\n"); + program_usage(SHORT_FORM); + } + pc->flags |= SADUMP; + pc->dumpfile = argv[optind]; + pc->readmem = read_sadump; + pc->writemem = write_sadump; + } else { error(INFO, "%s: not a supported file format\n", -- 1.7.4.4
>From 9de1d64de6eb236cfa4e482df63105cd9c82e9dd Mon Sep 17 00:00:00 2001 From: HATAYAMA Daisuke <d.hatayama@xxxxxxxxxxxxxx> Date: Thu, 15 Sep 2011 10:57:13 +0900 Subject: [PATCH 07/12] Makefile: Add sadump related descriptions Now crash can be built. Basic functionality to access memory data in sadump dumpfiles is available. Remaining patchs implememts interface for registers of active CPUes and small changes on sys and help -D. --- Makefile | 10 +++++++--- 1 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index fe6c852..2b8d7ab 100644 --- a/Makefile +++ b/Makefile @@ -68,6 +68,7 @@ LKCD_DUMP_HFILES=lkcd_vmdump_v1.h lkcd_vmdump_v2_v3.h lkcd_dump_v5.h \ LKCD_OBSOLETE_HFILES=lkcd_fix_mem.h LKCD_TRACE_HFILES=lkcd_x86_trace.h IBM_HFILES=ibm_common.h +SADUMP_HFILES=sadump.h UNWIND_HFILES=unwind.h unwind_i.h rse.h unwind_x86.h unwind_x86_64.h CFILES=main.c tools.c global_data.c memory.c filesys.c help.c task.c \ @@ -80,12 +81,12 @@ 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 + xen_hyper_dump_tables.c kvmdump.c qemu.c qemu-load.c sadump.c SOURCE_FILES=${CFILES} ${GENERIC_HFILES} ${MCORE_HFILES} \ ${REDHAT_CFILES} ${REDHAT_HFILES} ${UNWIND_HFILES} \ ${LKCD_DUMP_HFILES} ${LKCD_TRACE_HFILES} ${LKCD_OBSOLETE_HFILES}\ - ${IBM_HFILES} + ${IBM_HFILES} ${SADUMP_FILES} OBJECT_FILES=main.o tools.o global_data.o memory.o filesys.o help.o task.o \ build_data.o kernel.o test.o gdb_interface.o net.o dev.o \ @@ -97,7 +98,7 @@ 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 + xen_hyper_dump_tables.o kvmdump.o qemu.o qemu-load.o sadump.o MEMORY_DRIVER_FILES=memory_driver/Makefile memory_driver/crash.c memory_driver/README @@ -455,6 +456,9 @@ qemu.o: ${GENERIC_HFILES} ${REDHAT_HFILES} qemu.c qemu-load.o: ${GENERIC_HFILES} ${REDHAT_HFILES} qemu-load.c cc -c ${CRASH_CFLAGS} qemu-load.c ${WARNING_OPTIONS} ${WARNING_ERROR} +sadump.o: ${GENERIC_HFILES} ${SADUMP_HFILES} sadump.c + cc -c ${CRASH_CFLAGS} sadump.c ${WARNING_OPTIONS} ${WARNING_ERROR} + extensions.o: ${GENERIC_HFILES} extensions.c cc -c ${CRASH_CFLAGS} extensions.c ${WARNING_OPTIONS} ${WARNING_ERROR} -- 1.7.4.4
>From d650a854e6737064d753dd38c12e3d3d262dc29f Mon Sep 17 00:00:00 2001 From: HATAYAMA Daisuke <d.hatayama@xxxxxxxxxxxxxx> Date: Thu, 15 Sep 2011 11:10:24 +0900 Subject: [PATCH 08/12] sadump: Add interface for accessing registers sadump searchs three kinds of locations for register values according to the progress of kdump execution at crash: SMRAM CPU STATES, NT_PRSTATUS notes in crash_notes and frames on kernel stacks. Specifically, selecting a location is proceeded as follows: 1. If kdump was not triggered at crash or triggered but crash_notes was not initialized, use SMRAM CPU STATES that are register values collected by firmware through System Management Mode. Note that the register values could be the ones in user-mode execution mode. 2. If kdump was triggered and then crash_notes was initialized, first try to use registers contained on kernel stacks; this is done by existing crash's bt feature. If any of registers is not found, then try to retrieve registers saved in NT_PRSTATUS note entry at crash_notes. (So this column is exactly the same as the current kdump's behaviour.) SMRAM CPU STATE is contained in dump sub header, and each state is corresponding to one APIC ID, not Logical CPU ID. cpu_to_apicid() resolves each mapping of a given logical cpu id to some apic id by looking up bios_cpu_apicid or x86_bios_cpu_apicid. Each of crash_notes, bios_cpu_apicid and x86_bios_cpu_apicid is per cpu symbol or early per cpu symbol. To access these symbols, introduced are per_cpu_ptr(), legacy_per_cpu_ptr() and early_per_cpu_ptr(), clones of the macro in the kernel source code. --- defs.h | 3 + sadump.c | 378 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ x86.c | 6 + x86_64.c | 6 + 4 files changed, 393 insertions(+), 0 deletions(-) diff --git a/defs.h b/defs.h index a110881..9a6a879 100755 --- a/defs.h +++ b/defs.h @@ -1728,6 +1728,7 @@ struct size_table { /* stash of commonly-used sizes */ long softirq_action; long irq_data; long s390_stack_frame; + long percpu_data; }; struct array_table { @@ -4727,6 +4728,8 @@ int sadump_is_diskset(void); ulong get_sadump_panic_task(void); ulong get_sadump_switch_stack(ulong); FILE *set_sadump_fp(FILE *); +void get_sadump_regs(struct bt_info *bt, ulong *ipp, ulong *spp); +void sadump_display_regs(int, FILE *); int sadump_phys_base(ulong *); /* diff --git a/sadump.c b/sadump.c index 0996860..fc815de 100644 --- a/sadump.c +++ b/sadump.c @@ -40,6 +40,12 @@ static int lookup_diskset(ulong whole_offset, int *diskid, ulong *disk_offset); static struct tm *efi_time_t_to_tm(const efi_time_t *e, struct tm *t); static char * guid_to_str(efi_guid_t *guid, char *buf, size_t buflen); static int verify_magic_number(uint32_t magicnum[DUMP_PART_HEADER_MAGICNUM_SIZE]); +static ulong per_cpu_ptr(ulong ptr, int cpu); +static ulong early_per_cpu_ptr(char *symbol, struct syment *sym, int cpu); +static ulong legacy_per_cpu_ptr(ulong ptr, int cpu); +static int get_prstatus_from_crash_notes(int cpu, char *prstatus); +static int cpu_to_apicid(int cpu, int *apicid); +static int get_sadump_smram_cpu_state(int cpu, struct sadump_smram_cpu_state *smram); static int block_table_init(void); static ulong pfn_to_block(ulong pfn); @@ -830,6 +836,378 @@ verify_magic_number(uint32_t magicnum[DUMP_PART_HEADER_MAGICNUM_SIZE]) return TRUE; } +static ulong +per_cpu_ptr(ulong ptr, int cpu) +{ + if (cpu < 0 || cpu >= kt->cpus) + return 0UL; + + if (kt->cpus == 1) + return ptr; + + if (!(kt->flags & PER_CPU_OFF)) + return 0UL; + + if (machine_type("X86_64")) { + ulong __per_cpu_load; + + readmem(symbol_value("__per_cpu_load"), KVADDR, + &__per_cpu_load, sizeof(__per_cpu_load), + "__per_cpu_load", FAULT_ON_ERROR); + + if (kt->__per_cpu_offset[cpu] == __per_cpu_load) + return 0UL; + + } else if (machine_type("X86")) { + if (kt->__per_cpu_offset[cpu] == 0) + return 0UL; + + } + + return ptr + kt->__per_cpu_offset[cpu]; +} + +static ulong +early_per_cpu_ptr(char *symbol, struct syment *sym, int cpu) +{ + char sym_early_ptr[BUFSIZE], sym_early_map[BUFSIZE]; + ulong early_ptr; + + if (cpu < 0 || cpu >= kt->cpus) + return 0UL; + + if (!sym && !(sym = per_cpu_symbol_search(symbol))) + return 0UL; + + if (!(kt->flags & SMP)) + return per_cpu_ptr(sym->value, cpu); + + snprintf(sym_early_ptr, BUFSIZE, "%s_early_ptr", symbol); + snprintf(sym_early_map, BUFSIZE, "%s_early_map", symbol); + + if (!symbol_exists(sym_early_ptr) || !symbol_exists(sym_early_map)) + return 0UL; + + readmem(symbol_value(sym_early_ptr), KVADDR, &early_ptr, + sizeof(early_ptr), sym_early_ptr, FAULT_ON_ERROR); + + return early_ptr + ? symbol_value(sym_early_map)+cpu*sizeof(uint16_t) + : per_cpu_ptr(sym->value, cpu); +} + +static ulong +legacy_per_cpu_ptr(ulong ptr, int cpu) +{ + ulong addr; + + if (!(kt->flags & SMP)) + return ptr; + + if (cpu < 0 || cpu >= kt->cpus) + return 0UL; + + if (!readmem(~ptr + cpu * sizeof(ulong), KVADDR, &addr, sizeof(ulong), + "search percpu_data", FAULT_ON_ERROR)) + return 0UL; + + return addr; +} + +/** + * Retrieve eip and esp register values from crash_notes saved by + * kdump at crash. If register values has not been saved yet, set 0 to + * eip and esp instead. + */ +static int +get_prstatus_from_crash_notes(int cpu, char *prstatus) +{ + ulong crash_notes, crash_notes_ptr, percpu_addr; + char *prstatus_ptr, *note_buf, *zero_buf, *name; + uint32_t *buf; + + if (cpu < 0 || kt->cpus <= cpu) { + error(INFO, "sadump: given cpu is invalid: %d\n", cpu); + return FALSE; + } + + if (!symbol_exists("crash_notes")) { + error(INFO, "sadump: symbol crash_notes doesn't exist\n"); + return FALSE; + } + + crash_notes = symbol_value("crash_notes"); + + readmem(crash_notes, KVADDR, &crash_notes_ptr, sizeof(ulong), + "dereference crash_notes", FAULT_ON_ERROR); + + if (!crash_notes_ptr) { + if (CRASHDEBUG(1)) + error(INFO, + "sadump: buffer for crash_notes is NULL\n"); + return FALSE; + } + + percpu_addr = VALID_STRUCT(percpu_data) + ? legacy_per_cpu_ptr(crash_notes_ptr, cpu) + : per_cpu_ptr(crash_notes_ptr, cpu); + + zero_buf = GETBUF(SIZE(note_buf)); + BZERO(zero_buf, SIZE(note_buf)); + + note_buf = GETBUF(SIZE(note_buf)); + + readmem(percpu_addr, KVADDR, note_buf, SIZE(note_buf), + "read crash_notes", FAULT_ON_ERROR); + + if (memcmp(note_buf, zero_buf, SIZE(note_buf)) == 0) + return FALSE; + + if (BITS64()) { + Elf64_Nhdr *note64; + + note64 = (Elf64_Nhdr *)note_buf; + buf = (uint32_t *)note_buf; + name = (char *)(note64 + 1); + + if (note64->n_type != NT_PRSTATUS || + note64->n_namesz != strlen("CORE") + 1 || + strncmp(name, "CORE", note64->n_namesz) || + note64->n_descsz != SIZE(elf_prstatus)) + return FALSE; + + prstatus_ptr = (char *)(buf + (sizeof(*note64) + 3) / 4 + + (note64->n_namesz + 3) / 4); + + } else { + Elf32_Nhdr *note32; + + note32 = (Elf32_Nhdr *)note_buf; + buf = (uint32_t *)note_buf; + name = (char *)(note32 + 1); + + if ((note32->n_type != NT_PRSTATUS) && + (note32->n_namesz != strlen("CORE") + 1 || + strncmp(name, "CORE", note32->n_namesz) || + note32->n_descsz != SIZE(elf_prstatus))) + return FALSE; + + prstatus_ptr = (char *)(buf + (sizeof(*note32) + 3) / 4 + + (note32->n_namesz + 3) / 4); + + } + + memcpy(prstatus, prstatus_ptr, SIZE(elf_prstatus)); + + return TRUE; +} + +int +sadump_get_smram_cpu_state(int apicid, + struct sadump_smram_cpu_state *smram) +{ + ulong offset; + + if (!sd->sub_hdr_offset || !sd->smram_cpu_state_size || + apicid >= sd->dump_header->nr_cpus) + return FALSE; + + offset = sd->sub_hdr_offset + sizeof(uint32_t) + + sd->dump_header->nr_cpus * sizeof(struct sadump_apic_state); + + if (lseek(sd->dfd, offset + apicid * sd->smram_cpu_state_size, + SEEK_SET) == failed) + error(FATAL, + "sadump: cannot lseek smram cpu state in dump sub header\n"); + + if (read(sd->dfd, smram, sd->smram_cpu_state_size) != sd->smram_cpu_state_size) + error(FATAL, "sadump: cannot read smram cpu state in dump sub " + "header\n"); + + return TRUE; +} + +static int cpu_to_apicid(int cpu, int *apicid) +{ + struct syment *sym; + + if (symbol_exists("bios_cpu_apicid")) { + uint8_t apicid_u8; + + readmem(symbol_value("bios_cpu_apicid") + cpu*sizeof(uint8_t), + KVADDR, &apicid_u8, sizeof(uint8_t), "bios_cpu_apicid", + FAULT_ON_ERROR); + + *apicid = (int)apicid_u8; + + if (CRASHDEBUG(1)) + error(INFO, "sadump: apicid %u for cpu %d from " + "bios_cpu_apicid\n", apicid_u8, cpu); + + } else if ((sym = per_cpu_symbol_search("x86_bios_cpu_apicid"))) { + uint16_t apicid_u16; + + readmem(early_per_cpu_ptr("x86_bios_cpu_apicid", sym, cpu), + KVADDR, &apicid_u16, sizeof(uint16_t), + "x86_bios_cpu_apicid", FAULT_ON_ERROR); + + *apicid = (int)apicid_u16; + + if (CRASHDEBUG(1)) + error(INFO, "sadump: apicid %u for cpu %d from " + "x86_bios_cpu_apicid\n", apicid_u16, cpu); + + } else { + if (CRASHDEBUG(1)) + error(INFO, "sadump: no symbols for access to apicid\n"); + + return FALSE; + } + + return TRUE; +} + +static int +get_sadump_smram_cpu_state(int cpu, struct sadump_smram_cpu_state *smram) +{ + int apicid = 0; + + if (cpu < 0 || kt->cpus <= cpu) { + error(INFO, "sadump: given cpu is invalid: %d\n", cpu); + return FALSE; + } + + if (!cpu_to_apicid(cpu, &apicid)) + return FALSE; + + sadump_get_smram_cpu_state(apicid, smram); + + return TRUE; +} + +void get_sadump_regs(struct bt_info *bt, ulong *ipp, ulong *spp) +{ + ulong ip, sp; + struct sadump_smram_cpu_state smram; + char *prstatus; + int cpu = bt->tc->processor; + + if (!is_task_active(bt->task)) { + machdep->get_stack_frame(bt, ipp, spp); + return; + } + + bt->flags |= BT_DUMPFILE_SEARCH; + if (machine_type("X86_64")) + machdep->get_stack_frame(bt, ipp, spp); + else if (machine_type("X86")) + get_netdump_regs_x86(bt, ipp, spp); + if (bt->flags & BT_DUMPFILE_SEARCH) + return; + + prstatus = GETBUF(SIZE(elf_prstatus)); + + if (get_prstatus_from_crash_notes(cpu, prstatus)) { + ip = ULONG(prstatus + + OFFSET(elf_prstatus_pr_reg) + + OFFSET(user_regs_struct_rip)); + sp = ULONG(prstatus + + OFFSET(elf_prstatus_pr_reg) + + OFFSET(user_regs_struct_rsp)); + if (ip || sp) { + *ipp = ip; + *spp = sp; + return; + } + } + + get_sadump_smram_cpu_state(cpu, &smram); + ip = smram.Rip; + sp = ((uint64_t)smram.RspUpper << 32) + smram.RspLower; + + if (is_kernel_text(ip) && + (((sp >= GET_STACKBASE(bt->task)) && + (sp < GET_STACKTOP(bt->task))) || + in_alternate_stack(bt->tc->processor, sp))) { + *ipp = ip; + *spp = sp; + bt->flags |= BT_KERNEL_SPACE; + return; + } + + if (!is_kernel_text(ip) && + in_user_stack(bt->tc->task, sp)) + bt->flags |= BT_USER_SPACE; + +} + +void +sadump_display_regs(int cpu, FILE *ofp) +{ + struct sadump_smram_cpu_state smram; + + if (cpu < 0 || cpu >= kt->cpus) { + error(INFO, "sadump: given cpu is invalid: %d\n", cpu); + return; + } + + get_sadump_smram_cpu_state(cpu, &smram); + + if (machine_type("X86_64")) { + fprintf(ofp, + " RIP: %016llx RSP: %016llx RFLAGS: %08llx\n" + " RAX: %016llx RBX: %016llx RCX: %016llx\n" + " RDX: %016llx RSI: %016llx RDI: %016llx\n" + " RBP: %016llx R8: %016llx R9: %016llx\n" + " R10: %016llx R11: %016llx R12: %016llx\n" + " R13: %016llx R14: %016llx R15: %016llx\n" + " CS: %04x SS: %04x\n", + (ulonglong)(smram.Rip), + (ulonglong)(((uint64_t)smram.RspUpper<<32)+smram.RspLower), + (ulonglong)(smram.Rflags), + (ulonglong)(((uint64_t)smram.RaxUpper<<32)+smram.RaxLower), + (ulonglong)(((uint64_t)smram.RbxUpper<<32)+smram.RbxLower), + (ulonglong)(((uint64_t)smram.RcxUpper<<32)+smram.RcxLower), + (ulonglong)(((uint64_t)smram.RdxUpper<<32)+smram.RdxLower), + (ulonglong)(((uint64_t)smram.RsiUpper<<32)+smram.RsiLower), + (ulonglong)(((uint64_t)smram.RdiUpper<<32)+smram.RdiLower), + (ulonglong)(((uint64_t)smram.RbpUpper<<32)+smram.RbpLower), + (ulonglong)(((uint64_t)smram.R8Upper<<32)+smram.R8Lower), + (ulonglong)(((uint64_t)smram.R9Upper<<32)+smram.R9Lower), + (ulonglong)(((uint64_t)smram.R10Upper<<32)+smram.R10Lower), + (ulonglong)(((uint64_t)smram.R11Upper<<32)+smram.R11Lower), + (ulonglong)(((uint64_t)smram.R12Upper<<32)+smram.R12Lower), + (ulonglong)(((uint64_t)smram.R13Upper<<32)+smram.R13Lower), + (ulonglong)(((uint64_t)smram.R14Upper<<32)+smram.R14Lower), + (ulonglong)(((uint64_t)smram.R15Upper<<32)+smram.R15Lower), + smram.Cs, + smram.Ss); + } + + if (machine_type("X86")) { + fprintf(ofp, + " EAX: %08llx EBX: %08llx ECX: %08llx EDX: %08llx\n" + " DS: %04x ESI: %08llx ES: %04x EDI: %08llx\n" + " SS: %04x ESP: %08llx EBP: %08llx GS: %04x\n" + " CS: %04x EIP: %08llx EFLAGS: %08llx\n", + (ulonglong)smram.RaxLower, + (ulonglong)smram.RbxLower, + (ulonglong)smram.RcxLower, + (ulonglong)smram.RdxLower, + smram.Ds & 0xffff, + (ulonglong)smram.RsiLower, + smram.Es & 0xffff, + (ulonglong)smram.RdiLower, + smram.Ss, + (ulonglong)smram.RspLower, + (ulonglong)smram.RbpLower, + smram.Gs, + smram.Cs, + (ulonglong)smram.Rip, + (ulonglong)smram.Rflags); + } +} + /* * sadump does not save phys_base; it must resort to another way. */ diff --git a/x86.c b/x86.c index 9acab9f..cdd6468 100755 --- a/x86.c +++ b/x86.c @@ -1994,6 +1994,12 @@ x86_init(int when) else machdep->machspec->page_protnone = _PAGE_PSE; + STRUCT_SIZE_INIT(note_buf, "note_buf_t"); + STRUCT_SIZE_INIT(elf_prstatus, "elf_prstatus"); + MEMBER_OFFSET_INIT(elf_prstatus_pr_reg, "elf_prstatus", + "pr_reg"); + STRUCT_SIZE_INIT(percpu_data, "percpu_data"); + break; case POST_INIT: diff --git a/x86_64.c b/x86_64.c index c8bdd3f..5120cf1 100755 --- a/x86_64.c +++ b/x86_64.c @@ -525,6 +525,12 @@ x86_64_init(int when) else machdep->machspec->page_protnone = _PAGE_PSE; + STRUCT_SIZE_INIT(note_buf, "note_buf_t"); + STRUCT_SIZE_INIT(elf_prstatus, "elf_prstatus"); + MEMBER_OFFSET_INIT(elf_prstatus_pr_reg, "elf_prstatus", + "pr_reg"); + STRUCT_SIZE_INIT(percpu_data, "percpu_data"); + break; case POST_VM: -- 1.7.4.4
>From 22ee5fde19a9e6628d72a2896e94462d43845069 Mon Sep 17 00:00:00 2001 From: HATAYAMA Daisuke <d.hatayama@xxxxxxxxxxxxxx> Date: Thu, 15 Sep 2011 11:16:45 +0900 Subject: [PATCH 09/12] bt: Use back trace related features on sadump dumpfiles Use the features searching kernel stacks for registers in frames and displaying register values just as on kvmdump dumpfiles. --- kernel.c | 2 ++ netdump.c | 2 +- x86.c | 10 ++++++++-- x86_64.c | 16 ++++++++++++---- 4 files changed, 23 insertions(+), 7 deletions(-) diff --git a/kernel.c b/kernel.c index 13fa155..8ac793c 100755 --- a/kernel.c +++ b/kernel.c @@ -2284,6 +2284,8 @@ back_trace(struct bt_info *bt) get_lkcd_regs(bt, &eip, &esp); else if (XENDUMP_DUMPFILE()) get_xendump_regs(bt, &eip, &esp); + else if (SADUMP_DUMPFILE()) + get_sadump_regs(bt, &eip, &esp); else machdep->get_stack_frame(bt, &eip, &esp); diff --git a/netdump.c b/netdump.c index c20821e..4132758 100644 --- a/netdump.c +++ b/netdump.c @@ -2527,7 +2527,7 @@ next_sysrq: "starting backtrace locations of the active (non-crashing) " "xen tasks\n cannot be determined: try -t or -T options\n"); - if (KVMDUMP_DUMPFILE()) + if (KVMDUMP_DUMPFILE() || SADUMP_DUMPFILE()) bt->flags &= ~(ulonglong)BT_DUMPFILE_SEARCH; machdep->get_stack_frame(bt, eip, esp); diff --git a/x86.c b/x86.c index cdd6468..385cf32 100755 --- a/x86.c +++ b/x86.c @@ -682,10 +682,16 @@ db_stack_trace_cmd(addr, have_addr, count, modif, task, flags) kvmdump_display_regs(bt->tc->processor, fp); if (ELF_NOTES_VALID() && DISKDUMP_DUMPFILE()) diskdump_display_regs(bt->tc->processor, fp); + if (SADUMP_DUMPFILE()) + sadump_display_regs(bt->tc->processor, fp); fprintf(fp, " #0 [user space]\n"); return; - } else if ((bt->flags & BT_KERNEL_SPACE) && KVMDUMP_DUMPFILE()) - kvmdump_display_regs(bt->tc->processor, fp); + } else if ((bt->flags & BT_KERNEL_SPACE)) { + if (KVMDUMP_DUMPFILE()) + kvmdump_display_regs(bt->tc->processor, fp); + if (SADUMP_DUMPFILE()) + sadump_display_regs(bt->tc->processor, fp); + } addr = bt->stkptr; have_addr = TRUE; diff --git a/x86_64.c b/x86_64.c index 5120cf1..7296ec5 100755 --- a/x86_64.c +++ b/x86_64.c @@ -2872,7 +2872,12 @@ x86_64_low_budget_back_trace_cmd(struct bt_info *bt_in) diskdump_display_regs(bt->tc->processor, ofp); return; } - } else if ((bt->flags & BT_KERNEL_SPACE) && KVMDUMP_DUMPFILE()) { + if (SADUMP_DUMPFILE()) { + sadump_display_regs(bt->tc->processor, ofp); + return; + } + } else if ((bt->flags & BT_KERNEL_SPACE) && + (KVMDUMP_DUMPFILE() || SADUMP_DUMPFILE())) { fprintf(ofp, " [exception RIP: "); if ((sp = value_search(bt->instptr, &offset))) { fprintf(ofp, "%s", sp->name); @@ -2882,7 +2887,10 @@ x86_64_low_budget_back_trace_cmd(struct bt_info *bt_in) } else fprintf(ofp, "unknown or invalid address"); fprintf(ofp, "]\n"); - kvmdump_display_regs(bt->tc->processor, ofp); + if (KVMDUMP_DUMPFILE()) + kvmdump_display_regs(bt->tc->processor, ofp); + if (SADUMP_DUMPFILE()) + sadump_display_regs(bt->tc->processor, ofp); } else if (bt->flags & BT_START) { x86_64_print_stack_entry(bt, ofp, level, 0, bt->instptr); @@ -4380,7 +4388,7 @@ skip_stage: if (halt_rip && halt_rsp) { *rip = halt_rip; *rsp = halt_rsp; - if (KVMDUMP_DUMPFILE()) + if (KVMDUMP_DUMPFILE() || SADUMP_DUMPFILE()) bt_in->flags &= ~(ulonglong)BT_DUMPFILE_SEARCH; return; } @@ -4407,7 +4415,7 @@ skip_stage: machdep->get_stack_frame(bt, rip, rsp); - if (KVMDUMP_DUMPFILE()) + if (KVMDUMP_DUMPFILE() || SADUMP_DUMPFILE()) bt_in->flags &= ~(ulonglong)BT_DUMPFILE_SEARCH; } -- 1.7.4.4
>From 5a53df4e44f04377201602d2c9519ded2e18c146 Mon Sep 17 00:00:00 2001 From: HATAYAMA Daisuke <d.hatayama@xxxxxxxxxxxxxx> Date: Thu, 15 Sep 2011 11:24:10 +0900 Subject: [PATCH 10/12] sadump, kernel: sys command displays multiple dumpfiles on sadump diskset configuration Similar to kdump splitted dumpfiles. Sample output: crash> sys KERNEL: /media/pub2/debuginfo/vmlinux-2.6.32-131.0.15.el6.x86_64.gz DUMPFILE: /media/pub2/vmcores/sadump-diskset-backup CPUS: 12 DATE: Wed Aug 24 16:50:16 2011 UPTIME: 00:07:54 LOAD AVERAGE: 0.00, 0.12, 0.08 TASKS: 371 NODENAME: localhost.localdomain RELEASE: 2.6.32-131.0.15.el6.x86_64 VERSION: #1 SMP Tue May 10 15:42:40 EDT 2011 MACHINE: x86_64 (2000 Mhz) MEMORY: 15.7 GB PANIC: "" crash> sys KERNEL: /media/pub2/debuginfo/vmlinux-2.6.32-131.0.15.el6.x86_64.gz DUMPFILES: /media/pub2/vmcores/sadump-diskset-00 /media/pub2/vmcores/sadump-diskset-01 /media/pub2/vmcores/sadump-diskset-02 CPUS: 12 DATE: Wed Aug 24 16:50:16 2011 UPTIME: 00:07:54 LOAD AVERAGE: 0.00, 0.12, 0.08 TASKS: 371 NODENAME: localhost.localdomain RELEASE: 2.6.32-131.0.15.el6.x86_64 VERSION: #1 SMP Tue May 10 15:42:40 EDT 2011 MACHINE: x86_64 (2000 Mhz) MEMORY: 15.7 GB PANIC: "" --- defs.h | 1 + kernel.c | 8 ++++++-- sadump.c | 17 +++++++++++++++++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/defs.h b/defs.h index 9a6a879..a516ca4 100755 --- a/defs.h +++ b/defs.h @@ -4731,6 +4731,7 @@ FILE *set_sadump_fp(FILE *); void get_sadump_regs(struct bt_info *bt, ulong *ipp, ulong *spp); void sadump_display_regs(int, FILE *); int sadump_phys_base(ulong *); +void sadump_show_diskset(void); /* * qemu.c diff --git a/kernel.c b/kernel.c index 8ac793c..67a1982 100755 --- a/kernel.c +++ b/kernel.c @@ -950,7 +950,7 @@ non_matching_kernel(void) pc->namelist_debug_orig); } - if (dumpfile_is_split()) + if (dumpfile_is_split() || sadump_is_diskset()) fprintf(fp, " DUMPFILES: "); else fprintf(fp, " DUMPFILE: "); @@ -967,6 +967,8 @@ non_matching_kernel(void) else { if (dumpfile_is_split()) show_split_dumpfiles(); + else if (sadump_is_diskset()) + sadump_show_diskset(); else fprintf(fp, "%s", pc->dumpfile); } @@ -3962,7 +3964,7 @@ display_sys_stats(void) unlink(pc->namelist_debug); } - if (dumpfile_is_split()) + if (dumpfile_is_split() || sadump_is_diskset()) fprintf(fp, " DUMPFILES: "); else fprintf(fp, " DUMPFILE: "); @@ -3979,6 +3981,8 @@ display_sys_stats(void) else { if (dumpfile_is_split()) show_split_dumpfiles(); + else if (sadump_is_diskset()) + sadump_show_diskset(); else fprintf(fp, "%s", pc->dumpfile); } diff --git a/sadump.c b/sadump.c index fc815de..83674ee 100644 --- a/sadump.c +++ b/sadump.c @@ -1222,6 +1222,23 @@ int sadump_phys_base(ulong *phys_base) return FALSE; } +/* + * Used by "sys" command to show diskset disk names. + */ +void sadump_show_diskset(void) +{ + int i; + + for (i = 0; i < sd->sd_list_len; ++i) { + char *filename = sd->sd_list[i]->filename; + + fprintf(fp, "%s%s", i ? " " : "", + filename); + if ((i+1) < sd->sd_list_len) + fprintf(fp, "\n"); + } +} + static int block_table_init(void) { ulong section, max_section, pfn; -- 1.7.4.4
>From 230f03e0cbf721b6a9b5953602d25de3c2c944f9 Mon Sep 17 00:00:00 2001 From: HATAYAMA Daisuke <d.hatayama@xxxxxxxxxxxxxx> Date: Thu, 15 Sep 2011 11:28:29 +0900 Subject: [PATCH 11/12] sadump, memory: Add memory interface on sadump dumpfiles Now users can type help -D to dump sadump internal data for debugging purpose. sadump_memory_used() and sadump_free_memory() do nothing. --- defs.h | 3 + memory.c | 6 ++ sadump.c | 253 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 262 insertions(+), 0 deletions(-) diff --git a/defs.h b/defs.h index a516ca4..eee65c0 100755 --- a/defs.h +++ b/defs.h @@ -4727,6 +4727,9 @@ int sadump_init(char *, FILE *); int sadump_is_diskset(void); ulong get_sadump_panic_task(void); ulong get_sadump_switch_stack(ulong); +int sadump_memory_used(void); +int sadump_free_memory(void); +int sadump_memory_dump(FILE *); FILE *set_sadump_fp(FILE *); void get_sadump_regs(struct bt_info *bt, ulong *ipp, ulong *spp); void sadump_display_regs(int, FILE *); diff --git a/memory.c b/memory.c index 32079e1..9575d8e 100755 --- a/memory.c +++ b/memory.c @@ -14075,6 +14075,8 @@ dumpfile_memory(int cmd) retval = vas_memory_used(); else if (pc->flags & S390D) retval = s390_memory_used(); + else if (pc->flags & SADUMP) + retval = sadump_memory_used(); break; case DUMPFILE_FREE_MEM: @@ -14096,6 +14098,8 @@ dumpfile_memory(int cmd) retval = vas_free_memory(NULL); else if (pc->flags & S390D) retval = s390_free_memory(); + else if (pc->flags & SADUMP) + retval = sadump_free_memory(); break; case DUMPFILE_MEM_DUMP: @@ -14119,6 +14123,8 @@ dumpfile_memory(int cmd) retval = s390_memory_dump(fp); else if (pc->flags & PROC_KCORE) retval = kcore_memory_dump(fp); + else if (pc->flags & SADUMP) + retval = sadump_memory_dump(fp); break; case DUMPFILE_ENVIRONMENT: diff --git a/sadump.c b/sadump.c index 83674ee..49746b1 100644 --- a/sadump.c +++ b/sadump.c @@ -44,6 +44,7 @@ static ulong per_cpu_ptr(ulong ptr, int cpu); static ulong early_per_cpu_ptr(char *symbol, struct syment *sym, int cpu); static ulong legacy_per_cpu_ptr(ulong ptr, int cpu); static int get_prstatus_from_crash_notes(int cpu, char *prstatus); +static void display_smram_cpu_state(int apicid, struct sadump_smram_cpu_state *s); static int cpu_to_apicid(int cpu, int *apicid); static int get_sadump_smram_cpu_state(int cpu, struct sadump_smram_cpu_state *smram); static int block_table_init(void); @@ -836,6 +837,212 @@ verify_magic_number(uint32_t magicnum[DUMP_PART_HEADER_MAGICNUM_SIZE]) return TRUE; } +int sadump_memory_used(void) +{ + return 0; +} + +int sadump_free_memory(void) +{ + return 0; +} + +/* + * This function is dump-type independent, and could be used to dump + * the diskdump_data structure contents and perhaps the sadump header + * data. + */ +int sadump_memory_dump(FILE *fp) +{ + struct sadump_part_header *sph; + struct sadump_disk_set_header *sdh; + struct sadump_header *sh; + struct sadump_media_header *smh; + int i, others; + struct tm tm; + char guid[33]; + + fprintf(fp, "sadump_data: \n"); + fprintf(fp, " filename: %s\n", sd->filename); + fprintf(fp, " flags: %lx (", sd->flags); + others = 0; + if (sd->flags & SADUMP_LOCAL) + fprintf(fp, "%sSADUMP_LOCAL", others++ ? "|" : ""); + if (sd->flags & SADUMP_DISKSET) + fprintf(fp, "%sSADUMP_DISKSET", others++ ? "|" : ""); + if (sd->flags & SADUMP_MEDIA) + fprintf(fp, "%sSADUMP_MEDIA", others++ ? "|" : ""); + fprintf(fp, ") \n"); + fprintf(fp, " dfd: %d\n", sd->dfd); + fprintf(fp, " machine_type: %d ", sd->machine_type); + switch (sd->machine_type) + { + case EM_386: + fprintf(fp, "(EM_386)\n"); break; + case EM_X86_64: + fprintf(fp, "(EM_X86_64)\n"); break; + default: + fprintf(fp, "(unknown)\n"); break; + } + + fprintf(fp, "\n header: %lx\n", (ulong)sd->header); + sph = sd->header; + fprintf(fp, " signature1: %x\n", sph->signature1); + fprintf(fp, " signature2: %x\n", sph->signature2); + fprintf(fp, " enable: %u\n", sph->enable); + fprintf(fp, " reboot: %u\n", sph->reboot); + fprintf(fp, " compress: %u\n", sph->compress); + fprintf(fp, " recycle: %u\n", sph->recycle); + fprintf(fp, " label: (unused)\n"); + fprintf(fp, " sadump_id: %s\n", guid_to_str(&sph->sadump_id, guid, sizeof(guid))); + fprintf(fp, " disk_set_id: %s\n", guid_to_str(&sph->disk_set_id, guid, sizeof(guid))); + fprintf(fp, " vol_id: %s\n", guid_to_str(&sph->vol_id, guid, sizeof(guid))); + fprintf(fp, " time_stamp: %s\n", + strip_linefeeds(asctime(efi_time_t_to_tm(&sph->time_stamp, &tm)))); + fprintf(fp, " set_disk_set: %u\n", sph->set_disk_set); + fprintf(fp, " reserve: %u\n", sph->reserve); + fprintf(fp, " used_device: %llu\n", (ulonglong)sph->used_device); + fprintf(fp, " magicnum: %s\n", + verify_magic_number(sph->magicnum) + ? "(valid)" : "(invalid)"); + + fprintf(fp, "\n dump header: %lx\n", (ulong)sd->dump_header); + sh = sd->dump_header; + fprintf(fp, " signature: %s\n", sh->signature); + fprintf(fp, " header_version: %u\n", sh->header_version); + fprintf(fp, " reserve: %u\n", sh->reserve); + fprintf(fp, " timestamp: %s\n", + strip_linefeeds(asctime(efi_time_t_to_tm(&sh->timestamp, &tm)))); + fprintf(fp, " status: %u\n", sh->status); + fprintf(fp, " compress: %u\n", sh->compress); + fprintf(fp, " block_size: %u\n", sh->block_size); + fprintf(fp, " extra_hdr_size: %u\n", sh->extra_hdr_size); + fprintf(fp, " sub_hdr_size: %u\n", sh->sub_hdr_size); + fprintf(fp, " bitmap_blocks: %u\n", sh->bitmap_blocks); + fprintf(fp, "dumpable_bitmap_blocks: %u\n", sh->dumpable_bitmap_blocks); + fprintf(fp, " max_mapnr: %u\n", sh->max_mapnr); + fprintf(fp, " total_ram_blocks: %u\n", sh->total_ram_blocks); + fprintf(fp, " device_blocks: %u\n", sh->device_blocks); + fprintf(fp, " written_blocks: %u\n", sh->written_blocks); + fprintf(fp, " current_cpu: %u\n", sh->current_cpu); + fprintf(fp, " nr_cpus: %u\n", sh->nr_cpus); + + fprintf(fp, "\n dump sub heaer: "); + if (sh->sub_hdr_size > 0) { + ulong offset = sd->sub_hdr_offset; + struct sadump_apic_state as; + struct sadump_smram_cpu_state scs, zero; + uint32_t size; + uint aid; + + memset(&zero, 0, sizeof(zero)); + + if (!read_device(&size, sizeof(uint32_t), &offset)) { + error(INFO, "sadump: cannot read sub header size\n"); + return FALSE; + } + fprintf(fp, "\n size: %u\n", size); + for (aid = 0; aid < sh->nr_cpus; ++aid) { + if (!read_device(&as, sizeof(as), &offset)) { + error(INFO, "sadump: cannot read sub header " + "apic_id\n"); + return FALSE; + } + fprintf(fp, " " + "apic_id[%u]: ApicId %llu: Ldr: %llu\n", + aid, (ulonglong)as.ApicId, (ulonglong)as.Ldr); + } + for (aid = 0; aid < sh->nr_cpus; ++aid) { + if (!read_device(&scs, sizeof(scs), &offset)) { + error(INFO, "sadump: cannot read sub header " + "cpu_state\n"); + return FALSE; + } + if (memcmp(&scs, &zero, sizeof(scs)) != 0) { + fprintf(fp, "\n"); + display_smram_cpu_state(aid, &scs); + } + } + } else + fprintf(fp, "(n/a)\n"); + + fprintf(fp, "\n disk set header: %lx ", (ulong)sd->diskset_header); + if ((sdh = sd->diskset_header)) { + fprintf(fp, "\ndisk_set_header_size: %u\n", sdh->disk_set_header_size); + fprintf(fp, " disk_num: %u\n", sdh->disk_num); + fprintf(fp, " disk_set_size: %llu\n", (ulonglong)sdh->disk_set_size); + for (i = 0; i < sdh->disk_num - 1; ++i) { + struct sadump_volume_info *vol = &sdh->vol_info[i]; + + fprintf(fp, " vol_info[%d]: \n", i); + fprintf(fp, " id: %s\n", guid_to_str(&vol->id, guid, sizeof(guid))); + fprintf(fp, " vol_size: %llu\n", (ulonglong)vol->vol_size); + fprintf(fp, " status: %u\n", vol->status); + fprintf(fp, " cache_size: %u\n", vol->cache_size); + } + } else + fprintf(fp, "(n/a)\n"); + + fprintf(fp, "\n media header: %lx ", (ulong)sd->media_header); + if ((smh = sd->media_header)) { + fprintf(fp, "\n sadump_id: %s\n", guid_to_str(&smh->sadump_id, guid, sizeof(guid))); + fprintf(fp, " disk_set_id: %s\n", guid_to_str(&smh->disk_set_id, guid, sizeof(guid))); + fprintf(fp, " time_stamp: %s\n", + strip_linefeeds(asctime(efi_time_t_to_tm(&smh->time_stamp, &tm)))); + fprintf(fp, " sequential_num: %d\n", smh->sequential_num); + fprintf(fp, " term_cord: %d\n", smh->term_cord); + fprintf(fp, "disk_set_header_size: %d\n", smh->disk_set_header_size); + fprintf(fp, " disks_in_use: %d\n", smh->disks_in_use); + fprintf(fp, " reserve: (not displayed) \n"); + } else + fprintf(fp, "(n/a)\n"); + + fprintf(fp, "\n bitmap: %lx\n", (ulong)sd->bitmap); + fprintf(fp, " dumpable_bitmap: %lx\n", (ulong)sd->dumpable_bitmap); + fprintf(fp, " sub_hdr_offset: %lx\n", (ulong)sd->sub_hdr_offset); + fprintf(fp, "smram_cpu_state_size: %lx\n", (ulong)sd->smram_cpu_state_size); + fprintf(fp, " data_offset: %lx\n", sd->data_offset); + fprintf(fp, " block_size: %d\n", sd->block_size); + fprintf(fp, " block_shift: %d\n", sd->block_shift); + fprintf(fp, " page_buf: %lx\n", (ulong)sd->page_buf); + fprintf(fp, " block_table: %lx\n", (ulong)sd->block_table); + fprintf(fp, " sd_list_len: %d\n", sd->sd_list_len); + fprintf(fp, " sd_list: %lx\n", (ulong)sd->sd_list); + + for (i = 0; i < sd->sd_list_len; ++i) { + struct sadump_diskset_data *sdd = sd->sd_list[i]; + + fprintf(fp, "\n sd_list[%d]: \n", i); + fprintf(fp, " filename: %s\n", sdd->filename); + fprintf(fp, " dfd: %d\n", sdd->dfd); + + fprintf(fp, " header: %lx\n", (ulong)sdd->header); + sph = sdd->header; + fprintf(fp, " signature1: %x\n", sph->signature1); + fprintf(fp, " signature2: %x\n", sph->signature2); + fprintf(fp, " enable: %u\n", sph->enable); + fprintf(fp, " reboot: %u\n", sph->reboot); + fprintf(fp, " compress: %u\n", sph->compress); + fprintf(fp, " recycle: %u\n", sph->recycle); + fprintf(fp, " label: (unused)\n"); + fprintf(fp, " sadump_id: %s\n", guid_to_str(&sph->sadump_id, guid, sizeof(guid))); + fprintf(fp, " disk_set_id: %s\n", guid_to_str(&sph->disk_set_id, guid, sizeof(guid))); + fprintf(fp, " vol_id: %s\n", guid_to_str(&sph->vol_id, guid, sizeof(guid))); + fprintf(fp, " time_stamp: %s\n", + strip_linefeeds(asctime(efi_time_t_to_tm(&sph->time_stamp, &tm)))); + fprintf(fp, " set_disk_set: %u\n", sph->set_disk_set); + fprintf(fp, " reserve: %u\n", sph->reserve); + fprintf(fp, " used_device: %llu\n", (ulonglong)sph->used_device); + fprintf(fp, " magicnum: %s\n", + verify_magic_number(sph->magicnum) + ? "(valid)" : "(invalid)"); + + fprintf(fp, " data_offset: %lx\n", sdd->data_offset); + } + + return TRUE; +} + static ulong per_cpu_ptr(ulong ptr, int cpu) { @@ -1027,6 +1234,52 @@ sadump_get_smram_cpu_state(int apicid, return TRUE; } +static void +display_smram_cpu_state(int apicid, struct sadump_smram_cpu_state *s) +{ + fprintf(fp, + "APIC ID: %d\n" + " RIP: %016llx RSP: %08x%08x RBP: %08x%08x\n" + " RAX: %08x%08x RBX: %08x%08x RCX: %08x%08x\n" + " RDX: %08x%08x RSI: %08x%08x RDI: %08x%08x\n" + " R08: %08x%08x R09: %08x%08x R10: %08x%08x\n" + " R11: %08x%08x R12: %08x%08x R13: %08x%08x\n" + " R14: %08x%08x R15: %08x%08x\n" + " SMM REV: %08x SMM BASE %08x\n" + " CS : %08x DS: %08x SS: %08x ES: %08x FS: %08x\n" + " GS : %08x\n" + " CR0: %016llx CR3: %016llx CR4: %08x\n" + " GDT: %08x%08x LDT: %08x%08x IDT: %08x%08x\n" + " GDTlim: %08x LDTlim: %08x IDTlim: %08x\n" + " LDTR: %08x TR: %08x RFLAGS: %016llx\n" + " EPTP: %016llx EPTP_SETTING: %08x\n" + " DR6: %016llx DR7: %016llx\n" + " Ia32Efer: %016llx\n" + " IoMemAddr: %08x%08x IoEip: %016llx\n" + " IoMisc: %08x LdtInfo: %08x\n" + " IoInstructionRestart: %04x AutoHaltRestart: %04x\n", + apicid, + (ulonglong)s->Rip, s->RspUpper, s->RspLower, s->RbpUpper, s->RbpLower, + s->RaxUpper, s->RaxLower, s->RbxUpper, s->RbxLower, s->RcxUpper, s->RcxLower, + s->RdxUpper, s->RdxLower, s->RsiUpper, s->RsiLower, s->RdiUpper, s->RdiLower, + s->R8Upper, s->R8Lower, s->R9Upper, s->R9Lower, s->R10Upper, s->R10Lower, + s->R11Upper, s->R11Lower, s->R12Upper, s->R12Lower, s->R13Upper, s->R13Lower, + s->R14Upper, s->R14Lower, s->R15Upper, s->R15Lower, + s->SmmRevisionId, s->Smbase, + s->Cs, s->Ds, s->Ss, s->Es, s->Fs, s->Gs, + (ulonglong)s->Cr0, (ulonglong)s->Cr3, s->Cr4, + s->GdtUpper, s->GdtLower, s->LdtUpper, s->LdtLower, s->IdtUpper, s->IdtLower, + s->GdtLimit, s->LdtLimit, s->IdtLimit, + s->Ldtr, s->Tr, (ulonglong)s->Rflags, + (ulonglong)s->Eptp, s->EptpSetting, + (ulonglong)s->Dr6, (ulonglong)s->Dr7, + (ulonglong)s->Ia32Efer, + s->IoMemAddrUpper, s->IoMemAddrLower, (ulonglong)s->IoEip, + s->IoMisc, s->LdtInfo, + s->IoInstructionRestart, + s->AutoHaltRestart); +} + static int cpu_to_apicid(int cpu, int *apicid) { struct syment *sym; -- 1.7.4.4
>From b4542e39d2ed04b2824bcf8b08eb98e22fe5ee6f Mon Sep 17 00:00:00 2001 From: HATAYAMA Daisuke <d.hatayama@xxxxxxxxxxxxxx> Date: Thu, 15 Sep 2011 11:33:18 +0900 Subject: [PATCH 12/12] sadump: sadump_read() returns zero-filled buffer to the request for excluded pages if zero_excluded variable is on --- defs.h | 4 ++++ sadump.c | 19 +++++++++++++++++++ tools.c | 18 ++++++++++++------ 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/defs.h b/defs.h index eee65c0..c812927 100755 --- a/defs.h +++ b/defs.h @@ -254,6 +254,7 @@ struct number_option { #define SADUMP_LOCAL (0x1) #define SADUMP_DISKSET (0x2) #define SADUMP_MEDIA (0x4) +#define SADUMP_ZERO_EXCLUDED (0x8) #define SADUMP_VALID() (sd->flags & SADUMP_LOCAL) #define CRASHDEBUG(x) (pc->debug >= (x)) @@ -4735,6 +4736,9 @@ void get_sadump_regs(struct bt_info *bt, ulong *ipp, ulong *spp); void sadump_display_regs(int, FILE *); int sadump_phys_base(ulong *); void sadump_show_diskset(void); +int sadump_is_zero_excluded(void); +void sadump_set_zero_excluded(void); +void sadump_unset_zero_excluded(void); /* * qemu.c diff --git a/sadump.c b/sadump.c index 49746b1..b1b85dd 100644 --- a/sadump.c +++ b/sadump.c @@ -728,6 +728,8 @@ int read_sadump(int fd, void *bufptr, int cnt, ulong addr, physaddr_t paddr) if ((pfn >= sd->dump_header->max_mapnr) || !page_is_ram(pfn)) return SEEK_ERROR; if (!page_is_dumpable(pfn)) { + if (sd->flags & SADUMP_ZERO_EXCLUDED) + return PAGE_EXCLUDED; memset(bufptr, 0, cnt); return cnt; } @@ -872,6 +874,8 @@ int sadump_memory_dump(FILE *fp) fprintf(fp, "%sSADUMP_DISKSET", others++ ? "|" : ""); if (sd->flags & SADUMP_MEDIA) fprintf(fp, "%sSADUMP_MEDIA", others++ ? "|" : ""); + if (sd->flags & SADUMP_ZERO_EXCLUDED) + fprintf(fp, "%sSADUMP_ZERO_EXCLUDED", others++ ? "|" : ""); fprintf(fp, ") \n"); fprintf(fp, " dfd: %d\n", sd->dfd); fprintf(fp, " machine_type: %d ", sd->machine_type); @@ -1537,3 +1541,18 @@ static ulong pfn_to_block(ulong pfn) return block; } + +int sadump_is_zero_excluded(void) +{ + return (sd->flags & SADUMP_ZERO_EXCLUDED) ? TRUE : FALSE; +} + +void sadump_set_zero_excluded(void) +{ + sd->flags |= SADUMP_ZERO_EXCLUDED; +} + +void sadump_unset_zero_excluded(void) +{ + sd->flags &= ~SADUMP_ZERO_EXCLUDED; +} diff --git a/tools.c b/tools.c index ae38ce8..41e2323 100755 --- a/tools.c +++ b/tools.c @@ -2217,24 +2217,30 @@ cmd_set(void) optind++; if (from_rc_file) already_done(); - else if (STREQ(args[optind], "on")) + else if (STREQ(args[optind], "on")) { *diskdump_flags |= ZERO_EXCLUDED; - else if (STREQ(args[optind], "off")) + sadump_set_zero_excluded(); + } else if (STREQ(args[optind], "off")) { *diskdump_flags &= ~ZERO_EXCLUDED; - else if (IS_A_NUMBER(args[optind])) { + sadump_unset_zero_excluded(); + } else if (IS_A_NUMBER(args[optind])) { value = stol(args[optind], FAULT_ON_ERROR, NULL); - if (value) + if (value) { *diskdump_flags |= ZERO_EXCLUDED; - else + sadump_set_zero_excluded(); + } else { *diskdump_flags &= ~ZERO_EXCLUDED; + sadump_unset_zero_excluded(); + } } else goto invalid_set_command; } if (runtime) fprintf(fp, "zero_excluded: %s\n", - *diskdump_flags & ZERO_EXCLUDED ? + (*diskdump_flags & ZERO_EXCLUDED) || + sadump_is_zero_excluded() ? "on" : "off"); return; -- 1.7.4.4
-- Crash-utility mailing list Crash-utility@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/crash-utility