[PATCH 10/12] Generate and save VMCOREINFO and ELF note information

HATAYAMA Daisuke d.hatayama at jp.fujitsu.com
Tue Oct 11 11:17:13 EDT 2011


Retrieve VMCOREINFO from VMLINUX and ELF note information from
VMCORE(s) and save them in generated DUMPFILE.

ELF note information is NT_PRSTATUS only. If crash_notes is NULL,
indicating kdump has not saved register values, save SMRAM CPU STATE
values. If crash_notes is not NULL, indicating kdump has saved
register values at crash, then save the register values in
crash_notes.

Signed-off-by: HATAYAMA Daisuke <d.hatayama at jp.fujitsu.com>
---
 elf_info.c     |    2 +-
 makedumpfile.c |  103 +++++---
 makedumpfile.h |    2 +
 sadump_info.c  |  822 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 sadump_info.h  |   26 ++
 5 files changed, 912 insertions(+), 43 deletions(-)

diff --git a/elf_info.c b/elf_info.c
index 114dd05..48f8510 100644
--- a/elf_info.c
+++ b/elf_info.c
@@ -760,7 +760,7 @@ get_nr_cpus(void)
 int
 has_pt_note(void)
 {
-	if (offset_pt_note_memory && size_pt_note_memory)
+	if (offset_pt_note_memory || size_pt_note_memory)
 		return TRUE;
 	return FALSE;
 }
diff --git a/makedumpfile.c b/makedumpfile.c
index 4e3beef..a509f2c 100644
--- a/makedumpfile.c
+++ b/makedumpfile.c
@@ -1221,40 +1221,9 @@ get_mem_type(void)
 	return ret;
 }
 
-int
-generate_vmcoreinfo(void)
+void
+write_vmcoreinfo_data(void)
 {
-	if (!set_page_size(sysconf(_SC_PAGE_SIZE)))
-		return FALSE;
-
-	set_dwarf_debuginfo("vmlinux", NULL,
-			    info->name_vmlinux, info->fd_vmlinux);
-
-	if (!get_symbol_info())
-		return FALSE;
-
-	if (!get_structure_info())
-		return FALSE;
-
-	if (!get_srcfile_info())
-		return FALSE;
-
-	if ((SYMBOL(system_utsname) == NOT_FOUND_SYMBOL)
-	    && (SYMBOL(init_uts_ns) == NOT_FOUND_SYMBOL)) {
-		ERRMSG("Can't get the symbol of system_utsname.\n");
-		return FALSE;
-	}
-	if (!get_str_osrelease_from_vmlinux())
-		return FALSE;
-
-	if (!(info->kernel_version = get_kernel_version(info->release)))
-		return FALSE;
-
-	if (get_mem_type() == NOT_FOUND_MEMTYPE) {
-		ERRMSG("Can't find the memory type.\n");
-		return FALSE;
-	}
-
 	/*
 	 * write 1st kernel's OSRELEASE
 	 */
@@ -1357,6 +1326,43 @@ generate_vmcoreinfo(void)
 	 * write the source file of 1st kernel
 	 */
 	WRITE_SRCFILE("pud_t", pud_t);
+}
+
+int
+generate_vmcoreinfo(void)
+{
+	if (!set_page_size(sysconf(_SC_PAGE_SIZE)))
+		return FALSE;
+
+	set_dwarf_debuginfo("vmlinux", NULL,
+			    info->name_vmlinux, info->fd_vmlinux);
+
+	if (!get_symbol_info())
+		return FALSE;
+
+	if (!get_structure_info())
+		return FALSE;
+
+	if (!get_srcfile_info())
+		return FALSE;
+
+	if ((SYMBOL(system_utsname) == NOT_FOUND_SYMBOL)
+	    && (SYMBOL(init_uts_ns) == NOT_FOUND_SYMBOL)) {
+		ERRMSG("Can't get the symbol of system_utsname.\n");
+		return FALSE;
+	}
+	if (!get_str_osrelease_from_vmlinux())
+		return FALSE;
+
+	if (!(info->kernel_version = get_kernel_version(info->release)))
+		return FALSE;
+
+	if (get_mem_type() == NOT_FOUND_MEMTYPE) {
+		ERRMSG("Can't find the memory type.\n");
+		return FALSE;
+	}
+
+	write_vmcoreinfo_data();
 
 	return TRUE;
 }
@@ -2605,6 +2611,12 @@ out:
 
 		if (!get_mem_map())
 			return FALSE;
+
+		if (!info->flag_dmesg && info->flag_sadump &&
+		    sadump_check_debug_info() &&
+		    !sadump_generate_elf_note_from_dumpfile())
+			return FALSE;
+
 	} else {
 		if (!get_mem_map_without_mm())
 			return FALSE;
@@ -4236,16 +4248,23 @@ write_kdump_header(void)
 			    strerror(errno));
 			return FALSE;
 		}
-		if (lseek(info->fd_memory, offset_note, SEEK_SET) < 0) {
-			ERRMSG("Can't seek the dump memory(%s). %s\n",
-			    info->name_memory, strerror(errno));
-			goto out;
-		}
-		if (read(info->fd_memory, buf, size_note) != size_note) {
-			ERRMSG("Can't read the dump memory(%s). %s\n",
-			    info->name_memory, strerror(errno));
-			goto out;
+
+		if (!info->flag_sadump) {
+			if (lseek(info->fd_memory, offset_note, SEEK_SET) < 0) {
+				ERRMSG("Can't seek the dump memory(%s). %s\n",
+				       info->name_memory, strerror(errno));
+				goto out;
+			}
+			if (read(info->fd_memory, buf, size_note) != size_note) {
+				ERRMSG("Can't read the dump memory(%s). %s\n",
+				       info->name_memory, strerror(errno));
+				goto out;
+			}
+		} else {
+			if (!sadump_read_elf_note(buf, size_note))
+				goto out;
 		}
+
 		if (!write_buffer(info->fd_dumpfile, kh.offset_note, buf,
 		    kh.size_note, info->name_dumpfile))
 			goto out;
diff --git a/makedumpfile.h b/makedumpfile.h
index 433bc49..67a6b4f 100644
--- a/makedumpfile.h
+++ b/makedumpfile.h
@@ -1328,6 +1328,8 @@ is_dumpable(struct dump_bitmap *bitmap, unsigned long long pfn)
 	return is_on(bitmap->buf, pfn%PFN_BUFBITMAP);
 }
 
