2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
29 * Mach Operating System
30 * Copyright (c) 1991,1990 Carnegie Mellon University
31 * All Rights Reserved.
33 * Permission to use, copy, modify and distribute this software and its
34 * documentation is hereby granted, provided that both the copyright
35 * notice and this permission notice appear in all copies of the
36 * software, derivative works or modified versions, and any portions
37 * thereof, and that both notices appear in supporting documentation.
39 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
40 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
41 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
43 * Carnegie Mellon requests users of this software to return to
45 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
46 * School of Computer Science
47 * Carnegie Mellon University
48 * Pittsburgh PA 15213-3890
50 * any improvements or extensions that they make and grant Carnegie Mellon
51 * the rights to redistribute these changes.
56 * Author: David B. Golub, Carnegie Mellon University
61 * Miscellaneous printing.
63 #include <task_swapper.h>
65 #include <string.h> /* For strlen() */
66 #include <mach/port.h>
67 #include <kern/task.h>
68 #include <kern/thread.h>
69 #include <kern/thread_swap.h>
70 #include <kern/queue.h>
71 #include <kern/processor.h>
72 #include <ipc/ipc_port.h>
73 #include <ipc/ipc_space.h>
74 #include <ipc/ipc_pset.h>
75 #include <vm/vm_print.h> /* for db_vm() */
77 #include <machine/db_machdep.h>
78 #include <machine/thread.h>
80 #include <ddb/db_lex.h>
81 #include <ddb/db_variables.h>
82 #include <ddb/db_sym.h>
83 #include <ddb/db_task_thread.h>
84 #include <ddb/db_command.h>
85 #include <ddb/db_output.h> /* For db_printf() */
86 #include <ddb/db_print.h>
89 #include <kern/task_swap.h>
90 #endif /* TASK_SWAPPER */
92 /* Prototypes for functions local to this file. XXX -- should be static!
96 register thread_act_t thr_act
,
99 char *db_act_swap_stat(
100 register thread_act_t thr_act
,
108 void db_reset_print_entry(
111 void db_print_one_entry(
114 mach_port_name_t name
,
119 thread_act_t thr_act
,
121 boolean_t do_output
);
123 ipc_port_t
db_lookup_port(
124 thread_act_t thr_act
,
127 static void db_print_port_id(
134 thread_act_t thr_act
,
143 void db_print_task_vm(
149 void db_system_stats(void);
159 register struct db_variable
*regp
;
164 struct db_var_aux_param aux_param
;
165 task_t task
= TASK_NULL
;
167 aux_param
.modif
= modif
;
168 aux_param
.thr_act
= THR_ACT_NULL
;
169 if (db_option(modif
, 't')) {
171 if (!db_check_act_address_valid((thread_act_t
)addr
))
173 aux_param
.thr_act
= (thread_act_t
)addr
;
175 aux_param
.thr_act
= db_default_act
;
176 if (aux_param
.thr_act
!= THR_ACT_NULL
)
177 task
= aux_param
.thr_act
->task
;
179 for (regp
= db_regs
; regp
< db_eregs
; regp
++) {
180 if (regp
->max_level
> 1) {
181 db_printf("bad multi-suffixed register %s\n", regp
->name
);
184 aux_param
.level
= regp
->max_level
;
185 for (i
= regp
->low
; i
<= regp
->high
; i
++) {
186 aux_param
.suffix
[0] = i
;
187 db_read_write_variable(regp
, &value
, DB_VAR_GET
, &aux_param
);
188 if (regp
->max_level
> 0)
189 db_printf("%s%d%*s", regp
->name
, i
,
190 12-strlen(regp
->name
)-((i
<10)?1:2), "");
192 db_printf("%-12s", regp
->name
);
193 db_printf("%#*llN", 2+2*sizeof(db_expr_t
), value
);
194 db_find_xtrn_task_sym_and_offset((db_addr_t
)value
, &name
,
196 if (name
!= 0 && offset
<= db_maxoff
&& offset
!= value
) {
197 db_printf("\t%s", name
);
199 db_printf("+%#r", offset
);
206 #define OPTION_LONG 0x001 /* long print option */
207 #define OPTION_USER 0x002 /* print ps-like stuff */
208 #define OPTION_INDENT 0x100 /* print with indent */
209 #define OPTION_THREAD_TITLE 0x200 /* print thread title */
210 #define OPTION_TASK_TITLE 0x400 /* print thread title */
213 #define DB_TASK_NAME(task) /* no task name */
214 #define DB_TASK_NAME_TITLE "" /* no task name */
215 #endif /* DB_TASK_NAME */
217 #ifndef db_act_fp_used
218 #define db_act_fp_used(thr_act) FALSE
223 register thread_act_t thr_act
,
226 register char *p
= status
;
228 if (!thr_act
->active
) {
235 } else if (!thr_act
->thread
) {
243 thread_t athread
= thr_act
->thread
;
245 *p
++ = (athread
->state
& TH_RUN
) ? 'R' : '.';
246 *p
++ = (athread
->state
& TH_WAIT
) ? 'W' : '.';
247 *p
++ = (athread
->state
& TH_SUSP
) ? 'S' : '.';
248 *p
++ = (athread
->state
& TH_STACK_HANDOFF
) ? 'O' : '.';
249 *p
++ = (athread
->state
& TH_UNINT
) ? 'N' : '.';
250 /* show if the FPU has been used */
251 *p
++ = db_act_fp_used(thr_act
) ? 'F' : '.';
259 register thread_act_t thr_act
,
262 register char *p
= status
;
265 switch (thr_act
->swap_state
& TH_SW_STATE
) {
266 case TH_SW_UNSWAPPABLE
:
272 case TH_SW_GOING_OUT
:
281 case TH_SW_COMING_IN
:
288 *p
++ = (thr_act
->swap_state
& TH_SW_TASK_SWAPPING
) ? 'T' : '.';
289 #endif /* THREAD_SWAPPER */
295 char *policy_list
[] = { "TS", "RR", "??", "FF",
296 "??", "??", "??", "BE"};
300 thread_act_t thr_act
,
311 db_printf("db_print_act(NULL)!\n");
315 athread
= thr_act
->thread
;
316 if (flag
& OPTION_USER
) {
318 if (flag
& OPTION_LONG
) {
319 if (flag
& OPTION_INDENT
)
321 if (flag
& OPTION_THREAD_TITLE
) {
322 db_printf("%s ID: ACT STAT SW STACK SHUTTLE", indent
);
323 db_printf(" SUS PRI WAIT_FUNC\n");
325 policy
= ((athread
&& (athread
->sched_mode
&TH_MODE_TIMESHARE
))? 1: 2);
326 db_printf("%s%3d%c %0*X %s %s %0*X %0*X %3d %3d/%s ",
328 (thr_act
== current_act())? '#': ':',
329 2*sizeof(vm_offset_t
), thr_act
,
330 db_act_stat(thr_act
, status
),
331 db_act_swap_stat(thr_act
, swap_status
),
332 2*sizeof(vm_offset_t
), (athread
?athread
->kernel_stack
:0),
333 2*sizeof(vm_offset_t
), athread
,
334 thr_act
->suspend_count
,
335 (athread
? athread
->sched_pri
: 999), /* XXX */
336 policy_list
[policy
-1]);
338 /* no longer TH_SWAP, no continuation to print */
339 if (athread
->state
& TH_WAIT
)
340 db_task_printsym((db_addr_t
)athread
->wait_event
,
341 DB_STGY_ANY
, kernel_task
);
345 if (act_id
% 3 == 0) {
346 if (flag
& OPTION_INDENT
)
350 db_printf("%3d%c(%0*X,%s)", act_id
,
351 (thr_act
== current_act())? '#': ':',
352 2*sizeof(vm_offset_t
), thr_act
,
353 db_act_stat(thr_act
, status
));
356 if (flag
& OPTION_INDENT
)
357 db_printf(" %3d (%0*X) ", act_id
,
358 2*sizeof(vm_offset_t
), thr_act
);
360 db_printf("(%0*X) ", 2*sizeof(vm_offset_t
), thr_act
);
362 db_printf("%c%c%c%c%c",
363 (athread
->state
& TH_RUN
) ? 'R' : ' ',
364 (athread
->state
& TH_WAIT
) ? 'W' : ' ',
365 (athread
->state
& TH_SUSP
) ? 'S' : ' ',
366 (athread
->state
& TH_UNINT
)? 'N' : ' ',
367 db_act_fp_used(thr_act
) ? 'F' : ' ');
368 /* Obsolete TH_STACK_HANDOFF code, left for now; might enhance
369 * to print out safe_points instead */
370 if (athread
->state
& TH_STACK_HANDOFF
) {
371 if (athread
->continuation
) {
373 db_task_printsym((db_addr_t
)athread
->continuation
,
374 DB_STGY_ANY
, kernel_task
);
377 db_printf("(handoff)");
380 if (athread
->state
& TH_WAIT
) {
382 db_task_printsym((db_addr_t
)athread
->wait_event
,
383 DB_STGY_ANY
, kernel_task
);
397 thread_act_t thr_act
;
401 if (flag
& OPTION_USER
) {
402 if (flag
& OPTION_TASK_TITLE
) {
403 db_printf(" ID: TASK MAP THD RES SUS PR SW %s",
405 if ((flag
& OPTION_LONG
) == 0)
410 switch ((int) task
->swap_state
) {
417 case TASK_SW_GOING_OUT
:
420 case TASK_SW_COMING_IN
:
423 case TASK_SW_UNSWAPPABLE
:
430 #else /* TASK_SWAPPER */
432 #endif /* TASK_SWAPPER */
434 db_printf("%3d: %0*X %0*X %3d %3d %3d %2d %c ",
435 task_id
, 2*sizeof(vm_offset_t
), task
,
436 2*sizeof(vm_offset_t
), task
->map
,
437 task
->thread_count
, task
->res_thread_count
,
442 if (flag
& OPTION_LONG
) {
443 if (flag
& OPTION_TASK_TITLE
)
444 flag
|= OPTION_THREAD_TITLE
;
446 } else if (task
->thread_count
<= 1)
447 flag
&= ~OPTION_INDENT
;
449 queue_iterate(&task
->threads
, thr_act
, thread_act_t
, task_threads
) {
450 db_print_act(thr_act
, act_id
, flag
);
451 flag
&= ~OPTION_THREAD_TITLE
;
454 if ((flag
& OPTION_LONG
) == 0)
457 if (flag
& OPTION_LONG
) {
458 if (flag
& OPTION_TASK_TITLE
) {
459 db_printf(" TASK ACT\n");
460 if (task
->thread_count
> 1)
461 flag
|= OPTION_THREAD_TITLE
;
464 db_printf("%3d (%0*X): ", task_id
, 2*sizeof(vm_offset_t
), task
);
465 if (task
->thread_count
== 0) {
466 db_printf("no threads\n");
468 if (task
->thread_count
> 1) {
469 db_printf("%d threads: \n", task
->thread_count
);
470 flag
|= OPTION_INDENT
;
472 flag
&= ~OPTION_INDENT
;
474 queue_iterate(&task
->threads
, thr_act
,
475 thread_act_t
, task_threads
) {
476 db_print_act(thr_act
, act_id
++, flag
);
477 flag
&= ~OPTION_THREAD_TITLE
;
490 thread_act_t act
= (thread_act_t
)queue_first(&task
->threads
);
494 space
= task
->itk_space
;
496 count
= db_port_iterate(act
, FALSE
, FALSE
);
497 db_printf("%3d: %08x %08x %08x %sactive %d\n",
498 task_id
, task
, space
, task
->map
,
499 space
->is_active
? "":"!", count
);
516 db_printf("id task map pmap virtual rss pg rss mem wir pg wir mem\n");
520 pmap
= vm_map_pmap(map
);
522 size
= db_vm_map_total_size(map
);
523 resident
= pmap
->stats
.resident_count
;
524 wired
= pmap
->stats
.wired_count
;
526 db_printf("%2d %08x %08x %08x %7dK %6d %6dK %6d %6dK\n",
532 resident
, (resident
* PAGE_SIZE
) / 1024,
533 wired
, (wired
* PAGE_SIZE
) / 1024);
548 if (have_addr
== FALSE
) {
549 if ((thread
= db_default_act
) == THR_ACT_NULL
) {
550 if ((thread
= current_act()) == THR_ACT_NULL
) {
551 db_printf("no thread.\n");
557 task
= (task_t
) addr
;
560 task_id
= db_lookup_task(task
);
562 db_printf("0x%x is not a task_t\n", addr
);
566 db_print_task_vm(task
, task_id
, TRUE
, modif
);
578 boolean_t title
= TRUE
;
579 processor_set_t pset
= &default_pset
;
582 queue_iterate(&pset
->tasks
, task
, task_t
, pset_tasks
) {
583 db_print_task_vm(task
, task_id
, title
, modif
);
599 processor_set_t pset
= &default_pset
;
601 flag
= OPTION_TASK_TITLE
|OPTION_INDENT
;
602 if (db_option(modif
, 'u'))
604 if (db_option(modif
, 'l'))
608 queue_iterate(&pset
->tasks
, task
, task_t
, pset_tasks
) {
609 db_print_task(task
, task_id
, flag
);
610 flag
&= ~OPTION_TASK_TITLE
;
612 if ((flag
& (OPTION_LONG
|OPTION_INDENT
)) == OPTION_INDENT
)
628 flag
= OPTION_TASK_TITLE
;
629 if (db_option(modif
, 'u'))
631 if (db_option(modif
, 'l'))
635 task
= db_current_task();
636 if (task
== TASK_NULL
) {
637 db_error("No task\n");
641 task
= (task_t
) addr
;
643 if ((task_id
= db_lookup_task(task
)) < 0) {
644 db_printf("bad task address 0x%x\n", addr
);
649 db_printf(" ID: TASK SPACE MAP COUNT\n");
650 db_print_space(task
, task_id
, flag
);
663 processor_set_t pset
= &default_pset
;
665 flag
= OPTION_TASK_TITLE
|OPTION_INDENT
;
666 if (db_option(modif
, 'u'))
668 if (db_option(modif
, 'l'))
671 db_printf(" ID: TASK SPACE MAP COUNT\n");
672 queue_iterate(&pset
->tasks
, task
, task_t
, pset_tasks
) {
673 db_print_space(task
, task_id
, flag
);
685 processor_set_t pset
= &default_pset
;
687 queue_iterate(&pset
->tasks
, task
, task_t
, pset_tasks
) {
688 if (task
->itk_space
== space
) {
690 return (db_addr_t
)task
;
707 thread_act_t thr_act
;
709 flag
= OPTION_THREAD_TITLE
;
710 if (db_option(modif
, 'u'))
712 if (db_option(modif
, 'l'))
716 thr_act
= current_act();
717 if (thr_act
== THR_ACT_NULL
) {
718 db_error("No thr_act\n");
722 thr_act
= (thread_act_t
) addr
;
724 if ((act_id
= db_lookup_act(thr_act
)) < 0) {
725 db_printf("bad thr_act address %#llX\n", addr
);
730 if (flag
& OPTION_USER
) {
731 db_printf("TASK%d(%0*X):\n",
732 db_lookup_task(thr_act
->task
),
733 2*sizeof(vm_offset_t
), thr_act
->task
);
734 db_print_act(thr_act
, act_id
, flag
);
736 db_printf("task %d(%0*Xx): thr_act %d",
737 db_lookup_task(thr_act
->task
),
738 2*sizeof(vm_offset_t
), thr_act
->task
, act_id
);
739 db_print_act(thr_act
, act_id
, flag
);
741 if (db_option(modif
, 'i') && thr_act
->thread
&&
742 (thr_act
->thread
->state
& TH_WAIT
) &&
743 thr_act
->thread
->kernel_stack
== 0) {
745 db_printf("Wait State: option 0x%x\n",
746 thr_act
->thread
->ith_option
);
761 flag
= OPTION_TASK_TITLE
|OPTION_INDENT
;
762 if (db_option(modif
, 'u'))
764 if (db_option(modif
, 'l'))
768 task
= db_current_task();
769 if (task
== TASK_NULL
) {
770 db_error("No task\n");
774 task
= (task_t
) addr
;
776 if ((task_id
= db_lookup_task(task
)) < 0) {
777 db_printf("bad task address 0x%llX\n", addr
);
782 db_print_task(task
, task_id
, flag
);
793 thread_act_t thr_act
;
796 shuttle
= (thread_t
) addr
;
798 thr_act
= current_act();
799 if (thr_act
== THR_ACT_NULL
) {
800 db_error("No thr_act\n");
803 shuttle
= thr_act
->thread
;
804 if (shuttle
== THREAD_NULL
) {
805 db_error("No shuttle associated with current thr_act\n");
809 db_printf("shuttle %x:\n", shuttle
);
810 if (shuttle
->top_act
== THR_ACT_NULL
)
811 db_printf(" no activations\n");
813 db_printf(" activations:");
814 for (thr_act
= shuttle
->top_act
; thr_act
!= THR_ACT_NULL
;
815 thr_act
= thr_act
->lower
) {
816 if (thr_act
!= shuttle
->top_act
)
818 printf(" $task%d.%d(%x)", db_lookup_task(thr_act
->task
),
819 db_lookup_act(thr_act
), thr_act
);
829 return (port
->ip_messages
.imq_msgcount
);
832 static int db_print_ent_cnt
= 0;
834 void db_reset_print_entry(
837 db_print_ent_cnt
= 0;
844 mach_port_name_t name
,
848 ipc_port_t aport
= (ipc_port_t
)entry
->ie_object
;
849 ipc_entry_bits_t bits
;
851 bits
= entry
->ie_bits
;
852 if (is_pset
&& !aport
->ip_pset_count
)
854 if (db_print_ent_cnt
&& db_print_ent_cnt
% 2 == 0)
857 db_printf("\t%s%d[%x]",
858 !is_pset
&& aport
->ip_pset_count
? "pset" : "port",
860 MACH_PORT_MAKE(index
, IE_BITS_GEN(bits
)));
862 db_printf("\t%s[%x]",
863 !is_pset
&& aport
->ip_pset_count
? "pset" : "port",
866 db_printf("(%s,%x,%d)",
867 (bits
& MACH_PORT_TYPE_RECEIVE
)? "r":
868 (bits
& MACH_PORT_TYPE_SEND
)? "s": "S",
870 db_port_kmsg_count(aport
));
874 db_printf("(%s,%x,set_count=%d,%d)",
875 (bits
& MACH_PORT_TYPE_RECEIVE
)? "r":
876 (bits
& MACH_PORT_TYPE_SEND
)? "s": "S",
878 aport
->ip_pset_count
,
879 db_port_kmsg_count(aport
));
886 thread_act_t thr_act
,
891 ipc_tree_entry_t tentry
;
898 space
= thr_act
->task
->itk_space
;
899 entry
= space
->is_table
;
900 size
= space
->is_table_size
;
901 db_reset_print_entry();
902 for (index
= 0; index
< size
; ++index
, ++entry
) {
903 if (entry
->ie_bits
& MACH_PORT_TYPE_PORT_RIGHTS
) {
905 db_print_one_entry(entry
,
906 index
, MACH_PORT_NULL
, is_pset
, space
);
910 for (tentry
= ipc_splay_traverse_start(&space
->is_tree
);
912 tentry
= ipc_splay_traverse_next(&space
->is_tree
, FALSE
)) {
913 entry
= &tentry
->ite_entry
;
914 if (entry
->ie_bits
& MACH_PORT_TYPE_PORT_RIGHTS
) {
916 db_print_one_entry(entry
,
917 0, tentry
->ite_name
, is_pset
, space
);
926 thread_act_t thr_act
,
929 register ipc_space_t space
;
930 register ipc_entry_t entry
;
932 if (thr_act
== THR_ACT_NULL
)
934 space
= thr_act
->task
->itk_space
;
935 if (id
< 0 || id
>= space
->is_table_size
)
937 entry
= &space
->is_table
[id
];
938 if (entry
->ie_bits
& MACH_PORT_TYPE_PORT_RIGHTS
)
939 return((ipc_port_t
)entry
->ie_object
);
950 if (n
!= 0 && n
% 3 == 0)
952 db_printf("\tport%d(%s,%x)", id
,
953 (bits
& MACH_PORT_TYPE_RECEIVE
)? "r":
954 (bits
& MACH_PORT_TYPE_SEND
)? "s": "S", port
);
964 thread_act_t thr_act
;
967 thr_act
= current_act();
968 if (thr_act
== THR_ACT_NULL
) {
969 db_error("No thr_act\n");
973 thr_act
= (thread_act_t
) addr
;
974 if (db_lookup_act(thr_act
) < 0) {
975 db_printf("Bad thr_act address 0x%llX\n", addr
);
979 if (db_port_iterate(thr_act
, db_option(modif
,'s'), TRUE
))
984 * Useful system state when the world has hung.
989 extern void db_sched(void);
996 db_printf("current_{thread/task} 0x%x 0x%x\n",
997 current_thread(),current_task());
1000 void db_show_one_runq(run_queue_t runq
);
1005 boolean_t have_addr
,
1009 processor_set_t pset
= &default_pset
;
1012 boolean_t showedany
= FALSE
;
1014 #if NCPUS > 1 /* This code has not been tested. */
1015 queue_iterate(&pset
->processors
, proc
, processor_t
, processors
) {
1017 if (runq
->count
> 0) {
1018 db_printf("PROCESSOR %x IN SET %x\n", proc
, pset
);
1019 db_show_one_runq(runq
);
1023 #endif /* NCPUS > 1 */
1025 #error NCPUS undefined
1028 if (runq
->count
> 0) {
1029 db_printf("PROCESSOR SET %x\n", pset
);
1030 db_show_one_runq(runq
);
1034 db_printf("No runnable threads\n");
1041 int i
, task_id
, thr_act_id
;
1043 thread_act_t thr_act
;
1047 printf("PRI TASK.ACTIVATION\n");
1048 for (i
= runq
->highq
, q
= runq
->queues
+ i
; i
>= 0; i
--, q
--) {
1049 if (!queue_empty(q
)) {
1050 db_printf("%3d:", i
);
1051 queue_iterate(q
, thread
, thread_t
, links
) {
1052 thr_act
= thread
->top_act
;
1053 task
= thr_act
->task
;
1054 task_id
= db_lookup_task(task
);
1055 thr_act_id
= db_lookup_task_act(task
, thr_act
);
1056 db_printf(" %d.%d", task_id
, thr_act_id
);