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
main(int argc,char * argv[],char * envp[])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
tst_open(char * namelist,char * corefile,char * swapfile,int flag)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
tst_close(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
tst_nlist(struct nlist nl[])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
tst_read(uintptr_t addr,void * buf,size_t nbytes)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
tst_write(uintptr_t addr,void * buf,size_t nbytes)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 *
tst_getproc(pid_t pid)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 *
tst_nextproc(void)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
tst_setproc(void)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 *
tst_getu(struct proc * proc)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
safe_printf(const char * s)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
tst_getcmd(struct proc * proc,struct user * u)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
tst_segkp(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