From: David van Moolenbroek Date: Wed, 28 Oct 2015 17:52:48 +0000 (+0000) Subject: Import NetBSD libkvm X-Git-Url: http://zhaoyanbai.com/repos/%22http:/www.isc.org/icons/zpipe.c?a=commitdiff_plain;h=9da227510d14c35cccbd92c6a9e316b4079c4911;p=minix.git Import NetBSD libkvm Imported with no changes, but not all parts are expected to be functional. The libc nlist functionality is enabled for the purpose of successful linking, although the nlist functionaly has not been tested on MINIX3 nor is it needed for how we use libkvm. In terms of function calls: kvm_getproc2, kvm_getargv2, kvm_getenvv2, and kvm_getlwps are expected to work, whereas kvm_getproc, kvm_getargv, kvm_getenvv, and kvm_getfiles are not. Change-Id: I7539209736f1771fc0b7db5e839d2df72f5ac615 --- diff --git a/distrib/sets/lists/minix-base/mi b/distrib/sets/lists/minix-base/mi index 267a606b8..d9c86886c 100644 --- a/distrib/sets/lists/minix-base/mi +++ b/distrib/sets/lists/minix-base/mi @@ -711,6 +711,9 @@ ./usr/lib/libgcc_s.so minix-base ./usr/lib/libgcc_s.so.1 minix-base ./usr/lib/libgcc_s.so.1.0 minix-base +./usr/lib/libkvm.so minix-base +./usr/lib/libkvm.so.6 minix-base +./usr/lib/libkvm.so.6.0 minix-base ./usr/lib/liblua.so minix-base ./usr/lib/liblua.so.1.0 minix-base obsolete ./usr/lib/liblua.so.1 minix-base obsolete diff --git a/distrib/sets/lists/minix-comp/mi b/distrib/sets/lists/minix-comp/mi index 9ba9837a1..3b2d39e9b 100644 --- a/distrib/sets/lists/minix-comp/mi +++ b/distrib/sets/lists/minix-comp/mi @@ -1844,6 +1844,7 @@ ./usr/lib/bc/libhgfs.a minix-comp bitcode ./usr/lib/bc/libiberty.a minix-comp bitcode,binutils ./usr/lib/bc/libinputdriver.a minix-comp bitcode +./usr/lib/bc/libkvm.a minix-comp bitcode ./usr/lib/bc/libl.a minix-comp bitcode ./usr/lib/bc/liblua.a minix-comp bitcode ./usr/lib/bc/liblwip.a minix-comp bitcode @@ -1939,6 +1940,8 @@ ./usr/lib/libgcov.a minix-comp gcc=45,!gcccmds ./usr/lib/libinputdriver.a minix-comp ./usr/lib/libinputdriver_pic.a minix-comp +./usr/lib/libkvm.a minix-comp +./usr/lib/libkvm_pic.a minix-comp ./usr/lib/libl.a minix-comp ./usr/lib/liblua.a minix-comp ./usr/lib/liblua_pic.a minix-comp diff --git a/distrib/sets/lists/minix-man/mi b/distrib/sets/lists/minix-man/mi index 392acc80d..1f74dd21d 100644 --- a/distrib/sets/lists/minix-man/mi +++ b/distrib/sets/lists/minix-man/mi @@ -2049,6 +2049,28 @@ ./usr/man/man3/keypad.3 minix-man ./usr/man/man3/killchar.3 minix-man ./usr/man/man3/killpg.3 minix-man +./usr/man/man3/kvm.3 minix-man +./usr/man/man3/kvm_close.3 minix-man +./usr/man/man3/kvm_dump.3 minix-man +./usr/man/man3/kvm_dump_inval.3 minix-man +./usr/man/man3/kvm_dump_mkheader.3 minix-man +./usr/man/man3/kvm_dump_wrtheader.3 minix-man +./usr/man/man3/kvm_getargv.3 minix-man +./usr/man/man3/kvm_getargv2.3 minix-man +./usr/man/man3/kvm_getenvv.3 minix-man +./usr/man/man3/kvm_getenvv2.3 minix-man +./usr/man/man3/kvm_geterr.3 minix-man +./usr/man/man3/kvm_getfiles.3 minix-man +./usr/man/man3/kvm_getkernelname.3 minix-man +./usr/man/man3/kvm_getloadavg.3 minix-man +./usr/man/man3/kvm_getlwps.3 minix-man +./usr/man/man3/kvm_getproc2.3 minix-man +./usr/man/man3/kvm_getprocs.3 minix-man +./usr/man/man3/kvm_nlist.3 minix-man +./usr/man/man3/kvm_open.3 minix-man +./usr/man/man3/kvm_openfiles.3 minix-man +./usr/man/man3/kvm_read.3 minix-man +./usr/man/man3/kvm_write.3 minix-man ./usr/man/man3/l64a.3 minix-man ./usr/man/man3/l64a_r.3 minix-man ./usr/man/man3/labs.3 minix-man diff --git a/lib/Makefile b/lib/Makefile index 2bb912706..0987a8f4f 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -78,7 +78,7 @@ SUBDIR+= ../minix/lib/libmagicrt SUBDIR+= \ libbz2 \ libcrypt \ - libm \ + libkvm libm \ libpci libprop \ libpuffs librmt \ libterminfo \ diff --git a/lib/libc/gen/Makefile.inc b/lib/libc/gen/Makefile.inc index 07768bf74..888294229 100644 --- a/lib/libc/gen/Makefile.inc +++ b/lib/libc/gen/Makefile.inc @@ -23,9 +23,6 @@ SRCS+= _errno.c # closefrom.c confstr.c extattr.c \ # pthread_atfork.c # -# To be ported -# nlist.c nlist_aout.c nlist_coff.c nlist_ecoff.c nlist_elf32.c nlist_elf64.c -# # Not useful but portable # disklabel.c @@ -43,8 +40,8 @@ SRCS+= alarm.c alphasort.c arc4random.c assert.c asysctl.c \ getpass.c getprogname.c getpwent.c getttyent.c \ getusershell.c glob.c humanize_number.c initdir.c initgroups.c \ isascii.c isatty.c isctype.c lockf.c nftw.c \ - nice.c \ - opendir.c pause.c popen.c posix_spawn_sched.c \ + nice.c nlist.c nlist_aout.c nlist_coff.c nlist_ecoff.c nlist_elf32.c \ + nlist_elf64.c opendir.c pause.c popen.c posix_spawn_sched.c \ posix_spawn_fileactions.c posix_spawnp.c psignal.c \ ptree.c pwcache.c pw_scan.c raise.c randomid.c rb.c readdir.c \ rewinddir.c scandir.c seekdir.c setdomainname.c \ diff --git a/lib/libkvm/Makefile b/lib/libkvm/Makefile new file mode 100644 index 000000000..2678c1101 --- /dev/null +++ b/lib/libkvm/Makefile @@ -0,0 +1,74 @@ +# $NetBSD: Makefile,v 1.50 2014/08/10 23:39:08 matt Exp $ +# from: @(#)Makefile 8.1 (Berkeley) 6/4/93 + +WARNS= 3 + +USE_FORT?= yes # used primarily by setgid programs + +USE_SHLIBDIR= yes + +LIB= kvm +CPPFLAGS+=-DLIBC_SCCS -I${NETBSDSRCDIR}/sys -D_KMEMUSER + +SRCS= kvm.c kvm_file.c kvm_getloadavg.c kvm_proc.c + +# This library should compile to the same thing on all variants of +# ${MACHINE} with the same ${MACHINE_ARCH} so shared /usr works. +# If it is necessary to run different code based on ${MACHINE} then +# the dispatch on ${MACHINE} should be done at run time (see m68k). + +.include +.if exists(kvm_${KVM_MACHINE_ARCH}.c) +SRCS+= kvm_${KVM_MACHINE_ARCH}.c +.elif exists(kvm_${KVM_MACHINE_CPU}.c) +SRCS+= kvm_${KVM_MACHINE_CPU}.c +.elif exists(kvm_${MACHINE_ARCH}.c) +SRCS+= kvm_${MACHINE_ARCH}.c +.elif exists(kvm_${MACHINE_CPU}.c) +SRCS+= kvm_${MACHINE_CPU}.c +.else +.BEGIN: + @echo no kvm_xx.c for ${MACHINE_ARCH} nor ${MACHINE_CPU} + @false +.endif + +.if ${MACHINE_ARCH} == "i386" +LINTFLAGS+=-w +SRCS+= kvm_i386pae.c # Hook PAE support in the i386 build +.endif + +# Additional modules needed for m68k +.if (${MACHINE_ARCH} == "m68k" || ${MACHINE_CPU} == "m68k") +SRCS+= kvm_m68k_cmn.c kvm_sun2.c kvm_sun3.c kvm_sun3x.c +.endif + +MAN= kvm.3 kvm_dump.3 kvm_geterr.3 kvm_getfiles.3 kvm_getloadavg.3 \ + kvm_getkernelname.3 \ + kvm_getprocs.3 kvm_nlist.3 kvm_open.3 kvm_read.3 kvm_getlwps.3 + +MLINKS+=kvm_getprocs.3 kvm_getargv.3 kvm_getprocs.3 kvm_getenvv.3 +MLINKS+=kvm_getprocs.3 kvm_getproc2.3 +MLINKS+=kvm_getprocs.3 kvm_getargv2.3 kvm_getprocs.3 kvm_getenvv2.3 +MLINKS+=kvm_open.3 kvm_openfiles.3 kvm_open.3 kvm_close.3 +MLINKS+=kvm_read.3 kvm_write.3 +MLINKS+=kvm_dump.3 kvm_dump_mkheader.3 kvm_dump.3 kvm_dump_wrtheader.3 +MLINKS+=kvm_dump.3 kvm_dump_inval.3 + +# This fixes building with MACHINE==sparc64, MACHINE_ARCH==sparc +# XXX: this is a hack, but until the sparc MD headers are separated +# out from the sparc AD headers, it's the easiest solution. +# +.if (${MACHINE_ARCH} == "sparc") # { +.if !make(obj) && !make(clean) && !make(cleandir) +.BEGIN: + @([ -h machine ] || \ + ln -fs ${NETBSDSRCDIR}/sys/arch/sparc/include machine) + @([ -h sparc ] || ln -fs ${NETBSDSRCDIR}/sys/arch/sparc/include sparc) +.NOPATH: machine sparc +.endif +CLEANFILES+= machine sparc +CPPFLAGS+= -I. +.endif # } + + +.include diff --git a/lib/libkvm/kvm.3 b/lib/libkvm/kvm.3 new file mode 100644 index 000000000..acf2f4a44 --- /dev/null +++ b/lib/libkvm/kvm.3 @@ -0,0 +1,110 @@ +.\" $NetBSD: kvm.3,v 1.13 2011/09/13 08:53:15 wiz Exp $ +.\" +.\" Copyright (c) 1992, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software developed by the Computer Systems +.\" Engineering group at Lawrence Berkeley Laboratory under DARPA contract +.\" BG 91-66 and contributed to Berkeley. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)kvm.3 8.1 (Berkeley) 6/4/93 +.\" +.Dd September 14, 2011 +.Dt KVM 3 +.Os +.Sh NAME +.Nm kvm +.Nd kernel memory interface +.Sh LIBRARY +.Lb libkvm +.Sh DESCRIPTION +The +.Nm +library provides a uniform interface for accessing kernel virtual memory +images, including live systems and crash dumps. +Access to live systems is via +.Pa /dev/mem +while crash dumps can be examined via the core file generated by +.Xr savecore 8 . +The interface behaves identically in both cases. +Memory can be read and written, kernel symbol addresses can be +looked up efficiently, and information about user processes can +be gathered. +.Pp +.Fn kvm_open +is first called to obtain a descriptor for all subsequent calls. +.Sh FILES +.Bl -tag -width /dev/mem -compact +.It Pa /dev/mem +interface to physical memory +.El +.Sh COMPATIBILITY +The kvm interface was first introduced in SunOS. +A considerable number of programs have been developed that use this +interface, making backward compatibility highly desirable. +In most respects, the Sun kvm interface is consistent and clean. +Accordingly, the generic portion of the interface (i.e., +.Fn kvm_open , +.Fn kvm_close , +.Fn kvm_read , +.Fn kvm_write , +and +.Fn kvm_nlist ) +has been incorporated into the +.Bx +interface. +Indeed, many kvm applications (i.e., debuggers and statistical monitors) +use only this subset of the interface. +.Pp +The process interface was not kept. +This is not a portability issue since any code that manipulates +processes is inherently machine dependent. +.Pp +Finally, the Sun kvm error reporting semantics are poorly defined. +The library can be configured either to print errors to stderr automatically, +or to print no error messages at all. +In the latter case, the nature of the error cannot be determined. +To overcome this, the +.Bx +interface includes a routine, +.Xr kvm_geterr 3 , +to return (not print out) the error message corresponding to the most +recent error condition on the given descriptor. +.Sh SEE ALSO +.Xr kvm_close 3 , +.Xr kvm_getargv 3 , +.Xr kvm_getenvv 3 , +.Xr kvm_geterr 3 , +.Xr kvm_getkernelname 3 , +.Xr kvm_getloadavg 3 , +.Xr kvm_getlwps 3 , +.Xr kvm_getprocs 3 , +.Xr kvm_nlist 3 , +.Xr kvm_open 3 , +.Xr kvm_openfiles 3 , +.Xr kvm_read 3 , +.Xr kvm_write 3 diff --git a/lib/libkvm/kvm.c b/lib/libkvm/kvm.c new file mode 100644 index 000000000..a6e27b5a7 --- /dev/null +++ b/lib/libkvm/kvm.c @@ -0,0 +1,930 @@ +/* $NetBSD: kvm.c,v 1.101 2014/02/19 20:21:22 dsl Exp $ */ + +/*- + * Copyright (c) 1989, 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software developed by the Computer Systems + * Engineering group at Lawrence Berkeley Laboratory under DARPA contract + * BG 91-66 and contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)kvm.c 8.2 (Berkeley) 2/13/94"; +#else +__RCSID("$NetBSD: kvm.c,v 1.101 2014/02/19 20:21:22 dsl Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kvm_private.h" + +static int _kvm_get_header(kvm_t *); +static kvm_t *_kvm_open(kvm_t *, const char *, const char *, + const char *, int, char *); +static int clear_gap(kvm_t *, bool (*)(void *, const void *, size_t), + void *, size_t); +static off_t Lseek(kvm_t *, int, off_t, int); +static ssize_t Pread(kvm_t *, int, void *, size_t, off_t); + +char * +kvm_geterr(kvm_t *kd) +{ + return (kd->errbuf); +} + +const char * +kvm_getkernelname(kvm_t *kd) +{ + return kd->kernelname; +} + +/* + * Report an error using printf style arguments. "program" is kd->program + * on hard errors, and 0 on soft errors, so that under sun error emulation, + * only hard errors are printed out (otherwise, programs like gdb will + * generate tons of error messages when trying to access bogus pointers). + */ +void +_kvm_err(kvm_t *kd, const char *program, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + if (program != NULL) { + (void)fprintf(stderr, "%s: ", program); + (void)vfprintf(stderr, fmt, ap); + (void)fputc('\n', stderr); + } else + (void)vsnprintf(kd->errbuf, + sizeof(kd->errbuf), fmt, ap); + + va_end(ap); +} + +void +_kvm_syserr(kvm_t *kd, const char *program, const char *fmt, ...) +{ + va_list ap; + size_t n; + + va_start(ap, fmt); + if (program != NULL) { + (void)fprintf(stderr, "%s: ", program); + (void)vfprintf(stderr, fmt, ap); + (void)fprintf(stderr, ": %s\n", strerror(errno)); + } else { + char *cp = kd->errbuf; + + (void)vsnprintf(cp, sizeof(kd->errbuf), fmt, ap); + n = strlen(cp); + (void)snprintf(&cp[n], sizeof(kd->errbuf) - n, ": %s", + strerror(errno)); + } + va_end(ap); +} + +void * +_kvm_malloc(kvm_t *kd, size_t n) +{ + void *p; + + if ((p = malloc(n)) == NULL) + _kvm_err(kd, kd->program, "%s", strerror(errno)); + return (p); +} + +/* + * Wrapper around the lseek(2) system call; calls _kvm_syserr() for us + * in the event of emergency. + */ +static off_t +Lseek(kvm_t *kd, int fd, off_t offset, int whence) +{ + off_t off; + + errno = 0; + + if ((off = lseek(fd, offset, whence)) == -1 && errno != 0) { + _kvm_syserr(kd, kd->program, "Lseek"); + return ((off_t)-1); + } + return (off); +} + +ssize_t +_kvm_pread(kvm_t *kd, int fd, void *buf, size_t size, off_t off) +{ + ptrdiff_t moff; + void *newbuf; + size_t dsize; + ssize_t rv; + off_t doff; + + /* If aligned nothing to do. */ + if (((off % kd->fdalign) | (size % kd->fdalign)) == 0) { + return pread(fd, buf, size, off); + } + + /* + * Otherwise must buffer. We can't tolerate short reads in this + * case (lazy bum). + */ + moff = (ptrdiff_t)off % kd->fdalign; + doff = off - moff; + dsize = moff + size + kd->fdalign - 1; + dsize -= dsize % kd->fdalign; + if (kd->iobufsz < dsize) { + newbuf = realloc(kd->iobuf, dsize); + if (newbuf == NULL) { + _kvm_syserr(kd, 0, "cannot allocate I/O buffer"); + return (-1); + } + kd->iobuf = newbuf; + kd->iobufsz = dsize; + } + rv = pread(fd, kd->iobuf, dsize, doff); + if (rv < size + moff) + return -1; + memcpy(buf, kd->iobuf + moff, size); + return size; +} + +/* + * Wrapper around the pread(2) system call; calls _kvm_syserr() for us + * in the event of emergency. + */ +static ssize_t +Pread(kvm_t *kd, int fd, void *buf, size_t nbytes, off_t offset) +{ + ssize_t rv; + + errno = 0; + + if ((rv = _kvm_pread(kd, fd, buf, nbytes, offset)) != nbytes && + errno != 0) + _kvm_syserr(kd, kd->program, "Pread"); + return (rv); +} + +static kvm_t * +_kvm_open(kvm_t *kd, const char *uf, const char *mf, const char *sf, int flag, + char *errout) +{ + struct stat st; + int ufgiven; + + kd->pmfd = -1; + kd->vmfd = -1; + kd->swfd = -1; + kd->nlfd = -1; + kd->alive = KVM_ALIVE_DEAD; + kd->procbase = NULL; + kd->procbase_len = 0; + kd->procbase2 = NULL; + kd->procbase2_len = 0; + kd->lwpbase = NULL; + kd->lwpbase_len = 0; + kd->nbpg = getpagesize(); + kd->swapspc = NULL; + kd->argspc = NULL; + kd->argspc_len = 0; + kd->argbuf = NULL; + kd->argv = NULL; + kd->vmst = NULL; + kd->vm_page_buckets = NULL; + kd->kcore_hdr = NULL; + kd->cpu_dsize = 0; + kd->cpu_data = NULL; + kd->dump_off = 0; + kd->fdalign = 1; + kd->iobuf = NULL; + kd->iobufsz = 0; + + if (flag & KVM_NO_FILES) { + kd->alive = KVM_ALIVE_SYSCTL; + return(kd); + } + + /* + * Call the MD open hook. This sets: + * usrstack, min_uva, max_uva + */ + if (_kvm_mdopen(kd)) { + _kvm_err(kd, kd->program, "md init failed"); + goto failed; + } + + ufgiven = (uf != NULL); + if (!ufgiven) { +#ifdef CPU_BOOTED_KERNEL + /* 130 is 128 + '/' + '\0' */ + static char booted_kernel[130]; + int mib[2], rc; + size_t len; + + mib[0] = CTL_MACHDEP; + mib[1] = CPU_BOOTED_KERNEL; + booted_kernel[0] = '/'; + booted_kernel[1] = '\0'; + len = sizeof(booted_kernel) - 2; + rc = sysctl(&mib[0], 2, &booted_kernel[1], &len, NULL, 0); + booted_kernel[sizeof(booted_kernel) - 1] = '\0'; + uf = (booted_kernel[1] == '/') ? + &booted_kernel[1] : &booted_kernel[0]; + if (rc != -1) + rc = stat(uf, &st); + if (rc != -1 && !S_ISREG(st.st_mode)) + rc = -1; + if (rc == -1) +#endif /* CPU_BOOTED_KERNEL */ + uf = _PATH_UNIX; + } + else if (strlen(uf) >= MAXPATHLEN) { + _kvm_err(kd, kd->program, "exec file name too long"); + goto failed; + } + if (flag & ~O_RDWR) { + _kvm_err(kd, kd->program, "bad flags arg"); + goto failed; + } + if (mf == 0) + mf = _PATH_MEM; + if (sf == 0) + sf = _PATH_DRUM; + + /* + * Open the kernel namelist. If /dev/ksyms doesn't + * exist, open the current kernel. + */ + if (ufgiven == 0) + kd->nlfd = open(_PATH_KSYMS, O_RDONLY | O_CLOEXEC, 0); + if (kd->nlfd < 0) { + if ((kd->nlfd = open(uf, O_RDONLY | O_CLOEXEC, 0)) < 0) { + _kvm_syserr(kd, kd->program, "%s", uf); + goto failed; + } + strlcpy(kd->kernelname, uf, sizeof(kd->kernelname)); + } else { + strlcpy(kd->kernelname, _PATH_KSYMS, sizeof(kd->kernelname)); + /* + * We're here because /dev/ksyms was opened + * successfully. However, we don't want to keep it + * open, so we close it now. Later, we will open + * it again, since it will be the only case where + * kd->nlfd is negative. + */ + close(kd->nlfd); + kd->nlfd = -1; + } + + if ((kd->pmfd = open(mf, flag | O_CLOEXEC, 0)) < 0) { + _kvm_syserr(kd, kd->program, "%s", mf); + goto failed; + } + if (fstat(kd->pmfd, &st) < 0) { + _kvm_syserr(kd, kd->program, "%s", mf); + goto failed; + } + if (S_ISCHR(st.st_mode) && strcmp(mf, _PATH_MEM) == 0) { + /* + * If this is /dev/mem, open kmem too. (Maybe we should + * make it work for either /dev/mem or /dev/kmem -- in either + * case you're working with a live kernel.) + */ + if ((kd->vmfd = open(_PATH_KMEM, flag | O_CLOEXEC, 0)) < 0) { + _kvm_syserr(kd, kd->program, "%s", _PATH_KMEM); + goto failed; + } + kd->alive = KVM_ALIVE_FILES; + if ((kd->swfd = open(sf, flag | O_CLOEXEC, 0)) < 0) { + if (errno != ENXIO) { + _kvm_syserr(kd, kd->program, "%s", sf); + goto failed; + } + /* swap is not configured? not fatal */ + } + } else { + kd->fdalign = DEV_BSIZE; /* XXX */ + /* + * This is a crash dump. + * Initialize the virtual address translation machinery. + * + * If there is no valid core header, fail silently here. + * The address translations however will fail without + * header. Things can be made to run by calling + * kvm_dump_mkheader() before doing any translation. + */ + if (_kvm_get_header(kd) == 0) { + if (_kvm_initvtop(kd) < 0) + goto failed; + } + } + return (kd); +failed: + /* + * Copy out the error if doing sane error semantics. + */ + if (errout != 0) + (void)strlcpy(errout, kd->errbuf, _POSIX2_LINE_MAX); + (void)kvm_close(kd); + return (0); +} + +/* + * The kernel dump file (from savecore) contains: + * kcore_hdr_t kcore_hdr; + * kcore_seg_t cpu_hdr; + * (opaque) cpu_data; (size is cpu_hdr.c_size) + * kcore_seg_t mem_hdr; + * (memory) mem_data; (size is mem_hdr.c_size) + * + * Note: khdr is padded to khdr.c_hdrsize; + * cpu_hdr and mem_hdr are padded to khdr.c_seghdrsize + */ +static int +_kvm_get_header(kvm_t *kd) +{ + kcore_hdr_t kcore_hdr; + kcore_seg_t cpu_hdr; + kcore_seg_t mem_hdr; + size_t offset; + ssize_t sz; + + /* + * Read the kcore_hdr_t + */ + sz = Pread(kd, kd->pmfd, &kcore_hdr, sizeof(kcore_hdr), (off_t)0); + if (sz != sizeof(kcore_hdr)) + return (-1); + + /* + * Currently, we only support dump-files made by the current + * architecture... + */ + if ((CORE_GETMAGIC(kcore_hdr) != KCORE_MAGIC) || + (CORE_GETMID(kcore_hdr) != MID_MACHINE)) + return (-1); + + /* + * Currently, we only support exactly 2 segments: cpu-segment + * and data-segment in exactly that order. + */ + if (kcore_hdr.c_nseg != 2) + return (-1); + + /* + * Save away the kcore_hdr. All errors after this + * should do a to "goto fail" to deallocate things. + */ + kd->kcore_hdr = _kvm_malloc(kd, sizeof(kcore_hdr)); + memcpy(kd->kcore_hdr, &kcore_hdr, sizeof(kcore_hdr)); + offset = kcore_hdr.c_hdrsize; + + /* + * Read the CPU segment header + */ + sz = Pread(kd, kd->pmfd, &cpu_hdr, sizeof(cpu_hdr), (off_t)offset); + if (sz != sizeof(cpu_hdr)) + goto fail; + if ((CORE_GETMAGIC(cpu_hdr) != KCORESEG_MAGIC) || + (CORE_GETFLAG(cpu_hdr) != CORE_CPU)) + goto fail; + offset += kcore_hdr.c_seghdrsize; + + /* + * Read the CPU segment DATA. + */ + kd->cpu_dsize = cpu_hdr.c_size; + kd->cpu_data = _kvm_malloc(kd, cpu_hdr.c_size); + if (kd->cpu_data == NULL) + goto fail; + sz = Pread(kd, kd->pmfd, kd->cpu_data, cpu_hdr.c_size, (off_t)offset); + if (sz != cpu_hdr.c_size) + goto fail; + offset += cpu_hdr.c_size; + + /* + * Read the next segment header: data segment + */ + sz = Pread(kd, kd->pmfd, &mem_hdr, sizeof(mem_hdr), (off_t)offset); + if (sz != sizeof(mem_hdr)) + goto fail; + offset += kcore_hdr.c_seghdrsize; + + if ((CORE_GETMAGIC(mem_hdr) != KCORESEG_MAGIC) || + (CORE_GETFLAG(mem_hdr) != CORE_DATA)) + goto fail; + + kd->dump_off = offset; + return (0); + +fail: + if (kd->kcore_hdr != NULL) { + free(kd->kcore_hdr); + kd->kcore_hdr = NULL; + } + if (kd->cpu_data != NULL) { + free(kd->cpu_data); + kd->cpu_data = NULL; + kd->cpu_dsize = 0; + } + return (-1); +} + +/* + * The format while on the dump device is: (new format) + * kcore_seg_t cpu_hdr; + * (opaque) cpu_data; (size is cpu_hdr.c_size) + * kcore_seg_t mem_hdr; + * (memory) mem_data; (size is mem_hdr.c_size) + */ +int +kvm_dump_mkheader(kvm_t *kd, off_t dump_off) +{ + kcore_seg_t cpu_hdr; + size_t hdr_size; + ssize_t sz; + + if (kd->kcore_hdr != NULL) { + _kvm_err(kd, kd->program, "already has a dump header"); + return (-1); + } + if (ISALIVE(kd)) { + _kvm_err(kd, kd->program, "don't use on live kernel"); + return (-1); + } + + /* + * Validate new format crash dump + */ + sz = Pread(kd, kd->pmfd, &cpu_hdr, sizeof(cpu_hdr), dump_off); + if (sz != sizeof(cpu_hdr)) { + _kvm_err(kd, 0, "read %zx bytes at offset %"PRIx64 + " for cpu_hdr instead of requested %zu", + sz, dump_off, sizeof(cpu_hdr)); + return (-1); + } + if ((CORE_GETMAGIC(cpu_hdr) != KCORE_MAGIC) + || (CORE_GETMID(cpu_hdr) != MID_MACHINE)) { + _kvm_err(kd, 0, "invalid magic in cpu_hdr"); + return (0); + } + hdr_size = ALIGN(sizeof(cpu_hdr)); + + /* + * Read the CPU segment. + */ + kd->cpu_dsize = cpu_hdr.c_size; + kd->cpu_data = _kvm_malloc(kd, kd->cpu_dsize); + if (kd->cpu_data == NULL) { + _kvm_err(kd, kd->program, "no cpu_data"); + goto fail; + } + sz = Pread(kd, kd->pmfd, kd->cpu_data, cpu_hdr.c_size, + dump_off + hdr_size); + if (sz != cpu_hdr.c_size) { + _kvm_err(kd, kd->program, "size %zu != cpu_hdr.csize %"PRIu32, + sz, cpu_hdr.c_size); + goto fail; + } + hdr_size += kd->cpu_dsize; + + /* + * Leave phys mem pointer at beginning of memory data + */ + kd->dump_off = dump_off + hdr_size; + if (Lseek(kd, kd->pmfd, kd->dump_off, SEEK_SET) == -1) { + _kvm_err(kd, kd->program, "failed to seek to %" PRId64, + (int64_t)kd->dump_off); + goto fail; + } + + /* + * Create a kcore_hdr. + */ + kd->kcore_hdr = _kvm_malloc(kd, sizeof(kcore_hdr_t)); + if (kd->kcore_hdr == NULL) { + _kvm_err(kd, kd->program, "failed to allocate header"); + goto fail; + } + + kd->kcore_hdr->c_hdrsize = ALIGN(sizeof(kcore_hdr_t)); + kd->kcore_hdr->c_seghdrsize = ALIGN(sizeof(kcore_seg_t)); + kd->kcore_hdr->c_nseg = 2; + CORE_SETMAGIC(*(kd->kcore_hdr), KCORE_MAGIC, MID_MACHINE,0); + + /* + * Now that we have a valid header, enable translations. + */ + if (_kvm_initvtop(kd) == 0) + /* Success */ + return (hdr_size); + +fail: + if (kd->kcore_hdr != NULL) { + free(kd->kcore_hdr); + kd->kcore_hdr = NULL; + } + if (kd->cpu_data != NULL) { + free(kd->cpu_data); + kd->cpu_data = NULL; + kd->cpu_dsize = 0; + } + return (-1); +} + +static int +clear_gap(kvm_t *kd, bool (*write_buf)(void *, const void *, size_t), + void *cookie, size_t size) +{ + char buf[1024]; + size_t len; + + (void)memset(buf, 0, size > sizeof(buf) ? sizeof(buf) : size); + + while (size > 0) { + len = size > sizeof(buf) ? sizeof(buf) : size; + if (!(*write_buf)(cookie, buf, len)) { + _kvm_syserr(kd, kd->program, "clear_gap"); + return -1; + } + size -= len; + } + + return 0; +} + +/* + * Write the dump header by calling write_buf with cookie as first argument. + */ +int +kvm_dump_header(kvm_t *kd, bool (*write_buf)(void *, const void *, size_t), + void *cookie, int dumpsize) +{ + kcore_seg_t seghdr; + long offset; + size_t gap; + + if (kd->kcore_hdr == NULL || kd->cpu_data == NULL) { + _kvm_err(kd, kd->program, "no valid dump header(s)"); + return (-1); + } + + /* + * Write the generic header + */ + offset = 0; + if (!(*write_buf)(cookie, kd->kcore_hdr, sizeof(kcore_hdr_t))) { + _kvm_syserr(kd, kd->program, "kvm_dump_header"); + return (-1); + } + offset += kd->kcore_hdr->c_hdrsize; + gap = kd->kcore_hdr->c_hdrsize - sizeof(kcore_hdr_t); + if (clear_gap(kd, write_buf, cookie, gap) == -1) + return (-1); + + /* + * Write the CPU header + */ + CORE_SETMAGIC(seghdr, KCORESEG_MAGIC, 0, CORE_CPU); + seghdr.c_size = ALIGN(kd->cpu_dsize); + if (!(*write_buf)(cookie, &seghdr, sizeof(seghdr))) { + _kvm_syserr(kd, kd->program, "kvm_dump_header"); + return (-1); + } + offset += kd->kcore_hdr->c_seghdrsize; + gap = kd->kcore_hdr->c_seghdrsize - sizeof(seghdr); + if (clear_gap(kd, write_buf, cookie, gap) == -1) + return (-1); + + if (!(*write_buf)(cookie, kd->cpu_data, kd->cpu_dsize)) { + _kvm_syserr(kd, kd->program, "kvm_dump_header"); + return (-1); + } + offset += seghdr.c_size; + gap = seghdr.c_size - kd->cpu_dsize; + if (clear_gap(kd, write_buf, cookie, gap) == -1) + return (-1); + + /* + * Write the actual dump data segment header + */ + CORE_SETMAGIC(seghdr, KCORESEG_MAGIC, 0, CORE_DATA); + seghdr.c_size = dumpsize; + if (!(*write_buf)(cookie, &seghdr, sizeof(seghdr))) { + _kvm_syserr(kd, kd->program, "kvm_dump_header"); + return (-1); + } + offset += kd->kcore_hdr->c_seghdrsize; + gap = kd->kcore_hdr->c_seghdrsize - sizeof(seghdr); + if (clear_gap(kd, write_buf, cookie, gap) == -1) + return (-1); + + return (int)offset; +} + +static bool +kvm_dump_header_stdio(void *cookie, const void *buf, size_t len) +{ + return fwrite(buf, len, 1, (FILE *)cookie) == 1; +} + +int +kvm_dump_wrtheader(kvm_t *kd, FILE *fp, int dumpsize) +{ + return kvm_dump_header(kd, kvm_dump_header_stdio, fp, dumpsize); +} + +kvm_t * +kvm_openfiles(const char *uf, const char *mf, const char *sf, + int flag, char *errout) +{ + kvm_t *kd; + + if ((kd = malloc(sizeof(*kd))) == NULL) { + (void)strlcpy(errout, strerror(errno), _POSIX2_LINE_MAX); + return (0); + } + kd->program = 0; + return (_kvm_open(kd, uf, mf, sf, flag, errout)); +} + +kvm_t * +kvm_open(const char *uf, const char *mf, const char *sf, int flag, + const char *program) +{ + kvm_t *kd; + + if ((kd = malloc(sizeof(*kd))) == NULL) { + (void)fprintf(stderr, "%s: %s\n", + program ? program : getprogname(), strerror(errno)); + return (0); + } + kd->program = program; + return (_kvm_open(kd, uf, mf, sf, flag, NULL)); +} + +int +kvm_close(kvm_t *kd) +{ + int error = 0; + + if (kd->pmfd >= 0) + error |= close(kd->pmfd); + if (kd->vmfd >= 0) + error |= close(kd->vmfd); + if (kd->nlfd >= 0) + error |= close(kd->nlfd); + if (kd->swfd >= 0) + error |= close(kd->swfd); + if (kd->vmst) + _kvm_freevtop(kd); + kd->cpu_dsize = 0; + if (kd->cpu_data != NULL) + free(kd->cpu_data); + if (kd->kcore_hdr != NULL) + free(kd->kcore_hdr); + if (kd->procbase != 0) + free(kd->procbase); + if (kd->procbase2 != 0) + free(kd->procbase2); + if (kd->lwpbase != 0) + free(kd->lwpbase); + if (kd->swapspc != 0) + free(kd->swapspc); + if (kd->argspc != 0) + free(kd->argspc); + if (kd->argbuf != 0) + free(kd->argbuf); + if (kd->argv != 0) + free(kd->argv); + if (kd->iobuf != 0) + free(kd->iobuf); + free(kd); + + return (error); +} + +int +kvm_nlist(kvm_t *kd, struct nlist *nl) +{ + int rv, nlfd; + + /* + * kd->nlfd might be negative when we get here, and in that + * case that means that we're using /dev/ksyms. + * So open it again, just for the time we retrieve the list. + */ + if (kd->nlfd < 0) { + nlfd = open(_PATH_KSYMS, O_RDONLY | O_CLOEXEC, 0); + if (nlfd < 0) { + _kvm_err(kd, 0, "failed to open %s", _PATH_KSYMS); + return (nlfd); + } + } else + nlfd = kd->nlfd; + + /* + * Call the nlist(3) routines to retrieve the given namelist. + */ + rv = __fdnlist(nlfd, nl); + + if (rv == -1) + _kvm_err(kd, 0, "bad namelist"); + + if (kd->nlfd < 0) + close(nlfd); + + return (rv); +} + +int +kvm_dump_inval(kvm_t *kd) +{ + struct nlist nl[2]; + paddr_t pa; + size_t dsize; + off_t doff; + void *newbuf; + + if (ISALIVE(kd)) { + _kvm_err(kd, kd->program, "clearing dump on live kernel"); + return (-1); + } + nl[0].n_name = "_dumpmag"; + nl[1].n_name = NULL; + + if (kvm_nlist(kd, nl) == -1) { + _kvm_err(kd, 0, "bad namelist"); + return (-1); + } + if (_kvm_kvatop(kd, (vaddr_t)nl[0].n_value, &pa) == 0) + return (-1); + + errno = 0; + dsize = MAX(kd->fdalign, sizeof(u_long)); + if (kd->iobufsz < dsize) { + newbuf = realloc(kd->iobuf, dsize); + if (newbuf == NULL) { + _kvm_syserr(kd, 0, "cannot allocate I/O buffer"); + return (-1); + } + kd->iobuf = newbuf; + kd->iobufsz = dsize; + } + memset(kd->iobuf, 0, dsize); + doff = _kvm_pa2off(kd, pa); + doff -= doff % kd->fdalign; + if (pwrite(kd->pmfd, kd->iobuf, dsize, doff) == -1) { + _kvm_syserr(kd, 0, "cannot invalidate dump - pwrite"); + return (-1); + } + return (0); +} + +ssize_t +kvm_read(kvm_t *kd, u_long kva, void *buf, size_t len) +{ + int cc; + void *cp; + + if (ISKMEM(kd)) { + /* + * We're using /dev/kmem. Just read straight from the + * device and let the active kernel do the address translation. + */ + errno = 0; + cc = _kvm_pread(kd, kd->vmfd, buf, len, (off_t)kva); + if (cc < 0) { + _kvm_syserr(kd, 0, "kvm_read"); + return (-1); + } else if (cc < len) + _kvm_err(kd, kd->program, "short read"); + return (cc); + } else if (ISSYSCTL(kd)) { + _kvm_err(kd, kd->program, "kvm_open called with KVM_NO_FILES, " + "can't use kvm_read"); + return (-1); + } else { + if ((kd->kcore_hdr == NULL) || (kd->cpu_data == NULL)) { + _kvm_err(kd, kd->program, "no valid dump header"); + return (-1); + } + cp = buf; + while (len > 0) { + paddr_t pa; + off_t foff; + + cc = _kvm_kvatop(kd, (vaddr_t)kva, &pa); + if (cc == 0) + return (-1); + if (cc > len) + cc = len; + foff = _kvm_pa2off(kd, pa); + errno = 0; + cc = _kvm_pread(kd, kd->pmfd, cp, (size_t)cc, foff); + if (cc < 0) { + _kvm_syserr(kd, kd->program, "kvm_read"); + break; + } + /* + * If kvm_kvatop returns a bogus value or our core + * file is truncated, we might wind up seeking beyond + * the end of the core file in which case the read will + * return 0 (EOF). + */ + if (cc == 0) + break; + cp = (char *)cp + cc; + kva += cc; + len -= cc; + } + return ((char *)cp - (char *)buf); + } + /* NOTREACHED */ +} + +ssize_t +kvm_write(kvm_t *kd, u_long kva, const void *buf, size_t len) +{ + int cc; + + if (ISKMEM(kd)) { + /* + * Just like kvm_read, only we write. + */ + errno = 0; + cc = pwrite(kd->vmfd, buf, len, (off_t)kva); + if (cc < 0) { + _kvm_syserr(kd, 0, "kvm_write"); + return (-1); + } else if (cc < len) + _kvm_err(kd, kd->program, "short write"); + return (cc); + } else if (ISSYSCTL(kd)) { + _kvm_err(kd, kd->program, "kvm_open called with KVM_NO_FILES, " + "can't use kvm_write"); + return (-1); + } else { + _kvm_err(kd, kd->program, + "kvm_write not implemented for dead kernels"); + return (-1); + } + /* NOTREACHED */ +} diff --git a/lib/libkvm/kvm_aarch64.c b/lib/libkvm/kvm_aarch64.c new file mode 100644 index 000000000..593ecd76e --- /dev/null +++ b/lib/libkvm/kvm_aarch64.c @@ -0,0 +1,208 @@ +/* $NetBSD: kvm_aarch64.c,v 1.1 2014/08/10 05:47:37 matt Exp $ */ + +/*- + * Copyright (c) 2014 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Matt Thomas of 3am Software Foundry. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include "kvm_private.h" + +__RCSID("$NetBSD: kvm_aarch64.c,v 1.1 2014/08/10 05:47:37 matt Exp $"); + +/*ARGSUSED*/ +void +_kvm_freevtop(kvm_t *kd) +{ + return; +} + +/*ARGSUSED*/ +int +_kvm_initvtop(kvm_t *kd) +{ + return (0); +} + +int +_kvm_kvatop(kvm_t *kd, vaddr_t va, paddr_t *pa) +{ + if (ISALIVE(kd)) { + _kvm_err(kd, 0, "vatop called in live kernel!"); + return(0); + } + + if ((va & AARCH64_KSEG_MASK) != AARCH64_KSEG_START) { + /* + * Bogus address (not in KV space): punt. + */ + _kvm_err(kd, 0, "invalid kernel virtual address"); +lose: + *pa = -1; + return 0; + } + + const cpu_kcore_hdr_t * const cpu_kh = kd->cpu_data; + const u_int tg1 =__SHIFTOUT(cpu_kh->kh_tcr1, TCR_TG1); + const u_int t1siz = __SHIFTOUT(cpu_kh->kh_tcr1, TCR_T1SZ); + + /* + * Real kernel virtual address: do the translation. + */ + + u_int va_bits; + u_int page_shift; + + switch (tg1) { + case TCR_TG_4KB: + va_bits = t1siz + 36; + page_shift = 12; + break; + case TCR_TG_16KB: + va_bits = 48; + page_shift = 14; + break; + case TCR_TG_64KB: + va_bits = t1siz + 38; + page_shift = 16; + break; + default: + goto lose; + } + + const size_t page_size = 1 << page_shift; + const uint64_t page_mask = (page_size - 1); + const uint64_t page_addr = __BITS(47, 0) & ~page_mask; + const uint64_t pte_mask = page_mask >> 3; + const u_int pte_shift = page_shift - 3; + + /* how many level of page tables do we have? */ + u_int level = (48 + page_shift - 1) / page_shift; + + /* restrict va to the valid VA bits */ + va &= (1LL << va_bits) - 1; + + u_int addr_shift = page_shift + (level - 1) * pte_shift; + + /* clear out the unused low bits of the table address */ + paddr_t pte_addr = (cpu_kh->kh_ttbr1 & TTBR_BADDR); + pte_addr &= ~((8L << (va_bits - addr_shift)) - 1); + + for (;;) { + pt_entry_t pte; + + /* now index into the pte table */ + pte_addr += 8 * ((va >> addr_shift) & pte_mask); + + /* Find and read the PTE. */ + if (_kvm_pread(kd, kd->pmfd, &pte, sizeof(pte), + _kvm_pa2off(kd, pte_addr)) != sizeof(pte)) { + _kvm_syserr(kd, 0, "could not read pte"); + goto lose; + } + + /* Find and read the L2 PTE. */ + if ((pte & LX_VALID) == 0) { + _kvm_err(kd, 0, "invalid translation (invalid pte)"); + goto lose; + } + + if ((pte & LX_TYPE) == LX_TYPE_BLK) { + const paddr_t blk_mask = ((1L << addr_shift) - 1); + + *pa = (pte & page_addr & ~blk_mask) | (va & blk_mask); + return 0; + } + + if (level == page_shift) { + *pa = (pte & page_addr) | (va & page_mask); + return 0; + } + + /* + * Read next level of page table + */ + + pte_addr = pte & page_addr; + addr_shift -= pte_shift; + } +} + +/* + * Translate a physical address to a file-offset in the crash dump. + */ +off_t +_kvm_pa2off(kvm_t *kd, paddr_t pa) +{ + const cpu_kcore_hdr_t * const cpu_kh = kd->cpu_data; + off_t off = 0; + + for (const phys_ram_seg_t *ramsegs = cpu_kh->kh_ramsegs; + ramsegs->size != 0; ramsegs++) { + if (pa >= ramsegs->start + && pa < ramsegs->start + ramsegs->size) { + off += pa - ramsegs->start; + break; + } + off += ramsegs->size; + } + + return kd->dump_off + off; +} + +/* + * Machine-dependent initialization for ALL open kvm descriptors, + * not just those for a kernel crash dump. Some architectures + * have to deal with these NOT being constants! (i.e. m68k) + */ +int +_kvm_mdopen(kvm_t *kd) +{ + + kd->usrstack = USRSTACK; + kd->min_uva = VM_MIN_ADDRESS; + kd->max_uva = VM_MAXUSER_ADDRESS; + + return (0); +} diff --git a/lib/libkvm/kvm_alpha.c b/lib/libkvm/kvm_alpha.c new file mode 100644 index 000000000..03e6378e7 --- /dev/null +++ b/lib/libkvm/kvm_alpha.c @@ -0,0 +1,194 @@ +/* $NetBSD: kvm_alpha.c,v 1.27 2014/02/19 20:21:22 dsl Exp $ */ + +/* + * Copyright (c) 1994, 1995 Carnegie-Mellon University. + * All rights reserved. + * + * Author: Chris G. Demetriou + * + * Permission to use, copy, modify and distribute this software and + * its documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +#define __KVM_ALPHA_PRIVATE /* see */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include + +#include "kvm_private.h" + +__RCSID("$NetBSD: kvm_alpha.c,v 1.27 2014/02/19 20:21:22 dsl Exp $"); + +/*ARGSUSED*/ +void +_kvm_freevtop(kvm_t *kd) +{ + return; +} + +/*ARGSUSED*/ +int +_kvm_initvtop(kvm_t *kd) +{ + return (0); +} + +int +_kvm_kvatop(kvm_t *kd, vaddr_t va, paddr_t *pa) +{ + cpu_kcore_hdr_t *cpu_kh; + alpha_pt_entry_t pte; + u_long pteoff, page_off; + int rv; + + if (ISALIVE(kd)) { + _kvm_err(kd, 0, "vatop called in live kernel!"); + return(0); + } + + cpu_kh = kd->cpu_data; + page_off = va & (cpu_kh->page_size - 1); + + if (va >= ALPHA_K0SEG_BASE && va <= ALPHA_K0SEG_END) { + /* + * Direct-mapped address: just convert it. + */ + + *pa = ALPHA_K0SEG_TO_PHYS(va); + rv = cpu_kh->page_size - page_off; + } else if (va >= ALPHA_K1SEG_BASE && va <= ALPHA_K1SEG_END) { + /* + * Real kernel virtual address: do the translation. + */ + + /* Find and read the L1 PTE. */ + pteoff = cpu_kh->lev1map_pa + + l1pte_index(va) * sizeof(alpha_pt_entry_t); + if (_kvm_pread(kd, kd->pmfd, &pte, sizeof(pte), + _kvm_pa2off(kd, pteoff)) != sizeof(pte)) { + _kvm_syserr(kd, 0, "could not read L1 PTE"); + goto lose; + } + + /* Find and read the L2 PTE. */ + if ((pte & ALPHA_PTE_VALID) == 0) { + _kvm_err(kd, 0, "invalid translation (invalid L1 PTE)"); + goto lose; + } + pteoff = ALPHA_PTE_TO_PFN(pte) * cpu_kh->page_size + + l2pte_index(va) * sizeof(alpha_pt_entry_t); + if (_kvm_pread(kd, kd->pmfd, &pte, sizeof(pte), + _kvm_pa2off(kd, pteoff)) != sizeof(pte)) { + _kvm_syserr(kd, 0, "could not read L2 PTE"); + goto lose; + } + + /* Find and read the L3 PTE. */ + if ((pte & ALPHA_PTE_VALID) == 0) { + _kvm_err(kd, 0, "invalid translation (invalid L2 PTE)"); + goto lose; + } + pteoff = ALPHA_PTE_TO_PFN(pte) * cpu_kh->page_size + + l3pte_index(va) * sizeof(alpha_pt_entry_t); + if (_kvm_pread(kd, kd->pmfd, &pte, sizeof(pte), + _kvm_pa2off(kd, pteoff)) != sizeof(pte)) { + _kvm_syserr(kd, 0, "could not read L3 PTE"); + goto lose; + } + + /* Fill in the PA. */ + if ((pte & ALPHA_PTE_VALID) == 0) { + _kvm_err(kd, 0, "invalid translation (invalid L3 PTE)"); + goto lose; + } + *pa = ALPHA_PTE_TO_PFN(pte) * cpu_kh->page_size + page_off; + rv = cpu_kh->page_size - page_off; + } else { + /* + * Bogus address (not in KV space): punt. + */ + + _kvm_err(kd, 0, "invalid kernel virtual address"); +lose: + *pa = -1; + rv = 0; + } + + return (rv); +} + +/* + * Translate a physical address to a file-offset in the crash dump. + */ +off_t +_kvm_pa2off(kvm_t *kd, paddr_t pa) +{ + cpu_kcore_hdr_t *cpu_kh; + phys_ram_seg_t *ramsegs; + off_t off; + int i; + + cpu_kh = kd->cpu_data; + ramsegs = (phys_ram_seg_t *)((char *)cpu_kh + ALIGN(sizeof *cpu_kh)); + + off = 0; + for (i = 0; i < cpu_kh->nmemsegs; i++) { + if (pa >= ramsegs[i].start && + (pa - ramsegs[i].start) < ramsegs[i].size) { + off += (pa - ramsegs[i].start); + break; + } + off += ramsegs[i].size; + } + + return (kd->dump_off + off); +} + +/* + * Machine-dependent initialization for ALL open kvm descriptors, + * not just those for a kernel crash dump. Some architectures + * have to deal with these NOT being constants! (i.e. m68k) + */ +int +_kvm_mdopen(kvm_t *kd) +{ + + kd->usrstack = USRSTACK; + kd->min_uva = VM_MIN_ADDRESS; + kd->max_uva = VM_MAXUSER_ADDRESS; + + return (0); +} diff --git a/lib/libkvm/kvm_arm.c b/lib/libkvm/kvm_arm.c new file mode 100644 index 000000000..f5d984f16 --- /dev/null +++ b/lib/libkvm/kvm_arm.c @@ -0,0 +1,208 @@ +/* $NetBSD: kvm_arm.c,v 1.6 2010/09/20 23:23:16 jym Exp $ */ + +/*- + * Copyright (C) 1996 Wolfgang Solfrank. + * Copyright (C) 1996 TooLs GmbH. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by TooLs GmbH. + * 4. The name of TooLs GmbH may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * from: kvm_powerpc.c,v 1.3 1997/09/19 04:00:23 thorpej Exp + */ + +/* + * arm32 machine dependent routines for kvm. + */ + +#include +#if defined(LIBC_SCCS) && !defined(lint) +__RCSID("$NetBSD: kvm_arm.c,v 1.6 2010/09/20 23:23:16 jym Exp $"); +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include + +#include "kvm_private.h" + +void +_kvm_freevtop(kvm_t * kd) +{ + if (kd->vmst != 0) + free(kd->vmst); +} + +int +_kvm_initvtop(kvm_t * kd) +{ + return 0; +} + +int +_kvm_kvatop(kvm_t * kd, vaddr_t va, paddr_t *pa) +{ + cpu_kcore_hdr_t *cpu_kh; + pd_entry_t pde; + pt_entry_t pte; + paddr_t pde_pa, pte_pa; + + if (ISALIVE(kd)) { + _kvm_err(kd, 0, "vatop called in live kernel!"); + return (0); + } + cpu_kh = kd->cpu_data; + + if (cpu_kh->version != 1) { + _kvm_err(kd, 0, "unsupported kcore structure version"); + return 0; + } + if (cpu_kh->flags != 0) { + _kvm_err(kd, 0, "kcore flags not supported"); + return 0; + } + /* + * work out which L1 table we need + */ + if (va >= (cpu_kh->UserL1TableSize << 17)) + pde_pa = cpu_kh->PAKernelL1Table; + else + pde_pa = cpu_kh->PAUserL1Table; + + /* + * work out the offset into the L1 Table + */ + pde_pa += ((va >> 20) * sizeof(pd_entry_t)); + + if (_kvm_pread(kd, kd->pmfd, (void *) &pde, sizeof(pd_entry_t), + _kvm_pa2off(kd, pde_pa)) != sizeof(pd_entry_t)) { + _kvm_syserr(kd, 0, "could not read L1 entry"); + return (0); + } + /* + * next work out what kind of record it is + */ + switch (pde & L1_TYPE_MASK) { + case L1_TYPE_S: + *pa = (pde & L1_S_FRAME) | (va & L1_S_OFFSET); + return L1_S_SIZE - (va & L1_S_OFFSET); + case L1_TYPE_C: + pte_pa = (pde & L1_C_ADDR_MASK) + | ((va & 0xff000) >> 10); + break; + case L1_TYPE_F: + pte_pa = (pde & L1_S_ADDR_MASK) + | ((va & 0xffc00) >> 8); + break; + default: + _kvm_syserr(kd, 0, "L1 entry is invalid"); + return (0); + } + + /* + * locate the pte and load it + */ + if (_kvm_pread(kd, kd->pmfd, (void *) &pte, sizeof(pt_entry_t), + _kvm_pa2off(kd, pte_pa)) != sizeof(pt_entry_t)) { + _kvm_syserr(kd, 0, "could not read L2 entry"); + return (0); + } + switch (pte & L2_TYPE_MASK) { + case L2_TYPE_L: + *pa = (pte & L2_L_FRAME) | (va & L2_L_OFFSET); + return (L2_L_SIZE - (va & L2_L_OFFSET)); + case L2_TYPE_S: + *pa = (pte & L2_S_FRAME) | (va & L2_S_OFFSET); + return (L2_S_SIZE - (va & L2_S_OFFSET)); + case L2_TYPE_T: + *pa = (pte & L2_T_FRAME) | (va & L2_T_OFFSET); + return (L2_T_SIZE - (va & L2_T_OFFSET)); + default: + _kvm_syserr(kd, 0, "L2 entry is invalid"); + return (0); + } + + _kvm_err(kd, 0, "vatop not yet implemented!"); + return 0; +} + +off_t +_kvm_pa2off(kvm_t * kd, u_long pa) +{ + cpu_kcore_hdr_t *cpu_kh; + phys_ram_seg_t *ramsegs; + off_t off; + int i; + + cpu_kh = kd->cpu_data; + ramsegs = (void *) ((char *) (void *) cpu_kh + cpu_kh->omemsegs); + + off = 0; + for (i = 0; i < cpu_kh->nmemsegs; i++) { + if (pa >= ramsegs[i].start && + (pa - ramsegs[i].start) < ramsegs[i].size) { + off += (pa - ramsegs[i].start); + break; + } + off += ramsegs[i].size; + } + return (kd->dump_off + off); +} + +/* + * Machine-dependent initialization for ALL open kvm descriptors, + * not just those for a kernel crash dump. Some architectures + * have to deal with these NOT being constants! (i.e. arm) + */ +int +_kvm_mdopen(kvm_t * kd) +{ + uintptr_t max_uva; + extern struct ps_strings *__ps_strings; + +#if 0 /* XXX - These vary across arm machines... */ + kd->usrstack = USRSTACK; + kd->min_uva = VM_MIN_ADDRESS; + kd->max_uva = VM_MAXUSER_ADDRESS; +#endif + /* This is somewhat hack-ish, but it works. */ + max_uva = (uintptr_t) (__ps_strings + 1); + kd->usrstack = max_uva; + kd->max_uva = max_uva; + kd->min_uva = 0; + + return (0); +} diff --git a/lib/libkvm/kvm_dump.3 b/lib/libkvm/kvm_dump.3 new file mode 100644 index 000000000..7309fa971 --- /dev/null +++ b/lib/libkvm/kvm_dump.3 @@ -0,0 +1,109 @@ +.\" $NetBSD: kvm_dump.3,v 1.15 2009/10/20 19:10:09 snj Exp $ +.\" +.\" Copyright (c) 1996 Leo Weppelman +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" +.Dd March 17, 1996 +.Dt KVM_DUMP 3 +.Os +.Sh NAME +.Nm kvm_dump_mkheader , +.Nm kvm_dump_wrtheader , +.Nm kvm_dump_inval +.Nd crash dump support functions +.Sh LIBRARY +.Lb libkvm +.Sh SYNOPSIS +.In kvm.h +.Ft int +.Fn kvm_dump_mkheader "kvm_t *kd" "off_t dump_off" +.Ft int +.Fn kvm_dump_wrtheader "kvm_t *kd" "FILE *fp" "int dumpsize" +.Ft int +.Fn kvm_dump_inval "kvm_t *kd" +.Sh DESCRIPTION +First note that the functions described here were designed to be used by +.Xr savecore 8 . +.Pp +The function +.Fn kvm_dump_mkheader +checks if the physical memory file associated with +.Fa kd +contains a valid crash dump header as generated by a dumping kernel. +When a valid header is found, +.Fn kvm_dump_mkheader +initializes the internal kvm data structures as if a crash dump generated by +the +.Xr savecore 8 +program was opened. +This has the intentional side effect of enabling the +address translation machinery. +.Pp +A call to +.Fn kvm_dump_mkheader +will most likely be followed by a call to +.Fn kvm_dump_wrtheader . +This function takes care of generating the generic header, the CORE_CPU +section and the section header of the CORE_DATA section. +The data is written to the file pointed at by +.Fa fp . +The +.Fa dumpsize +argument is only used to properly the set the segment size of the CORE_DATA +section. +Note that this function assumes that +.Fa fp +is positioned at file location 0. +This function will not seek and therefore allows +.Fa fp +to be a file pointer obtained by +.Fn zopen . +.Pp +The +.Fn kvm_dump_inval +function clears the magic number in the physical memory file associated with +.Fa kd . +The address translations must be enabled for this to work (thus assuming +that +.Fn kvm_dump_mkheader +was called earlier in the sequence). +.Sh RETURN VALUES +All functions except +.Fn kvm_dump_mkheader +return 0 on success, -1 on failure. +The function +.Fn kvm_dump_mkheader +returns the size of the headers present before the actual dumpdata starts. +If no valid headers were found but no fatal errors occurred, 0 is returned. +On fatal errors the return value is -1. +.Pp +In the case of failure, +.Xr kvm_geterr 3 +can be used to retrieve the cause of the error. +.Sh SEE ALSO +.Xr kvm 3 , +.Xr kvm_open 3 +.Sh HISTORY +These functions first appeared in +.Nx 1.2 . diff --git a/lib/libkvm/kvm_file.c b/lib/libkvm/kvm_file.c new file mode 100644 index 000000000..6e9877994 --- /dev/null +++ b/lib/libkvm/kvm_file.c @@ -0,0 +1,181 @@ +/* $NetBSD: kvm_file.c,v 1.29 2014/02/19 20:21:22 dsl Exp $ */ + +/*- + * Copyright (c) 1989, 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)kvm_file.c 8.1 (Berkeley) 6/4/93"; +#else +__RCSID("$NetBSD: kvm_file.c,v 1.29 2014/02/19 20:21:22 dsl Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + +/* + * File list interface for kvm. pstat, fstat and netstat are + * users of this code, so we've factored it out into a separate module. + * Thus, we keep this grunge out of the other kvm applications (i.e., + * most other applications are interested only in open/close/read/nlist). + */ + +#define _KERNEL +#include +#undef _KERNEL +#include +#include +#include +#include +#define _KERNEL +#include +#undef _KERNEL +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include + +#include "kvm_private.h" + +static int +kvm_deadfiles(kvm_t *, int, int, long, int); + +/* + * Get file structures. + */ +/*ARGSUSED*/ +static int +kvm_deadfiles(kvm_t *kd, int op, int arg, long ofhead, int numfiles) +{ + size_t buflen = kd->argspc_len, n = 0; + struct file *fp; + struct filelist fhead; + char *where = kd->argspc; + + /* + * first copyout filehead + */ + if (buflen < sizeof(fhead) || + KREAD(kd, (u_long)ofhead, &fhead)) { + _kvm_err(kd, kd->program, "can't read filehead"); + return (0); + } + buflen -= sizeof(fhead); + where += sizeof(fhead); + (void)memcpy(kd->argspc, &fhead, sizeof(fhead)); + + /* + * followed by an array of file structures + */ + for (fp = fhead.lh_first; fp != 0; fp = fp->f_list.le_next) { + if (buflen > sizeof(struct file)) { + if (KREAD(kd, (u_long)fp, + ((struct file *)(void *)where))) { + _kvm_err(kd, kd->program, "can't read kfp"); + return (0); + } + buflen -= sizeof(struct file); + fp = (struct file *)(void *)where; + where += sizeof(struct file); + n++; + } + } + if (n != numfiles) { + _kvm_err(kd, kd->program, "inconsistent nfiles"); + return (0); + } + return (numfiles); +} + +char * +kvm_getfiles(kvm_t *kd, int op, int arg, int *cnt) +{ + size_t size; + int mib[2], st; + int numfiles; + struct file *fp, *fplim; + struct filelist fhead; + + if (ISSYSCTL(kd)) { + size = 0; + mib[0] = CTL_KERN; + mib[1] = KERN_FILE; + st = sysctl(mib, 2, NULL, &size, NULL, 0); + if (st == -1) { + _kvm_syserr(kd, kd->program, "kvm_getprocs"); + return (0); + } + KVM_ALLOC(kd, argspc, size); + st = sysctl(mib, 2, kd->argspc, &size, NULL, 0); + if (st == -1 || size < sizeof(fhead)) { + _kvm_syserr(kd, kd->program, "kvm_getfiles"); + return (0); + } + (void)memcpy(&fhead, kd->argspc, sizeof(fhead)); + fp = (struct file *)(void *)(kd->argspc + sizeof(fhead)); + fplim = (struct file *)(void *)(kd->argspc + size); + for (numfiles = 0; fhead.lh_first && (fp < fplim); + numfiles++, fp++) + fhead.lh_first = fp->f_list.le_next; + } else { + struct nlist nl[3], *p; + + nl[0].n_name = "_nfiles"; + nl[1].n_name = "_filehead"; + nl[2].n_name = 0; + + if (kvm_nlist(kd, nl) != 0) { + for (p = nl; p->n_type != 0; ++p) + ; + _kvm_err(kd, kd->program, + "%s: no such symbol", p->n_name); + return (0); + } + if (KREAD(kd, nl[0].n_value, &numfiles)) { + _kvm_err(kd, kd->program, "can't read numfiles"); + return (0); + } + size = sizeof(fhead) + (numfiles + 10) * sizeof(struct file); + KVM_ALLOC(kd, argspc, size); + numfiles = kvm_deadfiles(kd, op, arg, (long)nl[1].n_value, + numfiles); + if (numfiles == 0) + return (0); + } + *cnt = numfiles; + return (kd->argspc); +} diff --git a/lib/libkvm/kvm_geterr.3 b/lib/libkvm/kvm_geterr.3 new file mode 100644 index 000000000..6f646c07d --- /dev/null +++ b/lib/libkvm/kvm_geterr.3 @@ -0,0 +1,79 @@ +.\" $NetBSD: kvm_geterr.3,v 1.9 2009/03/10 23:49:07 joerg Exp $ +.\" +.\" Copyright (c) 1992, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software developed by the Computer Systems +.\" Engineering group at Lawrence Berkeley Laboratory under DARPA contract +.\" BG 91-66 and contributed to Berkeley. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)kvm_geterr.3 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt KVM_GETERR 3 +.Os +.Sh NAME +.Nm kvm_geterr +.Nd get error message on kvm descriptor +.Sh LIBRARY +.Lb libkvm +.Sh SYNOPSIS +.In kvm.h +.Ft char * +.Fn kvm_geterr "kvm_t *kd" +.Sh DESCRIPTION +This function returns a string describing the most recent error condition +on the descriptor +.Fa kd . +The results are undefined if the most recent +.Xr kvm 3 +library call did not produce an error. +The string returned is stored in memory owned by +.Xr kvm 3 +so the message should be copied out and saved elsewhere if necessary. +.Sh SEE ALSO +.Xr kvm 3 , +.Xr kvm_close 3 , +.Xr kvm_getargv 3 , +.Xr kvm_getenvv 3 , +.Xr kvm_getprocs 3 , +.Xr kvm_nlist 3 , +.Xr kvm_open 3 , +.Xr kvm_openfiles 3 , +.Xr kvm_read 3 , +.Xr kvm_write 3 +.Sh BUGS +This routine cannot be used to access error conditions due to a failed +.Fn kvm_openfiles +call, since failure is indicated by returning a +.Dv NULL +descriptor. +Therefore, errors on open are output to the special error buffer +passed to +.Fn kvm_openfiles . +This option is not available to +.Fn kvm_open . diff --git a/lib/libkvm/kvm_getfiles.3 b/lib/libkvm/kvm_getfiles.3 new file mode 100644 index 000000000..c6a336291 --- /dev/null +++ b/lib/libkvm/kvm_getfiles.3 @@ -0,0 +1,87 @@ +.\" $NetBSD: kvm_getfiles.3,v 1.11 2009/03/10 23:49:07 joerg Exp $ +.\" +.\" Copyright (c) 1992, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software developed by the Computer Systems +.\" Engineering group at Lawrence Berkeley Laboratory under DARPA contract +.\" BG 91-66 and contributed to Berkeley. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)kvm_getfiles.3 8.2 (Berkeley) 4/19/94 +.\" +.Dd April 19, 1994 +.Dt KVM_GETFILES 3 +.Os +.Sh NAME +.Nm kvm_getfiles +.Nd survey open files +.Sh LIBRARY +.Lb libkvm +.Sh SYNOPSIS +.In kvm.h +.In sys/kinfo.h +.Fd #define _KERNEL +.In sys/file.h +.Fd #undef _KERNEL +.\" .Fa kvm_t *kd +.Ft char * +.Fn kvm_getfiles "kvm_t *kd" "int op" "int arg" "int *cnt" +.Sh DESCRIPTION +.Fn kvm_getfiles +returns a (sub-)set of the open files in the kernel indicated by +.Fa kd . +The +.Fa op +and +.Fa arg +arguments constitute a predicate which limits the set of files +returned. +No predicates are currently defined. +.Pp +The number of processes found is returned in the reference parameter +.Fa cnt . +The files are returned as a contiguous array of file structures, +preceded by the address of the first file entry in the kernel. +This memory is owned by kvm and is not guaranteed to be persistent across +subsequent kvm library calls. +Data should be copied out if it needs to be saved. +.Sh RETURN VALUES +.Fn kvm_getfiles +will return +.Dv NULL +on failure. +.Sh SEE ALSO +.Xr kvm 3 , +.Xr kvm_close 3 , +.Xr kvm_geterr 3 , +.Xr kvm_nlist 3 , +.Xr kvm_open 3 , +.Xr kvm_openfiles 3 , +.Xr kvm_read 3 , +.Xr kvm_write 3 +.Sh BUGS +This routine does not belong in the kvm interface. diff --git a/lib/libkvm/kvm_getkernelname.3 b/lib/libkvm/kvm_getkernelname.3 new file mode 100644 index 000000000..f83d7ecbe --- /dev/null +++ b/lib/libkvm/kvm_getkernelname.3 @@ -0,0 +1,67 @@ +.\" $NetBSD: kvm_getkernelname.3,v 1.2 2011/09/13 08:53:10 wiz Exp $ +.\" +.\" +.\" Copyright (c) 2011 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by Christos Zoulas. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the NetBSD +.\" Foundation, Inc. and its contributors. +.\" 4. Neither the name of The NetBSD Foundation nor the names of its +.\" contributors may be used to endorse or promote products derived +.\" from this software without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd September 14, 2011 +.Dt KVM_GETKERNELNAME 3 +.Os +.Sh NAME +.Nm kvm_getkernelname +.Nd get kernel name of opened kvm descriptor +.Sh LIBRARY +.Lb libkvm +.Sh SYNOPSIS +.In kvm.h +.Ft const char * +.Fn kvm_getkernelname "kvm_t *kd" +.Sh DESCRIPTION +This function returns a string containing the kernel name used from the kvm +descriptor obtained by a previous +.Xr kvm_open 3 +or +.Xr kvm_openfiles 3 +call. +.Sh SEE ALSO +.Xr kvm 3 , +.Xr kvm_close 3 , +.Xr kvm_getargv 3 , +.Xr kvm_getenvv 3 , +.Xr kvm_getprocs 3 , +.Xr kvm_nlist 3 , +.Xr kvm_open 3 , +.Xr kvm_openfiles 3 , +.Xr kvm_read 3 , +.Xr kvm_write 3 diff --git a/lib/libkvm/kvm_getloadavg.3 b/lib/libkvm/kvm_getloadavg.3 new file mode 100644 index 000000000..1498b0a02 --- /dev/null +++ b/lib/libkvm/kvm_getloadavg.3 @@ -0,0 +1,66 @@ +.\" $NetBSD: kvm_getloadavg.3,v 1.11 2009/03/10 23:49:07 joerg Exp $ +.\" +.\" Copyright (c) 1992, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)kvm_getloadavg.3 8.1 (Berkeley) 6/4/93 +.\" +.Dd August 18, 2002 +.Dt KVM_GETLOADAVG 3 +.Os +.Sh NAME +.Nm kvm_getloadavg +.Nd get system load averages +.Sh LIBRARY +.Lb libkvm +.Sh SYNOPSIS +.In sys/resource.h +.In kvm.h +.Ft int +.Fn kvm_getloadavg "kvm_t *kd" "double loadavg[]" "int nelem" +.Sh DESCRIPTION +The +.Fn kvm_getloadavg +function returns the number of processes in the system run queue +of the kernel indicated by +.Fa kd , +averaged over various periods of time. +Up to +.Fa nelem +samples are retrieved and assigned to successive elements of +.Fa loadavg Ns Bq . +The system imposes a maximum of 3 samples, representing averages +over the last 1, 5, and 15 minutes, respectively. +.Sh RETURN VALUES +If the load average was unobtainable, \-1 is returned; otherwise, +the number of samples actually retrieved is returned. +.Sh SEE ALSO +.Xr uptime 1 , +.Xr getloadavg 3 , +.Xr kvm 3 , +.Xr kvm_open 3 , +.Xr sysctl 3 diff --git a/lib/libkvm/kvm_getloadavg.c b/lib/libkvm/kvm_getloadavg.c new file mode 100644 index 000000000..c2f48948c --- /dev/null +++ b/lib/libkvm/kvm_getloadavg.c @@ -0,0 +1,105 @@ +/* $NetBSD: kvm_getloadavg.c,v 1.11 2012/03/21 10:10:36 matt Exp $ */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)kvm_getloadavg.c 8.1 (Berkeley) 6/4/93"; +#else +__RCSID("$NetBSD: kvm_getloadavg.c,v 1.11 2012/03/21 10:10:36 matt Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "kvm_private.h" + +static struct nlist nl[] = { + { .n_name = "_averunnable" }, +#define X_AVERUNNABLE 0 + { .n_name = "_fscale" }, +#define X_FSCALE 1 + { .n_name = "" }, +}; + +/* + * kvm_getloadavg() -- Get system load averages, from live or dead kernels. + * + * Put `nelem' samples into `loadavg' array. + * Return number of samples retrieved, or -1 on error. + */ +int +kvm_getloadavg(kvm_t *kd, double loadavg[], int nelem) +{ + struct loadavg loadinfo; + struct nlist *p; + int fscale, i; + + if (ISALIVE(kd)) + return (getloadavg(loadavg, nelem)); + + if (kvm_nlist(kd, nl) != 0) { + for (p = nl; p->n_type != 0; ++p); + _kvm_err(kd, kd->program, + "%s: no such symbol", p->n_name); + return (-1); + } + + if (KREAD(kd, nl[X_AVERUNNABLE].n_value, &loadinfo)) { + _kvm_err(kd, kd->program, "can't read averunnable"); + return (-1); + } + + /* + * Old kernels have fscale separately; if not found assume + * running new format. + */ + if (!KREAD(kd, nl[X_FSCALE].n_value, &fscale)) + loadinfo.fscale = fscale; + + nelem = MIN(nelem, sizeof(loadinfo.ldavg) / sizeof(fixpt_t)); + for (i = 0; i < nelem; i++) + loadavg[i] = (double) loadinfo.ldavg[i] / loadinfo.fscale; + return (nelem); +} diff --git a/lib/libkvm/kvm_getlwps.3 b/lib/libkvm/kvm_getlwps.3 new file mode 100644 index 000000000..7c2e20c9f --- /dev/null +++ b/lib/libkvm/kvm_getlwps.3 @@ -0,0 +1,102 @@ +.\" $NetBSD: kvm_getlwps.3,v 1.6 2009/03/10 23:49:07 joerg Exp $ +.\" +.\"Copyright (c) 2002 The NetBSD Foundation, Inc. +.\"All rights reserved. +.\" +.\"This code is derived from software contributed to The NetBSD Foundation +.\"by Nathan J. Williams. +.\" +.\"Redistribution and use in source and binary forms, with or without +.\"modification, are permitted provided that the following conditions +.\"are met: +.\"1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\"2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\"THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +.\"``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +.\"TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\"PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +.\"BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\"CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\"SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\"INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\"CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\"ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\"POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd February 10, 2004 +.Dt KVM_GETLWPS 3 +.Os +.Sh NAME +.Nm kvm_getlwps +.Nd access state of LWPs belonging to a user process +.Sh LIBRARY +.Lb libkvm +.Sh SYNOPSIS +.In kvm.h +.In sys/param.h +.In sys/sysctl.h +.\" .Fa kvm_t *kd +.Ft struct kinfo_lwp * +.Fn kvm_getlwps "kvm_t *kd" "int pid" "u_long procaddr" "int *elemsize" "int *cnt" +.Sh DESCRIPTION +.Fn kvm_getlwps +returns the set of LWPs belonging to the process specified by +.Fa pid +or +.Fa procaddr +in the kernel indicated by +.Fa kd . +The number of LWPs found is returned in the reference parameter +.Fa cnt . +The LWPs are returned as a contiguous array of +.Sy kinfo_lwp +structures. +This memory is locally allocated, and subsequent calls to +.Fn kvm_getlwps +and +.Fn kvm_close +will overwrite this storage. +.Pp +Only the first +.Fa elemsize +bytes of each array entry are returned. +If the size of the +.Sy kinfo_lwp +structure increases in size in a future release of +.Nx +the kernel will only return the requested amount of data for +each array entry and programs that use +.Fn kvm_getlwps +will continue to function without the need for recompilation. +.Pp +If called against an active kernel, the +.Fn kvm_getlwps +function will use the +.Xr sysctl 3 +interface and return information about the process identified by +.Fa pid ; +otherwise the kernel memory device file or swap device will be +accessed and the process is identified by the location passed in +.Fa paddr . +.Sh RETURN VALUES +.Fn kvm_getlwps +returns +.Dv NULL +on failure. +.Sh SEE ALSO +.Xr kvm 3 , +.Xr kvm_close 3 , +.Xr kvm_geterr 3 , +.Xr kvm_getproc2 3 , +.Xr kvm_getprocs 3 , +.Xr kvm_nlist 3 , +.Xr kvm_open 3 , +.Xr kvm_openfiles 3 , +.Xr kvm_read 3 , +.Xr kvm_write 3 +.Sh BUGS +These routines do not belong in the kvm interface. diff --git a/lib/libkvm/kvm_getprocs.3 b/lib/libkvm/kvm_getprocs.3 new file mode 100644 index 000000000..24a6f4ab8 --- /dev/null +++ b/lib/libkvm/kvm_getprocs.3 @@ -0,0 +1,236 @@ +.\" $NetBSD: kvm_getprocs.3,v 1.15 2009/03/10 23:49:07 joerg Exp $ +.\" +.\" Copyright (c) 1992, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software developed by the Computer Systems +.\" Engineering group at Lawrence Berkeley Laboratory under DARPA contract +.\" BG 91-66 and contributed to Berkeley. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)kvm_getprocs.3 8.1 (Berkeley) 6/4/93 +.\" +.Dd February 10, 2004 +.Dt KVM_GETPROCS 3 +.Os +.Sh NAME +.Nm kvm_getprocs , +.Nm kvm_getargv , +.Nm kvm_getenvv +.Nd access user process state +.Sh LIBRARY +.Lb libkvm +.Sh SYNOPSIS +.In kvm.h +.In sys/param.h +.In sys/sysctl.h +.\" .Fa kvm_t *kd +.Ft struct kinfo_proc * +.Fn kvm_getprocs "kvm_t *kd" "int op" "int arg" "int *cnt" +.Ft char ** +.Fn kvm_getargv "kvm_t *kd" "const struct kinfo_proc *p" "int nchr" +.Ft char ** +.Fn kvm_getenvv "kvm_t *kd" "const struct kinfo_proc *p" "int nchr" +.Ft struct kinfo_proc2 * +.Fn kvm_getproc2 "kvm_t *kd" "int op" "int arg" "int elemsize" "int *cnt" +.Ft char ** +.Fn kvm_getargv2 "kvm_t *kd" "const struct kinfo_proc2 *p" "int nchr" +.Ft char ** +.Fn kvm_getenvv2 "kvm_t *kd" "const struct kinfo_proc2 *p" "int nchr" +.Sh DESCRIPTION +.Fn kvm_getprocs +returns a (sub-)set of active processes in the kernel indicated by +.Fa kd . +The +.Fa op +and +.Fa arg +arguments constitute a predicate +which limits the set of processes returned. +The value of +.Fa op +describes the filtering predicate as follows: +.Pp +.Bl -tag -width 20n -offset indent -compact +.It Sy KERN_PROC_ALL +all processes +.It Sy KERN_PROC_PID +processes with process id +.Fa arg +.It Sy KERN_PROC_PGRP +processes with process group +.Fa arg +.It Sy KERN_PROC_SESSION +processes with session id +.Fa arg +.It Sy KERN_PROC_TTY +processes with tty device +.Fa arg +.It Sy KERN_PROC_UID +processes with effective user id +.Fa arg +.It Sy KERN_PROC_RUID +processes with real user id +.Fa arg +.It Sy KERN_PROC_GID +processes with effective group id +.Fa arg +.It Sy KERN_PROC_RGID +processes with real group id +.Fa arg +.El +.Pp +The number of processes found is returned in the reference parameter +.Fa cnt . +The processes are returned as a contiguous array of +.Sy kinfo_proc +structures. +This memory is locally allocated, and subsequent calls to +.Fn kvm_getprocs +and +.Fn kvm_close +will overwrite this storage. +.Pp +If the +.Fa op +argument for +.Fn kvm_getprocs +is +.Sy KERN_PROC_TTY , +.Fa arg +can also be +.Sy KERN_PROC_TTY_NODEV +to select processes with no controlling tty and +.Sy KERN_PROC_TTY_REVOKE +to select processes which have had their controlling tty +revoked. +.Pp +.Fn kvm_getargv +returns a null-terminated argument vector that corresponds to the +command line arguments passed to process indicated by +.Fa p . +Most likely, these arguments correspond to the values passed to +.Xr exec 3 +on process creation. +This information is, however, +deliberately under control of the process itself. +Note that the original command name can be found, unaltered, +in the p_comm field of the process structure returned by +.Fn kvm_getprocs . +.Pp +The +.Fa nchr +argument indicates the maximum number of characters, including null bytes, +to use in building the strings. +If this amount is exceeded, the string +causing the overflow is truncated and the partial result is returned. +This is handy for programs like +.Xr ps 1 +and +.Xr w 1 +that print only a one line summary of a command and should not copy +out large amounts of text only to ignore it. +If +.Fa nchr +is zero, no limit is imposed and all argument strings are returned in +their entirety. +.Pp +The memory allocated to the argv pointers and string storage +is owned by the kvm library. +Subsequent +.Fn kvm_getprocs +and +.Xr kvm_close 3 +calls will clobber this storage. +.Pp +The +.Fn kvm_getenvv +function is similar to +.Fn kvm_getargv +but returns the vector of environment strings. +This data is also alterable by the process. +.Pp +.Fn kvm_getproc2 +is similar to +.Fn kvm_getprocs +but returns an array of +.Sy kinfo_proc2 +structures. +Additionally, only the first +.Fa elemsize +bytes of each array entry are returned. +If the size of the +.Sy kinfo_proc2 +structure increases in size in a future release of +.Nx +the kernel will only return the requested amount of data for +each array entry and programs that use +.Fn kvm_getproc2 +will continue to function without the need for recompilation. +.Pp +The +.Fn kvm_getargv2 +and +.Fn kvm_getenvv2 +are equivalents to the +.Fn kvm_getargv +and +.Fn kvm_getenvv +functions but use a +.Sy kinfo_proc2 +structure to specify the process. +.Pp +If called against an active kernel, the +.Fn kvm_getproc2 , +.Fn kvm_getargv2 , +and +.Fn kvm_getenvv2 +functions will use the +.Xr sysctl 3 +interface and do not require access to the kernel memory device +file or swap device. +.Sh RETURN VALUES +.Fn kvm_getprocs , +.Fn kvm_getargv , +.Fn kvm_getenvv , +.Fn kvm_getproc2 , +.Fn kvm_getargv2 , +and +.Fn kvm_getenvv2 +all return +.Dv NULL +on failure. +.Sh SEE ALSO +.Xr kvm 3 , +.Xr kvm_close 3 , +.Xr kvm_geterr 3 , +.Xr kvm_nlist 3 , +.Xr kvm_open 3 , +.Xr kvm_openfiles 3 , +.Xr kvm_read 3 , +.Xr kvm_write 3 +.Sh BUGS +These routines do not belong in the kvm interface. diff --git a/lib/libkvm/kvm_hppa.c b/lib/libkvm/kvm_hppa.c new file mode 100644 index 000000000..6188446a4 --- /dev/null +++ b/lib/libkvm/kvm_hppa.c @@ -0,0 +1,205 @@ +/* $NetBSD: kvm_hppa.c,v 1.7 2014/02/19 20:21:22 dsl Exp $ */ + +/*- + * Copyright (c) 1989, 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software developed by the Computer Systems + * Engineering group at Lawrence Berkeley Laboratory under DARPA contract + * BG 91-66 and contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)kvm_hp300.c 8.1 (Berkeley) 6/4/93"; +#else +__RCSID("$NetBSD: kvm_hppa.c,v 1.7 2014/02/19 20:21:22 dsl Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + +/* + * hppa machine dependent routines for kvm. + * XXX fredette - largely unimplemented so far. what is here + * is lifted and disabled. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include + +#include "kvm_private.h" + +#include +#include +#include +#include + +#ifndef btop +#define btop(x) (((unsigned)(x)) >> PGSHIFT) /* XXX */ +#define ptob(x) ((caddr_t)((x) << PGSHIFT)) /* XXX */ +#endif + +void +_kvm_freevtop(kvm_t *kd) +{ + + /* Not actually used for anything right now, but safe. */ + if (kd->vmst != 0) + free(kd->vmst); +} + +/*ARGSUSED*/ +int +_kvm_initvtop(kvm_t *kd) +{ + + return 0; +} + +/* + * Translate a kernel virtual address to a physical address. + */ +int +_kvm_kvatop(kvm_t *kd, vaddr_t va, paddr_t *pa) +{ +#if 0 + cpu_kcore_hdr_t *cpu_kh; + u_long page_off; + pd_entry_t pde; + pt_entry_t pte; + u_long pde_pa, pte_pa; +#endif + + if (ISALIVE(kd)) { + _kvm_err(kd, 0, "vatop called in live kernel!"); + return 0; + } + + _kvm_syserr(kd, 0, "could not read PTE"); + +#if 0 + cpu_kh = kd->cpu_data; + page_off = va & PGOFSET; + + /* + * Find and read the page directory entry. + */ + pde_pa = cpu_kh->ptdpaddr + (pdei(va) * sizeof(pd_entry_t)); + if (_kvm_pread(kd, kd->pmfd, (void *)&pde, sizeof(pde), + _kvm_pa2off(kd, pde_pa)) != sizeof(pde)) { + _kvm_syserr(kd, 0, "could not read PDE"); + goto lose; + } + + /* + * Find and read the page table entry. + */ + if ((pde & PG_V) == 0) { + _kvm_err(kd, 0, "invalid translation (invalid PDE)"); + goto lose; + } + pte_pa = (pde & PG_FRAME) + (ptei(va) * sizeof(pt_entry_t)); + if (_kvm_pread(kd, kd->pmfd, (void *) &pte, sizeof(pte), + _kvm_pa2off(kd, pte_pa)) != sizeof(pte)) { + _kvm_syserr(kd, 0, "could not read PTE"); + goto lose; + } + + /* + * Validate the PTE and return the physical address. + */ + if ((pte & PG_V) == 0) { + _kvm_err(kd, 0, "invalid translation (invalid PTE)"); + goto lose; + } + *pa = (pte & PG_FRAME) + page_off; + return (int)(NBPG - page_off); + + lose: +#endif + *pa = (u_long)~0L; + return 0; +} + +/* + * Translate a physical address to a file-offset in the crash dump. + */ +off_t +_kvm_pa2off(kvm_t *kd, paddr_t pa) +{ +#if 0 + cpu_kcore_hdr_t *cpu_kh; + phys_ram_seg_t *ramsegs; + off_t off; + int i; + + cpu_kh = kd->cpu_data; + ramsegs = (void *)((char *)(void *)cpu_kh + ALIGN(sizeof *cpu_kh)); + + off = 0; + for (i = 0; i < cpu_kh->nmemsegs; i++) { + if (pa >= ramsegs[i].start && + (pa - ramsegs[i].start) < ramsegs[i].size) { + off += (pa - ramsegs[i].start); + break; + } + off += ramsegs[i].size; + } + + return kd->dump_off + off; +#endif + return 0; +} + +/* + * Machine-dependent initialization for ALL open kvm descriptors, + * not just those for a kernel crash dump. Some architectures + * have to deal with these NOT being constants! (i.e. m68k) + */ +int +_kvm_mdopen(kvm_t *kd) +{ + + kd->usrstack = USRSTACK; + kd->min_uva = VM_MIN_ADDRESS; + kd->max_uva = VM_MAXUSER_ADDRESS; + + return 0; +} diff --git a/lib/libkvm/kvm_i386.c b/lib/libkvm/kvm_i386.c new file mode 100644 index 000000000..a317cc099 --- /dev/null +++ b/lib/libkvm/kvm_i386.c @@ -0,0 +1,236 @@ +/* $NetBSD: kvm_i386.c,v 1.30 2014/02/19 20:21:22 dsl Exp $ */ + +/*- + * Copyright (c) 1989, 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software developed by the Computer Systems + * Engineering group at Lawrence Berkeley Laboratory under DARPA contract + * BG 91-66 and contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)kvm_hp300.c 8.1 (Berkeley) 6/4/93"; +#else +__RCSID("$NetBSD: kvm_i386.c,v 1.30 2014/02/19 20:21:22 dsl Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + +/* + * i386 machine dependent routines for kvm. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include + +#include "kvm_private.h" + +#include +#include +#include +#include + +#ifndef btop +#define btop(x) (((unsigned)(x)) >> PGSHIFT) /* XXX */ +#define ptob(x) ((caddr_t)((x) << PGSHIFT)) /* XXX */ +#endif + +/* + * Indicates whether PAE is in use for the kernel image + * 0: native i386 memory mappings + * 1: i386 PAE mappings + */ +static int i386_use_pae; + +int _kvm_kvatop_i386(kvm_t *, vaddr_t, paddr_t *); +int _kvm_kvatop_i386pae(kvm_t *, vaddr_t, paddr_t *); + +void +_kvm_freevtop(kvm_t *kd) +{ + + /* Not actually used for anything right now, but safe. */ + if (kd->vmst != 0) + free(kd->vmst); +} + +/*ARGSUSED*/ +int +_kvm_initvtop(kvm_t *kd) +{ + cpu_kcore_hdr_t *cpu_kh = kd->cpu_data; + + i386_use_pae = 0; /* default: non PAE mode */ + if ((cpu_kh->pdppaddr & I386_KCORE_PAE) == I386_KCORE_PAE) + i386_use_pae = 1; + + return 0; +} + +/* + * Translate a kernel virtual address to a physical address. + */ +int +_kvm_kvatop(kvm_t *kd, vaddr_t va, paddr_t *pa) +{ + + if (ISALIVE(kd)) { + _kvm_err(kd, 0, "vatop called in live kernel!"); + return 0; + } + + switch (i386_use_pae) { + default: + case 0: + return _kvm_kvatop_i386(kd, va, pa); + case 1: + return _kvm_kvatop_i386pae(kd, va, pa); + } + +} + +/* + * Used to translate a virtual address to a physical address for systems + * with PAE mode disabled. Only two levels of virtual memory pages are + * dereferenced (L2 PDEs, then L1 PTEs). + */ +int +_kvm_kvatop_i386(kvm_t *kd, vaddr_t va, paddr_t *pa) +{ + cpu_kcore_hdr_t *cpu_kh; + u_long page_off; + pd_entry_t pde; + pt_entry_t pte; + paddr_t pde_pa, pte_pa; + + cpu_kh = kd->cpu_data; + page_off = va & PGOFSET; + + /* + * Find and read the page directory entry. + * pdppaddr being PAGE_SIZE aligned, we mask the option bits. + */ + pde_pa = (cpu_kh->pdppaddr & PG_FRAME) + (pl2_pi(va) * sizeof(pde)); + if (_kvm_pread(kd, kd->pmfd, (void *)&pde, sizeof(pde), + _kvm_pa2off(kd, pde_pa)) != sizeof(pde)) { + _kvm_syserr(kd, 0, "could not read PDE"); + goto lose; + } + + /* + * Find and read the page table entry. + */ + if ((pde & PG_V) == 0) { + _kvm_err(kd, 0, "invalid translation (invalid PDE)"); + goto lose; + } + if ((pde & PG_PS) != 0) { + /* + * This is a 4MB page. + */ + page_off = va & ~PG_LGFRAME; + *pa = (pde & PG_LGFRAME) + page_off; + return (int)(NBPD_L2 - page_off); + } + pte_pa = (pde & PG_FRAME) + (pl1_pi(va) * sizeof(pt_entry_t)); + if (_kvm_pread(kd, kd->pmfd, (void *) &pte, sizeof(pte), + _kvm_pa2off(kd, pte_pa)) != sizeof(pte)) { + _kvm_syserr(kd, 0, "could not read PTE"); + goto lose; + } + + /* + * Validate the PTE and return the physical address. + */ + if ((pte & PG_V) == 0) { + _kvm_err(kd, 0, "invalid translation (invalid PTE)"); + goto lose; + } + *pa = (pte & PG_FRAME) + page_off; + return (int)(NBPG - page_off); + + lose: + *pa = (paddr_t)~0L; + return 0; +} + +/* + * Translate a physical address to a file-offset in the crash dump. + */ +off_t +_kvm_pa2off(kvm_t *kd, paddr_t pa) +{ + cpu_kcore_hdr_t *cpu_kh; + phys_ram_seg_t *ramsegs; + off_t off; + int i; + + cpu_kh = kd->cpu_data; + ramsegs = (void *)((char *)(void *)cpu_kh + ALIGN(sizeof *cpu_kh)); + + off = 0; + for (i = 0; i < cpu_kh->nmemsegs; i++) { + if (pa >= ramsegs[i].start && + (pa - ramsegs[i].start) < ramsegs[i].size) { + off += (pa - ramsegs[i].start); + break; + } + off += ramsegs[i].size; + } + + return (kd->dump_off + off); +} + +/* + * Machine-dependent initialization for ALL open kvm descriptors, + * not just those for a kernel crash dump. Some architectures + * have to deal with these NOT being constants! (i.e. m68k) + */ +int +_kvm_mdopen(kvm_t *kd) +{ + + kd->usrstack = USRSTACK; + kd->min_uva = VM_MIN_ADDRESS; + kd->max_uva = VM_MAXUSER_ADDRESS; + + return 0; +} diff --git a/lib/libkvm/kvm_i386pae.c b/lib/libkvm/kvm_i386pae.c new file mode 100644 index 000000000..20226cc66 --- /dev/null +++ b/lib/libkvm/kvm_i386pae.c @@ -0,0 +1,130 @@ +/* $NetBSD: kvm_i386pae.c,v 1.2 2014/02/19 20:21:22 dsl Exp $ */ + +/* + * Copyright (c) 2010 Jean-Yves Migeon. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__RCSID("$NetBSD: kvm_i386pae.c,v 1.2 2014/02/19 20:21:22 dsl Exp $"); + +/* + * This will expose PAE functions, macros, definitions and constants. + * Note: this affects all virtual memory related functions. Only their + * PAE versions can be used below. + */ +#define PAE + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include + +#include "kvm_private.h" + +#include +#include +#include +#include + +int _kvm_kvatop_i386pae(kvm_t *, vaddr_t, paddr_t *); + +/* + * Used to translate a virtual address to a physical address for systems + * running under PAE mode. Three levels of virtual memory pages are handled + * here: the per-CPU L3 page, the 4 L2 PDs and the PTs. + */ +int +_kvm_kvatop_i386pae(kvm_t *kd, vaddr_t va, paddr_t *pa) +{ + cpu_kcore_hdr_t *cpu_kh; + u_long page_off; + pd_entry_t pde; + pt_entry_t pte; + paddr_t pde_pa, pte_pa; + + cpu_kh = kd->cpu_data; + page_off = va & PGOFSET; + + /* + * Find and read the PDE. Ignore the L3, as it is only a per-CPU + * page, not needed for kernel VA => PA translations. + * Remember that the 4 L2 pages are contiguous, so it is safe + * to increment pdppaddr to compute the address of the PDE. + * pdppaddr being PAGE_SIZE aligned, we mask the option bits. + */ + pde_pa = (cpu_kh->pdppaddr & PG_FRAME) + (pl2_pi(va) * sizeof(pde)); + if (_kvm_pread(kd, kd->pmfd, (void *)&pde, sizeof(pde), + _kvm_pa2off(kd, pde_pa)) != sizeof(pde)) { + _kvm_syserr(kd, 0, "could not read PDE"); + goto lose; + } + + /* + * Find and read the page table entry. + */ + if ((pde & PG_V) == 0) { + _kvm_err(kd, 0, "invalid translation (invalid PDE)"); + goto lose; + } + if ((pde & PG_PS) != 0) { + /* + * This is a 2MB page. + */ + page_off = va & ((vaddr_t)~PG_LGFRAME); + *pa = (pde & PG_LGFRAME) + page_off; + return (int)(NBPD_L2 - page_off); + } + + pte_pa = (pde & PG_FRAME) + (pl1_pi(va) * sizeof(pt_entry_t)); + if (_kvm_pread(kd, kd->pmfd, (void *) &pte, sizeof(pte), + _kvm_pa2off(kd, pte_pa)) != sizeof(pte)) { + _kvm_syserr(kd, 0, "could not read PTE"); + goto lose; + } + + /* + * Validate the PTE and return the physical address. + */ + if ((pte & PG_V) == 0) { + _kvm_err(kd, 0, "invalid translation (invalid PTE)"); + goto lose; + } + *pa = (pte & PG_FRAME) + page_off; + return (int)(NBPG - page_off); + +lose: + *pa = (paddr_t)~0L; + return 0; + +} diff --git a/lib/libkvm/kvm_ia64.c b/lib/libkvm/kvm_ia64.c new file mode 100644 index 000000000..e69de29bb diff --git a/lib/libkvm/kvm_m68k.c b/lib/libkvm/kvm_m68k.c new file mode 100644 index 000000000..de95e1691 --- /dev/null +++ b/lib/libkvm/kvm_m68k.c @@ -0,0 +1,171 @@ +/* $NetBSD: kvm_m68k.c,v 1.19 2014/01/27 21:00:01 matt Exp $ */ + +/*- + * Copyright (c) 1997 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Gordon W. Ross and Jason R. Thorpe. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Run-time kvm dispatcher for m68k machines. + * The actual MD code is in the files: + * kvm_m68k_cmn.c kvm_sun3.c ... + * + * Note: This file has to build on ALL m68k machines, + * so do NOT include any files here. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "kvm_private.h" +#include "kvm_m68k.h" + +__RCSID("$NetBSD: kvm_m68k.c,v 1.19 2014/01/27 21:00:01 matt Exp $"); + +struct name_ops { + const char *name; + struct kvm_ops *ops; +}; + +/* + * Match specific kcore types first, falling into a default. + */ +static struct name_ops optbl[] = { + { "sun2", &_kvm_ops_sun2 }, + { "sun3", &_kvm_ops_sun3 }, + { "sun3x", &_kvm_ops_sun3x }, + { NULL, &_kvm_ops_cmn }, +}; + +/* + * Prepare for translation of kernel virtual addresses into offsets + * into crash dump files. This is where we do the dispatch work. + */ +int +_kvm_initvtop(kvm_t *kd) +{ + cpu_kcore_hdr_t *h; + struct name_ops *nop; + struct vmstate *vm; + + vm = (struct vmstate *)_kvm_malloc(kd, sizeof (*vm)); + if (vm == 0) + return (-1); + + kd->vmst = vm; + + /* + * Use the machine name in the kcore header to determine + * our ops vector. When we reach an ops vector with + * no name, we've found a default. + */ + h = kd->cpu_data; + h->name[sizeof(h->name) - 1] = '\0'; /* sanity */ + for (nop = optbl; nop->name != NULL; nop++) + if (strcmp(nop->name, h->name) == 0) + break; + + vm->ops = nop->ops; + + /* + * Compute pgshift and pgofset. + */ + for (vm->pgshift = 0; (1 << vm->pgshift) < h->page_size; vm->pgshift++) + /* nothing */ ; + if ((1 << vm->pgshift) != h->page_size) + goto bad; + vm->pgofset = h->page_size - 1; + + if ((vm->ops->initvtop)(kd) < 0) + goto bad; + + return (0); + + bad: + kd->vmst = NULL; + free(vm); + return (-1); +} + +void +_kvm_freevtop(kvm_t *kd) +{ + (kd->vmst->ops->freevtop)(kd); + free(kd->vmst); +} + +int +_kvm_kvatop(kvm_t *kd, vaddr_t va, paddr_t *pap) +{ + return ((kd->vmst->ops->kvatop)(kd, va, pap)); +} + +off_t +_kvm_pa2off(kvm_t *kd, paddr_t pa) +{ + return ((kd->vmst->ops->pa2off)(kd, pa)); +} + +/* + * Machine-dependent initialization for ALL open kvm descriptors, + * not just those for a kernel crash dump. Some architectures + * have to deal with these NOT being constants! (i.e. m68k) + */ +int +_kvm_mdopen(kvm_t *kd) +{ + u_long max_uva; + extern struct ps_strings *__ps_strings; + +#if 0 /* XXX - These vary across m68k machines... */ + kd->usrstack = USRSTACK; + kd->min_uva = VM_MIN_ADDRESS; + kd->max_uva = VM_MAXUSER_ADDRESS; +#endif + /* This is somewhat hack-ish, but it works. */ + max_uva = (u_long) (__ps_strings + 1); + kd->usrstack = max_uva; + kd->max_uva = max_uva; + kd->min_uva = 0; + + return (0); +} diff --git a/lib/libkvm/kvm_m68k.h b/lib/libkvm/kvm_m68k.h new file mode 100644 index 000000000..b0c1e59c3 --- /dev/null +++ b/lib/libkvm/kvm_m68k.h @@ -0,0 +1,49 @@ +/* $NetBSD: kvm_m68k.h,v 1.6 2010/09/20 23:23:16 jym Exp $ */ + +/*- + * Copyright (c) 1997 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Gordon W. Ross and Jason R. Thorpe. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +struct kvm_ops { + int (*initvtop)(kvm_t *); + void (*freevtop)(kvm_t *); + int (*kvatop) (kvm_t *, vaddr_t, paddr_t *); + off_t (*pa2off) (kvm_t *, paddr_t); +}; + +struct vmstate { + struct kvm_ops *ops; /* ops vector */ + u_int32_t pgshift; /* log2(page_size) */ + u_int32_t pgofset; /* mask to find offset into page */ + void *private; /* private to the bottom layer */ +}; + +extern struct kvm_ops _kvm_ops_cmn; +extern struct kvm_ops _kvm_ops_sun2; +extern struct kvm_ops _kvm_ops_sun3; +extern struct kvm_ops _kvm_ops_sun3x; diff --git a/lib/libkvm/kvm_m68k_cmn.c b/lib/libkvm/kvm_m68k_cmn.c new file mode 100644 index 000000000..ae2254359 --- /dev/null +++ b/lib/libkvm/kvm_m68k_cmn.c @@ -0,0 +1,327 @@ +/* $NetBSD: kvm_m68k_cmn.c,v 1.18 2014/03/04 06:38:08 matt Exp $ */ + +/*- + * Copyright (c) 1989, 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software developed by the Computer Systems + * Engineering group at Lawrence Berkeley Laboratory under DARPA contract + * BG 91-66 and contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/*- + * Copyright (c) 1997 Jason R. Thorpe. All rights reserved. + * + * This code is derived from software developed by the Computer Systems + * Engineering group at Lawrence Berkeley Laboratory under DARPA contract + * BG 91-66 and contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)kvm_hp300.c 8.1 (Berkeley) 6/4/93"; +#else +__RCSID("$NetBSD: kvm_m68k_cmn.c,v 1.18 2014/03/04 06:38:08 matt Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + +/* + * Common m68k machine dependent routines for kvm. + * + * Note: This file has to build on ALL m68k machines, + * so do NOT include any files here. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "kvm_private.h" +#include "kvm_m68k.h" + +int _kvm_cmn_initvtop(kvm_t *); +void _kvm_cmn_freevtop(kvm_t *); +int _kvm_cmn_kvatop(kvm_t *, vaddr_t, paddr_t *); +off_t _kvm_cmn_pa2off(kvm_t *, paddr_t); + +struct kvm_ops _kvm_ops_cmn = { + _kvm_cmn_initvtop, + _kvm_cmn_freevtop, + _kvm_cmn_kvatop, + _kvm_cmn_pa2off }; + +static int vatop_030(kvm_t *, uint32_t, vaddr_t, paddr_t *); +static int vatop_040(kvm_t *, uint32_t, vaddr_t, paddr_t *); + +#define _kvm_btop(v, a) (((unsigned)(a)) >> (v)->pgshift) + +void +_kvm_cmn_freevtop(kvm_t *kd) +{ + /* No private state information to keep. */ +} + +int +_kvm_cmn_initvtop(kvm_t *kd) +{ + /* No private state information to keep. */ + return (0); +} + +int +_kvm_cmn_kvatop(kvm_t *kd, vaddr_t va, paddr_t *pa) +{ + cpu_kcore_hdr_t *h = kd->cpu_data; + struct m68k_kcore_hdr *m = &h->un._m68k; + int (*vtopf)(kvm_t *, uint32_t, vaddr_t, paddr_t *); + + if (ISALIVE(kd)) { + _kvm_err(kd, 0, "vatop called in live kernel!"); + return (0); + } + + /* + * 68040 and 68060 use same translation functions, + * as do 68030, 68851, HP MMU. + */ + if (m->mmutype == MMU_68040 || m->mmutype == MMU_68060) + vtopf = vatop_040; + else + vtopf = vatop_030; + + return ((*vtopf)(kd, m->sysseg_pa, va, pa)); +} + +/* + * Translate a physical address to a file-offset in the crash dump. + */ +off_t +_kvm_cmn_pa2off(kvm_t *kd, u_long pa) +{ + cpu_kcore_hdr_t *h = kd->cpu_data; + struct m68k_kcore_hdr *m = &h->un._m68k; + phys_ram_seg_t *rsp; + off_t off; + int i; + + off = 0; + rsp = m->ram_segs; + for (i = 0; i < M68K_NPHYS_RAM_SEGS && rsp[i].size != 0; i++) { + if (pa >= rsp[i].start && + pa < (rsp[i].start + rsp[i].size)) { + pa -= rsp[i].start; + break; + } + off += rsp[i].size; + } + return (kd->dump_off + off + pa); +} + +/***************************************************************** + * Local stuff... + */ + +static int +vatop_030(kvm_t *kd, uint32_t stpa, vaddr_t va, paddr_t *pa) +{ + cpu_kcore_hdr_t *h = kd->cpu_data; + struct m68k_kcore_hdr *m = &h->un._m68k; + struct vmstate *vm = kd->vmst; + paddr_t addr; + uint32_t ste, pte; + u_int p, offset; + + offset = va & vm->pgofset; + + /* + * We may be called before address translation is initialized. + * This is typically used to find the dump magic number. This + * means we do not yet have the kernel page tables available, + * so we must to a simple relocation. + */ + if (va < m->relocend) { + *pa = (va - h->kernbase) + m->reloc; + return (h->page_size - offset); + } + + addr = stpa + ((va >> m->sg_ishift) * sizeof(u_int32_t)); + + /* + * Can't use KREAD to read kernel segment table entries. + * Fortunately it is 1-to-1 mapped so we don't have to. + */ + if (stpa == m->sysseg_pa) { + if (_kvm_pread(kd, kd->pmfd, &ste, sizeof(ste), + _kvm_cmn_pa2off(kd, addr)) != sizeof(ste)) + goto invalid; + } else if (KREAD(kd, addr, &ste)) + goto invalid; + if ((ste & m->sg_v) == 0) { + _kvm_err(kd, 0, "invalid segment (%x)", ste); + return(0); + } + p = _kvm_btop(vm, va & m->sg_pmask); + addr = (ste & m->sg_frame) + (p * sizeof(u_int32_t)); + + /* + * Address from STE is a physical address so don't use kvm_read. + */ + if (_kvm_pread(kd, kd->pmfd, &pte, sizeof(pte), + _kvm_cmn_pa2off(kd, addr)) != sizeof(pte)) + goto invalid; + addr = pte & m->pg_frame; + if ((pte & m->pg_v) == 0) { + _kvm_err(kd, 0, "page not valid"); + return (0); + } + *pa = addr + offset; + + return (h->page_size - offset); +invalid: + _kvm_err(kd, 0, "invalid address (%lx)", va); + return (0); +} + +static int +vatop_040(kvm_t *kd, uint32_t stpa, vaddr_t va, paddr_t *pa) +{ + cpu_kcore_hdr_t *h = kd->cpu_data; + struct m68k_kcore_hdr *m = &h->un._m68k; + struct vmstate *vm = kd->vmst; + paddr_t addr; + uint32_t stpa2; + uint32_t ste, pte; + u_int offset; + + offset = va & vm->pgofset; + + /* + * We may be called before address translation is initialized. + * This is typically used to find the dump magic number. This + * means we do not yet have the kernel page tables available, + * so we must to a simple relocation. + */ + if (va < m->relocend) { + *pa = (va - h->kernbase) + m->reloc; + return (h->page_size - offset); + } + + addr = stpa + ((va >> m->sg40_shift1) * sizeof(u_int32_t)); + + /* + * Can't use KREAD to read kernel segment table entries. + * Fortunately it is 1-to-1 mapped so we don't have to. + */ + if (stpa == m->sysseg_pa) { + if (_kvm_pread(kd, kd->pmfd, &ste, sizeof(ste), + _kvm_cmn_pa2off(kd, addr)) != sizeof(ste)) + goto invalid; + } else if (KREAD(kd, addr, &ste)) + goto invalid; + if ((ste & m->sg_v) == 0) { + _kvm_err(kd, 0, "invalid level 1 descriptor (%x)", + ste); + return((off_t)0); + } + stpa2 = (ste & m->sg40_addr1); + addr = stpa2 + (((va & m->sg40_mask2) >> m->sg40_shift2) * + sizeof(u_int32_t)); + + /* + * Address from level 1 STE is a physical address, + * so don't use kvm_read. + */ + if (_kvm_pread(kd, kd->pmfd, &ste, sizeof(ste), + _kvm_cmn_pa2off(kd, addr)) != sizeof(ste)) + goto invalid; + if ((ste & m->sg_v) == 0) { + _kvm_err(kd, 0, "invalid level 2 descriptor (%x)", + ste); + return((off_t)0); + } + stpa2 = (ste & m->sg40_addr2); + addr = stpa2 + (((va & m->sg40_mask3) >> m->sg40_shift3) * + sizeof(u_int32_t)); + + /* + * Address from STE is a physical address so don't use kvm_read. + */ + if (_kvm_pread(kd, kd->pmfd, &pte, sizeof(pte), + _kvm_cmn_pa2off(kd, addr)) != sizeof(pte)) + goto invalid; + addr = pte & m->pg_frame; + if ((pte & m->pg_v) == 0) { + _kvm_err(kd, 0, "page not valid"); + return (0); + } + *pa = addr + offset; + + return (h->page_size - offset); + +invalid: + _kvm_err(kd, 0, "invalid address (%lx)", va); + return (0); +} diff --git a/lib/libkvm/kvm_mips.c b/lib/libkvm/kvm_mips.c new file mode 100644 index 000000000..5ab664d70 --- /dev/null +++ b/lib/libkvm/kvm_mips.c @@ -0,0 +1,244 @@ +/* $NetBSD: kvm_mips.c,v 1.22 2014/02/19 20:21:22 dsl Exp $ */ + +/* + * Copyright (c) 1994, 1995 Carnegie-Mellon University. + * All rights reserved. + * + * Author: Chris G. Demetriou + * + * Permission to use, copy, modify and distribute this software and + * its documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +/* + * Modified for NetBSD/mips by Jason R. Thorpe, Numerical Aerospace + * Simulation Facility, NASA Ames Research Center. + */ + +#include +#if defined(LIBC_SCCS) && !defined(lint) +__RCSID("$NetBSD: kvm_mips.c,v 1.22 2014/02/19 20:21:22 dsl Exp $"); +#endif /* LIBC_SCCS and not lint */ + +/* + * MIPS machine dependent routines for kvm. + */ + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include + +#include +#include + +#include "kvm_private.h" + +#include +#include + +void +_kvm_freevtop(kvm_t *kd) +{ + + /* Not actually used for anything right now, but safe. */ + if (kd->vmst != 0) + free(kd->vmst); +} + +int +_kvm_initvtop(kvm_t *kd) +{ + + return (0); +} + +/* + * Translate a kernel virtual address to a physical address. + */ +int +_kvm_kvatop(kvm_t *kd, vaddr_t va, paddr_t *pa) +{ + cpu_kcore_hdr_t *cpu_kh; + int page_off; + u_int pte; + paddr_t pte_pa; + + if (ISALIVE(kd)) { + _kvm_err(kd, 0, "vatop called in live kernel!"); + return((off_t)0); + } + + cpu_kh = kd->cpu_data; + page_off = va & PGOFSET; + +#ifdef _LP64 + if (MIPS_XKPHYS_P(va)) { + /* + * Direct-mapped cached address: just convert it. + */ + *pa = MIPS_XKPHYS_TO_PHYS(va); + return (NBPG - page_off); + } + + if (va < MIPS_XKPHYS_START) { + /* + * XUSEG (user virtual address space) - invalid. + */ + _kvm_err(kd, 0, "invalid kernel virtual address"); + goto lose; + } +#else + if (va < MIPS_KSEG0_START) { + /* + * KUSEG (user virtual address space) - invalid. + */ + _kvm_err(kd, 0, "invalid kernel virtual address"); + goto lose; + } +#endif + + if (MIPS_KSEG0_P(va)) { + /* + * Direct-mapped cached address: just convert it. + */ + *pa = MIPS_KSEG0_TO_PHYS(va); + return (NBPG - page_off); + } + + if (MIPS_KSEG1_P(va)) { + /* + * Direct-mapped uncached address: just convert it. + */ + *pa = MIPS_KSEG1_TO_PHYS(va); + return (NBPG - page_off); + } + +#ifdef _LP64 + if (va >= MIPS_KSEG2_START) { + /* + * KUSEG (user virtual address space) - invalid. + */ + _kvm_err(kd, 0, "invalid kernel virtual address"); + goto lose; + } +#endif + + /* + * We now know that we're a KSEG2 (kernel virtually mapped) + * address. Translate the address using the pmap's kernel + * page table. + */ + + /* + * Step 1: Make sure the kernel page table has a translation + * for the address. + */ +#ifdef _LP64 + if (va >= (MIPS_XKSEG_START + (cpu_kh->sysmapsize * NBPG))) { + _kvm_err(kd, 0, "invalid XKSEG address"); + goto lose; + } +#else + if (va >= (MIPS_KSEG2_START + (cpu_kh->sysmapsize * NBPG))) { + _kvm_err(kd, 0, "invalid KSEG2 address"); + goto lose; + } +#endif + + /* + * Step 2: Locate and read the PTE. + */ + pte_pa = cpu_kh->sysmappa + + (((va - MIPS_KSEG2_START) >> PGSHIFT) * sizeof(u_int)); + if (_kvm_pread(kd, kd->pmfd, &pte, sizeof(pte), + _kvm_pa2off(kd, pte_pa)) != sizeof(pte)) { + _kvm_syserr(kd, 0, "could not read PTE"); + goto lose; + } + + /* + * Step 3: Validate the PTE and return the physical address. + */ + if ((pte & cpu_kh->pg_v) == 0) { + _kvm_err(kd, 0, "invalid translation (invalid PTE)"); + goto lose; + } + *pa = (((pte & cpu_kh->pg_frame) >> cpu_kh->pg_shift) << PGSHIFT) + + page_off; + return (NBPG - page_off); + + lose: + *pa = -1; + return (0); +} + +/* + * Translate a physical address to a file-offset in the crash dump. + */ +off_t +_kvm_pa2off(kvm_t *kd, paddr_t pa) +{ + cpu_kcore_hdr_t *cpu_kh; + phys_ram_seg_t *ramsegs; + off_t off; + int i; + + cpu_kh = kd->cpu_data; + ramsegs = (phys_ram_seg_t *)((char *)cpu_kh + ALIGN(sizeof *cpu_kh)); + + off = 0; + for (i = 0; i < cpu_kh->nmemsegs; i++) { + if (pa >= ramsegs[i].start && + (pa - ramsegs[i].start) < ramsegs[i].size) { + off += (pa - ramsegs[i].start); + break; + } + off += ramsegs[i].size; + } + + return (kd->dump_off + off); +} + +/* + * Machine-dependent initialization for ALL open kvm descriptors, + * not just those for a kernel crash dump. Some architectures + * have to deal with these NOT being constants! (i.e. m68k) + */ +int +_kvm_mdopen(kvm_t *kd) +{ + + kd->usrstack = USRSTACK; + kd->min_uva = VM_MIN_ADDRESS; + kd->max_uva = VM_MAXUSER_ADDRESS; + + return (0); +} diff --git a/lib/libkvm/kvm_nlist.3 b/lib/libkvm/kvm_nlist.3 new file mode 100644 index 000000000..4ff4ae0f3 --- /dev/null +++ b/lib/libkvm/kvm_nlist.3 @@ -0,0 +1,93 @@ +.\" $NetBSD: kvm_nlist.3,v 1.11 2003/08/07 16:44:37 agc Exp $ +.\" +.\" Copyright (c) 1992, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software developed by the Computer Systems +.\" Engineering group at Lawrence Berkeley Laboratory under DARPA contract +.\" BG 91-66 and contributed to Berkeley. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)kvm_nlist.3 8.1 (Berkeley) 6/4/93 +.\" +.Dd May 11, 2003 +.Dt KVM_NLIST 3 +.Os +.Sh NAME +.Nm kvm_nlist +.Nd retrieve symbol table names from a kernel image +.Sh LIBRARY +.Lb libkvm +.Sh SYNOPSIS +.In kvm.h +.In nlist.h +.Ft int +.Fn kvm_nlist "kvm_t *kd" "struct nlist *nl" +.Sh DESCRIPTION +.Fn kvm_nlist +retrieves the symbol table entries indicated by the name list argument +.Fa \&nl . +This argument points to an array of nlist structures, terminated by +an entry whose n_name field is +.Dv NULL +(see +.Xr nlist 3 ) . +Each symbol is looked up using the n_name field, and if found, the +corresponding n_type and n_value fields are filled in. +These fields are set to 0 if the symbol is not found. +.Pp +If +.Fa \&kd +was created by a call to +.Fn kvm_open +with a +.Dv NULL +executable image name, +.Fn kvm_nlist +will use +.Pa /dev/ksyms +to retrieve the kernel symbol table. +.Sh RETURN VALUES +The +.Fn kvm_nlist +function returns the number of invalid entries found. +If the kernel symbol table was unreadable, -1 is returned. +.Sh FILES +.Bl -tag -width /dev/ksyms -compact +.It Pa /dev/ksyms +.El +.Sh SEE ALSO +.Xr kvm 3 , +.Xr kvm_close 3 , +.Xr kvm_getargv 3 , +.Xr kvm_getenvv 3 , +.Xr kvm_geterr 3 , +.Xr kvm_getprocs 3 , +.Xr kvm_open 3 , +.Xr kvm_openfiles 3 , +.Xr kvm_read 3 , +.Xr kvm_write 3 , +.Xr ksyms 4 diff --git a/lib/libkvm/kvm_open.3 b/lib/libkvm/kvm_open.3 new file mode 100644 index 000000000..55f4a673e --- /dev/null +++ b/lib/libkvm/kvm_open.3 @@ -0,0 +1,237 @@ +.\" $NetBSD: kvm_open.3,v 1.18 2011/09/12 21:11:32 christos Exp $ +.\" +.\" Copyright (c) 1992, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software developed by the Computer Systems +.\" Engineering group at Lawrence Berkeley Laboratory under DARPA contract +.\" BG 91-66 and contributed to Berkeley. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)kvm_open.3 8.3 (Berkeley) 4/19/94 +.\" +.Dd September 14, 2011 +.Dt KVM_OPEN 3 +.Os +.Sh NAME +.Nm kvm_open , +.Nm kvm_openfiles , +.Nm kvm_close +.Nd initialize kernel virtual memory access +.Sh LIBRARY +.Lb libkvm +.Sh SYNOPSIS +.In fcntl.h +.In kvm.h +.Ft kvm_t * +.Fn kvm_open "const char *execfile" "const char *corefile" "char *swapfile" "int flags" "const char *errstr" +.Ft kvm_t * +.Fn kvm_openfiles "const char *execfile" "const char *corefile" "char *swapfile" "int flags" "char *errbuf" +.Ft int +.Fn kvm_close "kvm_t *kd" +.Sh DESCRIPTION +The functions +.Fn kvm_open +and +.Fn kvm_openfiles +return a descriptor used to access kernel virtual memory +via the +.Xr kvm 3 +library routines. +Both active kernels and crash dumps are accessible +through this interface. +.Pp +.Fa execfile +is the executable image of the kernel being examined. +This file must contain a symbol table. +If this argument is +.Dv NULL , +the currently running system is assumed; in this case, the functions will +attempt to use the +.Xr ksyms 4 +device indicated by +.Dv _PATH_KSYMS +in +.In paths.h ; +if that fails, then they will use the file indicated by the +.Xr sysctl 3 +variable +.Va machdep.booted_kernel , +or (if the sysctl information is not available) +the default kernel path indicated by +.Dv _PATH_UNIX +in +.In paths.h . +.Pp +.Fa corefile +is the kernel memory device file. +It can be either +.Pa /dev/mem +or a crash dump core generated by +.Xr savecore 8 . +If +.Fa corefile +is +.Dv NULL , +the default indicated by +.Dv _PATH_MEM +from +.In paths.h +is used. +.Pp +.Fa swapfile +should indicate the swap device. +If +.Dv NULL , +.Dv _PATH_DRUM +from +.In paths.h +is used. +.Pp +The +.Fa flags +argument indicates read/write access as in +.Xr open 2 +and applies only to the core file. +The only permitted flags from +.Xr open 2 +are +.Dv O_RDONLY , +.Dv O_WRONLY , +and +.Dv O_RDWR . +.Pp +As a special case, a +.Fa flags +argument of +.Dv KVM_NO_FILES +will initialize the +.Xr kvm 3 +library for use on active kernels only using +.Xr sysctl 3 +for retrieving kernel data and ignores the +.Fa execfile , +.Fa corefile +and +.Fa swapfile +arguments. +Only a small subset of the +.Xr kvm 3 +library functions are available using this method. +These are currently +.Xr kvm_getproc2 3 , +.Xr kvm_getargv2 3 +and +.Xr kvm_getenvv2 3 . +.Pp +There are two open routines which differ only with respect to +the error mechanism. +One provides backward compatibility with the SunOS kvm library, while the +other provides an improved error reporting framework. +.Pp +The +.Fn kvm_open +function is the Sun kvm compatible open call. +Here, the +.Fa errstr +argument indicates how errors should be handled. +If it is +.Dv NULL , +no errors are reported and the application cannot know the +specific nature of the failed kvm call. +If it is not +.Dv NULL , +errors are printed to stderr with +.Fa errstr +prepended to the message, as in +.Xr perror 3 . +Normally, the name of the program is used here. +The string is assumed to persist at least until the corresponding +.Fn kvm_close +call. +.Pp +The +.Fn kvm_openfiles +function provides +.Bx +style error reporting. +Here, error messages are not printed out by the library. +Instead, the application obtains the error message +corresponding to the most recent kvm library call using +.Fn kvm_geterr +(see +.Xr kvm_geterr 3 ) . +The results are undefined if the most recent kvm call did not produce +an error. +Since +.Fn kvm_geterr +requires a kvm descriptor, but the open routines return +.Dv NULL +on failure, +.Fn kvm_geterr +cannot be used to get the error message if open fails. +Thus, +.Fn kvm_openfiles +will place any error message in the +.Fa errbuf +argument. +This buffer should be _POSIX2_LINE_MAX characters large (from +.In limits.h ) . +.Sh RETURN VALUES +The +.Fn kvm_open +and +.Fn kvm_openfiles +functions both return a descriptor to be used +in all subsequent kvm library calls. +The library is fully re-entrant. +On failure, +.Dv NULL +is returned, in which case +.Fn kvm_openfiles +writes the error message into +.Fa errbuf . +.Pp +The +.Fn kvm_close +function returns 0 on success and -1 on failure. +.Sh SEE ALSO +.Xr open 2 , +.Xr kvm 3 , +.Xr kvm_getargv 3 , +.Xr kvm_getenvv 3 , +.Xr kvm_geterr 3 , +.Xr kvm_getkernelname 3 , +.Xr kvm_getprocs 3 , +.Xr kvm_nlist 3 , +.Xr kvm_read 3 , +.Xr kvm_write 3 +.Sh BUGS +There should not be two open calls. +The ill-defined error semantics of the Sun library +and the desire to have a backward-compatible library for +.Bx +left little choice. diff --git a/lib/libkvm/kvm_or1k.c b/lib/libkvm/kvm_or1k.c new file mode 100644 index 000000000..3306eb710 --- /dev/null +++ b/lib/libkvm/kvm_or1k.c @@ -0,0 +1,126 @@ +/* $NetBSD: kvm_or1k.c,v 1.1 2014/09/03 19:34:26 matt Exp $ */ + +/*- + * Copyright (c) 2014 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Matt Thomas of 3am Software Foundry. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * OR1K machine dependent routines for kvm. + */ + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include "kvm_private.h" + +#include +#include +#include + +__RCSID("$NetBSD: kvm_or1k.c,v 1.1 2014/09/03 19:34:26 matt Exp $"); + +void +_kvm_freevtop(kvm_t *kd) +{ + if (kd->vmst != 0) + free(kd->vmst); +} + +/*ARGSUSED*/ +int +_kvm_initvtop(kvm_t *kd) +{ + + return 0; +} + +/* + * Translate a KVA to a PA + */ +int +_kvm_kvatop(kvm_t *kd, vaddr_t va, paddr_t *pa) +{ +// cpu_kcore_hdr_t *cpu_kh; + + if (ISALIVE(kd)) { + _kvm_err(kd, 0, "vatop called in live kernel!"); + return 0; + } + + /* No hit -- no translation */ + *pa = (u_long)~0UL; + return 0; +} + +off_t +_kvm_pa2off(kvm_t *kd, paddr_t pa) +{ + cpu_kcore_hdr_t *cpu_kh; + phys_ram_seg_t *ram; + off_t off; + void *e; + + cpu_kh = kd->cpu_data; + e = (char *) kd->cpu_data + kd->cpu_dsize; + ram = (void *)((char *)(void *)cpu_kh + ALIGN(sizeof *cpu_kh)); + off = kd->dump_off; + do { + if (pa >= ram->start && (pa - ram->start) < ram->size) { + return off + (pa - ram->start); + } + ram++; + off += ram->size; + } while ((void *) ram < e && ram->size); + + _kvm_err(kd, 0, "pa2off failed for pa %#" PRIxPADDR "\n", pa); + return (off_t) -1; +} + +/* + * Machine-dependent initialization for ALL open kvm descriptors, + * not just those for a kernel crash dump. Some architectures + * have to deal with these NOT being constants! (i.e. m68k) + */ +int +_kvm_mdopen(kvm_t *kd) +{ + kd->usrstack = USRSTACK; + kd->min_uva = VM_MIN_ADDRESS; + kd->max_uva = VM_MAXUSER_ADDRESS; + + return (0); +} diff --git a/lib/libkvm/kvm_powerpc.c b/lib/libkvm/kvm_powerpc.c new file mode 100644 index 000000000..f8c5eb9e7 --- /dev/null +++ b/lib/libkvm/kvm_powerpc.c @@ -0,0 +1,381 @@ +/* $NetBSD: kvm_powerpc.c,v 1.13 2014/01/27 21:00:01 matt Exp $ */ + +/* + * Copyright (c) 2005 Wasabi Systems, Inc. + * All rights reserved. + * + * Written by Allen Briggs for Wasabi Systems, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed for the NetBSD Project by + * Wasabi Systems, Inc. + * 4. The name of Wasabi Systems, Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/*- + * Copyright (C) 1996 Wolfgang Solfrank. + * Copyright (C) 1996 TooLs GmbH. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by TooLs GmbH. + * 4. The name of TooLs GmbH may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * PowerPC machine dependent routines for kvm. + */ + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include "kvm_private.h" + +#include +#include + +#include +#include +#include +#include + +__RCSID("$NetBSD: kvm_powerpc.c,v 1.13 2014/01/27 21:00:01 matt Exp $"); + +static int _kvm_match_601bat(kvm_t *, vaddr_t, paddr_t *, int *); +static int _kvm_match_bat(kvm_t *, vaddr_t, paddr_t *, int *); +static int _kvm_match_sr(kvm_t *, vaddr_t, paddr_t *, int *); +static struct pte *_kvm_scan_pteg(struct pteg *, uint32_t, uint32_t, int); + +void +_kvm_freevtop(kvm_t *kd) +{ + if (kd->vmst != 0) + free(kd->vmst); +} + +/*ARGSUSED*/ +int +_kvm_initvtop(kvm_t *kd) +{ + + return 0; +} + +#define BAT601_SIZE(b) ((((b) << 17) | ~BAT601_BLPI) + 1) + +static int +_kvm_match_601bat(kvm_t *kd, vaddr_t va, paddr_t *pa, int *off) +{ + cpu_kcore_hdr_t *cpu_kh; + u_long pgoff; + size_t size; + int i, nbat; + + cpu_kh = kd->cpu_data; + nbat = 4; + for (i=0 ; idbatu[i])) + continue; + if (BAT601_VA_MATCH_P(cpu_kh->dbatu[i], cpu_kh->dbatl[i], va)) { + size = BAT601_SIZE(cpu_kh->dbatu[i] & BAT601_BSM); + pgoff = va & (size-1); + *pa = (cpu_kh->dbatl[i] & BAT601_PBN) + pgoff; + *off = size - pgoff; + return 1; + } + } + return 0; +} + +#undef BAT601_SIZE + +#define BAT_SIZE(b) ((((b) << 15) | ~BAT_EPI) + 1) + +static int +_kvm_match_bat(kvm_t *kd, vaddr_t va, paddr_t *pa, int *off) +{ + cpu_kcore_hdr_t *cpu_kh; + u_long pgoff; + size_t size; + int i, nbat; + + cpu_kh = kd->cpu_data; + /* + * Assume that we're looking for data and check only the dbats. + */ + nbat = 8; + for (i=0 ; idbatu[i] & BAT_Vs) != 0) + && (BAT_VA_MATCH_P(cpu_kh->dbatu[i], va))) { + size = BAT_SIZE(cpu_kh->dbatu[i] & BAT_BL); + pgoff = va & (size-1); + *pa = (cpu_kh->dbatl[i] & BAT_RPN) + pgoff; + *off = size - pgoff; + return 1; + } + } + return 0; +} + +#undef BAT_SIZE + +#define SR_VSID_HASH_MASK 0x0007ffff + +static struct pte * +_kvm_scan_pteg(struct pteg *pteg, uint32_t vsid, uint32_t api, int secondary) +{ + struct pte *pte; + u_long ptehi; + int i; + + for (i=0 ; i<8 ; i++) { + pte = &pteg->pt[i]; + ptehi = (u_long) pte->pte_hi; + if ((ptehi & PTE_VALID) == 0) + continue; + if ((ptehi & PTE_HID) != secondary) + continue; + if (((ptehi & PTE_VSID) >> PTE_VSID_SHFT) != vsid) + continue; + if (((ptehi & PTE_API) >> PTE_API_SHFT) != api) + continue; + return pte; + } + return NULL; +} + +#define HASH_MASK 0x0007ffff + +static int +_kvm_match_sr(kvm_t *kd, vaddr_t va, paddr_t *pa, int *off) +{ + cpu_kcore_hdr_t *cpu_kh; + struct pteg pteg; + struct pte *pte; + uint32_t sr, pgoff, vsid, pgidx, api, hash; + uint32_t htaborg, htabmask, mhash; + paddr_t pteg_vaddr; + + cpu_kh = kd->cpu_data; + + sr = cpu_kh->sr[(va >> 28) & 0xf]; + if ((sr & SR_TYPE) != 0) { + /* Direct-store segment (shouldn't be) */ + return 0; + } + + pgoff = va & ADDR_POFF; + vsid = sr & SR_VSID; + pgidx = (va & ADDR_PIDX) >> ADDR_PIDX_SHFT; + api = pgidx >> 10; + hash = (vsid & HASH_MASK) ^ pgidx; + + htaborg = cpu_kh->sdr1 & 0xffff0000; + htabmask = cpu_kh->sdr1 & 0x1ff; + + mhash = (hash >> 10) & htabmask; + + pteg_vaddr = ( htaborg & 0xfe000000) | ((hash & 0x3ff) << 6) + | ((htaborg & 0x01ff0000) | (mhash << 16)); + + if (_kvm_pread(kd, kd->pmfd, (void *) &pteg, sizeof(pteg), + _kvm_pa2off(kd, pteg_vaddr)) != sizeof(pteg)) { + _kvm_syserr(kd, 0, "could not read primary PTEG"); + return 0; + } + + if ((pte = _kvm_scan_pteg(&pteg, vsid, api, 0)) != NULL) { + *pa = (pte->pte_lo & PTE_RPGN) | pgoff; + *off = NBPG - pgoff; + return 1; + } + + hash = (~hash) & HASH_MASK; + mhash = (hash >> 10) & htabmask; + + pteg_vaddr = ( htaborg & 0xfe000000) | ((hash & 0x3ff) << 6) + | ((htaborg & 0x01ff0000) | (mhash << 16)); + + if (_kvm_pread(kd, kd->pmfd, (void *) &pteg, sizeof(pteg), + _kvm_pa2off(kd, pteg_vaddr)) != sizeof(pteg)) { + _kvm_syserr(kd, 0, "could not read secondary PTEG"); + return 0; + } + + if ((pte = _kvm_scan_pteg(&pteg, vsid, api, 0)) != NULL) { + *pa = (pte->pte_lo & PTE_RPGN) | pgoff; + *off = NBPG - pgoff; + return 1; + } + + return 0; +} + +/* + * Translate a KVA to a PA + */ +int +_kvm_kvatop(kvm_t *kd, vaddr_t va, paddr_t *pa) +{ + cpu_kcore_hdr_t *cpu_kh; + int offs; + uint32_t pvr; + + if (ISALIVE(kd)) { + _kvm_err(kd, 0, "vatop called in live kernel!"); + return 0; + } + + cpu_kh = kd->cpu_data; + + pvr = (cpu_kh->pvr >> 16); + if (MPC745X_P(pvr)) + pvr = MPC7450; + + switch (pvr) { + case MPC601: + /* Check for a BAT hit first */ + if (_kvm_match_601bat(kd, va, pa, &offs)) { + return offs; + } + + /* No BAT hit; check page tables */ + if (_kvm_match_sr(kd, va, pa, &offs)) { + return offs; + } + break; + + case MPC603: + case MPC603e: + case MPC603ev: + case MPC604: + case MPC604ev: + case MPC750: + case IBM750FX: + case MPC7400: + case MPC7450: + case MPC7410: + case MPC8240: + case MPC8245: + /* Check for a BAT hit first */ + if (_kvm_match_bat(kd, va, pa, &offs)) { + return offs; + } + + /* No BAT hit; check page tables */ + if (_kvm_match_sr(kd, va, pa, &offs)) { + return offs; + } + break; + + default: + _kvm_err(kd, 0, "Unsupported CPU type (pvr 0x%08lx)!", + (unsigned long) cpu_kh->pvr); + break; + } + + /* No hit -- no translation */ + *pa = (paddr_t)~0UL; + return 0; +} + +off_t +_kvm_pa2off(kvm_t *kd, paddr_t pa) +{ + cpu_kcore_hdr_t *cpu_kh; + phys_ram_seg_t *ram; + off_t off; + void *e; + + cpu_kh = kd->cpu_data; + e = (char *) kd->cpu_data + kd->cpu_dsize; + ram = (void *)((char *)(void *)cpu_kh + ALIGN(sizeof *cpu_kh)); + off = kd->dump_off; + do { + if (pa >= ram->start && (pa - ram->start) < ram->size) { + return off + (pa - ram->start); + } + ram++; + off += ram->size; + } while ((void *) ram < e && ram->size); + + _kvm_err(kd, 0, "pa2off failed for pa %#" PRIxPADDR "\n", pa); + return (off_t) -1; +} + +/* + * Machine-dependent initialization for ALL open kvm descriptors, + * not just those for a kernel crash dump. Some architectures + * have to deal with these NOT being constants! (i.e. m68k) + */ +int +_kvm_mdopen(kvm_t *kd) +{ + uintptr_t max_uva; + extern struct ps_strings *__ps_strings; + +#if 0 /* XXX - These vary across powerpc machines... */ + kd->usrstack = USRSTACK; + kd->min_uva = VM_MIN_ADDRESS; + kd->max_uva = VM_MAXUSER_ADDRESS; +#endif + /* This is somewhat hack-ish, but it works. */ + max_uva = (uintptr_t) (__ps_strings + 1); + kd->usrstack = max_uva; + kd->max_uva = max_uva; + kd->min_uva = 0; + + return (0); +} diff --git a/lib/libkvm/kvm_powerpc64.c b/lib/libkvm/kvm_powerpc64.c new file mode 100644 index 000000000..6ac7fc86d --- /dev/null +++ b/lib/libkvm/kvm_powerpc64.c @@ -0,0 +1,184 @@ +/* $NetBSD: kvm_powerpc64.c,v 1.6 2014/08/23 02:25:23 matt Exp $ */ + +/* + * Copyright (c) 2005 Wasabi Systems, Inc. + * All rights reserved. + * + * Written by Allen Briggs for Wasabi Systems, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed for the NetBSD Project by + * Wasabi Systems, Inc. + * 4. The name of Wasabi Systems, Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/*- + * Copyright (C) 1996 Wolfgang Solfrank. + * Copyright (C) 1996 TooLs GmbH. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by TooLs GmbH. + * 4. The name of TooLs GmbH may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * PowerPC machine dependent routines for kvm. + */ + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include "kvm_private.h" + +#include +#include + +#include +#include +#include + +__RCSID("$NetBSD: kvm_powerpc64.c,v 1.6 2014/08/23 02:25:23 matt Exp $"); + +void +_kvm_freevtop(kvm_t *kd) +{ + if (kd->vmst != 0) + free(kd->vmst); +} + +/*ARGSUSED*/ +int +_kvm_initvtop(kvm_t *kd) +{ + + return 0; +} + +#define SR_VSID_HASH_MASK 0x0007ffff + +#define HASH_MASK 0x0007ffff + +/* + * Translate a KVA to a PA + */ +int +_kvm_kvatop(kvm_t *kd, vaddr_t va, paddr_t *pa) +{ + + if (ISALIVE(kd)) { + _kvm_err(kd, 0, "vatop called in live kernel!"); + return 0; + } + +#if 0 + cpu_kcore_hdr_t *cpu_kh = kd->cpu_data; + uint32_t pvr = (cpu_kh->pvr >> 16); +#endif + + + /* No hit -- no translation */ + *pa = (u_long)~0UL; + return 0; +} + +off_t +_kvm_pa2off(kvm_t *kd, paddr_t pa) +{ + cpu_kcore_hdr_t *cpu_kh; + phys_ram_seg_t *ram; + off_t off; + void *e; + + cpu_kh = kd->cpu_data; + e = (char *) kd->cpu_data + kd->cpu_dsize; + ram = (void *)((char *)(void *)cpu_kh + ALIGN(sizeof *cpu_kh)); + off = kd->dump_off; + do { + if (pa >= ram->start && (pa - ram->start) < ram->size) { + return off + (pa - ram->start); + } + ram++; + off += ram->size; + } while ((void *) ram < e && ram->size); + + _kvm_err(kd, 0, "pa2off failed for pa 0x%08lx\n", pa); + return (off_t) -1; +} + +/* + * Machine-dependent initialization for ALL open kvm descriptors, + * not just those for a kernel crash dump. Some architectures + * have to deal with these NOT being constants! (i.e. m68k) + */ +int +_kvm_mdopen(kvm_t *kd) +{ + uintptr_t max_uva; + extern struct ps_strings *__ps_strings; + +#if 0 /* XXX - These vary across powerpc machines... */ + kd->usrstack = USRSTACK; + kd->min_uva = VM_MIN_ADDRESS; + kd->max_uva = VM_MAXUSER_ADDRESS; +#endif + /* This is somewhat hack-ish, but it works. */ + max_uva = (uintptr_t) (__ps_strings + 1); + kd->usrstack = max_uva; + kd->max_uva = max_uva; + kd->min_uva = 0; + + return (0); +} diff --git a/lib/libkvm/kvm_private.h b/lib/libkvm/kvm_private.h new file mode 100644 index 000000000..ea00b5a86 --- /dev/null +++ b/lib/libkvm/kvm_private.h @@ -0,0 +1,137 @@ +/* $NetBSD: kvm_private.h,v 1.20 2011/09/12 21:11:32 christos Exp $ */ + +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software developed by the Computer Systems + * Engineering group at Lawrence Berkeley Laboratory under DARPA contract + * BG 91-66 and contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)kvm_private.h 8.1 (Berkeley) 6/4/93 + */ + +struct __kvm { + /* + * a string to be prepended to error messages + * provided for compatibility with sun's interface + * if this value is null, errors are saved in errbuf[] + */ + const char *program; + char *errp; /* XXX this can probably go away */ + char errbuf[_POSIX2_LINE_MAX]; + int pmfd; /* physical memory file (or crash dump) */ + int vmfd; /* virtual memory file (-1 if crash dump) */ + int swfd; /* swap file (e.g., /dev/drum) */ + int nlfd; /* namelist file (e.g., /vmunix) */ + char alive; /* live kernel? */ + struct kinfo_proc *procbase; + struct kinfo_proc2 *procbase2; + struct kinfo_lwp *lwpbase; + size_t procbase_len; + size_t procbase2_len; + size_t lwpbase_len; + u_long usrstack; /* address of end of user stack */ + u_long min_uva, max_uva; /* min/max user virtual address */ + int nbpg; /* page size */ + char *swapspc; /* (dynamic) storage for swapped pages */ + char *argspc, *argbuf; /* (dynamic) storage for argv strings */ + size_t argspc_len; /* length of the above */ + char **argv; /* (dynamic) storage for argv pointers */ + int argc; /* length of above (not actual # present) */ + + /* + * Header structures for kernel dumps. Only gets filled in for + * dead kernels. + */ + struct kcore_hdr *kcore_hdr; + size_t cpu_dsize; + void *cpu_data; + off_t dump_off; /* Where the actual dump starts */ + + /* + * Kernel virtual address translation state. This only gets filled + * in for dead kernels; otherwise, the running kernel (i.e. kmem) + * will do the translations for us. It could be big, so we + * only allocate it if necessary. + */ + struct vmstate *vmst; /* XXX: should become obsoleted */ + /* + * These kernel variables are used for looking up user addresses, + * and are cached for efficiency. + */ + struct pglist *vm_page_buckets; + int vm_page_hash_mask; + /* Buffer for raw disk I/O. */ + size_t fdalign; + uint8_t *iobuf; + size_t iobufsz; + char kernelname[MAXPATHLEN]; +}; + +/* Levels of aliveness */ +#define KVM_ALIVE_DEAD 0 /* dead, working from core file */ +#define KVM_ALIVE_FILES 1 /* alive, working from open kmem/drum */ +#define KVM_ALIVE_SYSCTL 2 /* alive, sysctl-type calls only */ + +#define ISALIVE(kd) ((kd)->alive != KVM_ALIVE_DEAD) +#define ISKMEM(kd) ((kd)->alive == KVM_ALIVE_FILES) +#define ISSYSCTL(kd) ((kd)->alive == KVM_ALIVE_SYSCTL || ISKMEM(kd)) + +/* + * Functions used internally by kvm, but across kvm modules. + */ +void _kvm_err(kvm_t *, const char *, const char *, ...) + __attribute__((__format__(__printf__, 3, 4))); +int _kvm_dump_mkheader(kvm_t *, kvm_t *); +void _kvm_freeprocs(kvm_t *); +void _kvm_freevtop(kvm_t *); +int _kvm_mdopen(kvm_t *); +int _kvm_initvtop(kvm_t *); +int _kvm_kvatop(kvm_t *, vaddr_t, paddr_t *); +void *_kvm_malloc(kvm_t *, size_t); +off_t _kvm_pa2off(kvm_t *, paddr_t); +void *_kvm_realloc(kvm_t *, void *, size_t); +void _kvm_syserr(kvm_t *, const char *, const char *, ...) + __attribute__((__format__(__printf__, 3, 4))); +ssize_t _kvm_pread(kvm_t *, int, void *, size_t, off_t); + +#define KREAD(kd, addr, obj) \ + (kvm_read(kd, addr, (obj), sizeof(*obj)) != sizeof(*obj)) + +#define KVM_ALLOC(kd, member, size) \ + do { \ + if (kd->member == NULL) \ + kd->member = _kvm_malloc(kd, kd->member ## _len = size); \ + else if (kd->member ## _len < size) \ + kd->member = _kvm_realloc(kd, kd->member, \ + kd->member ## _len = size); \ + if (kd->member == NULL) { \ + kd->member ## _len = 0; \ + return (NULL); \ + } \ + } while (/*CONSTCOND*/0) diff --git a/lib/libkvm/kvm_proc.c b/lib/libkvm/kvm_proc.c new file mode 100644 index 000000000..4b7c8c4d1 --- /dev/null +++ b/lib/libkvm/kvm_proc.c @@ -0,0 +1,1238 @@ +/* $NetBSD: kvm_proc.c,v 1.90 2014/02/19 20:21:22 dsl Exp $ */ + +/*- + * Copyright (c) 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Charles M. Hannum. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/*- + * Copyright (c) 1989, 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software developed by the Computer Systems + * Engineering group at Lawrence Berkeley Laboratory under DARPA contract + * BG 91-66 and contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)kvm_proc.c 8.3 (Berkeley) 9/23/93"; +#else +__RCSID("$NetBSD: kvm_proc.c,v 1.90 2014/02/19 20:21:22 dsl Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + +/* + * Proc traversal interface for kvm. ps and w are (probably) the exclusive + * users of this code, so we've factored it out into a separate module. + * Thus, we keep this grunge out of the other kvm applications (i.e., + * most other applications are interested only in open/close/read/nlist). + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include "kvm_private.h" + +/* + * Common info from kinfo_proc and kinfo_proc2 used by helper routines. + */ +struct miniproc { + struct vmspace *p_vmspace; + char p_stat; + struct proc *p_paddr; + pid_t p_pid; +}; + +/* + * Convert from struct proc and kinfo_proc{,2} to miniproc. + */ +#define PTOMINI(kp, p) \ + do { \ + (p)->p_stat = (kp)->p_stat; \ + (p)->p_pid = (kp)->p_pid; \ + (p)->p_paddr = NULL; \ + (p)->p_vmspace = (kp)->p_vmspace; \ + } while (/*CONSTCOND*/0); + +#define KPTOMINI(kp, p) \ + do { \ + (p)->p_stat = (kp)->kp_proc.p_stat; \ + (p)->p_pid = (kp)->kp_proc.p_pid; \ + (p)->p_paddr = (kp)->kp_eproc.e_paddr; \ + (p)->p_vmspace = (kp)->kp_proc.p_vmspace; \ + } while (/*CONSTCOND*/0); + +#define KP2TOMINI(kp, p) \ + do { \ + (p)->p_stat = (kp)->p_stat; \ + (p)->p_pid = (kp)->p_pid; \ + (p)->p_paddr = (void *)(long)(kp)->p_paddr; \ + (p)->p_vmspace = (void *)(long)(kp)->p_vmspace; \ + } while (/*CONSTCOND*/0); + +/* + * NetBSD uses kauth(9) to manage credentials, which are stored in kauth_cred_t, + * a kernel-only opaque type. This is an embedded version which is *INTERNAL* to + * kvm(3) so dumps can be read properly. + * + * Whenever NetBSD starts exporting credentials to userland consistently (using + * 'struct uucred', or something) this will have to be updated again. + */ +struct kvm_kauth_cred { + u_int cr_refcnt; /* reference count */ + uint8_t cr_pad[CACHE_LINE_SIZE - sizeof(u_int)]; + uid_t cr_uid; /* user id */ + uid_t cr_euid; /* effective user id */ + uid_t cr_svuid; /* saved effective user id */ + gid_t cr_gid; /* group id */ + gid_t cr_egid; /* effective group id */ + gid_t cr_svgid; /* saved effective group id */ + u_int cr_ngroups; /* number of groups */ + gid_t cr_groups[NGROUPS]; /* group memberships */ + specificdata_reference cr_sd; /* specific data */ +}; + +/* XXX: What uses these two functions? */ +char *_kvm_uread(kvm_t *, const struct proc *, u_long, u_long *); +ssize_t kvm_uread(kvm_t *, const struct proc *, u_long, char *, + size_t); + +static char *_kvm_ureadm(kvm_t *, const struct miniproc *, u_long, + u_long *); +static ssize_t kvm_ureadm(kvm_t *, const struct miniproc *, u_long, + char *, size_t); + +static char **kvm_argv(kvm_t *, const struct miniproc *, u_long, int, int); +static int kvm_deadprocs(kvm_t *, int, int, u_long, u_long, int); +static char **kvm_doargv(kvm_t *, const struct miniproc *, int, + void (*)(struct ps_strings *, u_long *, int *)); +static char **kvm_doargv2(kvm_t *, pid_t, int, int); +static int kvm_proclist(kvm_t *, int, int, struct proc *, + struct kinfo_proc *, int); +static int proc_verify(kvm_t *, u_long, const struct miniproc *); +static void ps_str_a(struct ps_strings *, u_long *, int *); +static void ps_str_e(struct ps_strings *, u_long *, int *); + + +static char * +_kvm_ureadm(kvm_t *kd, const struct miniproc *p, u_long va, u_long *cnt) +{ + u_long addr, head; + u_long offset; + struct vm_map_entry vme; + struct vm_amap amap; + struct vm_anon *anonp, anon; + struct vm_page pg; + u_long slot; + + if (kd->swapspc == NULL) { + kd->swapspc = _kvm_malloc(kd, (size_t)kd->nbpg); + if (kd->swapspc == NULL) + return (NULL); + } + + /* + * Look through the address map for the memory object + * that corresponds to the given virtual address. + * The header just has the entire valid range. + */ + head = (u_long)&p->p_vmspace->vm_map.header; + addr = head; + for (;;) { + if (KREAD(kd, addr, &vme)) + return (NULL); + + if (va >= vme.start && va < vme.end && + vme.aref.ar_amap != NULL) + break; + + addr = (u_long)vme.next; + if (addr == head) + return (NULL); + } + + /* + * we found the map entry, now to find the object... + */ + if (vme.aref.ar_amap == NULL) + return (NULL); + + addr = (u_long)vme.aref.ar_amap; + if (KREAD(kd, addr, &amap)) + return (NULL); + + offset = va - vme.start; + slot = offset / kd->nbpg + vme.aref.ar_pageoff; + /* sanity-check slot number */ + if (slot > amap.am_nslot) + return (NULL); + + addr = (u_long)amap.am_anon + (offset / kd->nbpg) * sizeof(anonp); + if (KREAD(kd, addr, &anonp)) + return (NULL); + + addr = (u_long)anonp; + if (KREAD(kd, addr, &anon)) + return (NULL); + + addr = (u_long)anon.an_page; + if (addr) { + if (KREAD(kd, addr, &pg)) + return (NULL); + + if (_kvm_pread(kd, kd->pmfd, kd->swapspc, (size_t)kd->nbpg, + (off_t)pg.phys_addr) != kd->nbpg) + return (NULL); + } else { + if (kd->swfd < 0 || + _kvm_pread(kd, kd->swfd, kd->swapspc, (size_t)kd->nbpg, + (off_t)(anon.an_swslot * kd->nbpg)) != kd->nbpg) + return (NULL); + } + + /* Found the page. */ + offset %= kd->nbpg; + *cnt = kd->nbpg - offset; + return (&kd->swapspc[(size_t)offset]); +} + +char * +_kvm_uread(kvm_t *kd, const struct proc *p, u_long va, u_long *cnt) +{ + struct miniproc mp; + + PTOMINI(p, &mp); + return (_kvm_ureadm(kd, &mp, va, cnt)); +} + +/* + * Convert credentials located in kernel space address 'cred' and store + * them in the appropriate members of 'eproc'. + */ +static int +_kvm_convertcred(kvm_t *kd, u_long cred, struct eproc *eproc) +{ + struct kvm_kauth_cred kauthcred; + struct ki_pcred *pc = &eproc->e_pcred; + struct ki_ucred *uc = &eproc->e_ucred; + + if (KREAD(kd, cred, &kauthcred) != 0) + return (-1); + + /* inlined version of kauth_cred_to_pcred, see kauth(9). */ + pc->p_ruid = kauthcred.cr_uid; + pc->p_svuid = kauthcred.cr_svuid; + pc->p_rgid = kauthcred.cr_gid; + pc->p_svgid = kauthcred.cr_svgid; + pc->p_refcnt = kauthcred.cr_refcnt; + pc->p_pad = NULL; + + /* inlined version of kauth_cred_to_ucred(), see kauth(9). */ + uc->cr_ref = kauthcred.cr_refcnt; + uc->cr_uid = kauthcred.cr_euid; + uc->cr_gid = kauthcred.cr_egid; + uc->cr_ngroups = (uint32_t)MIN(kauthcred.cr_ngroups, + sizeof(uc->cr_groups) / sizeof(uc->cr_groups[0])); + memcpy(uc->cr_groups, kauthcred.cr_groups, + uc->cr_ngroups * sizeof(uc->cr_groups[0])); + + return (0); +} + +/* + * Read proc's from memory file into buffer bp, which has space to hold + * at most maxcnt procs. + */ +static int +kvm_proclist(kvm_t *kd, int what, int arg, struct proc *p, + struct kinfo_proc *bp, int maxcnt) +{ + int cnt = 0; + int nlwps; + struct kinfo_lwp *kl; + struct eproc eproc; + struct pgrp pgrp; + struct session sess; + struct tty tty; + struct proc proc; + + for (; cnt < maxcnt && p != NULL; p = proc.p_list.le_next) { + if (KREAD(kd, (u_long)p, &proc)) { + _kvm_err(kd, kd->program, "can't read proc at %p", p); + return (-1); + } + if (_kvm_convertcred(kd, (u_long)proc.p_cred, &eproc) != 0) { + _kvm_err(kd, kd->program, + "can't read proc credentials at %p", p); + return (-1); + } + + switch (what) { + + case KERN_PROC_PID: + if (proc.p_pid != (pid_t)arg) + continue; + break; + + case KERN_PROC_UID: + if (eproc.e_ucred.cr_uid != (uid_t)arg) + continue; + break; + + case KERN_PROC_RUID: + if (eproc.e_pcred.p_ruid != (uid_t)arg) + continue; + break; + } + /* + * We're going to add another proc to the set. If this + * will overflow the buffer, assume the reason is because + * nprocs (or the proc list) is corrupt and declare an error. + */ + if (cnt >= maxcnt) { + _kvm_err(kd, kd->program, "nprocs corrupt"); + return (-1); + } + /* + * gather eproc + */ + eproc.e_paddr = p; + if (KREAD(kd, (u_long)proc.p_pgrp, &pgrp)) { + _kvm_err(kd, kd->program, "can't read pgrp at %p", + proc.p_pgrp); + return (-1); + } + eproc.e_sess = pgrp.pg_session; + eproc.e_pgid = pgrp.pg_id; + eproc.e_jobc = pgrp.pg_jobc; + if (KREAD(kd, (u_long)pgrp.pg_session, &sess)) { + _kvm_err(kd, kd->program, "can't read session at %p", + pgrp.pg_session); + return (-1); + } + if ((proc.p_lflag & PL_CONTROLT) && sess.s_ttyp != NULL) { + if (KREAD(kd, (u_long)sess.s_ttyp, &tty)) { + _kvm_err(kd, kd->program, + "can't read tty at %p", sess.s_ttyp); + return (-1); + } + eproc.e_tdev = (uint32_t)tty.t_dev; + eproc.e_tsess = tty.t_session; + if (tty.t_pgrp != NULL) { + if (KREAD(kd, (u_long)tty.t_pgrp, &pgrp)) { + _kvm_err(kd, kd->program, + "can't read tpgrp at %p", + tty.t_pgrp); + return (-1); + } + eproc.e_tpgid = pgrp.pg_id; + } else + eproc.e_tpgid = -1; + } else + eproc.e_tdev = (uint32_t)NODEV; + eproc.e_flag = sess.s_ttyvp ? EPROC_CTTY : 0; + eproc.e_sid = sess.s_sid; + if (sess.s_leader == p) + eproc.e_flag |= EPROC_SLEADER; + /* + * Fill in the old-style proc.p_wmesg by copying the wmesg + * from the first available LWP. + */ + kl = kvm_getlwps(kd, proc.p_pid, + (u_long)PTRTOUINT64(eproc.e_paddr), + sizeof(struct kinfo_lwp), &nlwps); + if (kl) { + if (nlwps > 0) { + strcpy(eproc.e_wmesg, kl[0].l_wmesg); + } + } + (void)kvm_read(kd, (u_long)proc.p_vmspace, &eproc.e_vm, + sizeof(eproc.e_vm)); + + eproc.e_xsize = eproc.e_xrssize = 0; + eproc.e_xccount = eproc.e_xswrss = 0; + + switch (what) { + + case KERN_PROC_PGRP: + if (eproc.e_pgid != (pid_t)arg) + continue; + break; + + case KERN_PROC_TTY: + if ((proc.p_lflag & PL_CONTROLT) == 0 || + eproc.e_tdev != (dev_t)arg) + continue; + break; + } + memcpy(&bp->kp_proc, &proc, sizeof(proc)); + memcpy(&bp->kp_eproc, &eproc, sizeof(eproc)); + ++bp; + ++cnt; + } + return (cnt); +} + +/* + * Build proc info array by reading in proc list from a crash dump. + * Return number of procs read. maxcnt is the max we will read. + */ +static int +kvm_deadprocs(kvm_t *kd, int what, int arg, u_long a_allproc, + u_long a_zombproc, int maxcnt) +{ + struct kinfo_proc *bp = kd->procbase; + int acnt, zcnt; + struct proc *p; + + if (KREAD(kd, a_allproc, &p)) { + _kvm_err(kd, kd->program, "cannot read allproc"); + return (-1); + } + acnt = kvm_proclist(kd, what, arg, p, bp, maxcnt); + if (acnt < 0) + return (acnt); + + if (KREAD(kd, a_zombproc, &p)) { + _kvm_err(kd, kd->program, "cannot read zombproc"); + return (-1); + } + zcnt = kvm_proclist(kd, what, arg, p, bp + acnt, + maxcnt - acnt); + if (zcnt < 0) + zcnt = 0; + + return (acnt + zcnt); +} + +struct kinfo_proc2 * +kvm_getproc2(kvm_t *kd, int op, int arg, size_t esize, int *cnt) +{ + size_t size; + int mib[6], st, nprocs; + struct pstats pstats; + + if (ISSYSCTL(kd)) { + size = 0; + mib[0] = CTL_KERN; + mib[1] = KERN_PROC2; + mib[2] = op; + mib[3] = arg; + mib[4] = (int)esize; +again: + mib[5] = 0; + st = sysctl(mib, 6, NULL, &size, NULL, (size_t)0); + if (st == -1) { + _kvm_syserr(kd, kd->program, "kvm_getproc2"); + return (NULL); + } + + mib[5] = (int) (size / esize); + KVM_ALLOC(kd, procbase2, size); + st = sysctl(mib, 6, kd->procbase2, &size, NULL, (size_t)0); + if (st == -1) { + if (errno == ENOMEM) { + goto again; + } + _kvm_syserr(kd, kd->program, "kvm_getproc2"); + return (NULL); + } + nprocs = (int) (size / esize); + } else { + char *kp2c; + struct kinfo_proc *kp; + struct kinfo_proc2 kp2, *kp2p; + struct kinfo_lwp *kl; + int i, nlwps; + + kp = kvm_getprocs(kd, op, arg, &nprocs); + if (kp == NULL) + return (NULL); + + size = nprocs * esize; + KVM_ALLOC(kd, procbase2, size); + kp2c = (char *)(void *)kd->procbase2; + kp2p = &kp2; + for (i = 0; i < nprocs; i++, kp++) { + struct timeval tv; + + kl = kvm_getlwps(kd, kp->kp_proc.p_pid, + (u_long)PTRTOUINT64(kp->kp_eproc.e_paddr), + sizeof(struct kinfo_lwp), &nlwps); + + if (kl == NULL) { + _kvm_syserr(kd, NULL, + "kvm_getlwps() failed on process %u\n", + kp->kp_proc.p_pid); + if (nlwps == 0) + return NULL; + else + continue; + } + + /* We use kl[0] as the "representative" LWP */ + memset(kp2p, 0, sizeof(kp2)); + kp2p->p_forw = kl[0].l_forw; + kp2p->p_back = kl[0].l_back; + kp2p->p_paddr = PTRTOUINT64(kp->kp_eproc.e_paddr); + kp2p->p_addr = kl[0].l_addr; + kp2p->p_fd = PTRTOUINT64(kp->kp_proc.p_fd); + kp2p->p_cwdi = PTRTOUINT64(kp->kp_proc.p_cwdi); + kp2p->p_stats = PTRTOUINT64(kp->kp_proc.p_stats); + kp2p->p_limit = PTRTOUINT64(kp->kp_proc.p_limit); + kp2p->p_vmspace = PTRTOUINT64(kp->kp_proc.p_vmspace); + kp2p->p_sigacts = PTRTOUINT64(kp->kp_proc.p_sigacts); + kp2p->p_sess = PTRTOUINT64(kp->kp_eproc.e_sess); + kp2p->p_tsess = 0; +#if 1 /* XXX: dsl - p_ru was only ever non-zero for zombies */ + kp2p->p_ru = 0; +#else + kp2p->p_ru = PTRTOUINT64(pstats.p_ru); +#endif + + kp2p->p_eflag = 0; + kp2p->p_exitsig = kp->kp_proc.p_exitsig; + kp2p->p_flag = kp->kp_proc.p_flag; + + kp2p->p_pid = kp->kp_proc.p_pid; + + kp2p->p_ppid = kp->kp_eproc.e_ppid; + kp2p->p_sid = kp->kp_eproc.e_sid; + kp2p->p__pgid = kp->kp_eproc.e_pgid; + + kp2p->p_tpgid = -1 /* XXX NO_PGID! */; + + kp2p->p_uid = kp->kp_eproc.e_ucred.cr_uid; + kp2p->p_ruid = kp->kp_eproc.e_pcred.p_ruid; + kp2p->p_svuid = kp->kp_eproc.e_pcred.p_svuid; + kp2p->p_gid = kp->kp_eproc.e_ucred.cr_gid; + kp2p->p_rgid = kp->kp_eproc.e_pcred.p_rgid; + kp2p->p_svgid = kp->kp_eproc.e_pcred.p_svgid; + + /*CONSTCOND*/ + memcpy(kp2p->p_groups, kp->kp_eproc.e_ucred.cr_groups, + MIN(sizeof(kp2p->p_groups), + sizeof(kp->kp_eproc.e_ucred.cr_groups))); + kp2p->p_ngroups = kp->kp_eproc.e_ucred.cr_ngroups; + + kp2p->p_jobc = kp->kp_eproc.e_jobc; + kp2p->p_tdev = kp->kp_eproc.e_tdev; + kp2p->p_tpgid = kp->kp_eproc.e_tpgid; + kp2p->p_tsess = PTRTOUINT64(kp->kp_eproc.e_tsess); + + kp2p->p_estcpu = 0; + bintime2timeval(&kp->kp_proc.p_rtime, &tv); + kp2p->p_rtime_sec = (uint32_t)tv.tv_sec; + kp2p->p_rtime_usec = (uint32_t)tv.tv_usec; + kp2p->p_cpticks = kl[0].l_cpticks; + kp2p->p_pctcpu = kp->kp_proc.p_pctcpu; + kp2p->p_swtime = kl[0].l_swtime; + kp2p->p_slptime = kl[0].l_slptime; +#if 0 /* XXX thorpej */ + kp2p->p_schedflags = kp->kp_proc.p_schedflags; +#else + kp2p->p_schedflags = 0; +#endif + + kp2p->p_uticks = kp->kp_proc.p_uticks; + kp2p->p_sticks = kp->kp_proc.p_sticks; + kp2p->p_iticks = kp->kp_proc.p_iticks; + + kp2p->p_tracep = PTRTOUINT64(kp->kp_proc.p_tracep); + kp2p->p_traceflag = kp->kp_proc.p_traceflag; + + kp2p->p_holdcnt = kl[0].l_holdcnt; + + memcpy(&kp2p->p_siglist, + &kp->kp_proc.p_sigpend.sp_set, + sizeof(ki_sigset_t)); + memset(&kp2p->p_sigmask, 0, + sizeof(ki_sigset_t)); + memcpy(&kp2p->p_sigignore, + &kp->kp_proc.p_sigctx.ps_sigignore, + sizeof(ki_sigset_t)); + memcpy(&kp2p->p_sigcatch, + &kp->kp_proc.p_sigctx.ps_sigcatch, + sizeof(ki_sigset_t)); + + kp2p->p_stat = kl[0].l_stat; + kp2p->p_priority = kl[0].l_priority; + kp2p->p_usrpri = kl[0].l_priority; + kp2p->p_nice = kp->kp_proc.p_nice; + + kp2p->p_xstat = kp->kp_proc.p_xstat; + kp2p->p_acflag = kp->kp_proc.p_acflag; + + /*CONSTCOND*/ + strncpy(kp2p->p_comm, kp->kp_proc.p_comm, + MIN(sizeof(kp2p->p_comm), + sizeof(kp->kp_proc.p_comm))); + + strncpy(kp2p->p_wmesg, kp->kp_eproc.e_wmesg, + sizeof(kp2p->p_wmesg)); + kp2p->p_wchan = kl[0].l_wchan; + strncpy(kp2p->p_login, kp->kp_eproc.e_login, + sizeof(kp2p->p_login)); + + kp2p->p_vm_rssize = kp->kp_eproc.e_xrssize; + kp2p->p_vm_tsize = kp->kp_eproc.e_vm.vm_tsize; + kp2p->p_vm_dsize = kp->kp_eproc.e_vm.vm_dsize; + kp2p->p_vm_ssize = kp->kp_eproc.e_vm.vm_ssize; + kp2p->p_vm_vsize = kp->kp_eproc.e_vm.vm_map.size + / kd->nbpg; + /* Adjust mapped size */ + kp2p->p_vm_msize = + (kp->kp_eproc.e_vm.vm_map.size / kd->nbpg) - + kp->kp_eproc.e_vm.vm_issize + + kp->kp_eproc.e_vm.vm_ssize; + + kp2p->p_eflag = (int32_t)kp->kp_eproc.e_flag; + + kp2p->p_realflag = kp->kp_proc.p_flag; + kp2p->p_nlwps = kp->kp_proc.p_nlwps; + kp2p->p_nrlwps = kp->kp_proc.p_nrlwps; + kp2p->p_realstat = kp->kp_proc.p_stat; + + if (P_ZOMBIE(&kp->kp_proc) || + kp->kp_proc.p_stats == NULL || + KREAD(kd, (u_long)kp->kp_proc.p_stats, &pstats)) { + kp2p->p_uvalid = 0; + } else { + kp2p->p_uvalid = 1; + + kp2p->p_ustart_sec = (u_int32_t) + pstats.p_start.tv_sec; + kp2p->p_ustart_usec = (u_int32_t) + pstats.p_start.tv_usec; + + kp2p->p_uutime_sec = (u_int32_t) + pstats.p_ru.ru_utime.tv_sec; + kp2p->p_uutime_usec = (u_int32_t) + pstats.p_ru.ru_utime.tv_usec; + kp2p->p_ustime_sec = (u_int32_t) + pstats.p_ru.ru_stime.tv_sec; + kp2p->p_ustime_usec = (u_int32_t) + pstats.p_ru.ru_stime.tv_usec; + + kp2p->p_uru_maxrss = pstats.p_ru.ru_maxrss; + kp2p->p_uru_ixrss = pstats.p_ru.ru_ixrss; + kp2p->p_uru_idrss = pstats.p_ru.ru_idrss; + kp2p->p_uru_isrss = pstats.p_ru.ru_isrss; + kp2p->p_uru_minflt = pstats.p_ru.ru_minflt; + kp2p->p_uru_majflt = pstats.p_ru.ru_majflt; + kp2p->p_uru_nswap = pstats.p_ru.ru_nswap; + kp2p->p_uru_inblock = pstats.p_ru.ru_inblock; + kp2p->p_uru_oublock = pstats.p_ru.ru_oublock; + kp2p->p_uru_msgsnd = pstats.p_ru.ru_msgsnd; + kp2p->p_uru_msgrcv = pstats.p_ru.ru_msgrcv; + kp2p->p_uru_nsignals = pstats.p_ru.ru_nsignals; + kp2p->p_uru_nvcsw = pstats.p_ru.ru_nvcsw; + kp2p->p_uru_nivcsw = pstats.p_ru.ru_nivcsw; + + kp2p->p_uctime_sec = (u_int32_t) + (pstats.p_cru.ru_utime.tv_sec + + pstats.p_cru.ru_stime.tv_sec); + kp2p->p_uctime_usec = (u_int32_t) + (pstats.p_cru.ru_utime.tv_usec + + pstats.p_cru.ru_stime.tv_usec); + } + + memcpy(kp2c, &kp2, esize); + kp2c += esize; + } + } + *cnt = nprocs; + return (kd->procbase2); +} + +struct kinfo_lwp * +kvm_getlwps(kvm_t *kd, int pid, u_long paddr, size_t esize, int *cnt) +{ + size_t size; + int mib[5], nlwps; + ssize_t st; + struct kinfo_lwp *kl; + + if (ISSYSCTL(kd)) { + size = 0; + mib[0] = CTL_KERN; + mib[1] = KERN_LWP; + mib[2] = pid; + mib[3] = (int)esize; + mib[4] = 0; +again: + st = sysctl(mib, 5, NULL, &size, NULL, (size_t)0); + if (st == -1) { + switch (errno) { + case ESRCH: /* Treat this as a soft error; see kvm.c */ + _kvm_syserr(kd, NULL, "kvm_getlwps"); + return NULL; + default: + _kvm_syserr(kd, kd->program, "kvm_getlwps"); + return NULL; + } + } + mib[4] = (int) (size / esize); + KVM_ALLOC(kd, lwpbase, size); + st = sysctl(mib, 5, kd->lwpbase, &size, NULL, (size_t)0); + if (st == -1) { + switch (errno) { + case ESRCH: /* Treat this as a soft error; see kvm.c */ + _kvm_syserr(kd, NULL, "kvm_getlwps"); + return NULL; + case ENOMEM: + goto again; + default: + _kvm_syserr(kd, kd->program, "kvm_getlwps"); + return NULL; + } + } + nlwps = (int) (size / esize); + } else { + /* grovel through the memory image */ + struct proc p; + struct lwp l; + u_long laddr; + void *back; + int i; + + st = kvm_read(kd, paddr, &p, sizeof(p)); + if (st == -1) { + _kvm_syserr(kd, kd->program, "kvm_getlwps"); + return (NULL); + } + + nlwps = p.p_nlwps; + size = nlwps * sizeof(*kd->lwpbase); + KVM_ALLOC(kd, lwpbase, size); + laddr = (u_long)PTRTOUINT64(p.p_lwps.lh_first); + for (i = 0; (i < nlwps) && (laddr != 0); i++) { + st = kvm_read(kd, laddr, &l, sizeof(l)); + if (st == -1) { + _kvm_syserr(kd, kd->program, "kvm_getlwps"); + return (NULL); + } + kl = &kd->lwpbase[i]; + kl->l_laddr = laddr; + kl->l_forw = PTRTOUINT64(l.l_runq.tqe_next); + laddr = (u_long)PTRTOUINT64(l.l_runq.tqe_prev); + st = kvm_read(kd, laddr, &back, sizeof(back)); + if (st == -1) { + _kvm_syserr(kd, kd->program, "kvm_getlwps"); + return (NULL); + } + kl->l_back = PTRTOUINT64(back); + kl->l_addr = PTRTOUINT64(l.l_addr); + kl->l_lid = l.l_lid; + kl->l_flag = l.l_flag; + kl->l_swtime = l.l_swtime; + kl->l_slptime = l.l_slptime; + kl->l_schedflags = 0; /* XXX */ + kl->l_holdcnt = 0; + kl->l_priority = l.l_priority; + kl->l_usrpri = l.l_priority; + kl->l_stat = l.l_stat; + kl->l_wchan = PTRTOUINT64(l.l_wchan); + if (l.l_wmesg) + (void)kvm_read(kd, (u_long)l.l_wmesg, + kl->l_wmesg, (size_t)WMESGLEN); + kl->l_cpuid = KI_NOCPU; + laddr = (u_long)PTRTOUINT64(l.l_sibling.le_next); + } + } + + *cnt = nlwps; + return (kd->lwpbase); +} + +struct kinfo_proc * +kvm_getprocs(kvm_t *kd, int op, int arg, int *cnt) +{ + size_t size; + int mib[4], st, nprocs; + + if (ISALIVE(kd)) { + size = 0; + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = op; + mib[3] = arg; + st = sysctl(mib, 4, NULL, &size, NULL, (size_t)0); + if (st == -1) { + _kvm_syserr(kd, kd->program, "kvm_getprocs"); + return (NULL); + } + KVM_ALLOC(kd, procbase, size); + st = sysctl(mib, 4, kd->procbase, &size, NULL, (size_t)0); + if (st == -1) { + _kvm_syserr(kd, kd->program, "kvm_getprocs"); + return (NULL); + } + if (size % sizeof(struct kinfo_proc) != 0) { + _kvm_err(kd, kd->program, + "proc size mismatch (%lu total, %lu chunks)", + (u_long)size, (u_long)sizeof(struct kinfo_proc)); + return (NULL); + } + nprocs = (int) (size / sizeof(struct kinfo_proc)); + } else { + struct nlist nl[4], *p; + + (void)memset(nl, 0, sizeof(nl)); + nl[0].n_name = "_nprocs"; + nl[1].n_name = "_allproc"; + nl[2].n_name = "_zombproc"; + nl[3].n_name = NULL; + + if (kvm_nlist(kd, nl) != 0) { + for (p = nl; p->n_type != 0; ++p) + continue; + _kvm_err(kd, kd->program, + "%s: no such symbol", p->n_name); + return (NULL); + } + if (KREAD(kd, nl[0].n_value, &nprocs)) { + _kvm_err(kd, kd->program, "can't read nprocs"); + return (NULL); + } + size = nprocs * sizeof(*kd->procbase); + KVM_ALLOC(kd, procbase, size); + nprocs = kvm_deadprocs(kd, op, arg, nl[1].n_value, + nl[2].n_value, nprocs); + if (nprocs < 0) + return (NULL); +#ifdef notdef + size = nprocs * sizeof(struct kinfo_proc); + (void)realloc(kd->procbase, size); +#endif + } + *cnt = nprocs; + return (kd->procbase); +} + +void * +_kvm_realloc(kvm_t *kd, void *p, size_t n) +{ + void *np = realloc(p, n); + + if (np == NULL) + _kvm_err(kd, kd->program, "out of memory"); + return (np); +} + +/* + * Read in an argument vector from the user address space of process p. + * addr if the user-space base address of narg null-terminated contiguous + * strings. This is used to read in both the command arguments and + * environment strings. Read at most maxcnt characters of strings. + */ +static char ** +kvm_argv(kvm_t *kd, const struct miniproc *p, u_long addr, int narg, + int maxcnt) +{ + char *np, *cp, *ep, *ap; + u_long oaddr = (u_long)~0L; + u_long len; + size_t cc; + char **argv; + + /* + * Check that there aren't an unreasonable number of arguments, + * and that the address is in user space. + */ + if (narg > ARG_MAX || addr < kd->min_uva || addr >= kd->max_uva) + return (NULL); + + if (kd->argv == NULL) { + /* + * Try to avoid reallocs. + */ + kd->argc = MAX(narg + 1, 32); + kd->argv = _kvm_malloc(kd, kd->argc * sizeof(*kd->argv)); + if (kd->argv == NULL) + return (NULL); + } else if (narg + 1 > kd->argc) { + kd->argc = MAX(2 * kd->argc, narg + 1); + kd->argv = _kvm_realloc(kd, kd->argv, kd->argc * + sizeof(*kd->argv)); + if (kd->argv == NULL) + return (NULL); + } + if (kd->argspc == NULL) { + kd->argspc = _kvm_malloc(kd, (size_t)kd->nbpg); + if (kd->argspc == NULL) + return (NULL); + kd->argspc_len = kd->nbpg; + } + if (kd->argbuf == NULL) { + kd->argbuf = _kvm_malloc(kd, (size_t)kd->nbpg); + if (kd->argbuf == NULL) + return (NULL); + } + cc = sizeof(char *) * narg; + if (kvm_ureadm(kd, p, addr, (void *)kd->argv, cc) != cc) + return (NULL); + ap = np = kd->argspc; + argv = kd->argv; + len = 0; + /* + * Loop over pages, filling in the argument vector. + */ + while (argv < kd->argv + narg && *argv != NULL) { + addr = (u_long)*argv & ~(kd->nbpg - 1); + if (addr != oaddr) { + if (kvm_ureadm(kd, p, addr, kd->argbuf, + (size_t)kd->nbpg) != kd->nbpg) + return (NULL); + oaddr = addr; + } + addr = (u_long)*argv & (kd->nbpg - 1); + cp = kd->argbuf + (size_t)addr; + cc = kd->nbpg - (size_t)addr; + if (maxcnt > 0 && cc > (size_t)(maxcnt - len)) + cc = (size_t)(maxcnt - len); + ep = memchr(cp, '\0', cc); + if (ep != NULL) + cc = ep - cp + 1; + if (len + cc > kd->argspc_len) { + ptrdiff_t off; + char **pp; + char *op = kd->argspc; + + kd->argspc_len *= 2; + kd->argspc = _kvm_realloc(kd, kd->argspc, + kd->argspc_len); + if (kd->argspc == NULL) + return (NULL); + /* + * Adjust argv pointers in case realloc moved + * the string space. + */ + off = kd->argspc - op; + for (pp = kd->argv; pp < argv; pp++) + *pp += off; + ap += off; + np += off; + } + memcpy(np, cp, cc); + np += cc; + len += cc; + if (ep != NULL) { + *argv++ = ap; + ap = np; + } else + *argv += cc; + if (maxcnt > 0 && len >= maxcnt) { + /* + * We're stopping prematurely. Terminate the + * current string. + */ + if (ep == NULL) { + *np = '\0'; + *argv++ = ap; + } + break; + } + } + /* Make sure argv is terminated. */ + *argv = NULL; + return (kd->argv); +} + +static void +ps_str_a(struct ps_strings *p, u_long *addr, int *n) +{ + + *addr = (u_long)p->ps_argvstr; + *n = p->ps_nargvstr; +} + +static void +ps_str_e(struct ps_strings *p, u_long *addr, int *n) +{ + + *addr = (u_long)p->ps_envstr; + *n = p->ps_nenvstr; +} + +/* + * Determine if the proc indicated by p is still active. + * This test is not 100% foolproof in theory, but chances of + * being wrong are very low. + */ +static int +proc_verify(kvm_t *kd, u_long kernp, const struct miniproc *p) +{ + struct proc kernproc; + + /* + * Just read in the whole proc. It's not that big relative + * to the cost of the read system call. + */ + if (kvm_read(kd, kernp, &kernproc, sizeof(kernproc)) != + sizeof(kernproc)) + return (0); + return (p->p_pid == kernproc.p_pid && + (kernproc.p_stat != SZOMB || p->p_stat == SZOMB)); +} + +static char ** +kvm_doargv(kvm_t *kd, const struct miniproc *p, int nchr, + void (*info)(struct ps_strings *, u_long *, int *)) +{ + char **ap; + u_long addr; + int cnt; + struct ps_strings arginfo; + + /* + * Pointers are stored at the top of the user stack. + */ + if (p->p_stat == SZOMB) + return (NULL); + cnt = (int)kvm_ureadm(kd, p, kd->usrstack - sizeof(arginfo), + (void *)&arginfo, sizeof(arginfo)); + if (cnt != sizeof(arginfo)) + return (NULL); + + (*info)(&arginfo, &addr, &cnt); + if (cnt == 0) + return (NULL); + ap = kvm_argv(kd, p, addr, cnt, nchr); + /* + * For live kernels, make sure this process didn't go away. + */ + if (ap != NULL && ISALIVE(kd) && + !proc_verify(kd, (u_long)p->p_paddr, p)) + ap = NULL; + return (ap); +} + +/* + * Get the command args. This code is now machine independent. + */ +char ** +kvm_getargv(kvm_t *kd, const struct kinfo_proc *kp, int nchr) +{ + struct miniproc p; + + KPTOMINI(kp, &p); + return (kvm_doargv(kd, &p, nchr, ps_str_a)); +} + +char ** +kvm_getenvv(kvm_t *kd, const struct kinfo_proc *kp, int nchr) +{ + struct miniproc p; + + KPTOMINI(kp, &p); + return (kvm_doargv(kd, &p, nchr, ps_str_e)); +} + +static char ** +kvm_doargv2(kvm_t *kd, pid_t pid, int type, int nchr) +{ + size_t bufs; + int narg, mib[4]; + size_t newargspc_len; + char **ap, *bp, *endp; + + /* + * Check that there aren't an unreasonable number of arguments. + */ + if (nchr > ARG_MAX) + return (NULL); + + if (nchr == 0) + nchr = ARG_MAX; + + /* Get number of strings in argv */ + mib[0] = CTL_KERN; + mib[1] = KERN_PROC_ARGS; + mib[2] = pid; + mib[3] = type == KERN_PROC_ARGV ? KERN_PROC_NARGV : KERN_PROC_NENV; + bufs = sizeof(narg); + if (sysctl(mib, 4, &narg, &bufs, NULL, (size_t)0) == -1) + return (NULL); + + if (kd->argv == NULL) { + /* + * Try to avoid reallocs. + */ + kd->argc = MAX(narg + 1, 32); + kd->argv = _kvm_malloc(kd, kd->argc * sizeof(*kd->argv)); + if (kd->argv == NULL) + return (NULL); + } else if (narg + 1 > kd->argc) { + kd->argc = MAX(2 * kd->argc, narg + 1); + kd->argv = _kvm_realloc(kd, kd->argv, kd->argc * + sizeof(*kd->argv)); + if (kd->argv == NULL) + return (NULL); + } + + newargspc_len = MIN(nchr, ARG_MAX); + KVM_ALLOC(kd, argspc, newargspc_len); + memset(kd->argspc, 0, (size_t)kd->argspc_len); /* XXX necessary? */ + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC_ARGS; + mib[2] = pid; + mib[3] = type; + bufs = kd->argspc_len; + if (sysctl(mib, 4, kd->argspc, &bufs, NULL, (size_t)0) == -1) + return (NULL); + + bp = kd->argspc; + bp[kd->argspc_len-1] = '\0'; /* make sure the string ends with nul */ + ap = kd->argv; + endp = bp + MIN(nchr, bufs); + + while (bp < endp) { + *ap++ = bp; + /* + * XXX: don't need following anymore, or stick check + * for max argc in above while loop? + */ + if (ap >= kd->argv + kd->argc) { + kd->argc *= 2; + kd->argv = _kvm_realloc(kd, kd->argv, + kd->argc * sizeof(*kd->argv)); + ap = kd->argv; + } + bp += strlen(bp) + 1; + } + *ap = NULL; + + return (kd->argv); +} + +char ** +kvm_getargv2(kvm_t *kd, const struct kinfo_proc2 *kp, int nchr) +{ + + return (kvm_doargv2(kd, kp->p_pid, KERN_PROC_ARGV, nchr)); +} + +char ** +kvm_getenvv2(kvm_t *kd, const struct kinfo_proc2 *kp, int nchr) +{ + + return (kvm_doargv2(kd, kp->p_pid, KERN_PROC_ENV, nchr)); +} + +/* + * Read from user space. The user context is given by p. + */ +static ssize_t +kvm_ureadm(kvm_t *kd, const struct miniproc *p, u_long uva, + char *buf, size_t len) +{ + char *cp; + + cp = buf; + while (len > 0) { + size_t cc; + char *dp; + u_long cnt; + + dp = _kvm_ureadm(kd, p, uva, &cnt); + if (dp == NULL) { + _kvm_err(kd, 0, "invalid address (%lx)", uva); + return (0); + } + cc = (size_t)MIN(cnt, len); + memcpy(cp, dp, cc); + cp += cc; + uva += cc; + len -= cc; + } + return (ssize_t)(cp - buf); +} + +ssize_t +kvm_uread(kvm_t *kd, const struct proc *p, u_long uva, char *buf, size_t len) +{ + struct miniproc mp; + + PTOMINI(p, &mp); + return (kvm_ureadm(kd, &mp, uva, buf, len)); +} diff --git a/lib/libkvm/kvm_read.3 b/lib/libkvm/kvm_read.3 new file mode 100644 index 000000000..4078ce224 --- /dev/null +++ b/lib/libkvm/kvm_read.3 @@ -0,0 +1,93 @@ +.\" $NetBSD: kvm_read.3,v 1.8 2003/08/07 16:44:39 agc Exp $ +.\" +.\" Copyright (c) 1992, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software developed by the Computer Systems +.\" Engineering group at Lawrence Berkeley Laboratory under DARPA contract +.\" BG 91-66 and contributed to Berkeley. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)kvm_read.3 8.1 (Berkeley) 6/4/93 +.\" +.Dd June 4, 1993 +.Dt KVM_READ 3 +.Os +.Sh NAME +.Nm kvm_read , +.Nm kvm_write +.Nd read or write kernel virtual memory +.Sh LIBRARY +.Lb libkvm +.Sh SYNOPSIS +.In kvm.h +.Ft ssize_t +.Fn kvm_read "kvm_t *kd" "u_long addr" "void *buf" "size_t nbytes" +.Ft ssize_t +.Fn kvm_write "kvm_t *kd" "u_long addr" "const void *buf" "size_t nbytes" +.Sh DESCRIPTION +The +.Fn kvm_read +and +.Fn kvm_write +functions are used to read and write kernel virtual memory (or a crash +dump file). +See +.Fn kvm_open 3 +or +.Fn kvm_openfiles 3 +for information regarding opening kernel virtual memory and crash dumps. +.Pp +The +.Fn kvm_read +function transfers +.Fa nbytes +bytes of data from +the kernel space address +.Fa addr +to +.Fa buf . +Conversely, +.Fn kvm_write +transfers data from +.Fa buf +to +.Fa addr . +Unlike their SunOS counterparts, these functions cannot be used to +read or write process address spaces. +.Sh RETURN VALUES +Upon success, the number of bytes actually transferred is returned. +Otherwise, -1 is returned. +.Sh SEE ALSO +.Xr kvm 3 , +.Xr kvm_close 3 , +.Xr kvm_getargv 3 , +.Xr kvm_getenvv 3 , +.Xr kvm_geterr 3 , +.Xr kvm_getprocs 3 , +.Xr kvm_nlist 3 , +.Xr kvm_open 3 , +.Xr kvm_openfiles 3 diff --git a/lib/libkvm/kvm_riscv.c b/lib/libkvm/kvm_riscv.c new file mode 100644 index 000000000..b41bc90cd --- /dev/null +++ b/lib/libkvm/kvm_riscv.c @@ -0,0 +1,126 @@ +/* $NetBSD: kvm_riscv.c,v 1.1 2014/09/19 17:36:25 matt Exp $ */ + +/*- + * Copyright (c) 2014 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Matt Thomas of 3am Software Foundry. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * OR1K machine dependent routines for kvm. + */ + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include "kvm_private.h" + +#include +#include +#include + +__RCSID("$NetBSD: kvm_riscv.c,v 1.1 2014/09/19 17:36:25 matt Exp $"); + +void +_kvm_freevtop(kvm_t *kd) +{ + if (kd->vmst != 0) + free(kd->vmst); +} + +/*ARGSUSED*/ +int +_kvm_initvtop(kvm_t *kd) +{ + + return 0; +} + +/* + * Translate a KVA to a PA + */ +int +_kvm_kvatop(kvm_t *kd, vaddr_t va, paddr_t *pa) +{ +// cpu_kcore_hdr_t *cpu_kh; + + if (ISALIVE(kd)) { + _kvm_err(kd, 0, "vatop called in live kernel!"); + return 0; + } + + /* No hit -- no translation */ + *pa = (u_long)~0UL; + return 0; +} + +off_t +_kvm_pa2off(kvm_t *kd, paddr_t pa) +{ + cpu_kcore_hdr_t *cpu_kh; + phys_ram_seg_t *ram; + off_t off; + void *e; + + cpu_kh = kd->cpu_data; + e = (char *) kd->cpu_data + kd->cpu_dsize; + ram = (void *)((char *)(void *)cpu_kh + ALIGN(sizeof *cpu_kh)); + off = kd->dump_off; + do { + if (pa >= ram->start && (pa - ram->start) < ram->size) { + return off + (pa - ram->start); + } + ram++; + off += ram->size; + } while ((void *) ram < e && ram->size); + + _kvm_err(kd, 0, "pa2off failed for pa %#" PRIxPADDR "\n", pa); + return (off_t) -1; +} + +/* + * Machine-dependent initialization for ALL open kvm descriptors, + * not just those for a kernel crash dump. Some architectures + * have to deal with these NOT being constants! (i.e. m68k) + */ +int +_kvm_mdopen(kvm_t *kd) +{ + kd->usrstack = USRSTACK; + kd->min_uva = VM_MIN_ADDRESS; + kd->max_uva = VM_MAXUSER_ADDRESS; + + return (0); +} diff --git a/lib/libkvm/kvm_sh3.c b/lib/libkvm/kvm_sh3.c new file mode 100644 index 000000000..0726a503b --- /dev/null +++ b/lib/libkvm/kvm_sh3.c @@ -0,0 +1,126 @@ +/* $NetBSD: kvm_sh3.c,v 1.9 2014/02/19 20:21:22 dsl Exp $ */ + +/*- + * Copyright (c) 1989, 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software developed by the Computer Systems + * Engineering group at Lawrence Berkeley Laboratory under DARPA contract + * BG 91-66 and contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)kvm_hp300.c 8.1 (Berkeley) 6/4/93"; +#else +__RCSID("$NetBSD: kvm_sh3.c,v 1.9 2014/02/19 20:21:22 dsl Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + +/* + * SH3 machine dependent routines for kvm. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include + +#include "kvm_private.h" + +#include +#include + +#ifndef btop +#define btop(x) (((unsigned)(x)) >> PGSHIFT) /* XXX */ +#define ptob(x) ((caddr_t)((x) << PGSHIFT)) /* XXX */ +#endif + +void +_kvm_freevtop(kvm_t *kd) +{ + + /* Not actually used for anything right now, but safe. */ + if (kd->vmst != 0) + free(kd->vmst); +} + +/*ARGSUSED*/ +int +_kvm_initvtop(kvm_t *kd) +{ + + return (0); +} + +/* + * Translate a kernel virtual address to a physical address. + */ +int +_kvm_kvatop(kvm_t *kd, vaddr_t va, paddr_t *pa) +{ + _kvm_err(kd, 0, "vatop not yet implemented!"); + return 0; +} + +/* + * Translate a physical address to a file-offset in the crash dump. + */ +off_t +_kvm_pa2off(kvm_t *kd, paddr_t pa) +{ + _kvm_err(kd, 0, "pa2off not yet implemented!"); + return 0; +} + +/* + * Machine-dependent initialization for ALL open kvm descriptors, + * not just those for a kernel crash dump. Some architectures + * have to deal with these NOT being constants! (i.e. m68k) + */ +int +_kvm_mdopen(kvm_t *kd) +{ + + kd->usrstack = USRSTACK; + kd->min_uva = VM_MIN_ADDRESS; + kd->max_uva = VM_MAXUSER_ADDRESS; + + return (0); +} diff --git a/lib/libkvm/kvm_sparc.c b/lib/libkvm/kvm_sparc.c new file mode 100644 index 000000000..55f19c3cb --- /dev/null +++ b/lib/libkvm/kvm_sparc.c @@ -0,0 +1,390 @@ +/* $NetBSD: kvm_sparc.c,v 1.34 2015/10/07 11:56:41 martin Exp $ */ + +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software developed by the Computer Systems + * Engineering group at Lawrence Berkeley Laboratory under DARPA contract + * BG 91-66 and contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)kvm_sparc.c 8.1 (Berkeley) 6/4/93"; +#else +__RCSID("$NetBSD: kvm_sparc.c,v 1.34 2015/10/07 11:56:41 martin Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + +/* + * Sparc machine dependent routines for kvm. Hopefully, the forthcoming + * vm code will one day obsolete this module. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include + +#include "kvm_private.h" + + +static int cputyp = -1; +static int pgshift; +static int nptesg; /* [sun4/sun4c] only */ + +#undef VA_VPG +#define VA_VPG(va) ((cputyp == CPU_SUN4C || cputyp == CPU_SUN4M) \ + ? VA_SUN4C_VPG(va) \ + : VA_SUN4_VPG(va)) + +#undef VA_OFF +#define VA_OFF(va) (va & (kd->nbpg - 1)) + +int _kvm_kvatop44c(kvm_t *, vaddr_t, paddr_t *); +int _kvm_kvatop4m (kvm_t *, vaddr_t, paddr_t *); +int _kvm_kvatop4u (kvm_t *, vaddr_t, paddr_t *); + +/* + * XXX + * taken from /sys/arch/sparc64/include/kcore.h. + * this is the same as the sparc one, except for the kphys addition, + * so luckily we can use this here... + */ +typedef struct sparc64_cpu_kcore_hdr { + int cputype; /* CPU type associated with this dump */ + u_long kernbase; /* copy of KERNBASE goes here */ + int nmemseg; /* # of physical memory segments */ + u_long memsegoffset; /* start of memseg array (relative */ + /* to the start of this header) */ + int nsegmap; /* # of segmaps following */ + u_long segmapoffset; /* start of segmap array (relative */ + /* to the start of this header) */ + int npmeg; /* # of PMEGs; [sun4/sun4c] only */ + u_long pmegoffset; /* start of pmeg array (relative */ + /* to the start of this header) */ +/* SPARC64 stuff */ + paddr_t kphys; /* Physical address of 4MB locked TLB */ +} sparc64_cpu_kcore_hdr_t; + +void +_kvm_freevtop(kvm_t *kd) +{ + if (kd->vmst != 0) { + _kvm_err(kd, kd->program, "_kvm_freevtop: internal error"); + kd->vmst = 0; + } +} + +/* + * Prepare for translation of kernel virtual addresses into offsets + * into crash dump files. We use the MMU specific goop written at the + * front of the crash dump by pmap_dumpmmu(). + */ +int +_kvm_initvtop(kvm_t *kd) +{ + sparc64_cpu_kcore_hdr_t *cpup = kd->cpu_data; + + switch (cputyp = cpup->cputype) { + case CPU_SUN4: + case CPU_SUN4U: + kd->nbpg = 8196; + pgshift = 13; + break; + case CPU_SUN4C: + case CPU_SUN4M: + kd->nbpg = 4096; + pgshift = 12; + break; + default: + _kvm_err(kd, kd->program, "Unsupported CPU type"); + return (-1); + } + nptesg = NBPSG / kd->nbpg; + return (0); +} + +/* + * Translate a kernel virtual address to a physical address using the + * mapping information in kd->vm. Returns the result in pa, and returns + * the number of bytes that are contiguously available from this + * physical address. This routine is used only for crash dumps. + */ +int +_kvm_kvatop(kvm_t *kd, vaddr_t va, paddr_t *pa) +{ + if (cputyp == -1) + if (_kvm_initvtop(kd) != 0) + return (-1); + + switch (cputyp) { + case CPU_SUN4: + case CPU_SUN4C: + return _kvm_kvatop44c(kd, va, pa); + break; + case CPU_SUN4M: + return _kvm_kvatop4m(kd, va, pa); + break; + case CPU_SUN4U: + default: + return _kvm_kvatop4u(kd, va, pa); + } +} + +/* + * (note: sun4 3-level MMU not yet supported) + */ +int +_kvm_kvatop44c(kvm_t *kd, vaddr_t va, paddr_t *pa) +{ + int vr, vs, pte; + sparc64_cpu_kcore_hdr_t *cpup = kd->cpu_data; + struct segmap *sp, *segmaps; + int *ptes; + int nkreg, nureg; + u_long kernbase = cpup->kernbase; + + if (va < kernbase) + goto err; + + /* + * Layout of CPU segment: + * cpu_kcore_hdr_t; + * [alignment] + * phys_ram_seg_t[cpup->nmemseg]; + * segmap[cpup->nsegmap]; + * ptes[cpup->npmegs]; + */ + segmaps = (struct segmap *)((long)kd->cpu_data + cpup->segmapoffset); + ptes = (int *)((int)kd->cpu_data + cpup->pmegoffset); + nkreg = ((int)((-(unsigned)kernbase) / NBPRG)); + nureg = 256 - nkreg; + + vr = VA_VREG(va); + vs = VA_VSEG(va); + + sp = &segmaps[(vr-nureg)*NSEGRG + vs]; + if (sp->sg_npte == 0) + goto err; + if (sp->sg_pmeg == cpup->npmeg - 1) /* =seginval */ + goto err; + pte = ptes[sp->sg_pmeg * nptesg + VA_VPG(va)]; + if ((pte & PG_V) != 0) { + paddr_t p, off = VA_OFF(va); + + p = (pte & PG_PFNUM) << pgshift; + *pa = p + off; + return (kd->nbpg - off); + } +err: + _kvm_err(kd, 0, "invalid address (%#"PRIxVADDR")", va); + return (0); +} + +int +_kvm_kvatop4m(kvm_t *kd, vaddr_t va, paddr_t *pa) +{ + sparc64_cpu_kcore_hdr_t *cpup = kd->cpu_data; + int vr, vs; + int pte; + off_t foff; + struct segmap *sp, *segmaps; + int nkreg, nureg; + u_long kernbase = cpup->kernbase; + + if (va < kernbase) + goto err; + + /* + * Layout of CPU segment: + * cpu_kcore_hdr_t; + * [alignment] + * phys_ram_seg_t[cpup->nmemseg]; + * segmap[cpup->nsegmap]; + */ + segmaps = (struct segmap *)((long)kd->cpu_data + cpup->segmapoffset); + nkreg = ((int)((-(unsigned)kernbase) / NBPRG)); + nureg = 256 - nkreg; + + vr = VA_VREG(va); + vs = VA_VSEG(va); + + sp = &segmaps[(vr-nureg)*NSEGRG + vs]; + if (sp->sg_npte == 0) + goto err; + + /* XXX - assume page tables in initial kernel DATA or BSS. */ + foff = _kvm_pa2off(kd, (u_long)&sp->sg_pte[VA_VPG(va)] - kernbase); + if (foff == (off_t)-1) + return (0); + + if (_kvm_pread(kd, kd->pmfd, &pte, sizeof(pte), foff) != sizeof(pte)) { + _kvm_syserr(kd, kd->program, "cannot read pte for " + "%#" PRIxVADDR, va); + return (0); + } + + if ((pte & SRMMU_TETYPE) == SRMMU_TEPTE) { + long p, off = VA_OFF(va); + + p = (pte & SRMMU_PPNMASK) << SRMMU_PPNPASHIFT; + *pa = p + off; + return (kd->nbpg - off); + } +err: + _kvm_err(kd, 0, "invalid address (%#"PRIxVADDR")", va); + return (0); +} + +/* + * sparc64 pmap's 32-bit page table format + */ +int +_kvm_kvatop4u(kvm_t *kd, vaddr_t va, paddr_t *pa) +{ + sparc64_cpu_kcore_hdr_t *cpup = kd->cpu_data; + int64_t **segmaps; + int64_t *ptes; + int64_t pte; + int64_t kphys = cpup->kphys; + u_long kernbase = cpup->kernbase; + + if (va < kernbase) + goto err; + + /* + * Kernel layout: + * + * kernbase: + * 4MB locked TLB (text+data+BSS) + * Random other stuff. + */ + if (va >= kernbase && va < kernbase + 4*1024*1024) + return (va - kernbase) + kphys; + +/* XXX: from sparc64/include/pmap.h */ +#define SPARC64_PTSZ (kd->nbpg/8) +#define SPARC64_STSZ (SPARC64_PTSZ) +#define SPARC64_PTMASK (SPARC64_PTSZ-1) +#define SPARC64_PTSHIFT (13) +#define SPARC64_PDSHIFT (10+SPARC64_PTSHIFT) +#define SPARC64_STSHIFT (10+SPARC64_PDSHIFT) +#define SPARC64_STMASK (SPARC64_STSZ-1) +#define sparc64_va_to_seg(v) (int)((((int64_t)(v))>>SPARC64_STSHIFT)&SPARC64_STMASK) +#define sparc64_va_to_pte(v) (int)((((int64_t)(v))>>SPARC64_PTSHIFT)&SPARC64_PTMASK) + +/* XXX: from sparc64/include/pte.h */ +#define SPARC64_TLB_V 0x8000000000000000LL +#define SPARC64_TLB_PA_MASK 0x000001ffffffe000LL + + /* + * Layout of CPU segment: + * cpu_kcore_hdr_t; + * [alignment] + * phys_ram_seg_t[cpup->nmemseg]; + * segmap[cpup->nsegmap]; + */ + segmaps = (int64_t **)((long)kd->cpu_data + cpup->segmapoffset); + ptes = (int64_t *)(intptr_t)_kvm_pa2off(kd, + (paddr_t)(intptr_t)segmaps[sparc64_va_to_seg(va)]); + pte = ptes[sparc64_va_to_pte(va)]; + if ((pte & SPARC64_TLB_V) != 0) + return ((pte & SPARC64_TLB_PA_MASK) | (va & (kd->nbpg - 1))); +err: + _kvm_err(kd, 0, "invalid address (%#"PRIxVADDR")", va); + return (0); +} + + +/* + * Translate a physical address to a file-offset in the crash dump. + */ +off_t +_kvm_pa2off(kvm_t *kd, paddr_t pa) +{ + sparc64_cpu_kcore_hdr_t *cpup = kd->cpu_data; + phys_ram_seg_t *mp; + off_t off; + int nmem; + + /* + * Layout of CPU segment: + * cpu_kcore_hdr_t; + * [alignment] + * phys_ram_seg_t[cpup->nmemseg]; + */ + mp = (phys_ram_seg_t *)((int)kd->cpu_data + cpup->memsegoffset); + off = 0; + + /* Translate (sparse) pfnum to (packed) dump offset */ + for (nmem = cpup->nmemseg; --nmem >= 0; mp++) { + if (mp->start <= pa && pa < mp->start + mp->size) + break; + off += mp->size; + } + if (nmem < 0) { + _kvm_err(kd, 0, "invalid address (%lx)", (unsigned long)pa); + return (-1); + } + + return (kd->dump_off + off + pa - mp->start); +} + +/* + * Machine-dependent initialization for ALL open kvm descriptors, + * not just those for a kernel crash dump. Some architectures + * have to deal with these NOT being constants! (i.e. m68k) + */ +int +_kvm_mdopen(kvm_t *kd) +{ + u_long max_uva; + extern struct ps_strings *__ps_strings; + + max_uva = (u_long) (__ps_strings + 1); + kd->usrstack = max_uva; + kd->max_uva = max_uva; + kd->min_uva = 0; + + return (0); +} diff --git a/lib/libkvm/kvm_sparc64.c b/lib/libkvm/kvm_sparc64.c new file mode 100644 index 000000000..abfb84b3e --- /dev/null +++ b/lib/libkvm/kvm_sparc64.c @@ -0,0 +1,281 @@ +/* $NetBSD: kvm_sparc64.c,v 1.17 2014/02/21 18:00:09 palle Exp $ */ + +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software developed by the Computer Systems + * Engineering group at Lawrence Berkeley Laboratory under DARPA contract + * BG 91-66 and contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)kvm_sparc.c 8.1 (Berkeley) 6/4/93"; +#else +__RCSID("$NetBSD: kvm_sparc64.c,v 1.17 2014/02/21 18:00:09 palle Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + +/* + * Sparc machine dependent routines for kvm. Hopefully, the forthcoming + * vm code will one day obsolete this module. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include + +#include "kvm_private.h" + +void +_kvm_freevtop(kvm_t *kd) +{ + if (kd->vmst != 0) { + _kvm_err(kd, kd->program, "_kvm_freevtop: internal error"); + kd->vmst = 0; + } +} + +/* + * Prepare for translation of kernel virtual addresses into offsets + * into crash dump files. We use the MMU specific goop written at the + * front of the crash dump by pmap_dumpmmu(). + * + * We should read in and cache the ksegs here to speed up operations... + */ +int +_kvm_initvtop(kvm_t *kd) +{ + kd->nbpg = 0x2000; + + return (0); +} + +/* + * Translate a kernel virtual address to a physical address using the + * mapping information in kd->vm. Returns the result in pa, and returns + * the number of bytes that are contiguously available from this + * physical address. This routine is used only for crash dumps. + */ +int +_kvm_kvatop(kvm_t *kd, vaddr_t va, paddr_t *pa) +{ + cpu_kcore_hdr_t *cpup = kd->cpu_data; + u_long kernbase = cpup->kernbase; + uint64_t *pseg, *pdir, *ptbl; + struct cpu_kcore_4mbseg *ktlb; + int64_t data; + int i; + + if (va < kernbase) + goto lose; + + /* Handle the wired 4MB TTEs and per-CPU mappings */ + if (cpup->memsegoffset > sizeof(cpu_kcore_hdr_t) && + cpup->newmagic == SPARC64_KCORE_NEWMAGIC) { + /* + * new format: we have a list of 4 MB mappings + */ + ktlb = (struct cpu_kcore_4mbseg *) + ((uintptr_t)kd->cpu_data + cpup->off4mbsegs); + for (i = 0; i < cpup->num4mbsegs; i++) { + uint64_t start = ktlb[i].va; + if (va < start || va >= start+PAGE_SIZE_4M) + continue; + *pa = ktlb[i].pa + va - start; + return (int)(start+PAGE_SIZE_4M - va); + } + + if (cpup->numcpuinfos > 0) { + /* we have per-CPU mapping info */ + uint64_t start, base; + + base = cpup->cpubase - 32*1024; + if (va >= base && va < (base + cpup->percpusz)) { + start = va - base; + *pa = cpup->cpusp + + cpup->thiscpu*cpup->percpusz + + start; + return cpup->percpusz - start; + } + } + } else { + /* + * old format: just a textbase/size and database/size + */ + if (va > cpup->ktextbase && va < + (cpup->ktextbase + cpup->ktextsz)) { + u_long vaddr; + + vaddr = va - cpup->ktextbase; + *pa = cpup->ktextp + vaddr; + return (int)(cpup->ktextsz - vaddr); + } + if (va > cpup->kdatabase && va < + (cpup->kdatabase + cpup->kdatasz)) { + u_long vaddr; + + vaddr = va - cpup->kdatabase; + *pa = cpup->kdatap + vaddr; + return (int)(cpup->kdatasz - vaddr); + } + } + + /* + * Parse kernel page table. + */ + pseg = (uint64_t *)(u_long)cpup->segmapoffset; + if (_kvm_pread(kd, kd->pmfd, &pdir, sizeof(pdir), + _kvm_pa2off(kd, (paddr_t)&pseg[va_to_seg(va)])) + != sizeof(pdir)) { + _kvm_syserr(kd, 0, "could not read L1 PTE"); + goto lose; + } + + if (!pdir) { + _kvm_err(kd, 0, "invalid L1 PTE"); + goto lose; + } + + if (_kvm_pread(kd, kd->pmfd, &ptbl, sizeof(ptbl), + _kvm_pa2off(kd, (paddr_t)&pdir[va_to_dir(va)])) + != sizeof(ptbl)) { + _kvm_syserr(kd, 0, "could not read L2 PTE"); + goto lose; + } + + if (!ptbl) { + _kvm_err(kd, 0, "invalid L2 PTE"); + goto lose; + } + + if (_kvm_pread(kd, kd->pmfd, &data, sizeof(data), + _kvm_pa2off(kd, (paddr_t)&ptbl[va_to_pte(va)])) + != sizeof(data)) { + _kvm_syserr(kd, 0, "could not read TTE"); + goto lose; + } + + if (data >= 0) { + _kvm_err(kd, 0, "invalid L2 TTE"); + goto lose; + } + + /* + * Calculate page offsets and things. + * + * XXXX -- We could support multiple page sizes. + */ + va = va & (kd->nbpg - 1); + data &= SUN4U_TLB_PA_MASK; /* XXX handle sun4u/sun4v */ + *pa = data + va; + + /* + * Parse and trnslate our TTE. + */ + + return (int)(kd->nbpg - va); + +lose: + *pa = (u_long)-1; + _kvm_err(kd, 0, "invalid address (%#"PRIxVADDR")", va); + return (0); +} + + +/* + * Translate a physical address to a file-offset in the crash dump. + */ +off_t +_kvm_pa2off(kvm_t *kd, paddr_t pa) +{ + cpu_kcore_hdr_t *cpup = kd->cpu_data; + phys_ram_seg_t *mp; + off_t off; + int nmem; + + /* + * Layout of CPU segment: + * cpu_kcore_hdr_t; + * [alignment] + * phys_ram_seg_t[cpup->nmemseg]; + */ + mp = (phys_ram_seg_t *)((long)kd->cpu_data + cpup->memsegoffset); + off = 0; + + /* Translate (sparse) pfnum to (packed) dump offset */ + for (nmem = cpup->nmemseg; --nmem >= 0; mp++) { + if (mp->start <= pa && pa < mp->start + mp->size) + break; + off += mp->size; + } + if (nmem < 0) { + _kvm_err(kd, 0, "invalid address (%#"PRIxPADDR")", pa); + return (-1); + } + + return (kd->dump_off + off + pa - mp->start); +} + +/* + * Machine-dependent initialization for ALL open kvm descriptors, + * not just those for a kernel crash dump. Some architectures + * have to deal with these NOT being constants! (i.e. m68k) + */ +int +_kvm_mdopen(kvm_t *kd) +{ + u_long max_uva; + extern struct ps_strings *__ps_strings; + + max_uva = (u_long) (__ps_strings + 1); + kd->usrstack = max_uva; + kd->max_uva = max_uva; + kd->min_uva = 0; + + return (0); +} diff --git a/lib/libkvm/kvm_sun2.c b/lib/libkvm/kvm_sun2.c new file mode 100644 index 000000000..bbd1b56b3 --- /dev/null +++ b/lib/libkvm/kvm_sun2.c @@ -0,0 +1,181 @@ +/* $NetBSD: kvm_sun2.c,v 1.6 2011/09/14 12:37:55 christos Exp $ */ + +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software developed by the Computer Systems + * Engineering group at Lawrence Berkeley Laboratory under DARPA contract + * BG 91-66 and contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)kvm_sparc.c 8.1 (Berkeley) 6/4/93"; +#else +__RCSID("$NetBSD: kvm_sun2.c,v 1.6 2011/09/14 12:37:55 christos Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + +/* + * Sun2 machine dependent routines for kvm. + * + * Note: This file has to build on ALL m68000 machines, + * so do NOT include any files here. + */ +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "kvm_private.h" +#include "kvm_m68k.h" + +int _kvm_sun2_initvtop(kvm_t *); +void _kvm_sun2_freevtop(kvm_t *); +int _kvm_sun2_kvatop (kvm_t *, vaddr_t, paddr_t *); +off_t _kvm_sun2_pa2off (kvm_t *, paddr_t); + +struct kvm_ops _kvm_ops_sun2 = { + _kvm_sun2_initvtop, + _kvm_sun2_freevtop, + _kvm_sun2_kvatop, + _kvm_sun2_pa2off }; + +#define _kvm_pg_pa(v, s, pte) \ + (((pte) & (s)->pg_frame) << (v)->pgshift) + +#define _kvm_va_segnum(s, x) \ + ((u_int)(x) >> (s)->segshift) +#define _kvm_pte_num_mask(v) \ + (0xf << (v)->pgshift) +#define _kvm_va_pte_num(v, va) \ + (((va) & _kvm_pte_num_mask((v))) >> (v)->pgshift) + +/* + * XXX Re-define these here, no other place for them. + */ +#define NKSEG 512 /* kernel segmap entries */ +#define NPAGSEG 16 /* pages per segment */ + +/* Finally, our local stuff... */ +struct private_vmstate { + /* Page Map Entry Group (PMEG) */ + int pmeg[NKSEG][NPAGSEG]; +}; + +/* + * Prepare for translation of kernel virtual addresses into offsets + * into crash dump files. We use the MMU specific goop written at the + * beginning of a crash dump by dumpsys() + * Note: sun2 MMU specific! + */ +int +_kvm_sun2_initvtop(kvm_t *kd) +{ + cpu_kcore_hdr_t *h = kd->cpu_data; + char *p; + + p = kd->cpu_data; + p += (h->page_size - sizeof(kcore_seg_t)); + kd->vmst->private = p; + + return (0); +} + +void +_kvm_sun2_freevtop(kvm_t *kd) +{ + /* This was set by pointer arithmetic, not allocation. */ + kd->vmst->private = (void*)0; +} + +/* + * Translate a kernel virtual address to a physical address using the + * mapping information in kd->vm. Returns the result in pa, and returns + * the number of bytes that are contiguously available from this + * physical address. This routine is used only for crash dumps. + */ +int +_kvm_sun2_kvatop(kvm_t *kd, vaddr_t va, paddr_t *pap) +{ + cpu_kcore_hdr_t *h = kd->cpu_data; + struct sun2_kcore_hdr *s = &h->un._sun2; + struct vmstate *v = kd->vmst; + struct private_vmstate *pv = v->private; + int pte, offset; + u_int segnum, sme, ptenum; + paddr_t pa; + + if (ISALIVE(kd)) { + _kvm_err(kd, 0, "vatop called in live kernel!"); + return(0); + } + + if (va < h->kernbase) { + _kvm_err(kd, 0, "not a kernel address"); + return(0); + } + + /* + * Get the segmap entry (sme) from the kernel segmap. + * Note: only have segmap entries from KERNBASE to end. + */ + segnum = _kvm_va_segnum(s, va - h->kernbase); + ptenum = _kvm_va_pte_num(v, va); + offset = va & v->pgofset; + + /* The segmap entry selects a PMEG. */ + sme = s->ksegmap[segnum]; + pte = pv->pmeg[sme][ptenum]; + + if ((pte & (s)->pg_valid) == 0) { + _kvm_err(kd, 0, "page not valid (VA=0x%lx)", va); + return (0); + } + pa = _kvm_pg_pa(v, s, pte) + offset; + + *pap = pa; + return (h->page_size - offset); +} + +/* + * Translate a physical address to a file-offset in the crash dump. + */ +off_t +_kvm_sun2_pa2off(kvm_t *kd, paddr_t pa) +{ + return(kd->dump_off + pa); +} diff --git a/lib/libkvm/kvm_sun3.c b/lib/libkvm/kvm_sun3.c new file mode 100644 index 000000000..298e338bf --- /dev/null +++ b/lib/libkvm/kvm_sun3.c @@ -0,0 +1,181 @@ +/* $NetBSD: kvm_sun3.c,v 1.15 2011/09/14 12:37:55 christos Exp $ */ + +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software developed by the Computer Systems + * Engineering group at Lawrence Berkeley Laboratory under DARPA contract + * BG 91-66 and contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)kvm_sparc.c 8.1 (Berkeley) 6/4/93"; +#else +__RCSID("$NetBSD: kvm_sun3.c,v 1.15 2011/09/14 12:37:55 christos Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + +/* + * Sun3 machine dependent routines for kvm. + * + * Note: This file has to build on ALL m68k machines, + * so do NOT include any files here. + */ +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "kvm_private.h" +#include "kvm_m68k.h" + +int _kvm_sun3_initvtop(kvm_t *); +void _kvm_sun3_freevtop(kvm_t *); +int _kvm_sun3_kvatop (kvm_t *, vaddr_t, paddr_t *); +off_t _kvm_sun3_pa2off (kvm_t *, paddr_t); + +struct kvm_ops _kvm_ops_sun3 = { + _kvm_sun3_initvtop, + _kvm_sun3_freevtop, + _kvm_sun3_kvatop, + _kvm_sun3_pa2off }; + +#define _kvm_pg_pa(v, s, pte) \ + (((pte) & (s)->pg_frame) << (v)->pgshift) + +#define _kvm_va_segnum(s, x) \ + ((u_int)(x) >> (s)->segshift) +#define _kvm_pte_num_mask(v) \ + (0xf << (v)->pgshift) +#define _kvm_va_pte_num(v, va) \ + (((va) & _kvm_pte_num_mask((v))) >> (v)->pgshift) + +/* + * XXX Re-define these here, no other place for them. + */ +#define NKSEG 256 /* kernel segmap entries */ +#define NPAGSEG 16 /* pages per segment */ + +/* Finally, our local stuff... */ +struct private_vmstate { + /* Page Map Entry Group (PMEG) */ + int pmeg[NKSEG][NPAGSEG]; +}; + +/* + * Prepare for translation of kernel virtual addresses into offsets + * into crash dump files. We use the MMU specific goop written at the + * beginning of a crash dump by dumpsys() + * Note: sun3 MMU specific! + */ +int +_kvm_sun3_initvtop(kvm_t *kd) +{ + cpu_kcore_hdr_t *h = kd->cpu_data; + char *p; + + p = kd->cpu_data; + p += (h->page_size - sizeof(kcore_seg_t)); + kd->vmst->private = p; + + return (0); +} + +void +_kvm_sun3_freevtop(kvm_t *kd) +{ + /* This was set by pointer arithmetic, not allocation. */ + kd->vmst->private = (void*)0; +} + +/* + * Translate a kernel virtual address to a physical address using the + * mapping information in kd->vm. Returns the result in pa, and returns + * the number of bytes that are contiguously available from this + * physical address. This routine is used only for crash dumps. + */ +int +_kvm_sun3_kvatop(kvm_t *kd, vaddr_t va, paddr_t *pap) +{ + cpu_kcore_hdr_t *h = kd->cpu_data; + struct sun3_kcore_hdr *s = &h->un._sun3; + struct vmstate *v = kd->vmst; + struct private_vmstate *pv = v->private; + int pte, offset; + u_int segnum, sme, ptenum; + paddr_t pa; + + if (ISALIVE(kd)) { + _kvm_err(kd, 0, "vatop called in live kernel!"); + return(0); + } + + if (va < h->kernbase) { + _kvm_err(kd, 0, "not a kernel address"); + return(0); + } + + /* + * Get the segmap entry (sme) from the kernel segmap. + * Note: only have segmap entries from KERNBASE to end. + */ + segnum = _kvm_va_segnum(s, va - h->kernbase); + ptenum = _kvm_va_pte_num(v, va); + offset = va & v->pgofset; + + /* The segmap entry selects a PMEG. */ + sme = s->ksegmap[segnum]; + pte = pv->pmeg[sme][ptenum]; + + if ((pte & (s)->pg_valid) == 0) { + _kvm_err(kd, 0, "page not valid (VA=%#"PRIxVADDR")", va); + return (0); + } + pa = _kvm_pg_pa(v, s, pte) + offset; + + *pap = pa; + return (h->page_size - offset); +} + +/* + * Translate a physical address to a file-offset in the crash dump. + */ +off_t +_kvm_sun3_pa2off(kvm_t *kd, paddr_t pa) +{ + return(kd->dump_off + pa); +} diff --git a/lib/libkvm/kvm_sun3x.c b/lib/libkvm/kvm_sun3x.c new file mode 100644 index 000000000..c7539d152 --- /dev/null +++ b/lib/libkvm/kvm_sun3x.c @@ -0,0 +1,176 @@ +/* $NetBSD: kvm_sun3x.c,v 1.12 2011/09/14 12:37:55 christos Exp $ */ + +/*- + * Copyright (c) 1997 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Gordon W. Ross. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)kvm_sparc.c 8.1 (Berkeley) 6/4/93"; +#else +__RCSID("$NetBSD: kvm_sun3x.c,v 1.12 2011/09/14 12:37:55 christos Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + +/* + * Sun3x machine dependent routines for kvm. + * + * Note: This file has to build on ALL m68k machines, + * so do NOT include any files here. + */ +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "kvm_private.h" +#include "kvm_m68k.h" + +int _kvm_sun3x_initvtop(kvm_t *); +void _kvm_sun3x_freevtop(kvm_t *); +int _kvm_sun3x_kvatop (kvm_t *, vaddr_t, paddr_t *); +off_t _kvm_sun3x_pa2off (kvm_t *, paddr_t); + +struct kvm_ops _kvm_ops_sun3x = { + _kvm_sun3x_initvtop, + _kvm_sun3x_freevtop, + _kvm_sun3x_kvatop, + _kvm_sun3x_pa2off }; + +#define _kvm_kvas_size(h) \ + (-((h)->kernbase)) +#define _kvm_nkptes(h, v) \ + (_kvm_kvas_size((h)) >> (v)->pgshift) +#define _kvm_pg_pa(pte, h) \ + ((pte) & (h)->pg_frame) + +/* + * Prepare for translation of kernel virtual addresses into offsets + * into crash dump files. Nothing to do here. + */ +int +_kvm_sun3x_initvtop(kvm_t *kd) +{ + return 0; +} + +void +_kvm_sun3x_freevtop(kvm_t *kd) +{ +} + +/* + * Translate a kernel virtual address to a physical address using the + * mapping information in kd->vm. Returns the result in pa, and returns + * the number of bytes that are contiguously available from this + * physical address. This routine is used only for crash dumps. + */ +int +_kvm_sun3x_kvatop(kvm_t *kd, vaddr_t va, paddr_t *pap) +{ + cpu_kcore_hdr_t *h = kd->cpu_data; + struct sun3x_kcore_hdr *s = &h->un._sun3x; + struct vmstate *v = kd->vmst; + int idx, len, offset, pte; + u_long pteva, pa; + + if (ISALIVE(kd)) { + _kvm_err(kd, 0, "vatop called in live kernel!"); + return(0); + } + + if (va < h->kernbase) { + _kvm_err(kd, 0, "not a kernel address"); + return(0); + } + + /* + * If this VA is in the contiguous range, short-cut. + * Note that this ends our recursion when we call + * kvm_read to access the kernel page table, which + * is guaranteed to be in the contiguous range. + */ + if (va < s->contig_end) { + len = s->contig_end - va; + pa = va - h->kernbase; + goto done; + } + + /* + * The KVA is beyond the contiguous range, so we must + * read the PTE for this KVA from the page table. + */ + idx = ((va - h->kernbase) >> v->pgshift); + pteva = s->kernCbase + (idx * 4); + if (kvm_read(kd, pteva, &pte, 4) != 4) { + _kvm_err(kd, 0, "can not read PTE!"); + return (0); + } + if ((pte & s->pg_valid) == 0) { + _kvm_err(kd, 0, "page not valid (VA=0x%lx)", va); + return (0); + } + offset = va & v->pgofset; + len = (h->page_size - offset); + pa = _kvm_pg_pa(pte, s) + offset; + +done: + *pap = pa; + return (len); +} + +/* + * Translate a physical address to a file-offset in the crash dump. + */ +off_t +_kvm_sun3x_pa2off(kvm_t *kd, paddr_t pa) +{ + off_t off; + phys_ram_seg_t *rsp; + cpu_kcore_hdr_t *h = kd->cpu_data; + struct sun3x_kcore_hdr *s = &h->un._sun3x; + + off = 0; + for (rsp = s->ram_segs; rsp->size; rsp++) { + if (pa >= rsp->start && pa < rsp->start + rsp->size) { + pa -= rsp->start; + break; + } + off += rsp->size; + } + return (kd->dump_off + off + pa); +} + diff --git a/lib/libkvm/kvm_vax.c b/lib/libkvm/kvm_vax.c new file mode 100644 index 000000000..d6b9ebe59 --- /dev/null +++ b/lib/libkvm/kvm_vax.c @@ -0,0 +1,158 @@ +/* $NetBSD: kvm_vax.c,v 1.20 2014/02/19 20:21:22 dsl Exp $ */ + +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software developed by the Computer Systems + * Engineering group at Lawrence Berkeley Laboratory under DARPA contract + * BG 91-66 and contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * VAX machine dependent routines for kvm. Hopefully, the forthcoming + * vm code will one day obsolete this module. Furthermore, I hope it + * gets here soon, because this basically is an error stub! (sorry) + * This code may not work anyway. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include + +#include +#include + +#include "kvm_private.h" + +__RCSID("$NetBSD: kvm_vax.c,v 1.20 2014/02/19 20:21:22 dsl Exp $"); + +struct vmstate { + u_long end; +}; + +void +_kvm_freevtop(kvm_t *kd) +{ + if (kd->vmst != 0) + free(kd->vmst); +} + +int +_kvm_initvtop(kvm_t *kd) +{ + struct vmstate *vm; + struct stat st; + struct nlist nl[2]; + + vm = (struct vmstate *)_kvm_malloc(kd, sizeof(*vm)); + if (vm == 0) + return (-1); + + kd->vmst = vm; + + if (fstat(kd->pmfd, &st) < 0) + return (-1); + + /* Get end of kernel address */ + nl[0].n_name = "_end"; + nl[1].n_name = 0; + if (kvm_nlist(kd, nl) != 0) { + _kvm_err(kd, kd->program, "pmap_stod: no such symbol"); + return (-1); + } + vm->end = (u_long)nl[0].n_value; + + return (0); +} + +#define VA_OFF(va) (va & (NBPG - 1)) + +/* + * Translate a kernel virtual address to a physical address using the + * mapping information in kd->vm. Returns the result in pa, and returns + * the number of bytes that are contiguously available from this + * physical address. This routine is used only for crash dumps. + */ +int +_kvm_kvatop(kvm_t *kd, vaddr_t va, paddr_t *pa) +{ + u_long end; + + if (va < (u_long) KERNBASE) { + _kvm_err(kd, 0, "invalid address (%#"PRIxVADDR"<%lx)", va, + (u_long)KERNBASE); + return (0); + } + + end = kd->vmst->end; + if (va >= end) { + _kvm_err(kd, 0, "invalid address (%#"PRIxVADDR"<%lx)", va, + end); + return (0); + } + + *pa = (va - (u_long) KERNBASE); + return (end - va); +} + +/* + * Translate a physical address to a file-offset in the crash dump. + * XXX - crash dump doesn't work anyway. + */ +off_t +_kvm_pa2off(kvm_t *kd, paddr_t pa) +{ + return(kd->dump_off + pa); +} + + +/* + * Machine-dependent initialization for ALL open kvm descriptors, + * not just those for a kernel crash dump. Some architectures + * have to deal with these NOT being constants! (i.e. m68k) + */ +int +_kvm_mdopen(kvm_t *kd) +{ + + kd->usrstack = USRSTACK; + kd->min_uva = VM_MIN_ADDRESS; + kd->max_uva = VM_MAXUSER_ADDRESS; + + return (0); +} diff --git a/lib/libkvm/kvm_x86_64.c b/lib/libkvm/kvm_x86_64.c new file mode 100644 index 000000000..f902f9482 --- /dev/null +++ b/lib/libkvm/kvm_x86_64.c @@ -0,0 +1,230 @@ +/* $NetBSD: kvm_x86_64.c,v 1.10 2014/02/19 20:21:22 dsl Exp $ */ + +/*- + * Copyright (c) 1989, 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software developed by the Computer Systems + * Engineering group at Lawrence Berkeley Laboratory under DARPA contract + * BG 91-66 and contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)kvm_hp300.c 8.1 (Berkeley) 6/4/93"; +#else +__RCSID("$NetBSD: kvm_x86_64.c,v 1.10 2014/02/19 20:21:22 dsl Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + +/* + * x86-64 machine dependent routines for kvm. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include + +#include "kvm_private.h" + +#include +#include +#include +#include + +void +_kvm_freevtop(kvm_t *kd) +{ + + /* Not actually used for anything right now, but safe. */ + if (kd->vmst != 0) + free(kd->vmst); +} + +/*ARGSUSED*/ +int +_kvm_initvtop(kvm_t *kd) +{ + + return (0); +} + +/* + * Translate a kernel virtual address to a physical address. + */ +int +_kvm_kvatop(kvm_t *kd, vaddr_t va, paddr_t *pa) +{ + cpu_kcore_hdr_t *cpu_kh; + u_long page_off; + pd_entry_t pde; + pt_entry_t pte; + paddr_t pde_pa, pte_pa; + + if (ISALIVE(kd)) { + _kvm_err(kd, 0, "vatop called in live kernel!"); + return (0); + } + + cpu_kh = kd->cpu_data; + + /* + * Find and read all entries to get to the pa. + */ + + /* + * Level 4. + */ + pde_pa = cpu_kh->ptdpaddr + (pl4_pi(va) * sizeof(pd_entry_t)); + if (_kvm_pread(kd, kd->pmfd, (void *)&pde, sizeof(pde), + _kvm_pa2off(kd, pde_pa)) != sizeof(pde)) { + _kvm_syserr(kd, 0, "could not read PT level 4 entry"); + goto lose; + } + if ((pde & PG_V) == 0) { + _kvm_err(kd, 0, "invalid translation (invalid level 4 PDE)"); + goto lose; + } + + /* + * Level 3. + */ + pde_pa = (pde & PG_FRAME) + (pl3_pi(va) * sizeof(pd_entry_t)); + if (_kvm_pread(kd, kd->pmfd, (void *)&pde, sizeof(pde), + _kvm_pa2off(kd, pde_pa)) != sizeof(pde)) { + _kvm_syserr(kd, 0, "could not read PT level 3 entry"); + goto lose; + } + if ((pde & PG_V) == 0) { + _kvm_err(kd, 0, "invalid translation (invalid level 3 PDE)"); + goto lose; + } + if (pde & PG_PS) { + page_off = va & (NBPD_L3 - 1); + *pa = (pde & PG_1GFRAME) + page_off; + return (int)(NBPD_L3 - page_off); + } + + /* + * Level 2. + */ + pde_pa = (pde & PG_FRAME) + (pl2_pi(va) * sizeof(pd_entry_t)); + if (_kvm_pread(kd, kd->pmfd, (void *)&pde, sizeof(pde), + _kvm_pa2off(kd, pde_pa)) != sizeof(pde)) { + _kvm_syserr(kd, 0, "could not read PT level 2 entry"); + goto lose; + } + if ((pde & PG_V) == 0) { + _kvm_err(kd, 0, "invalid translation (invalid level 2 PDE)"); + goto lose; + } + if (pde & PG_PS) { + page_off = va & (NBPD_L2 - 1); + *pa = (pde & PG_2MFRAME) + page_off; + return (int)(NBPD_L2 - page_off); + } + + /* + * Level 1. + */ + pte_pa = (pde & PG_FRAME) + (pl1_pi(va) * sizeof(pt_entry_t)); + if (_kvm_pread(kd, kd->pmfd, (void *) &pte, sizeof(pte), + _kvm_pa2off(kd, pte_pa)) != sizeof(pte)) { + _kvm_syserr(kd, 0, "could not read PTE"); + goto lose; + } + /* + * Validate the PTE and return the physical address. + */ + if ((pte & PG_V) == 0) { + _kvm_err(kd, 0, "invalid translation (invalid PTE)"); + goto lose; + } + page_off = va & PGOFSET; + *pa = (pte & PG_FRAME) + page_off; + return (int)(NBPG - page_off); + + lose: + *pa = (u_long)~0L; + return (0); +} + +/* + * Translate a physical address to a file-offset in the crash dump. + */ +off_t +_kvm_pa2off(kvm_t *kd, paddr_t pa) +{ + cpu_kcore_hdr_t *cpu_kh; + phys_ram_seg_t *ramsegs; + off_t off; + int i; + + cpu_kh = kd->cpu_data; + ramsegs = (void *)((char *)(void *)cpu_kh + ALIGN(sizeof *cpu_kh)); + + off = 0; + for (i = 0; i < cpu_kh->nmemsegs; i++) { + if (pa >= ramsegs[i].start && + (pa - ramsegs[i].start) < ramsegs[i].size) { + off += (pa - ramsegs[i].start); + break; + } + off += ramsegs[i].size; + } + + return (kd->dump_off + off); +} + +/* + * Machine-dependent initialization for ALL open kvm descriptors, + * not just those for a kernel crash dump. Some architectures + * have to deal with these NOT being constants! (i.e. m68k) + */ +int +_kvm_mdopen(kvm_t *kd) +{ + + kd->usrstack = USRSTACK; + kd->min_uva = VM_MIN_ADDRESS; + kd->max_uva = VM_MAXUSER_ADDRESS; + + return (0); +} diff --git a/lib/libkvm/shlib_version b/lib/libkvm/shlib_version new file mode 100644 index 000000000..1ce12ce34 --- /dev/null +++ b/lib/libkvm/shlib_version @@ -0,0 +1,5 @@ +# $NetBSD: shlib_version,v 1.12 2009/01/11 03:07:48 christos Exp $ +# Remember to update distrib/sets/lists/base/shl.* when changing +# +major=6 +minor=0