Changeset View
Changeset View
Standalone View
Standalone View
head/lib/libkvm/kvm_powerpc64.c
Show All 28 Lines | |||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/endian.h> | #include <sys/endian.h> | ||||
#include <sys/kerneldump.h> | #include <sys/kerneldump.h> | ||||
#include <sys/mman.h> | #include <sys/mman.h> | ||||
#include <vm/vm.h> | |||||
#include <db.h> | |||||
#include <elf.h> | #include <elf.h> | ||||
#include <limits.h> | |||||
#include <kvm.h> | #include <kvm.h> | ||||
#include <limits.h> | |||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <string.h> | #include <string.h> | ||||
#include "kvm_private.h" | #include "kvm_private.h" | ||||
struct vmstate { | struct vmstate { | ||||
void *map; | void *map; | ||||
size_t mapsz; | size_t mapsz; | ||||
▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | |||||
static int | static int | ||||
powerpc_maphdrs(kvm_t *kd) | powerpc_maphdrs(kvm_t *kd) | ||||
{ | { | ||||
struct vmstate *vm; | struct vmstate *vm; | ||||
size_t mapsz; | size_t mapsz; | ||||
vm = kd->vmst; | vm = kd->vmst; | ||||
vm->mapsz = PAGE_SIZE; | vm->mapsz = sizeof(*vm->eh) + sizeof(struct kerneldumpheader); | ||||
vm->map = mmap(NULL, vm->mapsz, PROT_READ, MAP_PRIVATE, kd->pmfd, 0); | vm->map = mmap(NULL, vm->mapsz, PROT_READ, MAP_PRIVATE, kd->pmfd, 0); | ||||
if (vm->map == MAP_FAILED) { | if (vm->map == MAP_FAILED) { | ||||
_kvm_err(kd, kd->program, "cannot map corefile"); | _kvm_err(kd, kd->program, "cannot map corefile"); | ||||
return (-1); | return (-1); | ||||
} | } | ||||
vm->dmphdrsz = 0; | vm->dmphdrsz = 0; | ||||
vm->eh = vm->map; | vm->eh = vm->map; | ||||
if (!valid_elf_header(vm->eh)) { | if (!valid_elf_header(vm->eh)) { | ||||
Show All 13 Lines | powerpc_maphdrs(kvm_t *kd) | ||||
mapsz = be16toh(vm->eh->e_phentsize) * be16toh(vm->eh->e_phnum) + | mapsz = be16toh(vm->eh->e_phentsize) * be16toh(vm->eh->e_phnum) + | ||||
be64toh(vm->eh->e_phoff); | be64toh(vm->eh->e_phoff); | ||||
munmap(vm->map, vm->mapsz); | munmap(vm->map, vm->mapsz); | ||||
/* Map all headers. */ | /* Map all headers. */ | ||||
vm->mapsz = vm->dmphdrsz + mapsz; | vm->mapsz = vm->dmphdrsz + mapsz; | ||||
vm->map = mmap(NULL, vm->mapsz, PROT_READ, MAP_PRIVATE, kd->pmfd, 0); | vm->map = mmap(NULL, vm->mapsz, PROT_READ, MAP_PRIVATE, kd->pmfd, 0); | ||||
if (vm->map == MAP_FAILED) { | if (vm->map == MAP_FAILED) { | ||||
_kvm_err(kd, kd->program, "cannot map corefle headers"); | _kvm_err(kd, kd->program, "cannot map corefile headers"); | ||||
return (-1); | return (-1); | ||||
} | } | ||||
vm->eh = (void *)((uintptr_t)vm->map + vm->dmphdrsz); | vm->eh = (void *)((uintptr_t)vm->map + vm->dmphdrsz); | ||||
vm->ph = (void *)((uintptr_t)vm->eh + be64toh(vm->eh->e_phoff)); | vm->ph = (void *)((uintptr_t)vm->eh + | ||||
(uintptr_t)be64toh(vm->eh->e_phoff)); | |||||
return (0); | return (0); | ||||
inval: | inval: | ||||
munmap(vm->map, vm->mapsz); | |||||
vm->map = MAP_FAILED; | |||||
_kvm_err(kd, kd->program, "invalid corefile"); | _kvm_err(kd, kd->program, "invalid corefile"); | ||||
return (-1); | return (-1); | ||||
} | } | ||||
/* | /* | ||||
* Determine the offset within the corefile corresponding the virtual | * Determine the offset within the corefile corresponding the virtual | ||||
* address. Return the number of contiguous bytes in the corefile or | * address. Return the number of contiguous bytes in the corefile or | ||||
* 0 when the virtual address is invalid. | * 0 when the virtual address is invalid. | ||||
*/ | */ | ||||
static size_t | static size_t | ||||
powerpc64_va2off(kvm_t *kd, u_long va, off_t *ofs) | powerpc64_va2off(kvm_t *kd, kvaddr_t va, off_t *ofs) | ||||
{ | { | ||||
struct vmstate *vm = kd->vmst; | struct vmstate *vm = kd->vmst; | ||||
Elf64_Phdr *ph; | Elf64_Phdr *ph; | ||||
int nph; | int nph; | ||||
ph = vm->ph; | ph = vm->ph; | ||||
nph = be16toh(vm->eh->e_phnum); | nph = be16toh(vm->eh->e_phnum); | ||||
while (nph && (va < be64toh(ph->p_vaddr) || | while (nph && (va < be64toh(ph->p_vaddr) || | ||||
va >= be64toh(ph->p_vaddr) + be64toh(ph->p_memsz))) { | va >= be64toh(ph->p_vaddr) + be64toh(ph->p_memsz))) { | ||||
nph--; | nph--; | ||||
ph = (void *)((uintptr_t)ph + be16toh(vm->eh->e_phentsize)); | ph = (void *)((uintptr_t)ph + be16toh(vm->eh->e_phentsize)); | ||||
} | } | ||||
if (nph == 0) | if (nph == 0) | ||||
return (0); | return (0); | ||||
/* Segment found. Return file offset and range. */ | /* Segment found. Return file offset and range. */ | ||||
*ofs = vm->dmphdrsz + be64toh(ph->p_offset) + | *ofs = vm->dmphdrsz + be64toh(ph->p_offset) + | ||||
(va - be64toh(ph->p_vaddr)); | (va - be64toh(ph->p_vaddr)); | ||||
return (be64toh(ph->p_memsz) - (va - be64toh(ph->p_vaddr))); | return (be64toh(ph->p_memsz) - (va - be64toh(ph->p_vaddr))); | ||||
} | } | ||||
void | static void | ||||
_kvm_freevtop(kvm_t *kd) | _powerpc64_freevtop(kvm_t *kd) | ||||
{ | { | ||||
struct vmstate *vm = kd->vmst; | struct vmstate *vm = kd->vmst; | ||||
if (vm == NULL) | if (vm->eh != MAP_FAILED) | ||||
return; | |||||
if (vm->eh != MAP_FAILED) { | |||||
munmap(vm->eh, vm->mapsz); | munmap(vm->eh, vm->mapsz); | ||||
vm->eh = MAP_FAILED; | |||||
} | |||||
free(vm); | free(vm); | ||||
kd->vmst = NULL; | kd->vmst = NULL; | ||||
} | } | ||||
int | static int | ||||
_kvm_initvtop(kvm_t *kd) | _powerpc64_probe(kvm_t *kd) | ||||
{ | { | ||||
return (_kvm_probe_elf_kernel(kd, ELFCLASS64, EM_PPC64) && | |||||
kd->nlehdr.e_ident[EI_DATA] == ELFDATA2MSB); | |||||
} | |||||
static int | |||||
_powerpc64_initvtop(kvm_t *kd) | |||||
{ | |||||
kd->vmst = (struct vmstate *)_kvm_malloc(kd, sizeof(*kd->vmst)); | kd->vmst = (struct vmstate *)_kvm_malloc(kd, sizeof(*kd->vmst)); | ||||
if (kd->vmst == NULL) { | if (kd->vmst == NULL) | ||||
_kvm_err(kd, kd->program, "out of virtual memory"); | |||||
return (-1); | return (-1); | ||||
} | |||||
if (powerpc_maphdrs(kd) == -1) { | if (powerpc_maphdrs(kd) == -1) | ||||
free(kd->vmst); | |||||
kd->vmst = NULL; | |||||
return (-1); | return (-1); | ||||
} | |||||
return (0); | return (0); | ||||
} | } | ||||
int | static int | ||||
_kvm_kvatop(kvm_t *kd, u_long va, off_t *ofs) | _powerpc64_kvatop(kvm_t *kd, kvaddr_t va, off_t *ofs) | ||||
{ | { | ||||
struct vmstate *vm; | struct vmstate *vm; | ||||
vm = kd->vmst; | vm = kd->vmst; | ||||
if (vm->ph->p_paddr == ~0UL) | if (be64toh(vm->ph->p_paddr) == 0xffffffffffffffff) | ||||
return ((int)powerpc64_va2off(kd, va, ofs)); | return ((int)powerpc64_va2off(kd, va, ofs)); | ||||
_kvm_err(kd, kd->program, "Raw corefile not supported"); | _kvm_err(kd, kd->program, "Raw corefile not supported"); | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | |||||
_powerpc64_native(kvm_t *kd) | |||||
{ | |||||
#ifdef __powerpc64__ | |||||
return (1); | |||||
#else | |||||
return (0); | |||||
#endif | |||||
} | |||||
struct kvm_arch kvm_powerpc64 = { | |||||
.ka_probe = _powerpc64_probe, | |||||
.ka_initvtop = _powerpc64_initvtop, | |||||
.ka_freevtop = _powerpc64_freevtop, | |||||
.ka_kvatop = _powerpc64_kvatop, | |||||
.ka_native = _powerpc64_native, | |||||
}; | |||||
KVM_ARCH(kvm_powerpc64); |