If a QEMU ELF dump from a KASLR-enabled kernel is missing the vmcoreinfo
data, try to calculate phys_base and kaslr_offset by using the technique
developed by Takao Indoh.
---
 defs.h         |  7 +++++++
 kaslr_helper.c | 25 +++++++++++++++++++++++--
 netdump.c      | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 netdump.h      |  1 +
 symbols.c      | 20 ++++++++++++++------
 x86_64.c       | 17 +++++++++++++++--
 6 files changed, 117 insertions(+), 10 deletions(-)

diff --git a/defs.h b/defs.h
index 45e9069..b117c4a 100644
--- a/defs.h
+++ b/defs.h
@@ -284,6 +284,9 @@ struct number_option {
 #define KVMDUMP_DUMPFILE()  (pc->flags & KVMDUMP)
 #define SADUMP_DUMPFILE()  (pc->flags & SADUMP)
 #define VMSS_DUMPFILE()     (pc->flags & VMWARE_VMSS)
+#define QEMU_MEM_DUMP_NO_VMCOREINFO() \
+           ((pc->flags2 & (QEMU_MEM_DUMP_ELF)) && !(pc->flags2 & VMCOREINFO))
+
 
 #define NETDUMP_LOCAL    (0x1)  /* netdump_data flags */
 #define NETDUMP_REMOTE   (0x2)  
@@ -6227,6 +6230,8 @@ 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);
 int arm_kdump_phys_base(ulong *);
 int is_proc_kcore(char *, ulong);
 int proc_kcore_init(FILE *);
@@ -6238,6 +6243,8 @@ 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 kdump_kaslr_check(void);
+QEMUCPUState *kdump_get_qemucpustate(int);
 #define PRSTATUS_NOTE (1)
 #define QEMU_NOTE     (2)
 
diff --git a/kaslr_helper.c b/kaslr_helper.c
index 24b378c..9f04e3b 100644
--- a/kaslr_helper.c
+++ b/kaslr_helper.c
@@ -237,6 +237,22 @@ get_vmcoreinfo(ulong elfcorehdr, ulong *addr, int *len)
        return TRUE;
 }
 
+static int
+qemu_get_cr3_idtr(ulong *cr3, ulong *idtr)
+{
+       QEMUCPUState *cpustat;
+
+       cpustat = kdump_get_qemucpustate(0);
+       if (!cpustat) {
+               return FALSE;
+       }
+
+       *cr3 = cpustat->cr[3];
+       *idtr = cpustat->idt.base;
+
+       return TRUE;
+}
+
 /*
  * Check if current kaslr_offset/phys_base is for 1st kernel or 2nd kernel.
  * If we are in 2nd kernel, get kaslr_offset/phys_base from vmcoreinfo.
@@ -380,9 +396,14 @@ calc_kaslr_offset(ulong *kaslr_offset, ulong *phys_base)
        if (!machine_type("X86_64"))
                return FALSE;
 
-       if (SADUMP_DUMPFILE() && !sadump_get_cr3_idtr(&cr3, &idtr)) {
+       if (SADUMP_DUMPFILE()) {
+               if (!sadump_get_cr3_idtr(&cr3, &idtr))
+                       return FALSE;
+       } else if (QEMU_MEM_DUMP_NO_VMCOREINFO()) {
+               if (!qemu_get_cr3_idtr(&cr3, &idtr))
+                       return FALSE;
+       } else
                return FALSE;
-       }
 
        if (st->pti_init_vmlinux || st->kaiser_init_vmlinux)
                pgd = cr3 & ~(CR3_PCID_MASK|PTI_USER_PGTABLE_MASK);
diff --git a/netdump.c b/netdump.c
index 6cf7ca8..136f889 100644
--- a/netdump.c
+++ b/netdump.c
@@ -3999,6 +3999,28 @@ no_nt_prstatus_exists:
        return pt_regs;
 }
 
+int
+kdump_phys_base(ulong *phys_base)
+{
+       if (!kdump_kaslr_check())
+               return FALSE;
+
+       *phys_base = nd->phys_base;
+
+       return TRUE;
+}
+
+int
+kdump_set_phys_base(ulong phys_base)
+{
+       if (!kdump_kaslr_check())
+               return FALSE;
+
+       nd->phys_base = phys_base;
+
+       return TRUE;
+}
+
 /*
  * 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 +4735,38 @@ error(INFO, "%s: backup region is used: %llx\n", 
typename, backup_offset + total
 error:
        error(WARNING, "failed to init kexec backup region\n");
 }
+
+int
+kdump_kaslr_check(void)
+{
+       if (!QEMU_MEM_DUMP_NO_VMCOREINFO())
+               return FALSE;
+
+       /* If vmcore has QEMU note, need to calculate kaslr offset */
+       if (nd->num_qemu_notes)
+               return TRUE;
+       else
+               return FALSE;
+}
+
+#ifdef X86_64
+QEMUCPUState *
+kdump_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];
+}
+#endif
diff --git a/netdump.h b/netdump.h
index 87d51ca..5474593 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..348d9ae 100644
--- a/symbols.c
+++ b/symbols.c
@@ -610,7 +610,11 @@ kaslr_init(void)
                st->_stext_vmlinux = UNINITIALIZED;
        }
 
