/* ** kvm.c A set of functions emulating KVM for machines without them. ** ** This code is in the public domain and may be used freely by anyone ** who wants to. ** ** Last update: 12 Dec 1992 ** ** Author: Peter Eriksson */ #ifndef NO_KVM #ifndef HAVE_KVM #ifdef NeXT31 # include #endif #include #include #include #ifdef IRIX # ifdef IRIX62 # if _MIPS_SZPTR == 64 # define _K64U64 1 # else # define _K32U32 1 # endif # endif # include # ifndef K0_TO_PHYS # define K0_TO_PHYS(x) (x) # endif # if defined(IRIX6) || (defined(IRIX62) && _MIPS_SZPTR == 64) # define nlist nlist64 # endif #endif #ifdef BSD43 # include # include # include # include #if 0 # include #else # include #endif # ifdef DIRBLKSIZ # undef DIRBLKSIZ # endif #if 0 # include #endif # include # include # include "paths.h" #endif #include "kernel/kvm.h" #include "paths.h" #if defined(BSD43) || defined(MIPS) extern int errno; #endif extern void *malloc(); kvm_t *kvm_open(namelist, corefile, swapfile, flag, errstr) char *namelist; char *corefile; char *swapfile; int flag; char *errstr; { kvm_t *kd; if (!namelist) namelist = _PATH_UNIX; if (!corefile) corefile = _PATH_KMEM; #ifdef BSD43 if (!swapfile) swapfile = _PATH_SWAP; #endif kd = (kvm_t *) malloc(sizeof(kvm_t)); if (!kd) { if (errstr) perror(errstr); return NULL; } kd->namelist = (char *) malloc(strlen(namelist)+1); if (!kd->namelist) { if (errstr) perror(errstr); return NULL; } if ((kd->fd = open(corefile, flag)) < 0) { if (errstr) perror(errstr); free(kd->namelist); free(kd); return NULL; } #ifdef BSD43 if ((kd->swap_fd = open(swapfile, flag)) < 0) { if (errstr) perror(errstr); close(kd->fd); free(kd->namelist); free(kd); return NULL; } if ((kd->mem_fd = open(_PATH_MEM, flag)) < 0) { if (errstr) perror(errstr); close(kd->swap_fd); close(kd->fd); free(kd->namelist); free(kd); return NULL; } #endif strcpy(kd->namelist, namelist); return kd; } int kvm_close(kd) kvm_t *kd; { int code; code = close(kd->fd); #ifdef BSD43 close(kd->swap_fd); close(kd->mem_fd); if (kd->proctab) free(kd->proctab); #endif free(kd->namelist); free(kd); return code; } /* ** Extract offsets to the symbols in the 'nl' list. Returns 0 if all found, ** or else the number of variables that was not found. */ int kvm_nlist(kd, nl) kvm_t *kd; struct nlist *nl; { int code; int i; code = nlist(kd->namelist, nl); if (code != 0) return code; /* ** Verify that we got all the needed variables. Needed because some ** implementations of nlist() returns 0 although it didn't find all ** variables. */ if (code == 0) { #if defined(__convex__) || defined(NeXT) for (i = 0; nl[i].n_un.n_name && nl[i].n_un.n_name[0]; i++) #else for (i = 0; nl[i].n_name && nl[i].n_name[0]; i++) #endif #if defined(_AUX_SOURCE) || defined(_CRAY) || defined(sco) || defined(_SEQUENT_) /* A/UX sets n_type to 0 if not compiled with -g. n_value will still ** contain the (correct?) value (unless symbol unknown). */ if( nl[i].n_value == 0) code++; #else if (nl[i].n_type == 0) code++; #endif } return code; } /* ** Get a piece of the kernel memory */ static int readbuf(fd, addr, buf, len) int fd; long addr; char *buf; int len; { #ifdef IRIX addr = K0_TO_PHYS(addr); #endif errno = 0; #if defined(__alpha) /* * Let us be paranoid about return values. * It should be like this on all implementations, * but some may have broken lseek or read returns. */ if (lseek(fd, addr, 0) != addr || errno != 0) return -1; if (read(fd, buf, len) != len || errno != 0) return -1; return len; #else if (lseek(fd, addr, 0) == -1 && errno != 0) return -1; return read(fd, buf, len); #endif } int kvm_read(kd, addr, buf, len) kvm_t *kd; long addr; char *buf; int len; { return readbuf(kd->fd, addr, buf, len); } #ifdef BSD43 struct user *kvm_getu(kd, procp) kvm_t *kd; struct proc *procp; { static union { struct user user; char upages[UPAGES][NBPG]; } userb; int ncl; struct pte *pteaddr, apte; struct pte arguutl[UPAGES+CLSIZE]; if ((procp->p_flag & SLOAD) == 0) { if(readbuf(kd->swap_fd, dtob(procp->p_swaddr), &userb.user, sizeof(struct user)) < 0) return NULL; } else { /* ** Sigh. I just *love* hard coded variable names in macros... */ { struct pte *usrpt = kd->usrpt; pteaddr = &kd->Usrptma[btokmx(procp->p_p0br) + procp->p_szpt - 1]; if (readbuf(kd->fd, pteaddr, &apte, sizeof(apte)) < 0) return NULL; } if (readbuf(kd->mem_fd, ctob(apte.pg_pfnum+1)-(UPAGES+CLSIZE)*sizeof(struct pte), arguutl, sizeof(arguutl)) < 0) return NULL; ncl = (sizeof(struct user) + NBPG*CLSIZE - 1) / (NBPG*CLSIZE); while (--ncl >= 0) { int i; i = ncl * CLSIZE; if(readbuf(kd->mem_fd, ctob(arguutl[CLSIZE+i].pg_pfnum), userb.upages[i], CLSIZE*NBPG) < 0) return NULL; } } return &userb.user; } struct proc *kvm_nextproc(kd) kvm_t *kd; { if (kd->proctab == NULL) if (kvm_setproc(kd) < 0) return NULL; if (kd->procidx < kd->nproc) return &kd->proctab[kd->procidx++]; return (struct proc *) NULL; } int kvm_setproc(kd) kvm_t *kd; { long procaddr; static struct nlist nl[] = { #define N_PROC 0 #define N_USRPTMA 1 #define N_NPROC 2 #define N_USRPT 3 { "_proc" }, { "_Usrptmap" }, { "_nproc" }, { "_usrpt" }, { "" } }; if (kvm_nlist(kd, nl) != 0) return -1; kd->Usrptma = (struct pte *) nl[N_USRPTMA].n_value; kd->usrpt = (struct pte *) nl[N_USRPT].n_value; if (readbuf(kd->fd, nl[N_NPROC].n_value, &kd->nproc, sizeof(kd->nproc)) < 0) return -1; if (readbuf(kd->fd, nl[N_PROC].n_value, &procaddr, sizeof(procaddr)) < 0) return -1; if (kd->proctab) free(kd->proctab); kd->proctab = (struct proc *) calloc(kd->nproc, sizeof(struct proc)); if (!kd->proctab) return -1; if (readbuf(kd->fd, procaddr, kd->proctab, kd->nproc*sizeof(struct proc)) < 0) return -1; kd->procidx = 0; return 0; } struct proc *kvm_getproc(kd, pid) kvm_t *kd; int pid; { struct proc *procp; if (kvm_setproc(kd) < 0) return NULL; while ((procp = kvm_nextproc(kd)) && procp->p_pid != pid) ; return procp; } #endif #else /* Just to make some compilers shut up! */ int kvm_dummy() { return 1; } #endif #endif