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 | 823 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ sadump_info.h | 26 ++ 5 files changed, 913 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 6e9dd83..750dcb6 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 adca47b..0b9c524 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,10 @@ struct sadump_info { uint32_t smram_cpu_state_size; unsigned long data_offset; unsigned long 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 +81,28 @@ static int read_sadump_header_diskset(int diskid, struct sadump_diskset_info *sd static unsigned long long pfn_to_block(unsigned long long pfn); static int lookup_diskset(unsigned long long whole_offset, int *diskid, unsigned long 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, char **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 +180,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) { @@ -767,6 +917,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 long pfn_to_block(unsigned long long pfn) { @@ -816,6 +1085,539 @@ lookup_diskset(unsigned long 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, char **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) { @@ -835,6 +1637,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) { @@ -885,8 +1704,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;