2 * Copyright (c) 2000-2004 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/queue.h>
67 #include <kern/processor.h>
68 #include <ipc/ipc_port.h>
69 #include <ipc/ipc_space.h>
70 #include <ipc/ipc_pset.h>
71 #include <vm/vm_print.h> /* for db_vm() */
73 #include <machine/db_machdep.h>
74 #include <machine/thread.h>
76 #include <ddb/db_lex.h>
77 #include <ddb/db_variables.h>
78 #include <ddb/db_sym.h>
79 #include <ddb/db_task_thread.h>
80 #include <ddb/db_command.h>
81 #include <ddb/db_output.h> /* For db_printf() */
82 #include <ddb/db_print.h>
85 #include <kern/task_swap.h>
86 #endif /* TASK_SWAPPER */
88 /* Prototypes for functions local to this file. XXX -- should be static!
92 register thread_t thr_act
,
95 char *db_act_swap_stat(
96 register thread_t thr_act
,
104 void db_reset_print_entry(
107 void db_print_one_entry(
110 mach_port_name_t name
,
117 boolean_t do_output
);
119 ipc_port_t
db_lookup_port(
123 static void db_print_port_id(
139 void db_print_task_vm(
145 void db_system_stats(void);
155 register struct db_variable
*regp
;
160 struct db_var_aux_param aux_param
;
161 task_t task
= TASK_NULL
;
163 aux_param
.modif
= modif
;
164 aux_param
.thr_act
= THREAD_NULL
;
165 if (db_option(modif
, 't')) {
167 if (!db_check_act_address_valid((thread_t
)addr
))
169 aux_param
.thr_act
= (thread_t
)addr
;
171 aux_param
.thr_act
= db_default_act
;
172 if (aux_param
.thr_act
!= THREAD_NULL
)
173 task
= aux_param
.thr_act
->task
;
175 for (regp
= db_regs
; regp
< db_eregs
; regp
++) {
176 if (regp
->max_level
> 1) {
177 db_printf("bad multi-suffixed register %s\n", regp
->name
);
180 aux_param
.level
= regp
->max_level
;
181 for (i
= regp
->low
; i
<= regp
->high
; i
++) {
182 aux_param
.suffix
[0] = i
;
183 db_read_write_variable(regp
, &value
, DB_VAR_GET
, &aux_param
);
184 if (regp
->max_level
> 0)
185 db_printf("%s%d%*s", regp
->name
, i
,
186 12-strlen(regp
->name
)-((i
<10)?1:2), "");
188 db_printf("%-12s", regp
->name
);
189 db_printf("%#*llN", 2+2*sizeof(db_expr_t
), (unsigned long long)value
);
190 db_find_xtrn_task_sym_and_offset((db_addr_t
)value
, &name
,
192 if (name
!= 0 && offset
<= db_maxoff
&& offset
!= value
) {
193 db_printf("\t%s", name
);
195 db_printf("+%#llr", (unsigned long long)offset
);
202 #define OPTION_LONG 0x001 /* long print option */
203 #define OPTION_USER 0x002 /* print ps-like stuff */
204 #define OPTION_INDENT 0x100 /* print with indent */
205 #define OPTION_THREAD_TITLE 0x200 /* print thread title */
206 #define OPTION_TASK_TITLE 0x400 /* print thread title */
209 #define DB_TASK_NAME(task) /* no task name */
210 #define DB_TASK_NAME_TITLE "" /* no task name */
211 #endif /* DB_TASK_NAME */
213 #ifndef db_act_fp_used
214 #define db_act_fp_used(thr_act) FALSE
219 register thread_t thr_act
,
222 register char *p
= status
;
224 if (!thr_act
->active
) {
232 thread_t athread
= thr_act
;
234 *p
++ = (athread
->state
& TH_RUN
) ? 'R' : '.';
235 *p
++ = (athread
->state
& TH_WAIT
) ? 'W' : '.';
236 *p
++ = (athread
->state
& TH_SUSP
) ? 'S' : '.';
237 *p
++ = (!athread
->kernel_stack
) ? 'O' : '.';
238 *p
++ = (athread
->state
& TH_UNINT
) ? 'N' : '.';
239 /* show if the FPU has been used */
240 *p
++ = db_act_fp_used(thr_act
) ? 'F' : '.';
248 register thread_t thr_act
,
251 register char *p
= status
;
257 char *policy_list
[] = { "TS", "RR", "??", "FF",
258 "??", "??", "??", "BE"};
273 db_printf("db_print_act(NULL)!\n");
278 if (flag
& OPTION_USER
) {
280 if (flag
& OPTION_LONG
) {
281 if (flag
& OPTION_INDENT
)
283 if (flag
& OPTION_THREAD_TITLE
) {
284 db_printf("%s ID: ACT STAT SW STACK SHUTTLE", indent
);
285 db_printf(" SUS PRI WAIT_FUNC\n");
287 policy
= ((athread
&& (athread
->sched_mode
&TH_MODE_TIMESHARE
))? 1: 2);
288 db_printf("%s%3d%c %0*X %s %s %0*X %0*X %3d %3d/%s ",
290 (thr_act
== current_thread())? '#': ':',
291 2*sizeof(vm_offset_t
), thr_act
,
292 db_act_stat(thr_act
, status
),
293 db_act_swap_stat(thr_act
, swap_status
),
294 2*sizeof(vm_offset_t
), (athread
?athread
->kernel_stack
:0),
295 2*sizeof(vm_offset_t
), athread
,
296 thr_act
->suspend_count
,
297 (athread
? athread
->sched_pri
: 999), /* XXX */
298 policy_list
[policy
-1]);
300 /* no longer TH_SWAP, no continuation to print */
301 if (athread
->state
& TH_WAIT
)
302 db_task_printsym((db_addr_t
)athread
->wait_event
,
303 DB_STGY_ANY
, kernel_task
);
307 if (act_id
% 3 == 0) {
308 if (flag
& OPTION_INDENT
)
312 db_printf("%3d%c(%0*X,%s)", act_id
,
313 (thr_act
== current_thread())? '#': ':',
314 2*sizeof(vm_offset_t
), thr_act
,
315 db_act_stat(thr_act
, status
));
318 if (flag
& OPTION_INDENT
)
319 db_printf(" %3d (%0*X) ", act_id
,
320 2*sizeof(vm_offset_t
), thr_act
);
322 db_printf("(%0*X) ", 2*sizeof(vm_offset_t
), thr_act
);
324 db_printf("%c%c%c%c%c",
325 (athread
->state
& TH_RUN
) ? 'R' : ' ',
326 (athread
->state
& TH_WAIT
) ? 'W' : ' ',
327 (athread
->state
& TH_SUSP
) ? 'S' : ' ',
328 (athread
->state
& TH_UNINT
)? 'N' : ' ',
329 db_act_fp_used(thr_act
) ? 'F' : ' ');
330 if (!athread
->kernel_stack
) {
331 if (athread
->continuation
) {
333 db_task_printsym((db_addr_t
)athread
->continuation
,
334 DB_STGY_ANY
, kernel_task
);
337 db_printf("(handoff)");
340 if (athread
->state
& TH_WAIT
) {
342 db_task_printsym((db_addr_t
)athread
->wait_event
,
343 DB_STGY_ANY
, kernel_task
);
361 if (flag
& OPTION_USER
) {
362 if (flag
& OPTION_TASK_TITLE
) {
363 db_printf(" ID: TASK MAP THD SUS PR SW %s",
365 if ((flag
& OPTION_LONG
) == 0)
370 switch ((int) task
->swap_state
) {
377 case TASK_SW_GOING_OUT
:
380 case TASK_SW_COMING_IN
:
383 case TASK_SW_UNSWAPPABLE
:
390 #else /* TASK_SWAPPER */
392 #endif /* TASK_SWAPPER */
394 db_printf("%3d: %0*X %0*X %3d %3d %2d %c ",
395 task_id
, 2*sizeof(vm_offset_t
), task
,
396 2*sizeof(vm_offset_t
), task
->map
,
402 if (flag
& OPTION_LONG
) {
403 if (flag
& OPTION_TASK_TITLE
)
404 flag
|= OPTION_THREAD_TITLE
;
406 } else if (task
->thread_count
<= 1)
407 flag
&= ~OPTION_INDENT
;
409 queue_iterate(&task
->threads
, thr_act
, thread_t
, task_threads
) {
410 db_print_act(thr_act
, act_id
, flag
);
411 flag
&= ~OPTION_THREAD_TITLE
;
414 if ((flag
& OPTION_LONG
) == 0)
417 if (flag
& OPTION_LONG
) {
418 if (flag
& OPTION_TASK_TITLE
) {
419 db_printf(" TASK ACT\n");
420 if (task
->thread_count
> 1)
421 flag
|= OPTION_THREAD_TITLE
;
424 db_printf("%3d (%0*X): ", task_id
, 2*sizeof(vm_offset_t
), task
);
425 if (task
->thread_count
== 0) {
426 db_printf("no threads\n");
428 if (task
->thread_count
> 1) {
429 db_printf("%d threads: \n", task
->thread_count
);
430 flag
|= OPTION_INDENT
;
432 flag
&= ~OPTION_INDENT
;
434 queue_iterate(&task
->threads
, thr_act
,
435 thread_t
, task_threads
) {
436 db_print_act(thr_act
, act_id
++, flag
);
437 flag
&= ~OPTION_THREAD_TITLE
;
450 thread_t act
= (thread_t
)queue_first(&task
->threads
);
454 space
= task
->itk_space
;
456 count
= db_port_iterate(act
, FALSE
, FALSE
);
457 db_printf("%3d: %08x %08x %08x %sactive %d\n",
458 task_id
, task
, space
, task
->map
,
459 space
->is_active
? "":"!", count
);
476 db_printf("id task map pmap virtual rss pg rss mem wir pg wir mem\n");
480 pmap
= vm_map_pmap(map
);
482 size
= db_vm_map_total_size(map
);
483 resident
= pmap
->stats
.resident_count
;
484 wired
= pmap
->stats
.wired_count
;
486 db_printf("%2d %08x %08x %08x %7dK %6d %6dK %6d %6dK\n",
492 resident
, (resident
* PAGE_SIZE
) / 1024,
493 wired
, (wired
* PAGE_SIZE
) / 1024);
508 if (have_addr
== FALSE
) {
509 if ((thread
= db_default_act
) == THREAD_NULL
) {
510 if ((thread
= current_thread()) == THREAD_NULL
) {
511 db_printf("no thread.\n");
517 task
= (task_t
) addr
;
520 task_id
= db_lookup_task(task
);
522 db_printf("0x%x is not a task_t\n", addr
);
526 db_print_task_vm(task
, task_id
, TRUE
, modif
);
538 boolean_t title
= TRUE
;
539 processor_set_t pset
= &default_pset
;
542 queue_iterate(&pset
->tasks
, task
, task_t
, pset_tasks
) {
543 db_print_task_vm(task
, task_id
, title
, modif
);
559 processor_set_t pset
= &default_pset
;
561 flag
= OPTION_TASK_TITLE
|OPTION_INDENT
;
562 if (db_option(modif
, 'u'))
564 if (db_option(modif
, 'l'))
568 queue_iterate(&pset
->tasks
, task
, task_t
, pset_tasks
) {
569 db_print_task(task
, task_id
, flag
);
570 flag
&= ~OPTION_TASK_TITLE
;
572 if ((flag
& (OPTION_LONG
|OPTION_INDENT
)) == OPTION_INDENT
)
588 flag
= OPTION_TASK_TITLE
;
589 if (db_option(modif
, 'u'))
591 if (db_option(modif
, 'l'))
595 task
= db_current_task();
596 if (task
== TASK_NULL
) {
597 db_error("No task\n");
601 task
= (task_t
) addr
;
603 if ((task_id
= db_lookup_task(task
)) < 0) {
604 db_printf("bad task address 0x%llx\n", (unsigned long long)addr
);
609 db_printf(" ID: TASK SPACE MAP COUNT\n");
610 db_print_space(task
, task_id
, flag
);
623 processor_set_t pset
= &default_pset
;
625 flag
= OPTION_TASK_TITLE
|OPTION_INDENT
;
626 if (db_option(modif
, 'u'))
628 if (db_option(modif
, 'l'))
631 db_printf(" ID: TASK SPACE MAP COUNT\n");
632 queue_iterate(&pset
->tasks
, task
, task_t
, pset_tasks
) {
633 db_print_space(task
, task_id
, flag
);
645 processor_set_t pset
= &default_pset
;
647 queue_iterate(&pset
->tasks
, task
, task_t
, pset_tasks
) {
648 if (task
->itk_space
== space
) {
650 return (db_addr_t
)task
;
669 flag
= OPTION_THREAD_TITLE
;
670 if (db_option(modif
, 'u'))
672 if (db_option(modif
, 'l'))
676 thr_act
= current_thread();
677 if (thr_act
== THREAD_NULL
) {
678 db_error("No thr_act\n");
682 thr_act
= (thread_t
) addr
;
684 if ((act_id
= db_lookup_act(thr_act
)) < 0) {
685 db_printf("bad thr_act address %#llX\n", (unsigned long long)addr
);
690 if (flag
& OPTION_USER
) {
691 db_printf("TASK%d(%0*X):\n",
692 db_lookup_task(thr_act
->task
),
693 2*sizeof(vm_offset_t
), thr_act
->task
);
694 db_print_act(thr_act
, act_id
, flag
);
696 db_printf("task %d(%0*Xx): thr_act %d",
697 db_lookup_task(thr_act
->task
),
698 2*sizeof(vm_offset_t
), thr_act
->task
, act_id
);
699 db_print_act(thr_act
, act_id
, flag
);
701 if (db_option(modif
, 'i') &&
702 (thr_act
->state
& TH_WAIT
) &&
703 thr_act
->kernel_stack
== 0) {
705 db_printf("Wait State: option 0x%x\n",
706 thr_act
->ith_option
);
721 flag
= OPTION_TASK_TITLE
|OPTION_INDENT
;
722 if (db_option(modif
, 'u'))
724 if (db_option(modif
, 'l'))
728 task
= db_current_task();
729 if (task
== TASK_NULL
) {
730 db_error("No task\n");
734 task
= (task_t
) addr
;
736 if ((task_id
= db_lookup_task(task
)) < 0) {
737 db_printf("bad task address 0x%llX\n", (unsigned long long)addr
);
742 db_print_task(task
, task_id
, flag
);
755 thread
= (thread_t
) addr
;
757 thread
= current_thread();
758 if (thread
== THREAD_NULL
) {
759 db_error("No thread\n");
763 db_printf("thread %x:\n", thread
);
764 printf(" $task%d.%d(%x)", db_lookup_task(thread
->task
),
765 db_lookup_act(thread
), thread
);
773 return (port
->ip_messages
.imq_msgcount
);
776 static int db_print_ent_cnt
= 0;
778 void db_reset_print_entry(
781 db_print_ent_cnt
= 0;
788 mach_port_name_t name
,
792 ipc_port_t aport
= (ipc_port_t
)entry
->ie_object
;
793 ipc_entry_bits_t bits
;
795 bits
= entry
->ie_bits
;
796 if (is_pset
&& !aport
->ip_pset_count
)
798 if (db_print_ent_cnt
&& db_print_ent_cnt
% 2 == 0)
801 db_printf("\t%s%d[%x]",
802 !is_pset
&& aport
->ip_pset_count
? "pset" : "port",
804 MACH_PORT_MAKE(index
, IE_BITS_GEN(bits
)));
806 db_printf("\t%s[%x]",
807 !is_pset
&& aport
->ip_pset_count
? "pset" : "port",
810 db_printf("(%s,%x,%d)",
811 (bits
& MACH_PORT_TYPE_RECEIVE
)? "r":
812 (bits
& MACH_PORT_TYPE_SEND
)? "s": "S",
814 db_port_kmsg_count(aport
));
818 db_printf("(%s,%x,set_count=%d,%d)",
819 (bits
& MACH_PORT_TYPE_RECEIVE
)? "r":
820 (bits
& MACH_PORT_TYPE_SEND
)? "s": "S",
822 aport
->ip_pset_count
,
823 db_port_kmsg_count(aport
));
835 ipc_tree_entry_t tentry
;
842 space
= thr_act
->task
->itk_space
;
843 entry
= space
->is_table
;
844 size
= space
->is_table_size
;
845 db_reset_print_entry();
846 for (index
= 0; index
< size
; ++index
, ++entry
) {
847 if (entry
->ie_bits
& MACH_PORT_TYPE_PORT_RIGHTS
) {
849 db_print_one_entry(entry
,
850 index
, MACH_PORT_NULL
, is_pset
, space
);
854 for (tentry
= ipc_splay_traverse_start(&space
->is_tree
);
856 tentry
= ipc_splay_traverse_next(&space
->is_tree
, FALSE
)) {
857 entry
= &tentry
->ite_entry
;
858 if (entry
->ie_bits
& MACH_PORT_TYPE_PORT_RIGHTS
) {
860 db_print_one_entry(entry
,
861 0, tentry
->ite_name
, is_pset
, space
);
873 register ipc_space_t space
;
874 register ipc_entry_t entry
;
876 if (thr_act
== THREAD_NULL
)
878 space
= thr_act
->task
->itk_space
;
879 if (id
< 0 || id
>= space
->is_table_size
)
881 entry
= &space
->is_table
[id
];
882 if (entry
->ie_bits
& MACH_PORT_TYPE_PORT_RIGHTS
)
883 return((ipc_port_t
)entry
->ie_object
);
894 if (n
!= 0 && n
% 3 == 0)
896 db_printf("\tport%d(%s,%x)", id
,
897 (bits
& MACH_PORT_TYPE_RECEIVE
)? "r":
898 (bits
& MACH_PORT_TYPE_SEND
)? "s": "S", port
);
911 thr_act
= current_thread();
912 if (thr_act
== THREAD_NULL
) {
913 db_error("No thr_act\n");
917 thr_act
= (thread_t
) addr
;
918 if (db_lookup_act(thr_act
) < 0) {
919 db_printf("Bad thr_act address 0x%llX\n", addr
);
923 if (db_port_iterate(thr_act
, db_option(modif
,'s'), TRUE
))
928 * Useful system state when the world has hung.
933 extern void db_sched(void);
940 db_printf("current_{thread/task} 0x%x 0x%x\n",
941 current_thread(),current_task());
944 void db_show_one_runq(run_queue_t runq
);
953 processor_set_t pset
= &default_pset
;
956 boolean_t showedany
= FALSE
;
958 queue_iterate(&pset
->processors
, proc
, processor_t
, processors
) {
960 if (runq
->count
> 0) {
961 db_printf("PROCESSOR %x IN SET %x\n", proc
, pset
);
962 db_show_one_runq(runq
);
967 if (runq
->count
> 0) {
968 db_printf("PROCESSOR SET %x\n", pset
);
969 db_show_one_runq(runq
);
973 db_printf("No runnable threads\n");
980 int i
, task_id
, thread_id
;
985 printf("PRI TASK.ACTIVATION\n");
986 for (i
= runq
->highq
, q
= runq
->queues
+ i
; i
>= 0; i
--, q
--) {
987 if (!queue_empty(q
)) {
988 db_printf("%3d:", i
);
989 queue_iterate(q
, thread
, thread_t
, links
) {
991 task_id
= db_lookup_task(task
);
992 thread_id
= db_lookup_task_act(task
, thread
);
993 db_printf(" %d.%d", task_id
, thread_id
);