summaryrefslogtreecommitdiffstats
path: root/lib/libkvm/kvm_sparc64.c
diff options
context:
space:
mode:
authortmm <tmm@FreeBSD.org>2002-10-20 17:06:50 +0000
committertmm <tmm@FreeBSD.org>2002-10-20 17:06:50 +0000
commit2e1d70d9a2701426ec9036d59f68181888ccc3c1 (patch)
tree70d0c003a63dc91199eab53d83ebaf8a22cf8c2b /lib/libkvm/kvm_sparc64.c
parent5c94fe601cff39fd3c7165b483c3718013206cd8 (diff)
downloadFreeBSD-src-2e1d70d9a2701426ec9036d59f68181888ccc3c1.zip
FreeBSD-src-2e1d70d9a2701426ec9036d59f68181888ccc3c1.tar.gz
Adapt to handle the new sparc64 core dump format correctly.
Reviewed by: jake
Diffstat (limited to 'lib/libkvm/kvm_sparc64.c')
-rw-r--r--lib/libkvm/kvm_sparc64.c127
1 files changed, 95 insertions, 32 deletions
diff --git a/lib/libkvm/kvm_sparc64.c b/lib/libkvm/kvm_sparc64.c
index 435eb43..081ddf8 100644
--- a/lib/libkvm/kvm_sparc64.c
+++ b/lib/libkvm/kvm_sparc64.c
@@ -62,6 +62,7 @@ static char sccsid[] = "@(#)kvm_hp300.c 8.1 (Berkeley) 6/4/93";
#include <vm/vm.h>
#include <vm/vm_param.h>
+#include <machine/kerneldump.h>
#include <machine/tte.h>
#include <machine/tsb.h>
@@ -75,23 +76,78 @@ static char sccsid[] = "@(#)kvm_hp300.c 8.1 (Berkeley) 6/4/93";
#endif
struct vmstate {
- vm_offset_t vm_tsb;
+ off_t vm_tsb_off;
vm_size_t vm_tsb_mask;
+ int vm_nregions;
+ struct sparc64_dump_reg *vm_regions;
};
void
_kvm_freevtop(kvm_t *kd)
{
if (kd->vmst != 0) {
+ free(kd->vmst->vm_regions);
free(kd->vmst);
}
}
+static int
+_kvm_read_phys(kvm_t *kd, off_t pos, void *buf, size_t size)
+{
+
+ /* XXX This has to be a raw file read, kvm_read is virtual. */
+ if (lseek(kd->pmfd, pos, SEEK_SET) == -1) {
+ _kvm_syserr(kd, kd->program, "_kvm_read_phys: lseek");
+ return (0);
+ }
+ if (read(kd->pmfd, buf, size) != size) {
+ _kvm_syserr(kd, kd->program, "_kvm_read_phys: read");
+ return (0);
+ }
+ return (1);
+}
+
+static int
+_kvm_reg_cmp(const void *a, const void *b)
+{
+ const struct sparc64_dump_reg *ra, *rb;
+
+ ra = a;
+ rb = b;
+ if (ra->dr_pa < rb->dr_pa)
+ return (-1);
+ else if (ra->dr_pa >= rb->dr_pa + rb->dr_size)
+ return (1);
+ else
+ return (0);
+}
+
+#define KVM_OFF_NOTFOUND 0
+
+static off_t
+_kvm_find_off(struct vmstate *vm, vm_offset_t pa, vm_size_t size)
+{
+ struct sparc64_dump_reg *reg, key;
+ vm_offset_t o;
+
+ key.dr_pa = pa;
+ reg = bsearch(&key, vm->vm_regions, vm->vm_nregions,
+ sizeof(*vm->vm_regions), _kvm_reg_cmp);
+ if (reg == NULL)
+ return (KVM_OFF_NOTFOUND);
+ o = pa - reg->dr_pa;
+ if (o + size > reg->dr_size)
+ return (KVM_OFF_NOTFOUND);
+ return (reg->dr_offs + o);
+}
+
int
_kvm_initvtop(kvm_t *kd)
{
- struct nlist nlist[2];
+ struct sparc64_dump_hdr hdr;
+ struct sparc64_dump_reg *regs;
struct vmstate *vm;
+ size_t regsz;
vm_offset_t pa;
vm_size_t mask;
@@ -101,25 +157,36 @@ _kvm_initvtop(kvm_t *kd)
return (-1);
}
kd->vmst = vm;
- vm->vm_tsb = 0;
- nlist[0].n_name = "tsb_kernel_phys";
- nlist[1].n_name = "tsb_kernel_mask";
- nlist[2].n_name = 0;
+ if (!_kvm_read_phys(kd, 0, &hdr, sizeof(hdr)))
+ goto fail_vm;
+ pa = hdr.dh_tsb_pa;
- if (kvm_nlist(kd, nlist) != 0) {
- _kvm_err(kd, kd->program, "bad namelist");
- return (-1);
+ regsz = hdr.dh_nregions * sizeof(*regs);
+ regs = _kvm_malloc(kd, regsz);
+ if (regs == NULL) {
+ _kvm_err(kd, kd->program, "cannot allocate regions");
+ goto fail_vm;
}
- if (kvm_read(kd, nlist[0].n_value, &pa, sizeof(pa)) != sizeof(pa) ||
- kvm_read(kd, nlist[1].n_value, &mask, sizeof(mask)) !=
- sizeof(mask)) {
- _kvm_err(kd, kd->program, "cannot read tsb_kernel_phys");
- return (-1);
+ if (!_kvm_read_phys(kd, sizeof(hdr), regs, regsz))
+ goto fail_regs;
+ qsort(regs, hdr.dh_nregions, sizeof(*regs), _kvm_reg_cmp);
+
+ vm->vm_tsb_mask = hdr.dh_tsb_mask;
+ vm->vm_regions = regs;
+ vm->vm_nregions = hdr.dh_nregions;
+ vm->vm_tsb_off = _kvm_find_off(vm, hdr.dh_tsb_pa, hdr.dh_tsb_size);
+ if (vm->vm_tsb_off == KVM_OFF_NOTFOUND) {
+ _kvm_err(kd, kd->program, "tsb not found in dump");
+ goto fail_regs;
}
- vm->vm_tsb = pa;
- vm->vm_tsb_mask = mask;
return (0);
+
+fail_regs:
+ free(regs);
+fail_vm:
+ free(vm);
+ return (-1);
}
int
@@ -127,29 +194,25 @@ _kvm_kvatop(kvm_t *kd, u_long va, u_long *pa)
{
struct vmstate *vm;
struct tte tte;
- u_long offset;
- u_long tte_pa;
- u_long vpn;
+ off_t tte_off, pa_off;
+ u_long pg_off, vpn;
+ int rest;
vpn = btop(va);
- offset = va & PAGE_MASK;
- tte_pa = kd->vmst->vm_tsb +
+ pg_off = va & PAGE_MASK;
+ tte_off = kd->vmst->vm_tsb_off +
((vpn & kd->vmst->vm_tsb_mask) << TTE_SHIFT);
- /* XXX This has to be a physical address read, kvm_read is virtual */
- if (lseek(kd->pmfd, tte_pa, 0) == -1) {
- _kvm_syserr(kd, kd->program, "_kvm_vatop: lseek");
+ if (!_kvm_read_phys(kd, tte_off, &tte, sizeof(tte)))
goto invalid;
- }
- if (read(kd->pmfd, &tte, sizeof(tte)) != sizeof(tte)) {
- _kvm_syserr(kd, kd->program, "_kvm_vatop: read");
- goto invalid;
- }
if (!tte_match(&tte, va))
goto invalid;
-
- *pa = TTE_GET_PA(&tte) + offset;
- return (PAGE_SIZE - offset);
+ rest = PAGE_SIZE - pg_off;
+ pa_off = _kvm_find_off(kd->vmst, TTE_GET_PA(&tte), rest);
+ if (pa_off == KVM_OFF_NOTFOUND)
+ goto invalid;
+ *pa = pa_off + pg_off;
+ return (rest);
invalid:
_kvm_err(kd, 0, "invalid address (%x)", va);
OpenPOWER on IntegriCloud