Subject: [PATCH 10/18] Generate and save VMCOREINFO and ELF note information This is a backport of commit ef2832fe5ab68d359957af42e9d5ec50bb251da9 Author: HATAYAMA Daisuke Date: Fri Dec 16 10:55:19 2011 +0900 [PATCH v2 10/14] Generate and save VMCOREINFO and ELF note information 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 Signed-off-by: Atsushi Kumagai --- diff -Nrup kexec-tools-2.0.0.old/makedumpfile-1.3.5/makedumpfile.c kexec-tools-2.0.0/makedumpfile-1.3.5/makedumpfile.c --- kexec-tools-2.0.0.old/makedumpfile-1.3.5/makedumpfile.c 2012-04-05 04:25:52.821497594 -0400 +++ kexec-tools-2.0.0/makedumpfile-1.3.5/makedumpfile.c 2012-04-05 06:52:16.031498038 -0400 @@ -3004,39 +3004,9 @@ set_dwarf_debuginfo(char *mod_name, char return search_module_debuginfo(); } -int -generate_vmcoreinfo(void) +void +write_vmcoreinfo_data(void) { - if (!set_page_size(sysconf(_SC_PAGE_SIZE))) - return FALSE; - - set_dwarf_debuginfo("vmlinux", 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 */ @@ -3140,6 +3110,42 @@ 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", 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; } @@ -4564,6 +4570,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; @@ -6235,17 +6247,23 @@ write_kdump_header(void) strerror(errno)); return FALSE; } - if (lseek(info->fd_memory, info->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, info->size_note) - != info->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, info->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, info->size_note) != info->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, info->size_note)) + goto out; + } + if (!write_buffer(info->fd_dumpfile, kh.offset_note, buf, kh.size_note, info->name_dumpfile)) goto out; diff -Nrup kexec-tools-2.0.0.old/makedumpfile-1.3.5/makedumpfile.h kexec-tools-2.0.0/makedumpfile-1.3.5/makedumpfile.h --- kexec-tools-2.0.0.old/makedumpfile-1.3.5/makedumpfile.h 2012-04-05 04:25:52.820497648 -0400 +++ kexec-tools-2.0.0/makedumpfile-1.3.5/makedumpfile.h 2012-04-05 04:36:32.982554978 -0400 @@ -1571,6 +1571,8 @@ is_dumpable(struct dump_bitmap *bitmap, return is_on(bitmap->buf, pfn%PFN_BUFBITMAP); } +void write_vmcoreinfo_data(void); + #ifdef __x86__ struct user_regs_struct { diff -Nrup kexec-tools-2.0.0.old/makedumpfile-1.3.5/sadump_info.c kexec-tools-2.0.0/makedumpfile-1.3.5/sadump_info.c --- kexec-tools-2.0.0.old/makedumpfile-1.3.5/sadump_info.c 2012-04-05 04:25:52.820497648 -0400 +++ kexec-tools-2.0.0/makedumpfile-1.3.5/sadump_info.c 2012-04-05 06:53:44.786464288 -0400 @@ -21,12 +21,28 @@ #include "makedumpfile.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; @@ -45,6 +61,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); @@ -58,6 +78,28 @@ static int read_sadump_header_diskset(in 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; @@ -135,6 +177,114 @@ 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 < info->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); + info->offset_note = 0; + info->size_note = size_pt_note; + info->offset_vmcoreinfo = offset_vmcoreinfo; + info->size_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 +916,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) { @@ -815,6 +1084,539 @@ lookup_diskset(unsigned long long whole_ 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 >= info->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 >= info->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 || info->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 +1636,23 @@ sadump_add_diskset_info(char *name_memor 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 +1703,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 -Nrup kexec-tools-2.0.0.old/makedumpfile-1.3.5/sadump_info.h kexec-tools-2.0.0/makedumpfile-1.3.5/sadump_info.h --- kexec-tools-2.0.0.old/makedumpfile-1.3.5/sadump_info.h 2012-04-05 04:25:52.820497648 -0400 +++ kexec-tools-2.0.0/makedumpfile-1.3.5/sadump_info.h 2012-04-05 04:36:32.983537207 -0400 @@ -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(unsign 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;