If the kdump from a KASLR-enabled kernel is missing the vmcoreinfo section, try to calculate phys_base and kaslr_offset by using the technique developed by Takao Indoh. --- defs.h | 7 ++++++ kaslr_helper.c | 3 +++ netdump.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ netdump.h | 1 + symbols.c | 31 +++++++++++++++---------- x86_64.c | 14 +++++++++-- 6 files changed, 115 insertions(+), 14 deletions(-) diff --git a/defs.h b/defs.h index 18b41d0..883100a 100644 --- a/defs.h +++ b/defs.h @@ -6203,6 +6203,10 @@ int get_netdump_arch(void); int exist_regs_in_elf_notes(struct task_context *); void *get_regs_from_elf_notes(struct task_context *); void map_cpus_to_prstatus(void); +int kdump_phys_base(ulong *); +int kdump_set_phys_base(ulong); +ulong qemu_get_idtr(void); +ulong qemu_get_cr3(void); int arm_kdump_phys_base(ulong *); int is_proc_kcore(char *, ulong); int proc_kcore_init(FILE *); @@ -6214,6 +6218,9 @@ void kdump_backup_region_init(void); void display_regs_from_elf_notes(int, FILE *); void display_ELF_note(int, int, void *, FILE *); void *netdump_get_prstatus_percpu(int); +int vmcore_kaslr_check(void); +ulong qemu_get_cr3(void); +ulong qemu_get_idtr(void); #define PRSTATUS_NOTE (1) #define QEMU_NOTE (2) diff --git a/kaslr_helper.c b/kaslr_helper.c index e2da81c..95b856f 100644 --- a/kaslr_helper.c +++ b/kaslr_helper.c @@ -382,6 +382,9 @@ calc_kaslr_offset(ulong *kaslr_offset, ulong *phys_base) if (SADUMP_DUMPFILE()) { idtr = sadump_get_idtr(); cr3 = sadump_get_cr3(); + } else if (KDUMP_DUMPFILE()) { + idtr = qemu_get_idtr(); + cr3 = qemu_get_cr3(); } else { return FALSE; } diff --git a/netdump.c b/netdump.c index 6cf7ca8..46615c0 100644 --- a/netdump.c +++ b/netdump.c @@ -3999,6 +3999,66 @@ no_nt_prstatus_exists: return pt_regs; } +int kdump_phys_base(ulong *phys_base) +{ + if (!vmcore_kaslr_check()) + return FALSE; + + if (nd->phys_base) { + *phys_base = nd->phys_base; + return TRUE; + } + + return FALSE; +} + +int kdump_set_phys_base(ulong phys_base) +{ + if (!vmcore_kaslr_check()) + return FALSE; + + nd->phys_base = phys_base; + + return TRUE; +} + +#ifdef X86_64 +static QEMUCPUState * get_qemucpustate(int cpu) +{ + if (cpu >= nd->num_qemu_notes) { + if (CRASHDEBUG(1)) + error(INFO, + "Invalid index for QEMU Note: %d (>= %d)\n", + cpu, nd->num_qemu_notes); + return NULL; + } + + if (!nd->elf64 || (nd->elf64->e_machine != EM_X86_64)) { + if (CRASHDEBUG(1)) + error(INFO, "Only x86_64 64bit is supported.\n"); + return NULL; + } + + return (QEMUCPUState *)nd->nt_qemu_percpu[cpu]; +} + +ulong qemu_get_idtr(void) +{ + QEMUCPUState *cpustat; + + cpustat = get_qemucpustate(0); + return cpustat->idt.base; +} + +ulong qemu_get_cr3(void) +{ + QEMUCPUState *cpustat; + + cpustat = get_qemucpustate(0); + return cpustat->cr[3]; +} +#endif + /* * In case of ARM we need to determine correct PHYS_OFFSET from the kdump file. * This is done by taking lowest physical address (LMA) from given load @@ -4713,3 +4773,16 @@ error(INFO, "%s: backup region is used: %llx\n", typename, backup_offset + total error: error(WARNING, "failed to init kexec backup region\n"); } + +int +vmcore_kaslr_check(void) +{ + if (!VMCORE_VALID() || !(pc->flags2 & QEMU_MEM_DUMP_ELF)) + return FALSE; + + /* If vmcore has QEMU note, need to calculate kaslr offset */ + if (nd->num_qemu_notes) + return TRUE; + else + return FALSE; +} diff --git a/netdump.h b/netdump.h index dbb054a..1a3e011 100644 --- a/netdump.h +++ b/netdump.h @@ -78,6 +78,7 @@ struct vmcore_data { ulong backup_src_size; ulonglong backup_offset; ulong arch_data; + ulong phys_base; }; #define DUMP_ELF_INCOMPLETE 0x1 /* dumpfile is incomplete */ diff --git a/symbols.c b/symbols.c index 54aa5b2..ddfb325 100644 --- a/symbols.c +++ b/symbols.c @@ -622,6 +622,9 @@ kaslr_init(void) free(string); kt->flags2 |= KASLR_CHECK; st->_stext_vmlinux = UNINITIALIZED; + } else if (vmcore_kaslr_check()) { + kt->flags2 |= KASLR_CHECK; + st->_stext_vmlinux = UNINITIALIZED; } } @@ -640,21 +643,25 @@ derive_kaslr_offset(bfd *abfd, int dynamic, bfd_byte *start, bfd_byte *end, unsigned long relocate; ulong _stext_relocated; - if (SADUMP_DUMPFILE()) { + if (SADUMP_DUMPFILE() || + (KDUMP_DUMPFILE() && kt->vmcoreinfo._stext_SYMBOL == 0)) { ulong kaslr_offset = 0; ulong phys_base = 0; - calc_kaslr_offset(&kaslr_offset, &phys_base); + if (calc_kaslr_offset(&kaslr_offset, &phys_base)) { + if (kaslr_offset) { + kt->relocate = kaslr_offset * -1; + kt->flags |= RELOC_SET; + } - if (kaslr_offset) { - kt->relocate = kaslr_offset * -1; - kt->flags |= RELOC_SET; + if (phys_base) { + if (SADUMP_DUMPFILE()) + sadump_set_phys_base(phys_base); + else + kdump_set_phys_base(phys_base); + } + return; } - - if (phys_base) - sadump_set_phys_base(phys_base); - - return; } if (ACTIVE()) { @@ -3071,7 +3078,7 @@ dump_symbol_table(void) else fprintf(fp, "\n"); - if (SADUMP_DUMPFILE()) { + if (SADUMP_DUMPFILE() || KDUMP_DUMPFILE()) { fprintf(fp, "divide_error_vmlinux: %lx\n", st->divide_error_vmlinux); fprintf(fp, " idt_table_vmlinux: %lx\n", st->idt_table_vmlinux); fprintf(fp, "saved_command_line_vmlinux: %lx\n", st->saved_command_line_vmlinux); @@ -12298,7 +12305,7 @@ numeric_forward(const void *P_x, const void *P_y) } } - if (SADUMP_DUMPFILE()) { + if (SADUMP_DUMPFILE() || KDUMP_DUMPFILE()) { /* Need for kaslr_offset and phys_base */ if (STREQ(x->name, "divide_error")) st->divide_error_vmlinux = valueof(x); diff --git a/x86_64.c b/x86_64.c index 0d5e150..05555c9 100644 --- a/x86_64.c +++ b/x86_64.c @@ -202,7 +202,7 @@ x86_64_init(int when) machdep->machspec->kernel_image_size = dtol(string, QUIET, NULL); free(string); } - if (SADUMP_DUMPFILE()) + if (SADUMP_DUMPFILE() || KDUMP_DUMPFILE()) /* Need for calculation of kaslr_offset and phys_base */ machdep->kvtop = x86_64_kvtop; break; @@ -2220,7 +2220,8 @@ x86_64_kvtop(struct task_context *tc, ulong kvaddr, physaddr_t *paddr, int verbo ulong pte; physaddr_t physpage; - if (SADUMP_DUMPFILE() && !(machdep->flags & KSYMS_START)) { + if ((SADUMP_DUMPFILE() || KDUMP_DUMPFILE()) && + !(machdep->flags & KSYMS_START)) { /* * In the case of sadump, to calculate kaslr_offset and * phys_base, kvtop is called during symtab_init(). In this @@ -6664,6 +6665,15 @@ x86_64_calc_phys_base(void) return; } + if (KDUMP_DUMPFILE()) { + if (kdump_phys_base(&phys_base)) { + machdep->machspec->phys_base = phys_base; + if (CRASHDEBUG(1)) + fprintf(fp, "kdump: phys_base: %lx\n", + phys_base); + } + } + if (SADUMP_DUMPFILE()) { if (sadump_phys_base(&phys_base)) { machdep->machspec->phys_base = phys_base; -- 2.14.3 -- Crash-utility mailing list Crash-utility@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/crash-utility