-       if (KDUMP_DUMPFILE() || DISKDUMP_DUMPFILE()) {
+       if (QEMU_MEM_DUMP_NO_VMCOREINFO()) {
+               if (KDUMP_DUMPFILE() && kdump_kaslr_check()) {
+                       kt->flags2 |= KASLR_CHECK;
+               }
+       } else if (KDUMP_DUMPFILE() || DISKDUMP_DUMPFILE()) {
                if ((string = pc->read_vmcoreinfo("SYMBOL(_stext)"))) {
                        kt->vmcoreinfo._stext_SYMBOL =
                                htol(string, RETURN_ON_ERROR, NULL);
@@ -640,7 +644,7 @@ 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() || QEMU_MEM_DUMP_NO_VMCOREINFO()) {
                ulong kaslr_offset = 0;
                ulong phys_base = 0;
 
@@ -651,8 +655,12 @@ derive_kaslr_offset(bfd *abfd, int dynamic, bfd_byte 
*start, bfd_byte *end,
                        kt->flags |= RELOC_SET;
                }
 
-               if (phys_base)
-                       sadump_set_phys_base(phys_base);
+               if (phys_base) {
+                       if (SADUMP_DUMPFILE())
+                               sadump_set_phys_base(phys_base);
+                       else if (KDUMP_DUMPFILE())
+                               kdump_set_phys_base(phys_base);
+               }
 
                return;
        }
@@ -3071,7 +3079,7 @@ dump_symbol_table(void)
        else
                fprintf(fp, "\n");
 
-       if (SADUMP_DUMPFILE()) {
+       if (SADUMP_DUMPFILE() || QEMU_MEM_DUMP_NO_VMCOREINFO()) {
                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 +12306,7 @@ numeric_forward(const void *P_x, const void *P_y)
                }
        }
 
-       if (SADUMP_DUMPFILE()) {
+       if (SADUMP_DUMPFILE() || QEMU_MEM_DUMP_NO_VMCOREINFO()) {
                /* 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 aaa0de6..4affc67 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() || QEMU_MEM_DUMP_NO_VMCOREINFO())
                        /* 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() || QEMU_MEM_DUMP_NO_VMCOREINFO())
+           && !(machdep->flags & KSYMS_START)) {
                /*
                 * In the case of sadump, to calculate kaslr_offset and
                 * phys_base, kvtop is called during symtab_init(). In this
@@ -6640,6 +6641,18 @@ x86_64_calc_phys_base(void)
         *  Get relocation value from whatever dumpfile format is being used.
         */
 
+       if (QEMU_MEM_DUMP_NO_VMCOREINFO()) {
+               if (KDUMP_DUMPFILE() && kdump_phys_base(&phys_base))
+                       machdep->machspec->phys_base = phys_base;
+
+               if (!x86_64_virt_phys_base())
+                       error(WARNING,
+                               "cannot determine physical base address:"
+                               " defaulting to %lx\n\n",
+                               machdep->machspec->phys_base);
+               return;
+       }
+
        if (DISKDUMP_DUMPFILE()) {
                if (diskdump_phys_base(&phys_base)) {
                        machdep->machspec->phys_base = phys_base;
-- 
2.14.3

--
Crash-utility mailing list
[email protected]
https://www.redhat.com/mailman/listinfo/crash-utility

Reply via email to