kvm_powerpc64.c revision 217777
12061Sjkh/*- 236682Sbde * Copyright (c) 2008, Juniper Networks, Inc. 32061Sjkh * All rights reserved. 433611Sjb * 532427Sjb * Redistribution and use in source and binary forms, with or without 632427Sjb * modification, are permitted provided that the following conditions 736111Sjb * are met: 833611Sjb * 1. Redistributions of source code must retain the above copyright 932427Sjb * notice, this list of conditions and the following disclaimer. 1032427Sjb * 2. Redistributions in binary form must reproduce the above copyright 112061Sjkh * notice, this list of conditions and the following disclaimer in the 1215603Smarkm * documentation and/or other materials provided with the distribution. 1330169Sjkh * 3. Neither the name of the author nor the names of any co-contributors 1420710Sasami * may be used to endorse or promote products derived from this software 1520710Sasami * without specific prior written permission. 163197Scsgr * 172061Sjkh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1812483Speter * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1934509Sbde * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 202160Scsgr * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 212834Swollman * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 222061Sjkh * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232061Sjkh * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242160Scsgr * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2517308Speter * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2619320Sadam * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2727788Sasami */ 2830169Sjkh 2925980Sasami#include <sys/cdefs.h> 301594Srgrimes__FBSDID("$FreeBSD: head/lib/libkvm/kvm_powerpc64.c 217777 2011-01-24 11:06:40Z uqs $"); 3117308Speter 3217308Speter#include <sys/param.h> 3327910Sasami#include <sys/endian.h> 3427910Sasami#include <sys/kerneldump.h> 3527910Sasami#include <sys/mman.h> 3617308Speter 3717308Speter#include <vm/vm.h> 3817308Speter 3919175Sbde#include <db.h> 4019175Sbde#include <elf.h> 4119175Sbde#include <limits.h> 4219175Sbde#include <kvm.h> 4317308Speter#include <stdlib.h> 4427910Sasami#include <string.h> 4534509Sbde 4627910Sasami#include "kvm_private.h" 4717308Speter 482061Sjkhstruct vmstate { 492061Sjkh void *map; 501594Srgrimes size_t mapsz; 5130169Sjkh size_t dmphdrsz; 5230169Sjkh Elf64_Ehdr *eh; 5330169Sjkh Elf64_Phdr *ph; 5430169Sjkh}; 5530169Sjkh 5630169Sjkhstatic int 5730169Sjkhvalid_elf_header(Elf64_Ehdr *eh) 5830169Sjkh{ 597407Srgrimes 607108Sphk if (!IS_ELF(*eh)) 617108Sphk return (0); 627108Sphk if (eh->e_ident[EI_CLASS] != ELFCLASS64) 637407Srgrimes return (0); 647407Srgrimes if (eh->e_ident[EI_DATA] != ELFDATA2MSB) 657407Srgrimes return (0); 667108Sphk if (eh->e_ident[EI_VERSION] != EV_CURRENT) 672061Sjkh return (0); 682061Sjkh if (eh->e_ident[EI_OSABI] != ELFOSABI_STANDALONE) 692061Sjkh return (0); 7017308Speter if (be16toh(eh->e_type) != ET_CORE) 712061Sjkh return (0); 722061Sjkh if (be16toh(eh->e_machine) != EM_PPC64) 732061Sjkh return (0); 742061Sjkh /* Can't think of anything else to check... */ 752061Sjkh return (1); 7635427Sbde} 7735427Sbde 7830169Sjkhstatic size_t 792626Scsgrdump_header_size(struct kerneldumpheader *dh) 802061Sjkh{ 812061Sjkh 822061Sjkh if (strcmp(dh->magic, KERNELDUMPMAGIC) != 0) 832061Sjkh return (0); 842061Sjkh if (strcmp(dh->architecture, "powerpc64") != 0) 852061Sjkh return (0); 8619320Sadam /* That should do it... */ 872061Sjkh return (sizeof(*dh)); 882061Sjkh} 892061Sjkh 902061Sjkh/* 912061Sjkh * Map the ELF headers into the process' address space. We do this in two 922061Sjkh * steps: first the ELF header itself and using that information the whole 932061Sjkh * set of headers. 942061Sjkh */ 952061Sjkhstatic int 962061Sjkhpowerpc_maphdrs(kvm_t *kd) 972061Sjkh{ 982834Swollman struct vmstate *vm; 992834Swollman size_t mapsz; 1002834Swollman 1012834Swollman vm = kd->vmst; 1022834Swollman 1032834Swollman vm->mapsz = PAGE_SIZE; 1041594Srgrimes vm->map = mmap(NULL, vm->mapsz, PROT_READ, MAP_PRIVATE, kd->pmfd, 0); 1054486Sphk if (vm->map == MAP_FAILED) { 1064486Sphk _kvm_err(kd, kd->program, "cannot map corefile"); 1074486Sphk return (-1); 1084486Sphk } 1094486Sphk vm->dmphdrsz = 0; 1102061Sjkh vm->eh = vm->map; 1112061Sjkh if (!valid_elf_header(vm->eh)) { 11225979Sjkh /* 11325979Sjkh * Hmmm, no ELF header. Maybe we still have a dump header. 11425979Sjkh * This is normal when the core file wasn't created by 11525979Sjkh * savecore(8), but instead was dumped over TFTP. We can 1162061Sjkh * easily skip the dump header... 11725979Sjkh */ 1182061Sjkh vm->dmphdrsz = dump_header_size(vm->map); 1192061Sjkh if (vm->dmphdrsz == 0) 12017308Speter goto inval; 1212061Sjkh vm->eh = (void *)((uintptr_t)vm->map + vm->dmphdrsz); 1222061Sjkh if (!valid_elf_header(vm->eh)) 1232061Sjkh goto inval; 1242061Sjkh } 1252061Sjkh mapsz = be16toh(vm->eh->e_phentsize) * be16toh(vm->eh->e_phnum) + 12612483Speter be64toh(vm->eh->e_phoff); 12712483Speter munmap(vm->map, vm->mapsz); 12812483Speter 12912483Speter /* Map all headers. */ 1302061Sjkh vm->mapsz = vm->dmphdrsz + mapsz; 13135479Sbde vm->map = mmap(NULL, vm->mapsz, PROT_READ, MAP_PRIVATE, kd->pmfd, 0); 1328854Srgrimes if (vm->map == MAP_FAILED) { 1332061Sjkh _kvm_err(kd, kd->program, "cannot map corefle headers"); 1342061Sjkh return (-1); 13512483Speter } 1362061Sjkh vm->eh = (void *)((uintptr_t)vm->map + vm->dmphdrsz); 13735479Sbde vm->ph = (void *)((uintptr_t)vm->eh + be64toh(vm->eh->e_phoff)); 13835479Sbde return (0); 13935479Sbde 14035479Sbde inval: 14135479Sbde munmap(vm->map, vm->mapsz); 14235479Sbde vm->map = MAP_FAILED; 14335479Sbde _kvm_err(kd, kd->program, "invalid corefile"); 14435479Sbde return (-1); 14535479Sbde} 14635462Sjkh 14735462Sjkh/* 14818714Sache * Determine the offset within the corefile corresponding the virtual 14917308Speter * address. Return the number of contiguous bytes in the corefile or 15034541Sbde * 0 when the virtual address is invalid. 15134575Sbde */ 15234575Sbdestatic size_t 15334575Sbdepowerpc64_va2off(kvm_t *kd, u_long va, off_t *ofs) 15434592Sbde{ 15517308Speter struct vmstate *vm = kd->vmst; 15634575Sbde Elf64_Phdr *ph; 15735427Sbde int nph; 15834575Sbde 15935427Sbde ph = vm->ph; 16034575Sbde nph = be16toh(vm->eh->e_phnum); 16115603Smarkm while (nph && (va < be64toh(ph->p_vaddr) || 16217308Speter va >= be64toh(ph->p_vaddr) + be64toh(ph->p_memsz))) { 16317308Speter nph--; 16417308Speter ph = (void *)((uintptr_t)ph + be16toh(vm->eh->e_phentsize)); 16517308Speter } 16617308Speter if (nph == 0) 16717308Speter return (0); 16817308Speter 16917308Speter /* Segment found. Return file offset and range. */ 17017308Speter *ofs = vm->dmphdrsz + be64toh(ph->p_offset) + 17118362Sjkh (va - be64toh(ph->p_vaddr)); 17219966Sache return (be64toh(ph->p_memsz) - (va - be64toh(ph->p_vaddr))); 17318362Sjkh} 17417308Speter 17527910Sasamivoid 17617308Speter_kvm_freevtop(kvm_t *kd) 17717308Speter{ 17817308Speter struct vmstate *vm = kd->vmst; 17936074Sbde 18027910Sasami if (vm == NULL) 18136074Sbde return; 18236074Sbde 18327910Sasami if (vm->eh != MAP_FAILED) { 18417308Speter munmap(vm->eh, vm->mapsz); 1852061Sjkh vm->eh = MAP_FAILED; 18627910Sasami } 1872061Sjkh free(vm); 18836074Sbde kd->vmst = NULL; 18927910Sasami} 1902061Sjkh 19117308Speterint 19227910Sasami_kvm_initvtop(kvm_t *kd) 19317308Speter{ 19427910Sasami 19527910Sasami kd->vmst = (struct vmstate *)_kvm_malloc(kd, sizeof(*kd->vmst)); 19627910Sasami if (kd->vmst == NULL) { 19717308Speter _kvm_err(kd, kd->program, "out of virtual memory"); 19827910Sasami return (-1); 19917308Speter } 20027910Sasami if (powerpc_maphdrs(kd) == -1) { 20127910Sasami free(kd->vmst); 20227910Sasami kd->vmst = NULL; 20327910Sasami return (-1); 20436622Scharnier } 20536622Scharnier return (0); 20627910Sasami} 20727910Sasami 20827910Sasamiint 20927910Sasami_kvm_kvatop(kvm_t *kd, u_long va, off_t *ofs) 21027910Sasami{ 21127910Sasami struct vmstate *vm; 21234509Sbde 21327910Sasami vm = kd->vmst; 21427910Sasami if (vm->ph->p_paddr == ~0UL) 21527910Sasami return ((int)powerpc64_va2off(kd, va, ofs)); 21636423Speter 21736423Speter _kvm_err(kd, kd->program, "Raw corefile not supported"); 21827910Sasami return (0); 21936423Speter} 22035479Sbde