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