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