]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ddb/orig/db_print.c
xnu-123.5.tar.gz
[apple/xnu.git] / osfmk / ddb / orig / db_print.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /*
23 * @OSF_COPYRIGHT@
24 */
25 /*
26 * HISTORY
27 *
28 * Revision 1.1.1.1 1998/09/22 21:05:48 wsanchez
29 * Import of Mac OS X kernel (~semeria)
30 *
31 * Revision 1.2 1998/04/29 17:35:25 mburg
32 * MK7.3 merger
33 *
34 * Revision 1.2.85.1 1998/02/03 09:24:09 gdt
35 * Merge up to MK7.3
36 * [1998/02/03 09:10:24 gdt]
37 *
38 * Revision 1.2.81.1 1997/03/27 18:46:38 barbou
39 * ri-osc CR1565 - clean up db_print_act, removing old !USER code
40 * which had gotten stale (the option made little sense here anyway).
41 * Added routine db_show_one_thread() to take either act/shuttle and
42 * do something sensible. [dwm] Also rationalize plain, /u and /l
43 * output for "show act", "show task" and "show all acts".
44 * [1995/08/28 15:47:00 bolinger]
45 * [97/02/25 barbou]
46 *
47 * Revision 1.2.31.13 1996/01/09 19:16:02 devrcs
48 * Alpha kdebug Changes:
49 * Correct various header spacing to account for 64-bit addresses.
50 * Modify db_show_all_*() functions, so the can be called from kdebug.
51 * ( There's no way to call with "char *modif", so added NULL check. )
52 * Changed db_error() calls to DB_ERROR() macro, so we return on error
53 * on Alpha (we gotta return to kdebug).
54 * Changed declarations of 'register foo' to 'register int foo'.
55 * [1995/12/01 21:42:20 jfraser]
56 *
57 * Merged '64-bit safe' changes from DEC alpha port.
58 * [1995/11/21 18:03:24 jfraser]
59 *
60 * Revision 1.2.31.12 1995/10/09 17:03:30 devrcs
61 * Merge forward.
62 * [1995/08/24 20:56:42 watkins]
63 *
64 * Revision 1.2.59.1 1995/08/04 17:03:17 watkins
65 * Change to stack per shuttle model.
66 * [1995/07/19 20:26:13 watkins]
67 *
68 * Revision 1.2.31.11 1995/09/18 19:08:49 devrcs
69 * Merge forward.
70 * [1995/08/24 20:56:42 watkins]
71 *
72 * Revision 1.2.59.1 1995/08/04 17:03:17 watkins
73 * Change to stack per shuttle model.
74 * [1995/07/19 20:26:13 watkins]
75 *
76 * Revision 1.2.31.10 1995/05/19 15:43:04 bernadat
77 * Fixed db_print_act for empty activations.
78 * Let thread swapping be configurable.
79 * [95/05/19 bernadat]
80 *
81 * Revision 1.2.31.9 1995/05/14 18:10:25 dwm
82 * ri-osc CR1304 - merge (nmk19_latest - nmk19b1) diffs into mainline.
83 * mk6 CR938 - restore mach_msg hot path
84 * remove use of now-defunct fields in thread [mmp,dwm]
85 * [1995/05/14 17:25:05 dwm]
86 *
87 * Revision 1.2.31.8 1995/04/07 18:53:00 barbou
88 * VM Merge - Task Swapper.
89 * Renamed TH_SWAPPED to TH_STACK_HANDOFF and swap_func to continuation
90 * to resolve name conflict.
91 * From kernel/kdb/kdb_mach.c:
92 * Put in changes for swapping.
93 * [1991/11/21 20:32:15 mmp]
94 * [94/07/27 barbou]
95 * [95/03/08 barbou]
96 *
97 * Revision 1.2.31.7 1995/02/28 01:58:38 dwm
98 * mk6 CR1120 - Merge mk6pro_shared into cnmk_shared
99 * * Rev1.2.43.1 1995/01/27 22:01:26 bolinger
100 * * Fix ri-osc CR977: Make "show space" and "show ipc_port" give
101 * * accurate count of ports active in IPC space. Make "show ipc_port"
102 * * output task-visible port name.
103 * [1995/02/28 01:12:46 dwm]
104 *
105 * Revision 1.2.31.6 1995/02/23 21:43:34 alanl
106 * Fix db_show_one_task_vm for thread_act_ts.
107 * [95/01/09 rwd]
108 *
109 * Merged with DIPC2_SHARED.
110 * [95/01/04 alanl]
111 *
112 * Revision 1.2.31.5 1995/01/10 04:49:52 devrcs
113 * mk6 CR801 - merge up from nmk18b4 to nmk18b7
114 * Fix "sh thr/ul"; no cont. to print, fix pri/policy format.
115 * * Rev 1.2.31.4 1994/10/11 16:35:58 emcmanus
116 * Added "show runq" and "show shuttle".
117 * [1994/12/09 20:36:49 dwm]
118 *
119 * mk6 CR668 - 1.3b26 merge
120 * * Revision 1.2.8.6 1994/05/06 18:39:37 tmt
121 * Merged osc1.3dec/shared with osc1.3b19
122 * Merge Alpha changes into osc1.312b source code.
123 * 64bit cleanup.
124 * * End1.3merge
125 * [1994/11/04 08:49:52 dwm]
126 *
127 * Revision 1.2.31.3 1994/09/23 01:20:51 ezf
128 * change marker to not FREE
129 * [1994/09/22 21:10:41 ezf]
130 *
131 * Revision 1.2.31.2 1994/06/14 17:21:05 bolinger
132 * Merge up to NMK17.2.
133 * [1994/06/14 17:20:35 bolinger]
134 *
135 * Revision 1.2.23.4 1994/04/15 18:41:31 paire
136 * Changed interface of db_task_from_space routine.
137 * [94/03/31 paire]
138 *
139 * Revision 1.2.23.3 1994/03/07 16:37:48 paire
140 * Merge with Intel R1_1
141 * Change from NMK14.10 [1993/11/15 16:06:21 rwd]
142 *
143 * Enhanced pretty print routine and added db_task_from_space.
144 * Change from NMK14.10 [93/09/24 sjs]
145 * [94/02/21 paire]
146 *
147 * Exported ANSI prototype of db_port_kmsg_count routine.
148 * Added header file include for the declaration of db_norma_ipc routine.
149 * [94/02/15 paire]
150 *
151 * Revision 1.2.23.2 1994/02/11 14:21:58 paire
152 * Added new vm_print.h header file for db_vm declaration.
153 * [94/02/09 paire]
154 *
155 * Revision 1.2.23.1 1994/02/08 10:58:19 bernadat
156 * print out msgcount for each port in db_port_iterate
157 * Change from NORMA_MK14.6(August 93) [1993/07/27 12:35:17 mmp]
158 *
159 * Removed defintion of db_maxoff (got from <ddb/db_sym.h>).
160 * [93/08/12 paire]
161 *
162 * Show ipc_space_remote msg counts only if NORMA_IPC is on
163 * [93/07/21 bernadat]
164 *
165 * Add /s option to "show ipc_port" to pick out port sets.
166 * Change from NORMA_MK14.6 [1993/02/17 16:29:54 dwm]
167 * [93/07/16 bernadat]
168 * [94/02/07 bernadat]
169 *
170 * Revision 1.2.20.8 1994/06/08 19:11:15 dswartz
171 * Preemption merge.
172 * [1994/06/08 19:10:18 dswartz]
173 *
174 * Revision 1.2.20.7 1994/04/30 21:28:24 bolinger
175 * Thread control ops synchronization: now that TH_SUSP is back,
176 * enable ddb to show it when printing thread state.
177 * [1994/04/28 21:55:42 bolinger]
178 *
179 * Revision 1.2.20.6 1994/03/17 22:35:31 dwm
180 * The infamous name change: thread_activation + thread_shuttle = thread.
181 * [1994/03/17 21:25:46 dwm]
182 *
183 * Revision 1.2.20.5 1994/01/26 15:43:37 bolinger
184 * Move kernel_stack from thread to activation.
185 * [1994/01/25 21:53:11 bolinger]
186 *
187 * Revision 1.2.20.4 1994/01/12 17:50:44 dwm
188 * Coloc: initial restructuring to follow Utah model.
189 * [1994/01/12 17:13:12 dwm]
190 *
191 * Revision 1.2.20.3 1993/11/18 18:11:47 dwm
192 * Coloc: remove continuations entirely; they are incompatible
193 * with migration, and their volume is obfuscatory.
194 * [1993/11/18 18:06:27 dwm]
195 *
196 * Revision 1.2.20.2 1993/10/12 16:38:50 dwm
197 * CoLoc: neuter continuations, ifdef USE_CONTINUATIONS.
198 * [1993/10/12 16:14:46 dwm]
199 *
200 * Revision 1.2.8.4 1993/08/11 20:38:06 elliston
201 * Add ANSI Prototypes. CR #9523.
202 * [1993/08/11 03:33:51 elliston]
203 *
204 * Revision 1.2.8.3 1993/07/27 18:27:55 elliston
205 * Add ANSI prototypes. CR #9523.
206 * [1993/07/27 18:12:39 elliston]
207 *
208 * Revision 1.2.8.2 1993/06/09 02:20:35 gm
209 * CR9176 - ANSI C violations: trailing tokens on CPP
210 * directives, extra semicolons after decl_ ..., asm keywords
211 * [1993/06/07 18:57:22 jeffc]
212 *
213 * Removed a '#if MACH_FIXPRI' which somehow survived the purge. CR #9131.
214 * [1993/05/11 20:56:00 dswartz]
215 *
216 * Revision 1.2 1993/04/19 16:02:50 devrcs
217 * Added printout of thread scheduling policy to long form
218 * of thread display.
219 * [93/01/28 jat]
220 *
221 * Changes from mk78:
222 * Removed unused variable from db_show_regs().
223 * [92/05/16 jfriedl]
224 * Converted some db_printsyms to db_task_printsyms.
225 * [92/04/10 danner]
226 * Changed db_print_thread so that both display formats
227 * show the floating-point-used status of the thread.
228 * [92/03/16 rpd]
229 * [93/02/02 bruel]
230 *
231 * Revision 1.1 1992/09/30 02:01:18 robert
232 * Initial revision
233 *
234 * $EndLog$
235 */
236 /* CMU_HIST */
237 /*
238 * Revision 2.11.3.2 92/04/08 15:43:10 jeffreyh
239 * Added i option to show thread. This gives wait state information.
240 * [92/04/08 sjs]
241 *
242 * Revision 2.11.3.1 92/03/03 16:13:34 jeffreyh
243 * Pick up changes from TRUNK
244 * [92/02/26 11:00:01 jeffreyh]
245 *
246 * Revision 2.13 92/02/20 18:34:28 elf
247 * Fixed typo.
248 * [92/02/20 elf]
249 *
250 * Revision 2.12 92/02/19 15:07:47 elf
251 * Added db_thread_fp_used, to avoid machine-dependent conditionals.
252 * [92/02/19 rpd]
253 *
254 * Added 'F' flag to db_thread_stat showing if the thread has a valid
255 * FPU context. Tested on i386 and pmax.
256 * [92/02/17 kivinen]
257 *
258 * Revision 2.11 91/11/12 11:50:32 rvb
259 * Added OPTION_USER ("/u") to db_show_all_threads, db_show_one_thread,
260 * db_show_one_task. Without it, we display old-style information.
261 * [91/10/31 rpd]
262 *
263 * Revision 2.10 91/10/09 16:01:48 af
264 * Supported "show registers" for non current thread.
265 * Changed display format of thread and task information.
266 * Changed "show thread" to print current thread information
267 * if no thread is specified.
268 * Added "show_one_task" for "show task" command.
269 * Added IPC port print routines for "show ipc_port" command.
270 * [91/08/29 tak]
271 *
272 * Revision 2.9 91/08/03 18:17:19 jsb
273 * In db_print_thread, if the thread is swapped and there is a
274 * continuation function, print the function name in parentheses
275 * instead of '(swapped)'.
276 * [91/07/04 09:59:27 jsb]
277 *
278 * Revision 2.8 91/07/31 17:30:43 dbg
279 * Revise scheduling state machine.
280 * [91/07/30 16:43:42 dbg]
281 *
282 * Revision 2.7 91/07/09 23:15:57 danner
283 * Fixed a few printf that should be db_printfs.
284 * [91/07/08 danner]
285 *
286 * Revision 2.6 91/05/14 15:35:25 mrt
287 * Correcting copyright
288 *
289 * Revision 2.5 91/02/05 17:06:53 mrt
290 * Changed to new Mach copyright
291 * [91/01/31 16:18:56 mrt]
292 *
293 * Revision 2.4 90/10/25 14:43:54 rwd
294 * Changed db_show_regs to print unsigned.
295 * [90/10/19 rpd]
296 * Generalized the watchpoint support.
297 * [90/10/16 rwd]
298 *
299 * Revision 2.3 90/09/09 23:19:52 rpd
300 * Avoid totally incorrect guesses of symbol names for small values.
301 * [90/08/30 17:39:08 af]
302 *
303 * Revision 2.2 90/08/27 21:51:49 dbg
304 * Insist that 'show thread' be called with an explicit address.
305 * [90/08/22 dbg]
306 *
307 * Fix type for db_maxoff.
308 * [90/08/20 dbg]
309 *
310 * Do not dereference the "valuep" field of a variable directly,
311 * call the new db_read/write_variable functions instead.
312 * Reflected changes in symbol lookup functions.
313 * [90/08/20 af]
314 * Reduce lint.
315 * [90/08/10 14:33:44 dbg]
316 *
317 * Created.
318 * [90/07/25 dbg]
319 *
320 */
321 /* CMU_ENDHIST */
322 /*
323 * Mach Operating System
324 * Copyright (c) 1991,1990 Carnegie Mellon University
325 * All Rights Reserved.
326 *
327 * Permission to use, copy, modify and distribute this software and its
328 * documentation is hereby granted, provided that both the copyright
329 * notice and this permission notice appear in all copies of the
330 * software, derivative works or modified versions, and any portions
331 * thereof, and that both notices appear in supporting documentation.
332 *
333 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
334 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
335 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
336 *
337 * Carnegie Mellon requests users of this software to return to
338 *
339 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
340 * School of Computer Science
341 * Carnegie Mellon University
342 * Pittsburgh PA 15213-3890
343 *
344 * any improvements or extensions that they make and grant Carnegie Mellon
345 * the rights to redistribute these changes.
346 */
347 /*
348 */
349 /*
350 * Author: David B. Golub, Carnegie Mellon University
351 * Date: 7/90
352 */
353
354 /*
355 * Miscellaneous printing.
356 */
357 #include <dipc.h>
358 #include <task_swapper.h>
359
360 #include <string.h> /* For strlen() */
361 #include <mach/port.h>
362 #include <kern/task.h>
363 #include <kern/thread.h>
364 #include <kern/thread_swap.h>
365 #include <kern/queue.h>
366 #include <ipc/ipc_port.h>
367 #include <ipc/ipc_space.h>
368 #include <ipc/ipc_pset.h>
369 #include <vm/vm_print.h> /* for db_vm() */
370
371 #include <machine/db_machdep.h>
372 #include <machine/thread.h>
373
374 #include <ddb/db_lex.h>
375 #include <ddb/db_variables.h>
376 #include <ddb/db_sym.h>
377 #include <ddb/db_task_thread.h>
378 #include <ddb/db_command.h>
379 #include <ddb/db_output.h> /* For db_printf() */
380 #include <ddb/db_print.h>
381
382 #include <kern/sf.h>
383 #include <kern/sp_mk.h> /*** ??? fix so this can be removed ***/
384
385 #if TASK_SWAPPER
386 #include <kern/task_swap.h>
387 #endif /* TASK_SWAPPER */
388
389 /* Prototypes for functions local to this file. XXX -- should be static!
390 */
391
392 char *db_act_stat(
393 register thread_act_t thr_act,
394 char *status);
395
396 char *db_act_swap_stat(
397 register thread_act_t thr_act,
398 char *status);
399
400 void db_print_task(
401 task_t task,
402 int task_id,
403 int flag);
404
405 void db_reset_print_entry(
406 void);
407
408 void db_print_one_entry(
409 ipc_entry_t entry,
410 int index,
411 mach_port_name_t name,
412 boolean_t is_pset);
413
414 int db_port_iterate(
415 thread_act_t thr_act,
416 boolean_t is_pset,
417 boolean_t do_output);
418
419 ipc_port_t db_lookup_port(
420 thread_act_t thr_act,
421 int id);
422
423 static void db_print_port_id(
424 int id,
425 ipc_port_t port,
426 unsigned bits,
427 int n);
428
429 void db_print_act(
430 thread_act_t thr_act,
431 int act_id,
432 int flag);
433
434 void db_print_space(
435 task_t task,
436 int task_id,
437 int flag);
438
439 void db_print_task_vm(
440 task_t task,
441 int task_id,
442 boolean_t title,
443 char *modif);
444
445 void db_system_stats(void);
446
447
448 void
449 db_show_regs(
450 db_expr_t addr,
451 boolean_t have_addr,
452 db_expr_t count,
453 char *modif)
454 {
455 register struct db_variable *regp;
456 db_expr_t value;
457 db_addr_t offset;
458 char * name;
459 register int i;
460 struct db_var_aux_param aux_param;
461 task_t task = TASK_NULL;
462
463 aux_param.modif = modif;
464 aux_param.thr_act = THR_ACT_NULL;
465 if (db_option(modif, 't')) {
466 if (have_addr) {
467 if (!db_check_act_address_valid((thread_act_t)addr))
468 return;
469 aux_param.thr_act = (thread_act_t)addr;
470 } else
471 aux_param.thr_act = db_default_act;
472 if (aux_param.thr_act != THR_ACT_NULL)
473 task = aux_param.thr_act->task;
474 }
475 for (regp = db_regs; regp < db_eregs; regp++) {
476 if (regp->max_level > 1) {
477 db_printf("bad multi-suffixed register %s\n", regp->name);
478 continue;
479 }
480 aux_param.level = regp->max_level;
481 for (i = regp->low; i <= regp->high; i++) {
482 aux_param.suffix[0] = i;
483 db_read_write_variable(regp, &value, DB_VAR_GET, &aux_param);
484 if (regp->max_level > 0)
485 db_printf("%s%d%*s", regp->name, i,
486 12-strlen(regp->name)-((i<10)?1:2), "");
487 else
488 db_printf("%-12s", regp->name);
489 db_printf("%#*N", 2+2*sizeof(vm_offset_t), value);
490 db_find_xtrn_task_sym_and_offset((db_addr_t)value, &name,
491 &offset, task);
492 if (name != 0 && offset <= db_maxoff && offset != value) {
493 db_printf("\t%s", name);
494 if (offset != 0)
495 db_printf("+%#r", offset);
496 }
497 db_printf("\n");
498 }
499 }
500 }
501
502 #define OPTION_LONG 0x001 /* long print option */
503 #define OPTION_USER 0x002 /* print ps-like stuff */
504 #define OPTION_INDENT 0x100 /* print with indent */
505 #define OPTION_THREAD_TITLE 0x200 /* print thread title */
506 #define OPTION_TASK_TITLE 0x400 /* print thread title */
507
508 #ifndef DB_TASK_NAME
509 #define DB_TASK_NAME(task) /* no task name */
510 #define DB_TASK_NAME_TITLE "" /* no task name */
511 #endif /* DB_TASK_NAME */
512
513 #ifndef db_act_fp_used
514 #define db_act_fp_used(thr_act) FALSE
515 #endif
516
517 char *
518 db_act_stat(
519 register thread_act_t thr_act,
520 char *status)
521 {
522 register char *p = status;
523
524 if (!thr_act->active) {
525 *p++ = 'D',
526 *p++ = 'y',
527 *p++ = 'i',
528 *p++ = 'n',
529 *p++ = 'g';
530 *p++ = ' ';
531 } else if (!thr_act->thread) {
532 *p++ = 'E',
533 *p++ = 'm',
534 *p++ = 'p',
535 *p++ = 't',
536 *p++ = 'y';
537 *p++ = ' ';
538 } else {
539 thread_t athread = thr_act->thread;
540
541 *p++ = (athread->state & TH_RUN) ? 'R' : '.';
542 *p++ = (athread->state & TH_WAIT) ? 'W' : '.';
543 *p++ = (athread->state & TH_SUSP) ? 'S' : '.';
544 *p++ = (athread->state & TH_SWAPPED_OUT) ? 'O' : '.';
545 *p++ = (athread->state & TH_UNINT) ? 'N' : '.';
546 /* show if the FPU has been used */
547 *p++ = db_act_fp_used(thr_act) ? 'F' : '.';
548 }
549 *p++ = 0;
550 return(status);
551 }
552
553 char *
554 db_act_swap_stat(
555 register thread_act_t thr_act,
556 char *status)
557 {
558 register char *p = status;
559
560 #if THREAD_SWAPPER
561 switch (thr_act->swap_state & TH_SW_STATE) {
562 case TH_SW_UNSWAPPABLE:
563 *p++ = 'U';
564 break;
565 case TH_SW_IN:
566 *p++ = 'I';
567 break;
568 case TH_SW_GOING_OUT:
569 *p++ = 'G';
570 break;
571 case TH_SW_WANT_IN:
572 *p++ = 'W';
573 break;
574 case TH_SW_OUT:
575 *p++ = 'O';
576 break;
577 case TH_SW_COMING_IN:
578 *p++ = 'C';
579 break;
580 default:
581 *p++ = '?';
582 break;
583 }
584 *p++ = (thr_act->swap_state & TH_SW_TASK_SWAPPING) ? 'T' : '.';
585 #endif /* THREAD_SWAPPER */
586 *p++ = 0;
587
588 return status;
589 }
590
591 char *policy_list[] = { "TS", "RR", "??", "FF",
592 "??", "??", "??", "BE"};
593
594 void
595 db_print_act(
596 thread_act_t thr_act,
597 int act_id,
598 int flag)
599 {
600 thread_t athread;
601 char status[8];
602 char swap_status[3];
603 char *indent = "";
604 int policy;
605
606 if (!thr_act) {
607 db_printf("db_print_act(NULL)!\n");
608 return;
609 }
610
611 athread = thr_act->thread;
612 if (flag & OPTION_USER) {
613
614 if (flag & OPTION_LONG) {
615 if (flag & OPTION_INDENT)
616 indent = " ";
617 if (flag & OPTION_THREAD_TITLE) {
618 db_printf("%s ID: ACT STAT SW STACK SHUTTLE", indent);
619 db_printf(" SUS PRI WAIT_FUNC\n");
620 }
621 policy = (athread ? athread->policy : 2);
622 db_printf("%s%3d%c %0*X %s %s %0*X %0*X %3d %3d/%s ",
623 indent, act_id,
624 (thr_act == current_act())? '#': ':',
625 2*sizeof(vm_offset_t), thr_act,
626 db_act_stat(thr_act, status),
627 db_act_swap_stat(thr_act, swap_status),
628 2*sizeof(vm_offset_t), (athread ?athread->kernel_stack:0),
629 2*sizeof(vm_offset_t), athread,
630 thr_act->suspend_count,
631 (athread ? athread->sched_pri : 999), /* XXX */
632 policy_list[policy-1]);
633 if (athread) {
634 /* no longer TH_SWAP, no continuation to print */
635 if (athread->state & TH_WAIT)
636 db_task_printsym((db_addr_t)athread->wait_event,
637 DB_STGY_ANY, kernel_task);
638 }
639 db_printf("\n");
640 } else {
641 if (act_id % 3 == 0) {
642 if (flag & OPTION_INDENT)
643 db_printf("\n ");
644 } else
645 db_printf(" ");
646 db_printf("%3d%c(%0*X,%s)", act_id,
647 (thr_act == current_act())? '#': ':',
648 2*sizeof(vm_offset_t), thr_act,
649 db_act_stat(thr_act, status));
650 }
651 } else {
652 if (flag & OPTION_INDENT)
653 db_printf(" %3d (%0*X) ", act_id,
654 2*sizeof(vm_offset_t), thr_act);
655 else
656 db_printf("(%0*X) ", 2*sizeof(vm_offset_t), thr_act);
657 if (athread) {
658 db_printf("%c%c%c%c%c",
659 (athread->state & TH_RUN) ? 'R' : ' ',
660 (athread->state & TH_WAIT) ? 'W' : ' ',
661 (athread->state & TH_SUSP) ? 'S' : ' ',
662 (athread->state & TH_UNINT)? 'N' : ' ',
663 db_act_fp_used(thr_act) ? 'F' : ' ');
664 /* Obsolete TH_STACK_HANDOFF code, left for now; might enhance
665 * to print out safe_points instead */
666 if (athread->state & TH_STACK_HANDOFF) {
667 if (athread->continuation) {
668 db_printf("(");
669 db_task_printsym((db_addr_t)athread->continuation,
670 DB_STGY_ANY, kernel_task);
671 db_printf(")");
672 } else {
673 db_printf("(handoff)");
674 }
675 }
676 if (athread->state & TH_WAIT) {
677 db_printf(" ");
678 db_task_printsym((db_addr_t)athread->wait_event,
679 DB_STGY_ANY, kernel_task);
680 }
681 } else
682 db_printf("Empty");
683 db_printf("\n");
684 }
685 }
686
687 void
688 db_print_task(
689 task_t task,
690 int task_id,
691 int flag)
692 {
693 thread_act_t thr_act;
694 int act_id;
695 char sstate;
696
697 if (flag & OPTION_USER) {
698 if (flag & OPTION_TASK_TITLE) {
699 db_printf(" ID: TASK MAP THD RES SUS PR SW %s",
700 DB_TASK_NAME_TITLE);
701 if ((flag & OPTION_LONG) == 0)
702 db_printf(" ACTS");
703 db_printf("\n");
704 }
705 #if TASK_SWAPPER
706 switch ((int) task->swap_state) {
707 case TASK_SW_IN:
708 sstate = 'I';
709 break;
710 case TASK_SW_OUT:
711 sstate = 'O';
712 break;
713 case TASK_SW_GOING_OUT:
714 sstate = 'G';
715 break;
716 case TASK_SW_COMING_IN:
717 sstate = 'C';
718 break;
719 case TASK_SW_UNSWAPPABLE:
720 sstate = 'U';
721 break;
722 default:
723 sstate = '?';
724 break;
725 }
726 #else /* TASK_SWAPPER */
727 sstate = 'I';
728 #endif /* TASK_SWAPPER */
729 /*** ??? fix me ***/
730 db_printf("%3d: %0*X %0*X %3d %3d %3d %2d %c ",
731 task_id, 2*sizeof(vm_offset_t), task,
732 2*sizeof(vm_offset_t), task->map,
733 task->thr_act_count, task->res_act_count,
734 task->suspend_count,
735 ((mk_sp_attributes_t)(task->sp_attributes))->priority,
736 sstate);
737 DB_TASK_NAME(task);
738 if (flag & OPTION_LONG) {
739 if (flag & OPTION_TASK_TITLE)
740 flag |= OPTION_THREAD_TITLE;
741 db_printf("\n");
742 } else if (task->thr_act_count <= 1)
743 flag &= ~OPTION_INDENT;
744 act_id = 0;
745 queue_iterate(&task->thr_acts, thr_act, thread_act_t, thr_acts) {
746 db_print_act(thr_act, act_id, flag);
747 flag &= ~OPTION_THREAD_TITLE;
748 act_id++;
749 }
750 if ((flag & OPTION_LONG) == 0)
751 db_printf("\n");
752 } else {
753 if (flag & OPTION_LONG) {
754 if (flag & OPTION_TASK_TITLE) {
755 db_printf(" TASK ACT\n");
756 if (task->thr_act_count > 1)
757 flag |= OPTION_THREAD_TITLE;
758 }
759 }
760 db_printf("%3d (%0*X): ", task_id, 2*sizeof(vm_offset_t), task);
761 if (task->thr_act_count == 0) {
762 db_printf("no threads\n");
763 } else {
764 if (task->thr_act_count > 1) {
765 db_printf("%d threads: \n", task->thr_act_count);
766 flag |= OPTION_INDENT;
767 } else
768 flag &= ~OPTION_INDENT;
769 act_id = 0;
770 queue_iterate(&task->thr_acts, thr_act,
771 thread_act_t, thr_acts) {
772 db_print_act(thr_act, act_id++, flag);
773 flag &= ~OPTION_THREAD_TITLE;
774 }
775 }
776 }
777 }
778
779 void
780 db_print_space(
781 task_t task,
782 int task_id,
783 int flag)
784 {
785 ipc_space_t space;
786 thread_act_t act = (thread_act_t)queue_first(&task->thr_acts);
787 int count;
788
789 count = 0;
790 space = task->itk_space;
791 if (act)
792 count = db_port_iterate(act, FALSE, FALSE);
793 db_printf("%3d: %08x %08x %08x %sactive %d\n",
794 task_id, task, space, task->map,
795 space->is_active? "":"!", count);
796 }
797
798 void
799 db_print_task_vm(
800 task_t task,
801 int task_id,
802 boolean_t title,
803 char *modif)
804 {
805 vm_map_t map;
806 pmap_t pmap;
807 vm_size_t size;
808 long resident;
809 long wired;
810
811 if (title) {
812 db_printf("id task map pmap virtual rss pg rss mem wir pg wir mem\n");
813 }
814
815 map = task->map;
816 pmap = vm_map_pmap(map);
817
818 size = db_vm_map_total_size(map);
819 resident = pmap->stats.resident_count;
820 wired = pmap->stats.wired_count;
821
822 db_printf("%2d %08x %08x %08x %7dK %6d %6dK %6d %6dK\n",
823 task_id,
824 task,
825 map,
826 pmap,
827 size / 1024,
828 resident, (resident * PAGE_SIZE) / 1024,
829 wired, (wired * PAGE_SIZE) / 1024);
830 }
831
832
833 void
834 db_show_one_task_vm(
835 db_expr_t addr,
836 boolean_t have_addr,
837 db_expr_t count,
838 char *modif)
839 {
840 thread_act_t thread;
841 task_t task;
842 int task_id;
843
844 if (have_addr == FALSE) {
845 if ((thread = db_default_act) == THR_ACT_NULL) {
846 if ((thread = current_act()) == THR_ACT_NULL) {
847 db_printf("no thread.\n");
848 return;
849 }
850 }
851 task = thread->task;
852 } else {
853 task = (task_t) addr;
854 }
855
856 task_id = db_lookup_task(task);
857 if (task_id < 0) {
858 db_printf("0x%x is not a task_t\n", addr);
859 return;
860 }
861
862 db_print_task_vm(task, task_id, TRUE, modif);
863 }
864
865 void
866 db_show_all_task_vm(
867 db_expr_t addr,
868 boolean_t have_addr,
869 db_expr_t count,
870 char *modif)
871 {
872 task_t task;
873 int task_id;
874 boolean_t title = TRUE;
875 processor_set_t pset;
876
877 task_id = 0;
878 queue_iterate(&all_psets, pset, processor_set_t, all_psets) {
879 queue_iterate(&pset->tasks, task, task_t, pset_tasks) {
880 db_print_task_vm(task, task_id, title, modif);
881 title = FALSE;
882 task_id++;
883 }
884 }
885 }
886
887 void
888 db_show_all_acts(
889 db_expr_t addr,
890 boolean_t have_addr,
891 db_expr_t count,
892 char * modif)
893 {
894 task_t task;
895 int task_id;
896 int flag;
897 processor_set_t pset;
898
899 flag = OPTION_TASK_TITLE|OPTION_INDENT;
900 if (db_option(modif, 'u'))
901 flag |= OPTION_USER;
902 if (db_option(modif, 'l'))
903 flag |= OPTION_LONG;
904
905 task_id = 0;
906 queue_iterate(&all_psets, pset, processor_set_t, all_psets) {
907 queue_iterate(&pset->tasks, task, task_t, pset_tasks) {
908 db_print_task(task, task_id, flag);
909 flag &= ~OPTION_TASK_TITLE;
910 task_id++;
911 if ((flag & (OPTION_LONG|OPTION_INDENT)) == OPTION_INDENT)
912 db_printf("\n");
913 }
914 }
915 }
916
917 void
918 db_show_one_space(
919 db_expr_t addr,
920 boolean_t have_addr,
921 db_expr_t count,
922 char * modif)
923 {
924 int flag;
925 int task_id;
926 task_t task;
927
928 flag = OPTION_TASK_TITLE;
929 if (db_option(modif, 'u'))
930 flag |= OPTION_USER;
931 if (db_option(modif, 'l'))
932 flag |= OPTION_LONG;
933
934 if (!have_addr) {
935 task = db_current_task();
936 if (task == TASK_NULL) {
937 db_error("No task\n");
938 /*NOTREACHED*/
939 }
940 } else
941 task = (task_t) addr;
942
943 if ((task_id = db_lookup_task(task)) < 0) {
944 db_printf("bad task address 0x%x\n", addr);
945 db_error(0);
946 /*NOTREACHED*/
947 }
948
949 db_printf(" ID: TASK SPACE MAP COUNT\n");
950 db_print_space(task, task_id, flag);
951 }
952
953 void
954 db_show_all_spaces(
955 db_expr_t addr,
956 boolean_t have_addr,
957 db_expr_t count,
958 char * modif)
959 {
960 task_t task;
961 int task_id = 0;
962 int flag;
963 processor_set_t pset;
964
965 flag = OPTION_TASK_TITLE|OPTION_INDENT;
966 if (db_option(modif, 'u'))
967 flag |= OPTION_USER;
968 if (db_option(modif, 'l'))
969 flag |= OPTION_LONG;
970
971 db_printf(" ID: TASK SPACE MAP COUNT\n");
972 queue_iterate(&all_psets, pset, processor_set_t, all_psets) {
973 queue_iterate(&pset->tasks, task, task_t, pset_tasks) {
974 db_print_space(task, task_id, flag);
975 task_id++;
976 }
977 }
978 }
979
980 db_addr_t
981 db_task_from_space(
982 ipc_space_t space,
983 int *task_id)
984 {
985 task_t task;
986 int tid = 0;
987 processor_set_t pset;
988
989 queue_iterate(&all_psets, pset, processor_set_t, all_psets) {
990 queue_iterate(&pset->tasks, task, task_t, pset_tasks) {
991 if (task->itk_space == space) {
992 *task_id = tid;
993 return (db_addr_t)task;
994 }
995 tid++;
996 }
997 }
998 *task_id = 0;
999 return (0);
1000 }
1001
1002 void
1003 db_show_one_act(
1004 db_expr_t addr,
1005 boolean_t have_addr,
1006 db_expr_t count,
1007 char * modif)
1008 {
1009 int flag;
1010 int act_id;
1011 thread_act_t thr_act;
1012
1013 flag = OPTION_THREAD_TITLE;
1014 if (db_option(modif, 'u'))
1015 flag |= OPTION_USER;
1016 if (db_option(modif, 'l'))
1017 flag |= OPTION_LONG;
1018
1019 if (!have_addr) {
1020 thr_act = current_act();
1021 if (thr_act == THR_ACT_NULL) {
1022 db_error("No thr_act\n");
1023 /*NOTREACHED*/
1024 }
1025 } else
1026 thr_act = (thread_act_t) addr;
1027
1028 if ((act_id = db_lookup_act(thr_act)) < 0) {
1029 db_printf("bad thr_act address %#x\n", addr);
1030 db_error(0);
1031 /*NOTREACHED*/
1032 }
1033
1034 if (flag & OPTION_USER) {
1035 db_printf("TASK%d(%0*X):\n",
1036 db_lookup_task(thr_act->task),
1037 2*sizeof(vm_offset_t), thr_act->task);
1038 db_print_act(thr_act, act_id, flag);
1039 } else {
1040 db_printf("task %d(%0*Xx): thr_act %d",
1041 db_lookup_task(thr_act->task),
1042 2*sizeof(vm_offset_t), thr_act->task, act_id);
1043 db_print_act(thr_act, act_id, flag);
1044 }
1045 if (db_option(modif, 'i') && thr_act->thread &&
1046 (thr_act->thread->state & TH_WAIT) &&
1047 thr_act->thread->kernel_stack == 0) {
1048
1049 db_printf("Wait State: option 0x%x\n",
1050 thr_act->thread->ith_option);
1051 }
1052 }
1053
1054 void
1055 db_show_one_task(
1056 db_expr_t addr,
1057 boolean_t have_addr,
1058 db_expr_t count,
1059 char * modif)
1060 {
1061 int flag;
1062 int task_id;
1063 task_t task;
1064
1065 flag = OPTION_TASK_TITLE|OPTION_INDENT;
1066 if (db_option(modif, 'u'))
1067 flag |= OPTION_USER;
1068 if (db_option(modif, 'l'))
1069 flag |= OPTION_LONG;
1070
1071 if (!have_addr) {
1072 task = db_current_task();
1073 if (task == TASK_NULL) {
1074 db_error("No task\n");
1075 /*NOTREACHED*/
1076 }
1077 } else
1078 task = (task_t) addr;
1079
1080 if ((task_id = db_lookup_task(task)) < 0) {
1081 db_printf("bad task address 0x%x\n", addr);
1082 db_error(0);
1083 /*NOTREACHED*/
1084 }
1085
1086 db_print_task(task, task_id, flag);
1087 }
1088
1089 void
1090 db_show_shuttle(
1091 db_expr_t addr,
1092 boolean_t have_addr,
1093 db_expr_t count,
1094 char * modif)
1095 {
1096 thread_shuttle_t shuttle;
1097 thread_act_t thr_act;
1098
1099 if (have_addr)
1100 shuttle = (thread_shuttle_t) addr;
1101 else {
1102 thr_act = current_act();
1103 if (thr_act == THR_ACT_NULL) {
1104 db_error("No thr_act\n");
1105 /*NOTREACHED*/
1106 }
1107 shuttle = thr_act->thread;
1108 if (shuttle == THREAD_NULL) {
1109 db_error("No shuttle associated with current thr_act\n");
1110 /*NOTREACHED*/
1111 }
1112 }
1113 db_printf("shuttle %x:\n", shuttle);
1114 if (shuttle->top_act == THR_ACT_NULL)
1115 db_printf(" no activations\n");
1116 else {
1117 db_printf(" activations:");
1118 for (thr_act = shuttle->top_act; thr_act != THR_ACT_NULL;
1119 thr_act = thr_act->lower) {
1120 if (thr_act != shuttle->top_act)
1121 printf(" from");
1122 printf(" $task%d.%d(%x)", db_lookup_task(thr_act->task),
1123 db_lookup_act(thr_act), thr_act);
1124 }
1125 db_printf("\n");
1126 }
1127 }
1128
1129 #define db_pset_kmsg_count(port) \
1130 (ipc_list_count((port)->ip_pset->ips_messages.imq_messages.ikmq_base))
1131
1132 int
1133 db_port_kmsg_count(
1134 ipc_port_t port)
1135 {
1136 return (port->ip_pset ? db_pset_kmsg_count(port) : port->ip_msgcount);
1137 }
1138
1139 static int db_print_ent_cnt = 0;
1140
1141 void db_reset_print_entry(
1142 void)
1143 {
1144 db_print_ent_cnt = 0;
1145 }
1146
1147 void
1148 db_print_one_entry(
1149 ipc_entry_t entry,
1150 int index,
1151 mach_port_t name,
1152 boolean_t is_pset)
1153 {
1154 ipc_port_t aport = (ipc_port_t)entry->ie_object;
1155 unsigned bits = entry->ie_bits;
1156
1157 if (is_pset && !aport->ip_pset)
1158 return;
1159 if (db_print_ent_cnt && db_print_ent_cnt % 2 == 0)
1160 db_printf("\n");
1161 if (!name)
1162 db_printf("\t%s%d[%x]",
1163 !is_pset && aport->ip_pset ? "pset" : "port",
1164 index,
1165 MACH_PORT_MAKE(index, IE_BITS_GEN(bits)));
1166 else
1167 db_printf("\t%s[%x]",
1168 !is_pset && aport->ip_pset ? "pset" : "port",
1169 name);
1170 if (!is_pset) {
1171 db_printf("(%s,%x,%d)",
1172 (bits & MACH_PORT_TYPE_RECEIVE)? "r":
1173 (bits & MACH_PORT_TYPE_SEND)? "s": "S",
1174 aport,
1175 db_port_kmsg_count(aport));
1176 db_print_ent_cnt++;
1177 }
1178 else {
1179 db_printf("(%s,%x,set=%x,%d)",
1180 (bits & MACH_PORT_TYPE_RECEIVE)? "r":
1181 (bits & MACH_PORT_TYPE_SEND)? "s": "S",
1182 aport,
1183 aport->ip_pset,
1184 db_pset_kmsg_count(aport));
1185 db_print_ent_cnt++;
1186 }
1187 }
1188
1189 int
1190 db_port_iterate(
1191 thread_act_t thr_act,
1192 boolean_t is_pset,
1193 boolean_t do_output)
1194 {
1195 ipc_entry_t entry;
1196 ipc_tree_entry_t tentry;
1197 int index;
1198 int size;
1199 int count;
1200 ipc_space_t space;
1201
1202 count = 0;
1203 space = thr_act->task->itk_space;
1204 entry = space->is_table;
1205 size = space->is_table_size;
1206 db_reset_print_entry();
1207 for (index = 0; index < size; ++index, ++entry) {
1208 if (entry->ie_bits & MACH_PORT_TYPE_PORT_RIGHTS) {
1209 if (do_output)
1210 db_print_one_entry(entry,
1211 index, (mach_port_t)0, is_pset);
1212 ++count;
1213 }
1214 }
1215 for (tentry = ipc_splay_traverse_start(&space->is_tree);
1216 tentry != ITE_NULL;
1217 tentry = ipc_splay_traverse_next(&space->is_tree, FALSE)) {
1218 entry = &tentry->ite_entry;
1219 if (entry->ie_bits & MACH_PORT_TYPE_PORT_RIGHTS) {
1220 if (do_output)
1221 db_print_one_entry(entry,
1222 0, tentry->ite_name, is_pset);
1223 ++count;
1224 }
1225 }
1226 return (count);
1227 }
1228
1229 ipc_port_t
1230 db_lookup_port(
1231 thread_act_t thr_act,
1232 int id)
1233 {
1234 register ipc_space_t space;
1235 register ipc_entry_t entry;
1236
1237 if (thr_act == THR_ACT_NULL)
1238 return(0);
1239 space = thr_act->task->itk_space;
1240 if (id < 0 || id >= space->is_table_size)
1241 return(0);
1242 entry = &space->is_table[id];
1243 if (entry->ie_bits & MACH_PORT_TYPE_PORT_RIGHTS)
1244 return((ipc_port_t)entry->ie_object);
1245 return(0);
1246 }
1247
1248 static void
1249 db_print_port_id(
1250 int id,
1251 ipc_port_t port,
1252 unsigned bits,
1253 int n)
1254 {
1255 if (n != 0 && n % 3 == 0)
1256 db_printf("\n");
1257 db_printf("\tport%d(%s,%x)", id,
1258 (bits & MACH_PORT_TYPE_RECEIVE)? "r":
1259 (bits & MACH_PORT_TYPE_SEND)? "s": "S", port);
1260 }
1261
1262 void
1263 db_show_port_id(
1264 db_expr_t addr,
1265 boolean_t have_addr,
1266 db_expr_t count,
1267 char * modif)
1268 {
1269 thread_act_t thr_act;
1270
1271 if (!have_addr) {
1272 thr_act = current_act();
1273 if (thr_act == THR_ACT_NULL) {
1274 db_error("No thr_act\n");
1275 /*NOTREACHED*/
1276 }
1277 } else
1278 thr_act = (thread_act_t) addr;
1279 if (db_lookup_act(thr_act) < 0) {
1280 db_printf("Bad thr_act address 0x%x\n", addr);
1281 db_error(0);
1282 /*NOTREACHED*/
1283 }
1284 if (db_port_iterate(thr_act, db_option(modif,'s'), TRUE))
1285 db_printf("\n");
1286 }
1287
1288 /*
1289 * Useful system state when the world has hung.
1290 */
1291 void
1292 db_system_stats()
1293 {
1294 extern void db_device(void);
1295 extern void db_sched(void);
1296 #if DIPC
1297 extern void db_dipc_stats(void);
1298 extern void db_show_kkt(void);
1299 #endif /* DIPC */
1300
1301 db_sched();
1302 iprintf("\n");
1303 db_vm();
1304 iprintf("\n");
1305 db_device();
1306 #if DIPC
1307 iprintf("\n");
1308 db_dipc_stats();
1309 iprintf("\n");
1310 db_show_kkt();
1311 #endif /* DIPC */
1312 iprintf("\n");
1313 db_printf("current_{thread/task} 0x%x 0x%x\n",
1314 current_thread(),current_task());
1315 }
1316
1317 void db_show_one_runq(run_queue_t runq);
1318
1319 void
1320 db_show_runq(
1321 db_expr_t addr,
1322 boolean_t have_addr,
1323 db_expr_t count,
1324 char * modif)
1325 {
1326 processor_set_t pset;
1327 processor_t proc;
1328 run_queue_t runq;
1329 boolean_t showedany = FALSE;
1330
1331 queue_iterate(&all_psets, pset, processor_set_t, all_psets) {
1332 #if NCPUS > 1 /* This code has not been tested. */
1333 queue_iterate(&pset->processors, proc, processor_t, processors) {
1334 runq = &proc->runq;
1335 if (runq->count > 0) {
1336 db_printf("PROCESSOR %x IN SET %x\n", proc, pset);
1337 db_show_one_runq(runq);
1338 showedany = TRUE;
1339 }
1340 }
1341 #endif /* NCPUS > 1 */
1342 #ifndef NCPUS
1343 #error NCPUS undefined
1344 #endif
1345 runq = &pset->runq;
1346 if (runq->count > 0) {
1347 db_printf("PROCESSOR SET %x\n", pset);
1348 db_show_one_runq(runq);
1349 showedany = TRUE;
1350 }
1351 }
1352 if (!showedany)
1353 db_printf("No runnable threads\n");
1354 }
1355
1356 void
1357 db_show_one_runq(
1358 run_queue_t runq)
1359 {
1360 int i, task_id, thr_act_id;
1361 queue_t q;
1362 thread_act_t thr_act;
1363 thread_t thread;
1364 task_t task;
1365
1366 printf("PRI TASK.ACTIVATION\n");
1367 for (i = runq->low, q = runq->runq + i; i < NRQS; i++, q++) {
1368 if (!queue_empty(q)) {
1369 db_printf("%3d:", i);
1370 queue_iterate(q, thread, thread_t, links) {
1371 thr_act = thread->top_act;
1372 task = thr_act->task;
1373 task_id = db_lookup_task(task);
1374 thr_act_id = db_lookup_task_act(task, thr_act);
1375 db_printf(" %d.%d", task_id, thr_act_id);
1376 }
1377 db_printf("\n");
1378 }
1379 }
1380 }