[PATCH 00/12] Add sadump format support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hello Dave,

I'm sorry for taking considerably long time. Now I post a patch set
implementing sadump support for crash utility.

Applying this patch set, crash utility will be able to recognize
sadump-related formats on 3 kinds configurations: single partition,
diskset and media backup file.

The crash version the patch set can be applied to is 5.1.7.

Please look at each patch description for detailed explanation.

BTW, do you want sadump dumpfiles? I geuss you need them for testing
samples.

 Makefile  |   10 +-
 defs.h    |   33 ++
 filesys.c |    2 +-
 kernel.c  |    6 +-
 main.c    |   49 ++-
 memory.c  |   23 +-
 netdump.c |    2 +-
 remote.c  |    2 +-
 sadump.c  | 1554 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 sadump.h  |  210 +++++++++
 tools.c   |   18 +-
 x86.c     |   16 +-
 x86_64.c  |   39 ++-
 13 files changed, 1929 insertions(+), 35 deletions(-)

Thanks.
HATAYAMA, Daisuke
>From 061eba79369a1265debf7ba761115ae4613aa580 Mon Sep 17 00:00:00 2001
From: HATAYAMA Daisuke <d.hatayama@xxxxxxxxxxxxxx>
Date: Tue, 13 Sep 2011 12:18:39 +0900
Subject: [PATCH 01/12] defs.h: Add basic sadump related macros and flags

Note that SADUMP flag is introduced to pc->flags2, not pc->flags since all the
64 bits of the latter is now fully used. Accordingly, MEMORY_SOURCES2 is newly
introduced.

---
 defs.h |   22 ++++++++++++++++++++++
 1 files changed, 22 insertions(+), 0 deletions(-)

diff --git a/defs.h b/defs.h
index 330c341..a1011c8 100755
--- a/defs.h
+++ b/defs.h
@@ -202,6 +202,7 @@ 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 MEMORY_SOURCES2 (SADUMP)
 #define DUMPFILE_TYPES      (DISKDUMP|NETDUMP|KDUMP|MCLXCD|LKCD|S390D|XENDUMP|KVMDUMP)
 #define REMOTE()            (pc->flags & REMOTE_DAEMON)
 #define REMOTE_ACTIVE()     (pc->flags & REM_LIVE_SYSTEM) 
@@ -218,6 +219,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->flags2 & SADUMP)
 
 #define NETDUMP_LOCAL    (0x1)  /* netdump_data flags */
 #define NETDUMP_REMOTE   (0x2)  
