Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 24 Jun 2005 16:19:39 GMT
From:      Paul Saab <ps@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 78912 for review
Message-ID:  <200506241619.j5OGJddF058314@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=78912

Change 78912 by ps@butter.corp on 2005/06/24 16:19:25

	checkpoint for new elf crashdump parsing.  This does not
	support PAE yet.

Affected files ...

.. //depot/projects/hammer/lib/libkvm/kvm_i386.c#2 edit

Differences ...

==== //depot/projects/hammer/lib/libkvm/kvm_i386.c#2 (text+ko) ====

@@ -53,6 +53,7 @@
 #include <sys/user.h>
 #include <sys/proc.h>
 #include <sys/stat.h>
+#include <sys/mman.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <nlist.h>
@@ -61,6 +62,8 @@
 #include <vm/vm.h>
 #include <vm/vm_param.h>
 
+#include <machine/elf.h>
+
 #include <limits.h>
 
 #include "kvm_private.h"
@@ -71,36 +74,98 @@
 #endif
 
 struct vmstate {
+	void		*mmapbase;
+	size_t		mmapsize;
 	pd_entry_t	*PTD;
 };
 
+/*
+ * Map the ELF headers into the process' address space. We do this in two
+ * steps: first the ELF header itself and using that information the whole
+ * set of headers. (Taken from kvm_ia64.c)
+ */
+static int
+_kvm_maphdrs(kvm_t *kd, size_t sz)
+{
+	struct vmstate *vm = kd->vmst;
+
+	/* munmap() previous mmap(). */
+	if (vm->mmapbase != NULL) {
+		munmap(vm->mmapbase, vm->mmapsize);
+		vm->mmapbase = NULL;
+	}
+
+	vm->mmapsize = sz;
+	vm->mmapbase = mmap(NULL, sz, PROT_READ, MAP_PRIVATE, kd->pmfd, 0);
+	if (vm->mmapbase == MAP_FAILED) {
+		_kvm_err(kd, kd->program, "cannot mmap corefile");
+		return (-1);
+	}
+	return (0);
+}
+
+/*
+ * Translate a physical memory address to a file-offset in the crash-dump.
+ * (Taken from kvm_ia64.c)
+ */
+static size_t
+_kvm_pa2off(kvm_t *kd, uint64_t pa, u_long *ofs)
+{
+	Elf_Ehdr *e = kd->vmst->mmapbase;
+	Elf_Phdr *p = (Elf_Phdr*)((char*)e + e->e_phoff);
+	int n = e->e_phnum;
+
+	while (n && (pa < p->p_paddr || pa >= p->p_paddr + p->p_memsz)) {
+printf("%d %.8x %.8x %.8x\n", n, pa, p->p_paddr, p->p_paddr + p->p_memsz);
+		p++, n--;
+	}
+printf("%d %.8x %.8x %.8x\n", n, pa, p->p_paddr, p->p_paddr + p->p_memsz);
+
+	if (n == 0)
+		return (0);
+
+	*ofs = (pa - p->p_paddr) + p->p_offset;
+	return (PAGE_SIZE - ((size_t)pa & PAGE_MASK));
+}
+
 void
 _kvm_freevtop(kvm_t *kd)
 {
-	if (kd->vmst != 0) {
-		if (kd->vmst->PTD) {
-			free(kd->vmst->PTD);
-		}
-		free(kd->vmst);
-	}
+	struct vmstate *vm = kd->vmst;
+
+	if (vm->mmapbase != NULL)
+		munmap(vm->mmapbase, vm->mmapsize);
+
+	if (vm->PTD)
+		free(vm->PTD);
+	free(vm);
+	kd->vmst = NULL;
 }
 
 int
 _kvm_initvtop(kvm_t *kd)
 {
-	struct vmstate *vm;
 	struct nlist nlist[2];
 	u_long pa;
 	u_long kernbase;
 	pd_entry_t	*PTD;
+	Elf_Ehdr	*ehdr;
+	size_t		hdrsz;
 
-	vm = (struct vmstate *)_kvm_malloc(kd, sizeof(*vm));
-	if (vm == 0) {
+	kd->vmst = (struct vmstate *)_kvm_malloc(kd, sizeof(*kd->vmst));
+	if (kd->vmst == 0) {
 		_kvm_err(kd, kd->program, "cannot allocate vm");
 		return (-1);
 	}
-	kd->vmst = vm;
-	vm->PTD = 0;
+	kd->vmst->PTD = 0;
+
+	if (_kvm_maphdrs(kd, sizeof(Elf_Ehdr)) == -1)
+		return (-1);
+
+	ehdr = kd->vmst->mmapbase;
+	hdrsz = ehdr->e_phoff + ehdr->e_phentsize * ehdr->e_phnum;
+	if (_kvm_maphdrs(kd, hdrsz) == -1)
+		return (-1);
 
 	nlist[0].n_name = "kernbase";
 	nlist[1].n_name = 0;
@@ -127,21 +192,24 @@
 		_kvm_err(kd, kd->program, "cannot read PTD");
 		return (-1);
 	}
-	vm->PTD = PTD;
+	kd->vmst->PTD = PTD;
 	return (0);
 }
 
