2 * Copyright (c) 2000-2007 Apple 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(
139 void db_print_task_vm(
145 void db_system_stats(void);
149 db_show_regs(db_expr_t addr
, boolean_t have_addr
, __unused db_expr_t count
,
152 register struct db_variable
*regp
;
157 struct db_var_aux_param aux_param
;
158 task_t task
= TASK_NULL
;
160 aux_param
.modif
= modif
;
161 aux_param
.thr_act
= THREAD_NULL
;
162 if (db_option(modif
, 't')) {
164 if (!db_check_act_address_valid((thread_t
)(unsigned long)addr
))
166 aux_param
.thr_act
= (thread_t
)(unsigned long)addr
;
168 aux_param
.thr_act
= db_default_act
;
169 if (aux_param
.thr_act
!= THREAD_NULL
)
170 task
= aux_param
.thr_act
->task
;
172 for (regp
= db_regs
; regp
< db_eregs
; regp
++) {
173 if (regp
->max_level
> 1) {
174 db_printf("bad multi-suffixed register %s\n", regp
->name
);
177 aux_param
.level
= regp
->max_level
;
178 for (i
= regp
->low
; i
<= regp
->high
; i
++) {
179 aux_param
.suffix
[0] = i
;
180 db_read_write_variable(regp
, &value
, DB_VAR_GET
, &aux_param
);
181 if (regp
->max_level
> 0)
182 db_printf("%s%d%*s", regp
->name
, i
,
183 12-strlen(regp
->name
)-((i
<10)?1:2), "");
185 db_printf("%-12s", regp
->name
);
186 db_printf("%#*llN", 2+2*sizeof(db_expr_t
), (unsigned long long)value
);
187 db_find_xtrn_task_sym_and_offset((db_addr_t
)value
, &name
,
189 if (name
!= 0 && offset
<= db_maxoff
&& offset
!= value
) {
190 db_printf("\t%s", name
);
192 db_printf("+%#llr", (unsigned long long)offset
);
199 #define OPTION_LONG 0x001 /* long print option */
200 #define OPTION_USER 0x002 /* print ps-like stuff */
201 #define OPTION_INDENT 0x100 /* print with indent */
202 #define OPTION_THREAD_TITLE 0x200 /* print thread title */
203 #define OPTION_TASK_TITLE 0x400 /* print thread title */
206 #define DB_TASK_NAME(task) /* no task name */
207 #define DB_TASK_NAME_TITLE "" /* no task name */
208 #endif /* DB_TASK_NAME */
210 #ifndef db_act_fp_used
211 #define db_act_fp_used(thr_act) FALSE
216 register thread_t thr_act
,
219 register char *p
= status
;
221 if (!thr_act
->active
) {
229 thread_t athread
= thr_act
;
231 *p
++ = (athread
->state
& TH_RUN
) ? 'R' : '.';
232 *p
++ = (athread
->state
& TH_WAIT
) ? 'W' : '.';
233 *p
++ = (athread
->state
& TH_SUSP
) ? 'S' : '.';
234 *p
++ = (!athread
->kernel_stack
) ? 'O' : '.';
235 *p
++ = (athread
->state
& TH_UNINT
) ? 'N' : '.';
236 /* show if the FPU has been used */
237 *p
++ = db_act_fp_used(thr_act
) ? 'F' : '.';
244 db_act_swap_stat(__unused thread_t thr_act
, char *status
)
246 register char *p
= status
;
252 const char *policy_list
[] = { "TS", "RR", "??", "FF", "??", "??", "??", "BE"};
263 const char *indent
= "";
267 db_printf("db_print_act(NULL)!\n");
272 if (flag
& OPTION_USER
) {
274 if (flag
& OPTION_LONG
) {
275 if (flag
& OPTION_INDENT
)
277 if (flag
& OPTION_THREAD_TITLE
) {
278 db_printf("%s ID: ACT STAT SW STACK SHUTTLE", indent
);
279 db_printf(" SUS PRI WAIT_FUNC\n");
281 policy
= ((athread
&& (athread
->sched_mode
&TH_MODE_TIMESHARE
))? 1: 2);
282 db_printf("%s%3d%c %0*X %s %s %0*X %0*X %3d %3d/%s ",
284 (thr_act
== current_thread())? '#': ':',
285 2*sizeof(vm_offset_t
), thr_act
,
286 db_act_stat(thr_act
, status
),
287 db_act_swap_stat(thr_act
, swap_status
),
288 2*sizeof(vm_offset_t
), (athread
?athread
->kernel_stack
:0),
289 2*sizeof(vm_offset_t
), athread
,
290 thr_act
->suspend_count
,
291 (athread
? athread
->sched_pri
: 999), /* XXX */
292 policy_list
[policy
-1]);
294 /* no longer TH_SWAP, no continuation to print */
295 if (athread
->state
& TH_WAIT
)
296 db_task_printsym((db_addr_t
)athread
->wait_event
,
297 DB_STGY_ANY
, kernel_task
);
301 if (act_id
% 3 == 0) {
302 if (flag
& OPTION_INDENT
)
306 db_printf("%3d%c(%0*X,%s)", act_id
,
307 (thr_act
== current_thread())? '#': ':',
308 2*sizeof(vm_offset_t
), thr_act
,
309 db_act_stat(thr_act
, status
));
312 if (flag
& OPTION_INDENT
)
313 db_printf(" %3d (%0*X) ", act_id
,
314 2*sizeof(vm_offset_t
), thr_act
);
316 db_printf("(%0*X) ", 2*sizeof(vm_offset_t
), thr_act
);
318 db_printf("%c%c%c%c%c",
319 (athread
->state
& TH_RUN
) ? 'R' : ' ',
320 (athread
->state
& TH_WAIT
) ? 'W' : ' ',
321 (athread
->state
& TH_SUSP
) ? 'S' : ' ',
322 (athread
->state
& TH_UNINT
)? 'N' : ' ',
323 db_act_fp_used(thr_act
) ? 'F' : ' ');
324 if (!athread
->kernel_stack
) {
325 if (athread
->continuation
) {
327 db_task_printsym((db_addr_t
)(unsigned long)athread
->continuation
,
328 DB_STGY_ANY
, kernel_task
);
331 db_printf("(handoff)");
334 if (athread
->state
& TH_WAIT
) {
336 db_task_printsym((db_addr_t
)athread
->wait_event
,
337 DB_STGY_ANY
, kernel_task
);
355 if (flag
& OPTION_USER
) {
356 if (flag
& OPTION_TASK_TITLE
) {
357 db_printf(" ID: TASK MAP THD SUS PR SW %s",
359 if ((flag
& OPTION_LONG
) == 0)
364 switch ((int) task
->swap_state
) {
371 case TASK_SW_GOING_OUT
:
374 case TASK_SW_COMING_IN
:
377 case TASK_SW_UNSWAPPABLE
:
384 #else /* TASK_SWAPPER */
386 #endif /* TASK_SWAPPER */
388 db_printf("%3d: %0*X %0*X %3d %3d %2d %c ",
389 task_id
, 2*sizeof(vm_offset_t
), task
,
390 2*sizeof(vm_offset_t
), task
->map
,
396 if (flag
& OPTION_LONG
) {
397 if (flag
& OPTION_TASK_TITLE
)
398 flag
|= OPTION_THREAD_TITLE
;
400 } else if (task
->thread_count
<= 1)
401 flag
&= ~OPTION_INDENT
;
403 queue_iterate(&task
->threads
, thr_act
, thread_t
, task_threads
) {
404 db_print_act(thr_act
, act_id
, flag
);
405 flag
&= ~OPTION_THREAD_TITLE
;
408 if ((flag
& OPTION_LONG
) == 0)
411 if (flag
& OPTION_LONG
) {
412 if (flag
& OPTION_TASK_TITLE
) {
413 db_printf(" TASK ACT\n");
414 if (task
->thread_count
> 1)
415 flag
|= OPTION_THREAD_TITLE
;
418 db_printf("%3d (%0*X): ", task_id
, 2*sizeof(vm_offset_t
), task
);
419 if (task
->thread_count
== 0) {
420 db_printf("no threads\n");
422 if (task
->thread_count
> 1) {
423 db_printf("%d threads: \n", task
->thread_count
);
424 flag
|= OPTION_INDENT
;
426 flag
&= ~OPTION_INDENT
;
428 queue_iterate(&task
->threads
, thr_act
,
429 thread_t
, task_threads
) {
430 db_print_act(thr_act
, act_id
++, flag
);
431 flag
&= ~OPTION_THREAD_TITLE
;
438 db_print_space(task_t task
, int task_id
, __unused
int flag
)
441 thread_t act
= (thread_t
)queue_first(&task
->threads
);
445 space
= task
->itk_space
;
447 count
= db_port_iterate(act
, FALSE
, FALSE
);
448 db_printf("%3d: %08x %08x %08x %sactive %d\n",
449 task_id
, task
, space
, task
->map
,
450 space
->is_active
? "":"!", count
);
454 db_print_task_vm(task_t task
, int task_id
, boolean_t title
,
455 __unused
char *modif
)
464 db_printf("id task map pmap virtual rss pg rss mem wir pg wir mem\n");
468 pmap
= vm_map_pmap(map
);
470 size
= db_vm_map_total_size((unsigned long)map
);
471 resident
= pmap
->stats
.resident_count
;
472 wired
= pmap
->stats
.wired_count
;
474 db_printf("%2d %08x %08x %08x %7dK %6d %6dK %6d %6dK\n",
480 resident
, (resident
* PAGE_SIZE
) / 1024,
481 wired
, (wired
* PAGE_SIZE
) / 1024);
486 db_show_one_task_vm(db_expr_t addr
, boolean_t have_addr
,
487 __unused db_expr_t count
, char *modif
)
493 if (have_addr
== FALSE
) {
494 if ((thread
= db_default_act
) == THREAD_NULL
) {
495 if ((thread
= current_thread()) == THREAD_NULL
) {
496 db_printf("no thread.\n");
502 task
= (task_t
)(unsigned long)addr
;
505 task_id
= db_lookup_task(task
);
507 db_printf("0x%x is not a task_t\n", addr
);
511 db_print_task_vm(task
, task_id
, TRUE
, modif
);
515 db_show_all_task_vm(__unused db_expr_t addr
, __unused boolean_t have_addr
,
516 __unused db_expr_t count
, char *modif
)
520 boolean_t title
= TRUE
;
523 queue_iterate(&tasks
, task
, task_t
, tasks
) {
524 db_print_task_vm(task
, task_id
, title
, modif
);
531 db_show_all_acts(__unused db_expr_t addr
, __unused boolean_t have_addr
,
532 __unused db_expr_t count
, char *modif
)
538 flag
= OPTION_TASK_TITLE
|OPTION_INDENT
;
539 if (db_option(modif
, 'u'))
541 if (db_option(modif
, 'l'))
545 queue_iterate(&tasks
, task
, task_t
, tasks
) {
546 db_print_task(task
, task_id
, flag
);
547 flag
&= ~OPTION_TASK_TITLE
;
549 if ((flag
& (OPTION_LONG
|OPTION_INDENT
)) == OPTION_INDENT
)
555 db_show_one_space(db_expr_t addr
, boolean_t have_addr
,
556 __unused db_expr_t count
, char *modif
)
562 flag
= OPTION_TASK_TITLE
;
563 if (db_option(modif
, 'u'))
565 if (db_option(modif
, 'l'))
569 task
= db_current_task();
570 if (task
== TASK_NULL
) {
571 db_error("No task\n");
575 task
= (task_t
)(unsigned long)addr
;
577 if ((task_id
= db_lookup_task(task
)) < 0) {
578 db_printf("bad task address 0x%llx\n", (unsigned long long)addr
);
583 db_printf(" ID: TASK SPACE MAP COUNT\n");
584 db_print_space(task
, task_id
, flag
);
588 db_show_all_spaces(__unused db_expr_t addr
, __unused boolean_t have_addr
,
589 __unused db_expr_t count
, char *modif
)
595 flag
= OPTION_TASK_TITLE
|OPTION_INDENT
;
596 if (db_option(modif
, 'u'))
598 if (db_option(modif
, 'l'))
601 db_printf(" ID: TASK SPACE MAP COUNT\n");
602 queue_iterate(&tasks
, task
, task_t
, tasks
) {
603 db_print_space(task
, task_id
, flag
);
616 queue_iterate(&tasks
, task
, task_t
, tasks
) {
617 if (task
->itk_space
== space
) {
619 return (db_addr_t
)(unsigned long)task
;
628 db_show_one_act(db_expr_t addr
, boolean_t have_addr
, __unused db_expr_t count
,
635 flag
= OPTION_THREAD_TITLE
;
636 if (db_option(modif
, 'u'))
638 if (db_option(modif
, 'l'))
642 thr_act
= current_thread();
643 if (thr_act
== THREAD_NULL
) {
644 db_error("No thr_act\n");
648 thr_act
= (thread_t
)(unsigned long)addr
;
650 if ((act_id
= db_lookup_act(thr_act
)) < 0) {
651 db_printf("bad thr_act address %#llX\n", (unsigned long long)addr
);
656 if (flag
& OPTION_USER
) {
657 db_printf("TASK%d(%0*X):\n",
658 db_lookup_task(thr_act
->task
),
659 2*sizeof(vm_offset_t
), thr_act
->task
);
660 db_print_act(thr_act
, act_id
, flag
);
662 db_printf("task %d(%0*Xx): thr_act %d",
663 db_lookup_task(thr_act
->task
),
664 2*sizeof(vm_offset_t
), thr_act
->task
, act_id
);
665 db_print_act(thr_act
, act_id
, flag
);
667 if (db_option(modif
, 'i') &&
668 (thr_act
->state
& TH_WAIT
) &&
669 thr_act
->kernel_stack
== 0) {
671 db_printf("Wait State: option 0x%x\n",
672 thr_act
->ith_option
);
677 db_show_one_task(db_expr_t addr
, boolean_t have_addr
,
678 __unused db_expr_t count
, char *modif
)
684 flag
= OPTION_TASK_TITLE
|OPTION_INDENT
;
685 if (db_option(modif
, 'u'))
687 if (db_option(modif
, 'l'))
691 task
= db_current_task();
692 if (task
== TASK_NULL
) {
693 db_error("No task\n");
697 task
= (task_t
)(unsigned long)addr
;
699 if ((task_id
= db_lookup_task(task
)) < 0) {
700 db_printf("bad task address 0x%llX\n", (unsigned long long)addr
);
705 db_print_task(task
, task_id
, flag
);
709 db_show_shuttle(db_expr_t addr
, boolean_t have_addr
, __unused db_expr_t count
,
710 __unused
char *modif
)
715 thread
= (thread_t
)(unsigned long)addr
;
717 thread
= current_thread();
718 if (thread
== THREAD_NULL
) {
719 db_error("No thread\n");
723 db_printf("thread %x:\n", thread
);
724 printf(" $task%d.%d(%x)", db_lookup_task(thread
->task
),
725 db_lookup_act(thread
), thread
);
733 return (port
->ip_messages
.imq_msgcount
);
736 static int db_print_ent_cnt
= 0;
738 void db_reset_print_entry(
741 db_print_ent_cnt
= 0;
745 db_print_one_entry(ipc_entry_t entry
, int index
, mach_port_name_t name
,
746 boolean_t is_pset
, __unused ipc_space_t space
)
748 ipc_port_t aport
= (ipc_port_t
)entry
->ie_object
;
749 ipc_entry_bits_t bits
;
751 bits
= entry
->ie_bits
;
752 if (is_pset
&& !aport
->ip_pset_count
)
754 if (db_print_ent_cnt
&& db_print_ent_cnt
% 2 == 0)
757 db_printf("\t%s%d[%x]",
758 !is_pset
&& aport
->ip_pset_count
? "pset" : "port",
760 MACH_PORT_MAKE(index
, IE_BITS_GEN(bits
)));
762 db_printf("\t%s[%x]",
763 !is_pset
&& aport
->ip_pset_count
? "pset" : "port",
766 db_printf("(%s,%x,%d)",
767 (bits
& MACH_PORT_TYPE_RECEIVE
)? "r":
768 (bits
& MACH_PORT_TYPE_SEND
)? "s": "S",
770 db_port_kmsg_count(aport
));
774 db_printf("(%s,%x,set_count=%d,%d)",
775 (bits
& MACH_PORT_TYPE_RECEIVE
)? "r":
776 (bits
& MACH_PORT_TYPE_SEND
)? "s": "S",
778 aport
->ip_pset_count
,
779 db_port_kmsg_count(aport
));
791 ipc_tree_entry_t tentry
;
798 space
= thr_act
->task
->itk_space
;
799 entry
= space
->is_table
;
800 size
= space
->is_table_size
;
801 db_reset_print_entry();
802 for (index
= 0; index
< size
; ++index
, ++entry
) {
803 if (entry
->ie_bits
& MACH_PORT_TYPE_PORT_RIGHTS
) {
805 db_print_one_entry(entry
,
806 index
, MACH_PORT_NULL
, is_pset
, space
);
810 for (tentry
= ipc_splay_traverse_start(&space
->is_tree
);
812 tentry
= ipc_splay_traverse_next(&space
->is_tree
, FALSE
)) {
813 entry
= &tentry
->ite_entry
;
814 if (entry
->ie_bits
& MACH_PORT_TYPE_PORT_RIGHTS
) {
816 db_print_one_entry(entry
,
817 0, tentry
->ite_name
, is_pset
, space
);
829 register ipc_space_t space
;
830 register ipc_entry_t entry
;
832 if (thr_act
== THREAD_NULL
)
834 space
= thr_act
->task
->itk_space
;
835 if (id
< 0 || (unsigned)id
>= space
->is_table_size
)
837 entry
= &space
->is_table
[id
];
838 if (entry
->ie_bits
& MACH_PORT_TYPE_PORT_RIGHTS
)
839 return((ipc_port_t
)entry
->ie_object
);
844 db_show_port_id(db_expr_t addr
, boolean_t have_addr
, __unused db_expr_t count
,
850 thr_act
= current_thread();
851 if (thr_act
== THREAD_NULL
) {
852 db_error("No thr_act\n");
856 thr_act
= (thread_t
)(unsigned long)addr
;
857 if (db_lookup_act(thr_act
) < 0) {
858 db_printf("Bad thr_act address 0x%llX\n", addr
);
862 if (db_port_iterate(thr_act
, db_option(modif
,'s'), TRUE
))
866 extern void db_sched(void);
868 * Useful system state when the world has hung.
871 db_system_stats(void)
878 db_printf("current_{thread/task} 0x%x 0x%x\n",
879 current_thread(),current_task());
882 void db_show_one_runq(run_queue_t runq
);
885 db_show_runq(__unused db_expr_t addr
, __unused boolean_t have_addr
,
886 __unused db_expr_t count
, __unused
char *modif
)
890 boolean_t showedany
= FALSE
;
892 for (proc
= processor_list
; proc
!= PROCESSOR_NULL
; proc
= proc
->processor_list
) {
894 if (runq
->count
> 0) {
895 db_printf("PROCESSOR %x IN SET %x\n", proc
, proc
->processor_set
);
896 db_show_one_runq(runq
);
900 if (rt_runq
.count
> 0) {
901 db_printf("REAL TIME\n");
902 db_show_one_runq(runq
);
906 db_printf("No runnable threads\n");
913 int i
, task_id
, thread_id
;
918 printf("PRI TASK.ACTIVATION\n");
919 for (i
= runq
->highq
, q
= runq
->queues
+ i
; i
>= 0; i
--, q
--) {
920 if (!queue_empty(q
)) {
921 db_printf("%3d:", i
);
922 queue_iterate(q
, thread
, thread_t
, links
) {
924 task_id
= db_lookup_task(task
);
925 thread_id
= db_lookup_task_act(task
, thread
);
926 db_printf(" %d.%d", task_id
, thread_id
);