17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 227c478bd9Sstevel@tonic-gate /* 237c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 27*1320caf7SBryan Cantrill /* 28*1320caf7SBryan Cantrill * Copyright (c) 2013, Joyent, Inc. All rights reserved. 29*1320caf7SBryan Cantrill */ 307c478bd9Sstevel@tonic-gate 317c478bd9Sstevel@tonic-gate #include <kvm.h> 327c478bd9Sstevel@tonic-gate #include <stdio.h> 337c478bd9Sstevel@tonic-gate #include <stdlib.h> 347c478bd9Sstevel@tonic-gate #include <stdarg.h> 357c478bd9Sstevel@tonic-gate #include <unistd.h> 367c478bd9Sstevel@tonic-gate #include <limits.h> 377c478bd9Sstevel@tonic-gate #include <fcntl.h> 387c478bd9Sstevel@tonic-gate #include <strings.h> 39*1320caf7SBryan Cantrill #include <errno.h> 407c478bd9Sstevel@tonic-gate #include <sys/mem.h> 417c478bd9Sstevel@tonic-gate #include <sys/stat.h> 427c478bd9Sstevel@tonic-gate #include <sys/mman.h> 437c478bd9Sstevel@tonic-gate #include <sys/dumphdr.h> 447c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 457c478bd9Sstevel@tonic-gate 467c478bd9Sstevel@tonic-gate struct _kvmd { 477c478bd9Sstevel@tonic-gate struct dumphdr kvm_dump; 487c478bd9Sstevel@tonic-gate char *kvm_debug; 497c478bd9Sstevel@tonic-gate int kvm_openflag; 507c478bd9Sstevel@tonic-gate int kvm_corefd; 517c478bd9Sstevel@tonic-gate int kvm_kmemfd; 527c478bd9Sstevel@tonic-gate int kvm_memfd; 537c478bd9Sstevel@tonic-gate size_t kvm_coremapsize; 547c478bd9Sstevel@tonic-gate char *kvm_core; 557c478bd9Sstevel@tonic-gate dump_map_t *kvm_map; 567c478bd9Sstevel@tonic-gate pfn_t *kvm_pfn; 577c478bd9Sstevel@tonic-gate struct as *kvm_kas; 587c478bd9Sstevel@tonic-gate proc_t *kvm_practive; 597c478bd9Sstevel@tonic-gate pid_t kvm_pid; 607c478bd9Sstevel@tonic-gate char kvm_namelist[MAXNAMELEN + 1]; 61*1320caf7SBryan Cantrill boolean_t kvm_namelist_core; 627c478bd9Sstevel@tonic-gate proc_t kvm_proc; 637c478bd9Sstevel@tonic-gate }; 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate #define PREAD (ssize_t (*)(int, void *, size_t, offset_t))pread64 667c478bd9Sstevel@tonic-gate #define PWRITE (ssize_t (*)(int, void *, size_t, offset_t))pwrite64 677c478bd9Sstevel@tonic-gate 68*1320caf7SBryan Cantrill static int kvm_nlist_core(kvm_t *kd, struct nlist nl[], const char *err); 69*1320caf7SBryan Cantrill 707c478bd9Sstevel@tonic-gate static kvm_t * 717c478bd9Sstevel@tonic-gate fail(kvm_t *kd, const char *err, const char *message, ...) 727c478bd9Sstevel@tonic-gate { 737c478bd9Sstevel@tonic-gate va_list args; 747c478bd9Sstevel@tonic-gate 757c478bd9Sstevel@tonic-gate va_start(args, message); 767c478bd9Sstevel@tonic-gate if (err || (kd && kd->kvm_debug)) { 777c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", err ? err : "KVM_DEBUG"); 787c478bd9Sstevel@tonic-gate (void) vfprintf(stderr, message, args); 797c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\n"); 807c478bd9Sstevel@tonic-gate } 817c478bd9Sstevel@tonic-gate va_end(args); 827c478bd9Sstevel@tonic-gate if (kd != NULL) 837c478bd9Sstevel@tonic-gate (void) kvm_close(kd); 847c478bd9Sstevel@tonic-gate return (NULL); 857c478bd9Sstevel@tonic-gate } 867c478bd9Sstevel@tonic-gate 877c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 887c478bd9Sstevel@tonic-gate kvm_t * 897c478bd9Sstevel@tonic-gate kvm_open(const char *namelist, const char *corefile, const char *swapfile, 907c478bd9Sstevel@tonic-gate int flag, const char *err) 917c478bd9Sstevel@tonic-gate { 927c478bd9Sstevel@tonic-gate kvm_t *kd; 937c478bd9Sstevel@tonic-gate struct stat64 memstat, kmemstat, allkmemstat, corestat; 947c478bd9Sstevel@tonic-gate struct nlist nl[3] = { { "kas" }, { "practive" }, { "" } }; 957c478bd9Sstevel@tonic-gate 967c478bd9Sstevel@tonic-gate if ((kd = calloc(1, sizeof (kvm_t))) == NULL) 977c478bd9Sstevel@tonic-gate return (fail(NULL, err, "cannot allocate space for kvm_t")); 987c478bd9Sstevel@tonic-gate 997c478bd9Sstevel@tonic-gate kd->kvm_corefd = kd->kvm_kmemfd = kd->kvm_memfd = -1; 1007c478bd9Sstevel@tonic-gate kd->kvm_debug = getenv("KVM_DEBUG"); 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate if ((kd->kvm_openflag = flag) != O_RDONLY && flag != O_RDWR) 1037c478bd9Sstevel@tonic-gate return (fail(kd, err, "illegal flag 0x%x to kvm_open()", flag)); 1047c478bd9Sstevel@tonic-gate 1057c478bd9Sstevel@tonic-gate if (corefile == NULL) 1067c478bd9Sstevel@tonic-gate corefile = "/dev/kmem"; 1077c478bd9Sstevel@tonic-gate 1087c478bd9Sstevel@tonic-gate if (stat64(corefile, &corestat) == -1) 1097c478bd9Sstevel@tonic-gate return (fail(kd, err, "cannot stat %s", corefile)); 1107c478bd9Sstevel@tonic-gate 1117c478bd9Sstevel@tonic-gate if (S_ISCHR(corestat.st_mode)) { 1127c478bd9Sstevel@tonic-gate if (stat64("/dev/mem", &memstat) == -1) 1137c478bd9Sstevel@tonic-gate return (fail(kd, err, "cannot stat /dev/mem")); 1147c478bd9Sstevel@tonic-gate 1157c478bd9Sstevel@tonic-gate if (stat64("/dev/kmem", &kmemstat) == -1) 1167c478bd9Sstevel@tonic-gate return (fail(kd, err, "cannot stat /dev/kmem")); 1177c478bd9Sstevel@tonic-gate 1187c478bd9Sstevel@tonic-gate if (stat64("/dev/allkmem", &allkmemstat) == -1) 1197c478bd9Sstevel@tonic-gate return (fail(kd, err, "cannot stat /dev/allkmem")); 1207c478bd9Sstevel@tonic-gate if (corestat.st_rdev == memstat.st_rdev || 1217c478bd9Sstevel@tonic-gate corestat.st_rdev == kmemstat.st_rdev || 1227c478bd9Sstevel@tonic-gate corestat.st_rdev == allkmemstat.st_rdev) { 1237c478bd9Sstevel@tonic-gate char *kmem = (corestat.st_rdev == allkmemstat.st_rdev ? 1247c478bd9Sstevel@tonic-gate "/dev/allkmem" : "/dev/kmem"); 1257c478bd9Sstevel@tonic-gate 1267c478bd9Sstevel@tonic-gate if ((kd->kvm_kmemfd = open64(kmem, flag)) == -1) 1277c478bd9Sstevel@tonic-gate return (fail(kd, err, "cannot open %s", kmem)); 1287c478bd9Sstevel@tonic-gate if ((kd->kvm_memfd = open64("/dev/mem", flag)) == -1) 1297c478bd9Sstevel@tonic-gate return (fail(kd, err, "cannot open /dev/mem")); 1307c478bd9Sstevel@tonic-gate } 1317c478bd9Sstevel@tonic-gate } else { 1327c478bd9Sstevel@tonic-gate if ((kd->kvm_corefd = open64(corefile, flag)) == -1) 1337c478bd9Sstevel@tonic-gate return (fail(kd, err, "cannot open %s", corefile)); 1347c478bd9Sstevel@tonic-gate if (pread64(kd->kvm_corefd, &kd->kvm_dump, 1357c478bd9Sstevel@tonic-gate sizeof (kd->kvm_dump), 0) != sizeof (kd->kvm_dump)) 1367c478bd9Sstevel@tonic-gate return (fail(kd, err, "cannot read dump header")); 1377c478bd9Sstevel@tonic-gate if (kd->kvm_dump.dump_magic != DUMP_MAGIC) 1387c478bd9Sstevel@tonic-gate return (fail(kd, err, "%s is not a kernel core file " 1397c478bd9Sstevel@tonic-gate "(bad magic number %x)", corefile, 1407c478bd9Sstevel@tonic-gate kd->kvm_dump.dump_magic)); 1417c478bd9Sstevel@tonic-gate if (kd->kvm_dump.dump_version != DUMP_VERSION) 1427c478bd9Sstevel@tonic-gate return (fail(kd, err, 1437c478bd9Sstevel@tonic-gate "libkvm version (%u) != corefile version (%u)", 1447c478bd9Sstevel@tonic-gate DUMP_VERSION, kd->kvm_dump.dump_version)); 1457c478bd9Sstevel@tonic-gate if (kd->kvm_dump.dump_wordsize != DUMP_WORDSIZE) 1467c478bd9Sstevel@tonic-gate return (fail(kd, err, "%s is a %d-bit core file - " 1477c478bd9Sstevel@tonic-gate "cannot examine with %d-bit libkvm", corefile, 1487c478bd9Sstevel@tonic-gate kd->kvm_dump.dump_wordsize, DUMP_WORDSIZE)); 1497c478bd9Sstevel@tonic-gate /* 1507c478bd9Sstevel@tonic-gate * We try to mmap(2) the entire corefile for performance 1517c478bd9Sstevel@tonic-gate * (so we can use bcopy(3C) rather than pread(2)). Failing 1527c478bd9Sstevel@tonic-gate * that, we insist on at least mmap(2)ing the dump map. 1537c478bd9Sstevel@tonic-gate */ 1547c478bd9Sstevel@tonic-gate kd->kvm_coremapsize = (size_t)corestat.st_size; 1557c478bd9Sstevel@tonic-gate if (corestat.st_size > LONG_MAX || 1567c478bd9Sstevel@tonic-gate (kd->kvm_core = mmap64(0, kd->kvm_coremapsize, 1577c478bd9Sstevel@tonic-gate PROT_READ, MAP_SHARED, kd->kvm_corefd, 0)) == MAP_FAILED) { 1587c478bd9Sstevel@tonic-gate kd->kvm_coremapsize = kd->kvm_dump.dump_data; 1597c478bd9Sstevel@tonic-gate if ((kd->kvm_core = mmap64(0, kd->kvm_coremapsize, 1607c478bd9Sstevel@tonic-gate PROT_READ, MAP_SHARED, kd->kvm_corefd, 0)) == 1617c478bd9Sstevel@tonic-gate MAP_FAILED) 1627c478bd9Sstevel@tonic-gate return (fail(kd, err, "cannot mmap corefile")); 1637c478bd9Sstevel@tonic-gate } 1647c478bd9Sstevel@tonic-gate kd->kvm_map = (void *)(kd->kvm_core + kd->kvm_dump.dump_map); 1657c478bd9Sstevel@tonic-gate kd->kvm_pfn = (void *)(kd->kvm_core + kd->kvm_dump.dump_pfn); 1667c478bd9Sstevel@tonic-gate } 1677c478bd9Sstevel@tonic-gate 1687c478bd9Sstevel@tonic-gate if (namelist == NULL) 1697c478bd9Sstevel@tonic-gate namelist = "/dev/ksyms"; 1707c478bd9Sstevel@tonic-gate 1717c478bd9Sstevel@tonic-gate (void) strncpy(kd->kvm_namelist, namelist, MAXNAMELEN); 1727c478bd9Sstevel@tonic-gate 173*1320caf7SBryan Cantrill if (kvm_nlist(kd, nl) == -1) { 174*1320caf7SBryan Cantrill if (kd->kvm_corefd == -1) { 175*1320caf7SBryan Cantrill return (fail(kd, err, "%s is not a %d-bit " 176*1320caf7SBryan Cantrill "kernel namelist", namelist, DUMP_WORDSIZE)); 177*1320caf7SBryan Cantrill } 178*1320caf7SBryan Cantrill 179*1320caf7SBryan Cantrill if (kvm_nlist_core(kd, nl, err) == -1) 180*1320caf7SBryan Cantrill return (NULL); /* fail() already called */ 181*1320caf7SBryan Cantrill } 1827c478bd9Sstevel@tonic-gate 1837c478bd9Sstevel@tonic-gate kd->kvm_kas = (struct as *)nl[0].n_value; 1847c478bd9Sstevel@tonic-gate kd->kvm_practive = (proc_t *)nl[1].n_value; 1857c478bd9Sstevel@tonic-gate 1867c478bd9Sstevel@tonic-gate (void) kvm_setproc(kd); 1877c478bd9Sstevel@tonic-gate return (kd); 1887c478bd9Sstevel@tonic-gate } 1897c478bd9Sstevel@tonic-gate 1907c478bd9Sstevel@tonic-gate int 1917c478bd9Sstevel@tonic-gate kvm_close(kvm_t *kd) 1927c478bd9Sstevel@tonic-gate { 1937c478bd9Sstevel@tonic-gate if (kd->kvm_core != NULL && kd->kvm_core != MAP_FAILED) 1947c478bd9Sstevel@tonic-gate (void) munmap(kd->kvm_core, kd->kvm_coremapsize); 1957c478bd9Sstevel@tonic-gate if (kd->kvm_corefd != -1) 1967c478bd9Sstevel@tonic-gate (void) close(kd->kvm_corefd); 1977c478bd9Sstevel@tonic-gate if (kd->kvm_kmemfd != -1) 1987c478bd9Sstevel@tonic-gate (void) close(kd->kvm_kmemfd); 1997c478bd9Sstevel@tonic-gate if (kd->kvm_memfd != -1) 2007c478bd9Sstevel@tonic-gate (void) close(kd->kvm_memfd); 201*1320caf7SBryan Cantrill if (kd->kvm_namelist_core) 202*1320caf7SBryan Cantrill (void) unlink(kd->kvm_namelist); 2037c478bd9Sstevel@tonic-gate free(kd); 2047c478bd9Sstevel@tonic-gate return (0); 2057c478bd9Sstevel@tonic-gate } 2067c478bd9Sstevel@tonic-gate 207*1320caf7SBryan Cantrill const char * 208*1320caf7SBryan Cantrill kvm_namelist(kvm_t *kd) 209*1320caf7SBryan Cantrill { 210*1320caf7SBryan Cantrill return (kd->kvm_namelist); 211*1320caf7SBryan Cantrill } 212*1320caf7SBryan Cantrill 2137c478bd9Sstevel@tonic-gate int 2147c478bd9Sstevel@tonic-gate kvm_nlist(kvm_t *kd, struct nlist nl[]) 2157c478bd9Sstevel@tonic-gate { 2167c478bd9Sstevel@tonic-gate return (nlist(kd->kvm_namelist, nl)); 2177c478bd9Sstevel@tonic-gate } 2187c478bd9Sstevel@tonic-gate 219*1320caf7SBryan Cantrill /* 220*1320caf7SBryan Cantrill * If we don't have a name list, try to dig it out of the kernel crash dump. 221*1320caf7SBryan Cantrill * (The symbols have been present in the dump, uncompressed, for nearly a 222*1320caf7SBryan Cantrill * decade as of this writing -- and it is frankly surprising that the archaic 223*1320caf7SBryan Cantrill * notion of a disjoint symbol table managed to survive that change.) 224*1320caf7SBryan Cantrill */ 225*1320caf7SBryan Cantrill static int 226*1320caf7SBryan Cantrill kvm_nlist_core(kvm_t *kd, struct nlist nl[], const char *err) 227*1320caf7SBryan Cantrill { 228*1320caf7SBryan Cantrill dumphdr_t *dump = &kd->kvm_dump; 229*1320caf7SBryan Cantrill char *msg = "couldn't extract symbols from dump"; 230*1320caf7SBryan Cantrill char *template = "/tmp/.libkvm.kvm_nlist_core.pid%d.XXXXXX"; 231*1320caf7SBryan Cantrill int fd, rval; 232*1320caf7SBryan Cantrill 233*1320caf7SBryan Cantrill if (dump->dump_ksyms_size != dump->dump_ksyms_csize) { 234*1320caf7SBryan Cantrill (void) fail(kd, err, "%s: kernel symbols are compressed", msg); 235*1320caf7SBryan Cantrill return (-1); 236*1320caf7SBryan Cantrill } 237*1320caf7SBryan Cantrill 238*1320caf7SBryan Cantrill if (dump->dump_ksyms + dump->dump_ksyms_size > kd->kvm_coremapsize) { 239*1320caf7SBryan Cantrill (void) fail(kd, err, "%s: kernel symbols not mapped", msg); 240*1320caf7SBryan Cantrill return (-1); 241*1320caf7SBryan Cantrill } 242*1320caf7SBryan Cantrill 243*1320caf7SBryan Cantrill /* 244*1320caf7SBryan Cantrill * Beause this temporary file may be left as a turd if the caller 245*1320caf7SBryan Cantrill * does not properly call kvm_close(), we make sure that it clearly 246*1320caf7SBryan Cantrill * indicates its origins. 247*1320caf7SBryan Cantrill */ 248*1320caf7SBryan Cantrill (void) snprintf(kd->kvm_namelist, MAXNAMELEN, template, getpid()); 249*1320caf7SBryan Cantrill 250*1320caf7SBryan Cantrill if ((fd = mkstemp(kd->kvm_namelist)) == -1) { 251*1320caf7SBryan Cantrill (void) fail(kd, err, "%s: couldn't create temporary " 252*1320caf7SBryan Cantrill "symbols file: %s", msg, strerror(errno)); 253*1320caf7SBryan Cantrill return (-1); 254*1320caf7SBryan Cantrill } 255*1320caf7SBryan Cantrill 256*1320caf7SBryan Cantrill kd->kvm_namelist_core = B_TRUE; 257*1320caf7SBryan Cantrill 258*1320caf7SBryan Cantrill do { 259*1320caf7SBryan Cantrill rval = write(fd, (caddr_t)((uintptr_t)kd->kvm_core + 260*1320caf7SBryan Cantrill (uintptr_t)dump->dump_ksyms), dump->dump_ksyms_size); 261*1320caf7SBryan Cantrill } while (rval < dump->dump_ksyms_size && errno == EINTR); 262*1320caf7SBryan Cantrill 263*1320caf7SBryan Cantrill if (rval < dump->dump_ksyms_size) { 264*1320caf7SBryan Cantrill (void) fail(kd, err, "%s: couldn't write to temporary " 265*1320caf7SBryan Cantrill "symbols file: %s", msg, strerror(errno)); 266*1320caf7SBryan Cantrill (void) close(fd); 267*1320caf7SBryan Cantrill return (-1); 268*1320caf7SBryan Cantrill } 269*1320caf7SBryan Cantrill 270*1320caf7SBryan Cantrill (void) close(fd); 271*1320caf7SBryan Cantrill 272*1320caf7SBryan Cantrill if (kvm_nlist(kd, nl) == -1) { 273*1320caf7SBryan Cantrill (void) fail(kd, err, "%s: symbols not valid", msg); 274*1320caf7SBryan Cantrill return (-1); 275*1320caf7SBryan Cantrill } 276*1320caf7SBryan Cantrill 277*1320caf7SBryan Cantrill return (0); 278*1320caf7SBryan Cantrill } 279*1320caf7SBryan Cantrill 2807c478bd9Sstevel@tonic-gate static offset_t 2817c478bd9Sstevel@tonic-gate kvm_lookup(kvm_t *kd, struct as *as, uint64_t addr) 2827c478bd9Sstevel@tonic-gate { 2837c478bd9Sstevel@tonic-gate uintptr_t pageoff = addr & (kd->kvm_dump.dump_pagesize - 1); 2847c478bd9Sstevel@tonic-gate uint64_t page = addr - pageoff; 2857c478bd9Sstevel@tonic-gate offset_t off = 0; 2867c478bd9Sstevel@tonic-gate 2877c478bd9Sstevel@tonic-gate if (kd->kvm_debug) 2887c478bd9Sstevel@tonic-gate fprintf(stderr, "kvm_lookup(%p, %llx):", (void *)as, addr); 2897c478bd9Sstevel@tonic-gate 2907c478bd9Sstevel@tonic-gate if (as == NULL) { /* physical addressing mode */ 2917c478bd9Sstevel@tonic-gate long first = 0; 2927c478bd9Sstevel@tonic-gate long last = kd->kvm_dump.dump_npages - 1; 2937c478bd9Sstevel@tonic-gate pfn_t target = (pfn_t)(page >> kd->kvm_dump.dump_pageshift); 2947c478bd9Sstevel@tonic-gate while (last >= first) { 2957c478bd9Sstevel@tonic-gate long middle = (first + last) / 2; 2967c478bd9Sstevel@tonic-gate pfn_t pfn = kd->kvm_pfn[middle]; 2977c478bd9Sstevel@tonic-gate if (kd->kvm_debug) 2987c478bd9Sstevel@tonic-gate fprintf(stderr, " %ld ->", middle); 2997c478bd9Sstevel@tonic-gate if (pfn == target) { 3007c478bd9Sstevel@tonic-gate off = kd->kvm_dump.dump_data + pageoff + 3017c478bd9Sstevel@tonic-gate ((uint64_t)middle << 3027c478bd9Sstevel@tonic-gate kd->kvm_dump.dump_pageshift); 3037c478bd9Sstevel@tonic-gate break; 3047c478bd9Sstevel@tonic-gate } 3057c478bd9Sstevel@tonic-gate if (pfn < target) 3067c478bd9Sstevel@tonic-gate first = middle + 1; 3077c478bd9Sstevel@tonic-gate else 3087c478bd9Sstevel@tonic-gate last = middle - 1; 3097c478bd9Sstevel@tonic-gate } 3107c478bd9Sstevel@tonic-gate } else { 3117c478bd9Sstevel@tonic-gate long hash = DUMP_HASH(&kd->kvm_dump, as, page); 3127c478bd9Sstevel@tonic-gate off = kd->kvm_map[hash].dm_first; 3137c478bd9Sstevel@tonic-gate while (off != 0) { 3147c478bd9Sstevel@tonic-gate dump_map_t *dmp = (void *)(kd->kvm_core + off); 3157c478bd9Sstevel@tonic-gate if (kd->kvm_debug) 3167c478bd9Sstevel@tonic-gate fprintf(stderr, " %llx ->", off); 3177c478bd9Sstevel@tonic-gate if (dmp < kd->kvm_map || 3187c478bd9Sstevel@tonic-gate dmp > kd->kvm_map + kd->kvm_dump.dump_hashmask || 3197c478bd9Sstevel@tonic-gate (off & (sizeof (offset_t) - 1)) != 0 || 3207c478bd9Sstevel@tonic-gate DUMP_HASH(&kd->kvm_dump, dmp->dm_as, dmp->dm_va) != 3217c478bd9Sstevel@tonic-gate hash) { 3227c478bd9Sstevel@tonic-gate if (kd->kvm_debug) 3237c478bd9Sstevel@tonic-gate fprintf(stderr, " dump map corrupt\n"); 3247c478bd9Sstevel@tonic-gate return (0); 3257c478bd9Sstevel@tonic-gate } 3267c478bd9Sstevel@tonic-gate if (dmp->dm_va == page && dmp->dm_as == as) { 3277c478bd9Sstevel@tonic-gate off = dmp->dm_data + pageoff; 3287c478bd9Sstevel@tonic-gate break; 3297c478bd9Sstevel@tonic-gate } 3307c478bd9Sstevel@tonic-gate off = dmp->dm_next; 3317c478bd9Sstevel@tonic-gate } 3327c478bd9Sstevel@tonic-gate } 3337c478bd9Sstevel@tonic-gate if (kd->kvm_debug) 3347c478bd9Sstevel@tonic-gate fprintf(stderr, "%s found: %llx\n", off ? "" : " not", off); 3357c478bd9Sstevel@tonic-gate return (off); 3367c478bd9Sstevel@tonic-gate } 3377c478bd9Sstevel@tonic-gate 3387c478bd9Sstevel@tonic-gate static ssize_t 3397c478bd9Sstevel@tonic-gate kvm_rw(kvm_t *kd, uint64_t addr, void *buf, size_t size, 3407c478bd9Sstevel@tonic-gate struct as *as, ssize_t (*prw)(int, void *, size_t, offset_t)) 3417c478bd9Sstevel@tonic-gate { 3427c478bd9Sstevel@tonic-gate offset_t off; 3437c478bd9Sstevel@tonic-gate size_t resid = size; 3447c478bd9Sstevel@tonic-gate 3457c478bd9Sstevel@tonic-gate /* 3467c478bd9Sstevel@tonic-gate * read/write of zero bytes always succeeds 3477c478bd9Sstevel@tonic-gate */ 3487c478bd9Sstevel@tonic-gate if (size == 0) 3497c478bd9Sstevel@tonic-gate return (0); 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate if (kd->kvm_core == NULL) { 3527c478bd9Sstevel@tonic-gate char procbuf[100]; 3537c478bd9Sstevel@tonic-gate int procfd; 3547c478bd9Sstevel@tonic-gate ssize_t rval; 3557c478bd9Sstevel@tonic-gate 3567c478bd9Sstevel@tonic-gate if (as == kd->kvm_kas) 3577c478bd9Sstevel@tonic-gate return (prw(kd->kvm_kmemfd, buf, size, addr)); 3587c478bd9Sstevel@tonic-gate if (as == NULL) 3597c478bd9Sstevel@tonic-gate return (prw(kd->kvm_memfd, buf, size, addr)); 3607c478bd9Sstevel@tonic-gate 3617c478bd9Sstevel@tonic-gate (void) sprintf(procbuf, "/proc/%ld/as", kd->kvm_pid); 3627c478bd9Sstevel@tonic-gate if ((procfd = open64(procbuf, kd->kvm_openflag)) == -1) 3637c478bd9Sstevel@tonic-gate return (-1); 3647c478bd9Sstevel@tonic-gate rval = prw(procfd, buf, size, addr); 3657c478bd9Sstevel@tonic-gate (void) close(procfd); 3667c478bd9Sstevel@tonic-gate return (rval); 3677c478bd9Sstevel@tonic-gate } 3687c478bd9Sstevel@tonic-gate 3697c478bd9Sstevel@tonic-gate while (resid != 0) { 3707c478bd9Sstevel@tonic-gate uintptr_t pageoff = addr & (kd->kvm_dump.dump_pagesize - 1); 3717c478bd9Sstevel@tonic-gate ssize_t len = MIN(resid, kd->kvm_dump.dump_pagesize - pageoff); 3727c478bd9Sstevel@tonic-gate 3737c478bd9Sstevel@tonic-gate if ((off = kvm_lookup(kd, as, addr)) == 0) 3747c478bd9Sstevel@tonic-gate break; 3757c478bd9Sstevel@tonic-gate 3767c478bd9Sstevel@tonic-gate if (prw == PREAD && off < kd->kvm_coremapsize) 3777c478bd9Sstevel@tonic-gate bcopy(kd->kvm_core + off, buf, len); 3787c478bd9Sstevel@tonic-gate else if ((len = prw(kd->kvm_corefd, buf, len, off)) <= 0) 3797c478bd9Sstevel@tonic-gate break; 3807c478bd9Sstevel@tonic-gate resid -= len; 3817c478bd9Sstevel@tonic-gate addr += len; 3827c478bd9Sstevel@tonic-gate buf = (char *)buf + len; 3837c478bd9Sstevel@tonic-gate } 3847c478bd9Sstevel@tonic-gate return (resid < size ? size - resid : -1); 3857c478bd9Sstevel@tonic-gate } 3867c478bd9Sstevel@tonic-gate 3877c478bd9Sstevel@tonic-gate ssize_t 3887c478bd9Sstevel@tonic-gate kvm_read(kvm_t *kd, uintptr_t addr, void *buf, size_t size) 3897c478bd9Sstevel@tonic-gate { 3907c478bd9Sstevel@tonic-gate return (kvm_rw(kd, addr, buf, size, kd->kvm_kas, PREAD)); 3917c478bd9Sstevel@tonic-gate } 3927c478bd9Sstevel@tonic-gate 3937c478bd9Sstevel@tonic-gate ssize_t 3947c478bd9Sstevel@tonic-gate kvm_kread(kvm_t *kd, uintptr_t addr, void *buf, size_t size) 3957c478bd9Sstevel@tonic-gate { 3967c478bd9Sstevel@tonic-gate return (kvm_rw(kd, addr, buf, size, kd->kvm_kas, PREAD)); 3977c478bd9Sstevel@tonic-gate } 3987c478bd9Sstevel@tonic-gate 3997c478bd9Sstevel@tonic-gate ssize_t 4007c478bd9Sstevel@tonic-gate kvm_uread(kvm_t *kd, uintptr_t addr, void *buf, size_t size) 4017c478bd9Sstevel@tonic-gate { 4027c478bd9Sstevel@tonic-gate return (kvm_rw(kd, addr, buf, size, kd->kvm_proc.p_as, PREAD)); 4037c478bd9Sstevel@tonic-gate } 4047c478bd9Sstevel@tonic-gate 4057c478bd9Sstevel@tonic-gate ssize_t 4067c478bd9Sstevel@tonic-gate kvm_aread(kvm_t *kd, uintptr_t addr, void *buf, size_t size, struct as *as) 4077c478bd9Sstevel@tonic-gate { 4087c478bd9Sstevel@tonic-gate return (kvm_rw(kd, addr, buf, size, as, PREAD)); 4097c478bd9Sstevel@tonic-gate } 4107c478bd9Sstevel@tonic-gate 4117c478bd9Sstevel@tonic-gate ssize_t 4127c478bd9Sstevel@tonic-gate kvm_pread(kvm_t *kd, uint64_t addr, void *buf, size_t size) 4137c478bd9Sstevel@tonic-gate { 4147c478bd9Sstevel@tonic-gate return (kvm_rw(kd, addr, buf, size, NULL, PREAD)); 4157c478bd9Sstevel@tonic-gate } 4167c478bd9Sstevel@tonic-gate 4177c478bd9Sstevel@tonic-gate ssize_t 4187c478bd9Sstevel@tonic-gate kvm_write(kvm_t *kd, uintptr_t addr, const void *buf, size_t size) 4197c478bd9Sstevel@tonic-gate { 4207c478bd9Sstevel@tonic-gate return (kvm_rw(kd, addr, (void *)buf, size, kd->kvm_kas, PWRITE)); 4217c478bd9Sstevel@tonic-gate } 4227c478bd9Sstevel@tonic-gate 4237c478bd9Sstevel@tonic-gate ssize_t 4247c478bd9Sstevel@tonic-gate kvm_kwrite(kvm_t *kd, uintptr_t addr, const void *buf, size_t size) 4257c478bd9Sstevel@tonic-gate { 4267c478bd9Sstevel@tonic-gate return (kvm_rw(kd, addr, (void *)buf, size, kd->kvm_kas, PWRITE)); 4277c478bd9Sstevel@tonic-gate } 4287c478bd9Sstevel@tonic-gate 4297c478bd9Sstevel@tonic-gate ssize_t 4307c478bd9Sstevel@tonic-gate kvm_uwrite(kvm_t *kd, uintptr_t addr, const void *buf, size_t size) 4317c478bd9Sstevel@tonic-gate { 4327c478bd9Sstevel@tonic-gate return (kvm_rw(kd, addr, (void *)buf, size, kd->kvm_proc.p_as, PWRITE)); 4337c478bd9Sstevel@tonic-gate } 4347c478bd9Sstevel@tonic-gate 4357c478bd9Sstevel@tonic-gate ssize_t 4367c478bd9Sstevel@tonic-gate kvm_awrite(kvm_t *kd, uintptr_t addr, const void *buf, size_t size, 4377c478bd9Sstevel@tonic-gate struct as *as) 4387c478bd9Sstevel@tonic-gate { 4397c478bd9Sstevel@tonic-gate return (kvm_rw(kd, addr, (void *)buf, size, as, PWRITE)); 4407c478bd9Sstevel@tonic-gate } 4417c478bd9Sstevel@tonic-gate 4427c478bd9Sstevel@tonic-gate ssize_t 4437c478bd9Sstevel@tonic-gate kvm_pwrite(kvm_t *kd, uint64_t addr, const void *buf, size_t size) 4447c478bd9Sstevel@tonic-gate { 4457c478bd9Sstevel@tonic-gate return (kvm_rw(kd, addr, (void *)buf, size, NULL, PWRITE)); 4467c478bd9Sstevel@tonic-gate } 4477c478bd9Sstevel@tonic-gate 4487c478bd9Sstevel@tonic-gate uint64_t 4497c478bd9Sstevel@tonic-gate kvm_physaddr(kvm_t *kd, struct as *as, uintptr_t addr) 4507c478bd9Sstevel@tonic-gate { 4517c478bd9Sstevel@tonic-gate mem_vtop_t mem_vtop; 4527c478bd9Sstevel@tonic-gate offset_t off; 4537c478bd9Sstevel@tonic-gate 4547c478bd9Sstevel@tonic-gate if (kd->kvm_core == NULL) { 4557c478bd9Sstevel@tonic-gate mem_vtop.m_as = as; 4567c478bd9Sstevel@tonic-gate mem_vtop.m_va = (void *)addr; 4577c478bd9Sstevel@tonic-gate if (ioctl(kd->kvm_kmemfd, MEM_VTOP, &mem_vtop) == 0) 4587c478bd9Sstevel@tonic-gate return ((uint64_t)mem_vtop.m_pfn * getpagesize() + 4597c478bd9Sstevel@tonic-gate (addr & (getpagesize() - 1))); 4607c478bd9Sstevel@tonic-gate } else { 4617c478bd9Sstevel@tonic-gate if ((off = kvm_lookup(kd, as, addr)) != 0) { 4627c478bd9Sstevel@tonic-gate long pfn_index = 4637c478bd9Sstevel@tonic-gate (u_offset_t)(off - kd->kvm_dump.dump_data) >> 4647c478bd9Sstevel@tonic-gate kd->kvm_dump.dump_pageshift; 4657c478bd9Sstevel@tonic-gate return (((uint64_t)kd->kvm_pfn[pfn_index] << 4667c478bd9Sstevel@tonic-gate kd->kvm_dump.dump_pageshift) + 4677c478bd9Sstevel@tonic-gate (addr & (kd->kvm_dump.dump_pagesize - 1))); 4687c478bd9Sstevel@tonic-gate } 4697c478bd9Sstevel@tonic-gate } 4707c478bd9Sstevel@tonic-gate return (-1ULL); 4717c478bd9Sstevel@tonic-gate } 4727c478bd9Sstevel@tonic-gate 4737c478bd9Sstevel@tonic-gate struct proc * 4747c478bd9Sstevel@tonic-gate kvm_getproc(kvm_t *kd, pid_t pid) 4757c478bd9Sstevel@tonic-gate { 4767c478bd9Sstevel@tonic-gate (void) kvm_setproc(kd); 4777c478bd9Sstevel@tonic-gate while (kvm_nextproc(kd) != NULL) 4787c478bd9Sstevel@tonic-gate if (kd->kvm_pid == pid) 4797c478bd9Sstevel@tonic-gate return (&kd->kvm_proc); 4807c478bd9Sstevel@tonic-gate return (NULL); 4817c478bd9Sstevel@tonic-gate } 4827c478bd9Sstevel@tonic-gate 4837c478bd9Sstevel@tonic-gate struct proc * 4847c478bd9Sstevel@tonic-gate kvm_nextproc(kvm_t *kd) 4857c478bd9Sstevel@tonic-gate { 4867c478bd9Sstevel@tonic-gate if (kd->kvm_proc.p_next == NULL || 4877c478bd9Sstevel@tonic-gate kvm_kread(kd, (uintptr_t)kd->kvm_proc.p_next, 4887c478bd9Sstevel@tonic-gate &kd->kvm_proc, sizeof (proc_t)) != sizeof (proc_t) || 4897c478bd9Sstevel@tonic-gate kvm_kread(kd, (uintptr_t)&kd->kvm_proc.p_pidp->pid_id, 4907c478bd9Sstevel@tonic-gate &kd->kvm_pid, sizeof (pid_t)) != sizeof (pid_t)) 4917c478bd9Sstevel@tonic-gate return (NULL); 4927c478bd9Sstevel@tonic-gate 4937c478bd9Sstevel@tonic-gate return (&kd->kvm_proc); 4947c478bd9Sstevel@tonic-gate } 4957c478bd9Sstevel@tonic-gate 4967c478bd9Sstevel@tonic-gate int 4977c478bd9Sstevel@tonic-gate kvm_setproc(kvm_t *kd) 4987c478bd9Sstevel@tonic-gate { 4997c478bd9Sstevel@tonic-gate (void) kvm_kread(kd, (uintptr_t)kd->kvm_practive, 5007c478bd9Sstevel@tonic-gate &kd->kvm_proc.p_next, sizeof (proc_t *)); 5017c478bd9Sstevel@tonic-gate kd->kvm_pid = -1; 5027c478bd9Sstevel@tonic-gate return (0); 5037c478bd9Sstevel@tonic-gate } 5047c478bd9Sstevel@tonic-gate 5057c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5067c478bd9Sstevel@tonic-gate struct user * 5077c478bd9Sstevel@tonic-gate kvm_getu(kvm_t *kd, struct proc *p) 5087c478bd9Sstevel@tonic-gate { 5097c478bd9Sstevel@tonic-gate return (&p->p_user); 5107c478bd9Sstevel@tonic-gate } 511