/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 1996-1998 by Sun Microsystems, Inc. * All rights reserved. */ #include #include #include #include #include #include "kvm.h" #include #include #include #include #include #include #include #ifdef __sparc #include /* for STACK_BIAS */ #else #define STACK_BIAS 0 #endif kvm_t *cookie; struct proc *tst_getproc(pid_t); struct proc *tst_nextproc(void); struct user *tst_getu(struct proc *); int tst_setproc(void); int tst_getcmd(struct proc *, struct user *); void tst_segkp(void); void tst_nlist(struct nlist nl[]); void tst_open(char *, char *, char *, int); void tst_close(void); ssize_t tst_read(uintptr_t, void *, size_t); ssize_t tst_write(uintptr_t, void *, size_t); int tst_getcmd(struct proc *, struct user *); void tst_segkvp(void); char *name; char *core; char *swap; int wflag; struct nlist nl[] = { {"free"}, {"fragtbl"}, {"freemem"}, {"allthreads"}, {"nbuckets"}, {"cputype"}, {0} }; int main(int argc, char *argv[], char *envp[]) { int c, errflg = 0; long xx; struct nlist *nlp; struct proc *proc; struct user *u; int envc, ccnt; for (envc = 0; *envp++ != NULL; envc++) continue; envp -= 2; ccnt = (*envp - *argv) + strlen(*envp) + 1; printf("pid %d:: %d args; %d envs; %d chars (%p - %p)\n", getpid(), argc, envc, ccnt, &argv[0], *envp + strlen(*envp)); while ((c = getopt(argc, argv, "w")) != EOF) switch (c) { case 'w': wflag++; break; case '?': errflg++; } if (errflg) { fprintf(stderr, "usage: %s [-w] [name] [core] [swap]\n", argv[0]); return (2); } if (optind < argc) { name = argv[optind++]; if (*name == '\0') name = NULL; } else name = NULL; if (optind < argc) { core = argv[optind++]; if (*core == '\0') core = NULL; } else core = NULL; if (optind < argc) { swap = argv[optind++]; if (*swap == '\0') swap = NULL; } else swap = NULL; tst_open(name, core, swap, (wflag ? O_RDWR : O_RDONLY)); if (cookie == NULL) return (1); tst_nlist(nl); for (nlp = nl; nlp[0].n_type != 0; nlp++) tst_read(nlp[0].n_value, &xx, sizeof (xx)); while ((proc = tst_nextproc()) != NULL) { struct pid pid; if (kvm_read(cookie, (uintptr_t)proc->p_pidp, &pid, sizeof (pid)) != sizeof (pid)) { printf("ERROR: couldn't get pid\n"); break; } tst_getproc(pid.pid_id); } tst_setproc(); while ((proc = tst_nextproc()) != NULL) { if ((u = tst_getu(proc)) != NULL) (void) tst_getcmd(proc, u); } tst_segkp(); tst_close(); return (0); } void tst_open(char *namelist, char *corefile, char *swapfile, int flag) { printf("kvm_open(%s, %s, %s, %s)\n", (namelist == NULL) ? "LIVE_KERNEL" : namelist, (corefile == NULL) ? "LIVE_KERNEL" : corefile, (swapfile == NULL) ? ((corefile == NULL) ? "LIVE_KERNEL" : "(none)") : swapfile, (flag == O_RDONLY) ? "O_RDONLY" : ((flag == O_RDWR) ? "O_RDWR" : "???")); if ((cookie = kvm_open(namelist, corefile, swapfile, flag, "libkvm test")) == NULL) printf("ERROR: kvm_open returned %p\n", cookie); } void tst_close(void) { int i; printf("kvm_close()\n"); if ((i = kvm_close(cookie)) != 0) printf("ERROR: kvm_close returned %d\n", i); } void tst_nlist(struct nlist nl[]) { int i; char *t, *s; printf("kvm_nlist([nl])\n"); if ((i = kvm_nlist(cookie, nl)) != 0) printf("ERROR: kvm_nlist returned %d\n", i); for (i = 0; nl[i].n_name != 0 && nl[i].n_name[0] != '\0'; i++) { /* * Debug: * n_value gets filled in with st_value, * n_type gets filled in w/ELF32_ST_TYPE(sym->st_info) * n_scnum gets filled in w/st_shndx */ switch (nl[i].n_type) { case STT_NOTYPE: t = "NOTYPE"; break; case STT_OBJECT: t = "OBJECT"; break; case STT_FUNC: t = "FUNC"; break; case STT_SECTION: t = "SECTION"; break; case STT_FILE: t = "FILE"; break; case STT_NUM: t = "NUM"; break; default: t = "???"; } switch ((unsigned)nl[i].n_scnum) { static char strbuf[40]; case SHN_UNDEF: s = "UNDEF"; break; case SHN_LORESERVE: s = "LORESERVE"; break; case SHN_ABS: s = "ABS"; break; case SHN_COMMON: s = "COMMON"; break; case SHN_HIRESERVE: s = "HIRESERVE"; break; default: (void) sprintf(strbuf, "unknown (%d)", nl[i].n_scnum); s = strbuf; break; } printf("%s: %lx (%s, %s)\n", nl[i].n_name, nl[i].n_value, s, t); } } ssize_t tst_read(uintptr_t addr, void *buf, size_t nbytes) { ssize_t e; int i; char *b; printf("kvm_read(%lx, [buf], %lu)\n", addr, nbytes); if ((e = kvm_read(cookie, addr, buf, nbytes)) != nbytes) printf("ERROR: kvm_read returned %ld instead of %lu\n", e, nbytes); for (b = buf, i = 0; i < nbytes; b++, i++) printf("%lx: %02x (%04o)\n", addr + i, *b & 0xff, *b & 0xff); return (e); } ssize_t tst_write(uintptr_t addr, void *buf, size_t nbytes) { ssize_t e; ssize_t i; void *b; printf("kvm_write(%lx, [buf], %lu)\n", addr, nbytes); if ((e = kvm_write(cookie, addr, buf, nbytes)) != nbytes) printf("ERROR: kvm_write returned %ld instead of %lu\n", e, nbytes); if ((b = malloc(nbytes)) == 0) printf("ERROR: malloc for readback failed\n"); else { if ((i = kvm_read(cookie, addr, b, nbytes)) != nbytes) printf("ERROR: readback returned %ld\n", i); else if (memcmp(b, buf, nbytes)) printf("ERROR: write check failed!\n"); (void) free(b); } return (e); } struct proc * tst_getproc(pid_t pid) { struct proc *proc; struct pid pidbuf; printf("kvm_getproc(%d)\n", pid); if ((proc = kvm_getproc(cookie, pid)) == NULL) { printf("ERROR: kvm_getproc returned NULL\n"); return (proc); } if (kvm_read(cookie, (uintptr_t)proc->p_pidp, &pidbuf, sizeof (pidbuf)) != sizeof (pidbuf)) { printf("ERROR: couldn't get pid\n"); return (proc); } printf("p_pid: %d\n", pidbuf.pid_id); return (proc); } struct proc * tst_nextproc(void) { struct proc *proc; struct pid pidbuf; printf("kvm_nextproc()\n"); if ((proc = kvm_nextproc(cookie)) == NULL) { printf("kvm_nextproc returned NULL\n"); return (proc); } /* * p_pid is now a macro which turns into a ptr dereference; * must do a kvm_read to get contents. */ if (kvm_read(cookie, (u_long)proc->p_pidp, (char *)&pidbuf, sizeof (struct pid)) != sizeof (struct pid)) { printf("ERROR: couldn't get pid\n"); } printf("p_pid: %d\n", pidbuf.pid_id); return (proc); } int tst_setproc(void) { int i; printf("kvm_setproc()\n"); if ((i = kvm_setproc(cookie)) != 0) printf("ERROR: kvm_setproc returned %d\n", i); return (i); } struct user * tst_getu(struct proc *proc) { register int e; struct proc tp; struct user *u; struct pid pidbuf; if (kvm_read(cookie, (uintptr_t)proc->p_pidp, &pidbuf, sizeof (pidbuf)) != sizeof (pidbuf)) printf("ERROR: couldn't get pid\n"); printf("kvm_getu(pid:%d)\n", pidbuf.pid_id); if ((u = kvm_getu(cookie, proc)) == NULL) printf("ERROR: kvm_getu returned NULL\n"); return (u); } static void safe_printf(const char *s) { char buf[BUFSIZ], *p; (void) strncpy(buf, s, BUFSIZ - 1); buf[BUFSIZ - 1] = '\0'; for (p = buf; *p != '\0'; p++) { if (!isprint(*p)) *p = ' '; } (void) printf("\"%s\"\n", buf); } int tst_getcmd(struct proc *proc, struct user *u) { char **arg; char **env; int i; char **p; struct pid pidbuf; if (kvm_kread(cookie, (uintptr_t)proc->p_pidp, &pidbuf, sizeof (pidbuf)) != sizeof (pidbuf)) { printf("ERROR: couldn't get pid\n"); return (-1); } printf("kvm_getcmd(pid:%d, [u], arg, env)\n", pidbuf.pid_id); if ((i = kvm_getcmd(cookie, proc, u, &arg, &env)) != 0) { printf("kvm_getcmd returned %d\n", i); return (i); } printf("Args: "); for (p = arg; *p != NULL; p++) safe_printf(*p); printf("Env: "); for (p = env; *p != NULL; p++) safe_printf(*p); (void) free(arg); (void) free(env); return (0); } void tst_segkp(void) { kthread_t t; caddr_t tp, alltp; uintptr_t stk[16]; int i; if (kvm_read(cookie, nl[3].n_value, &alltp, sizeof (alltp)) != sizeof (alltp)) { printf("ERROR: couldn't read allthread, addr 0x%lx\n", nl[3].n_value); return; } printf("allthreads 0x%lx\n", nl[3].n_value); printf("next offset 0x%lx\n", (uintptr_t)&(t.t_next) - (uintptr_t)&t); for (tp = alltp; tp; tp = (caddr_t)(t.t_next)) { if (kvm_read(cookie, (uintptr_t)tp, &t, sizeof (t)) != sizeof (t)) { printf("ERROR: couldn't read thread, addr 0x%p\n", tp); return; } printf("thread 0x%p\n", tp); printf("\tstk 0x%p sp 0x%lx tid %d next 0x%p prev 0x%p\n", tp, t.t_stk, t.t_pcb.val[1], t.t_tid, t.t_next, t.t_prev); if (kvm_read(cookie, t.t_pcb.val[1] + STACK_BIAS, stk, sizeof (stk)) != sizeof (stk)) { printf("ERROR: couldn't read stack, taddr 0x%p\n", tp); continue; } for (i = 0; i < 16; i++) { printf("%-16lx ", stk[i]); if (((i + 1) % 4) == 0) printf("\n"); } if ((caddr_t)(t.t_next) == alltp) break; } }