1 /* $NetBSD: db_proc.c,v 1.18 2026/03/15 21:24:17 christos 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.18 2026/03/15 21:24:17 christos 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("mawlLn", 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 case 'L': 157 db_printf("PID %5s S %3s %9s %18s %18s %-8s\n", 158 "LID", "CPU", "FLAGS", "STRUCT LWP *", "NAME", "WAIT"); 159 break; 160 case 'n': 161 db_printf("PID %8s %8s %10s S %7s %4s %16s %7s\n", 162 "PPID", "PGRP", "UID", "FLAGS", "LWPS", "COMMAND", "WAIT"); 163 break; 164 case 'w': 165 db_printf("PID %5s %16s %8s %4s %-16s %s\n", 166 "LID", "COMMAND", "EMUL", "PRI", "WAIT-MSG", 167 "WAIT-CHANNEL"); 168 break; 169 } 170 171 for (pp = db_proc_first(); pp != NULL; pp = db_proc_next(pp)) { 172 db_read_bytes((db_addr_t)pp, sizeof(p), (char *)&p); 173 if (p.p_stat == 0) { 174 continue; 175 } 176 lp = p.p_lwps.lh_first; 177 if (lp != NULL) { 178 db_read_bytes((db_addr_t)lp, sizeof(l), (char *)&l); 179 } 180 db_printf("%-5d", p.p_pid); 181 182 switch (*mode) { 183 case 'a': 184 db_printf(" %-16.16s %18lx %18lx %18lx\n", 185 p.p_comm, (long)pp, 186 (long)(lp != NULL ? l.l_addr : 0), 187 (long)p.p_vmspace); 188 break; 189 case 'l': 190 case 'L': 191 while (lp != NULL) { 192 if (l.l_name != NULL) { 193 db_read_string(l.l_name, 194 MAXCOMLEN, db_nbuf); 195 db_nbuf[MAXCOMLEN] = '\0'; 196 } else { 197 strlcpy(db_nbuf, p.p_comm, 198 sizeof(db_nbuf)); 199 } 200 run = (l.l_stat == LSONPROC || 201 (l.l_pflag & LP_RUNNING) != 0); 202 if (l.l_cpu != NULL) { 203 db_read_bytes((db_addr_t) 204 &l.l_cpu->ci_data.cpu_index, 205 sizeof(cpuno), (char *)&cpuno); 206 } else 207 cpuno = -1; 208 if (l.l_wchan && l.l_wmesg) { 209 db_read_string(l.l_wmesg, 210 sizeof(wbuf), wbuf); 211 wbuf[MAXCOMLEN] = '\0'; 212 } else { 213 wbuf[0] = '\0'; 214 } 215 db_printf("%c%5d %d %3d %9x %18lx %18s %-8s\n", 216 (run ? '>' : ' '), l.l_lid, 217 l.l_stat, cpuno, l.l_flag, (long)lp, 218 db_nbuf, wbuf); 219 if (*mode == 'L') { 220 db_stack_trace_print(\ 221 (db_expr_t)(uintptr_t)lp, 222 true, -1, "a", db_printf); 223 } 224 lp = LIST_NEXT((&l), l_sibling); 225 if (lp != NULL) { 226 db_printf("%-5d", p.p_pid); 227 db_read_bytes((db_addr_t)lp, sizeof(l), 228 (char *)&l); 229 } 230 } 231 break; 232 case 'n': 233 db_read_bytes((db_addr_t)p.p_pgrp, sizeof(pgrp), 234 (char *)&pgrp); 235 if (lp != NULL && l.l_wchan && l.l_wmesg) { 236 db_read_string(l.l_wmesg, 237 sizeof(wbuf), wbuf); 238 wbuf[MAXCOMLEN] = '\0'; 239 } else { 240 wbuf[0] = '\0'; 241 } 242 db_printf("%8d %8d %10d %d %#7x %4d %16s %7.7s\n", 243 p.p_pptr != NULL ? p.p_pptr->p_pid : -1, pgrp.pg_id, 244 #ifdef _KERNEL 245 kauth_cred_getuid(p.p_cred), 246 #else 247 /* XXX CRASH(8) */ 666, 248 #endif 249 p.p_stat, p.p_flag, 250 p.p_nlwps, p.p_comm, 251 (p.p_nlwps != 1) ? "*" : wbuf); 252 break; 253 254 case 'w': 255 while (lp != NULL) { 256 if (l.l_wchan && l.l_wmesg) { 257 db_read_string(l.l_wmesg, 258 sizeof(wbuf), wbuf); 259 wbuf[MAXCOMLEN] = '\0'; 260 } else { 261 wbuf[0] = '\0'; 262 } 263 run = (l.l_stat == LSONPROC || 264 (l.l_pflag & LP_RUNNING) != 0); 265 db_read_bytes((db_addr_t)&p.p_emul->e_name, 266 sizeof(ename), (char *)&ename); 267 268 db_read_string(ename, sizeof(db_nbuf), db_nbuf); 269 db_nbuf[MAXCOMLEN] = '\0'; 270 271 db_printf( 272 "%c%5d %16s %8s %4d %-16s %-18lx\n", 273 (run ? '>' : ' '), l.l_lid, 274 p.p_comm, db_nbuf, 275 l.l_priority, wbuf, (long)l.l_wchan); 276 lp = LIST_NEXT((&l), l_sibling); 277 if (lp != NULL) { 278 db_printf("%-5d", p.p_pid); 279 db_read_bytes((db_addr_t)lp, sizeof(l), 280 (char *)&l); 281 } 282 } 283 break; 284 } 285 } 286 } 287 288 void 289 db_show_proc(db_expr_t addr, bool haddr, db_expr_t count, const char *modif) 290 { 291 static proc_t p; 292 static lwp_t l; 293 const char *mode; 294 proc_t *pp; 295 lwp_t *lp; 296 char db_nbuf[MAXCOMLEN + 1], wbuf[MAXCOMLEN + 1]; 297 bool run; 298 int cpuno; 299 300 if (modif[0] == 0) 301 mode = "p"; /* default == by pid */ 302 else 303 mode = strchr("ap", modif[0]); 304 305 if (mode == NULL || !haddr) { 306 db_printf("usage: show proc [/a] [/p] address|pid\n"); 307 db_printf("\t/a == argument is an address of any lwp\n"); 308 db_printf("\t/p == argument is a pid [default]\n"); 309 return; 310 } 311 312 switch (*mode) { 313 case 'a': 314 lp = (lwp_t *)(uintptr_t)addr; 315 db_printf("lwp_t %lx\n", (long)lp); 316 db_read_bytes((db_addr_t)lp, sizeof(l), (char *)&l); 317 pp = l.l_proc; 318 break; 319 default: 320 case 'p': 321 pp = db_proc_find((pid_t)addr); 322 lp = NULL; 323 break; 324 } 325 326 if (pp == NULL) { 327 db_printf("bad address\n"); 328 return; 329 } 330 331 db_read_bytes((db_addr_t)pp, sizeof(p), (char *)&p); 332 if (lp == NULL) 333 lp = p.p_lwps.lh_first; 334 335 db_printf("%s: pid %d proc %lx vmspace/map %lx flags %x\n", 336 p.p_comm, p.p_pid, (long)pp, (long)p.p_vmspace, p.p_flag); 337 338 while (lp != NULL) { 339 db_read_bytes((db_addr_t)lp, sizeof(l), (char *)&l); 340 341 run = (l.l_stat == LSONPROC || 342 (l.l_pflag & LP_RUNNING) != 0); 343 344 db_printf("%slwp %d", (run ? "> " : " "), l.l_lid); 345 if (l.l_name != NULL) { 346 db_read_string(l.l_name, MAXCOMLEN, db_nbuf); 347 db_nbuf[MAXCOMLEN] = '\0'; 348 db_printf(" [%s]", db_nbuf); 349 } 350 db_printf(" %lx pcb %lx\n", (long)lp, (long)l.l_addr); 351 352 if (l.l_cpu != NULL) { 353 db_read_bytes((db_addr_t) 354 &l.l_cpu->ci_data.cpu_index, 355 sizeof(cpuno), (char *)&cpuno); 356 } else 357 cpuno = -1; 358 db_printf(" stat %d flags %x cpu %d pri %d ref %d\n", 359 l.l_stat, l.l_flag, cpuno, l.l_priority, l.l_refcnt); 360 361 if (l.l_wchan && l.l_wmesg) { 362 db_read_string(l.l_wmesg, MAXCOMLEN, wbuf); 363 wbuf[MAXCOMLEN] = '\0'; 364 db_printf(" wmesg %s wchan %lx\n", 365 wbuf, (long)l.l_wchan); 366 } 367 368 lp = LIST_NEXT(&l, l_sibling); 369 } 370 } 371