@@ -250,6 +252,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; }
@@ -431,6 +438,7 @@ struct program_context {
 #define FLAT          (0x1ULL)
 #define ELF_NOTES     (0x2ULL)
 #define GET_OSRELEASE (0x4ULL)
+#define SADUMP        (0x8ULL)
 #define FLAT_FORMAT() (pc->flags2 & FLAT)
 #define ELF_NOTES_VALID() (pc->flags2 & ELF_NOTES)
 	char *cleanup;
@@ -4709,6 +4717,20 @@ struct kvm_register_set {
 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 *);
+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(unsigned long *);
+
+/*
  * qemu.c
  */
 int qemu_init(char *);
-- 
1.7.4.4

>From fc98d656035df6e82bb90153913a9d6e9eb0fa7d Mon Sep 17 00:00:00 2001
From: HATAYAMA Daisuke <d.hatayama@xxxxxxxxxxxxxx>
Date: Tue, 13 Sep 2011 12:20:17 +0900
Subject: [PATCH 02/12] sadump: 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.  

---
 sadump.c |  891 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 sadump.h |  210 +++++++++++++++
 2 files changed, 1101 insertions(+), 0 deletions(-)
 create mode 100644 sadump.c
 create mode 100644 sadump.h

diff --git a/sadump.c b/sadump.c
new file mode 100644
index 0000000..176467a
--- /dev/null
+++ b/sadump.c
@@ -0,0 +1,891 @@
+/*
+ * 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);
+}
+
+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.
+ */
+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;
+}
+
+/*
+ * sadump does not save phys_base; it must resort to another way.
+ */
+int sadump_phys_base(unsigned long *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;
+	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 8dc610dabbabccb5c74f3e94fb51422d44681b01 Mon Sep 17 00:00:00 2001
From: HATAYAMA Daisuke <d.hatayama@xxxxxxxxxxxxxx>
Date: Tue, 13 Sep 2011 12:22:30 +0900
Subject: [PATCH 03/12] x86_64: Set up phys_base on sadump dumpfiles

x86_64_virt_phys_base() needs to be used since no phys_base is saved.

---
 x86_64.c |   17 +++++++++++++++++
 1 files changed, 17 insertions(+), 0 deletions(-)

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 725569d3a003ba5585c832cc3fe216a9477fe7ef Mon Sep 17 00:00:00 2001
From: HATAYAMA Daisuke <d.hatayama@xxxxxxxxxxxxxx>
Date: Tue, 13 Sep 2011 12:23:06 +0900
Subject: [PATCH 04/12] memory: Get page size on sadump dumpfiles

---
 memory.c |   17 ++++++++++++++---
 1 files changed, 14 insertions(+), 3 deletions(-)

diff --git a/memory.c b/memory.c
index 4d44706..8e3d695 100755
--- a/memory.c
+++ b/memory.c
@@ -13856,9 +13856,20 @@ memory_page_size(void)
 		break;
 
 	default:
-		psz = 0;
-		error(FATAL, "memory_page_size: invalid pc->flags: %lx\n", 
-			pc->flags & MEMORY_SOURCES); 
+		switch (pc->flags2 & MEMORY_SOURCES2)
+		{
+		case SADUMP:
+			psz = sadump_page_size();
+			break;
+
+		default:
+			psz = 0;
+			error(FATAL, "memory_page_size: "
+			      "invalid pc->flags: %lx and pc->flags2: %lx\n",
+			      pc->flags & MEMORY_SOURCES,
+			      pc->flags2 & MEMORY_SOURCES2);
+		}
+
 	}
 
 	return psz;
-- 
1.7.4.4

>From 10f6191e34ed60826461e34c633e0cf96fbc18e7 Mon Sep 17 00:00:00 2001
From: HATAYAMA Daisuke <d.hatayama@xxxxxxxxxxxxxx>
Date: Tue, 13 Sep 2011 12:24:16 +0900
Subject: [PATCH 05/12] filesys: Permit the dumpfile if it's in sadump format

---
 filesys.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/filesys.c b/filesys.c
index c19c154..23496a9 100755
--- a/filesys.c
+++ b/filesys.c
@@ -200,7 +200,7 @@ memory_source_init(void)
 	        	error(FATAL, "%s: %s\n", pc->dumpfile, 
 				strerror(ENOENT));
 	
-		if (!(pc->flags & DUMPFILE_TYPES)) 
+		if (!(pc->flags & DUMPFILE_TYPES) && !(pc->flags2 & SADUMP))
 			error(FATAL, "%s: dump format not supported!\n",
 				pc->dumpfile);
 	
-- 
1.7.4.4

>From 17493b215e3e2ce7b329f04f3e01341a1112c44d Mon Sep 17 00:00:00 2001
From: HATAYAMA Daisuke <d.hatayama@xxxxxxxxxxxxxx>
Date: Tue, 13 Sep 2011 12:45:39 +0900
Subject: [PATCH 06/12] main, remote: Add sadump dumpfiles check

---
 main.c   |   49 ++++++++++++++++++++++++++++++++++++-------------
 remote.c |    2 +-
 2 files changed, 37 insertions(+), 14 deletions(-)

