[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 3/5] contrib/elf2dmp: improve paging root selection
From: |
Viktor Prutyanov |
Subject: |
[Qemu-devel] [PATCH 3/5] contrib/elf2dmp: improve paging root selection |
Date: |
Wed, 29 Aug 2018 15:41:26 +0300 |
Even if KERNEL_GS_BASEs are absent in QEMU CPU states, there
is a chance to find suitable CR3 value from CPU which runs kernel task.
Signed-off-by: Viktor Prutyanov <address@hidden>
---
contrib/elf2dmp/main.c | 56 +++++++++++++++++++++++++++++++++++++++-------
contrib/elf2dmp/qemu_elf.c | 16 +++++++++++--
contrib/elf2dmp/qemu_elf.h | 3 +++
3 files changed, 65 insertions(+), 10 deletions(-)
diff --git a/contrib/elf2dmp/main.c b/contrib/elf2dmp/main.c
index eb11e66..62f08e0 100644
--- a/contrib/elf2dmp/main.c
+++ b/contrib/elf2dmp/main.c
@@ -188,17 +188,53 @@ static void
win_context_init_from_qemu_cpu_state(WinContext *ctx,
*ctx = win_ctx;
}
-static void fix_dtb(struct va_space *vs, QEMUCPUState *s)
+/*
+ * Finds paging-structure hierarchy base,
+ * if previously set doesn't give access to kernel structures
+ */
+static int fix_dtb(struct va_space *vs, QEMU_Elf *qe)
{
- uint64_t Prcb = (s->gs.base >> 63) ? s->gs.base : s->kernel_gs_base;
- void *prcb = va_space_resolve(vs, Prcb);
+ /*
+ * Firstly, test previously set DTB.
+ */
+ if (va_space_resolve(vs, SharedUserData)) {
+ return 0;
+ }
+
+ /*
+ * Secondly, find CPU which run system task.
+ */
+ for (size_t i = 0; i < qe->state_nr; i++) {
+ QEMUCPUState *s = qe->state[i];
- if (!prcb) {
- va_space_set_dtb(vs, *(uint64_t *)va_space_resolve(vs, Prcb + 0x7000));
+ if (is_system(s)) {
+ va_space_set_dtb(vs, s->cr[3]);
+ printf("DTB 0x%016lx has been found from CPU #%zu"
+ " as system task CR3\n", vs->dtb, i);
+ return !(va_space_resolve(vs, SharedUserData));
+ }
}
- assert(va_space_resolve(vs, Prcb));
- printf("DTB is 0x%016lx\n", vs->dtb);
+ /*
+ * Thirdly, use KERNEL_GS_BASE from CPU #0 as PRCB address and
+ * CR3 as [Prcb+0x7000]
+ */
+ if (qe->has_kernel_gs_base) {
+ QEMUCPUState *s = qe->state[0];
+ uint64_t Prcb = s->kernel_gs_base;
+ uint64_t *cr3 = va_space_resolve(vs, Prcb + 0x7000);
+
+ if (!cr3) {
+ return 1;
+ }
+
+ va_space_set_dtb(vs, *cr3);
+ printf("DirectoryTableBase = 0x%016lx has been found from CPU #0"
+ " as interrupt handling CR3\n", vs->dtb);
+ return !(va_space_resolve(vs, SharedUserData));
+ }
+
+ return 1;
}
static int fill_header(WinDumpHeader64 *hdr, struct pa_space *ps,
@@ -448,7 +484,11 @@ int main(int argc, char *argv[])
printf("CPU #0 CR3 is 0x%016lx\n", state->cr[3]);
va_space_create(&vs, &ps, state->cr[3]);
- fix_dtb(&vs, state);
+ if (fix_dtb(&vs, &qemu_elf)) {
+ eprintf("Failed to find paging base\n");
+ err = 1;
+ goto out_elf;
+ }
printf("CPU #0 IDT is at 0x%016lx\n", state->idt.base);
diff --git a/contrib/elf2dmp/qemu_elf.c b/contrib/elf2dmp/qemu_elf.c
index f7b5ebd..d139db2 100644
--- a/contrib/elf2dmp/qemu_elf.c
+++ b/contrib/elf2dmp/qemu_elf.c
@@ -33,6 +33,11 @@
DIV_ROUND_UP((name_size), 4) + \
DIV_ROUND_UP((desc_size), 4)) * 4)
+int is_system(QEMUCPUState *s)
+{
+ return s->gs.base >> 63;
+}
+
static char *nhdr_get_name(Elf64_Nhdr *nhdr)
{
return (char *)nhdr + ROUND_UP(sizeof(*nhdr), 4);
@@ -76,13 +81,20 @@ static int init_states(QEMU_Elf *qe)
return 1;
}
+ qe->has_kernel_gs_base = 1;
+
for (Elf64_Nhdr *nhdr = start; nhdr < end; nhdr = nhdr_get_next(nhdr)) {
if (!strcmp(nhdr_get_name(nhdr), QEMU_NOTE_NAME)) {
QEMUCPUState *state = nhdr_get_desc(nhdr);
if (state->size < sizeof(*state)) {
- eprintf("QEMU CPU state size %d doesn't match\n", state->size);
- return 1;
+ eprintf("CPU #%zu: QEMU CPU state size %u doesn't match\n",
+ cpu_nr, state->size);
+ /*
+ * We assume either every QEMU CPU state has KERNEL_GS_BASE or
+ * no one has.
+ */
+ qe->has_kernel_gs_base = 0;
}
cpu_nr++;
}
diff --git a/contrib/elf2dmp/qemu_elf.h b/contrib/elf2dmp/qemu_elf.h
index 2a28bb0..d85d655 100644
--- a/contrib/elf2dmp/qemu_elf.h
+++ b/contrib/elf2dmp/qemu_elf.h
@@ -31,12 +31,15 @@ typedef struct QEMUCPUState {
uint64_t kernel_gs_base;
} QEMUCPUState;
+int is_system(QEMUCPUState *s);
+
typedef struct QEMU_Elf {
int fd;
size_t size;
void *map;
QEMUCPUState **state;
size_t state_nr;
+ int has_kernel_gs_base;
} QEMU_Elf;
int QEMU_Elf_init(QEMU_Elf *qe, const char *filename);
--
2.7.4