From 3f1be0889a0d21a65163aae391655616f341f58f Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Fri, 22 Oct 2010 19:32:01 -0700 Subject: [PATCH] libkvm - Add ability to access userspace from kgdb on cores * Use %cr3 from the dumppcb instead of KPML4phys on x86_64, and similarly for i386, to access the full page table as of when the panic occured instead of just the kernel page table. * minidumps do not dump userspace so userspace will still not be available, but this gives us the option of sysctl'ing off minidumps when userspace access is desired, and kgdb will then be able to access the current userspace context as of the panic, as well. --- lib/libkvm/kvm_i386.c | 16 ++++++++++------ lib/libkvm/kvm_x86_64.c | 26 ++++++++++++++------------ 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/lib/libkvm/kvm_i386.c b/lib/libkvm/kvm_i386.c index 3fed91a0ac..5f63ba2589 100644 --- a/lib/libkvm/kvm_i386.c +++ b/lib/libkvm/kvm_i386.c @@ -163,6 +163,7 @@ _kvm_initvtop(kvm_t *kd) Elf_Ehdr *ehdr; size_t hdrsz; char minihdr[8]; + struct pcb dumppcb; if (pread(kd->pmfd, &minihdr, 8, 0) == 8) if (memcmp(&minihdr, "minidump", 8) == 0) @@ -200,18 +201,21 @@ _kvm_initvtop(kvm_t *kd) else kernbase = nlist[0].n_value; - nlist[0].n_name = "_IdlePTD"; + nlist[0].n_name = "_dumppcb"; nlist[1].n_name = 0; if (kvm_nlist(kd, nlist) != 0) { _kvm_err(kd, kd->program, "bad namelist"); return (-1); } - if (kvm_read(kd, (nlist[0].n_value - kernbase), &pa, sizeof(pa)) != - sizeof(pa)) { - _kvm_err(kd, kd->program, "cannot read IdlePTD"); + + if (kvm_read(kd, (nlist[0].n_value - kernbase), &dumppcb, + sizeof(dumppcb)) != sizeof(dumppcb)) { + _kvm_err(kd, kd->program, "cannot read dumppcb"); return (-1); } + pa = dumppcb.pcb_cr3 & PG_FRAME; + PTD = _kvm_malloc(kd, PAGE_SIZE); if (kvm_read(kd, pa, PTD, PAGE_SIZE) != PAGE_SIZE) { _kvm_err(kd, kd->program, "cannot read PTD"); @@ -279,7 +283,7 @@ _kvm_vatop(kvm_t *kd, u_long va, off_t *pa) #endif pde_pa = ((u_long)pde & PG_FRAME4M) + (va & PAGE4M_MASK); s = _kvm_pa2off(kd, pde_pa, &ofs); - if (s <= sizeof pde) { + if (s < sizeof pde) { _kvm_syserr(kd, kd->program, "_kvm_vatop: pde_pa not found"); goto invalid; @@ -293,7 +297,7 @@ _kvm_vatop(kvm_t *kd, u_long va, off_t *pa) pte_pa = ((u_long)pde & PG_FRAME) + (pteindex * sizeof(pde)); s = _kvm_pa2off(kd, pte_pa, &ofs); - if (s <= sizeof pte) { + if (s < sizeof pte) { _kvm_err(kd, kd->program, "_kvm_vatop: pdpe_pa not found"); goto invalid; } diff --git a/lib/libkvm/kvm_x86_64.c b/lib/libkvm/kvm_x86_64.c index 38593b2071..eb15a91476 100644 --- a/lib/libkvm/kvm_x86_64.c +++ b/lib/libkvm/kvm_x86_64.c @@ -161,6 +161,7 @@ _kvm_initvtop(kvm_t *kd) Elf_Ehdr *ehdr; size_t hdrsz; char minihdr[8]; + struct pcb dumppcb; if (pread(kd->pmfd, &minihdr, 8, 0) == 8) if (memcmp(&minihdr, "minidump", 8) == 0) @@ -176,8 +177,8 @@ _kvm_initvtop(kvm_t *kd) if (_kvm_maphdrs(kd, sizeof(Elf_Ehdr)) == -1) return (-1); /* - * Check if this is indeed an ELF header. If not, assume old style dump or - * memory layout. + * Check if this is indeed an ELF header. If not, assume old style + *dump or memory layout. */ ehdr = kd->vmst->mmapbase; if (!IS_ELF(*ehdr)) { @@ -199,21 +200,23 @@ _kvm_initvtop(kvm_t *kd) } kernbase = nlist[0].n_value; - nlist[0].n_name = "KPML4phys"; + nlist[0].n_name = "dumppcb"; nlist[1].n_name = 0; if (kvm_nlist(kd, nlist) != 0) { - _kvm_err(kd, kd->program, "bad namelist - no KPML4phys"); + _kvm_err(kd, kd->program, "bad namelist - no dumppcb"); return (-1); } - if (kvm_read(kd, (nlist[0].n_value - kernbase), &pa, sizeof(pa)) != - sizeof(pa)) { - _kvm_err(kd, kd->program, "cannot read KPML4phys"); + if (kvm_read(kd, (nlist[0].n_value - kernbase), &dumppcb, + sizeof(dumppcb)) != sizeof(dumppcb)) { + _kvm_err(kd, kd->program, "cannot read dumppcb"); return (-1); } + pa = dumppcb.pcb_cr3 & PG_FRAME; + PML4 = _kvm_malloc(kd, PAGE_SIZE); if (kvm_read(kd, pa, PML4, PAGE_SIZE) != PAGE_SIZE) { - _kvm_err(kd, kd->program, "cannot read KPML4phys"); + _kvm_err(kd, kd->program, "cannot read dumppcb"); return (-1); } kd->vmst->PML4 = PML4; @@ -269,7 +272,7 @@ _kvm_vatop(kvm_t *kd, u_long va, off_t *pa) (pdpeindex * sizeof(pdp_entry_t)); s = _kvm_pa2off(kd, pdpe_pa, &ofs); - if (s <= sizeof pdpe) { + if (s < sizeof pdpe) { _kvm_err(kd, kd->program, "_kvm_vatop: pdpe_pa not found"); goto invalid; } @@ -286,12 +289,11 @@ _kvm_vatop(kvm_t *kd, u_long va, off_t *pa) goto invalid; } - pdeindex = (va >> PDRSHIFT) & (NPDEPG-1); pde_pa = ((u_long)pdpe & PG_FRAME) + (pdeindex * sizeof(pd_entry_t)); s = _kvm_pa2off(kd, pde_pa, &ofs); - if (s <= sizeof pde) { + if (s < sizeof pde) { _kvm_syserr(kd, kd->program, "_kvm_vatop: pde_pa not found"); goto invalid; } @@ -329,7 +331,7 @@ _kvm_vatop(kvm_t *kd, u_long va, off_t *pa) pte_pa = ((u_long)pde & PG_FRAME) + (pteindex * sizeof(pt_entry_t)); s = _kvm_pa2off(kd, pte_pa, &ofs); - if (s <= sizeof pte) { + if (s < sizeof pte) { _kvm_err(kd, kd->program, "_kvm_vatop: pte_pa not found"); goto invalid; } -- 2.11.4.GIT