2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
20 * @APPLE_LICENSE_HEADER_END@
26 * Mach Operating System
27 * Copyright (c) 1991,1990 Carnegie Mellon University
28 * All Rights Reserved.
30 * Permission to use, copy, modify and distribute this software and its
31 * documentation is hereby granted, provided that both the copyright
32 * notice and this permission notice appear in all copies of the
33 * software, derivative works or modified versions, and any portions
34 * thereof, and that both notices appear in supporting documentation.
36 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
37 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
38 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
40 * Carnegie Mellon requests users of this software to return to
42 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
43 * School of Computer Science
44 * Carnegie Mellon University
45 * Pittsburgh PA 15213-3890
47 * any improvements or extensions that they make and grant Carnegie Mellon
48 * the rights to redistribute these changes.
53 * Author: David B. Golub, Carnegie Mellon University
58 * Miscellaneous printing.
60 #include <task_swapper.h>
62 #include <string.h> /* For strlen() */
63 #include <mach/port.h>
64 #include <kern/task.h>
65 #include <kern/thread.h>
66 #include <kern/thread_swap.h>
67 #include <kern/queue.h>
68 #include <kern/processor.h>
69 #include <ipc/ipc_port.h>
70 #include <ipc/ipc_space.h>
71 #include <ipc/ipc_pset.h>
72 #include <vm/vm_print.h> /* for db_vm() */
74 #include <machine/db_machdep.h>
75 #include <machine/thread.h>
77 #include <ddb/db_lex.h>
78 #include <ddb/db_variables.h>
79 #include <ddb/db_sym.h>
80 #include <ddb/db_task_thread.h>
81 #include <ddb/db_command.h>
82 #include <ddb/db_output.h> /* For db_printf() */
83 #include <ddb/db_print.h>
86 #include <kern/task_swap.h>
87 #endif /* TASK_SWAPPER */
89 /* Prototypes for functions local to this file. XXX -- should be static!
93 register thread_act_t thr_act
,
96 char *db_act_swap_stat(
97 register thread_act_t thr_act
,
105 void db_reset_print_entry(
108 void db_print_one_entry(
111 mach_port_name_t name
,
116 thread_act_t thr_act
,
118 boolean_t do_output
);
120 ipc_port_t
db_lookup_port(
121 thread_act_t thr_act
,
124 static void db_print_port_id(
131 thread_act_t thr_act
,
140 void db_print_task_vm(
146 void db_system_stats(void);
156 register struct db_variable
*regp
;
161 struct db_var_aux_param aux_param
;
162 task_t task
= TASK_NULL
;
164 aux_param
.modif
= modif
;
165 aux_param
.thr_act
= THR_ACT_NULL
;
166 if (db_option(modif
, 't')) {
168 if (!db_check_act_address_valid((thread_act_t
)addr
))
170 aux_param
.thr_act
= (thread_act_t
)addr
;
172 aux_param
.thr_act
= db_default_act
;
173 if (aux_param
.thr_act
!= THR_ACT_NULL
)
174 task
= aux_param
.thr_act
->task
;
176 for (regp
= db_regs
; regp
< db_eregs
; regp
++) {
177 if (regp
->max_level
> 1) {
178 db_printf("bad multi-suffixed register %s\n", regp
->name
);
181 aux_param
.level
= regp
->max_level
;
182 for (i
= regp
->low
; i
<= regp
->high
; i
++) {
183 aux_param
.suffix
[0] = i
;
184 db_read_write_variable(regp
, &value
, DB_VAR_GET
, &aux_param
);
185 if (regp
->max_level
> 0)
186 db_printf("%s%d%*s", regp
->name
, i
,
187 12-strlen(regp
->name
)-((i
<10)?1:2), "");
189 db_printf("%-12s", regp
->name
);
190 db_printf("%#*N", 2+2*sizeof(vm_offset_t
), value
);
191 db_find_xtrn_task_sym_and_offset((db_addr_t
)value
, &name
,
193 if (name
!= 0 && offset
<= db_maxoff
&& offset
!= value
) {
194 db_printf("\t%s", name
);
196 db_printf("+%#r", offset
);
203 #define OPTION_LONG 0x001 /* long print option */
204 #define OPTION_USER 0x002 /* print ps-like stuff */
205 #define OPTION_INDENT 0x100 /* print with indent */
206 #define OPTION_THREAD_TITLE 0x200 /* print thread title */
207 #define OPTION_TASK_TITLE 0x400 /* print thread title */
210 #define DB_TASK_NAME(task) /* no task name */
211 #define DB_TASK_NAME_TITLE "" /* no task name */
212 #endif /* DB_TASK_NAME */
214 #ifndef db_act_fp_used
215 #define db_act_fp_used(thr_act) FALSE
220 register thread_act_t thr_act
,
223 register char *p
= status
;
225 if (!thr_act
->active
) {
232 } else if (!thr_act
->thread
) {
240 thread_t athread
= thr_act
->thread
;
242 *p
++ = (athread
->state
& TH_RUN
) ? 'R' : '.';
243 *p
++ = (athread
->state
& TH_WAIT
) ? 'W' : '.';
244 *p
++ = (athread
->state
& TH_SUSP
) ? 'S' : '.';
245 *p
++ = (athread
->state
& TH_STACK_HANDOFF
) ? 'O' : '.';
246 *p
++ = (athread
->state
& TH_UNINT
) ? 'N' : '.';
247 /* show if the FPU has been used */
248 *p
++ = db_act_fp_used(thr_act
) ? 'F' : '.';
256 register thread_act_t thr_act
,
259 register char *p
= status
;
262 switch (thr_act
->swap_state
& TH_SW_STATE
) {
263 case TH_SW_UNSWAPPABLE
:
269 case TH_SW_GOING_OUT
:
278 case TH_SW_COMING_IN
:
285 *p
++ = (thr_act
->swap_state
& TH_SW_TASK_SWAPPING
) ? 'T' : '.';
286 #endif /* THREAD_SWAPPER */
292 char *policy_list
[] = { "TS", "RR", "??", "FF",
293 "??", "??", "??", "BE"};
297 thread_act_t thr_act
,
308 db_printf("db_print_act(NULL)!\n");
312 athread
= thr_act
->thread
;
313 if (flag
& OPTION_USER
) {
315 if (flag
& OPTION_LONG
) {
316 if (flag
& OPTION_INDENT
)
318 if (flag
& OPTION_THREAD_TITLE
) {
319 db_printf("%s ID: ACT STAT SW STACK SHUTTLE", indent
);
320 db_printf(" SUS PRI WAIT_FUNC\n");
322 policy
= ((athread
&& (athread
->sched_mode
&TH_MODE_TIMESHARE
))? 1: 2);
323 db_printf("%s%3d%c %0*X %s %s %0*X %0*X %3d %3d/%s ",
325 (thr_act
== current_act())? '#': ':',
326 2*sizeof(vm_offset_t
), thr_act
,
327 db_act_stat(thr_act
, status
),
328 db_act_swap_stat(thr_act
, swap_status
),
329 2*sizeof(vm_offset_t
), (athread
?athread
->kernel_stack
:0),
330 2*sizeof(vm_offset_t
), athread
,
331 thr_act
->suspend_count
,
332 (athread
? athread
->sched_pri
: 999), /* XXX */
333 policy_list
[policy
-1]);
335 /* no longer TH_SWAP, no continuation to print */
336 if (athread
->state
& TH_WAIT
)
337 db_task_printsym((db_addr_t
)athread
->wait_event
,
338 DB_STGY_ANY
, kernel_task
);
342 if (act_id
% 3 == 0) {
343 if (flag
& OPTION_INDENT
)
347 db_printf("%3d%c(%0*X,%s)", act_id
,
348 (thr_act
== current_act())? '#': ':',
349 2*sizeof(vm_offset_t
), thr_act
,
350 db_act_stat(thr_act
, status
));
353 if (flag
& OPTION_INDENT
)
354 db_printf(" %3d (%0*X) ", act_id
,
355 2*sizeof(vm_offset_t
), thr_act
);
357 db_printf("(%0*X) ", 2*sizeof(vm_offset_t
), thr_act
);
359 db_printf("%c%c%c%c%c",
360 (athread
->state
& TH_RUN
) ? 'R' : ' ',
361 (athread
->state
& TH_WAIT
) ? 'W' : ' ',
362 (athread
->state
& TH_SUSP
) ? 'S' : ' ',
363 (athread
->state
& TH_UNINT
)? 'N' : ' ',
364 db_act_fp_used(thr_act
) ? 'F' : ' ');
365 /* Obsolete TH_STACK_HANDOFF code, left for now; might enhance
366 * to print out safe_points instead */
367 if (athread
->state
& TH_STACK_HANDOFF
) {
368 if (athread
->continuation
) {
370 db_task_printsym((db_addr_t
)athread
->continuation
,
371 DB_STGY_ANY
, kernel_task
);
374 db_printf("(handoff)");
377 if (athread
->state
& TH_WAIT
) {
379 db_task_printsym((db_addr_t
)athread
->wait_event
,
380 DB_STGY_ANY
, kernel_task
);
394 thread_act_t thr_act
;
398 if (flag
& OPTION_USER
) {
399 if (flag
& OPTION_TASK_TITLE
) {
400 db_printf(" ID: TASK MAP THD RES SUS PR SW %s",
402 if ((flag
& OPTION_LONG
) == 0)
407 switch ((int) task
->swap_state
) {
414 case TASK_SW_GOING_OUT
:
417 case TASK_SW_COMING_IN
:
420 case TASK_SW_UNSWAPPABLE
:
427 #else /* TASK_SWAPPER */
429 #endif /* TASK_SWAPPER */
431 db_printf("%3d: %0*X %0*X %3d %3d %3d %2d %c ",
432 task_id
, 2*sizeof(vm_offset_t
), task
,
433 2*sizeof(vm_offset_t
), task
->map
,
434 task
->thr_act_count
, task
->res_act_count
,
439 if (flag
& OPTION_LONG
) {
440 if (flag
& OPTION_TASK_TITLE
)
441 flag
|= OPTION_THREAD_TITLE
;
443 } else if (task
->thr_act_count
<= 1)
444 flag
&= ~OPTION_INDENT
;
446 queue_iterate(&task
->thr_acts
, thr_act
, thread_act_t
, thr_acts
) {
447 db_print_act(thr_act
, act_id
, flag
);
448 flag
&= ~OPTION_THREAD_TITLE
;
451 if ((flag
& OPTION_LONG
) == 0)
454 if (flag
& OPTION_LONG
) {
455 if (flag
& OPTION_TASK_TITLE
) {
456 db_printf(" TASK ACT\n");
457 if (task
->thr_act_count
> 1)
458 flag
|= OPTION_THREAD_TITLE
;
461 db_printf("%3d (%0*X): ", task_id
, 2*sizeof(vm_offset_t
), task
);
462 if (task
->thr_act_count
== 0) {
463 db_printf("no threads\n");
465 if (task
->thr_act_count
> 1) {
466 db_printf("%d threads: \n", task
->thr_act_count
);
467 flag
|= OPTION_INDENT
;
469 flag
&= ~OPTION_INDENT
;
471 queue_iterate(&task
->thr_acts
, thr_act
,
472 thread_act_t
, thr_acts
) {
473 db_print_act(thr_act
, act_id
++, flag
);
474 flag
&= ~OPTION_THREAD_TITLE
;
487 thread_act_t act
= (thread_act_t
)queue_first(&task
->thr_acts
);
491 space
= task
->itk_space
;
493 count
= db_port_iterate(act
, FALSE
, FALSE
);
494 db_printf("%3d: %08x %08x %08x %sactive %d\n",
495 task_id
, task
, space
, task
->map
,
496 space
->is_active
? "":"!", count
);
513 db_printf("id task map pmap virtual rss pg rss mem wir pg wir mem\n");
517 pmap
= vm_map_pmap(map
);
519 size
= db_vm_map_total_size(map
);
520 resident
= pmap
->stats
.resident_count
;
521 wired
= pmap
->stats
.wired_count
;
523 db_printf("%2d %08x %08x %08x %7dK %6d %6dK %6d %6dK\n",
529 resident
, (resident
* PAGE_SIZE
) / 1024,
530 wired
, (wired
* PAGE_SIZE
) / 1024);
545 if (have_addr
== FALSE
) {
546 if ((thread
= db_default_act
) == THR_ACT_NULL
) {
547 if ((thread
= current_act()) == THR_ACT_NULL
) {
548 db_printf("no thread.\n");
554 task
= (task_t
) addr
;
557 task_id
= db_lookup_task(task
);
559 db_printf("0x%x is not a task_t\n", addr
);
563 db_print_task_vm(task
, task_id
, TRUE
, modif
);
575 boolean_t title
= TRUE
;
576 processor_set_t pset
= &default_pset
;
579 queue_iterate(&pset
->tasks
, task
, task_t
, pset_tasks
) {
580 db_print_task_vm(task
, task_id
, title
, modif
);
596 processor_set_t pset
= &default_pset
;
598 flag
= OPTION_TASK_TITLE
|OPTION_INDENT
;
599 if (db_option(modif
, 'u'))
601 if (db_option(modif
, 'l'))
605 queue_iterate(&pset
->tasks
, task
, task_t
, pset_tasks
) {
606 db_print_task(task
, task_id
, flag
);
607 flag
&= ~OPTION_TASK_TITLE
;
609 if ((flag
& (OPTION_LONG
|OPTION_INDENT
)) == OPTION_INDENT
)
625 flag
= OPTION_TASK_TITLE
;
626 if (db_option(modif
, 'u'))
628 if (db_option(modif
, 'l'))
632 task
= db_current_task();
633 if (task
== TASK_NULL
) {
634 db_error("No task\n");
638 task
= (task_t
) addr
;
640 if ((task_id
= db_lookup_task(task
)) < 0) {
641 db_printf("bad task address 0x%x\n", addr
);
646 db_printf(" ID: TASK SPACE MAP COUNT\n");
647 db_print_space(task
, task_id
, flag
);
660 processor_set_t pset
= &default_pset
;
662 flag
= OPTION_TASK_TITLE
|OPTION_INDENT
;
663 if (db_option(modif
, 'u'))
665 if (db_option(modif
, 'l'))
668 db_printf(" ID: TASK SPACE MAP COUNT\n");
669 queue_iterate(&pset
->tasks
, task
, task_t
, pset_tasks
) {
670 db_print_space(task
, task_id
, flag
);
682 processor_set_t pset
= &default_pset
;
684 queue_iterate(&pset
->tasks
, task
, task_t
, pset_tasks
) {
685 if (task
->itk_space
== space
) {
687 return (db_addr_t
)task
;
704 thread_act_t thr_act
;
706 flag
= OPTION_THREAD_TITLE
;
707 if (db_option(modif
, 'u'))
709 if (db_option(modif
, 'l'))
713 thr_act
= current_act();
714 if (thr_act
== THR_ACT_NULL
) {
715 db_error("No thr_act\n");
719 thr_act
= (thread_act_t
) addr
;
721 if ((act_id
= db_lookup_act(thr_act
)) < 0) {
722 db_printf("bad thr_act address %#x\n", addr
);
727 if (flag
& OPTION_USER
) {
728 db_printf("TASK%d(%0*X):\n",
729 db_lookup_task(thr_act
->task
),
730 2*sizeof(vm_offset_t
), thr_act
->task
);
731 db_print_act(thr_act
, act_id
, flag
);
733 db_printf("task %d(%0*Xx): thr_act %d",
734 db_lookup_task(thr_act
->task
),
735 2*sizeof(vm_offset_t
), thr_act
->task
, act_id
);
736 db_print_act(thr_act
, act_id
, flag
);
738 if (db_option(modif
, 'i') && thr_act
->thread
&&
739 (thr_act
->thread
->state
& TH_WAIT
) &&
740 thr_act
->thread
->kernel_stack
== 0) {
742 db_printf("Wait State: option 0x%x\n",
743 thr_act
->thread
->ith_option
);
758 flag
= OPTION_TASK_TITLE
|OPTION_INDENT
;
759 if (db_option(modif
, 'u'))
761 if (db_option(modif
, 'l'))
765 task
= db_current_task();
766 if (task
== TASK_NULL
) {
767 db_error("No task\n");
771 task
= (task_t
) addr
;
773 if ((task_id
= db_lookup_task(task
)) < 0) {
774 db_printf("bad task address 0x%x\n", addr
);
779 db_print_task(task
, task_id
, flag
);
789 thread_shuttle_t shuttle
;
790 thread_act_t thr_act
;
793 shuttle
= (thread_shuttle_t
) addr
;
795 thr_act
= current_act();
796 if (thr_act
== THR_ACT_NULL
) {
797 db_error("No thr_act\n");
800 shuttle
= thr_act
->thread
;
801 if (shuttle
== THREAD_NULL
) {
802 db_error("No shuttle associated with current thr_act\n");
806 db_printf("shuttle %x:\n", shuttle
);
807 if (shuttle
->top_act
== THR_ACT_NULL
)
808 db_printf(" no activations\n");
810 db_printf(" activations:");
811 for (thr_act
= shuttle
->top_act
; thr_act
!= THR_ACT_NULL
;
812 thr_act
= thr_act
->lower
) {
813 if (thr_act
!= shuttle
->top_act
)
815 printf(" $task%d.%d(%x)", db_lookup_task(thr_act
->task
),
816 db_lookup_act(thr_act
), thr_act
);
826 return (port
->ip_messages
.imq_msgcount
);
829 static int db_print_ent_cnt
= 0;
831 void db_reset_print_entry(
834 db_print_ent_cnt
= 0;
841 mach_port_name_t name
,
845 ipc_port_t aport
= (ipc_port_t
)entry
->ie_object
;
846 ipc_entry_bits_t bits
;
848 bits
= entry
->ie_bits
;
849 if (is_pset
&& !aport
->ip_pset_count
)
851 if (db_print_ent_cnt
&& db_print_ent_cnt
% 2 == 0)
854 db_printf("\t%s%d[%x]",
855 !is_pset
&& aport
->ip_pset_count
? "pset" : "port",
857 MACH_PORT_MAKE(index
, IE_BITS_GEN(bits
)));
859 db_printf("\t%s[%x]",
860 !is_pset
&& aport
->ip_pset_count
? "pset" : "port",
863 db_printf("(%s,%x,%d)",
864 (bits
& MACH_PORT_TYPE_RECEIVE
)? "r":
865 (bits
& MACH_PORT_TYPE_SEND
)? "s": "S",
867 db_port_kmsg_count(aport
));
871 db_printf("(%s,%x,set_count=%d,%d)",
872 (bits
& MACH_PORT_TYPE_RECEIVE
)? "r":
873 (bits
& MACH_PORT_TYPE_SEND
)? "s": "S",
875 aport
->ip_pset_count
,
876 db_port_kmsg_count(aport
));
883 thread_act_t thr_act
,
888 ipc_tree_entry_t tentry
;
895 space
= thr_act
->task
->itk_space
;
896 entry
= space
->is_table
;
897 size
= space
->is_table_size
;
898 db_reset_print_entry();
899 for (index
= 0; index
< size
; ++index
, ++entry
) {
900 if (entry
->ie_bits
& MACH_PORT_TYPE_PORT_RIGHTS
) {
902 db_print_one_entry(entry
,
903 index
, MACH_PORT_NULL
, is_pset
, space
);
907 for (tentry
= ipc_splay_traverse_start(&space
->is_tree
);
909 tentry
= ipc_splay_traverse_next(&space
->is_tree
, FALSE
)) {
910 entry
= &tentry
->ite_entry
;
911 if (entry
->ie_bits
& MACH_PORT_TYPE_PORT_RIGHTS
) {
913 db_print_one_entry(entry
,
914 0, tentry
->ite_name
, is_pset
, space
);
923 thread_act_t thr_act
,
926 register ipc_space_t space
;
927 register ipc_entry_t entry
;
929 if (thr_act
== THR_ACT_NULL
)
931 space
= thr_act
->task
->itk_space
;
932 if (id
< 0 || id
>= space
->is_table_size
)
934 entry
= &space
->is_table
[id
];
935 if (entry
->ie_bits
& MACH_PORT_TYPE_PORT_RIGHTS
)
936 return((ipc_port_t
)entry
->ie_object
);
947 if (n
!= 0 && n
% 3 == 0)
949 db_printf("\tport%d(%s,%x)", id
,
950 (bits
& MACH_PORT_TYPE_RECEIVE
)? "r":
951 (bits
& MACH_PORT_TYPE_SEND
)? "s": "S", port
);
961 thread_act_t thr_act
;
964 thr_act
= current_act();
965 if (thr_act
== THR_ACT_NULL
) {
966 db_error("No thr_act\n");
970 thr_act
= (thread_act_t
) addr
;
971 if (db_lookup_act(thr_act
) < 0) {
972 db_printf("Bad thr_act address 0x%x\n", addr
);
976 if (db_port_iterate(thr_act
, db_option(modif
,'s'), TRUE
))
981 * Useful system state when the world has hung.
986 extern void db_sched(void);
993 db_printf("current_{thread/task} 0x%x 0x%x\n",
994 current_thread(),current_task());
997 void db_show_one_runq(run_queue_t runq
);
1002 boolean_t have_addr
,
1006 processor_set_t pset
= &default_pset
;
1009 boolean_t showedany
= FALSE
;
1011 #if NCPUS > 1 /* This code has not been tested. */
1012 queue_iterate(&pset
->processors
, proc
, processor_t
, processors
) {
1014 if (runq
->count
> 0) {
1015 db_printf("PROCESSOR %x IN SET %x\n", proc
, pset
);
1016 db_show_one_runq(runq
);
1020 #endif /* NCPUS > 1 */
1022 #error NCPUS undefined
1025 if (runq
->count
> 0) {
1026 db_printf("PROCESSOR SET %x\n", pset
);
1027 db_show_one_runq(runq
);
1031 db_printf("No runnable threads\n");
1038 int i
, task_id
, thr_act_id
;
1040 thread_act_t thr_act
;
1044 printf("PRI TASK.ACTIVATION\n");
1045 for (i
= runq
->highq
, q
= runq
->queues
+ i
; i
>= 0; i
--, q
--) {
1046 if (!queue_empty(q
)) {
1047 db_printf("%3d:", i
);
1048 queue_iterate(q
, thread
, thread_t
, links
) {
1049 thr_act
= thread
->top_act
;
1050 task
= thr_act
->task
;
1051 task_id
= db_lookup_task(task
);
1052 thr_act_id
= db_lookup_task_act(task
, thr_act
);
1053 db_printf(" %d.%d", task_id
, thr_act_id
);