+void write_vmcoreinfo_data(void);
+
 #ifdef __x86__
 
 struct user_regs_struct {
diff --git a/sadump_info.c b/sadump_info.c
index fa05443..2e15871 100644
--- a/sadump_info.c
+++ b/sadump_info.c
@@ -19,15 +19,33 @@
 #if defined(__x86__) || defined(__x86_64__)
 
 #include "makedumpfile.h"
+#include "elf_info.h"
 #include "print_info.h"
+#include "elf_info.h"
 #include "sadump_mod.h"
 
+#ifdef __x86__
+
+#define KEXEC_NOTE_HEAD_BYTES roundup(sizeof(Elf32_Nhdr), 4)
+
+#endif
+
 #ifdef __x86_64__
 
 #define MEGABYTES(x)	((x) * (1048576))
 
+#define KEXEC_NOTE_HEAD_BYTES roundup(sizeof(Elf64_Nhdr), 4)
+
 #endif
 
+#define KEXEC_CORE_NOTE_NAME "CORE"
+#define KEXEC_CORE_NOTE_NAME_BYTES roundup(sizeof(KEXEC_CORE_NOTE_NAME), 4)
+#define KEXEC_CORE_NOTE_DESC_BYTES roundup(sizeof(struct elf_prstatus), 4)
+
+#define KEXEC_NOTE_BYTES ((KEXEC_NOTE_HEAD_BYTES * 2) +                \
+			  KEXEC_CORE_NOTE_NAME_BYTES +		       \
+			  KEXEC_CORE_NOTE_DESC_BYTES )
+
 struct sadump_diskset_info {
 	char *name_memory;
 	int fd_memory;
@@ -46,6 +64,9 @@ struct sadump_info {
 	uint32_t smram_cpu_state_size;
 	unsigned long data_offset;
 	unsigned long *block_table;
+	unsigned long *__per_cpu_offset;
+	unsigned long __per_cpu_load;
+	FILE *file_elf_note;
 };
 
 static char *guid_to_str(efi_guid_t *guid, char *buf, size_t buflen);
@@ -59,6 +80,28 @@ static int read_sadump_header_diskset(int diskid, struct sadump_diskset_info *sd
 static unsigned long pfn_to_block(unsigned long pfn);
 static int lookup_diskset(unsigned long whole_offset, int *diskid,
 			  unsigned long *disk_offset);
+static int per_cpu_init(void);
+static int get_data_from_elf_note_desc(const char *note_buf, uint32_t n_descsz,
+				       char *name, uint32_t n_type, void **data);
+static int alignfile(unsigned long *offset);
+static int
+write_elf_note_header(char *name, void *data, size_t descsz, uint32_t type,
+		      unsigned long *offset, unsigned long *desc_offset);
+static unsigned long legacy_per_cpu_ptr(unsigned long ptr, int cpu);
+static unsigned long per_cpu_ptr(unsigned long ptr, int cpu);
+static int get_prstatus_from_crash_notes(int cpu, char *prstatus_buf);
+static int cpu_to_apicid(int cpu, int *apicid);
+static int get_smram_cpu_state(int apicid, struct sadump_smram_cpu_state *smram);
+static int copy_regs_from_prstatus(struct elf_prstatus *prstatus,
+				   const char *prstatus_buf);
+static int
+copy_regs_from_smram_cpu_state(struct elf_prstatus *prstatus,
+			       const struct sadump_smram_cpu_state *smram);
+static void
+debug_message_smram_cpu_state(int apicid, struct sadump_smram_cpu_state *s);
+static void
+debug_message_user_regs_struct(int cpu, struct elf_prstatus *prstatus);
+static int get_registers(int cpu, struct elf_prstatus *prstatus);
 
 static struct sadump_info sadump_info = {};
 static struct sadump_info *si = &sadump_info;
@@ -136,6 +179,112 @@ sadump_copy_1st_bitmap_from_memory(void)
 	return TRUE;
 }
 
+int
+sadump_generate_vmcoreinfo_from_vmlinux(size_t *vmcoreinfo_size)
+{
+	size_t size;
+
+	if (!info->file_vmcoreinfo)
+		return FALSE;
+
+	if ((SYMBOL(system_utsname) == NOT_FOUND_SYMBOL) &&
+	    (SYMBOL(init_uts_ns) == NOT_FOUND_SYMBOL)) {
+		ERRMSG("Can't get the symbol of system_utsname.\n");
+		return FALSE;
+	}
+
+	if (get_mem_type() == NOT_FOUND_MEMTYPE) {
+		ERRMSG("Can't find the memory type.\n");
+		return FALSE;
+	}
+
+	strncpy(info->release, info->system_utsname.release,
+		strlen(info->system_utsname.release) + 1);
+
+	write_vmcoreinfo_data();
+
+	size = ftell(info->file_vmcoreinfo);
+
+	*vmcoreinfo_size = size;
+
+	return TRUE;
+}
+
+int
+sadump_generate_elf_note_from_dumpfile(void)
+{
+	size_t size_vmcoreinfo, size_pt_note;
+	int x_cpu;
+	unsigned long offset, offset_vmcoreinfo;
+	char *vmcoreinfo_buf = NULL;
+	int retval = FALSE;
+
+	if (!per_cpu_init())
+		return FALSE;
+
+	if (!(info->file_vmcoreinfo = tmpfile())) {
+		ERRMSG("Can't create a temporary strings(%s).\n",
+		       FILENAME_VMCOREINFO);
+		return FALSE;
+	}
+	if (!sadump_generate_vmcoreinfo_from_vmlinux(&size_vmcoreinfo)) {
+		ERRMSG("Can't generate vmcoreinfo data.\n");
+		goto error;
+	}
+	if ((vmcoreinfo_buf = malloc(size_vmcoreinfo)) == NULL) {
+		ERRMSG("Can't allocate vmcoreinfo buffer. %s\n",
+		       strerror(errno));
+		goto cleanup;
+	}
+	rewind(info->file_vmcoreinfo);
+	if (fread(vmcoreinfo_buf, size_vmcoreinfo, 1,
+		  info->file_vmcoreinfo) != 1) {
+		ERRMSG("Can't read vmcoreinfo temporary file. %s\n",
+		       strerror(errno));
+		goto cleanup;
+	}
+
+	if (!(si->file_elf_note = tmpfile())) {
+		ERRMSG("Can't create a temporary elf_note file. %s\n",
+		       strerror(errno));
+		goto cleanup;
+	}
+	offset = 0;
+	for (x_cpu = 0; x_cpu < get_nr_cpus(); ++x_cpu) {
+		struct elf_prstatus prstatus;
+
+		memset(&prstatus, 0, sizeof(prstatus));
+
+		if (!get_registers(x_cpu, &prstatus))
+			goto cleanup;
+
+		if (!write_elf_note_header("CORE", &prstatus, sizeof(prstatus),
+					   NT_PRSTATUS, &offset, NULL))
+			goto cleanup;
+
+	}
+
+	if (!write_elf_note_header("VMCOREINFO", vmcoreinfo_buf,
+				   size_vmcoreinfo, 0, &offset,
+				   &offset_vmcoreinfo))
+		goto cleanup;
+
+	size_pt_note = ftell(si->file_elf_note);
+	set_pt_note(0, size_pt_note);
+	set_vmcoreinfo(offset_vmcoreinfo, size_vmcoreinfo);
+
+	retval = TRUE;
+
+cleanup:
+	free(vmcoreinfo_buf);
+	if (info->file_vmcoreinfo) {
+		fclose(info->file_vmcoreinfo);
+		info->file_vmcoreinfo = NULL;
+	}
+error:
+	return retval;
+}
+
 static char *
 guid_to_str(efi_guid_t *guid, char *buf, size_t buflen)
 {
@@ -766,6 +915,125 @@ error:
 	return FALSE;
 }
 
+int
+sadump_check_debug_info(void)
+{
+	if (SYMBOL(linux_banner) == NOT_FOUND_SYMBOL)
+		return FALSE;
+	if (SYMBOL(bios_cpu_apicid) == NOT_FOUND_SYMBOL &&
+	    SYMBOL(x86_bios_cpu_apicid) == NOT_FOUND_SYMBOL)
+		return FALSE;
+	if (SYMBOL(x86_bios_cpu_apicid) != NOT_FOUND_SYMBOL &&
+	    (SYMBOL(x86_bios_cpu_apicid_early_ptr) == NOT_FOUND_SYMBOL ||
+	     SYMBOL(x86_bios_cpu_apicid_early_map) == NOT_FOUND_SYMBOL))
+		return FALSE;
+	if (SYMBOL(crash_notes) == NOT_FOUND_SYMBOL)
+		return FALSE;
+	if (SIZE(percpu_data) == NOT_FOUND_STRUCTURE &&
+	    SYMBOL(__per_cpu_load) == NOT_FOUND_SYMBOL)
+		return FALSE;
+	if (SYMBOL(__per_cpu_load) != NOT_FOUND_SYMBOL &&
+	    (SYMBOL(__per_cpu_offset) == NOT_FOUND_SYMBOL &&
+	     ARRAY_LENGTH(__per_cpu_offset) == NOT_FOUND_STRUCTURE))
+		return FALSE;
+	if (SIZE(elf_prstatus) == NOT_FOUND_STRUCTURE)
+		return FALSE;
+	if (OFFSET(elf_prstatus.pr_reg) == NOT_FOUND_STRUCTURE)
+		return FALSE;
+#ifdef __x86__
+	if (OFFSET(user_regs_struct.bx) == NOT_FOUND_STRUCTURE)
+		return FALSE;
+	if (OFFSET(user_regs_struct.cx) == NOT_FOUND_STRUCTURE)
+		return FALSE;
+	if (OFFSET(user_regs_struct.dx) == NOT_FOUND_STRUCTURE)
+		return FALSE;
+	if (OFFSET(user_regs_struct.si) == NOT_FOUND_STRUCTURE)
+		return FALSE;
+	if (OFFSET(user_regs_struct.di) == NOT_FOUND_STRUCTURE)
+		return FALSE;
+	if (OFFSET(user_regs_struct.bp) == NOT_FOUND_STRUCTURE)
+		return FALSE;
+	if (OFFSET(user_regs_struct.ax) == NOT_FOUND_STRUCTURE)
+		return FALSE;
+	if (OFFSET(user_regs_struct.ds) == NOT_FOUND_STRUCTURE)
+		return FALSE;
+	if (OFFSET(user_regs_struct.es) == NOT_FOUND_STRUCTURE)
+		return FALSE;
+	if (OFFSET(user_regs_struct.fs) == NOT_FOUND_STRUCTURE)
+		return FALSE;
+	if (OFFSET(user_regs_struct.gs) == NOT_FOUND_STRUCTURE)
+		return FALSE;
+	if (OFFSET(user_regs_struct.orig_ax) == NOT_FOUND_STRUCTURE)
+		return FALSE;
+	if (OFFSET(user_regs_struct.ip) == NOT_FOUND_STRUCTURE)
+		return FALSE;
+	if (OFFSET(user_regs_struct.cs) == NOT_FOUND_STRUCTURE)
+		return FALSE;
+	if (OFFSET(user_regs_struct.flags) == NOT_FOUND_STRUCTURE)
+		return FALSE;
+	if (OFFSET(user_regs_struct.sp) == NOT_FOUND_STRUCTURE)
+		return FALSE;
+	if (OFFSET(user_regs_struct.ss) == NOT_FOUND_STRUCTURE)
+		return FALSE;
+#elif defined(__x86_64__)
+	if (OFFSET(user_regs_struct.r15) == NOT_FOUND_STRUCTURE)
+		return FALSE;
+	if (OFFSET(user_regs_struct.r14) == NOT_FOUND_STRUCTURE)
+		return FALSE;
+	if (OFFSET(user_regs_struct.r13) == NOT_FOUND_STRUCTURE)
+		return FALSE;
+	if (OFFSET(user_regs_struct.r12) == NOT_FOUND_STRUCTURE)
+		return FALSE;
+	if (OFFSET(user_regs_struct.bp) == NOT_FOUND_STRUCTURE)
+		return FALSE;
+	if (OFFSET(user_regs_struct.bx) == NOT_FOUND_STRUCTURE)
+		return FALSE;
+	if (OFFSET(user_regs_struct.r11) == NOT_FOUND_STRUCTURE)
+		return FALSE;
+	if (OFFSET(user_regs_struct.r10) == NOT_FOUND_STRUCTURE)
+		return FALSE;
+	if (OFFSET(user_regs_struct.r9) == NOT_FOUND_STRUCTURE)
+		return FALSE;
+	if (OFFSET(user_regs_struct.r8) == NOT_FOUND_STRUCTURE)
+		return FALSE;
+	if (OFFSET(user_regs_struct.ax) == NOT_FOUND_STRUCTURE)
+		return FALSE;
+	if (OFFSET(user_regs_struct.cx) == NOT_FOUND_STRUCTURE)
+		return FALSE;
+	if (OFFSET(user_regs_struct.dx) == NOT_FOUND_STRUCTURE)
+		return FALSE;
+	if (OFFSET(user_regs_struct.si) == NOT_FOUND_STRUCTURE)
+		return FALSE;
+	if (OFFSET(user_regs_struct.di) == NOT_FOUND_STRUCTURE)
+		return FALSE;
+	if (OFFSET(user_regs_struct.orig_ax) == NOT_FOUND_STRUCTURE)
+		return FALSE;
+	if (OFFSET(user_regs_struct.ip) == NOT_FOUND_STRUCTURE)
+		return FALSE;
+	if (OFFSET(user_regs_struct.cs) == NOT_FOUND_STRUCTURE)
+		return FALSE;
+	if (OFFSET(user_regs_struct.flags) == NOT_FOUND_STRUCTURE)
+		return FALSE;
+	if (OFFSET(user_regs_struct.sp) == NOT_FOUND_STRUCTURE)
+		return FALSE;
+	if (OFFSET(user_regs_struct.ss) == NOT_FOUND_STRUCTURE)
+		return FALSE;
+	if (OFFSET(user_regs_struct.fs_base) == NOT_FOUND_STRUCTURE)
+		return FALSE;
+	if (OFFSET(user_regs_struct.gs_base) == NOT_FOUND_STRUCTURE)
+		return FALSE;
+	if (OFFSET(user_regs_struct.ds) == NOT_FOUND_STRUCTURE)
+		return FALSE;
+	if (OFFSET(user_regs_struct.es) == NOT_FOUND_STRUCTURE)
+		return FALSE;
+	if (OFFSET(user_regs_struct.fs) == NOT_FOUND_STRUCTURE)
+		return FALSE;
+        if (OFFSET(user_regs_struct.gs) == NOT_FOUND_STRUCTURE)
+		return FALSE;
+#endif /* __x86_64__ */
+	return TRUE;
+}
+
 static unsigned long
 pfn_to_block(unsigned long pfn)
 {
@@ -815,6 +1083,539 @@ lookup_diskset(unsigned long whole_offset, int *diskid,
 	return TRUE;
 }
 
+static int
+per_cpu_init(void)
+{
+	size_t __per_cpu_offset_size;
+	int i;
+
+	if (SIZE(percpu_data) != NOT_FOUND_STRUCTURE)
+		return TRUE;
+
+	__per_cpu_offset_size =
+		ARRAY_LENGTH(__per_cpu_offset) * sizeof(unsigned long);
+
+	if (!(si->__per_cpu_offset = malloc(__per_cpu_offset_size))) {
+		ERRMSG("Can't allocate __per_cpu_offset buffer.\n");
+		return FALSE;
+	}
+
+	if (!readmem(VADDR, SYMBOL(__per_cpu_offset), si->__per_cpu_offset,
+		     __per_cpu_offset_size)) {
+		ERRMSG("Can't read __per_cpu_offset memory.\n");
+		return FALSE;
+	}
+
+	if (!readmem(VADDR, SYMBOL(__per_cpu_load), &si->__per_cpu_load,
+		     sizeof(unsigned long))) {
+		ERRMSG("Can't read __per_cpu_load memory.\n");
+		return FALSE;
+	}
+
+	DEBUG_MSG("sadump: __per_cpu_load: %#lx\n", si->__per_cpu_load);
+	DEBUG_MSG("sadump: __per_cpu_offset: LENGTH: %ld\n",
+		  ARRAY_LENGTH(__per_cpu_offset));
+
+	for (i = 0; i < ARRAY_LENGTH(__per_cpu_offset); ++i) {
+		DEBUG_MSG("sadump: __per_cpu_offset[%d]: %#lx\n", i,
+			  si->__per_cpu_offset[i]);
+	}
+
+	return TRUE;
+}
+
+static int
+get_data_from_elf_note_desc(const char *note_buf, uint32_t n_descsz,
+			    char *name, uint32_t n_type, void **data)
+{
+	Elf32_Nhdr *note32;
+	char *note_name;
+
+	note32 = (Elf32_Nhdr *)note_buf;
+	note_name = (char *)(note32 + 1);
+
+	if (note32->n_type != n_type ||
+	    note32->n_namesz != strlen(name) + 1 ||
+	    note32->n_descsz != n_descsz ||
+	    strncmp(note_name, name, note32->n_namesz))
+		return FALSE;
+
+	*data = (char *)note_buf +
+		roundup(sizeof(Elf32_Nhdr) + note32->n_namesz, 4);
+
+	return TRUE;
+}
+
+static int
+alignfile(unsigned long *offset)
+{
+	char nullbyte = '\0';
+	unsigned int len;
+
+	len = roundup(*offset, 4) - *offset;
+	if (fwrite(&nullbyte, 1, len, si->file_elf_note) != len) {
+		ERRMSG("Can't write elf_note file. %s\n", strerror(errno));
+		return FALSE;
+	}
+	*offset += len;
+	return TRUE;
+}
+
+static int
+write_elf_note_header(char *name, void *data, size_t descsz, uint32_t type,
+		      unsigned long *offset, unsigned long *desc_offset)
+{
+	Elf32_Nhdr nhdr;
+
+	nhdr.n_namesz = strlen(name) + 1;
+	nhdr.n_descsz = descsz;
+	nhdr.n_type = type;
+
+	if (fwrite(&nhdr, sizeof(nhdr), 1, si->file_elf_note) != 1) {
+		ERRMSG("Can't write elf_note file. %s\n", strerror(errno));
+		return FALSE;
+	}
+	*offset += sizeof(nhdr);
+
+	if (fwrite(name, nhdr.n_namesz, 1, si->file_elf_note) != 1) {
+		ERRMSG("Can't write elf_note file. %s\n", strerror(errno));
+		return FALSE;
+	}
+	*offset += nhdr.n_namesz;
+	if (!alignfile(offset))
+		return FALSE;
+
+	if (desc_offset)
+		*desc_offset = *offset;
+
+	if (fwrite(data, nhdr.n_descsz, 1, si->file_elf_note) != 1) {
+		ERRMSG("Can't write elf_note file. %s\n", strerror(errno));
+		return FALSE;
+	}
+	*offset += nhdr.n_descsz;
+	if (!alignfile(offset))
+		return FALSE;
+
+	return TRUE;
+}
+
+static unsigned long
+legacy_per_cpu_ptr(unsigned long ptr, int cpu)
+{
+	unsigned long addr;
+
+	if (cpu < 0 || cpu >= get_nr_cpus())
+		return 0UL;
+
+	if (!readmem(VADDR, ~ptr + cpu*sizeof(unsigned long), &addr,
+		     sizeof(addr)))
+		return 0UL;
+
+	return addr;
+}
+
+static unsigned long
+per_cpu_ptr(unsigned long ptr, int cpu)
+{
+	if (cpu < 0 || cpu >= get_nr_cpus())
+		return 0UL;
+
+	if (si->__per_cpu_offset[cpu] == si->__per_cpu_load)
+		return 0UL;
+
+	return ptr + si->__per_cpu_offset[cpu];
+}
+
+static int
+get_prstatus_from_crash_notes(int cpu, char *prstatus_buf)
+{
+	unsigned long crash_notes_vaddr, percpu_addr;
+	char note_buf[KEXEC_NOTE_BYTES], zero_buf[KEXEC_NOTE_BYTES];
+	char *prstatus_ptr;
+
+	if (cpu < 0 || get_nr_cpus() <= cpu)
+		return FALSE;
+
+	if (SYMBOL(crash_notes) == NOT_FOUND_SYMBOL)
+		return FALSE;
+
+	if (!readmem(VADDR, SYMBOL(crash_notes), &crash_notes_vaddr,
+		     sizeof(crash_notes_vaddr)))
+		return FALSE;
+
+	if (!crash_notes_vaddr) {
+		DEBUG_MSG("sadump: crash_notes %d is NULL\n", cpu);
+		return FALSE;
+	}
+
+	memset(zero_buf, 0, KEXEC_NOTE_BYTES);
+
+	percpu_addr = SIZE(percpu_data) != NOT_FOUND_STRUCTURE
+		? legacy_per_cpu_ptr(crash_notes_vaddr, cpu)
+		: per_cpu_ptr(crash_notes_vaddr, cpu);
+
+	if (!readmem(VADDR, percpu_addr, note_buf, KEXEC_NOTE_BYTES))
+		return FALSE;
+
+	if (memcmp(note_buf, zero_buf, KEXEC_NOTE_BYTES) == 0)
+		return FALSE;
+
+	if (!get_data_from_elf_note_desc(note_buf, SIZE(elf_prstatus), "CORE",
+					 NT_PRSTATUS, (void *)&prstatus_ptr))
+		return FALSE;
+
+	memcpy(prstatus_buf, prstatus_ptr, SIZE(elf_prstatus));
+
+	return TRUE;
+}
+
+static int
+cpu_to_apicid(int cpu, int *apicid)
+{
+	if (SYMBOL(bios_cpu_apicid) != NOT_FOUND_SYMBOL) {
+		uint8_t apicid_u8;
+
+		if (!readmem(VADDR, SYMBOL(bios_cpu_apicid)+cpu*sizeof(uint8_t),
+			     &apicid_u8, sizeof(uint8_t)))
+			return FALSE;
+
+		*apicid = (int)apicid_u8;
+
+		DEBUG_MSG("sadump: apicid %u for cpu %d from "
+			  "bios_cpu_apicid\n", apicid_u8, cpu);
+
+	} else if (SYMBOL(x86_bios_cpu_apicid) != NOT_FOUND_SYMBOL) {
+		uint16_t apicid_u16;
+		unsigned long early_ptr, apicid_addr;
+
+		if (!readmem(VADDR, SYMBOL(x86_bios_cpu_apicid_early_ptr),
+			     &early_ptr, sizeof(early_ptr)))
+			return FALSE;
+
+		apicid_addr = early_ptr
+			? SYMBOL(x86_bios_cpu_apicid_early_map)+cpu*sizeof(uint16_t)
+			: per_cpu_ptr(SYMBOL(x86_bios_cpu_apicid), cpu);
+
+		if (!readmem(VADDR, apicid_addr, &apicid_u16, sizeof(uint16_t)))
+			return FALSE;
+
+		*apicid = (int)apicid_u16;
+
+		DEBUG_MSG("sadump: apicid %u for cpu %d from "
+			  "x86_bios_cpu_apicid\n", apicid_u16, cpu);
+
+	} else {
+
+		ERRMSG("sadump: no symbols for access to acpidid\n");
+
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static int
+get_smram_cpu_state(int apicid, struct sadump_smram_cpu_state *smram)
+{
+	unsigned long offset;
+
+	if (!si->sub_hdr_offset || !si->smram_cpu_state_size ||
+	    apicid >= si->sh_memory->nr_cpus)
+		return FALSE;
+
+	offset = si->sub_hdr_offset + sizeof(uint32_t) +
+		si->sh_memory->nr_cpus * sizeof(struct sadump_apic_state);
+
+	if (lseek(info->fd_memory, offset+apicid*si->smram_cpu_state_size,
+		  SEEK_SET) < 0)
+		DEBUG_MSG("sadump: cannot lseek smram cpu state in dump sub "
+			  "header\n");
+
+	if (read(info->fd_memory, smram, si->smram_cpu_state_size) !=
+	    si->smram_cpu_state_size)
+		DEBUG_MSG("sadump: cannot read smram cpu state in dump sub "
+			  "header\n");
+
+	return TRUE;
+}
+
+#ifdef __x86__
+
+static int
+copy_regs_from_prstatus(struct elf_prstatus *prstatus,
+			const char *prstatus_buf)
+{
+	struct user_regs_struct *r = &prstatus->pr_reg;
+	const char *pr_reg_buf = prstatus_buf + OFFSET(elf_prstatus.pr_reg);
+
+	r->bx = ULONG(pr_reg_buf + OFFSET(user_regs_struct.bx));
+	r->cx = ULONG(pr_reg_buf + OFFSET(user_regs_struct.cx));
+	r->dx = ULONG(pr_reg_buf + OFFSET(user_regs_struct.dx));
+	r->si = ULONG(pr_reg_buf + OFFSET(user_regs_struct.si));
+	r->di = ULONG(pr_reg_buf + OFFSET(user_regs_struct.di));
+	r->bp = ULONG(pr_reg_buf + OFFSET(user_regs_struct.bp));
+	r->ax = ULONG(pr_reg_buf + OFFSET(user_regs_struct.ax));
+	r->ds = ULONG(pr_reg_buf + OFFSET(user_regs_struct.ds));
+	r->es = ULONG(pr_reg_buf + OFFSET(user_regs_struct.es));
+	r->fs = ULONG(pr_reg_buf + OFFSET(user_regs_struct.fs));
+	r->gs = ULONG(pr_reg_buf + OFFSET(user_regs_struct.gs));
+	r->orig_ax = ULONG(pr_reg_buf + OFFSET(user_regs_struct.orig_ax));
+	r->ip = ULONG(pr_reg_buf + OFFSET(user_regs_struct.ip));
+	r->cs = ULONG(pr_reg_buf + OFFSET(user_regs_struct.cs));
+	r->flags = ULONG(pr_reg_buf + OFFSET(user_regs_struct.flags));
+	r->sp = ULONG(pr_reg_buf + OFFSET(user_regs_struct.sp));
+	r->ss = ULONG(pr_reg_buf + OFFSET(user_regs_struct.ss));
+
+	return TRUE;
+}
+
+static int
+copy_regs_from_smram_cpu_state(struct elf_prstatus *prstatus,
+			       const struct sadump_smram_cpu_state *smram)
+{
+	struct user_regs_struct *regs = &prstatus->pr_reg;
+
+	regs->bx = smram->RbxLower;
+	regs->cx = smram->RcxLower;
+	regs->dx = smram->RdxLower;
+	regs->si = smram->RsiLower;
+	regs->di = smram->RdiLower;
+	regs->bp = smram->RbpLower;
+	regs->ax = smram->RaxLower;
+	regs->ds = smram->Ds & 0xffff;
+	regs->es = smram->Es & 0xffff;
+	regs->fs = smram->Fs & 0xffff;
+	regs->gs = smram->Gs & 0xffff;
+	regs->orig_ax = smram->RaxLower;
+	regs->ip = (uint32_t)smram->Rip;
+	regs->cs = smram->Cs & 0xffff;
+	regs->flags = (uint32_t)smram->Rflags;
+	regs->sp = smram->RspLower;
+	regs->ss = smram->Ss & 0xffff;
+
+	return TRUE;
+}
+
+static void
+debug_message_user_regs_struct(int cpu, struct elf_prstatus *prstatus)
+{
+	struct user_regs_struct *r = &prstatus->pr_reg;
+
+	DEBUG_MSG(
+		"sadump: CPU: %d\n"
+		"    BX: %08lx CX: %08lx DX: %08lx SI: %08lx\n"
+		"    DI: %08lx BP: %08lx AX: %08lx ORIG_AX: %08lx\n"
+		"    DS: %04lx ES: %04lx FS: %04lx GS: %04lx CS: %04lx SS: %04lx\n"
+		"    IP: %08lx FLAGS: %04lx SP: %08lx\n",
+		cpu,
+		r->bx, r->cx, r->dx, r->si,
+		r->di, r->bp, r->ax, r->orig_ax,
+		r->ds, r->es, r->fs, r->gs, r->cs, r->ss,
+		r->ip, r->flags, r->sp);
+}
+
+#elif defined(__x86_64__)
+
+static int
+copy_regs_from_prstatus(struct elf_prstatus *prstatus,
+			const char *prstatus_buf)
+{
+	struct user_regs_struct *r = &prstatus->pr_reg;
+	const char *pr_reg_buf = prstatus_buf + OFFSET(elf_prstatus.pr_reg);
+
+	r->r15 = ULONG(pr_reg_buf + OFFSET(user_regs_struct.r15));
+	r->r14 = ULONG(pr_reg_buf + OFFSET(user_regs_struct.r14));
+	r->r13 = ULONG(pr_reg_buf + OFFSET(user_regs_struct.r13));
+	r->bp = ULONG(pr_reg_buf + OFFSET(user_regs_struct.bp));
+	r->bx = ULONG(pr_reg_buf + OFFSET(user_regs_struct.bx));
+	r->r11 = ULONG(pr_reg_buf + OFFSET(user_regs_struct.r11));
+	r->r10 = ULONG(pr_reg_buf + OFFSET(user_regs_struct.r10));
+	r->r9 = ULONG(pr_reg_buf + OFFSET(user_regs_struct.r9));
+	r->r8 = ULONG(pr_reg_buf + OFFSET(user_regs_struct.r8));
+	r->ax = ULONG(pr_reg_buf + OFFSET(user_regs_struct.ax));
+	r->cx = ULONG(pr_reg_buf + OFFSET(user_regs_struct.cx));
+	r->dx = ULONG(pr_reg_buf + OFFSET(user_regs_struct.dx));
+	r->si = ULONG(pr_reg_buf + OFFSET(user_regs_struct.si));
+	r->di = ULONG(pr_reg_buf + OFFSET(user_regs_struct.di));
+	r->orig_ax = ULONG(pr_reg_buf + OFFSET(user_regs_struct.orig_ax));
+	r->ip = ULONG(pr_reg_buf + OFFSET(user_regs_struct.ip));
+	r->cs = ULONG(pr_reg_buf + OFFSET(user_regs_struct.cs));
+	r->flags = ULONG(pr_reg_buf + OFFSET(user_regs_struct.flags));
+	r->sp = ULONG(pr_reg_buf + OFFSET(user_regs_struct.sp));
+	r->ss = ULONG(pr_reg_buf + OFFSET(user_regs_struct.ss));
+	r->fs_base = ULONG(pr_reg_buf + OFFSET(user_regs_struct.fs_base));
+	r->gs_base = ULONG(pr_reg_buf + OFFSET(user_regs_struct.gs_base));
+	r->ds = ULONG(pr_reg_buf + OFFSET(user_regs_struct.ds));
+	r->es = ULONG(pr_reg_buf + OFFSET(user_regs_struct.es));
+	r->fs = ULONG(pr_reg_buf + OFFSET(user_regs_struct.fs));
+	r->gs = ULONG(pr_reg_buf + OFFSET(user_regs_struct.gs));
+
+	return TRUE;
+}
+
+static int
+copy_regs_from_smram_cpu_state(struct elf_prstatus *prstatus,
+			       const struct sadump_smram_cpu_state *smram)
+{
+	struct user_regs_struct *regs = &prstatus->pr_reg;
+
+	regs->r15 = ((uint64_t)smram->R15Upper<<32)+smram->R15Lower;
+	regs->r14 = ((uint64_t)smram->R14Upper<<32)+smram->R14Lower;
+	regs->r13 = ((uint64_t)smram->R13Upper<<32)+smram->R13Lower;
+	regs->r12 = ((uint64_t)smram->R12Upper<<32)+smram->R12Lower;
+	regs->bp = ((uint64_t)smram->RbpUpper<<32)+smram->RbpLower;
+	regs->bx = ((uint64_t)smram->RbxUpper<<32)+smram->RbxLower;
+	regs->r11 = ((uint64_t)smram->R11Upper<<32)+smram->R11Lower;
+	regs->r10 = ((uint64_t)smram->R10Upper<<32)+smram->R10Lower;
+	regs->r9 = ((uint64_t)smram->R9Upper<<32)+smram->R9Lower;
+	regs->r8 = ((uint64_t)smram->R8Upper<<32)+smram->R8Lower;
+	regs->ax = ((uint64_t)smram->RaxUpper<<32)+smram->RaxLower;
+	regs->cx = ((uint64_t)smram->RcxUpper<<32)+smram->RcxLower;
+	regs->dx = ((uint64_t)smram->RdxUpper<<32)+smram->RdxLower;
+	regs->si = ((uint64_t)smram->RsiUpper<<32)+smram->RsiLower;
+	regs->di = ((uint64_t)smram->RdiUpper<<32)+smram->RdiLower;
+	regs->orig_ax = ((uint64_t)smram->RaxUpper<<32)+smram->RaxLower;
+	regs->ip = smram->Rip;
+	regs->cs = smram->Cs;
+	regs->flags = smram->Rflags;
+	regs->sp = ((uint64_t)smram->RspUpper<<32)+smram->RspLower;
+	regs->ss = smram->Ss;
+	regs->fs_base = 0;
+	regs->gs_base = 0;
+	regs->ds = smram->Ds;
+	regs->es = smram->Es;
+	regs->fs = smram->Fs;
+	regs->gs = smram->Gs;
+
+	return TRUE;
+}
+
+static void
+debug_message_user_regs_struct(int cpu, struct elf_prstatus *prstatus)
+{
+	struct user_regs_struct *r = &prstatus->pr_reg;
+
+	DEBUG_MSG(
+		"sadump: CPU: %d\n"
+		"    R15: %016llx R14: %016llx R13: %016llx\n"
+		"    R12: %016llx RBP: %016llx RBX: %016llx\n"
+		"    R11: %016llx R10: %016llx R9: %016llx\n"
+		"    R8: %016llx RAX: %016llx RCX: %016llx\n"
+		"    RDX: %016llx RSI: %016llx RDI: %016llx\n"
+		"    ORIG_RAX: %016llx RIP: %016llx\n"
+		"    CS: %04lx FLAGS: %08llx RSP: %016llx\n"
+		"    SS: %04lx FS_BASE: %04lx GS_BASE: %04lx\n"
+		"    DS: %04lx ES: %04lx FS: %04lx GS: %04lx\n",
+		cpu,
+		(unsigned long long)r->r15, (unsigned long long)r->r14,
+		(unsigned long long)r->r13, (unsigned long long)r->r12,
+		(unsigned long long)r->bp, (unsigned long long)r->bx,
+		(unsigned long long)r->r11, (unsigned long long)r->r10,
+		(unsigned long long)r->r9, (unsigned long long)r->r8,
+		(unsigned long long)r->ax, (unsigned long long)r->cx,
+		(unsigned long long)r->dx, (unsigned long long)r->si,
+		(unsigned long long)r->di,
+		(unsigned long long)r->orig_ax,
+		(unsigned long long)r->ip, r->cs,
+		(unsigned long long)r->flags, (unsigned long long)r->sp,
+		r->ss, r->fs_base, r->gs_base, r->ds, r->es, r->fs,
+		r->gs);
+}
+
+#endif /* __x86_64__ */
+
+static void
+debug_message_smram_cpu_state(int apicid, struct sadump_smram_cpu_state *s)
+{
+	DEBUG_MSG(
+		"sadump: 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,
+		(unsigned long long)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,
+		(unsigned long long)s->Cr0, (unsigned long long)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, (unsigned long long)s->Rflags,
+		(unsigned long long)s->Eptp, s->EptpSetting,
+		(unsigned long long)s->Dr6, (unsigned long long)s->Dr7,
+		(unsigned long long)s->Ia32Efer,
+		s->IoMemAddrUpper, s->IoMemAddrLower, (unsigned long long)s->IoEip,
+		s->IoMisc, s->LdtInfo,
+		s->IoInstructionRestart,
+		s->AutoHaltRestart);
+}
+
+static int
+get_registers(int cpu, struct elf_prstatus *prstatus)
+{
+	struct sadump_smram_cpu_state smram;
+	char *prstatus_buf = NULL;
+	int retval = FALSE, apicid = 0;
+
+	if (!(prstatus_buf = malloc(SIZE(elf_prstatus)))) {
+		ERRMSG("Can't allocate elf_prstatus buffer. %s\n",
+		       strerror(errno));
+		goto error;
+	}
+
+	if (get_prstatus_from_crash_notes(cpu, prstatus_buf)) {
+
+		if (!copy_regs_from_prstatus(prstatus, prstatus_buf))
+			goto cleanup;
+
+		DEBUG_MSG("sadump: cpu #%d registers from crash_notes\n", cpu);
+
+		debug_message_user_regs_struct(cpu, prstatus);
+
+	} else {
+
+		if (!cpu_to_apicid(cpu, &apicid))
+			goto cleanup;
+
+		if (!get_smram_cpu_state(apicid, &smram))
+			goto cleanup;
+
+		copy_regs_from_smram_cpu_state(prstatus, &smram);
+
+		DEBUG_MSG("sadump: cpu #%d registers from SMRAM\n", cpu);
+
+		debug_message_smram_cpu_state(apicid, &smram);
+		debug_message_user_regs_struct(cpu, prstatus);
+
+	}
+
+	retval = TRUE;
+cleanup:
+	free(prstatus_buf);
+error:
+	return retval;
+}
+
 int
 sadump_add_diskset_info(char *name_memory)
 {
@@ -834,6 +1635,23 @@ sadump_add_diskset_info(char *name_memory)
 	return TRUE;
 }
 
+int
+sadump_read_elf_note(char *buf, size_t size_note)
+{
+	if (!si->file_elf_note)
+		return FALSE;
+
+	rewind(si->file_elf_note);
+
+	if (fread(buf, size_note, 1, si->file_elf_note) != 1) {
+		ERRMSG("Can't read elf note file. %s\n",
+		       strerror(errno));
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
 long
 sadump_page_size(void)
 {
@@ -884,8 +1702,12 @@ free_sadump_info(void)
 		}
 		free(si->diskset_info);
 	}
+	if (si->__per_cpu_offset)
+		free(si->__per_cpu_offset);
 	if (si->block_table)
 		free(si->block_table);
+	if (si->file_elf_note)
+		fclose(si->file_elf_note);
 }
 
 #endif /* defined(__x86__) && defined(__x86_64__) */
diff --git a/sadump_info.h b/sadump_info.h
index 401b769..c1f948f 100644
--- a/sadump_info.h
+++ b/sadump_info.h
@@ -44,7 +44,12 @@ int sadump_get_nr_cpus(int *nr_cpus);
 int sadump_set_timestamp(struct timeval *ts);
 unsigned long long sadump_get_max_mapnr(void);
 int readpmem_sadump(unsigned long long paddr, void *bufptr, size_t size);
+int sadump_check_debug_info(void);
+int sadump_generate_vmcoreinfo_from_vmlinux(size_t *vmcoreinfo_size);
+int sadump_generate_elf_note_from_dumpfile(void);
+int sadump_copy_1st_bitmap_from_memory(void);
 int sadump_add_diskset_info(char *name_memory);
+int sadump_read_elf_note(char *buf, size_t size_note);
 long sadump_page_size(void);
 char *sadump_head_disk_name_memory(void);
 char *sadump_format_type_name(void);
@@ -97,11 +102,32 @@ static inline int readpmem_sadump(unsigned long long paddr,
 	return FALSE;
 }
 
+static inline int sadump_check_debug_info(void)
+{
+	return FALSE;
+}
+
+static inline int
+sadump_generate_vmcoreinfo_from_vmlinux(size_t *vmcoreinfo_size)
+{
+	return FALSE;
+}
+
+static inline int sadump_generate_elf_note_from_dumpfile(void)
+{
+	return FALSE;
+}
+
 static inline int sadump_add_diskset_info(char *name_memory)
 {
 	return TRUE;
 }
 
+static inline int sadump_read_elf_note(char *buf, size_t size_note)
+{
+	return FALSE;
+}
+
 static inline long sadump_page_size(void)
 {
 	return 0;
-- 
1.7.4.4





More information about the kexec mailing list