-static int
-_kvm_vatop(kvm_t *kd, u_long va, u_long *pa)
+int
+_kvm_kvatop(kvm_t *kd, u_long va, u_long *pa)
 {
 	struct vmstate *vm;
 	u_long offset;
 	u_long pte_pa;
+	u_long pde_pa;
 	pd_entry_t pde;
 	pt_entry_t pte;
 	u_long pdeindex;
 	u_long pteindex;
-	int i;
+	size_t s;
+	u_long a, ofs;
+
 
 	if (ISALIVE(kd)) {
 		_kvm_err(kd, 0, "vatop called in live kernel!");
@@ -156,8 +224,13 @@
 	 * not yet set) then return pa == va to avoid infinite recursion.
 	 */
 	if (vm->PTD == 0) {
-		*pa = va;
-		return (PAGE_SIZE - offset);
+		s = _kvm_pa2off(kd, va, pa);
+		if (s == 0) {
+			_kvm_err(kd, kd->program, 
+			    "_kvm_kvatop: bootstrap data not in dump");
+			goto invalid;
+		} else
+			return (PAGE_SIZE - offset);
 	}
 
 	pdeindex = va >> PDRSHIFT;
@@ -174,15 +247,27 @@
 	       */
 #define	PAGE4M_MASK	(NBPDR - 1)
 #define	PG_FRAME4M	(~PAGE4M_MASK)
-		*pa = ((u_long)pde & PG_FRAME4M) + (va & PAGE4M_MASK);
+		pde_pa = ((u_long)pde & PG_FRAME4M) + (va & PAGE4M_MASK);
+		s = _kvm_pa2off(kd, pde_pa, &ofs);
+		if (s <= sizeof pde) {
+			_kvm_syserr(kd, kd->program, "_kvm_kvatop: pde_pa not found");
+			goto invalid;
+		}
+		*pa = ofs;
 		return (NBPDR - (va & PAGE4M_MASK));
 	}
 
 	pteindex = (va >> PAGE_SHIFT) & (NPTEPG-1);
 	pte_pa = ((u_long)pde & PG_FRAME) + (pteindex * sizeof(pt_entry_t));
 
+	s = _kvm_pa2off(kd, pte_pa, &ofs);
+	if (s <= sizeof pte) {
+		_kvm_err(kd, kd->program, "_kvm_kvatop: pdpe_pa not found");
+		goto invalid;
+	}
+
 	/* XXX This has to be a physical address read, kvm_read is virtual */
-	if (lseek(kd->pmfd, pte_pa, 0) == -1) {
+	if (lseek(kd->pmfd, ofs, 0) == -1) {
 		_kvm_syserr(kd, kd->program, "_kvm_vatop: lseek");
 		goto invalid;
 	}
@@ -193,16 +278,15 @@
 	if (((u_long)pte & PG_V) == 0)
 		goto invalid;
 
-	*pa = ((u_long)pte & PG_FRAME) + offset;
-	return (PAGE_SIZE - offset);
+	a = ((u_long)pte & PG_FRAME) + offset;
+	s =_kvm_pa2off(kd, a, pa);
+	if (s == 0) {
+		_kvm_err(kd, kd->program, "_kvm_kvatop: address not in dump");
+		goto invalid;
+	} else
+		return (PAGE_SIZE - offset);
 
 invalid:
 	_kvm_err(kd, 0, "invalid address (%x)", va);
 	return (0);
 }
-
-int
-_kvm_kvatop(kvm_t *kd, u_long va, u_long *pa)
-{
-	return (_kvm_vatop(kd, va, pa));
-}



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200506241619.j5OGJddF058314>