diff --git a/main.c b/main.c
index b557010..a4119c3 100755
--- a/main.c
+++ b/main.c
@@ -367,7 +367,7 @@ main(int argc, char **argv)
 	while (argv[optind]) {
 
 		if (is_remote_daemon(argv[optind])) {
-                	if (pc->flags & DUMPFILE_TYPES) {
+                	if (pc->flags & DUMPFILE_TYPES || pc->flags2 & SADUMP) {
 				error(INFO, 
 				      "too many dumpfile/memory arguments\n");
 				program_usage(SHORT_FORM);
@@ -424,7 +424,8 @@ main(int argc, char **argv)
 				pc->flags2 |= FLAT;
 
 			if (STREQ(argv[optind], "/dev/mem")) {
-                        	if (pc->flags & MEMORY_SOURCES) {
+                        	if ((pc->flags & MEMORY_SOURCES) ||
+				    (pc->flags2 & MEMORY_SOURCES2)) {
                                 	error(INFO, 
                                             "too many dumpfile arguments\n");
                                 	program_usage(SHORT_FORM);
@@ -436,7 +437,8 @@ main(int argc, char **argv)
 				pc->live_memsrc = argv[optind];
 
 			} else if (is_proc_kcore(argv[optind], KCORE_LOCAL)) {
-				if (pc->flags & MEMORY_SOURCES) {
+				if ((pc->flags & MEMORY_SOURCES) ||
+				    (pc->flags2 & MEMORY_SOURCES2)) {
 					error(INFO, 
 					    "too many dumpfile arguments\n");
 					program_usage(SHORT_FORM);
@@ -448,7 +450,8 @@ main(int argc, char **argv)
 				pc->live_memsrc = argv[optind];
 
 			} else if (is_netdump(argv[optind], NETDUMP_LOCAL)) {
-                                if (pc->flags & MEMORY_SOURCES) {
+				if ((pc->flags & MEMORY_SOURCES) ||
+				    (pc->flags2 & MEMORY_SOURCES2)) {
                                         error(INFO,
                                             "too many dumpfile arguments\n");
                                         program_usage(SHORT_FORM);
@@ -465,7 +468,8 @@ main(int argc, char **argv)
 				}
 
                         } else if (is_kdump(argv[optind], KDUMP_LOCAL)) {
-                                if (pc->flags & MEMORY_SOURCES) {
+				if ((pc->flags & MEMORY_SOURCES) ||
+				    (pc->flags2 & MEMORY_SOURCES2)) {
                                         error(INFO,
                                             "too many dumpfile arguments\n");
                                         program_usage(SHORT_FORM);
@@ -476,7 +480,8 @@ main(int argc, char **argv)
                                 pc->writemem = write_kdump;
 
                         } else if (is_kvmdump(argv[optind])) {
-                                if (pc->flags & MEMORY_SOURCES) {
+				if ((pc->flags & MEMORY_SOURCES) ||
+				    (pc->flags2 & MEMORY_SOURCES2)) {
                                         error(INFO,
                                             "too many dumpfile arguments\n");
                                         program_usage(SHORT_FORM);
@@ -495,7 +500,8 @@ main(int argc, char **argv)
 				pc->kvmdump_mapfile = argv[optind];
                                 
                         } else if (is_xendump(argv[optind])) {
-                                if (pc->flags & MEMORY_SOURCES) {
+				if ((pc->flags & MEMORY_SOURCES) ||
+				    (pc->flags2 & MEMORY_SOURCES2)) {
                                         error(INFO,
                                             "too many dumpfile arguments\n");
                                         program_usage(SHORT_FORM);
@@ -510,8 +516,9 @@ main(int argc, char **argv)
                                 pc->flags |= (SYSMAP|SYSMAP_ARG);
 
 			} else if (is_diskdump(argv[optind])) {
-                                if ((pc->flags & MEMORY_SOURCES) &&
-                                    (!dumpfile_is_split())) {
+				if (((pc->flags & MEMORY_SOURCES) ||
+				     (pc->flags2 & MEMORY_SOURCES2)) &&
+				    !dumpfile_is_split()) {
                                         error(INFO,
                                             "too many dumpfile arguments\n");
                                         program_usage(SHORT_FORM);
@@ -522,7 +529,8 @@ main(int argc, char **argv)
                                 pc->writemem = write_diskdump;
 
 			} else if (is_lkcd_compressed_dump(argv[optind])) {
-				if (pc->flags & MEMORY_SOURCES) {
+				if ((pc->flags & MEMORY_SOURCES) ||
+				    (pc->flags2 & MEMORY_SOURCES2)) {
                                         error(INFO,
                                             "too many dumpfile arguments\n");
                                         program_usage(SHORT_FORM);
@@ -533,7 +541,8 @@ main(int argc, char **argv)
 				pc->writemem = write_lkcd_dumpfile;
 
 			} else if (is_mclx_compressed_dump(argv[optind])) {
-				if (pc->flags & MEMORY_SOURCES) {
+				if ((pc->flags & MEMORY_SOURCES) ||
+				    (pc->flags2 & MEMORY_SOURCES2)) {
 					error(INFO,
                                             "too many dumpfile arguments\n");
                                         program_usage(SHORT_FORM);
@@ -544,7 +553,8 @@ main(int argc, char **argv)
 				pc->writemem = write_mclx_dumpfile;
 
                         } else if (is_s390_dump(argv[optind])) {
-                                if (pc->flags & MEMORY_SOURCES) {
+				if ((pc->flags & MEMORY_SOURCES) ||
+				    (pc->flags2 & MEMORY_SOURCES2)) {
                                         error(INFO,
                                             "too many dumpfile arguments\n");
                                         program_usage(SHORT_FORM);
@@ -554,7 +564,20 @@ main(int argc, char **argv)
                                 pc->readmem = read_s390_dumpfile;
                                 pc->writemem = write_s390_dumpfile;
 
-			} else { 
+			} else if (is_sadump(argv[optind])) {
+				if (((pc->flags & MEMORY_SOURCES) ||
+				     (pc->flags2 & MEMORY_SOURCES2)) &&
+				    !sadump_is_diskset()) {
+                                        error(INFO,
+                                            "too many dumpfile arguments\n");
+                                        program_usage(SHORT_FORM);
+				}
+				pc->flags2 |= SADUMP;
+				pc->dumpfile = argv[optind];
+				pc->readmem = read_sadump;
+				pc->writemem = write_sadump;
+
+			} else {
 				error(INFO, 
 				    "%s: not a supported file format\n",
 					argv[optind]);
diff --git a/remote.c b/remote.c
index a06c14b..b10598c 100755
--- a/remote.c
+++ b/remote.c
@@ -2226,7 +2226,7 @@ remote_fd_init(void)
 	 *  Account for the remote possibility of a local dumpfile 
 	 *  being entered on the command line.
 	 */
-        if (pc->flags & MEMORY_SOURCES) {
+        if ((pc->flags & MEMORY_SOURCES) || (pc->flags2 & MEMORY_SOURCES2)) {
 		if (pc->server_memsrc) {
                 	error(INFO, "too many dumpfile/memory arguments\n");
 			program_usage(SHORT_FORM);
-- 
1.7.4.4

>From b106e946bba31e4395431e757ca2d7bcebd19b05 Mon Sep 17 00:00:00 2001
From: HATAYAMA Daisuke <d.hatayama@xxxxxxxxxxxxxx>
Date: Tue, 13 Sep 2011 12:46:22 +0900
Subject: [PATCH 07/12] Makefile: Add sadump related descriptions

Now crsah can be built, and basic functionality to access memory data
in sadump dumpfiles is available.

Other functionalities, such as accessing registers and hunds of
auxiliary features like sys and help -D, have yet to be available.

---
 Makefile |   10 +++++++---
 1 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/Makefile b/Makefile
index fe6c852..87fb103 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_HFILES}
 
 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 3c8190eb5f087a8fe0806c863675b925c6a19d7b Mon Sep 17 00:00:00 2001
From: HATAYAMA Daisuke <d.hatayama@xxxxxxxxxxxxxx>
Date: Tue, 13 Sep 2011 14:39:22 +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 |  374 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 x86.c    |    6 +
 x86_64.c |    6 +
 4 files changed, 389 insertions(+), 0 deletions(-)

diff --git a/defs.h b/defs.h
index a1011c8..783096e 100755
--- a/defs.h
+++ b/defs.h
@@ -1729,6 +1729,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 {
@@ -4728,6 +4729,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(unsigned long *);
 
 /*
diff --git a/sadump.c b/sadump.c
index 176467a..4109f8f 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,374 @@ 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 = symbol_value("__per_cpu_load");
+
+		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 c098e2d8d92c8448dcf8c924f6ca98d87c3ddc38 Mon Sep 17 00:00:00 2001
From: HATAYAMA Daisuke <d.hatayama@xxxxxxxxxxxxxx>
Date: Tue, 13 Sep 2011 14:57:33 +0900
Subject: [PATCH 09/12] bt: Add sadump related processing

Register values in SMRAM CPU STATE could be the ones in user-execution mode, so
sadump needs the same processing as kvmdump does.

---
 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 7b49605bc1c26810589150fabf53a72b3df8858c Mon Sep 17 00:00:00 2001
From: HATAYAMA Daisuke <d.hatayama@xxxxxxxxxxxxxx>
Date: Tue, 13 Sep 2011 15:18:14 +0900
Subject: [PATCH 10/12] sadump, kernel: sys displays multiple dumpfiles on 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 |    4 +++-
 sadump.c |   17 +++++++++++++++++
 3 files changed, 21 insertions(+), 1 deletions(-)

diff --git a/defs.h b/defs.h
index 783096e..cb47072 100755
--- a/defs.h
+++ b/defs.h
@@ -4732,6 +4732,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(unsigned long *);
+void sadump_show_diskset(void);
 
 /*
  * qemu.c
diff --git a/kernel.c b/kernel.c
index 8ac793c..a7242f1 100755
--- a/kernel.c
+++ b/kernel.c
@@ -3962,7 +3962,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 +3979,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 4109f8f..a892c72 100644
--- a/sadump.c
+++ b/sadump.c
@@ -1218,6 +1218,23 @@ int sadump_phys_base(unsigned long *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 40599aa830e6fa709ce7b2ceb87bbcabe93f857b Mon Sep 17 00:00:00 2001
From: HATAYAMA Daisuke <d.hatayama@xxxxxxxxxxxxxx>
Date: Tue, 13 Sep 2011 15:28:03 +0900
Subject: [PATCH 11/12] memory: Add sadump related memory interface

sadump_memory_used() and sadump_free_memory() do nothing.

sadump_memory_dump() dumps sadump_data, users can call this function through
help -D command.
---
 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 cb47072..7ad46c9 100755
--- a/defs.h
+++ b/defs.h
@@ -4728,6 +4728,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 8e3d695..fa1746f 100755
--- a/memory.c
+++ b/memory.c
@@ -14082,6 +14082,8 @@ dumpfile_memory(int cmd)
                         retval = vas_memory_used();
 		else if (pc->flags & S390D)
 			retval = s390_memory_used();
+		else if (pc->flags2 & SADUMP)
+			retval = sadump_memory_used();
 		break;
 
 	case DUMPFILE_FREE_MEM:
@@ -14103,6 +14105,8 @@ dumpfile_memory(int cmd)
                         retval = vas_free_memory(NULL);
                 else if (pc->flags & S390D)
                         retval = s390_free_memory();
+		else if (pc->flags2 & SADUMP)
+			retval = sadump_free_memory();
 		break;
 
 	case DUMPFILE_MEM_DUMP:
@@ -14126,6 +14130,8 @@ dumpfile_memory(int cmd)
                         retval = s390_memory_dump(fp);
                 else if (pc->flags & PROC_KCORE)
                         retval = kcore_memory_dump(fp);
+		else if (pc->flags2 & SADUMP)
+			retval = sadump_memory_dump(fp);
 		break;
 	
 	case DUMPFILE_ENVIRONMENT:
diff --git a/sadump.c b/sadump.c
index a892c72..9736d9e 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)
 {
@@ -1023,6 +1230,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 e53a87e4f17271f2f1984c7002ed988a30c714bb Mon Sep 17 00:00:00 2001
From: HATAYAMA Daisuke <d.hatayama@xxxxxxxxxxxxxx>
Date: Tue, 13 Sep 2011 15:47:43 +0900
Subject: [PATCH 12/12] sadump: fill buffer with zero 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 7ad46c9..dcc8fcf 100755
--- a/defs.h
+++ b/defs.h
@@ -255,6 +255,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))
@@ -4736,6 +4737,9 @@ void get_sadump_regs(struct bt_info *bt, ulong *ipp, ulong *spp);
 void sadump_display_regs(int, FILE *);
 int sadump_phys_base(unsigned long *);
 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 9736d9e..14c6eae 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);
@@ -1533,3 +1537,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

[Index of Archives]     [Fedora Development]     [Fedora Desktop]     [Fedora SELinux]     [Yosemite News]     [KDE Users]     [Fedora Tools]

 

Powered by Linux