kvm.c revision 147672
117683Spst/*- 239291Sfenner * Copyright (c) 1989, 1992, 1993 317683Spst * The Regents of the University of California. All rights reserved. 417683Spst * 517683Spst * This code is derived from software developed by the Computer Systems 617683Spst * Engineering group at Lawrence Berkeley Laboratory under DARPA contract 717683Spst * BG 91-66 and contributed to Berkeley. 817683Spst * 917683Spst * Redistribution and use in source and binary forms, with or without 1017683Spst * modification, are permitted provided that the following conditions 1117683Spst * are met: 1217683Spst * 1. Redistributions of source code must retain the above copyright 1317683Spst * notice, this list of conditions and the following disclaimer. 1417683Spst * 2. Redistributions in binary form must reproduce the above copyright 1517683Spst * notice, this list of conditions and the following disclaimer in the 1617683Spst * documentation and/or other materials provided with the distribution. 1717683Spst * 3. All advertising materials mentioning features or use of this software 1817683Spst * must display the following acknowledgement: 1917683Spst * This product includes software developed by the University of 20162020Ssam * California, Berkeley and its contributors. 21162020Ssam * 4. Neither the name of the University nor the names of its contributors 2217683Spst * may be used to endorse or promote products derived from this software 2317683Spst * without specific prior written permission. 24127664Sbms * 25172680Smlaier * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2617683Spst * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2717683Spst * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2875107Sfenner * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2975107Sfenner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3075107Sfenner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3175107Sfenner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3217683Spst * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33183102Scsjp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3417683Spst * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3517683Spst * SUCH DAMAGE. 3617683Spst */ 3717683Spst 3817683Spst#include <sys/cdefs.h> 39127664Sbms__FBSDID("$FreeBSD: head/lib/libkvm/kvm.c 147672 2005-06-29 22:39:41Z peter $"); 4017683Spst 4117683Spst#if defined(LIBC_SCCS) && !defined(lint) 42127664Sbms#if 0 4398530Sfennerstatic char sccsid[] = "@(#)kvm.c 8.2 (Berkeley) 2/13/94"; 44127664Sbms#endif 4598530Sfenner#endif /* LIBC_SCCS and not lint */ 46127664Sbms 47127664Sbms#include <sys/param.h> 4898530Sfenner#include <sys/user.h> 49127664Sbms#include <sys/proc.h> 50127664Sbms#include <sys/ioctl.h> 51127664Sbms#include <sys/stat.h> 52127664Sbms#include <sys/sysctl.h> 53127664Sbms#include <sys/linker.h> 54127664Sbms 55127664Sbms#include <vm/vm.h> 56127664Sbms#include <vm/vm_param.h> 57127664Sbms 58127664Sbms#include <machine/vmparam.h> 59127664Sbms 60127664Sbms#include <ctype.h> 61127664Sbms#include <fcntl.h> 6298530Sfenner#include <kvm.h> 63127664Sbms#include <limits.h> 64127664Sbms#include <nlist.h> 65147894Ssam#include <paths.h> 66127664Sbms#include <stdio.h> 6717683Spst#include <stdlib.h> 68127664Sbms#include <string.h> 69127664Sbms#include <unistd.h> 70127664Sbms 71127664Sbms#include "kvm_private.h" 72127664Sbms 73127664Sbms/* from src/lib/libc/gen/nlist.c */ 74127664Sbmsint __fdnlist(int, struct nlist *); 75127664Sbms 76127664Sbmschar * 77127664Sbmskvm_geterr(kd) 78127664Sbms kvm_t *kd; 79127664Sbms{ 80127664Sbms return (kd->errbuf); 81127664Sbms} 82127664Sbms 83127664Sbms#include <stdarg.h> 84127664Sbms 85127664Sbms/* 86127664Sbms * Report an error using printf style arguments. "program" is kd->program 87127664Sbms * on hard errors, and 0 on soft errors, so that under sun error emulation, 88127664Sbms * only hard errors are printed out (otherwise, programs like gdb will 89127664Sbms * generate tons of error messages when trying to access bogus pointers). 90183102Scsjp */ 91183102Scsjpvoid 92183102Scsjp_kvm_err(kvm_t *kd, const char *program, const char *fmt, ...) 93183102Scsjp{ 9417683Spst va_list ap; 9517683Spst 9617683Spst va_start(ap, fmt); 9717683Spst if (program != NULL) { 9817683Spst (void)fprintf(stderr, "%s: ", program); 9917683Spst (void)vfprintf(stderr, fmt, ap); 10017683Spst (void)fputc('\n', stderr); 10117683Spst } else 10217683Spst (void)vsnprintf(kd->errbuf, 10317683Spst sizeof(kd->errbuf), (char *)fmt, ap); 104127664Sbms 105127664Sbms va_end(ap); 106127664Sbms} 107127664Sbms 10817683Spstvoid 10917683Spst_kvm_syserr(kvm_t *kd, const char *program, const char *fmt, ...) 11017683Spst{ 11117683Spst va_list ap; 112127664Sbms int n; 11356889Sfenner 114127664Sbms va_start(ap, fmt); 115162012Ssam if (program != NULL) { 116127664Sbms (void)fprintf(stderr, "%s: ", program); 117127664Sbms (void)vfprintf(stderr, fmt, ap); 118127664Sbms (void)fprintf(stderr, ": %s\n", strerror(errno)); 119127664Sbms } else { 12017683Spst char *cp = kd->errbuf; 12117683Spst 12217683Spst (void)vsnprintf(cp, sizeof(kd->errbuf), (char *)fmt, ap); 12398530Sfenner n = strlen(cp); 12498530Sfenner (void)snprintf(&cp[n], sizeof(kd->errbuf) - n, ": %s", 12598530Sfenner strerror(errno)); 12698530Sfenner } 12798530Sfenner va_end(ap); 12898530Sfenner} 12998530Sfenner 13098530Sfennervoid * 13198530Sfenner_kvm_malloc(kd, n) 13298530Sfenner kvm_t *kd; 13398530Sfenner size_t n; 13498530Sfenner{ 13598530Sfenner void *p; 13617683Spst 13775107Sfenner if ((p = calloc(n, sizeof(char))) == NULL) 13875107Sfenner _kvm_err(kd, kd->program, "can't allocate %u bytes: %s", 13917683Spst n, strerror(errno)); 14017683Spst return (p); 14117683Spst} 14217683Spst 14317683Spststatic kvm_t * 14417683Spst_kvm_open(kd, uf, mf, flag, errout) 14517683Spst kvm_t *kd; 14617683Spst const char *uf; 147183102Scsjp const char *mf; 148183102Scsjp int flag; 149183102Scsjp char *errout; 150183102Scsjp{ 151183102Scsjp struct stat st; 152183102Scsjp 153183102Scsjp kd->vmfd = -1; 154183102Scsjp kd->pmfd = -1; 155183102Scsjp kd->nlfd = -1; 156183102Scsjp kd->vmst = 0; 157127664Sbms kd->procbase = 0; 158183102Scsjp kd->argspc = 0; 159183102Scsjp kd->argv = 0; 160183102Scsjp 161183102Scsjp if (uf == 0) 162183102Scsjp uf = getbootfile(); 163183102Scsjp else if (strlen(uf) >= MAXPATHLEN) { 164183102Scsjp _kvm_err(kd, kd->program, "exec file name too long"); 165183102Scsjp goto failed; 166183102Scsjp } 167183102Scsjp if (flag & ~O_RDWR) { 168183102Scsjp _kvm_err(kd, kd->program, "bad flags arg"); 169183102Scsjp goto failed; 170183102Scsjp } 171183102Scsjp if (mf == 0) 172183102Scsjp mf = _PATH_MEM; 173183102Scsjp 174183102Scsjp if ((kd->pmfd = open(mf, flag, 0)) < 0) { 175183102Scsjp _kvm_syserr(kd, kd->program, "%s", mf); 176183102Scsjp goto failed; 177183102Scsjp } 178183102Scsjp if (fstat(kd->pmfd, &st) < 0) { 179183102Scsjp _kvm_syserr(kd, kd->program, "%s", mf); 180183102Scsjp goto failed; 181183102Scsjp } 182183102Scsjp if (fcntl(kd->pmfd, F_SETFD, FD_CLOEXEC) < 0) { 183183102Scsjp _kvm_syserr(kd, kd->program, "%s", mf); 184183102Scsjp goto failed; 185183102Scsjp } 186183102Scsjp if (S_ISCHR(st.st_mode)) { 187183102Scsjp /* 188183102Scsjp * If this is a character special device, then check that 189183102Scsjp * it's /dev/mem. If so, open kmem too. (Maybe we should 190183102Scsjp * make it work for either /dev/mem or /dev/kmem -- in either 191183102Scsjp * case you're working with a live kernel.) 192183102Scsjp */ 193183102Scsjp if (strcmp(mf, _PATH_DEVNULL) == 0) { 194183102Scsjp kd->vmfd = open(_PATH_DEVNULL, O_RDONLY); 195183102Scsjp return (kd); 196183102Scsjp } else if (strcmp(mf, _PATH_MEM) == 0) { 197183102Scsjp if ((kd->vmfd = open(_PATH_KMEM, flag)) < 0) { 198183102Scsjp _kvm_syserr(kd, kd->program, "%s", _PATH_KMEM); 199183102Scsjp goto failed; 200183102Scsjp } 201183102Scsjp if (fcntl(kd->vmfd, F_SETFD, FD_CLOEXEC) < 0) { 202183102Scsjp _kvm_syserr(kd, kd->program, "%s", _PATH_KMEM); 203183102Scsjp goto failed; 204183102Scsjp } 205183102Scsjp return (kd); 206183102Scsjp } 207183102Scsjp } 208183102Scsjp /* 209183102Scsjp * This is a crash dump. 210183102Scsjp * Initialize the virtual address translation machinery, 211183102Scsjp * but first setup the namelist fd. 212183102Scsjp */ 213183102Scsjp if ((kd->nlfd = open(uf, O_RDONLY, 0)) < 0) { 214183102Scsjp _kvm_syserr(kd, kd->program, "%s", uf); 215183102Scsjp goto failed; 216183102Scsjp } 217183102Scsjp if (fcntl(kd->nlfd, F_SETFD, FD_CLOEXEC) < 0) { 218183102Scsjp _kvm_syserr(kd, kd->program, "%s", uf); 219183102Scsjp goto failed; 220183102Scsjp } 221183102Scsjp if (_kvm_initvtop(kd) < 0) 222183102Scsjp goto failed; 223183102Scsjp return (kd); 224183102Scsjpfailed: 225183102Scsjp /* 226183102Scsjp * Copy out the error if doing sane error semantics. 227183102Scsjp */ 228183102Scsjp if (errout != 0) 229183102Scsjp strlcpy(errout, kd->errbuf, _POSIX2_LINE_MAX); 230183102Scsjp (void)kvm_close(kd); 231183102Scsjp return (0); 232183102Scsjp} 233183102Scsjp 234183102Scsjpkvm_t * 235183102Scsjpkvm_openfiles(uf, mf, sf, flag, errout) 236183102Scsjp const char *uf; 237183102Scsjp const char *mf; 238183102Scsjp const char *sf __unused; 239183102Scsjp int flag; 240183102Scsjp char *errout; 241183102Scsjp{ 242183102Scsjp kvm_t *kd; 243183102Scsjp 244183102Scsjp if ((kd = malloc(sizeof(*kd))) == NULL) { 245183102Scsjp (void)strlcpy(errout, strerror(errno), _POSIX2_LINE_MAX); 246183102Scsjp return (0); 247183102Scsjp } 248183102Scsjp memset(kd, 0, sizeof(*kd)); 249183102Scsjp kd->program = 0; 250183102Scsjp return (_kvm_open(kd, uf, mf, flag, errout)); 251183102Scsjp} 252183102Scsjp 253183102Scsjpkvm_t * 254183102Scsjpkvm_open(uf, mf, sf, flag, errstr) 255183102Scsjp const char *uf; 256183102Scsjp const char *mf; 257183102Scsjp const char *sf __unused; 258183102Scsjp int flag; 259183102Scsjp const char *errstr; 260183102Scsjp{ 261183102Scsjp kvm_t *kd; 262183102Scsjp 263183102Scsjp if ((kd = malloc(sizeof(*kd))) == NULL) { 264183102Scsjp if (errstr != NULL) 265183102Scsjp (void)fprintf(stderr, "%s: %s\n", 266183102Scsjp errstr, strerror(errno)); 267183102Scsjp return (0); 268183102Scsjp } 269183102Scsjp memset(kd, 0, sizeof(*kd)); 270183102Scsjp kd->program = errstr; 271183102Scsjp return (_kvm_open(kd, uf, mf, flag, NULL)); 272183102Scsjp} 273183102Scsjp 274183102Scsjpint 275183102Scsjpkvm_close(kd) 276183102Scsjp kvm_t *kd; 277183102Scsjp{ 278183102Scsjp int error = 0; 279183102Scsjp 280183102Scsjp if (kd->pmfd >= 0) 281183102Scsjp error |= close(kd->pmfd); 282183102Scsjp if (kd->vmfd >= 0) 283183102Scsjp error |= close(kd->vmfd); 284183102Scsjp if (kd->nlfd >= 0) 285183102Scsjp error |= close(kd->nlfd); 286183102Scsjp if (kd->vmst) 287183102Scsjp _kvm_freevtop(kd); 288183102Scsjp if (kd->procbase != 0) 289183102Scsjp free((void *)kd->procbase); 290183102Scsjp if (kd->argv != 0) 291183102Scsjp free((void *)kd->argv); 292183102Scsjp free((void *)kd); 293183102Scsjp 294183102Scsjp return (0); 295183102Scsjp} 296183102Scsjp 297183102Scsjpint 298183102Scsjpkvm_nlist(kd, nl) 299183102Scsjp kvm_t *kd; 300183102Scsjp struct nlist *nl; 301127664Sbms{ 30217683Spst struct nlist *p; 30317683Spst int nvalid; 30417683Spst struct kld_sym_lookup lookup; 30517683Spst 306146768Ssam /* 307127664Sbms * If we can't use the kld symbol lookup, revert to the 308183102Scsjp * slow library call. 309183102Scsjp */ 310183102Scsjp if (!ISALIVE(kd)) 311146768Ssam return (__fdnlist(kd->nlfd, nl)); 312146768Ssam 313146768Ssam /* 31417683Spst * We can use the kld lookup syscall. Go through each nlist entry 315127664Sbms * and look it up with a kldsym(2) syscall. 31617683Spst */ 317127664Sbms nvalid = 0; 318127664Sbms for (p = nl; p->n_name && p->n_name[0]; ++p) { 319127664Sbms lookup.version = sizeof(lookup); 320127664Sbms lookup.symname = p->n_name; 321127664Sbms lookup.symvalue = 0; 322127664Sbms lookup.symsize = 0; 323127664Sbms 324127664Sbms if (lookup.symname[0] == '_') 325127664Sbms lookup.symname++; 326127664Sbms 327127664Sbms if (kldsym(0, KLDSYM_LOOKUP, &lookup) != -1) { 328127664Sbms p->n_type = N_TEXT; 32917683Spst p->n_other = 0; 33017683Spst p->n_desc = 0; 331183102Scsjp p->n_value = lookup.symvalue; 332183102Scsjp ++nvalid; 333183102Scsjp /* lookup.symsize */ 334183102Scsjp } 335183102Scsjp } 336183102Scsjp /* 337183102Scsjp * Return the number of entries that weren't found. 338183102Scsjp */ 339183102Scsjp return ((p - nl) - nvalid); 340183102Scsjp} 341183102Scsjp 342183102Scsjpssize_t 343183102Scsjpkvm_read(kd, kva, buf, len) 344183102Scsjp kvm_t *kd; 345183102Scsjp u_long kva; 346183102Scsjp void *buf; 347183102Scsjp size_t len; 348183102Scsjp{ 349183102Scsjp int cc; 350183102Scsjp char *cp; 351183102Scsjp 35217683Spst if (ISALIVE(kd)) { 35317683Spst /* 35417683Spst * We're using /dev/kmem. Just read straight from the 35517683Spst * device and let the active kernel do the address translation. 35617683Spst */ 35717683Spst errno = 0; 35817683Spst if (lseek(kd->vmfd, (off_t)kva, 0) == -1 && errno != 0) { 359127664Sbms _kvm_err(kd, 0, "invalid address (%x)", kva); 360127664Sbms return (-1); 361127664Sbms } 362127664Sbms cc = read(kd->vmfd, buf, len); 363127664Sbms if (cc < 0) { 364127664Sbms _kvm_syserr(kd, 0, "kvm_read"); 365127664Sbms return (-1); 366127664Sbms } else if (cc < len) 367127664Sbms _kvm_err(kd, kd->program, "short read"); 368127664Sbms return (cc); 369127664Sbms } else { 370127664Sbms cp = buf; 371127664Sbms while (len > 0) { 372127664Sbms off_t pa; 373127664Sbms 374127664Sbms cc = _kvm_kvatop(kd, kva, &pa); 375127664Sbms if (cc == 0) 376127664Sbms return (-1); 377127664Sbms if (cc > len) 378127664Sbms cc = len; 379127664Sbms errno = 0; 380127664Sbms if (lseek(kd->pmfd, pa, 0) == -1 && errno != 0) { 381127664Sbms _kvm_syserr(kd, 0, _PATH_MEM); 382127664Sbms break; 383127664Sbms } 384127664Sbms cc = read(kd->pmfd, cp, cc); 38517683Spst if (cc < 0) { 38617683Spst _kvm_syserr(kd, kd->program, "kvm_read"); 38717683Spst break; 38817683Spst } 38917683Spst /* 39017683Spst * If kvm_kvatop returns a bogus value or our core 39117683Spst * file is truncated, we might wind up seeking beyond 39217683Spst * the end of the core file in which case the read will 39317683Spst * return 0 (EOF). 39417683Spst */ 39517683Spst if (cc == 0) 39617683Spst break; 39717683Spst cp += cc; 39817683Spst kva += cc; 39917683Spst len -= cc; 40017683Spst } 40117683Spst return (cp - (char *)buf); 40275107Sfenner } 40375107Sfenner /* NOTREACHED */ 40417683Spst} 40517683Spst 40617683Spstssize_t 40717683Spstkvm_write(kd, kva, buf, len) 40817683Spst kvm_t *kd; 40917683Spst u_long kva; 41017683Spst const void *buf; 41117683Spst size_t len; 41217683Spst{ 41317683Spst int cc; 41417683Spst 415146768Ssam if (ISALIVE(kd)) { 416146768Ssam /* 417146768Ssam * Just like kvm_read, only we write. 41817683Spst */ 41917683Spst errno = 0; 420127664Sbms if (lseek(kd->vmfd, (off_t)kva, 0) == -1 && errno != 0) { 421127664Sbms _kvm_err(kd, 0, "invalid address (%x)", kva); 422127664Sbms return (-1); 423127664Sbms } 424127664Sbms cc = write(kd->vmfd, buf, len); 425127664Sbms if (cc < 0) { 426127664Sbms _kvm_syserr(kd, 0, "kvm_write"); 427127664Sbms return (-1); 428127664Sbms } else if (cc < len) 429127664Sbms _kvm_err(kd, kd->program, "short write"); 430127664Sbms return (cc); 431127664Sbms } else { 432127664Sbms _kvm_err(kd, kd->program, 433127664Sbms "kvm_write not implemented for dead kernels"); 434127664Sbms return (-1); 435127664Sbms } 436127664Sbms /* NOTREACHED */ 437127664Sbms} 438127664Sbms