| Commit | Line | Data |
|---|---|---|
| 984263bc MD |
1 | /*- |
| 2 | * Copyright (c) 1989, 1992, 1993 | |
| 3 | * The Regents of the University of California. All rights reserved. | |
| 4 | * | |
| 5 | * This code is derived from software developed by the Computer Systems | |
| 6 | * Engineering group at Lawrence Berkeley Laboratory under DARPA contract | |
| 7 | * BG 91-66 and contributed to Berkeley. | |
| 8 | * | |
| 9 | * Redistribution and use in source and binary forms, with or without | |
| 10 | * modification, are permitted provided that the following conditions | |
| 11 | * are met: | |
| 12 | * 1. Redistributions of source code must retain the above copyright | |
| 13 | * notice, this list of conditions and the following disclaimer. | |
| 14 | * 2. Redistributions in binary form must reproduce the above copyright | |
| 15 | * notice, this list of conditions and the following disclaimer in the | |
| 16 | * documentation and/or other materials provided with the distribution. | |
| 17 | * 3. All advertising materials mentioning features or use of this software | |
| 18 | * must display the following acknowledgement: | |
| 19 | * This product includes software developed by the University of | |
| 20 | * California, Berkeley and its contributors. | |
| 21 | * 4. Neither the name of the University nor the names of its contributors | |
| 22 | * may be used to endorse or promote products derived from this software | |
| 23 | * without specific prior written permission. | |
| 24 | * | |
| 25 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
| 26 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| 27 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
| 28 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
| 29 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
| 30 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
| 31 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| 32 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| 33 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
| 34 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| 35 | * SUCH DAMAGE. | |
| 36 | * | |
| 37 | * $FreeBSD: src/lib/libkvm/kvm_proc.c,v 1.25.2.3 2002/08/24 07:27:46 kris Exp $ | |
| 3641b7ca | 38 | * $DragonFly: src/lib/libkvm/kvm_proc.c,v 1.18 2008/06/05 18:06:30 swildner Exp $ |
| 1de703da MD |
39 | * |
| 40 | * @(#)kvm_proc.c 8.3 (Berkeley) 9/23/93 | |
| 984263bc MD |
41 | */ |
| 42 | ||
| 984263bc MD |
43 | /* |
| 44 | * Proc traversal interface for kvm. ps and w are (probably) the exclusive | |
| 45 | * users of this code, so we've factored it out into a separate module. | |
| 46 | * Thus, we keep this grunge out of the other kvm applications (i.e., | |
| 47 | * most other applications are interested only in open/close/read/nlist). | |
| 48 | */ | |
| 49 | ||
| 9f17b787 | 50 | #include <sys/user.h> /* MUST BE FIRST */ |
| b13267a5 MD |
51 | #include <sys/conf.h> |
| 52 | #include <sys/param.h> | |
| 984263bc MD |
53 | #include <sys/proc.h> |
| 54 | #include <sys/exec.h> | |
| 55 | #include <sys/stat.h> | |
| e42f5937 | 56 | #include <sys/globaldata.h> |
| 984263bc MD |
57 | #include <sys/ioctl.h> |
| 58 | #include <sys/tty.h> | |
| 59 | #include <sys/file.h> | |
| 5dfd06ac | 60 | #include <sys/jail.h> |
| 984263bc MD |
61 | #include <stdio.h> |
| 62 | #include <stdlib.h> | |
| 63 | #include <unistd.h> | |
| 64 | #include <nlist.h> | |
| 65 | #include <kvm.h> | |
| 66 | ||
| 67 | #include <vm/vm.h> | |
| 68 | #include <vm/vm_param.h> | |
| 69 | #include <vm/swap_pager.h> | |
| 70 | ||
| 71 | #include <sys/sysctl.h> | |
| 72 | ||
| 73 | #include <limits.h> | |
| 74 | #include <memory.h> | |
| 75 | #include <paths.h> | |
| 76 | ||
| 77 | #include "kvm_private.h" | |
| 78 | ||
| 79 | #if used | |
| 80 | static char * | |
| 576a9733 | 81 | kvm_readswap(kvm_t *kd, const struct proc *p, u_long va, u_long *cnt) |
| 984263bc | 82 | { |
| e5a620e1 | 83 | #if defined(__FreeBSD__) || defined(__DragonFly__) |
| 984263bc MD |
84 | /* XXX Stubbed out, our vm system is differnet */ |
| 85 | _kvm_err(kd, kd->program, "kvm_readswap not implemented"); | |
| 86 | return(0); | |
| e5a620e1 | 87 | #endif |
| 984263bc MD |
88 | } |
| 89 | #endif | |
| 90 | ||
| 91 | #define KREAD(kd, addr, obj) \ | |
| 92 | (kvm_read(kd, addr, (char *)(obj), sizeof(*obj)) != sizeof(*obj)) | |
| e42f5937 MD |
93 | #define KREADSTR(kd, addr) \ |
| 94 | kvm_readstr(kd, (u_long)addr, NULL, NULL) | |
| 5dfd06ac SS |
95 | |
| 96 | static struct kinfo_proc * | |
| 97 | kinfo_resize_proc(kvm_t *kd, struct kinfo_proc *bp) | |
| 98 | { | |
| 99 | if (bp < kd->procend) | |
| 100 | return bp; | |
| 101 | ||
| 102 | size_t pos = bp - kd->procend; | |
| 103 | size_t size = kd->procend - kd->procbase; | |
| 104 | ||
| 105 | if (size == 0) | |
| 106 | size = 8; | |
| 107 | else | |
| 108 | size *= 2; | |
| 109 | kd->procbase = _kvm_realloc(kd, kd->procbase, sizeof(*bp) * size); | |
| 110 | if (kd->procbase == NULL) | |
| 111 | return NULL; | |
| 112 | kd->procend = kd->procbase + size; | |
| 113 | bp = kd->procbase + pos; | |
| 114 | return bp; | |
| 115 | } | |
| 116 | ||
| 984263bc | 117 | /* |
| c15b1d97 MD |
118 | * note: this function is also used by /usr/src/sys/kern/kern_kinfo.c as |
| 119 | * compiled by userland. | |
| 120 | */ | |
| 121 | dev_t | |
| 122 | dev2udev(cdev_t dev) | |
| 123 | { | |
| 124 | if (dev == NULL) | |
| 125 | return NOUDEV; | |
| 126 | if ((dev->si_umajor & 0xffffff00) || | |
| 127 | (dev->si_uminor & 0x0000ff00)) { | |
| 128 | return NOUDEV; | |
| 129 | } | |
| 130 | return((dev->si_umajor << 8) | dev->si_uminor); | |
| 131 | } | |
| 132 | ||
| e42f5937 MD |
133 | /* |
| 134 | * Helper routine which traverses the left hand side of a red-black sub-tree. | |
| 135 | */ | |
| 136 | static uintptr_t | |
| 137 | kvm_lwptraverse(kvm_t *kd, struct lwp *lwp, uintptr_t lwppos) | |
| 138 | { | |
| 139 | for (;;) { | |
| 140 | if (KREAD(kd, lwppos, lwp)) { | |
| 141 | _kvm_err(kd, kd->program, "can't read lwp at %p", | |
| 142 | (void *)lwppos); | |
| 143 | return ((uintptr_t)-1); | |
| 144 | } | |
| 145 | if (lwp->u.lwp_rbnode.rbe_left == NULL) | |
| 146 | break; | |
| 147 | lwppos = (uintptr_t)lwp->u.lwp_rbnode.rbe_left; | |
| 148 | } | |
| 149 | return(lwppos); | |
| 150 | } | |
| 151 | ||
| 152 | /* | |
| 153 | * Iterate LWPs in a process. | |
| 154 | * | |
| 155 | * The first lwp in a red-black tree is a left-side traversal of the tree. | |
| 156 | */ | |
| 157 | static uintptr_t | |
| 158 | kvm_firstlwp(kvm_t *kd, struct lwp *lwp, struct proc *proc) | |
| 159 | { | |
| 160 | return(kvm_lwptraverse(kd, lwp, (uintptr_t)proc->p_lwp_tree.rbh_root)); | |
| 161 | } | |
| 162 | ||
| 163 | /* | |
| 164 | * If the current element is the left side of the parent the next element | |
| 165 | * will be a left side traversal of the parent's right side. If the parent | |
| 166 | * has no right side the next element will be the parent. | |
| 167 | * | |
| 168 | * If the current element is the right side of the parent the next element | |
| 169 | * is the parent. | |
| 170 | * | |
| 171 | * If the parent is NULL we are done. | |
| 172 | */ | |
| 173 | static uintptr_t | |
| 174 | kvm_nextlwp(kvm_t *kd, uintptr_t lwppos, struct lwp *lwp, struct proc *proc) | |
| 175 | { | |
| 176 | uintptr_t nextpos; | |
| 177 | ||
| 178 | nextpos = (uintptr_t)lwp->u.lwp_rbnode.rbe_parent; | |
| 179 | if (nextpos) { | |
| 180 | if (KREAD(kd, nextpos, lwp)) { | |
| 181 | _kvm_err(kd, kd->program, "can't read lwp at %p", | |
| 182 | (void *)lwppos); | |
| 183 | return ((uintptr_t)-1); | |
| 184 | } | |
| 185 | if (lwppos == (uintptr_t)lwp->u.lwp_rbnode.rbe_left) { | |
| 186 | /* | |
| 187 | * If we had gone down the left side the next element | |
| 188 | * is a left hand traversal of the parent's right | |
| 189 | * side, or the parent itself if there is no right | |
| 190 | * side. | |
| 191 | */ | |
| 192 | lwppos = (uintptr_t)lwp->u.lwp_rbnode.rbe_right; | |
| 193 | if (lwppos) | |
| 194 | nextpos = kvm_lwptraverse(kd, lwp, lwppos); | |
| 195 | } else { | |
| 196 | /* | |
| 197 | * If we had gone down the right side the next | |
| 198 | * element is the parent. | |
| 199 | */ | |
| 200 | /* nextpos = nextpos */ | |
| 201 | } | |
| 202 | } | |
| 203 | return(nextpos); | |
| 204 | } | |
| c15b1d97 MD |
205 | |
| 206 | /* | |
| 984263bc MD |
207 | * Read proc's from memory file into buffer bp, which has space to hold |
| 208 | * at most maxcnt procs. | |
| 209 | */ | |
| 210 | static int | |
| 576a9733 | 211 | kvm_proclist(kvm_t *kd, int what, int arg, struct proc *p, |
| 5dfd06ac | 212 | struct kinfo_proc *bp) |
| 984263bc | 213 | { |
| 984263bc | 214 | struct pgrp pgrp; |
| 5dfd06ac | 215 | struct pgrp tpgrp; |
| e42f5937 | 216 | struct globaldata gdata; |
| 984263bc | 217 | struct session sess; |
| e42f5937 | 218 | struct session tsess; |
| 984263bc MD |
219 | struct tty tty; |
| 220 | struct proc proc; | |
| 5dfd06ac | 221 | struct ucred ucred; |
| 17c88c3a | 222 | struct thread thread; |
| 984263bc | 223 | struct proc pproc; |
| b13267a5 | 224 | struct cdev cdev; |
| 5dfd06ac SS |
225 | struct vmspace vmspace; |
| 226 | struct prison prison; | |
| e42f5937 | 227 | struct sigacts sigacts; |
| 5dfd06ac SS |
228 | struct lwp lwp; |
| 229 | uintptr_t lwppos; | |
| e42f5937 MD |
230 | int count; |
| 231 | char *wmesg; | |
| 232 | ||
| 233 | count = 0; | |
| 984263bc | 234 | |
| 5dfd06ac | 235 | for (; p != NULL; p = proc.p_list.le_next) { |
| 984263bc | 236 | if (KREAD(kd, (u_long)p, &proc)) { |
| b58f1e66 | 237 | _kvm_err(kd, kd->program, "can't read proc at %p", p); |
| 984263bc MD |
238 | return (-1); |
| 239 | } | |
| 5dfd06ac SS |
240 | if (KREAD(kd, (u_long)proc.p_ucred, &ucred)) { |
| 241 | _kvm_err(kd, kd->program, "can't read ucred at %p", | |
| 242 | proc.p_ucred); | |
| 17c88c3a MD |
243 | return (-1); |
| 244 | } | |
| 5dfd06ac | 245 | proc.p_ucred = &ucred; |
| 984263bc | 246 | |
| 5dfd06ac | 247 | switch(what & ~KERN_PROC_FLAGMASK) { |
| 984263bc MD |
248 | |
| 249 | case KERN_PROC_PID: | |
| 250 | if (proc.p_pid != (pid_t)arg) | |
| 251 | continue; | |
| 252 | break; | |
| 253 | ||
| 254 | case KERN_PROC_UID: | |
| 5dfd06ac | 255 | if (ucred.cr_uid != (uid_t)arg) |
| 984263bc MD |
256 | continue; |
| 257 | break; | |
| 258 | ||
| 259 | case KERN_PROC_RUID: | |
| 5dfd06ac | 260 | if (ucred.cr_ruid != (uid_t)arg) |
| 984263bc MD |
261 | continue; |
| 262 | break; | |
| 263 | } | |
| 5dfd06ac | 264 | |
| 984263bc | 265 | if (KREAD(kd, (u_long)proc.p_pgrp, &pgrp)) { |
| b58f1e66 | 266 | _kvm_err(kd, kd->program, "can't read pgrp at %p", |
| 984263bc MD |
267 | proc.p_pgrp); |
| 268 | return (-1); | |
| 269 | } | |
| 5dfd06ac SS |
270 | proc.p_pgrp = &pgrp; |
| 271 | if (proc.p_pptr) { | |
| 984263bc | 272 | if (KREAD(kd, (u_long)proc.p_pptr, &pproc)) { |
| b58f1e66 | 273 | _kvm_err(kd, kd->program, "can't read pproc at %p", |
| 984263bc MD |
274 | proc.p_pptr); |
| 275 | return (-1); | |
| 276 | } | |
| 5dfd06ac SS |
277 | proc.p_pptr = &pproc; |
| 278 | } | |
| e42f5937 MD |
279 | |
| 280 | if (proc.p_sigacts) { | |
| 281 | if (KREAD(kd, (u_long)proc.p_sigacts, &sigacts)) { | |
| 282 | _kvm_err(kd, kd->program, | |
| 283 | "can't read sigacts at %p", | |
| 284 | proc.p_sigacts); | |
| 285 | return (-1); | |
| 286 | } | |
| 287 | proc.p_sigacts = &sigacts; | |
| 288 | } | |
| 289 | ||
| 984263bc | 290 | if (KREAD(kd, (u_long)pgrp.pg_session, &sess)) { |
| b58f1e66 | 291 | _kvm_err(kd, kd->program, "can't read session at %p", |
| 984263bc MD |
292 | pgrp.pg_session); |
| 293 | return (-1); | |
| 294 | } | |
| 5dfd06ac SS |
295 | pgrp.pg_session = &sess; |
| 296 | ||
| 4643740a | 297 | if ((proc.p_flags & P_CONTROLT) && sess.s_ttyp != NULL) { |
| 984263bc MD |
298 | if (KREAD(kd, (u_long)sess.s_ttyp, &tty)) { |
| 299 | _kvm_err(kd, kd->program, | |
| b58f1e66 | 300 | "can't read tty at %p", sess.s_ttyp); |
| 984263bc MD |
301 | return (-1); |
| 302 | } | |
| 5dfd06ac | 303 | sess.s_ttyp = &tty; |
| 028066b1 | 304 | if (tty.t_dev && tty.t_dev != NULL) { |
| 5dfd06ac | 305 | if (KREAD(kd, (u_long)tty.t_dev, &cdev)) |
| 028066b1 | 306 | tty.t_dev = NULL; |
| 5dfd06ac SS |
307 | else |
| 308 | tty.t_dev = &cdev; | |
| b13267a5 | 309 | } |
| 984263bc | 310 | if (tty.t_pgrp != NULL) { |
| 5dfd06ac | 311 | if (KREAD(kd, (u_long)tty.t_pgrp, &tpgrp)) { |
| 984263bc | 312 | _kvm_err(kd, kd->program, |
| b58f1e66 | 313 | "can't read tpgrp at %p", |
| 984263bc MD |
314 | tty.t_pgrp); |
| 315 | return (-1); | |
| 316 | } | |
| 5dfd06ac SS |
317 | tty.t_pgrp = &tpgrp; |
| 318 | } | |
| e42f5937 MD |
319 | if (tty.t_session != NULL) { |
| 320 | if (KREAD(kd, (u_long)tty.t_session, &tsess)) { | |
| 321 | _kvm_err(kd, kd->program, | |
| 322 | "can't read tsess at %p", | |
| 323 | tty.t_session); | |
| 324 | return (-1); | |
| 325 | } | |
| 326 | tty.t_session = &tsess; | |
| 327 | } | |
| 5dfd06ac SS |
328 | } |
| 329 | ||
| 330 | if (KREAD(kd, (u_long)proc.p_vmspace, &vmspace)) { | |
| 331 | _kvm_err(kd, kd->program, "can't read vmspace at %p", | |
| 332 | proc.p_vmspace); | |
| 333 | return (-1); | |
| 334 | } | |
| 335 | proc.p_vmspace = &vmspace; | |
| 984263bc | 336 | |
| 5dfd06ac SS |
337 | if (ucred.cr_prison != NULL) { |
| 338 | if (KREAD(kd, (u_long)ucred.cr_prison, &prison)) { | |
| 339 | _kvm_err(kd, kd->program, "can't read prison at %p", | |
| 340 | ucred.cr_prison); | |
| 341 | return (-1); | |
| 342 | } | |
| 343 | ucred.cr_prison = &prison; | |
| 344 | } | |
| 345 | ||
| 346 | switch (what & ~KERN_PROC_FLAGMASK) { | |
| 984263bc MD |
347 | |
| 348 | case KERN_PROC_PGRP: | |
| 5dfd06ac | 349 | if (proc.p_pgrp->pg_id != (pid_t)arg) |
| 984263bc MD |
350 | continue; |
| 351 | break; | |
| 352 | ||
| 353 | case KERN_PROC_TTY: | |
| 4643740a | 354 | if ((proc.p_flags & P_CONTROLT) == 0 || |
| c15b1d97 | 355 | dev2udev(proc.p_pgrp->pg_session->s_ttyp->t_dev) |
| 5dfd06ac | 356 | != (dev_t)arg) |
| 984263bc MD |
357 | continue; |
| 358 | break; | |
| 359 | } | |
| 5dfd06ac SS |
360 | |
| 361 | if ((bp = kinfo_resize_proc(kd, bp)) == NULL) | |
| 362 | return (-1); | |
| 363 | fill_kinfo_proc(&proc, bp); | |
| 364 | bp->kp_paddr = (uintptr_t)p; | |
| 365 | ||
| e42f5937 MD |
366 | lwppos = kvm_firstlwp(kd, &lwp, &proc); |
| 367 | if (lwppos == 0) { | |
| 5dfd06ac | 368 | bp++; /* Just export the proc then */ |
| e42f5937 MD |
369 | count++; |
| 370 | } | |
| 371 | while (lwppos && lwppos != (uintptr_t)-1) { | |
| 5dfd06ac SS |
372 | if (p != lwp.lwp_proc) { |
| 373 | _kvm_err(kd, kd->program, "lwp has wrong parent"); | |
| 374 | return (-1); | |
| 375 | } | |
| 376 | lwp.lwp_proc = &proc; | |
| 377 | if (KREAD(kd, (u_long)lwp.lwp_thread, &thread)) { | |
| b58f1e66 | 378 | _kvm_err(kd, kd->program, "can't read thread at %p", |
| 5dfd06ac SS |
379 | lwp.lwp_thread); |
| 380 | return (-1); | |
| 381 | } | |
| 382 | lwp.lwp_thread = &thread; | |
| 383 | ||
| e42f5937 MD |
384 | if (thread.td_gd) { |
| 385 | if (KREAD(kd, (u_long)thread.td_gd, &gdata)) { | |
| 386 | _kvm_err(kd, kd->program, "can't read" | |
| 387 | " gd at %p", | |
| 388 | thread.td_gd); | |
| 389 | return(-1); | |
| 390 | } | |
| 391 | thread.td_gd = &gdata; | |
| 392 | } | |
| 393 | if (thread.td_wmesg) { | |
| 394 | wmesg = (void *)KREADSTR(kd, thread.td_wmesg); | |
| 395 | if (wmesg == NULL) { | |
| 396 | _kvm_err(kd, kd->program, "can't read" | |
| 397 | " wmesg %p", | |
| 398 | thread.td_wmesg); | |
| 399 | return(-1); | |
| 400 | } | |
| 401 | thread.td_wmesg = wmesg; | |
| 402 | } else { | |
| 403 | wmesg = NULL; | |
| 404 | } | |
| 405 | ||
| 5dfd06ac SS |
406 | if ((bp = kinfo_resize_proc(kd, bp)) == NULL) |
| 407 | return (-1); | |
| 408 | fill_kinfo_proc(&proc, bp); | |
| 409 | fill_kinfo_lwp(&lwp, &bp->kp_lwp); | |
| 410 | bp->kp_paddr = (uintptr_t)p; | |
| 411 | bp++; | |
| e42f5937 MD |
412 | count++; |
| 413 | if (wmesg) | |
| 414 | free(wmesg); | |
| 5dfd06ac SS |
415 | if ((what & KERN_PROC_FLAG_LWP) == 0) |
| 416 | break; | |
| e42f5937 | 417 | lwppos = kvm_nextlwp(kd, lwppos, &lwp, &proc); |
| 5dfd06ac | 418 | } |
| e42f5937 MD |
419 | if (lwppos == (uintptr_t)-1) |
| 420 | return(-1); | |
| 984263bc | 421 | } |
| e42f5937 | 422 | return (count); |
| 984263bc MD |
423 | } |
| 424 | ||
| 425 | /* | |
| 426 | * Build proc info array by reading in proc list from a crash dump. | |
| 5dfd06ac | 427 | * We reallocate kd->procbase as necessary. |
| 984263bc MD |
428 | */ |
| 429 | static int | |
| 576a9733 | 430 | kvm_deadprocs(kvm_t *kd, int what, int arg, u_long a_allproc, |
| 5dfd06ac | 431 | u_long a_zombproc) |
| 984263bc | 432 | { |
| 576a9733 CP |
433 | struct kinfo_proc *bp = kd->procbase; |
| 434 | int acnt, zcnt; | |
| 984263bc MD |
435 | struct proc *p; |
| 436 | ||
| 437 | if (KREAD(kd, a_allproc, &p)) { | |
| 438 | _kvm_err(kd, kd->program, "cannot read allproc"); | |
| 439 | return (-1); | |
| 440 | } | |
| 5dfd06ac | 441 | acnt = kvm_proclist(kd, what, arg, p, bp); |
| 984263bc MD |
442 | if (acnt < 0) |
| 443 | return (acnt); | |
| 444 | ||
| 445 | if (KREAD(kd, a_zombproc, &p)) { | |
| 446 | _kvm_err(kd, kd->program, "cannot read zombproc"); | |
| 447 | return (-1); | |
| 448 | } | |
| 5dfd06ac | 449 | zcnt = kvm_proclist(kd, what, arg, p, bp + acnt); |
| 984263bc MD |
450 | if (zcnt < 0) |
| 451 | zcnt = 0; | |
| 452 | ||
| 453 | return (acnt + zcnt); | |
| 454 | } | |
| 455 | ||
| 456 | struct kinfo_proc * | |
| 576a9733 | 457 | kvm_getprocs(kvm_t *kd, int op, int arg, int *cnt) |
| 984263bc MD |
458 | { |
| 459 | int mib[4], st, nprocs; | |
| 2b0645c3 | 460 | int miblen = ((op & ~KERN_PROC_FLAGMASK) == KERN_PROC_ALL) ? 3 : 4; |
| 984263bc MD |
461 | size_t size; |
| 462 | ||
| 463 | if (kd->procbase != 0) { | |
| 464 | free((void *)kd->procbase); | |
| 465 | /* | |
| 466 | * Clear this pointer in case this call fails. Otherwise, | |
| 467 | * kvm_close() will free it again. | |
| 468 | */ | |
| 469 | kd->procbase = 0; | |
| 470 | } | |
| 104d324f | 471 | if (kvm_ishost(kd)) { |
| 984263bc MD |
472 | size = 0; |
| 473 | mib[0] = CTL_KERN; | |
| 474 | mib[1] = KERN_PROC; | |
| 475 | mib[2] = op; | |
| 476 | mib[3] = arg; | |
| 2b0645c3 | 477 | st = sysctl(mib, miblen, NULL, &size, NULL, 0); |
| 984263bc MD |
478 | if (st == -1) { |
| 479 | _kvm_syserr(kd, kd->program, "kvm_getprocs"); | |
| 480 | return (0); | |
| 481 | } | |
| 482 | do { | |
| 483 | size += size / 10; | |
| 484 | kd->procbase = (struct kinfo_proc *) | |
| 485 | _kvm_realloc(kd, kd->procbase, size); | |
| 486 | if (kd->procbase == 0) | |
| 487 | return (0); | |
| 2b0645c3 | 488 | st = sysctl(mib, miblen, kd->procbase, &size, NULL, 0); |
| 984263bc MD |
489 | } while (st == -1 && errno == ENOMEM); |
| 490 | if (st == -1) { | |
| 491 | _kvm_syserr(kd, kd->program, "kvm_getprocs"); | |
| 492 | return (0); | |
| 493 | } | |
| 494 | if (size % sizeof(struct kinfo_proc) != 0) { | |
| 495 | _kvm_err(kd, kd->program, | |
| b58f1e66 | 496 | "proc size mismatch (%zd total, %zd chunks)", |
| 984263bc MD |
497 | size, sizeof(struct kinfo_proc)); |
| 498 | return (0); | |
| 499 | } | |
| 500 | nprocs = size / sizeof(struct kinfo_proc); | |
| 501 | } else { | |
| 502 | struct nlist nl[4], *p; | |
| 503 | ||
| 504 | nl[0].n_name = "_nprocs"; | |
| 505 | nl[1].n_name = "_allproc"; | |
| 506 | nl[2].n_name = "_zombproc"; | |
| 507 | nl[3].n_name = 0; | |
| 508 | ||
| 509 | if (kvm_nlist(kd, nl) != 0) { | |
| 510 | for (p = nl; p->n_type != 0; ++p) | |
| 511 | ; | |
| 512 | _kvm_err(kd, kd->program, | |
| 513 | "%s: no such symbol", p->n_name); | |
| 514 | return (0); | |
| 515 | } | |
| 516 | if (KREAD(kd, nl[0].n_value, &nprocs)) { | |
| 517 | _kvm_err(kd, kd->program, "can't read nprocs"); | |
| 518 | return (0); | |
| 519 | } | |
| 984263bc | 520 | nprocs = kvm_deadprocs(kd, op, arg, nl[1].n_value, |
| 5dfd06ac | 521 | nl[2].n_value); |
| 984263bc MD |
522 | #ifdef notdef |
| 523 | size = nprocs * sizeof(struct kinfo_proc); | |
| 524 | (void)realloc(kd->procbase, size); | |
| 525 | #endif | |
| 526 | } | |
| 527 | *cnt = nprocs; | |
| 528 | return (kd->procbase); | |
| 529 | } | |
| 530 | ||
| 531 | void | |
| 576a9733 | 532 | _kvm_freeprocs(kvm_t *kd) |
| 984263bc MD |
533 | { |
| 534 | if (kd->procbase) { | |
| 535 | free(kd->procbase); | |
| 536 | kd->procbase = 0; | |
| 537 | } | |
| 538 | } | |
| 539 | ||
| 540 | void * | |
| 576a9733 | 541 | _kvm_realloc(kvm_t *kd, void *p, size_t n) |
| 984263bc MD |
542 | { |
| 543 | void *np = (void *)realloc(p, n); | |
| 544 | ||
| 545 | if (np == 0) { | |
| 546 | free(p); | |
| 547 | _kvm_err(kd, kd->program, "out of memory"); | |
| 548 | } | |
| 549 | return (np); | |
| 550 | } | |
| 551 | ||
| 552 | #ifndef MAX | |
| 553 | #define MAX(a, b) ((a) > (b) ? (a) : (b)) | |
| 554 | #endif | |
| 555 | ||
| 556 | /* | |
| 5dfd06ac | 557 | * Read in an argument vector from the user address space of process pid. |
| 984263bc MD |
558 | * addr if the user-space base address of narg null-terminated contiguous |
| 559 | * strings. This is used to read in both the command arguments and | |
| 560 | * environment strings. Read at most maxcnt characters of strings. | |
| 561 | */ | |
| 562 | static char ** | |
| 5dfd06ac | 563 | kvm_argv(kvm_t *kd, pid_t pid, u_long addr, int narg, int maxcnt) |
| 984263bc | 564 | { |
| 576a9733 CP |
565 | char *np, *cp, *ep, *ap; |
| 566 | u_long oaddr = -1; | |
| 567 | int len, cc; | |
| 568 | char **argv; | |
| 984263bc MD |
569 | |
| 570 | /* | |
| 571 | * Check that there aren't an unreasonable number of agruments, | |
| 572 | * and that the address is in user space. | |
| 573 | */ | |
| c99d7e60 MD |
574 | if (narg > 512 || |
| 575 | addr < VM_MIN_USER_ADDRESS || addr >= VM_MAX_USER_ADDRESS) { | |
| 984263bc | 576 | return (0); |
| c99d7e60 | 577 | } |
| 984263bc MD |
578 | |
| 579 | /* | |
| 580 | * kd->argv : work space for fetching the strings from the target | |
| 581 | * process's space, and is converted for returning to caller | |
| 582 | */ | |
| 583 | if (kd->argv == 0) { | |
| 584 | /* | |
| 585 | * Try to avoid reallocs. | |
| 586 | */ | |
| 587 | kd->argc = MAX(narg + 1, 32); | |
| 588 | kd->argv = (char **)_kvm_malloc(kd, kd->argc * | |
| 589 | sizeof(*kd->argv)); | |
| 590 | if (kd->argv == 0) | |
| 591 | return (0); | |
| 592 | } else if (narg + 1 > kd->argc) { | |
| 593 | kd->argc = MAX(2 * kd->argc, narg + 1); | |
| 594 | kd->argv = (char **)_kvm_realloc(kd, kd->argv, kd->argc * | |
| 595 | sizeof(*kd->argv)); | |
| 596 | if (kd->argv == 0) | |
| 597 | return (0); | |
| 598 | } | |
| 599 | /* | |
| 600 | * kd->argspc : returned to user, this is where the kd->argv | |
| 601 | * arrays are left pointing to the collected strings. | |
| 602 | */ | |
| 603 | if (kd->argspc == 0) { | |
| 604 | kd->argspc = (char *)_kvm_malloc(kd, PAGE_SIZE); | |
| 605 | if (kd->argspc == 0) | |
| 606 | return (0); | |
| 607 | kd->arglen = PAGE_SIZE; | |
| 608 | } | |
| 609 | /* | |
| 610 | * kd->argbuf : used to pull in pages from the target process. | |
| 611 | * the strings are copied out of here. | |
| 612 | */ | |
| 613 | if (kd->argbuf == 0) { | |
| 614 | kd->argbuf = (char *)_kvm_malloc(kd, PAGE_SIZE); | |
| 615 | if (kd->argbuf == 0) | |
| 616 | return (0); | |
| 617 | } | |
| 618 | ||
| 619 | /* Pull in the target process'es argv vector */ | |
| 620 | cc = sizeof(char *) * narg; | |
| 5dfd06ac | 621 | if (kvm_uread(kd, pid, addr, (char *)kd->argv, cc) != cc) |
| 984263bc MD |
622 | return (0); |
| 623 | /* | |
| 624 | * ap : saved start address of string we're working on in kd->argspc | |
| 625 | * np : pointer to next place to write in kd->argspc | |
| 626 | * len: length of data in kd->argspc | |
| 627 | * argv: pointer to the argv vector that we are hunting around the | |
| 628 | * target process space for, and converting to addresses in | |
| 629 | * our address space (kd->argspc). | |
| 630 | */ | |
| 631 | ap = np = kd->argspc; | |
| 632 | argv = kd->argv; | |
| 633 | len = 0; | |
| 634 | /* | |
| 635 | * Loop over pages, filling in the argument vector. | |
| 636 | * Note that the argv strings could be pointing *anywhere* in | |
| 637 | * the user address space and are no longer contiguous. | |
| 638 | * Note that *argv is modified when we are going to fetch a string | |
| 639 | * that crosses a page boundary. We copy the next part of the string | |
| 640 | * into to "np" and eventually convert the pointer. | |
| 641 | */ | |
| 642 | while (argv < kd->argv + narg && *argv != 0) { | |
| 643 | ||
| 644 | /* get the address that the current argv string is on */ | |
| 645 | addr = (u_long)*argv & ~(PAGE_SIZE - 1); | |
| 646 | ||
| 647 | /* is it the same page as the last one? */ | |
| 648 | if (addr != oaddr) { | |
| 5dfd06ac | 649 | if (kvm_uread(kd, pid, addr, kd->argbuf, PAGE_SIZE) != |
| 984263bc MD |
650 | PAGE_SIZE) |
| 651 | return (0); | |
| 652 | oaddr = addr; | |
| 653 | } | |
| 654 | ||
| 655 | /* offset within the page... kd->argbuf */ | |
| 656 | addr = (u_long)*argv & (PAGE_SIZE - 1); | |
| 657 | ||
| 658 | /* cp = start of string, cc = count of chars in this chunk */ | |
| 659 | cp = kd->argbuf + addr; | |
| 660 | cc = PAGE_SIZE - addr; | |
| 661 | ||
| 662 | /* dont get more than asked for by user process */ | |
| 663 | if (maxcnt > 0 && cc > maxcnt - len) | |
| 664 | cc = maxcnt - len; | |
| 665 | ||
| 666 | /* pointer to end of string if we found it in this page */ | |
| 667 | ep = memchr(cp, '\0', cc); | |
| 668 | if (ep != 0) | |
| 669 | cc = ep - cp + 1; | |
| 670 | /* | |
| 671 | * at this point, cc is the count of the chars that we are | |
| 672 | * going to retrieve this time. we may or may not have found | |
| 673 | * the end of it. (ep points to the null if the end is known) | |
| 674 | */ | |
| 675 | ||
| 676 | /* will we exceed the malloc/realloced buffer? */ | |
| 677 | if (len + cc > kd->arglen) { | |
| edec16ba | 678 | size_t off; |
| 660c873b DR |
679 | char **pp; |
| 680 | char *op = kd->argspc; | |
| 984263bc MD |
681 | |
| 682 | kd->arglen *= 2; | |
| 683 | kd->argspc = (char *)_kvm_realloc(kd, kd->argspc, | |
| 684 | kd->arglen); | |
| 685 | if (kd->argspc == 0) | |
| 686 | return (0); | |
| 687 | /* | |
| 688 | * Adjust argv pointers in case realloc moved | |
| 689 | * the string space. | |
| 690 | */ | |
| 691 | off = kd->argspc - op; | |
| 692 | for (pp = kd->argv; pp < argv; pp++) | |
| 693 | *pp += off; | |
| 694 | ap += off; | |
| 695 | np += off; | |
| 696 | } | |
| 697 | /* np = where to put the next part of the string in kd->argspc*/ | |
| 698 | /* np is kinda redundant.. could use "kd->argspc + len" */ | |
| 699 | memcpy(np, cp, cc); | |
| 700 | np += cc; /* inc counters */ | |
| 701 | len += cc; | |
| 702 | ||
| 703 | /* | |
| 704 | * if end of string found, set the *argv pointer to the | |
| 705 | * saved beginning of string, and advance. argv points to | |
| 706 | * somewhere in kd->argv.. This is initially relative | |
| 707 | * to the target process, but when we close it off, we set | |
| 708 | * it to point in our address space. | |
| 709 | */ | |
| 710 | if (ep != 0) { | |
| 711 | *argv++ = ap; | |
| 712 | ap = np; | |
| 713 | } else { | |
| 714 | /* update the address relative to the target process */ | |
| 715 | *argv += cc; | |
| 716 | } | |
| 717 | ||
| 718 | if (maxcnt > 0 && len >= maxcnt) { | |
| 719 | /* | |
| 720 | * We're stopping prematurely. Terminate the | |
| 721 | * current string. | |
| 722 | */ | |
| 723 | if (ep == 0) { | |
| 724 | *np = '\0'; | |
| 725 | *argv++ = ap; | |
| 726 | } | |
| 727 | break; | |
| 728 | } | |
| 729 | } | |
| 730 | /* Make sure argv is terminated. */ | |
| 731 | *argv = 0; | |
| 732 | return (kd->argv); | |
| 733 | } | |
| 734 | ||
| 735 | static void | |
| 576a9733 | 736 | ps_str_a(struct ps_strings *p, u_long *addr, int *n) |
| 984263bc MD |
737 | { |
| 738 | *addr = (u_long)p->ps_argvstr; | |
| 739 | *n = p->ps_nargvstr; | |
| 740 | } | |
| 741 | ||
| 742 | static void | |
| 576a9733 | 743 | ps_str_e(struct ps_strings *p, u_long *addr, int *n) |
| 984263bc MD |
744 | { |
| 745 | *addr = (u_long)p->ps_envstr; | |
| 746 | *n = p->ps_nenvstr; | |
| 747 | } | |
| 748 | ||
| 749 | /* | |
| 750 | * Determine if the proc indicated by p is still active. | |
| 751 | * This test is not 100% foolproof in theory, but chances of | |
| 752 | * being wrong are very low. | |
| 753 | */ | |
| 754 | static int | |
| 5dfd06ac | 755 | proc_verify(kvm_t *kd, const struct kinfo_proc *p) |
| 984263bc MD |
756 | { |
| 757 | struct kinfo_proc kp; | |
| 758 | int mib[4]; | |
| 759 | size_t len; | |
| 5dfd06ac | 760 | int error; |
| 984263bc MD |
761 | |
| 762 | mib[0] = CTL_KERN; | |
| 763 | mib[1] = KERN_PROC; | |
| 764 | mib[2] = KERN_PROC_PID; | |
| 5dfd06ac SS |
765 | mib[3] = p->kp_pid; |
| 766 | ||
| 984263bc | 767 | len = sizeof(kp); |
| 5dfd06ac SS |
768 | error = sysctl(mib, 4, &kp, &len, NULL, 0); |
| 769 | if (error) | |
| 984263bc | 770 | return (0); |
| 5dfd06ac SS |
771 | |
| 772 | error = (p->kp_pid == kp.kp_pid && | |
| 416d05d7 | 773 | (kp.kp_stat != SZOMB || p->kp_stat == SZOMB)); |
| 5dfd06ac | 774 | return (error); |
| 984263bc MD |
775 | } |
| 776 | ||
| 777 | static char ** | |
| 576a9733 CP |
778 | kvm_doargv(kvm_t *kd, const struct kinfo_proc *kp, int nchr, |
| 779 | void (*info)(struct ps_strings *, u_long *, int *)) | |
| 984263bc | 780 | { |
| 576a9733 | 781 | char **ap; |
| 984263bc MD |
782 | u_long addr; |
| 783 | int cnt; | |
| 784 | static struct ps_strings arginfo; | |
| 785 | static u_long ps_strings; | |
| 786 | size_t len; | |
| 787 | ||
| 3641b7ca | 788 | if (ps_strings == 0) { |
| 984263bc MD |
789 | len = sizeof(ps_strings); |
| 790 | if (sysctlbyname("kern.ps_strings", &ps_strings, &len, NULL, | |
| 791 | 0) == -1) | |
| 792 | ps_strings = PS_STRINGS; | |
| 793 | } | |
| 794 | ||
| 795 | /* | |
| 796 | * Pointers are stored at the top of the user stack. | |
| 797 | */ | |
| 416d05d7 | 798 | if (kp->kp_stat == SZOMB || |
| 5dfd06ac | 799 | kvm_uread(kd, kp->kp_pid, ps_strings, (char *)&arginfo, |
| 984263bc MD |
800 | sizeof(arginfo)) != sizeof(arginfo)) |
| 801 | return (0); | |
| 802 | ||
| 803 | (*info)(&arginfo, &addr, &cnt); | |
| 804 | if (cnt == 0) | |
| 805 | return (0); | |
| 5dfd06ac | 806 | ap = kvm_argv(kd, kp->kp_pid, addr, cnt, nchr); |
| 984263bc MD |
807 | /* |
| 808 | * For live kernels, make sure this process didn't go away. | |
| 809 | */ | |
| 104d324f | 810 | if (ap != 0 && (kvm_ishost(kd) || kvm_isvkernel(kd)) && |
| 5dfd06ac | 811 | !proc_verify(kd, kp)) |
| 984263bc MD |
812 | ap = 0; |
| 813 | return (ap); | |
| 814 | } | |
| 815 | ||
| 816 | /* | |
| 817 | * Get the command args. This code is now machine independent. | |
| 818 | */ | |
| 819 | char ** | |
| 576a9733 | 820 | kvm_getargv(kvm_t *kd, const struct kinfo_proc *kp, int nchr) |
| 984263bc MD |
821 | { |
| 822 | int oid[4]; | |
| 823 | int i; | |
| 824 | size_t bufsz; | |
| 825 | static unsigned long buflen; | |
| 826 | static char *buf, *p; | |
| 827 | static char **bufp; | |
| 828 | static int argc; | |
| 829 | ||
| 104d324f | 830 | if (!kvm_ishost(kd)) { /* XXX: vkernels */ |
| 984263bc MD |
831 | _kvm_err(kd, kd->program, |
| 832 | "cannot read user space from dead kernel"); | |
| 833 | return (0); | |
| 834 | } | |
| 835 | ||
| 836 | if (!buflen) { | |
| 837 | bufsz = sizeof(buflen); | |
| 838 | i = sysctlbyname("kern.ps_arg_cache_limit", | |
| 839 | &buflen, &bufsz, NULL, 0); | |
| 840 | if (i == -1) { | |
| 841 | buflen = 0; | |
| 842 | } else { | |
| 843 | buf = malloc(buflen); | |
| 844 | if (buf == NULL) | |
| 845 | buflen = 0; | |
| 846 | argc = 32; | |
| 847 | bufp = malloc(sizeof(char *) * argc); | |
| 848 | } | |
| 849 | } | |
| 850 | if (buf != NULL) { | |
| 851 | oid[0] = CTL_KERN; | |
| 852 | oid[1] = KERN_PROC; | |
| 853 | oid[2] = KERN_PROC_ARGS; | |
| 5dfd06ac | 854 | oid[3] = kp->kp_pid; |
| 984263bc MD |
855 | bufsz = buflen; |
| 856 | i = sysctl(oid, 4, buf, &bufsz, 0, 0); | |
| 857 | if (i == 0 && bufsz > 0) { | |
| 858 | i = 0; | |
| 859 | p = buf; | |
| 860 | do { | |
| 861 | bufp[i++] = p; | |
| 862 | p += strlen(p) + 1; | |
| 863 | if (i >= argc) { | |
| 864 | argc += argc; | |
| 865 | bufp = realloc(bufp, | |
| 866 | sizeof(char *) * argc); | |
| 867 | } | |
| 868 | } while (p < buf + bufsz); | |
| 869 | bufp[i++] = 0; | |
| 870 | return (bufp); | |
| 871 | } | |
| 872 | } | |
| 5dfd06ac | 873 | if (kp->kp_flags & P_SYSTEM) |
| 984263bc MD |
874 | return (NULL); |
| 875 | return (kvm_doargv(kd, kp, nchr, ps_str_a)); | |
| 876 | } | |
| 877 | ||
| 878 | char ** | |
| 576a9733 | 879 | kvm_getenvv(kvm_t *kd, const struct kinfo_proc *kp, int nchr) |
| 984263bc MD |
880 | { |
| 881 | return (kvm_doargv(kd, kp, nchr, ps_str_e)); | |
| 882 | } | |
| 883 | ||
| 884 | /* | |
| 5dfd06ac | 885 | * Read from user space. The user context is given by pid. |
| 984263bc MD |
886 | */ |
| 887 | ssize_t | |
| 5dfd06ac | 888 | kvm_uread(kvm_t *kd, pid_t pid, u_long uva, char *buf, size_t len) |
| 984263bc | 889 | { |
| 576a9733 | 890 | char *cp; |
| 984263bc MD |
891 | char procfile[MAXPATHLEN]; |
| 892 | ssize_t amount; | |
| 893 | int fd; | |
| 894 | ||
| 104d324f | 895 | if (!kvm_ishost(kd)) { /* XXX: vkernels */ |
| 984263bc MD |
896 | _kvm_err(kd, kd->program, |
| 897 | "cannot read user space from dead kernel"); | |
| 898 | return (0); | |
| 899 | } | |
| 900 | ||
| 5dfd06ac | 901 | sprintf(procfile, "/proc/%d/mem", pid); |
| 984263bc MD |
902 | fd = open(procfile, O_RDONLY, 0); |
| 903 | if (fd < 0) { | |
| 904 | _kvm_err(kd, kd->program, "cannot open %s", procfile); | |
| 905 | close(fd); | |
| 906 | return (0); | |
| 907 | } | |
| 908 | ||
| 909 | cp = buf; | |
| 910 | while (len > 0) { | |
| 911 | errno = 0; | |
| 912 | if (lseek(fd, (off_t)uva, 0) == -1 && errno != 0) { | |
| b58f1e66 | 913 | _kvm_err(kd, kd->program, "invalid address (%lx) in %s", |
| 984263bc MD |
914 | uva, procfile); |
| 915 | break; | |
| 916 | } | |
| 917 | amount = read(fd, cp, len); | |
| 918 | if (amount < 0) { | |
| 919 | _kvm_syserr(kd, kd->program, "error reading %s", | |
| 920 | procfile); | |
| 921 | break; | |
| 922 | } | |
| 923 | if (amount == 0) { | |
| 924 | _kvm_err(kd, kd->program, "EOF reading %s", procfile); | |
| 925 | break; | |
| 926 | } | |
| 927 | cp += amount; | |
| 928 | uva += amount; | |
| 929 | len -= amount; | |
| 930 | } | |
| 931 | ||
| 932 | close(fd); | |
| 933 | return ((ssize_t)(cp - buf)); | |
| 934 | } |