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 <[email protected]>
---
 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



_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec

Reply via email to