1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <kvm.h> 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <stdarg.h> 33 #include <unistd.h> 34 #include <limits.h> 35 #include <fcntl.h> 36 #include <strings.h> 37 #include <sys/mem.h> 38 #include <sys/stat.h> 39 #include <sys/mman.h> 40 #include <sys/dumphdr.h> 41 #include <sys/sysmacros.h> 42 43 struct _kvmd { 44 struct dumphdr kvm_dump; 45 char *kvm_debug; 46 int kvm_openflag; 47 int kvm_corefd; 48 int kvm_kmemfd; 49 int kvm_memfd; 50 size_t kvm_coremapsize; 51 char *kvm_core; 52 dump_map_t *kvm_map; 53 pfn_t *kvm_pfn; 54 struct as *kvm_kas; 55 proc_t *kvm_practive; 56 pid_t kvm_pid; 57 char kvm_namelist[MAXNAMELEN + 1]; 58 proc_t kvm_proc; 59 }; 60 61 #define PREAD (ssize_t (*)(int, void *, size_t, offset_t))pread64 62 #define PWRITE (ssize_t (*)(int, void *, size_t, offset_t))pwrite64 63 64 static kvm_t * 65 fail(kvm_t *kd, const char *err, const char *message, ...) 66 { 67 va_list args; 68 69 va_start(args, message); 70 if (err || (kd && kd->kvm_debug)) { 71 (void) fprintf(stderr, "%s: ", err ? err : "KVM_DEBUG"); 72 (void) vfprintf(stderr, message, args); 73 (void) fprintf(stderr, "\n"); 74 } 75 va_end(args); 76 if (kd != NULL) 77 (void) kvm_close(kd); 78 return (NULL); 79 } 80 81 /*ARGSUSED*/ 82 kvm_t * 83 kvm_open(const char *namelist, const char *corefile, const char *swapfile, 84 int flag, const char *err) 85 { 86 kvm_t *kd; 87 struct stat64 memstat, kmemstat, allkmemstat, corestat; 88 struct nlist nl[3] = { { "kas" }, { "practive" }, { "" } }; 89 90 if ((kd = calloc(1, sizeof (kvm_t))) == NULL) 91 return (fail(NULL, err, "cannot allocate space for kvm_t")); 92 93 kd->kvm_corefd = kd->kvm_kmemfd = kd->kvm_memfd = -1; 94 kd->kvm_debug = getenv("KVM_DEBUG"); 95 96 if ((kd->kvm_openflag = flag) != O_RDONLY && flag != O_RDWR) 97 return (fail(kd, err, "illegal flag 0x%x to kvm_open()", flag)); 98 99 if (corefile == NULL) 100 corefile = "/dev/kmem"; 101 102 if (stat64(corefile, &corestat) == -1) 103 return (fail(kd, err, "cannot stat %s", corefile)); 104 105 if (S_ISCHR(corestat.st_mode)) { 106 if (stat64("/dev/mem", &memstat) == -1) 107 return (fail(kd, err, "cannot stat /dev/mem")); 108 109 if (stat64("/dev/kmem", &kmemstat) == -1) 110 return (fail(kd, err, "cannot stat /dev/kmem")); 111 112 if (stat64("/dev/allkmem", &allkmemstat) == -1) 113 return (fail(kd, err, "cannot stat /dev/allkmem")); 114 if (corestat.st_rdev == memstat.st_rdev || 115 corestat.st_rdev == kmemstat.st_rdev || 116 corestat.st_rdev == allkmemstat.st_rdev) { 117 char *kmem = (corestat.st_rdev == allkmemstat.st_rdev ? 118 "/dev/allkmem" : "/dev/kmem"); 119 120 if ((kd->kvm_kmemfd = open64(kmem, flag)) == -1) 121 return (fail(kd, err, "cannot open %s", kmem)); 122 if ((kd->kvm_memfd = open64("/dev/mem", flag)) == -1) 123 return (fail(kd, err, "cannot open /dev/mem")); 124 } 125 } else { 126 if ((kd->kvm_corefd = open64(corefile, flag)) == -1) 127 return (fail(kd, err, "cannot open %s", corefile)); 128 if (pread64(kd->kvm_corefd, &kd->kvm_dump, 129 sizeof (kd->kvm_dump), 0) != sizeof (kd->kvm_dump)) 130 return (fail(kd, err, "cannot read dump header")); 131 if (kd->kvm_dump.dump_magic != DUMP_MAGIC) 132 return (fail(kd, err, "%s is not a kernel core file " 133 "(bad magic number %x)", corefile, 134 kd->kvm_dump.dump_magic)); 135 if (kd->kvm_dump.dump_version != DUMP_VERSION) 136 return (fail(kd, err, 137 "libkvm version (%u) != corefile version (%u)", 138 DUMP_VERSION, kd->kvm_dump.dump_version)); 139 if (kd->kvm_dump.dump_wordsize != DUMP_WORDSIZE) 140 return (fail(kd, err, "%s is a %d-bit core file - " 141 "cannot examine with %d-bit libkvm", corefile, 142 kd->kvm_dump.dump_wordsize, DUMP_WORDSIZE)); 143 /* 144 * We try to mmap(2) the entire corefile for performance 145 * (so we can use bcopy(3C) rather than pread(2)). Failing 146 * that, we insist on at least mmap(2)ing the dump map. 147 */ 148 kd->kvm_coremapsize = (size_t)corestat.st_size; 149 if (corestat.st_size > LONG_MAX || 150 (kd->kvm_core = mmap64(0, kd->kvm_coremapsize, 151 PROT_READ, MAP_SHARED, kd->kvm_corefd, 0)) == MAP_FAILED) { 152 kd->kvm_coremapsize = kd->kvm_dump.dump_data; 153 if ((kd->kvm_core = mmap64(0, kd->kvm_coremapsize, 154 PROT_READ, MAP_SHARED, kd->kvm_corefd, 0)) == 155 MAP_FAILED) 156 return (fail(kd, err, "cannot mmap corefile")); 157 } 158 kd->kvm_map = (void *)(kd->kvm_core + kd->kvm_dump.dump_map); 159 kd->kvm_pfn = (void *)(kd->kvm_core + kd->kvm_dump.dump_pfn); 160 } 161 162 if (namelist == NULL) 163 namelist = "/dev/ksyms"; 164 165 (void) strncpy(kd->kvm_namelist, namelist, MAXNAMELEN); 166 167 if (kvm_nlist(kd, nl) == -1) 168 return (fail(kd, err, "%s is not a %d-bit kernel namelist", 169 namelist, DUMP_WORDSIZE)); 170 171 kd->kvm_kas = (struct as *)nl[0].n_value; 172 kd->kvm_practive = (proc_t *)nl[1].n_value; 173 174 (void) kvm_setproc(kd); 175 return (kd); 176 } 177 178 int 179 kvm_close(kvm_t *kd) 180 { 181 if (kd->kvm_core != NULL && kd->kvm_core != MAP_FAILED) 182 (void) munmap(kd->kvm_core, kd->kvm_coremapsize); 183 if (kd->kvm_corefd != -1) 184 (void) close(kd->kvm_corefd); 185 if (kd->kvm_kmemfd != -1) 186 (void) close(kd->kvm_kmemfd); 187 if (kd->kvm_memfd != -1) 188 (void) close(kd->kvm_memfd); 189 free(kd); 190 return (0); 191 } 192 193 int 194 kvm_nlist(kvm_t *kd, struct nlist nl[]) 195 { 196 return (nlist(kd->kvm_namelist, nl)); 197 } 198 199 static offset_t 200 kvm_lookup(kvm_t *kd, struct as *as, uint64_t addr) 201 { 202 uintptr_t pageoff = addr & (kd->kvm_dump.dump_pagesize - 1); 203 uint64_t page = addr - pageoff; 204 offset_t off = 0; 205 206 if (kd->kvm_debug) 207 fprintf(stderr, "kvm_lookup(%p, %llx):", (void *)as, addr); 208 209 if (as == NULL) { /* physical addressing mode */ 210 long first = 0; 211 long last = kd->kvm_dump.dump_npages - 1; 212 pfn_t target = (pfn_t)(page >> kd->kvm_dump.dump_pageshift); 213 while (last >= first) { 214 long middle = (first + last) / 2; 215 pfn_t pfn = kd->kvm_pfn[middle]; 216 if (kd->kvm_debug) 217 fprintf(stderr, " %ld ->", middle); 218 if (pfn == target) { 219 off = kd->kvm_dump.dump_data + pageoff + 220 ((uint64_t)middle << 221 kd->kvm_dump.dump_pageshift); 222 break; 223 } 224 if (pfn < target) 225 first = middle + 1; 226 else 227 last = middle - 1; 228 } 229 } else { 230 long hash = DUMP_HASH(&kd->kvm_dump, as, page); 231 off = kd->kvm_map[hash].dm_first; 232 while (off != 0) { 233 dump_map_t *dmp = (void *)(kd->kvm_core + off); 234 if (kd->kvm_debug) 235 fprintf(stderr, " %llx ->", off); 236 if (dmp < kd->kvm_map || 237 dmp > kd->kvm_map + kd->kvm_dump.dump_hashmask || 238 (off & (sizeof (offset_t) - 1)) != 0 || 239 DUMP_HASH(&kd->kvm_dump, dmp->dm_as, dmp->dm_va) != 240 hash) { 241 if (kd->kvm_debug) 242 fprintf(stderr, " dump map corrupt\n"); 243 return (0); 244 } 245 if (dmp->dm_va == page && dmp->dm_as == as) { 246 off = dmp->dm_data + pageoff; 247 break; 248 } 249 off = dmp->dm_next; 250 } 251 } 252 if (kd->kvm_debug) 253 fprintf(stderr, "%s found: %llx\n", off ? "" : " not", off); 254 return (off); 255 } 256 257 static ssize_t 258 kvm_rw(kvm_t *kd, uint64_t addr, void *buf, size_t size, 259 struct as *as, ssize_t (*prw)(int, void *, size_t, offset_t)) 260 { 261 offset_t off; 262 size_t resid = size; 263 264 /* 265 * read/write of zero bytes always succeeds 266 */ 267 if (size == 0) 268 return (0); 269 270 if (kd->kvm_core == NULL) { 271 char procbuf[100]; 272 int procfd; 273 ssize_t rval; 274 275 if (as == kd->kvm_kas) 276 return (prw(kd->kvm_kmemfd, buf, size, addr)); 277 if (as == NULL) 278 return (prw(kd->kvm_memfd, buf, size, addr)); 279 280 (void) sprintf(procbuf, "/proc/%ld/as", kd->kvm_pid); 281 if ((procfd = open64(procbuf, kd->kvm_openflag)) == -1) 282 return (-1); 283 rval = prw(procfd, buf, size, addr); 284 (void) close(procfd); 285 return (rval); 286 } 287 288 while (resid != 0) { 289 uintptr_t pageoff = addr & (kd->kvm_dump.dump_pagesize - 1); 290 ssize_t len = MIN(resid, kd->kvm_dump.dump_pagesize - pageoff); 291 292 if ((off = kvm_lookup(kd, as, addr)) == 0) 293 break; 294 295 if (prw == PREAD && off < kd->kvm_coremapsize) 296 bcopy(kd->kvm_core + off, buf, len); 297 else if ((len = prw(kd->kvm_corefd, buf, len, off)) <= 0) 298 break; 299 resid -= len; 300 addr += len; 301 buf = (char *)buf + len; 302 } 303 return (resid < size ? size - resid : -1); 304 } 305 306 ssize_t 307 kvm_read(kvm_t *kd, uintptr_t addr, void *buf, size_t size) 308 { 309 return (kvm_rw(kd, addr, buf, size, kd->kvm_kas, PREAD)); 310 } 311 312 ssize_t 313 kvm_kread(kvm_t *kd, uintptr_t addr, void *buf, size_t size) 314 { 315 return (kvm_rw(kd, addr, buf, size, kd->kvm_kas, PREAD)); 316 } 317 318 ssize_t 319 kvm_uread(kvm_t *kd, uintptr_t addr, void *buf, size_t size) 320 { 321 return (kvm_rw(kd, addr, buf, size, kd->kvm_proc.p_as, PREAD)); 322 } 323 324 ssize_t 325 kvm_aread(kvm_t *kd, uintptr_t addr, void *buf, size_t size, struct as *as) 326 { 327 return (kvm_rw(kd, addr, buf, size, as, PREAD)); 328 } 329 330 ssize_t 331 kvm_pread(kvm_t *kd, uint64_t addr, void *buf, size_t size) 332 { 333 return (kvm_rw(kd, addr, buf, size, NULL, PREAD)); 334 } 335 336 ssize_t 337 kvm_write(kvm_t *kd, uintptr_t addr, const void *buf, size_t size) 338 { 339 return (kvm_rw(kd, addr, (void *)buf, size, kd->kvm_kas, PWRITE)); 340 } 341 342 ssize_t 343 kvm_kwrite(kvm_t *kd, uintptr_t addr, const void *buf, size_t size) 344 { 345 return (kvm_rw(kd, addr, (void *)buf, size, kd->kvm_kas, PWRITE)); 346 } 347 348 ssize_t 349 kvm_uwrite(kvm_t *kd, uintptr_t addr, const void *buf, size_t size) 350 { 351 return (kvm_rw(kd, addr, (void *)buf, size, kd->kvm_proc.p_as, PWRITE)); 352 } 353 354 ssize_t 355 kvm_awrite(kvm_t *kd, uintptr_t addr, const void *buf, size_t size, 356 struct as *as) 357 { 358 return (kvm_rw(kd, addr, (void *)buf, size, as, PWRITE)); 359 } 360 361 ssize_t 362 kvm_pwrite(kvm_t *kd, uint64_t addr, const void *buf, size_t size) 363 { 364 return (kvm_rw(kd, addr, (void *)buf, size, NULL, PWRITE)); 365 } 366 367 uint64_t 368 kvm_physaddr(kvm_t *kd, struct as *as, uintptr_t addr) 369 { 370 mem_vtop_t mem_vtop; 371 offset_t off; 372 373 if (kd->kvm_core == NULL) { 374 mem_vtop.m_as = as; 375 mem_vtop.m_va = (void *)addr; 376 if (ioctl(kd->kvm_kmemfd, MEM_VTOP, &mem_vtop) == 0) 377 return ((uint64_t)mem_vtop.m_pfn * getpagesize() + 378 (addr & (getpagesize() - 1))); 379 } else { 380 if ((off = kvm_lookup(kd, as, addr)) != 0) { 381 long pfn_index = 382 (u_offset_t)(off - kd->kvm_dump.dump_data) >> 383 kd->kvm_dump.dump_pageshift; 384 return (((uint64_t)kd->kvm_pfn[pfn_index] << 385 kd->kvm_dump.dump_pageshift) + 386 (addr & (kd->kvm_dump.dump_pagesize - 1))); 387 } 388 } 389 return (-1ULL); 390 } 391 392 struct proc * 393 kvm_getproc(kvm_t *kd, pid_t pid) 394 { 395 (void) kvm_setproc(kd); 396 while (kvm_nextproc(kd) != NULL) 397 if (kd->kvm_pid == pid) 398 return (&kd->kvm_proc); 399 return (NULL); 400 } 401 402 struct proc * 403 kvm_nextproc(kvm_t *kd) 404 { 405 if (kd->kvm_proc.p_next == NULL || 406 kvm_kread(kd, (uintptr_t)kd->kvm_proc.p_next, 407 &kd->kvm_proc, sizeof (proc_t)) != sizeof (proc_t) || 408 kvm_kread(kd, (uintptr_t)&kd->kvm_proc.p_pidp->pid_id, 409 &kd->kvm_pid, sizeof (pid_t)) != sizeof (pid_t)) 410 return (NULL); 411 412 return (&kd->kvm_proc); 413 } 414 415 int 416 kvm_setproc(kvm_t *kd) 417 { 418 (void) kvm_kread(kd, (uintptr_t)kd->kvm_practive, 419 &kd->kvm_proc.p_next, sizeof (proc_t *)); 420 kd->kvm_pid = -1; 421 return (0); 422 } 423 424 /*ARGSUSED*/ 425 struct user * 426 kvm_getu(kvm_t *kd, struct proc *p) 427 { 428 return (&p->p_user); 429 } 430