Adapt to handle the new sparc64 core dump format correctly.

Reviewed by:	jake
This commit is contained in:
tmm 2002-10-20 17:06:50 +00:00
parent 5c94fe601c
commit 2e1d70d9a2

View File

@ -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);