| 1 | /* $NetBSD: kvm.c,v 1.104 2018/11/05 00:43:30 mrg Exp $ */ |
| 2 | |
| 3 | /*- |
| 4 | * Copyright (c) 1989, 1992, 1993 |
| 5 | * The Regents of the University of California. All rights reserved. |
| 6 | * |
| 7 | * This code is derived from software developed by the Computer Systems |
| 8 | * Engineering group at Lawrence Berkeley Laboratory under DARPA contract |
| 9 | * BG 91-66 and contributed to Berkeley. |
| 10 | * |
| 11 | * Redistribution and use in source and binary forms, with or without |
| 12 | * modification, are permitted provided that the following conditions |
| 13 | * are met: |
| 14 | * 1. Redistributions of source code must retain the above copyright |
| 15 | * notice, this list of conditions and the following disclaimer. |
| 16 | * 2. Redistributions in binary form must reproduce the above copyright |
| 17 | * notice, this list of conditions and the following disclaimer in the |
| 18 | * documentation and/or other materials provided with the distribution. |
| 19 | * 3. Neither the name of the University nor the names of its contributors |
| 20 | * may be used to endorse or promote products derived from this software |
| 21 | * without specific prior written permission. |
| 22 | * |
| 23 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
| 24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 25 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 26 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
| 27 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| 28 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| 29 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| 30 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| 31 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| 32 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| 33 | * SUCH DAMAGE. |
| 34 | */ |
| 35 | |
| 36 | #include <sys/cdefs.h> |
| 37 | #if defined(LIBC_SCCS) && !defined(lint) |
| 38 | #if 0 |
| 39 | static char sccsid[] = "@(#)kvm.c 8.2 (Berkeley) 2/13/94" ; |
| 40 | #else |
| 41 | __RCSID("$NetBSD: kvm.c,v 1.104 2018/11/05 00:43:30 mrg Exp $" ); |
| 42 | #endif |
| 43 | #endif /* LIBC_SCCS and not lint */ |
| 44 | |
| 45 | #include <sys/param.h> |
| 46 | #include <sys/lwp.h> |
| 47 | #include <sys/proc.h> |
| 48 | #include <sys/ioctl.h> |
| 49 | #include <sys/stat.h> |
| 50 | #include <sys/sysctl.h> |
| 51 | |
| 52 | #include <sys/core.h> |
| 53 | #include <sys/exec.h> |
| 54 | #include <sys/kcore.h> |
| 55 | #include <sys/ksyms.h> |
| 56 | #include <sys/types.h> |
| 57 | |
| 58 | #include <uvm/uvm_extern.h> |
| 59 | |
| 60 | #include <machine/cpu.h> |
| 61 | |
| 62 | #include <ctype.h> |
| 63 | #include <errno.h> |
| 64 | #include <fcntl.h> |
| 65 | #include <limits.h> |
| 66 | #include <nlist.h> |
| 67 | #include <paths.h> |
| 68 | #include <stdarg.h> |
| 69 | #include <stdio.h> |
| 70 | #include <stdlib.h> |
| 71 | #include <string.h> |
| 72 | #include <unistd.h> |
| 73 | #include <kvm.h> |
| 74 | |
| 75 | #include "kvm_private.h" |
| 76 | |
| 77 | static int _kvm_get_header(kvm_t *); |
| 78 | static kvm_t *_kvm_open(kvm_t *, const char *, const char *, |
| 79 | const char *, int, char *); |
| 80 | static int clear_gap(kvm_t *, bool (*)(void *, const void *, size_t), |
| 81 | void *, size_t); |
| 82 | static off_t Lseek(kvm_t *, int, off_t, int); |
| 83 | static ssize_t Pread(kvm_t *, int, void *, size_t, off_t); |
| 84 | |
| 85 | char * |
| 86 | kvm_geterr(kvm_t *kd) |
| 87 | { |
| 88 | return (kd->errbuf); |
| 89 | } |
| 90 | |
| 91 | const char * |
| 92 | kvm_getkernelname(kvm_t *kd) |
| 93 | { |
| 94 | return kd->kernelname; |
| 95 | } |
| 96 | |
| 97 | /* |
| 98 | * Report an error using printf style arguments. "program" is kd->program |
| 99 | * on hard errors, and 0 on soft errors, so that under sun error emulation, |
| 100 | * only hard errors are printed out (otherwise, programs like gdb will |
| 101 | * generate tons of error messages when trying to access bogus pointers). |
| 102 | */ |
| 103 | void |
| 104 | _kvm_err(kvm_t *kd, const char *program, const char *fmt, ...) |
| 105 | { |
| 106 | va_list ap; |
| 107 | |
| 108 | va_start(ap, fmt); |
| 109 | if (program != NULL) { |
| 110 | (void)fprintf(stderr, "%s: " , program); |
| 111 | (void)vfprintf(stderr, fmt, ap); |
| 112 | (void)fputc('\n', stderr); |
| 113 | } else |
| 114 | (void)vsnprintf(kd->errbuf, |
| 115 | sizeof(kd->errbuf), fmt, ap); |
| 116 | |
| 117 | va_end(ap); |
| 118 | } |
| 119 | |
| 120 | void |
| 121 | _kvm_syserr(kvm_t *kd, const char *program, const char *fmt, ...) |
| 122 | { |
| 123 | va_list ap; |
| 124 | size_t n; |
| 125 | |
| 126 | va_start(ap, fmt); |
| 127 | if (program != NULL) { |
| 128 | (void)fprintf(stderr, "%s: " , program); |
| 129 | (void)vfprintf(stderr, fmt, ap); |
| 130 | (void)fprintf(stderr, ": %s\n" , strerror(errno)); |
| 131 | } else { |
| 132 | char *cp = kd->errbuf; |
| 133 | |
| 134 | (void)vsnprintf(cp, sizeof(kd->errbuf), fmt, ap); |
| 135 | n = strlen(cp); |
| 136 | (void)snprintf(&cp[n], sizeof(kd->errbuf) - n, ": %s" , |
| 137 | strerror(errno)); |
| 138 | } |
| 139 | va_end(ap); |
| 140 | } |
| 141 | |
| 142 | void * |
| 143 | _kvm_malloc(kvm_t *kd, size_t n) |
| 144 | { |
| 145 | void *p; |
| 146 | |
| 147 | if ((p = malloc(n)) == NULL) |
| 148 | _kvm_err(kd, kd->program, "%s" , strerror(errno)); |
| 149 | return (p); |
| 150 | } |
| 151 | |
| 152 | /* |
| 153 | * Wrapper around the lseek(2) system call; calls _kvm_syserr() for us |
| 154 | * in the event of emergency. |
| 155 | */ |
| 156 | static off_t |
| 157 | Lseek(kvm_t *kd, int fd, off_t offset, int whence) |
| 158 | { |
| 159 | off_t off; |
| 160 | |
| 161 | errno = 0; |
| 162 | |
| 163 | if ((off = lseek(fd, offset, whence)) == -1 && errno != 0) { |
| 164 | _kvm_syserr(kd, kd->program, "Lseek" ); |
| 165 | return ((off_t)-1); |
| 166 | } |
| 167 | return (off); |
| 168 | } |
| 169 | |
| 170 | ssize_t |
| 171 | _kvm_pread(kvm_t *kd, int fd, void *buf, size_t size, off_t off) |
| 172 | { |
| 173 | ptrdiff_t moff; |
| 174 | void *newbuf; |
| 175 | size_t dsize; |
| 176 | ssize_t rv; |
| 177 | off_t doff; |
| 178 | |
| 179 | /* If aligned nothing to do. */ |
| 180 | if (((off % kd->fdalign) | (size % kd->fdalign)) == 0) { |
| 181 | return pread(fd, buf, size, off); |
| 182 | } |
| 183 | |
| 184 | /* |
| 185 | * Otherwise must buffer. We can't tolerate short reads in this |
| 186 | * case (lazy bum). |
| 187 | */ |
| 188 | moff = (ptrdiff_t)off % kd->fdalign; |
| 189 | doff = off - moff; |
| 190 | dsize = moff + size + kd->fdalign - 1; |
| 191 | dsize -= dsize % kd->fdalign; |
| 192 | if (kd->iobufsz < dsize) { |
| 193 | newbuf = realloc(kd->iobuf, dsize); |
| 194 | if (newbuf == NULL) { |
| 195 | _kvm_syserr(kd, 0, "cannot allocate I/O buffer" ); |
| 196 | return (-1); |
| 197 | } |
| 198 | kd->iobuf = newbuf; |
| 199 | kd->iobufsz = dsize; |
| 200 | } |
| 201 | rv = pread(fd, kd->iobuf, dsize, doff); |
| 202 | if (rv < size + moff) |
| 203 | return -1; |
| 204 | memcpy(buf, kd->iobuf + moff, size); |
| 205 | return size; |
| 206 | } |
| 207 | |
| 208 | /* |
| 209 | * Wrapper around the pread(2) system call; calls _kvm_syserr() for us |
| 210 | * in the event of emergency. |
| 211 | */ |
| 212 | static ssize_t |
| 213 | Pread(kvm_t *kd, int fd, void *buf, size_t nbytes, off_t offset) |
| 214 | { |
| 215 | ssize_t rv; |
| 216 | |
| 217 | errno = 0; |
| 218 | |
| 219 | if ((rv = _kvm_pread(kd, fd, buf, nbytes, offset)) != nbytes && |
| 220 | errno != 0) |
| 221 | _kvm_syserr(kd, kd->program, "Pread" ); |
| 222 | return (rv); |
| 223 | } |
| 224 | |
| 225 | static kvm_t * |
| 226 | _kvm_open(kvm_t *kd, const char *uf, const char *mf, const char *sf, int flag, |
| 227 | char *errout) |
| 228 | { |
| 229 | struct stat st; |
| 230 | int ufgiven; |
| 231 | |
| 232 | kd->pmfd = -1; |
| 233 | kd->vmfd = -1; |
| 234 | kd->swfd = -1; |
| 235 | kd->nlfd = -1; |
| 236 | kd->alive = KVM_ALIVE_DEAD; |
| 237 | kd->procbase = NULL; |
| 238 | kd->procbase_len = 0; |
| 239 | kd->procbase2 = NULL; |
| 240 | kd->procbase2_len = 0; |
| 241 | kd->lwpbase = NULL; |
| 242 | kd->lwpbase_len = 0; |
| 243 | kd->nbpg = getpagesize(); |
| 244 | kd->swapspc = NULL; |
| 245 | kd->argspc = NULL; |
| 246 | kd->argspc_len = 0; |
| 247 | kd->argbuf = NULL; |
| 248 | kd->argv = NULL; |
| 249 | kd->vmst = NULL; |
| 250 | kd->vm_page_buckets = NULL; |
| 251 | kd->kcore_hdr = NULL; |
| 252 | kd->cpu_dsize = 0; |
| 253 | kd->cpu_data = NULL; |
| 254 | kd->dump_off = 0; |
| 255 | kd->fdalign = 1; |
| 256 | kd->iobuf = NULL; |
| 257 | kd->iobufsz = 0; |
| 258 | kd->errbuf[0] = '\0'; |
| 259 | |
| 260 | if (flag & KVM_NO_FILES) { |
| 261 | kd->alive = KVM_ALIVE_SYSCTL; |
| 262 | return(kd); |
| 263 | } |
| 264 | |
| 265 | /* |
| 266 | * Call the MD open hook. This sets: |
| 267 | * usrstack, min_uva, max_uva |
| 268 | */ |
| 269 | if (_kvm_mdopen(kd)) { |
| 270 | _kvm_err(kd, kd->program, "md init failed" ); |
| 271 | goto failed; |
| 272 | } |
| 273 | |
| 274 | ufgiven = (uf != NULL); |
| 275 | if (!ufgiven) { |
| 276 | #ifdef CPU_BOOTED_KERNEL |
| 277 | /* 130 is 128 + '/' + '\0' */ |
| 278 | static char booted_kernel[130]; |
| 279 | int mib[2], rc; |
| 280 | size_t len; |
| 281 | |
| 282 | mib[0] = CTL_MACHDEP; |
| 283 | mib[1] = CPU_BOOTED_KERNEL; |
| 284 | booted_kernel[0] = '/'; |
| 285 | booted_kernel[1] = '\0'; |
| 286 | len = sizeof(booted_kernel) - 2; |
| 287 | rc = sysctl(&mib[0], 2, &booted_kernel[1], &len, NULL, 0); |
| 288 | booted_kernel[sizeof(booted_kernel) - 1] = '\0'; |
| 289 | uf = (booted_kernel[1] == '/') ? |
| 290 | &booted_kernel[1] : &booted_kernel[0]; |
| 291 | if (rc != -1) |
| 292 | rc = stat(uf, &st); |
| 293 | if (rc != -1 && !S_ISREG(st.st_mode)) |
| 294 | rc = -1; |
| 295 | if (rc == -1) |
| 296 | #endif /* CPU_BOOTED_KERNEL */ |
| 297 | uf = _PATH_UNIX; |
| 298 | } |
| 299 | else if (strlen(uf) >= MAXPATHLEN) { |
| 300 | _kvm_err(kd, kd->program, "exec file name too long" ); |
| 301 | goto failed; |
| 302 | } |
| 303 | if (flag & ~O_RDWR) { |
| 304 | _kvm_err(kd, kd->program, "bad flags arg" ); |
| 305 | goto failed; |
| 306 | } |
| 307 | if (mf == 0) |
| 308 | mf = _PATH_MEM; |
| 309 | if (sf == 0) |
| 310 | sf = _PATH_DRUM; |
| 311 | |
| 312 | /* |
| 313 | * Open the kernel namelist. If /dev/ksyms doesn't |
| 314 | * exist, open the current kernel. |
| 315 | */ |
| 316 | if (ufgiven == 0) |
| 317 | kd->nlfd = open(_PATH_KSYMS, O_RDONLY | O_CLOEXEC, 0); |
| 318 | if (kd->nlfd < 0) { |
| 319 | if ((kd->nlfd = open(uf, O_RDONLY | O_CLOEXEC, 0)) < 0) { |
| 320 | _kvm_syserr(kd, kd->program, "%s" , uf); |
| 321 | goto failed; |
| 322 | } |
| 323 | strlcpy(kd->kernelname, uf, sizeof(kd->kernelname)); |
| 324 | } else { |
| 325 | strlcpy(kd->kernelname, _PATH_KSYMS, sizeof(kd->kernelname)); |
| 326 | } |
| 327 | |
| 328 | if ((kd->pmfd = open(mf, flag | O_CLOEXEC, 0)) < 0) { |
| 329 | _kvm_syserr(kd, kd->program, "%s" , mf); |
| 330 | goto failed; |
| 331 | } |
| 332 | if (fstat(kd->pmfd, &st) < 0) { |
| 333 | _kvm_syserr(kd, kd->program, "%s" , mf); |
| 334 | goto failed; |
| 335 | } |
| 336 | if (S_ISCHR(st.st_mode) && strcmp(mf, _PATH_MEM) == 0) { |
| 337 | /* |
| 338 | * If this is /dev/mem, open kmem too. (Maybe we should |
| 339 | * make it work for either /dev/mem or /dev/kmem -- in either |
| 340 | * case you're working with a live kernel.) |
| 341 | */ |
| 342 | if ((kd->vmfd = open(_PATH_KMEM, flag | O_CLOEXEC, 0)) < 0) { |
| 343 | _kvm_syserr(kd, kd->program, "%s" , _PATH_KMEM); |
| 344 | goto failed; |
| 345 | } |
| 346 | kd->alive = KVM_ALIVE_FILES; |
| 347 | if ((kd->swfd = open(sf, flag | O_CLOEXEC, 0)) < 0) { |
| 348 | if (errno != ENXIO) { |
| 349 | _kvm_syserr(kd, kd->program, "%s" , sf); |
| 350 | goto failed; |
| 351 | } |
| 352 | /* swap is not configured? not fatal */ |
| 353 | } |
| 354 | } else { |
| 355 | kd->fdalign = DEV_BSIZE; /* XXX */ |
| 356 | /* |
| 357 | * This is a crash dump. |
| 358 | * Initialize the virtual address translation machinery. |
| 359 | * |
| 360 | * If there is no valid core header, fail silently here. |
| 361 | * The address translations however will fail without |
| 362 | * header. Things can be made to run by calling |
| 363 | * kvm_dump_mkheader() before doing any translation. |
| 364 | */ |
| 365 | if (_kvm_get_header(kd) == 0) { |
| 366 | if (_kvm_initvtop(kd) < 0) |
| 367 | goto failed; |
| 368 | } |
| 369 | } |
| 370 | return (kd); |
| 371 | failed: |
| 372 | /* |
| 373 | * Copy out the error if doing sane error semantics. |
| 374 | */ |
| 375 | if (errout != 0) |
| 376 | (void)strlcpy(errout, kd->errbuf, _POSIX2_LINE_MAX); |
| 377 | (void)kvm_close(kd); |
| 378 | return (0); |
| 379 | } |
| 380 | |
| 381 | /* |
| 382 | * The kernel dump file (from savecore) contains: |
| 383 | * kcore_hdr_t kcore_hdr; |
| 384 | * kcore_seg_t cpu_hdr; |
| 385 | * (opaque) cpu_data; (size is cpu_hdr.c_size) |
| 386 | * kcore_seg_t mem_hdr; |
| 387 | * (memory) mem_data; (size is mem_hdr.c_size) |
| 388 | * |
| 389 | * Note: khdr is padded to khdr.c_hdrsize; |
| 390 | * cpu_hdr and mem_hdr are padded to khdr.c_seghdrsize |
| 391 | */ |
| 392 | static int |
| 393 | (kvm_t *kd) |
| 394 | { |
| 395 | kcore_hdr_t kcore_hdr; |
| 396 | kcore_seg_t cpu_hdr; |
| 397 | kcore_seg_t mem_hdr; |
| 398 | size_t offset; |
| 399 | ssize_t sz; |
| 400 | |
| 401 | /* |
| 402 | * Read the kcore_hdr_t |
| 403 | */ |
| 404 | sz = Pread(kd, kd->pmfd, &kcore_hdr, sizeof(kcore_hdr), (off_t)0); |
| 405 | if (sz != sizeof(kcore_hdr)) |
| 406 | return (-1); |
| 407 | |
| 408 | /* |
| 409 | * Currently, we only support dump-files made by the current |
| 410 | * architecture... |
| 411 | */ |
| 412 | if ((CORE_GETMAGIC(kcore_hdr) != KCORE_MAGIC) || |
| 413 | (CORE_GETMID(kcore_hdr) != MID_MACHINE)) |
| 414 | return (-1); |
| 415 | |
| 416 | /* |
| 417 | * Currently, we only support exactly 2 segments: cpu-segment |
| 418 | * and data-segment in exactly that order. |
| 419 | */ |
| 420 | if (kcore_hdr.c_nseg != 2) |
| 421 | return (-1); |
| 422 | |
| 423 | /* |
| 424 | * Save away the kcore_hdr. All errors after this |
| 425 | * should do a to "goto fail" to deallocate things. |
| 426 | */ |
| 427 | kd->kcore_hdr = _kvm_malloc(kd, sizeof(kcore_hdr)); |
| 428 | memcpy(kd->kcore_hdr, &kcore_hdr, sizeof(kcore_hdr)); |
| 429 | offset = kcore_hdr.c_hdrsize; |
| 430 | |
| 431 | /* |
| 432 | * Read the CPU segment header |
| 433 | */ |
| 434 | sz = Pread(kd, kd->pmfd, &cpu_hdr, sizeof(cpu_hdr), (off_t)offset); |
| 435 | if (sz != sizeof(cpu_hdr)) |
| 436 | goto fail; |
| 437 | if ((CORE_GETMAGIC(cpu_hdr) != KCORESEG_MAGIC) || |
| 438 | (CORE_GETFLAG(cpu_hdr) != CORE_CPU)) |
| 439 | goto fail; |
| 440 | offset += kcore_hdr.c_seghdrsize; |
| 441 | |
| 442 | /* |
| 443 | * Read the CPU segment DATA. |
| 444 | */ |
| 445 | kd->cpu_dsize = cpu_hdr.c_size; |
| 446 | kd->cpu_data = _kvm_malloc(kd, cpu_hdr.c_size); |
| 447 | if (kd->cpu_data == NULL) |
| 448 | goto fail; |
| 449 | sz = Pread(kd, kd->pmfd, kd->cpu_data, cpu_hdr.c_size, (off_t)offset); |
| 450 | if (sz != cpu_hdr.c_size) |
| 451 | goto fail; |
| 452 | offset += cpu_hdr.c_size; |
| 453 | |
| 454 | /* |
| 455 | * Read the next segment header: data segment |
| 456 | */ |
| 457 | sz = Pread(kd, kd->pmfd, &mem_hdr, sizeof(mem_hdr), (off_t)offset); |
| 458 | if (sz != sizeof(mem_hdr)) |
| 459 | goto fail; |
| 460 | offset += kcore_hdr.c_seghdrsize; |
| 461 | |
| 462 | if ((CORE_GETMAGIC(mem_hdr) != KCORESEG_MAGIC) || |
| 463 | (CORE_GETFLAG(mem_hdr) != CORE_DATA)) |
| 464 | goto fail; |
| 465 | |
| 466 | kd->dump_off = offset; |
| 467 | return (0); |
| 468 | |
| 469 | fail: |
| 470 | if (kd->kcore_hdr != NULL) { |
| 471 | free(kd->kcore_hdr); |
| 472 | kd->kcore_hdr = NULL; |
| 473 | } |
| 474 | if (kd->cpu_data != NULL) { |
| 475 | free(kd->cpu_data); |
| 476 | kd->cpu_data = NULL; |
| 477 | kd->cpu_dsize = 0; |
| 478 | } |
| 479 | return (-1); |
| 480 | } |
| 481 | |
| 482 | /* |
| 483 | * The format while on the dump device is: (new format) |
| 484 | * kcore_seg_t cpu_hdr; |
| 485 | * (opaque) cpu_data; (size is cpu_hdr.c_size) |
| 486 | * kcore_seg_t mem_hdr; |
| 487 | * (memory) mem_data; (size is mem_hdr.c_size) |
| 488 | */ |
| 489 | int |
| 490 | (kvm_t *kd, off_t dump_off) |
| 491 | { |
| 492 | kcore_seg_t cpu_hdr; |
| 493 | size_t hdr_size; |
| 494 | ssize_t sz; |
| 495 | |
| 496 | if (kd->kcore_hdr != NULL) { |
| 497 | _kvm_err(kd, kd->program, "already has a dump header" ); |
| 498 | return (-1); |
| 499 | } |
| 500 | if (ISALIVE(kd)) { |
| 501 | _kvm_err(kd, kd->program, "don't use on live kernel" ); |
| 502 | return (-1); |
| 503 | } |
| 504 | |
| 505 | /* |
| 506 | * Validate new format crash dump |
| 507 | */ |
| 508 | sz = Pread(kd, kd->pmfd, &cpu_hdr, sizeof(cpu_hdr), dump_off); |
| 509 | if (sz != sizeof(cpu_hdr)) { |
| 510 | if (sz == -1) |
| 511 | _kvm_err(kd, 0, "read %zx bytes at offset %" PRIx64 |
| 512 | " for cpu_hdr failed: %s" , sizeof(cpu_hdr), |
| 513 | dump_off, strerror(errno)); |
| 514 | else |
| 515 | _kvm_err(kd, 0, "read %zx bytes at offset %" PRIx64 |
| 516 | " for cpu_hdr instead of requested %zu" , |
| 517 | sz, dump_off, sizeof(cpu_hdr)); |
| 518 | return (-1); |
| 519 | } |
| 520 | if ((CORE_GETMAGIC(cpu_hdr) != KCORE_MAGIC) |
| 521 | || (CORE_GETMID(cpu_hdr) != MID_MACHINE)) { |
| 522 | _kvm_err(kd, 0, "invalid magic in cpu_hdr" ); |
| 523 | return (0); |
| 524 | } |
| 525 | hdr_size = ALIGN(sizeof(cpu_hdr)); |
| 526 | |
| 527 | /* |
| 528 | * Read the CPU segment. |
| 529 | */ |
| 530 | kd->cpu_dsize = cpu_hdr.c_size; |
| 531 | kd->cpu_data = _kvm_malloc(kd, kd->cpu_dsize); |
| 532 | if (kd->cpu_data == NULL) { |
| 533 | _kvm_err(kd, kd->program, "no cpu_data" ); |
| 534 | goto fail; |
| 535 | } |
| 536 | sz = Pread(kd, kd->pmfd, kd->cpu_data, cpu_hdr.c_size, |
| 537 | dump_off + hdr_size); |
| 538 | if (sz != cpu_hdr.c_size) { |
| 539 | _kvm_err(kd, kd->program, "size %zu != cpu_hdr.csize %" PRIu32, |
| 540 | sz, cpu_hdr.c_size); |
| 541 | goto fail; |
| 542 | } |
| 543 | hdr_size += kd->cpu_dsize; |
| 544 | |
| 545 | /* |
| 546 | * Leave phys mem pointer at beginning of memory data |
| 547 | */ |
| 548 | kd->dump_off = dump_off + hdr_size; |
| 549 | if (Lseek(kd, kd->pmfd, kd->dump_off, SEEK_SET) == -1) { |
| 550 | _kvm_err(kd, kd->program, "failed to seek to %" PRId64, |
| 551 | (int64_t)kd->dump_off); |
| 552 | goto fail; |
| 553 | } |
| 554 | |
| 555 | /* |
| 556 | * Create a kcore_hdr. |
| 557 | */ |
| 558 | kd->kcore_hdr = _kvm_malloc(kd, sizeof(kcore_hdr_t)); |
| 559 | if (kd->kcore_hdr == NULL) { |
| 560 | _kvm_err(kd, kd->program, "failed to allocate header" ); |
| 561 | goto fail; |
| 562 | } |
| 563 | |
| 564 | kd->kcore_hdr->c_hdrsize = ALIGN(sizeof(kcore_hdr_t)); |
| 565 | kd->kcore_hdr->c_seghdrsize = ALIGN(sizeof(kcore_seg_t)); |
| 566 | kd->kcore_hdr->c_nseg = 2; |
| 567 | CORE_SETMAGIC(*(kd->kcore_hdr), KCORE_MAGIC, MID_MACHINE,0); |
| 568 | |
| 569 | /* |
| 570 | * Now that we have a valid header, enable translations. |
| 571 | */ |
| 572 | if (_kvm_initvtop(kd) == 0) |
| 573 | /* Success */ |
| 574 | return (hdr_size); |
| 575 | |
| 576 | fail: |
| 577 | if (kd->kcore_hdr != NULL) { |
| 578 | free(kd->kcore_hdr); |
| 579 | kd->kcore_hdr = NULL; |
| 580 | } |
| 581 | if (kd->cpu_data != NULL) { |
| 582 | free(kd->cpu_data); |
| 583 | kd->cpu_data = NULL; |
| 584 | kd->cpu_dsize = 0; |
| 585 | } |
| 586 | return (-1); |
| 587 | } |
| 588 | |
| 589 | static int |
| 590 | clear_gap(kvm_t *kd, bool (*write_buf)(void *, const void *, size_t), |
| 591 | void *cookie, size_t size) |
| 592 | { |
| 593 | char buf[1024]; |
| 594 | size_t len; |
| 595 | |
| 596 | (void)memset(buf, 0, size > sizeof(buf) ? sizeof(buf) : size); |
| 597 | |
| 598 | while (size > 0) { |
| 599 | len = size > sizeof(buf) ? sizeof(buf) : size; |
| 600 | if (!(*write_buf)(cookie, buf, len)) { |
| 601 | _kvm_syserr(kd, kd->program, "clear_gap" ); |
| 602 | return -1; |
| 603 | } |
| 604 | size -= len; |
| 605 | } |
| 606 | |
| 607 | return 0; |
| 608 | } |
| 609 | |
| 610 | /* |
| 611 | * Write the dump header by calling write_buf with cookie as first argument. |
| 612 | */ |
| 613 | int |
| 614 | (kvm_t *kd, bool (*write_buf)(void *, const void *, size_t), |
| 615 | void *cookie, int dumpsize) |
| 616 | { |
| 617 | kcore_seg_t seghdr; |
| 618 | long offset; |
| 619 | size_t gap; |
| 620 | |
| 621 | if (kd->kcore_hdr == NULL || kd->cpu_data == NULL) { |
| 622 | _kvm_err(kd, kd->program, "no valid dump header(s)" ); |
| 623 | return (-1); |
| 624 | } |
| 625 | |
| 626 | /* |
| 627 | * Write the generic header |
| 628 | */ |
| 629 | offset = 0; |
| 630 | if (!(*write_buf)(cookie, kd->kcore_hdr, sizeof(kcore_hdr_t))) { |
| 631 | _kvm_syserr(kd, kd->program, "kvm_dump_header" ); |
| 632 | return (-1); |
| 633 | } |
| 634 | offset += kd->kcore_hdr->c_hdrsize; |
| 635 | gap = kd->kcore_hdr->c_hdrsize - sizeof(kcore_hdr_t); |
| 636 | if (clear_gap(kd, write_buf, cookie, gap) == -1) |
| 637 | return (-1); |
| 638 | |
| 639 | /* |
| 640 | * Write the CPU header |
| 641 | */ |
| 642 | CORE_SETMAGIC(seghdr, KCORESEG_MAGIC, 0, CORE_CPU); |
| 643 | seghdr.c_size = ALIGN(kd->cpu_dsize); |
| 644 | if (!(*write_buf)(cookie, &seghdr, sizeof(seghdr))) { |
| 645 | _kvm_syserr(kd, kd->program, "kvm_dump_header" ); |
| 646 | return (-1); |
| 647 | } |
| 648 | offset += kd->kcore_hdr->c_seghdrsize; |
| 649 | gap = kd->kcore_hdr->c_seghdrsize - sizeof(seghdr); |
| 650 | if (clear_gap(kd, write_buf, cookie, gap) == -1) |
| 651 | return (-1); |
| 652 | |
| 653 | if (!(*write_buf)(cookie, kd->cpu_data, kd->cpu_dsize)) { |
| 654 | _kvm_syserr(kd, kd->program, "kvm_dump_header" ); |
| 655 | return (-1); |
| 656 | } |
| 657 | offset += seghdr.c_size; |
| 658 | gap = seghdr.c_size - kd->cpu_dsize; |
| 659 | if (clear_gap(kd, write_buf, cookie, gap) == -1) |
| 660 | return (-1); |
| 661 | |
| 662 | /* |
| 663 | * Write the actual dump data segment header |
| 664 | */ |
| 665 | CORE_SETMAGIC(seghdr, KCORESEG_MAGIC, 0, CORE_DATA); |
| 666 | seghdr.c_size = dumpsize; |
| 667 | if (!(*write_buf)(cookie, &seghdr, sizeof(seghdr))) { |
| 668 | _kvm_syserr(kd, kd->program, "kvm_dump_header" ); |
| 669 | return (-1); |
| 670 | } |
| 671 | offset += kd->kcore_hdr->c_seghdrsize; |
| 672 | gap = kd->kcore_hdr->c_seghdrsize - sizeof(seghdr); |
| 673 | if (clear_gap(kd, write_buf, cookie, gap) == -1) |
| 674 | return (-1); |
| 675 | |
| 676 | return (int)offset; |
| 677 | } |
| 678 | |
| 679 | static bool |
| 680 | (void *cookie, const void *buf, size_t len) |
| 681 | { |
| 682 | return fwrite(buf, len, 1, (FILE *)cookie) == 1; |
| 683 | } |
| 684 | |
| 685 | int |
| 686 | (kvm_t *kd, FILE *fp, int dumpsize) |
| 687 | { |
| 688 | return kvm_dump_header(kd, kvm_dump_header_stdio, fp, dumpsize); |
| 689 | } |
| 690 | |
| 691 | kvm_t * |
| 692 | kvm_openfiles(const char *uf, const char *mf, const char *sf, |
| 693 | int flag, char *errout) |
| 694 | { |
| 695 | kvm_t *kd; |
| 696 | |
| 697 | if ((kd = malloc(sizeof(*kd))) == NULL) { |
| 698 | (void)strlcpy(errout, strerror(errno), _POSIX2_LINE_MAX); |
| 699 | return (0); |
| 700 | } |
| 701 | kd->program = 0; |
| 702 | return (_kvm_open(kd, uf, mf, sf, flag, errout)); |
| 703 | } |
| 704 | |
| 705 | kvm_t * |
| 706 | kvm_open(const char *uf, const char *mf, const char *sf, int flag, |
| 707 | const char *program) |
| 708 | { |
| 709 | kvm_t *kd; |
| 710 | |
| 711 | if ((kd = malloc(sizeof(*kd))) == NULL) { |
| 712 | (void)fprintf(stderr, "%s: %s\n" , |
| 713 | program ? program : getprogname(), strerror(errno)); |
| 714 | return (0); |
| 715 | } |
| 716 | kd->program = program; |
| 717 | return (_kvm_open(kd, uf, mf, sf, flag, NULL)); |
| 718 | } |
| 719 | |
| 720 | int |
| 721 | kvm_close(kvm_t *kd) |
| 722 | { |
| 723 | int error = 0; |
| 724 | |
| 725 | if (kd->pmfd >= 0) |
| 726 | error |= close(kd->pmfd); |
| 727 | if (kd->vmfd >= 0) |
| 728 | error |= close(kd->vmfd); |
| 729 | if (kd->nlfd >= 0) |
| 730 | error |= close(kd->nlfd); |
| 731 | if (kd->swfd >= 0) |
| 732 | error |= close(kd->swfd); |
| 733 | if (kd->vmst) |
| 734 | _kvm_freevtop(kd); |
| 735 | kd->cpu_dsize = 0; |
| 736 | if (kd->cpu_data != NULL) |
| 737 | free(kd->cpu_data); |
| 738 | if (kd->kcore_hdr != NULL) |
| 739 | free(kd->kcore_hdr); |
| 740 | if (kd->procbase != 0) |
| 741 | free(kd->procbase); |
| 742 | if (kd->procbase2 != 0) |
| 743 | free(kd->procbase2); |
| 744 | if (kd->lwpbase != 0) |
| 745 | free(kd->lwpbase); |
| 746 | if (kd->swapspc != 0) |
| 747 | free(kd->swapspc); |
| 748 | if (kd->argspc != 0) |
| 749 | free(kd->argspc); |
| 750 | if (kd->argbuf != 0) |
| 751 | free(kd->argbuf); |
| 752 | if (kd->argv != 0) |
| 753 | free(kd->argv); |
| 754 | if (kd->iobuf != 0) |
| 755 | free(kd->iobuf); |
| 756 | free(kd); |
| 757 | |
| 758 | return (error); |
| 759 | } |
| 760 | |
| 761 | int |
| 762 | kvm_nlist(kvm_t *kd, struct nlist *nl) |
| 763 | { |
| 764 | int rv; |
| 765 | |
| 766 | /* |
| 767 | * Call the nlist(3) routines to retrieve the given namelist. |
| 768 | */ |
| 769 | rv = __fdnlist(kd->nlfd, nl); |
| 770 | |
| 771 | if (rv == -1) |
| 772 | _kvm_err(kd, 0, "bad namelist" ); |
| 773 | |
| 774 | return (rv); |
| 775 | } |
| 776 | |
| 777 | int |
| 778 | kvm_dump_inval(kvm_t *kd) |
| 779 | { |
| 780 | struct nlist nl[2]; |
| 781 | paddr_t pa; |
| 782 | size_t dsize; |
| 783 | off_t doff; |
| 784 | void *newbuf; |
| 785 | |
| 786 | if (ISALIVE(kd)) { |
| 787 | _kvm_err(kd, kd->program, "clearing dump on live kernel" ); |
| 788 | return (-1); |
| 789 | } |
| 790 | nl[0].n_name = "_dumpmag" ; |
| 791 | nl[1].n_name = NULL; |
| 792 | |
| 793 | if (kvm_nlist(kd, nl) == -1) { |
| 794 | _kvm_err(kd, 0, "bad namelist" ); |
| 795 | return (-1); |
| 796 | } |
| 797 | if (_kvm_kvatop(kd, (vaddr_t)nl[0].n_value, &pa) == 0) |
| 798 | return (-1); |
| 799 | |
| 800 | errno = 0; |
| 801 | dsize = MAX(kd->fdalign, sizeof(u_long)); |
| 802 | if (kd->iobufsz < dsize) { |
| 803 | newbuf = realloc(kd->iobuf, dsize); |
| 804 | if (newbuf == NULL) { |
| 805 | _kvm_syserr(kd, 0, "cannot allocate I/O buffer" ); |
| 806 | return (-1); |
| 807 | } |
| 808 | kd->iobuf = newbuf; |
| 809 | kd->iobufsz = dsize; |
| 810 | } |
| 811 | memset(kd->iobuf, 0, dsize); |
| 812 | doff = _kvm_pa2off(kd, pa); |
| 813 | doff -= doff % kd->fdalign; |
| 814 | if (pwrite(kd->pmfd, kd->iobuf, dsize, doff) == -1) { |
| 815 | _kvm_syserr(kd, 0, "cannot invalidate dump - pwrite" ); |
| 816 | return (-1); |
| 817 | } |
| 818 | return (0); |
| 819 | } |
| 820 | |
| 821 | ssize_t |
| 822 | kvm_read(kvm_t *kd, u_long kva, void *buf, size_t len) |
| 823 | { |
| 824 | int cc; |
| 825 | void *cp; |
| 826 | |
| 827 | if (ISKMEM(kd)) { |
| 828 | /* |
| 829 | * We're using /dev/kmem. Just read straight from the |
| 830 | * device and let the active kernel do the address translation. |
| 831 | */ |
| 832 | errno = 0; |
| 833 | cc = _kvm_pread(kd, kd->vmfd, buf, len, (off_t)kva); |
| 834 | if (cc < 0) { |
| 835 | _kvm_syserr(kd, 0, "kvm_read" ); |
| 836 | return (-1); |
| 837 | } else if (cc < len) |
| 838 | _kvm_err(kd, kd->program, "short read" ); |
| 839 | return (cc); |
| 840 | } else if (ISSYSCTL(kd)) { |
| 841 | _kvm_err(kd, kd->program, "kvm_open called with KVM_NO_FILES, " |
| 842 | "can't use kvm_read" ); |
| 843 | return (-1); |
| 844 | } else { |
| 845 | if ((kd->kcore_hdr == NULL) || (kd->cpu_data == NULL)) { |
| 846 | _kvm_err(kd, kd->program, "no valid dump header" ); |
| 847 | return (-1); |
| 848 | } |
| 849 | cp = buf; |
| 850 | while (len > 0) { |
| 851 | paddr_t pa; |
| 852 | off_t foff; |
| 853 | |
| 854 | cc = _kvm_kvatop(kd, (vaddr_t)kva, &pa); |
| 855 | if (cc == 0) { |
| 856 | _kvm_err(kd, kd->program, "_kvm_kvatop(%lx)" , kva); |
| 857 | return (-1); |
| 858 | } |
| 859 | if (cc > len) |
| 860 | cc = len; |
| 861 | foff = _kvm_pa2off(kd, pa); |
| 862 | errno = 0; |
| 863 | cc = _kvm_pread(kd, kd->pmfd, cp, (size_t)cc, foff); |
| 864 | if (cc < 0) { |
| 865 | _kvm_syserr(kd, kd->program, "kvm_read" ); |
| 866 | break; |
| 867 | } |
| 868 | /* |
| 869 | * If kvm_kvatop returns a bogus value or our core |
| 870 | * file is truncated, we might wind up seeking beyond |
| 871 | * the end of the core file in which case the read will |
| 872 | * return 0 (EOF). |
| 873 | */ |
| 874 | if (cc == 0) |
| 875 | break; |
| 876 | cp = (char *)cp + cc; |
| 877 | kva += cc; |
| 878 | len -= cc; |
| 879 | } |
| 880 | return ((char *)cp - (char *)buf); |
| 881 | } |
| 882 | /* NOTREACHED */ |
| 883 | } |
| 884 | |
| 885 | ssize_t |
| 886 | kvm_write(kvm_t *kd, u_long kva, const void *buf, size_t len) |
| 887 | { |
| 888 | int cc; |
| 889 | |
| 890 | if (ISKMEM(kd)) { |
| 891 | /* |
| 892 | * Just like kvm_read, only we write. |
| 893 | */ |
| 894 | errno = 0; |
| 895 | cc = pwrite(kd->vmfd, buf, len, (off_t)kva); |
| 896 | if (cc < 0) { |
| 897 | _kvm_syserr(kd, 0, "kvm_write" ); |
| 898 | return (-1); |
| 899 | } else if (cc < len) |
| 900 | _kvm_err(kd, kd->program, "short write" ); |
| 901 | return (cc); |
| 902 | } else if (ISSYSCTL(kd)) { |
| 903 | _kvm_err(kd, kd->program, "kvm_open called with KVM_NO_FILES, " |
| 904 | "can't use kvm_write" ); |
| 905 | return (-1); |
| 906 | } else { |
| 907 | _kvm_err(kd, kd->program, |
| 908 | "kvm_write not implemented for dead kernels" ); |
| 909 | return (-1); |
| 910 | } |
| 911 | /* NOTREACHED */ |
| 912 | } |
| 913 | |