2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
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
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
34 * Mach Operating System
35 * Copyright (c) 1991,1990 Carnegie Mellon University
36 * All Rights Reserved.
38 * Permission to use, copy, modify and distribute this software and its
39 * documentation is hereby granted, provided that both the copyright
40 * notice and this permission notice appear in all copies of the
41 * software, derivative works or modified versions, and any portions
42 * thereof, and that both notices appear in supporting documentation.
44 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
45 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
46 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
48 * Carnegie Mellon requests users of this software to return to
50 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
51 * School of Computer Science
52 * Carnegie Mellon University
53 * Pittsburgh PA 15213-3890
55 * any improvements or extensions that they make and grant Carnegie Mellon
56 * the rights to redistribute these changes.
61 * Author: David B. Golub, Carnegie Mellon University
66 * Miscellaneous printing.
68 #include <task_swapper.h>
70 #include <string.h> /* For strlen() */
71 #include <mach/port.h>
72 #include <kern/task.h>
73 #include <kern/thread.h>
74 #include <kern/queue.h>
75 #include <kern/processor.h>
76 #include <ipc/ipc_port.h>
77 #include <ipc/ipc_space.h>
78 #include <ipc/ipc_pset.h>
79 #include <vm/vm_print.h> /* for db_vm() */
81 #include <machine/db_machdep.h>
82 #include <machine/thread.h>
84 #include <ddb/db_lex.h>
85 #include <ddb/db_variables.h>
86 #include <ddb/db_sym.h>
87 #include <ddb/db_task_thread.h>
88 #include <ddb/db_command.h>
89 #include <ddb/db_output.h> /* For db_printf() */
90 #include <ddb/db_print.h>
93 #include <kern/task_swap.h>
94 #endif /* TASK_SWAPPER */
96 /* Prototypes for functions local to this file. XXX -- should be static!
100 register thread_t thr_act
,
103 char *db_act_swap_stat(
104 register thread_t thr_act
,
112 void db_reset_print_entry(
115 void db_print_one_entry(
118 mach_port_name_t name
,
125 boolean_t do_output
);
127 ipc_port_t
db_lookup_port(
131 static void db_print_port_id(
147 void db_print_task_vm(
153 void db_system_stats(void);
163 register struct db_variable
*regp
;
168 struct db_var_aux_param aux_param
;
169 task_t task
= TASK_NULL
;
171 aux_param
.modif
= modif
;
172 aux_param
.thr_act
= THREAD_NULL
;
173 if (db_option(modif
, 't')) {
175 if (!db_check_act_address_valid((thread_t
)addr
))
177 aux_param
.thr_act
= (thread_t
)addr
;
179 aux_param
.thr_act
= db_default_act
;
180 if (aux_param
.thr_act
!= THREAD_NULL
)
181 task
= aux_param
.thr_act
->task
;
183 for (regp
= db_regs
; regp
< db_eregs
; regp
++) {
184 if (regp
->max_level
> 1) {
185 db_printf("bad multi-suffixed register %s\n", regp
->name
);
188 aux_param
.level
= regp
->max_level
;
189 for (i
= regp
->low
; i
<= regp
->high
; i
++) {
190 aux_param
.suffix
[0] = i
;
191 db_read_write_variable(regp
, &value
, DB_VAR_GET
, &aux_param
);
192 if (regp
->max_level
> 0)
193 db_printf("%s%d%*s", regp
->name
, i
,
194 12-strlen(regp
->name
)-((i
<10)?1:2), "");
196 db_printf("%-12s", regp
->name
);
197 db_printf("%#*llN", 2+2*sizeof(db_expr_t
), (unsigned long long)value
);
198 db_find_xtrn_task_sym_and_offset((db_addr_t
)value
, &name
,
200 if (name
!= 0 && offset
<= db_maxoff
&& offset
!= value
) {
201 db_printf("\t%s", name
);
203 db_printf("+%#llr", (unsigned long long)offset
);
210 #define OPTION_LONG 0x001 /* long print option */
211 #define OPTION_USER 0x002 /* print ps-like stuff */
212 #define OPTION_INDENT 0x100 /* print with indent */
213 #define OPTION_THREAD_TITLE 0x200 /* print thread title */
214 #define OPTION_TASK_TITLE 0x400 /* print thread title */
217 #define DB_TASK_NAME(task) /* no task name */
218 #define DB_TASK_NAME_TITLE "" /* no task name */
219 #endif /* DB_TASK_NAME */
221 #ifndef db_act_fp_used
222 #define db_act_fp_used(thr_act) FALSE
227 register thread_t thr_act
,
230 register char *p
= status
;
232 if (!thr_act
->active
) {
240 thread_t athread
= thr_act
;
242 *p
++ = (athread
->state
& TH_RUN
) ? 'R' : '.';
243 *p
++ = (athread
->state
& TH_WAIT
) ? 'W' : '.';
244 *p
++ = (athread
->state
& TH_SUSP
) ? 'S' : '.';
245 *p
++ = (!athread
->kernel_stack
) ? '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_t thr_act
,
259 register char *p
= status
;
265 char *policy_list
[] = { "TS", "RR", "??", "FF",
266 "??", "??", "??", "BE"};
281 db_printf("db_print_act(NULL)!\n");
286 if (flag
& OPTION_USER
) {
288 if (flag
& OPTION_LONG
) {
289 if (flag
& OPTION_INDENT
)
291 if (flag
& OPTION_THREAD_TITLE
) {
292 db_printf("%s ID: ACT STAT SW STACK SHUTTLE", indent
);
293 db_printf(" SUS PRI WAIT_FUNC\n");
295 policy
= ((athread
&& (athread
->sched_mode
&TH_MODE_TIMESHARE
))? 1: 2);
296 db_printf("%s%3d%c %0*X %s %s %0*X %0*X %3d %3d/%s ",
298 (thr_act
== current_thread())? '#': ':',
299 2*sizeof(vm_offset_t
), thr_act
,
300 db_act_stat(thr_act
, status
),
301 db_act_swap_stat(thr_act
, swap_status
),
302 2*sizeof(vm_offset_t
), (athread
?athread
->kernel_stack
:0),
303 2*sizeof(vm_offset_t
), athread
,
304 thr_act
->suspend_count
,
305 (athread
? athread
->sched_pri
: 999), /* XXX */
306 policy_list
[policy
-1]);
308 /* no longer TH_SWAP, no continuation to print */
309 if (athread
->state
& TH_WAIT
)
310 db_task_printsym((db_addr_t
)athread
->wait_event
,
311 DB_STGY_ANY
, kernel_task
);
315 if (act_id
% 3 == 0) {
316 if (flag
& OPTION_INDENT
)
320 db_printf("%3d%c(%0*X,%s)", act_id
,
321 (thr_act
== current_thread())? '#': ':',
322 2*sizeof(vm_offset_t
), thr_act
,
323 db_act_stat(thr_act
, status
));
326 if (flag
& OPTION_INDENT
)
327 db_printf(" %3d (%0*X) ", act_id
,
328 2*sizeof(vm_offset_t
), thr_act
);
330 db_printf("(%0*X) ", 2*sizeof(vm_offset_t
), thr_act
);
332 db_printf("%c%c%c%c%c",
333 (athread
->state
& TH_RUN
) ? 'R' : ' ',
334 (athread
->state
& TH_WAIT
) ? 'W' : ' ',
335 (athread
->state
& TH_SUSP
) ? 'S' : ' ',
336 (athread
->state
& TH_UNINT
)? 'N' : ' ',
337 db_act_fp_used(thr_act
) ? 'F' : ' ');
338 if (!athread
->kernel_stack
) {
339 if (athread
->continuation
) {
341 db_task_printsym((db_addr_t
)athread
->continuation
,
342 DB_STGY_ANY
, kernel_task
);
345 db_printf("(handoff)");
348 if (athread
->state
& TH_WAIT
) {
350 db_task_printsym((db_addr_t
)athread
->wait_event
,
351 DB_STGY_ANY
, kernel_task
);
369 if (flag
& OPTION_USER
) {
370 if (flag
& OPTION_TASK_TITLE
) {
371 db_printf(" ID: TASK MAP THD SUS PR SW %s",
373 if ((flag
& OPTION_LONG
) == 0)
378 switch ((int) task
->swap_state
) {
385 case TASK_SW_GOING_OUT
:
388 case TASK_SW_COMING_IN
:
391 case TASK_SW_UNSWAPPABLE
:
398 #else /* TASK_SWAPPER */
400 #endif /* TASK_SWAPPER */
402 db_printf("%3d: %0*X %0*X %3d %3d %2d %c ",
403 task_id
, 2*sizeof(vm_offset_t
), task
,
404 2*sizeof(vm_offset_t
), task
->map
,
410 if (flag
& OPTION_LONG
) {
411 if (flag
& OPTION_TASK_TITLE
)
412 flag
|= OPTION_THREAD_TITLE
;
414 } else if (task
->thread_count
<= 1)
415 flag
&= ~OPTION_INDENT
;
417 queue_iterate(&task
->threads
, thr_act
, thread_t
, task_threads
) {
418 db_print_act(thr_act
, act_id
, flag
);
419 flag
&= ~OPTION_THREAD_TITLE
;
422 if ((flag
& OPTION_LONG
) == 0)
425 if (flag
& OPTION_LONG
) {
426 if (flag
& OPTION_TASK_TITLE
) {
427 db_printf(" TASK ACT\n");
428 if (task
->thread_count
> 1)
429 flag
|= OPTION_THREAD_TITLE
;
432 db_printf("%3d (%0*X): ", task_id
, 2*sizeof(vm_offset_t
), task
);
433 if (task
->thread_count
== 0) {
434 db_printf("no threads\n");
436 if (task
->thread_count
> 1) {
437 db_printf("%d threads: \n", task
->thread_count
);
438 flag
|= OPTION_INDENT
;
440 flag
&= ~OPTION_INDENT
;
442 queue_iterate(&task
->threads
, thr_act
,
443 thread_t
, task_threads
) {
444 db_print_act(thr_act
, act_id
++, flag
);
445 flag
&= ~OPTION_THREAD_TITLE
;
458 thread_t act
= (thread_t
)queue_first(&task
->threads
);
462 space
= task
->itk_space
;
464 count
= db_port_iterate(act
, FALSE
, FALSE
);
465 db_printf("%3d: %08x %08x %08x %sactive %d\n",
466 task_id
, task
, space
, task
->map
,
467 space
->is_active
? "":"!", count
);
484 db_printf("id task map pmap virtual rss pg rss mem wir pg wir mem\n");
488 pmap
= vm_map_pmap(map
);
490 size
= db_vm_map_total_size(map
);
491 resident
= pmap
->stats
.resident_count
;
492 wired
= pmap
->stats
.wired_count
;
494 db_printf("%2d %08x %08x %08x %7dK %6d %6dK %6d %6dK\n",
500 resident
, (resident
* PAGE_SIZE
) / 1024,
501 wired
, (wired
* PAGE_SIZE
) / 1024);
516 if (have_addr
== FALSE
) {
517 if ((thread
= db_default_act
) == THREAD_NULL
) {
518 if ((thread
= current_thread()) == THREAD_NULL
) {
519 db_printf("no thread.\n");
525 task
= (task_t
) addr
;
528 task_id
= db_lookup_task(task
);
530 db_printf("0x%x is not a task_t\n", addr
);
534 db_print_task_vm(task
, task_id
, TRUE
, modif
);
546 boolean_t title
= TRUE
;
547 processor_set_t pset
= &default_pset
;
550 queue_iterate(&pset
->tasks
, task
, task_t
, pset_tasks
) {
551 db_print_task_vm(task
, task_id
, title
, modif
);
567 processor_set_t pset
= &default_pset
;
569 flag
= OPTION_TASK_TITLE
|OPTION_INDENT
;
570 if (db_option(modif
, 'u'))
572 if (db_option(modif
, 'l'))
576 queue_iterate(&pset
->tasks
, task
, task_t
, pset_tasks
) {
577 db_print_task(task
, task_id
, flag
);
578 flag
&= ~OPTION_TASK_TITLE
;
580 if ((flag
& (OPTION_LONG
|OPTION_INDENT
)) == OPTION_INDENT
)
596 flag
= OPTION_TASK_TITLE
;
597 if (db_option(modif
, 'u'))
599 if (db_option(modif
, 'l'))
603 task
= db_current_task();
604 if (task
== TASK_NULL
) {
605 db_error("No task\n");
609 task
= (task_t
) addr
;
611 if ((task_id
= db_lookup_task(task
)) < 0) {
612 db_printf("bad task address 0x%llx\n", (unsigned long long)addr
);
617 db_printf(" ID: TASK SPACE MAP COUNT\n");
618 db_print_space(task
, task_id
, flag
);
631 processor_set_t pset
= &default_pset
;
633 flag
= OPTION_TASK_TITLE
|OPTION_INDENT
;
634 if (db_option(modif
, 'u'))
636 if (db_option(modif
, 'l'))
639 db_printf(" ID: TASK SPACE MAP COUNT\n");
640 queue_iterate(&pset
->tasks
, task
, task_t
, pset_tasks
) {
641 db_print_space(task
, task_id
, flag
);
653 processor_set_t pset
= &default_pset
;
655 queue_iterate(&pset
->tasks
, task
, task_t
, pset_tasks
) {
656 if (task
->itk_space
== space
) {
658 return (db_addr_t
)task
;
677 flag
= OPTION_THREAD_TITLE
;
678 if (db_option(modif
, 'u'))
680 if (db_option(modif
, 'l'))
684 thr_act
= current_thread();
685 if (thr_act
== THREAD_NULL
) {
686 db_error("No thr_act\n");
690 thr_act
= (thread_t
) addr
;
692 if ((act_id
= db_lookup_act(thr_act
)) < 0) {
693 db_printf("bad thr_act address %#llX\n", (unsigned long long)addr
);
698 if (flag
& OPTION_USER
) {
699 db_printf("TASK%d(%0*X):\n",
700 db_lookup_task(thr_act
->task
),
701 2*sizeof(vm_offset_t
), thr_act
->task
);
702 db_print_act(thr_act
, act_id
, flag
);
704 db_printf("task %d(%0*Xx): thr_act %d",
705 db_lookup_task(thr_act
->task
),
706 2*sizeof(vm_offset_t
), thr_act
->task
, act_id
);
707 db_print_act(thr_act
, act_id
, flag
);
709 if (db_option(modif
, 'i') &&
710 (thr_act
->state
& TH_WAIT
) &&
711 thr_act
->kernel_stack
== 0) {
713 db_printf("Wait State: option 0x%x\n",
714 thr_act
->ith_option
);
729 flag
= OPTION_TASK_TITLE
|OPTION_INDENT
;
730 if (db_option(modif
, 'u'))
732 if (db_option(modif
, 'l'))
736 task
= db_current_task();
737 if (task
== TASK_NULL
) {
738 db_error("No task\n");
742 task
= (task_t
) addr
;
744 if ((task_id
= db_lookup_task(task
)) < 0) {
745 db_printf("bad task address 0x%llX\n", (unsigned long long)addr
);
750 db_print_task(task
, task_id
, flag
);
763 thread
= (thread_t
) addr
;
765 thread
= current_thread();
766 if (thread
== THREAD_NULL
) {
767 db_error("No thread\n");
771 db_printf("thread %x:\n", thread
);
772 printf(" $task%d.%d(%x)", db_lookup_task(thread
->task
),
773 db_lookup_act(thread
), thread
);
781 return (port
->ip_messages
.imq_msgcount
);
784 static int db_print_ent_cnt
= 0;
786 void db_reset_print_entry(
789 db_print_ent_cnt
= 0;
796 mach_port_name_t name
,
800 ipc_port_t aport
= (ipc_port_t
)entry
->ie_object
;
801 ipc_entry_bits_t bits
;
803 bits
= entry
->ie_bits
;
804 if (is_pset
&& !aport
->ip_pset_count
)
806 if (db_print_ent_cnt
&& db_print_ent_cnt
% 2 == 0)
809 db_printf("\t%s%d[%x]",
810 !is_pset
&& aport
->ip_pset_count
? "pset" : "port",
812 MACH_PORT_MAKE(index
, IE_BITS_GEN(bits
)));
814 db_printf("\t%s[%x]",
815 !is_pset
&& aport
->ip_pset_count
? "pset" : "port",
818 db_printf("(%s,%x,%d)",
819 (bits
& MACH_PORT_TYPE_RECEIVE
)? "r":
820 (bits
& MACH_PORT_TYPE_SEND
)? "s": "S",
822 db_port_kmsg_count(aport
));
826 db_printf("(%s,%x,set_count=%d,%d)",
827 (bits
& MACH_PORT_TYPE_RECEIVE
)? "r":
828 (bits
& MACH_PORT_TYPE_SEND
)? "s": "S",
830 aport
->ip_pset_count
,
831 db_port_kmsg_count(aport
));
843 ipc_tree_entry_t tentry
;
850 space
= thr_act
->task
->itk_space
;
851 entry
= space
->is_table
;
852 size
= space
->is_table_size
;
853 db_reset_print_entry();
854 for (index
= 0; index
< size
; ++index
, ++entry
) {
855 if (entry
->ie_bits
& MACH_PORT_TYPE_PORT_RIGHTS
) {
857 db_print_one_entry(entry
,
858 index
, MACH_PORT_NULL
, is_pset
, space
);
862 for (tentry
= ipc_splay_traverse_start(&space
->is_tree
);
864 tentry
= ipc_splay_traverse_next(&space
->is_tree
, FALSE
)) {
865 entry
= &tentry
->ite_entry
;
866 if (entry
->ie_bits
& MACH_PORT_TYPE_PORT_RIGHTS
) {
868 db_print_one_entry(entry
,
869 0, tentry
->ite_name
, is_pset
, space
);
881 register ipc_space_t space
;
882 register ipc_entry_t entry
;
884 if (thr_act
== THREAD_NULL
)
886 space
= thr_act
->task
->itk_space
;
887 if (id
< 0 || id
>= space
->is_table_size
)
889 entry
= &space
->is_table
[id
];
890 if (entry
->ie_bits
& MACH_PORT_TYPE_PORT_RIGHTS
)
891 return((ipc_port_t
)entry
->ie_object
);
902 if (n
!= 0 && n
% 3 == 0)
904 db_printf("\tport%d(%s,%x)", id
,
905 (bits
& MACH_PORT_TYPE_RECEIVE
)? "r":
906 (bits
& MACH_PORT_TYPE_SEND
)? "s": "S", port
);
919 thr_act
= current_thread();
920 if (thr_act
== THREAD_NULL
) {
921 db_error("No thr_act\n");
925 thr_act
= (thread_t
) addr
;
926 if (db_lookup_act(thr_act
) < 0) {
927 db_printf("Bad thr_act address 0x%llX\n", addr
);
931 if (db_port_iterate(thr_act
, db_option(modif
,'s'), TRUE
))
936 * Useful system state when the world has hung.
941 extern void db_sched(void);
948 db_printf("current_{thread/task} 0x%x 0x%x\n",
949 current_thread(),current_task());
952 void db_show_one_runq(run_queue_t runq
);
961 processor_set_t pset
= &default_pset
;
964 boolean_t showedany
= FALSE
;
966 queue_iterate(&pset
->processors
, proc
, processor_t
, processors
) {
968 if (runq
->count
> 0) {
969 db_printf("PROCESSOR %x IN SET %x\n", proc
, pset
);
970 db_show_one_runq(runq
);
975 if (runq
->count
> 0) {
976 db_printf("PROCESSOR SET %x\n", pset
);
977 db_show_one_runq(runq
);
981 db_printf("No runnable threads\n");
988 int i
, task_id
, thread_id
;
993 printf("PRI TASK.ACTIVATION\n");
994 for (i
= runq
->highq
, q
= runq
->queues
+ i
; i
>= 0; i
--, q
--) {
995 if (!queue_empty(q
)) {
996 db_printf("%3d:", i
);
997 queue_iterate(q
, thread
, thread_t
, links
) {
999 task_id
= db_lookup_task(task
);
1000 thread_id
= db_lookup_task_act(task
, thread
);
1001 db_printf(" %d.%d", task_id
, thread_id
);