1 /* $NetBSD: db_proc.c,v 1.14 2021/01/11 07:49:04 simonb Exp $ */ 2 3 /*- 4 * Copyright (c) 2009, 2020 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Andrew Doran. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * Copyright (c) 1982, 1986, 1989, 1991, 1993 34 * The Regents of the University of California. All rights reserved. 35 * 36 * Redistribution and use in source and binary forms, with or without 37 * modification, are permitted provided that the following conditions 38 * are met: 39 * 1. Redistributions of source code must retain the above copyright 40 * notice, this list of conditions and the following disclaimer. 41 * 2. Redistributions in binary form must reproduce the above copyright 42 * notice, this list of conditions and the following disclaimer in the 43 * documentation and/or other materials provided with the distribution. 44 * 3. Neither the name of the University nor the names of its contributors 45 * may be used to endorse or promote products derived from this software 46 * without specific prior written permission. 47 * 48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 58 * SUCH DAMAGE. 59 * 60 * from: kern_proc.c 8.4 (Berkeley) 1/4/94 61 */ 62 63 #include <sys/cdefs.h> 64 __KERNEL_RCSID(0, "$NetBSD: db_proc.c,v 1.14 2021/01/11 07:49:04 simonb Exp $"); 65 66 #ifndef _KERNEL 67 #include <stdbool.h> 68 #endif 69 70 #include <sys/param.h> 71 #include <sys/cpu.h> 72 #include <sys/proc.h> 73 #ifdef _KERNEL /* XXX */ 74 #include <sys/kauth.h> 75 #endif 76 77 #include <ddb/ddb.h> 78 79 proc_t * 80 db_proc_first(void) 81 { 82 83 return db_read_ptr("allproc"); 84 } 85 86 proc_t * 87 db_proc_next(proc_t *p) 88 { 89 90 db_read_bytes((db_addr_t)&p->p_list.le_next, sizeof(p), (char *)&p); 91 return p; 92 } 93 94 proc_t * 95 db_proc_find(pid_t pid) 96 { 97 proc_t *p; 98 pid_t tp; 99 100 for (p = db_proc_first(); p != NULL; p = db_proc_next(p)) { 101 db_read_bytes((db_addr_t)&p->p_pid, sizeof(tp), 102 (char *)&tp); 103 if (tp == pid) { 104 return p; 105 } 106 } 107 return NULL; 108 } 109 110 static void 111 db_read_string(const char *src, size_t len, char *dst) 112 { 113 size_t i; 114 115 for (i = 0; i < len; i++) { 116 db_read_bytes((db_addr_t)&src[i], 1, &dst[i]); 117 if (dst[i] == '\0') 118 break; 119 } 120 } 121 122 void 123 db_show_all_procs(db_expr_t addr, bool haddr, db_expr_t count, 124 const char *modif) 125 { 126 static struct pgrp pgrp; 127 static proc_t p; 128 static lwp_t l; 129 const char *mode, *ename; 130 proc_t *pp; 131 lwp_t *lp; 132 char db_nbuf[MAXCOMLEN + 1], wbuf[MAXCOMLEN + 1]; 133 bool run; 134 int cpuno; 135 136 if (modif[0] == 0) 137 mode = "l"; /* default == lwp mode */ 138 else 139 mode = strchr("mawln", modif[0]); 140 141 if (mode == NULL || *mode == 'm') { 142 db_printf("usage: show all procs [/a] [/l] [/n] [/w]\n"); 143 db_printf("\t/a == show process address info\n"); 144 db_printf("\t/l == show LWP info [default]\n"); 145 db_printf("\t/n == show normal process info\n"); 146 db_printf("\t/w == show process wait/emul info\n"); 147 return; 148 } 149 150 switch (*mode) { 151 case 'a': 152 db_printf("PID %-16s %18s %18s %18s\n", 153 "COMMAND", "STRUCT PROC *", "UAREA *", "VMSPACE/VM_MAP"); 154 break; 155 case 'l': 156 db_printf("PID %4s S %3s %9s %18s %18s %-8s\n", 157 "LID", "CPU", "FLAGS", "STRUCT LWP *", "NAME", "WAIT"); 158 break; 159 case 'n': 160 db_printf("PID %8s %8s %10s S %7s %4s %16s %7s\n", 161 "PPID", "PGRP", "UID", "FLAGS", "LWPS", "COMMAND", "WAIT"); 162 break; 163 case 'w': 164 db_printf("PID %4s %16s %8s %4s %-12s%s\n", 165 "LID", "COMMAND", "EMUL", "PRI", "WAIT-MSG", 166 "WAIT-CHANNEL"); 167 break; 168 } 169 170 for (pp = db_proc_first(); pp != NULL; pp = db_proc_next(pp)) { 171 db_read_bytes((db_addr_t)pp, sizeof(p), (char *)&p); 172 if (p.p_stat == 0) { 173 continue; 174 } 175 lp = p.p_lwps.lh_first; 176 if (lp != NULL) { 177 db_read_bytes((db_addr_t)lp, sizeof(l), (char *)&l); 178 } 179 db_printf("%-5d", p.p_pid); 180 181 switch (*mode) { 182 case 'a': 183 db_printf(" %-16.16s %18lx %18lx %18lx\n", 184 p.p_comm, (long)pp, 185 (long)(lp != NULL ? l.l_addr : 0), 186 (long)p.p_vmspace); 187 break; 188 case 'l': 189 while (lp != NULL) { 190 if (l.l_name != NULL) { 191 db_read_string(l.l_name, 192 MAXCOMLEN, db_nbuf); 193 db_nbuf[MAXCOMLEN] = '\0'; 194 } else { 195 strlcpy(db_nbuf, p.p_comm, 196 sizeof(db_nbuf)); 197 } 198 run = (l.l_stat == LSONPROC || 199 (l.l_pflag & LP_RUNNING) != 0); 200 if (l.l_cpu != NULL) { 201 db_read_bytes((db_addr_t) 202 &l.l_cpu->ci_data.cpu_index, 203 sizeof(cpuno), (char *)&cpuno); 204 } else 205 cpuno = -1; 206 if (l.l_wchan && l.l_wmesg) { 207 db_read_string(l.l_wmesg, 208 sizeof(wbuf), wbuf); 209 wbuf[MAXCOMLEN] = '\0'; 210 } else { 211 wbuf[0] = '\0'; 212 } 213 db_printf("%c%4d %d %3d %9x %18lx %18s %-8s\n", 214 (run ? '>' : ' '), l.l_lid, 215 l.l_stat, cpuno, l.l_flag, (long)lp, 216 db_nbuf, wbuf); 217 lp = LIST_NEXT((&l), l_sibling); 218 if (lp != NULL) { 219 db_printf("%-5d", p.p_pid); 220 db_read_bytes((db_addr_t)lp, sizeof(l), 221 (char *)&l); 222 } 223 } 224 break; 225 case 'n': 226 db_read_bytes((db_addr_t)p.p_pgrp, sizeof(pgrp), 227 (char *)&pgrp); 228 if (lp != NULL && l.l_wchan && l.l_wmesg) { 229 db_read_string(l.l_wmesg, 230 sizeof(wbuf), wbuf); 231 wbuf[MAXCOMLEN] = '\0'; 232 } else { 233 wbuf[0] = '\0'; 234 } 235 db_printf("%8d %8d %10d %d %#7x %4d %16s %7.7s\n", 236 p.p_pptr != NULL ? p.p_pptr->p_pid : -1, pgrp.pg_id, 237 #ifdef _KERNEL 238 kauth_cred_getuid(p.p_cred), 239 #else 240 /* XXX CRASH(8) */ 666, 241 #endif 242 p.p_stat, p.p_flag, 243 p.p_nlwps, p.p_comm, 244 (p.p_nlwps != 1) ? "*" : wbuf); 245 break; 246 247 case 'w': 248 while (lp != NULL) { 249 if (l.l_wchan && l.l_wmesg) { 250 db_read_string(l.l_wmesg, 251 sizeof(wbuf), wbuf); 252 wbuf[MAXCOMLEN] = '\0'; 253 } else { 254 wbuf[0] = '\0'; 255 } 256 run = (l.l_stat == LSONPROC || 257 (l.l_pflag & LP_RUNNING) != 0); 258 db_read_bytes((db_addr_t)&p.p_emul->e_name, 259 sizeof(ename), (char *)&ename); 260 261 db_read_string(ename, sizeof(db_nbuf), db_nbuf); 262 db_nbuf[MAXCOMLEN] = '\0'; 263 264 db_printf( 265 "%c%4d %16s %8s %4d %-12s %-18lx\n", 266 (run ? '>' : ' '), l.l_lid, 267 p.p_comm, db_nbuf, 268 l.l_priority, wbuf, (long)l.l_wchan); 269 lp = LIST_NEXT((&l), l_sibling); 270 if (lp != NULL) { 271 db_printf("%-5d", p.p_pid); 272 db_read_bytes((db_addr_t)lp, sizeof(l), 273 (char *)&l); 274 } 275 } 276 break; 277 } 278 } 279 } 280 281 void 282 db_show_proc(db_expr_t addr, bool haddr, db_expr_t count, const char *modif) 283 { 284 static proc_t p; 285 static lwp_t l; 286 const char *mode; 287 proc_t *pp; 288 lwp_t *lp; 289 char db_nbuf[MAXCOMLEN + 1], wbuf[MAXCOMLEN + 1]; 290 bool run; 291 int cpuno; 292 293 if (modif[0] == 0) 294 mode = "p"; /* default == by pid */ 295 else 296 mode = strchr("ap", modif[0]); 297 298 if (mode == NULL || !haddr) { 299 db_printf("usage: show proc [/a] [/p] address|pid\n"); 300 db_printf("\t/a == argument is an address of any lwp\n"); 301 db_printf("\t/p == argument is a pid [default]\n"); 302 return; 303 } 304 305 switch (*mode) { 306 case 'a': 307 lp = (lwp_t *)(uintptr_t)addr; 308 db_printf("lwp_t %lx\n", (long)lp); 309 db_read_bytes((db_addr_t)lp, sizeof(l), (char *)&l); 310 pp = l.l_proc; 311 break; 312 default: 313 case 'p': 314 pp = db_proc_find((pid_t)addr); 315 lp = NULL; 316 break; 317 } 318 319 if (pp == NULL) { 320 db_printf("bad address\n"); 321 return; 322 } 323 324 db_read_bytes((db_addr_t)pp, sizeof(p), (char *)&p); 325 if (lp == NULL) 326 lp = p.p_lwps.lh_first; 327 328 db_printf("%s: pid %d proc %lx vmspace/map %lx flags %x\n", 329 p.p_comm, p.p_pid, (long)pp, (long)p.p_vmspace, p.p_flag); 330 331 while (lp != NULL) { 332 db_read_bytes((db_addr_t)lp, sizeof(l), (char *)&l); 333 334 run = (l.l_stat == LSONPROC || 335 (l.l_pflag & LP_RUNNING) != 0); 336 337 db_printf("%slwp %d", (run ? "> " : " "), l.l_lid); 338 if (l.l_name != NULL) { 339 db_read_string(l.l_name, MAXCOMLEN, db_nbuf); 340 db_nbuf[MAXCOMLEN] = '\0'; 341 db_printf(" [%s]", db_nbuf); 342 } 343 db_printf(" %lx pcb %lx\n", (long)lp, (long)l.l_addr); 344 345 if (l.l_cpu != NULL) { 346 db_read_bytes((db_addr_t) 347 &l.l_cpu->ci_data.cpu_index, 348 sizeof(cpuno), (char *)&cpuno); 349 } else 350 cpuno = -1; 351 db_printf(" stat %d flags %x cpu %d pri %d ref %d\n", 352 l.l_stat, l.l_flag, cpuno, l.l_priority, l.l_refcnt); 353 354 if (l.l_wchan && l.l_wmesg) { 355 db_read_string(l.l_wmesg, MAXCOMLEN, wbuf); 356 wbuf[MAXCOMLEN] = '\0'; 357 db_printf(" wmesg %s wchan %lx\n", 358 wbuf, (long)l.l_wchan); 359 } 360 361 lp = LIST_NEXT(&l, l_sibling); 362 } 363 } 364