2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_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 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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
32 * Mach Operating System
33 * Copyright (c) 1991,1990 Carnegie Mellon University
34 * All Rights Reserved.
36 * Permission to use, copy, modify and distribute this software and its
37 * documentation is hereby granted, provided that both the copyright
38 * notice and this permission notice appear in all copies of the
39 * software, derivative works or modified versions, and any portions
40 * thereof, and that both notices appear in supporting documentation.
42 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
43 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
44 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
46 * Carnegie Mellon requests users of this software to return to
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
59 * Author: David B. Golub, Carnegie Mellon University
64 * Miscellaneous printing.
66 #include <task_swapper.h>
68 #include <string.h> /* For strlen() */
69 #include <mach/port.h>
70 #include <kern/task.h>
71 #include <kern/thread.h>
72 #include <kern/queue.h>
73 #include <kern/processor.h>
74 #include <ipc/ipc_port.h>
75 #include <ipc/ipc_space.h>
76 #include <ipc/ipc_pset.h>
77 #include <vm/vm_print.h> /* for db_vm() */
79 #include <machine/db_machdep.h>
80 #include <machine/thread.h>
82 #include <ddb/db_lex.h>
83 #include <ddb/db_variables.h>
84 #include <ddb/db_sym.h>
85 #include <ddb/db_task_thread.h>
86 #include <ddb/db_command.h>
87 #include <ddb/db_output.h> /* For db_printf() */
88 #include <ddb/db_print.h>
91 #include <kern/task_swap.h>
92 #endif /* TASK_SWAPPER */
94 /* Prototypes for functions local to this file. XXX -- should be static!
98 register thread_t thr_act
,
101 char *db_act_swap_stat(
102 register thread_t thr_act
,
110 void db_reset_print_entry(
113 void db_print_one_entry(
116 mach_port_name_t name
,
123 boolean_t do_output
);
125 ipc_port_t
db_lookup_port(
129 static void db_print_port_id(
145 void db_print_task_vm(
151 void db_system_stats(void);
161 register struct db_variable
*regp
;
166 struct db_var_aux_param aux_param
;
167 task_t task
= TASK_NULL
;
169 aux_param
.modif
= modif
;
170 aux_param
.thr_act
= THREAD_NULL
;
171 if (db_option(modif
, 't')) {
173 if (!db_check_act_address_valid((thread_t
)addr
))
175 aux_param
.thr_act
= (thread_t
)addr
;
177 aux_param
.thr_act
= db_default_act
;
178 if (aux_param
.thr_act
!= THREAD_NULL
)
179 task
= aux_param
.thr_act
->task
;
181 for (regp
= db_regs
; regp
< db_eregs
; regp
++) {
182 if (regp
->max_level
> 1) {
183 db_printf("bad multi-suffixed register %s\n", regp
->name
);
186 aux_param
.level
= regp
->max_level
;
187 for (i
= regp
->low
; i
<= regp
->high
; i
++) {
188 aux_param
.suffix
[0] = i
;
189 db_read_write_variable(regp
, &value
, DB_VAR_GET
, &aux_param
);
190 if (regp
->max_level
> 0)
191 db_printf("%s%d%*s", regp
->name
, i
,
192 12-strlen(regp
->name
)-((i
<10)?1:2), "");
194 db_printf("%-12s", regp
->name
);
195 db_printf("%#*llN", 2+2*sizeof(db_expr_t
), (unsigned long long)value
);
196 db_find_xtrn_task_sym_and_offset((db_addr_t
)value
, &name
,
198 if (name
!= 0 && offset
<= db_maxoff
&& offset
!= value
) {
199 db_printf("\t%s", name
);
201 db_printf("+%#llr", (unsigned long long)offset
);
208 #define OPTION_LONG 0x001 /* long print option */
209 #define OPTION_USER 0x002 /* print ps-like stuff */
210 #define OPTION_INDENT 0x100 /* print with indent */
211 #define OPTION_THREAD_TITLE 0x200 /* print thread title */
212 #define OPTION_TASK_TITLE 0x400 /* print thread title */
215 #define DB_TASK_NAME(task) /* no task name */
216 #define DB_TASK_NAME_TITLE "" /* no task name */
217 #endif /* DB_TASK_NAME */
219 #ifndef db_act_fp_used
220 #define db_act_fp_used(thr_act) FALSE
225 register thread_t thr_act
,
228 register char *p
= status
;
230 if (!thr_act
->active
) {
238 thread_t athread
= thr_act
;
240 *p
++ = (athread
->state
& TH_RUN
) ? 'R' : '.';
241 *p
++ = (athread
->state
& TH_WAIT
) ? 'W' : '.';
242 *p
++ = (athread
->state
& TH_SUSP
) ? 'S' : '.';
243 *p
++ = (!athread
->kernel_stack
) ? 'O' : '.';
244 *p
++ = (athread
->state
& TH_UNINT
) ? 'N' : '.';
245 /* show if the FPU has been used */
246 *p
++ = db_act_fp_used(thr_act
) ? 'F' : '.';
254 register thread_t thr_act
,
257 register char *p
= status
;
263 char *policy_list
[] = { "TS", "RR", "??", "FF",
264 "??", "??", "??", "BE"};
279 db_printf("db_print_act(NULL)!\n");
284 if (flag
& OPTION_USER
) {
286 if (flag
& OPTION_LONG
) {
287 if (flag
& OPTION_INDENT
)
289 if (flag
& OPTION_THREAD_TITLE
) {
290 db_printf("%s ID: ACT STAT SW STACK SHUTTLE", indent
);
291 db_printf(" SUS PRI WAIT_FUNC\n");
293 policy
= ((athread
&& (athread
->sched_mode
&TH_MODE_TIMESHARE
))? 1: 2);
294 db_printf("%s%3d%c %0*X %s %s %0*X %0*X %3d %3d/%s ",
296 (thr_act
== current_thread())? '#': ':',
297 2*sizeof(vm_offset_t
), thr_act
,
298 db_act_stat(thr_act
, status
),
299 db_act_swap_stat(thr_act
, swap_status
),
300 2*sizeof(vm_offset_t
), (athread
?athread
->kernel_stack
:0),
301 2*sizeof(vm_offset_t
), athread
,
302 thr_act
->suspend_count
,
303 (athread
? athread
->sched_pri
: 999), /* XXX */
304 policy_list
[policy
-1]);
306 /* no longer TH_SWAP, no continuation to print */
307 if (athread
->state
& TH_WAIT
)
308 db_task_printsym((db_addr_t
)athread
->wait_event
,
309 DB_STGY_ANY
, kernel_task
);
313 if (act_id
% 3 == 0) {
314 if (flag
& OPTION_INDENT
)
318 db_printf("%3d%c(%0*X,%s)", act_id
,
319 (thr_act
== current_thread())? '#': ':',
320 2*sizeof(vm_offset_t
), thr_act
,
321 db_act_stat(thr_act
, status
));
324 if (flag
& OPTION_INDENT
)
325 db_printf(" %3d (%0*X) ", act_id
,
326 2*sizeof(vm_offset_t
), thr_act
);
328 db_printf("(%0*X) ", 2*sizeof(vm_offset_t
), thr_act
);
330 db_printf("%c%c%c%c%c",
331 (athread
->state
& TH_RUN
) ? 'R' : ' ',
332 (athread
->state
& TH_WAIT
) ? 'W' : ' ',
333 (athread
->state
& TH_SUSP
) ? 'S' : ' ',
334 (athread
->state
& TH_UNINT
)? 'N' : ' ',
335 db_act_fp_used(thr_act
) ? 'F' : ' ');
336 if (!athread
->kernel_stack
) {
337 if (athread
->continuation
) {
339 db_task_printsym((db_addr_t
)athread
->continuation
,
340 DB_STGY_ANY
, kernel_task
);
343 db_printf("(handoff)");
346 if (athread
->state
& TH_WAIT
) {
348 db_task_printsym((db_addr_t
)athread
->wait_event
,
349 DB_STGY_ANY
, kernel_task
);
367 if (flag
& OPTION_USER
) {
368 if (flag
& OPTION_TASK_TITLE
) {
369 db_printf(" ID: TASK MAP THD SUS PR SW %s",
371 if ((flag
& OPTION_LONG
) == 0)
376 switch ((int) task
->swap_state
) {
383 case TASK_SW_GOING_OUT
:
386 case TASK_SW_COMING_IN
:
389 case TASK_SW_UNSWAPPABLE
:
396 #else /* TASK_SWAPPER */
398 #endif /* TASK_SWAPPER */
400 db_printf("%3d: %0*X %0*X %3d %3d %2d %c ",
401 task_id
, 2*sizeof(vm_offset_t
), task
,
402 2*sizeof(vm_offset_t
), task
->map
,
408 if (flag
& OPTION_LONG
) {
409 if (flag
& OPTION_TASK_TITLE
)
410 flag
|= OPTION_THREAD_TITLE
;
412 } else if (task
->thread_count
<= 1)
413 flag
&= ~OPTION_INDENT
;
415 queue_iterate(&task
->threads
, thr_act
, thread_t
, task_threads
) {
416 db_print_act(thr_act
, act_id
, flag
);
417 flag
&= ~OPTION_THREAD_TITLE
;
420 if ((flag
& OPTION_LONG
) == 0)
423 if (flag
& OPTION_LONG
) {
424 if (flag
& OPTION_TASK_TITLE
) {
425 db_printf(" TASK ACT\n");
426 if (task
->thread_count
> 1)
427 flag
|= OPTION_THREAD_TITLE
;
430 db_printf("%3d (%0*X): ", task_id
, 2*sizeof(vm_offset_t
), task
);
431 if (task
->thread_count
== 0) {
432 db_printf("no threads\n");
434 if (task
->thread_count
> 1) {
435 db_printf("%d threads: \n", task
->thread_count
);
436 flag
|= OPTION_INDENT
;
438 flag
&= ~OPTION_INDENT
;
440 queue_iterate(&task
->threads
, thr_act
,
441 thread_t
, task_threads
) {
442 db_print_act(thr_act
, act_id
++, flag
);
443 flag
&= ~OPTION_THREAD_TITLE
;
456 thread_t act
= (thread_t
)queue_first(&task
->threads
);
460 space
= task
->itk_space
;
462 count
= db_port_iterate(act
, FALSE
, FALSE
);
463 db_printf("%3d: %08x %08x %08x %sactive %d\n",
464 task_id
, task
, space
, task
->map
,
465 space
->is_active
? "":"!", count
);
482 db_printf("id task map pmap virtual rss pg rss mem wir pg wir mem\n");
486 pmap
= vm_map_pmap(map
);
488 size
= db_vm_map_total_size(map
);
489 resident
= pmap
->stats
.resident_count
;
490 wired
= pmap
->stats
.wired_count
;
492 db_printf("%2d %08x %08x %08x %7dK %6d %6dK %6d %6dK\n",
498 resident
, (resident
* PAGE_SIZE
) / 1024,
499 wired
, (wired
* PAGE_SIZE
) / 1024);
514 if (have_addr
== FALSE
) {
515 if ((thread
= db_default_act
) == THREAD_NULL
) {
516 if ((thread
= current_thread()) == THREAD_NULL
) {
517 db_printf("no thread.\n");
523 task
= (task_t
) addr
;
526 task_id
= db_lookup_task(task
);
528 db_printf("0x%x is not a task_t\n", addr
);
532 db_print_task_vm(task
, task_id
, TRUE
, modif
);
544 boolean_t title
= TRUE
;
545 processor_set_t pset
= &default_pset
;
548 queue_iterate(&pset
->tasks
, task
, task_t
, pset_tasks
) {
549 db_print_task_vm(task
, task_id
, title
, modif
);
565 processor_set_t pset
= &default_pset
;
567 flag
= OPTION_TASK_TITLE
|OPTION_INDENT
;
568 if (db_option(modif
, 'u'))
570 if (db_option(modif
, 'l'))
574 queue_iterate(&pset
->tasks
, task
, task_t
, pset_tasks
) {
575 db_print_task(task
, task_id
, flag
);
576 flag
&= ~OPTION_TASK_TITLE
;
578 if ((flag
& (OPTION_LONG
|OPTION_INDENT
)) == OPTION_INDENT
)
594 flag
= OPTION_TASK_TITLE
;
595 if (db_option(modif
, 'u'))
597 if (db_option(modif
, 'l'))
601 task
= db_current_task();
602 if (task
== TASK_NULL
) {
603 db_error("No task\n");
607 task
= (task_t
) addr
;
609 if ((task_id
= db_lookup_task(task
)) < 0) {
610 db_printf("bad task address 0x%llx\n", (unsigned long long)addr
);
615 db_printf(" ID: TASK SPACE MAP COUNT\n");
616 db_print_space(task
, task_id
, flag
);
629 processor_set_t pset
= &default_pset
;
631 flag
= OPTION_TASK_TITLE
|OPTION_INDENT
;
632 if (db_option(modif
, 'u'))
634 if (db_option(modif
, 'l'))
637 db_printf(" ID: TASK SPACE MAP COUNT\n");
638 queue_iterate(&pset
->tasks
, task
, task_t
, pset_tasks
) {
639 db_print_space(task
, task_id
, flag
);
651 processor_set_t pset
= &default_pset
;
653 queue_iterate(&pset
->tasks
, task
, task_t
, pset_tasks
) {
654 if (task
->itk_space
== space
) {
656 return (db_addr_t
)task
;
675 flag
= OPTION_THREAD_TITLE
;
676 if (db_option(modif
, 'u'))
678 if (db_option(modif
, 'l'))
682 thr_act
= current_thread();
683 if (thr_act
== THREAD_NULL
) {
684 db_error("No thr_act\n");
688 thr_act
= (thread_t
) addr
;
690 if ((act_id
= db_lookup_act(thr_act
)) < 0) {
691 db_printf("bad thr_act address %#llX\n", (unsigned long long)addr
);
696 if (flag
& OPTION_USER
) {
697 db_printf("TASK%d(%0*X):\n",
698 db_lookup_task(thr_act
->task
),
699 2*sizeof(vm_offset_t
), thr_act
->task
);
700 db_print_act(thr_act
, act_id
, flag
);
702 db_printf("task %d(%0*Xx): thr_act %d",
703 db_lookup_task(thr_act
->task
),
704 2*sizeof(vm_offset_t
), thr_act
->task
, act_id
);
705 db_print_act(thr_act
, act_id
, flag
);
707 if (db_option(modif
, 'i') &&
708 (thr_act
->state
& TH_WAIT
) &&
709 thr_act
->kernel_stack
== 0) {
711 db_printf("Wait State: option 0x%x\n",
712 thr_act
->ith_option
);
727 flag
= OPTION_TASK_TITLE
|OPTION_INDENT
;
728 if (db_option(modif
, 'u'))
730 if (db_option(modif
, 'l'))
734 task
= db_current_task();
735 if (task
== TASK_NULL
) {
736 db_error("No task\n");
740 task
= (task_t
) addr
;
742 if ((task_id
= db_lookup_task(task
)) < 0) {
743 db_printf("bad task address 0x%llX\n", (unsigned long long)addr
);
748 db_print_task(task
, task_id
, flag
);
761 thread
= (thread_t
) addr
;
763 thread
= current_thread();
764 if (thread
== THREAD_NULL
) {
765 db_error("No thread\n");
769 db_printf("thread %x:\n", thread
);
770 printf(" $task%d.%d(%x)", db_lookup_task(thread
->task
),
771 db_lookup_act(thread
), thread
);
779 return (port
->ip_messages
.imq_msgcount
);
782 static int db_print_ent_cnt
= 0;
784 void db_reset_print_entry(
787 db_print_ent_cnt
= 0;
794 mach_port_name_t name
,
798 ipc_port_t aport
= (ipc_port_t
)entry
->ie_object
;
799 ipc_entry_bits_t bits
;
801 bits
= entry
->ie_bits
;
802 if (is_pset
&& !aport
->ip_pset_count
)
804 if (db_print_ent_cnt
&& db_print_ent_cnt
% 2 == 0)
807 db_printf("\t%s%d[%x]",
808 !is_pset
&& aport
->ip_pset_count
? "pset" : "port",
810 MACH_PORT_MAKE(index
, IE_BITS_GEN(bits
)));
812 db_printf("\t%s[%x]",
813 !is_pset
&& aport
->ip_pset_count
? "pset" : "port",
816 db_printf("(%s,%x,%d)",
817 (bits
& MACH_PORT_TYPE_RECEIVE
)? "r":
818 (bits
& MACH_PORT_TYPE_SEND
)? "s": "S",
820 db_port_kmsg_count(aport
));
824 db_printf("(%s,%x,set_count=%d,%d)",
825 (bits
& MACH_PORT_TYPE_RECEIVE
)? "r":
826 (bits
& MACH_PORT_TYPE_SEND
)? "s": "S",
828 aport
->ip_pset_count
,
829 db_port_kmsg_count(aport
));
841 ipc_tree_entry_t tentry
;
848 space
= thr_act
->task
->itk_space
;
849 entry
= space
->is_table
;
850 size
= space
->is_table_size
;
851 db_reset_print_entry();
852 for (index
= 0; index
< size
; ++index
, ++entry
) {
853 if (entry
->ie_bits
& MACH_PORT_TYPE_PORT_RIGHTS
) {
855 db_print_one_entry(entry
,
856 index
, MACH_PORT_NULL
, is_pset
, space
);
860 for (tentry
= ipc_splay_traverse_start(&space
->is_tree
);
862 tentry
= ipc_splay_traverse_next(&space
->is_tree
, FALSE
)) {
863 entry
= &tentry
->ite_entry
;
864 if (entry
->ie_bits
& MACH_PORT_TYPE_PORT_RIGHTS
) {
866 db_print_one_entry(entry
,
867 0, tentry
->ite_name
, is_pset
, space
);
879 register ipc_space_t space
;
880 register ipc_entry_t entry
;
882 if (thr_act
== THREAD_NULL
)
884 space
= thr_act
->task
->itk_space
;
885 if (id
< 0 || id
>= space
->is_table_size
)
887 entry
= &space
->is_table
[id
];
888 if (entry
->ie_bits
& MACH_PORT_TYPE_PORT_RIGHTS
)
889 return((ipc_port_t
)entry
->ie_object
);
900 if (n
!= 0 && n
% 3 == 0)
902 db_printf("\tport%d(%s,%x)", id
,
903 (bits
& MACH_PORT_TYPE_RECEIVE
)? "r":
904 (bits
& MACH_PORT_TYPE_SEND
)? "s": "S", port
);
917 thr_act
= current_thread();
918 if (thr_act
== THREAD_NULL
) {
919 db_error("No thr_act\n");
923 thr_act
= (thread_t
) addr
;
924 if (db_lookup_act(thr_act
) < 0) {
925 db_printf("Bad thr_act address 0x%llX\n", addr
);
929 if (db_port_iterate(thr_act
, db_option(modif
,'s'), TRUE
))
934 * Useful system state when the world has hung.
939 extern void db_sched(void);
946 db_printf("current_{thread/task} 0x%x 0x%x\n",
947 current_thread(),current_task());
950 void db_show_one_runq(run_queue_t runq
);
959 processor_set_t pset
= &default_pset
;
962 boolean_t showedany
= FALSE
;
964 queue_iterate(&pset
->processors
, proc
, processor_t
, processors
) {
966 if (runq
->count
> 0) {
967 db_printf("PROCESSOR %x IN SET %x\n", proc
, pset
);
968 db_show_one_runq(runq
);
973 if (runq
->count
> 0) {
974 db_printf("PROCESSOR SET %x\n", pset
);
975 db_show_one_runq(runq
);
979 db_printf("No runnable threads\n");
986 int i
, task_id
, thread_id
;
991 printf("PRI TASK.ACTIVATION\n");
992 for (i
= runq
->highq
, q
= runq
->queues
+ i
; i
>= 0; i
--, q
--) {
993 if (!queue_empty(q
)) {
994 db_printf("%3d:", i
);
995 queue_iterate(q
, thread
, thread_t
, links
) {
997 task_id
= db_lookup_task(task
);
998 thread_id
= db_lookup_task_act(task
, thread
);
999 db_printf(" %d.%d", task_id
, thread_id
);