1 /*- 2 * Copyright (c) 2007 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Simon 'corecode' Schubert <corecode@fs.ei.tum.de> 6 * by Thomas E. Spanjaard <tgen@netphreax.net> 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 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 16 * the documentation and/or other materials provided with the 17 * distribution. 18 * 3. Neither the name of The DragonFly Project nor the names of its 19 * contributors may be used to endorse or promote products derived 20 * from this software without specific, prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 26 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 30 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 31 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 32 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 /* 37 * This is a source file used by both the kernel and libkvm. 38 */ 39 40 #ifndef _KERNEL 41 #define _KERNEL_STRUCTURES 42 #endif 43 44 #include <sys/proc.h> 45 #include <vm/vm_map.h> 46 #include <sys/kinfo.h> 47 #include <sys/tty.h> 48 #include <sys/conf.h> 49 #include <sys/jail.h> 50 #include <sys/mplock2.h> 51 #include <sys/globaldata.h> 52 #ifdef _KERNEL 53 #include <sys/systm.h> 54 #else 55 #include <string.h> 56 57 dev_t devid_from_dev(cdev_t dev); /* kvm_proc.c */ 58 #endif 59 60 61 #ifndef _KERNEL 62 /* 63 * This is a temporary hack for when libkvm compiles in this file 64 * from userland. These functions don't belong here. 65 */ 66 static void 67 timevalfix(struct timeval *t1) 68 { 69 70 if (t1->tv_usec < 0) { 71 t1->tv_sec--; 72 t1->tv_usec += 1000000; 73 } 74 if (t1->tv_usec >= 1000000) { 75 t1->tv_sec++; 76 t1->tv_usec -= 1000000; 77 } 78 } 79 80 static void 81 timevaladd(struct timeval *t1, const struct timeval *t2) 82 { 83 84 t1->tv_sec += t2->tv_sec; 85 t1->tv_usec += t2->tv_usec; 86 timevalfix(t1); 87 } 88 89 static void 90 ruadd(struct rusage *ru, struct rusage *ru2) 91 { 92 long *ip, *ip2; 93 int i; 94 95 timevaladd(&ru->ru_utime, &ru2->ru_utime); 96 timevaladd(&ru->ru_stime, &ru2->ru_stime); 97 if (ru->ru_maxrss < ru2->ru_maxrss) 98 ru->ru_maxrss = ru2->ru_maxrss; 99 ip = &ru->ru_first; ip2 = &ru2->ru_first; 100 for (i = &ru->ru_last - &ru->ru_first; i >= 0; i--) 101 *ip++ += *ip2++; 102 } 103 104 #endif 105 106 /* 107 * Fill in a struct kinfo_proc, and zero the lwp fields for a possible 108 * fill_kinfo_lwp() aggregation. 109 * 110 * NOTE! We may be asked to fill in kinfo_proc for a zombied process, and 111 * the process may be in the middle of being deallocated. Check all pointers 112 * for NULL. 113 * 114 * Caller must hold p->p_token 115 */ 116 void 117 fill_kinfo_proc(struct proc *p, struct kinfo_proc *kp) 118 { 119 struct session *sess; 120 struct pgrp *pgrp; 121 struct vmspace *vm; 122 123 pgrp = p->p_pgrp; 124 sess = pgrp ? pgrp->pg_session : NULL; 125 126 bzero(kp, sizeof(*kp)); 127 128 kp->kp_paddr = (uintptr_t)p; 129 kp->kp_fd = (uintptr_t)p->p_fd; 130 131 kp->kp_flags = p->p_flags; 132 kp->kp_stat = p->p_stat; 133 kp->kp_lock = p->p_lock; 134 kp->kp_acflag = p->p_acflag; 135 kp->kp_traceflag = p->p_traceflag; 136 kp->kp_siglist = p->p_siglist; 137 if (p->p_sigacts) { 138 kp->kp_sigignore = p->p_sigignore; /* p_sigacts-> */ 139 kp->kp_sigcatch = p->p_sigcatch; /* p_sigacts-> */ 140 kp->kp_sigflag = p->p_sigacts->ps_flag; 141 } 142 kp->kp_start = p->p_start; 143 144 strncpy(kp->kp_comm, p->p_comm, sizeof(kp->kp_comm) - 1); 145 kp->kp_comm[sizeof(kp->kp_comm) - 1] = 0; 146 147 if (p->p_ucred) { 148 kp->kp_uid = p->p_ucred->cr_uid; 149 kp->kp_ngroups = p->p_ucred->cr_ngroups; 150 if (p->p_ucred->cr_groups) { 151 bcopy(p->p_ucred->cr_groups, kp->kp_groups, 152 NGROUPS * sizeof(kp->kp_groups[0])); 153 } 154 kp->kp_ruid = p->p_ucred->cr_ruid; 155 kp->kp_svuid = p->p_ucred->cr_svuid; 156 kp->kp_rgid = p->p_ucred->cr_rgid; 157 kp->kp_svgid = p->p_ucred->cr_svgid; 158 159 /* 160 * Copy just some of the capabilities for now to avoid 161 * changing the size of the kp structure. 162 */ 163 bcopy(p->p_ucred->cr_caps.caps, kp->kp_syscaps, 164 sizeof(kp->kp_syscaps)); 165 } 166 167 kp->kp_pid = p->p_pid; 168 if (p->p_oppid != 0) 169 kp->kp_ppid = p->p_oppid; 170 else 171 kp->kp_ppid = p->p_pptr != NULL ? p->p_pptr->p_pid : -1; 172 if (pgrp) { 173 kp->kp_pgid = pgrp->pg_id; 174 kp->kp_jobc = pgrp->pg_jobc; 175 } 176 if (sess) { 177 kp->kp_sid = sess->s_sid; 178 bcopy(sess->s_login, kp->kp_login, MAXLOGNAME); 179 if (sess->s_ttyvp != NULL) 180 kp->kp_auxflags |= KI_CTTY; 181 if ((p->p_session != NULL) && SESS_LEADER(p)) 182 kp->kp_auxflags |= KI_SLEADER; 183 } 184 if (sess && (p->p_flags & P_CONTROLT) != 0 && sess->s_ttyp != NULL) { 185 kp->kp_tdev = devid_from_dev(sess->s_ttyp->t_dev); 186 if (sess->s_ttyp->t_pgrp != NULL) 187 kp->kp_tpgid = sess->s_ttyp->t_pgrp->pg_id; 188 else 189 kp->kp_tpgid = -1; 190 if (sess->s_ttyp->t_session != NULL) 191 kp->kp_tsid = sess->s_ttyp->t_session->s_sid; 192 else 193 kp->kp_tsid = -1; 194 } else { 195 kp->kp_tdev = NOUDEV; 196 } 197 kp->kp_exitstat = p->p_xstat; 198 kp->kp_nthreads = p->p_nthreads; 199 kp->kp_nice = p->p_nice; 200 kp->kp_swtime = p->p_swtime; 201 202 if ((vm = p->p_vmspace) != NULL) { 203 kp->kp_vm_map_size = vm->vm_map.size; 204 kp->kp_vm_rssize = vmspace_resident_count(vm); 205 kp->kp_vm_swrss = vm->vm_swrss; 206 kp->kp_vm_tsize = btoc(vm->vm_tsize); 207 kp->kp_vm_dsize = btoc(vm->vm_dsize); 208 kp->kp_vm_ssize = btoc(vm->vm_ssize); 209 } 210 211 if (p->p_ucred && jailed(p->p_ucred)) 212 kp->kp_jailid = p->p_ucred->cr_prison->pr_id; 213 214 kp->kp_ru = p->p_ru; 215 kp->kp_cru = p->p_cru; 216 } 217 218 /* 219 * Fill in a struct kinfo_lwp. This routine also doubles as an aggregator 220 * of lwps for the proc. 221 * 222 * The kl structure must be initially zerod by the caller. Note that 223 * fill_kinfo_proc() will do this for us. 224 */ 225 void 226 fill_kinfo_lwp(struct lwp *lwp, struct kinfo_lwp *kl) 227 { 228 kl->kl_pid = lwp->lwp_proc->p_pid; 229 kl->kl_tid = lwp->lwp_tid; 230 231 kl->kl_flags = lwp->lwp_flags; 232 kl->kl_stat = lwp->lwp_stat; 233 kl->kl_lock = lwp->lwp_lock; 234 kl->kl_tdflags = lwp->lwp_thread->td_flags; 235 236 /* 237 * The process/lwp stat may not reflect whether the process is 238 * actually sleeping or not if the related thread was directly 239 * descheduled by LWKT. Adjust the stat if the thread is not 240 * runnable and not waiting to be scheduled on a cpu by the 241 * user process scheduler. 242 */ 243 if (kl->kl_stat == LSRUN) { 244 if ((kl->kl_tdflags & TDF_RUNQ) == 0 && 245 (lwp->lwp_mpflags & LWP_MP_ONRUNQ) == 0) { 246 kl->kl_stat = LSSLEEP; 247 } 248 } 249 #ifdef _KERNEL 250 kl->kl_mpcount = get_mplock_count(lwp->lwp_thread); 251 #else 252 kl->kl_mpcount = 0; 253 #endif 254 255 kl->kl_prio = lwp->lwp_usdata.bsd4.priority; /* XXX TGEN dangerous assumption */ 256 kl->kl_tdprio = lwp->lwp_thread->td_pri; 257 kl->kl_rtprio = lwp->lwp_rtprio; 258 259 kl->kl_uticks += lwp->lwp_thread->td_uticks; 260 kl->kl_sticks += lwp->lwp_thread->td_sticks; 261 kl->kl_iticks += lwp->lwp_thread->td_iticks; 262 kl->kl_cpticks += lwp->lwp_cpticks; 263 kl->kl_pctcpu += lwp->lwp_proc->p_stat == SZOMB ? 0 : lwp->lwp_pctcpu; 264 kl->kl_slptime += lwp->lwp_slptime; 265 kl->kl_origcpu = lwp->lwp_usdata.bsd4.batch; 266 kl->kl_estcpu = lwp->lwp_usdata.bsd4.estcpu; 267 kl->kl_cpuid = lwp->lwp_thread->td_gd->gd_cpuid; 268 269 ruadd(&kl->kl_ru, &lwp->lwp_ru); 270 271 kl->kl_siglist = lwp->lwp_siglist; 272 kl->kl_sigmask = lwp->lwp_sigmask; 273 274 kl->kl_wchan = (uintptr_t)lwp->lwp_thread->td_wchan; 275 if (lwp->lwp_thread->td_wmesg) { 276 strncpy(kl->kl_wmesg, lwp->lwp_thread->td_wmesg, WMESGLEN); 277 kl->kl_wmesg[WMESGLEN] = 0; 278 } 279 strlcpy(kl->kl_comm, lwp->lwp_thread->td_comm, sizeof(kl->kl_comm)); 280 } 281 282 /* 283 * Fill in a struct kinfo_proc for kernel threads (i.e. those without proc). 284 */ 285 void 286 fill_kinfo_proc_kthread(struct thread *td, struct kinfo_proc *kp) 287 { 288 bzero(kp, sizeof(*kp)); 289 290 /* 291 * Fill in fake proc information and semi-fake lwp info. 292 */ 293 kp->kp_pid = -1; 294 kp->kp_tdev = NOUDEV; 295 strncpy(kp->kp_comm, td->td_comm, sizeof(kp->kp_comm) - 1); 296 kp->kp_comm[sizeof(kp->kp_comm) - 1] = 0; 297 kp->kp_flags = P_SYSTEM; 298 if (td != &td->td_gd->gd_idlethread) 299 kp->kp_stat = SACTIVE; 300 else 301 kp->kp_stat = SIDL; 302 kp->kp_nthreads = 1; 303 kp->kp_ktaddr = (uintptr_t)td; 304 305 kp->kp_lwp.kl_pid = -1; 306 kp->kp_lwp.kl_tid = -1; 307 kp->kp_lwp.kl_tdflags = td->td_flags; 308 #ifdef _KERNEL 309 kp->kp_lwp.kl_mpcount = get_mplock_count(td); 310 #else 311 kp->kp_lwp.kl_mpcount = 0; 312 #endif 313 314 kp->kp_lwp.kl_tdprio = td->td_pri; 315 kp->kp_lwp.kl_rtprio.type = RTP_PRIO_THREAD; 316 kp->kp_lwp.kl_rtprio.prio = td->td_pri; 317 318 kp->kp_lwp.kl_uticks = td->td_uticks; 319 kp->kp_lwp.kl_sticks = td->td_sticks; 320 kp->kp_lwp.kl_iticks = td->td_iticks; 321 kp->kp_lwp.kl_cpuid = td->td_gd->gd_cpuid; 322 323 kp->kp_lwp.kl_wchan = (uintptr_t)td->td_wchan; 324 if (td->td_flags & TDF_RUNQ) 325 kp->kp_lwp.kl_stat = LSRUN; 326 else 327 kp->kp_lwp.kl_stat = LSSLEEP; 328 if (td->td_wmesg) { 329 strncpy(kp->kp_lwp.kl_wmesg, td->td_wmesg, WMESGLEN); 330 kp->kp_lwp.kl_wmesg[WMESGLEN] = 0; 331 } 332 strlcpy(kp->kp_lwp.kl_comm, td->td_comm, sizeof(kp->kp_lwp.kl_comm)); 333 } 334