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 (c) 1996-1998 by Sun Microsystems, Inc. 24 * All rights reserved. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <unistd.h> 30 #include <string.h> 31 #include <stdlib.h> 32 #include <stdio.h> 33 #include <ctype.h> 34 35 #include "kvm.h" 36 37 #include <nlist.h> 38 #include <sys/thread.h> 39 #include <sys/fcntl.h> 40 #include <sys/param.h> 41 #include <sys/user.h> 42 #include <sys/proc.h> 43 #include <sys/elf.h> 44 45 #ifdef __sparc 46 #include <sys/stack.h> /* for STACK_BIAS */ 47 #else 48 #define STACK_BIAS 0 49 #endif 50 51 kvm_t *cookie; 52 53 struct proc *tst_getproc(pid_t); 54 struct proc *tst_nextproc(void); 55 struct user *tst_getu(struct proc *); 56 int tst_setproc(void); 57 int tst_getcmd(struct proc *, struct user *); 58 void tst_segkp(void); 59 void tst_nlist(struct nlist nl[]); 60 void tst_open(char *, char *, char *, int); 61 void tst_close(void); 62 ssize_t tst_read(uintptr_t, void *, size_t); 63 ssize_t tst_write(uintptr_t, void *, size_t); 64 int tst_getcmd(struct proc *, struct user *); 65 void tst_segkvp(void); 66 67 char *name; 68 char *core; 69 char *swap; 70 int wflag; 71 72 struct nlist nl[] = { 73 {"free"}, 74 {"fragtbl"}, 75 {"freemem"}, 76 {"allthreads"}, 77 {"nbuckets"}, 78 {"cputype"}, 79 {0} 80 }; 81 82 int 83 main(int argc, char *argv[], char *envp[]) 84 { 85 int c, errflg = 0; 86 long xx; 87 struct nlist *nlp; 88 struct proc *proc; 89 struct user *u; 90 int envc, ccnt; 91 92 for (envc = 0; *envp++ != NULL; envc++) 93 continue; 94 envp -= 2; 95 ccnt = (*envp - *argv) + strlen(*envp) + 1; 96 printf("pid %d:: %d args; %d envs; %d chars (%p - %p)\n", 97 getpid(), argc, envc, ccnt, 98 &argv[0], *envp + strlen(*envp)); 99 100 while ((c = getopt(argc, argv, "w")) != EOF) 101 switch (c) { 102 case 'w': 103 wflag++; 104 break; 105 case '?': 106 errflg++; 107 } 108 if (errflg) { 109 fprintf(stderr, "usage: %s [-w] [name] [core] [swap]\n", 110 argv[0]); 111 return (2); 112 } 113 if (optind < argc) { 114 name = argv[optind++]; 115 if (*name == '\0') 116 name = NULL; 117 } else 118 name = NULL; 119 if (optind < argc) { 120 core = argv[optind++]; 121 if (*core == '\0') 122 core = NULL; 123 } else 124 core = NULL; 125 if (optind < argc) { 126 swap = argv[optind++]; 127 if (*swap == '\0') 128 swap = NULL; 129 } else 130 swap = NULL; 131 132 tst_open(name, core, swap, (wflag ? O_RDWR : O_RDONLY)); 133 if (cookie == NULL) 134 return (1); 135 136 tst_nlist(nl); 137 138 for (nlp = nl; nlp[0].n_type != 0; nlp++) 139 tst_read(nlp[0].n_value, &xx, sizeof (xx)); 140 141 while ((proc = tst_nextproc()) != NULL) { 142 struct pid pid; 143 if (kvm_read(cookie, (uintptr_t)proc->p_pidp, &pid, 144 sizeof (pid)) != sizeof (pid)) { 145 printf("ERROR: couldn't get pid\n"); 146 break; 147 } 148 tst_getproc(pid.pid_id); 149 } 150 151 tst_setproc(); 152 153 while ((proc = tst_nextproc()) != NULL) { 154 if ((u = tst_getu(proc)) != NULL) 155 (void) tst_getcmd(proc, u); 156 } 157 158 tst_segkp(); 159 tst_close(); 160 161 return (0); 162 } 163 164 void 165 tst_open(char *namelist, char *corefile, char *swapfile, int flag) 166 { 167 printf("kvm_open(%s, %s, %s, %s)\n", 168 (namelist == NULL) ? "LIVE_KERNEL" : namelist, 169 (corefile == NULL) ? "LIVE_KERNEL" : corefile, 170 (swapfile == NULL) ? 171 ((corefile == NULL) ? "LIVE_KERNEL" : "(none)") : swapfile, 172 (flag == O_RDONLY) ? "O_RDONLY" : ((flag == O_RDWR) ? 173 "O_RDWR" : "???")); 174 175 if ((cookie = kvm_open(namelist, corefile, 176 swapfile, flag, "libkvm test")) == NULL) 177 printf("ERROR: kvm_open returned %p\n", cookie); 178 } 179 180 void 181 tst_close(void) 182 { 183 int i; 184 185 printf("kvm_close()\n"); 186 if ((i = kvm_close(cookie)) != 0) 187 printf("ERROR: kvm_close returned %d\n", i); 188 } 189 190 void 191 tst_nlist(struct nlist nl[]) 192 { 193 int i; 194 char *t, *s; 195 196 printf("kvm_nlist([nl])\n"); 197 if ((i = kvm_nlist(cookie, nl)) != 0) 198 printf("ERROR: kvm_nlist returned %d\n", i); 199 for (i = 0; nl[i].n_name != 0 && nl[i].n_name[0] != '\0'; i++) { 200 /* 201 * Debug: 202 * n_value gets filled in with st_value, 203 * n_type gets filled in w/ELF32_ST_TYPE(sym->st_info) 204 * n_scnum gets filled in w/st_shndx 205 */ 206 switch (nl[i].n_type) { 207 case STT_NOTYPE: 208 t = "NOTYPE"; 209 break; 210 case STT_OBJECT: 211 t = "OBJECT"; 212 break; 213 case STT_FUNC: 214 t = "FUNC"; 215 break; 216 case STT_SECTION: 217 t = "SECTION"; 218 break; 219 case STT_FILE: 220 t = "FILE"; 221 break; 222 case STT_NUM: 223 t = "NUM"; 224 break; 225 default: 226 t = "???"; 227 } 228 229 switch ((unsigned)nl[i].n_scnum) { 230 static char strbuf[40]; 231 232 case SHN_UNDEF: 233 s = "UNDEF"; 234 break; 235 case SHN_LORESERVE: 236 s = "LORESERVE"; 237 break; 238 case SHN_ABS: 239 s = "ABS"; 240 break; 241 case SHN_COMMON: 242 s = "COMMON"; 243 break; 244 case SHN_HIRESERVE: 245 s = "HIRESERVE"; 246 break; 247 default: 248 (void) sprintf(strbuf, "unknown (%d)", nl[i].n_scnum); 249 s = strbuf; 250 break; 251 } 252 253 printf("%s: %lx (%s, %s)\n", 254 nl[i].n_name, nl[i].n_value, s, t); 255 } 256 } 257 258 ssize_t 259 tst_read(uintptr_t addr, void *buf, size_t nbytes) 260 { 261 ssize_t e; 262 int i; 263 char *b; 264 265 printf("kvm_read(%lx, [buf], %lu)\n", addr, nbytes); 266 if ((e = kvm_read(cookie, addr, buf, nbytes)) != nbytes) 267 printf("ERROR: kvm_read returned %ld instead of %lu\n", 268 e, nbytes); 269 for (b = buf, i = 0; i < nbytes; b++, i++) 270 printf("%lx: %02x (%04o)\n", addr + i, 271 *b & 0xff, *b & 0xff); 272 273 return (e); 274 } 275 276 ssize_t 277 tst_write(uintptr_t addr, void *buf, size_t nbytes) 278 { 279 ssize_t e; 280 ssize_t i; 281 void *b; 282 283 printf("kvm_write(%lx, [buf], %lu)\n", addr, nbytes); 284 if ((e = kvm_write(cookie, addr, buf, nbytes)) != nbytes) 285 printf("ERROR: kvm_write returned %ld instead of %lu\n", 286 e, nbytes); 287 if ((b = malloc(nbytes)) == 0) 288 printf("ERROR: malloc for readback failed\n"); 289 else { 290 if ((i = kvm_read(cookie, addr, b, nbytes)) != nbytes) 291 printf("ERROR: readback returned %ld\n", i); 292 else if (memcmp(b, buf, nbytes)) 293 printf("ERROR: write check failed!\n"); 294 (void) free(b); 295 } 296 return (e); 297 } 298 299 struct proc * 300 tst_getproc(pid_t pid) 301 { 302 struct proc *proc; 303 struct pid pidbuf; 304 305 printf("kvm_getproc(%d)\n", pid); 306 if ((proc = kvm_getproc(cookie, pid)) == NULL) { 307 printf("ERROR: kvm_getproc returned NULL\n"); 308 return (proc); 309 } 310 311 if (kvm_read(cookie, (uintptr_t)proc->p_pidp, &pidbuf, 312 sizeof (pidbuf)) != sizeof (pidbuf)) { 313 printf("ERROR: couldn't get pid\n"); 314 return (proc); 315 } 316 317 printf("p_pid: %d\n", pidbuf.pid_id); 318 return (proc); 319 } 320 321 struct proc * 322 tst_nextproc(void) 323 { 324 struct proc *proc; 325 struct pid pidbuf; 326 327 printf("kvm_nextproc()\n"); 328 if ((proc = kvm_nextproc(cookie)) == NULL) { 329 printf("kvm_nextproc returned NULL\n"); 330 return (proc); 331 } 332 333 /* 334 * p_pid is now a macro which turns into a ptr dereference; 335 * must do a kvm_read to get contents. 336 */ 337 if (kvm_read(cookie, (u_long)proc->p_pidp, (char *)&pidbuf, 338 sizeof (struct pid)) != sizeof (struct pid)) { 339 printf("ERROR: couldn't get pid\n"); 340 } 341 printf("p_pid: %d\n", pidbuf.pid_id); 342 343 return (proc); 344 } 345 346 int 347 tst_setproc(void) 348 { 349 int i; 350 351 printf("kvm_setproc()\n"); 352 if ((i = kvm_setproc(cookie)) != 0) 353 printf("ERROR: kvm_setproc returned %d\n", i); 354 return (i); 355 } 356 357 struct user * 358 tst_getu(struct proc *proc) 359 { 360 register int e; 361 struct proc tp; 362 struct user *u; 363 struct pid pidbuf; 364 365 if (kvm_read(cookie, (uintptr_t)proc->p_pidp, &pidbuf, 366 sizeof (pidbuf)) != sizeof (pidbuf)) 367 printf("ERROR: couldn't get pid\n"); 368 369 printf("kvm_getu(pid:%d)\n", pidbuf.pid_id); 370 if ((u = kvm_getu(cookie, proc)) == NULL) 371 printf("ERROR: kvm_getu returned NULL\n"); 372 return (u); 373 } 374 375 static void 376 safe_printf(const char *s) 377 { 378 char buf[BUFSIZ], *p; 379 380 (void) strncpy(buf, s, BUFSIZ - 1); 381 buf[BUFSIZ - 1] = '\0'; 382 383 for (p = buf; *p != '\0'; p++) { 384 if (!isprint(*p)) 385 *p = ' '; 386 } 387 388 (void) printf("\"%s\"\n", buf); 389 } 390 391 int 392 tst_getcmd(struct proc *proc, struct user *u) 393 { 394 char **arg; 395 char **env; 396 int i; 397 char **p; 398 struct pid pidbuf; 399 400 if (kvm_kread(cookie, (uintptr_t)proc->p_pidp, &pidbuf, 401 sizeof (pidbuf)) != sizeof (pidbuf)) { 402 printf("ERROR: couldn't get pid\n"); 403 return (-1); 404 } 405 406 printf("kvm_getcmd(pid:%d, [u], arg, env)\n", pidbuf.pid_id); 407 if ((i = kvm_getcmd(cookie, proc, u, &arg, &env)) != 0) { 408 printf("kvm_getcmd returned %d\n", i); 409 return (i); 410 } 411 412 printf("Args: "); 413 for (p = arg; *p != NULL; p++) 414 safe_printf(*p); 415 printf("Env: "); 416 for (p = env; *p != NULL; p++) 417 safe_printf(*p); 418 419 (void) free(arg); 420 (void) free(env); 421 422 return (0); 423 } 424 425 void 426 tst_segkp(void) 427 { 428 kthread_t t; 429 caddr_t tp, alltp; 430 uintptr_t stk[16]; 431 int i; 432 433 if (kvm_read(cookie, nl[3].n_value, &alltp, sizeof (alltp)) 434 != sizeof (alltp)) { 435 printf("ERROR: couldn't read allthread, addr 0x%lx\n", 436 nl[3].n_value); 437 return; 438 } 439 printf("allthreads 0x%lx\n", nl[3].n_value); 440 printf("next offset 0x%lx\n", 441 (uintptr_t)&(t.t_next) - (uintptr_t)&t); 442 443 for (tp = alltp; tp; tp = (caddr_t)(t.t_next)) { 444 if (kvm_read(cookie, 445 (uintptr_t)tp, &t, sizeof (t)) != sizeof (t)) { 446 printf("ERROR: couldn't read thread, addr 0x%p\n", tp); 447 return; 448 } 449 450 printf("thread 0x%p\n", tp); 451 printf("\tstk 0x%p sp 0x%lx tid %d next 0x%p prev 0x%p\n", 452 tp, t.t_stk, t.t_pcb.val[1], t.t_tid, t.t_next, t.t_prev); 453 454 if (kvm_read(cookie, t.t_pcb.val[1] + STACK_BIAS, stk, 455 sizeof (stk)) != sizeof (stk)) { 456 printf("ERROR: couldn't read stack, taddr 0x%p\n", tp); 457 continue; 458 } 459 for (i = 0; i < 16; i++) { 460 printf("%-16lx ", stk[i]); 461 if (((i + 1) % 4) == 0) 462 printf("\n"); 463 } 464 465 if ((caddr_t)(t.t_next) == alltp) 466 break; 467 } 468 } 469