]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ddb/db_print.c
xnu-517.3.7.tar.gz
[apple/xnu.git] / osfmk / ddb / db_print.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
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
13 * file.
14 *
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.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /*
26 * @OSF_COPYRIGHT@
27 */
28 /*
29 * Mach Operating System
30 * Copyright (c) 1991,1990 Carnegie Mellon University
31 * All Rights Reserved.
32 *
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.
38 *
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.
42 *
43 * Carnegie Mellon requests users of this software to return to
44 *
45 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
46 * School of Computer Science
47 * Carnegie Mellon University
48 * Pittsburgh PA 15213-3890
49 *
50 * any improvements or extensions that they make and grant Carnegie Mellon
51 * the rights to redistribute these changes.
52 */
53 /*
54 */
55 /*
56 * Author: David B. Golub, Carnegie Mellon University
57 * Date: 7/90
58 */
59
60 /*
61 * Miscellaneous printing.
62 */
63 #include <task_swapper.h>
64
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() */
76
77 #include <machine/db_machdep.h>
78 #include <machine/thread.h>
79
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>
87
88 #if TASK_SWAPPER
89 #include <kern/task_swap.h>
90 #endif /* TASK_SWAPPER */
91
92 /* Prototypes for functions local to this file. XXX -- should be static!
93 */
94
95 char *db_act_stat(
96 register thread_act_t thr_act,
97 char *status);
98
99 char *db_act_swap_stat(
100 register thread_act_t thr_act,
101 char *status);
102
103 void db_print_task(
104 task_t task,
105 int task_id,
106 int flag);
107
108 void db_reset_print_entry(
109 void);
110
111 void db_print_one_entry(
112 ipc_entry_t entry,
113 int index,
114 mach_port_name_t name,
115 boolean_t is_pset,
116 ipc_space_t space);
117
118 int db_port_iterate(
119 thread_act_t thr_act,
120 boolean_t is_pset,
121 boolean_t do_output);
122
123 ipc_port_t db_lookup_port(
124 thread_act_t thr_act,
125 int id);
126
127 static void db_print_port_id(
128 int id,
129 ipc_port_t port,
130 unsigned bits,
131 int n);
132
133 void db_print_act(
134 thread_act_t thr_act,
135 int act_id,
136 int flag);
137
138 void db_print_space(
139 task_t task,
140 int task_id,
141 int flag);
142
143 void db_print_task_vm(
144 task_t task,
145 int task_id,
146 boolean_t title,
147 char *modif);
148
149 void db_system_stats(void);
150
151
152 void
153 db_show_regs(
154 db_expr_t addr,
155 boolean_t have_addr,
156 db_expr_t count,
157 char *modif)
158 {
159 register struct db_variable *regp;
160 db_expr_t value;
161 db_addr_t offset;
162 char * name;
163 register int i;
164 struct db_var_aux_param aux_param;
165 task_t task = TASK_NULL;
166
167 aux_param.modif = modif;
168 aux_param.thr_act = THR_ACT_NULL;
169 if (db_option(modif, 't')) {
170 if (have_addr) {
171 if (!db_check_act_address_valid((thread_act_t)addr))
172 return;
173 aux_param.thr_act = (thread_act_t)addr;
174 } else
175 aux_param.thr_act = db_default_act;
176 if (aux_param.thr_act != THR_ACT_NULL)
177 task = aux_param.thr_act->task;
178 }
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);
182 continue;
183 }
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), "");
191 else
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,
195 &offset, task);
196 if (name != 0 && offset <= db_maxoff && offset != value) {
197 db_printf("\t%s", name);
198 if (offset != 0)
199 db_printf("+%#r", offset);
200 }
201 db_printf("\n");
202 }
203 }
204 }
205
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 */
211
212 #ifndef DB_TASK_NAME
213 #define DB_TASK_NAME(task) /* no task name */
214 #define DB_TASK_NAME_TITLE "" /* no task name */
215 #endif /* DB_TASK_NAME */
216
217 #ifndef db_act_fp_used
218 #define db_act_fp_used(thr_act) FALSE
219 #endif
220
221 char *
222 db_act_stat(
223 register thread_act_t thr_act,
224 char *status)
225 {
226 register char *p = status;
227
228 if (!thr_act->active) {
229 *p++ = 'D',
230 *p++ = 'y',
231 *p++ = 'i',
232 *p++ = 'n',
233 *p++ = 'g';
234 *p++ = ' ';
235 } else if (!thr_act->thread) {
236 *p++ = 'E',
237 *p++ = 'm',
238 *p++ = 'p',
239 *p++ = 't',
240 *p++ = 'y';
241 *p++ = ' ';
242 } else {
243 thread_t athread = thr_act->thread;
244
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' : '.';
252 }
253 *p++ = 0;
254 return(status);
255 }
256
257 char *
258 db_act_swap_stat(
259 register thread_act_t thr_act,
260 char *status)
261 {
262 register char *p = status;
263
264 #if THREAD_SWAPPER
265 switch (thr_act->swap_state & TH_SW_STATE) {
266 case TH_SW_UNSWAPPABLE:
267 *p++ = 'U';
268 break;
269 case TH_SW_IN:
270 *p++ = 'I';
271 break;
272 case TH_SW_GOING_OUT:
273 *p++ = 'G';
274 break;
275 case TH_SW_WANT_IN:
276 *p++ = 'W';
277 break;
278 case TH_SW_OUT:
279 *p++ = 'O';
280 break;
281 case TH_SW_COMING_IN:
282 *p++ = 'C';
283 break;
284 default:
285 *p++ = '?';
286 break;
287 }
288 *p++ = (thr_act->swap_state & TH_SW_TASK_SWAPPING) ? 'T' : '.';
289 #endif /* THREAD_SWAPPER */
290 *p++ = 0;
291
292 return status;
293 }
294
295 char *policy_list[] = { "TS", "RR", "??", "FF",
296 "??", "??", "??", "BE"};
297
298 void
299 db_print_act(
300 thread_act_t thr_act,
301 int act_id,
302 int flag)
303 {
304 thread_t athread;
305 char status[8];
306 char swap_status[3];
307 char *indent = "";
308 int policy;
309
310 if (!thr_act) {
311 db_printf("db_print_act(NULL)!\n");
312 return;
313 }
314
315 athread = thr_act->thread;
316 if (flag & OPTION_USER) {
317
318 if (flag & OPTION_LONG) {
319 if (flag & OPTION_INDENT)
320 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");
324 }
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 ",
327 indent, act_id,
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]);
337 if (athread) {
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);
342 }
343 db_printf("\n");
344 } else {
345 if (act_id % 3 == 0) {
346 if (flag & OPTION_INDENT)
347 db_printf("\n ");
348 } else
349 db_printf(" ");
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));
354 }
355 } else {
356 if (flag & OPTION_INDENT)
357 db_printf(" %3d (%0*X) ", act_id,
358 2*sizeof(vm_offset_t), thr_act);
359 else
360 db_printf("(%0*X) ", 2*sizeof(vm_offset_t), thr_act);
361 if (athread) {
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) {
372 db_printf("(");
373 db_task_printsym((db_addr_t)athread->continuation,
374 DB_STGY_ANY, kernel_task);
375 db_printf(")");
376 } else {
377 db_printf("(handoff)");
378 }
379 }
380 if (athread->state & TH_WAIT) {
381 db_printf(" ");
382 db_task_printsym((db_addr_t)athread->wait_event,
383 DB_STGY_ANY, kernel_task);
384 }
385 } else
386 db_printf("Empty");
387 db_printf("\n");
388 }
389 }
390
391 void
392 db_print_task(
393 task_t task,
394 int task_id,
395 int flag)
396 {
397 thread_act_t thr_act;
398 int act_id;
399 char sstate;
400
401 if (flag & OPTION_USER) {
402 if (flag & OPTION_TASK_TITLE) {
403 db_printf(" ID: TASK MAP THD RES SUS PR SW %s",
404 DB_TASK_NAME_TITLE);
405 if ((flag & OPTION_LONG) == 0)
406 db_printf(" ACTS");
407 db_printf("\n");
408 }
409 #if TASK_SWAPPER
410 switch ((int) task->swap_state) {
411 case TASK_SW_IN:
412 sstate = 'I';
413 break;
414 case TASK_SW_OUT:
415 sstate = 'O';
416 break;
417 case TASK_SW_GOING_OUT:
418 sstate = 'G';
419 break;
420 case TASK_SW_COMING_IN:
421 sstate = 'C';
422 break;
423 case TASK_SW_UNSWAPPABLE:
424 sstate = 'U';
425 break;
426 default:
427 sstate = '?';
428 break;
429 }
430 #else /* TASK_SWAPPER */
431 sstate = 'I';
432 #endif /* TASK_SWAPPER */
433 /*** ??? fix me ***/
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,
438 task->suspend_count,
439 task->priority,
440 sstate);
441 DB_TASK_NAME(task);
442 if (flag & OPTION_LONG) {
443 if (flag & OPTION_TASK_TITLE)
444 flag |= OPTION_THREAD_TITLE;
445 db_printf("\n");
446 } else if (task->thread_count <= 1)
447 flag &= ~OPTION_INDENT;
448 act_id = 0;
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;
452 act_id++;
453 }
454 if ((flag & OPTION_LONG) == 0)
455 db_printf("\n");
456 } else {
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;
462 }
463 }
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");
467 } else {
468 if (task->thread_count > 1) {
469 db_printf("%d threads: \n", task->thread_count);
470 flag |= OPTION_INDENT;
471 } else
472 flag &= ~OPTION_INDENT;
473 act_id = 0;
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;
478 }
479 }
480 }
481 }
482
483 void
484 db_print_space(
485 task_t task,
486 int task_id,
487 int flag)
488 {
489 ipc_space_t space;
490 thread_act_t act = (thread_act_t)queue_first(&task->threads);
491 int count;
492
493 count = 0;
494 space = task->itk_space;
495 if (act)
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);
500 }
501
502 void
503 db_print_task_vm(
504 task_t task,
505 int task_id,
506 boolean_t title,
507 char *modif)
508 {
509 vm_map_t map;
510 pmap_t pmap;
511 vm_size_t size;
512 long resident;
513 long wired;
514
515 if (title) {
516 db_printf("id task map pmap virtual rss pg rss mem wir pg wir mem\n");
517 }
518
519 map = task->map;
520 pmap = vm_map_pmap(map);
521
522 size = db_vm_map_total_size(map);
523 resident = pmap->stats.resident_count;
524 wired = pmap->stats.wired_count;
525
526 db_printf("%2d %08x %08x %08x %7dK %6d %6dK %6d %6dK\n",
527 task_id,
528 task,
529 map,
530 pmap,
531 size / 1024,
532 resident, (resident * PAGE_SIZE) / 1024,
533 wired, (wired * PAGE_SIZE) / 1024);
534 }
535
536
537 void
538 db_show_one_task_vm(
539 db_expr_t addr,
540 boolean_t have_addr,
541 db_expr_t count,
542 char *modif)
543 {
544 thread_act_t thread;
545 task_t task;
546 int task_id;
547
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");
552 return;
553 }
554 }
555 task = thread->task;
556 } else {
557 task = (task_t) addr;
558 }
559
560 task_id = db_lookup_task(task);
561 if (task_id < 0) {
562 db_printf("0x%x is not a task_t\n", addr);
563 return;
564 }
565
566 db_print_task_vm(task, task_id, TRUE, modif);
567 }
568
569 void
570 db_show_all_task_vm(
571 db_expr_t addr,
572 boolean_t have_addr,
573 db_expr_t count,
574 char *modif)
575 {
576 task_t task;
577 int task_id;
578 boolean_t title = TRUE;
579 processor_set_t pset = &default_pset;
580
581 task_id = 0;
582 queue_iterate(&pset->tasks, task, task_t, pset_tasks) {
583 db_print_task_vm(task, task_id, title, modif);
584 title = FALSE;
585 task_id++;
586 }
587 }
588
589 void
590 db_show_all_acts(
591 db_expr_t addr,
592 boolean_t have_addr,
593 db_expr_t count,
594 char * modif)
595 {
596 task_t task;
597 int task_id;
598 int flag;
599 processor_set_t pset = &default_pset;
600
601 flag = OPTION_TASK_TITLE|OPTION_INDENT;
602 if (db_option(modif, 'u'))
603 flag |= OPTION_USER;
604 if (db_option(modif, 'l'))
605 flag |= OPTION_LONG;
606
607 task_id = 0;
608 queue_iterate(&pset->tasks, task, task_t, pset_tasks) {
609 db_print_task(task, task_id, flag);
610 flag &= ~OPTION_TASK_TITLE;
611 task_id++;
612 if ((flag & (OPTION_LONG|OPTION_INDENT)) == OPTION_INDENT)
613 db_printf("\n");
614 }
615 }
616
617 void
618 db_show_one_space(
619 db_expr_t addr,
620 boolean_t have_addr,
621 db_expr_t count,
622 char * modif)
623 {
624 int flag;
625 int task_id;
626 task_t task;
627
628 flag = OPTION_TASK_TITLE;
629 if (db_option(modif, 'u'))
630 flag |= OPTION_USER;
631 if (db_option(modif, 'l'))
632 flag |= OPTION_LONG;
633
634 if (!have_addr) {
635 task = db_current_task();
636 if (task == TASK_NULL) {
637 db_error("No task\n");
638 /*NOTREACHED*/
639 }
640 } else
641 task = (task_t) addr;
642
643 if ((task_id = db_lookup_task(task)) < 0) {
644 db_printf("bad task address 0x%x\n", addr);
645 db_error(0);
646 /*NOTREACHED*/
647 }
648
649 db_printf(" ID: TASK SPACE MAP COUNT\n");
650 db_print_space(task, task_id, flag);
651 }
652
653 void
654 db_show_all_spaces(
655 db_expr_t addr,
656 boolean_t have_addr,
657 db_expr_t count,
658 char * modif)
659 {
660 task_t task;
661 int task_id = 0;
662 int flag;
663 processor_set_t pset = &default_pset;
664
665 flag = OPTION_TASK_TITLE|OPTION_INDENT;
666 if (db_option(modif, 'u'))
667 flag |= OPTION_USER;
668 if (db_option(modif, 'l'))
669 flag |= OPTION_LONG;
670
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);
674 task_id++;
675 }
676 }
677
678 db_addr_t
679 db_task_from_space(
680 ipc_space_t space,
681 int *task_id)
682 {
683 task_t task;
684 int tid = 0;
685 processor_set_t pset = &default_pset;
686
687 queue_iterate(&pset->tasks, task, task_t, pset_tasks) {
688 if (task->itk_space == space) {
689 *task_id = tid;
690 return (db_addr_t)task;
691 }
692 tid++;
693 }
694 *task_id = 0;
695 return (0);
696 }
697
698 void
699 db_show_one_act(
700 db_expr_t addr,
701 boolean_t have_addr,
702 db_expr_t count,
703 char * modif)
704 {
705 int flag;
706 int act_id;
707 thread_act_t thr_act;
708
709 flag = OPTION_THREAD_TITLE;
710 if (db_option(modif, 'u'))
711 flag |= OPTION_USER;
712 if (db_option(modif, 'l'))
713 flag |= OPTION_LONG;
714
715 if (!have_addr) {
716 thr_act = current_act();
717 if (thr_act == THR_ACT_NULL) {
718 db_error("No thr_act\n");
719 /*NOTREACHED*/
720 }
721 } else
722 thr_act = (thread_act_t) addr;
723
724 if ((act_id = db_lookup_act(thr_act)) < 0) {
725 db_printf("bad thr_act address %#llX\n", addr);
726 db_error(0);
727 /*NOTREACHED*/
728 }
729
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);
735 } else {
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);
740 }
741 if (db_option(modif, 'i') && thr_act->thread &&
742 (thr_act->thread->state & TH_WAIT) &&
743 thr_act->thread->kernel_stack == 0) {
744
745 db_printf("Wait State: option 0x%x\n",
746 thr_act->thread->ith_option);
747 }
748 }
749
750 void
751 db_show_one_task(
752 db_expr_t addr,
753 boolean_t have_addr,
754 db_expr_t count,
755 char * modif)
756 {
757 int flag;
758 int task_id;
759 task_t task;
760
761 flag = OPTION_TASK_TITLE|OPTION_INDENT;
762 if (db_option(modif, 'u'))
763 flag |= OPTION_USER;
764 if (db_option(modif, 'l'))
765 flag |= OPTION_LONG;
766
767 if (!have_addr) {
768 task = db_current_task();
769 if (task == TASK_NULL) {
770 db_error("No task\n");
771 /*NOTREACHED*/
772 }
773 } else
774 task = (task_t) addr;
775
776 if ((task_id = db_lookup_task(task)) < 0) {
777 db_printf("bad task address 0x%llX\n", addr);
778 db_error(0);
779 /*NOTREACHED*/
780 }
781
782 db_print_task(task, task_id, flag);
783 }
784
785 void
786 db_show_shuttle(
787 db_expr_t addr,
788 boolean_t have_addr,
789 db_expr_t count,
790 char * modif)
791 {
792 thread_t shuttle;
793 thread_act_t thr_act;
794
795 if (have_addr)
796 shuttle = (thread_t) addr;
797 else {
798 thr_act = current_act();
799 if (thr_act == THR_ACT_NULL) {
800 db_error("No thr_act\n");
801 /*NOTREACHED*/
802 }
803 shuttle = thr_act->thread;
804 if (shuttle == THREAD_NULL) {
805 db_error("No shuttle associated with current thr_act\n");
806 /*NOTREACHED*/
807 }
808 }
809 db_printf("shuttle %x:\n", shuttle);
810 if (shuttle->top_act == THR_ACT_NULL)
811 db_printf(" no activations\n");
812 else {
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)
817 printf(" from");
818 printf(" $task%d.%d(%x)", db_lookup_task(thr_act->task),
819 db_lookup_act(thr_act), thr_act);
820 }
821 db_printf("\n");
822 }
823 }
824
825 int
826 db_port_kmsg_count(
827 ipc_port_t port)
828 {
829 return (port->ip_messages.imq_msgcount);
830 }
831
832 static int db_print_ent_cnt = 0;
833
834 void db_reset_print_entry(
835 void)
836 {
837 db_print_ent_cnt = 0;
838 }
839
840 void
841 db_print_one_entry(
842 ipc_entry_t entry,
843 int index,
844 mach_port_name_t name,
845 boolean_t is_pset,
846 ipc_space_t space)
847 {
848 ipc_port_t aport = (ipc_port_t)entry->ie_object;
849 ipc_entry_bits_t bits;
850
851 bits = entry->ie_bits;
852 if (is_pset && !aport->ip_pset_count)
853 return;
854 if (db_print_ent_cnt && db_print_ent_cnt % 2 == 0)
855 db_printf("\n");
856 if (!name)
857 db_printf("\t%s%d[%x]",
858 !is_pset && aport->ip_pset_count ? "pset" : "port",
859 index,
860 MACH_PORT_MAKE(index, IE_BITS_GEN(bits)));
861 else
862 db_printf("\t%s[%x]",
863 !is_pset && aport->ip_pset_count ? "pset" : "port",
864 name);
865 if (!is_pset) {
866 db_printf("(%s,%x,%d)",
867 (bits & MACH_PORT_TYPE_RECEIVE)? "r":
868 (bits & MACH_PORT_TYPE_SEND)? "s": "S",
869 aport,
870 db_port_kmsg_count(aport));
871 db_print_ent_cnt++;
872 }
873 else {
874 db_printf("(%s,%x,set_count=%d,%d)",
875 (bits & MACH_PORT_TYPE_RECEIVE)? "r":
876 (bits & MACH_PORT_TYPE_SEND)? "s": "S",
877 aport,
878 aport->ip_pset_count,
879 db_port_kmsg_count(aport));
880 db_print_ent_cnt++;
881 }
882 }
883
884 int
885 db_port_iterate(
886 thread_act_t thr_act,
887 boolean_t is_pset,
888 boolean_t do_output)
889 {
890 ipc_entry_t entry;
891 ipc_tree_entry_t tentry;
892 int index;
893 int size;
894 int count;
895 ipc_space_t space;
896
897 count = 0;
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) {
904 if (do_output)
905 db_print_one_entry(entry,
906 index, MACH_PORT_NULL, is_pset, space);
907 ++count;
908 }
909 }
910 for (tentry = ipc_splay_traverse_start(&space->is_tree);
911 tentry != ITE_NULL;
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) {
915 if (do_output)
916 db_print_one_entry(entry,
917 0, tentry->ite_name, is_pset, space);
918 ++count;
919 }
920 }
921 return (count);
922 }
923
924 ipc_port_t
925 db_lookup_port(
926 thread_act_t thr_act,
927 int id)
928 {
929 register ipc_space_t space;
930 register ipc_entry_t entry;
931
932 if (thr_act == THR_ACT_NULL)
933 return(0);
934 space = thr_act->task->itk_space;
935 if (id < 0 || id >= space->is_table_size)
936 return(0);
937 entry = &space->is_table[id];
938 if (entry->ie_bits & MACH_PORT_TYPE_PORT_RIGHTS)
939 return((ipc_port_t)entry->ie_object);
940 return(0);
941 }
942
943 static void
944 db_print_port_id(
945 int id,
946 ipc_port_t port,
947 unsigned bits,
948 int n)
949 {
950 if (n != 0 && n % 3 == 0)
951 db_printf("\n");
952 db_printf("\tport%d(%s,%x)", id,
953 (bits & MACH_PORT_TYPE_RECEIVE)? "r":
954 (bits & MACH_PORT_TYPE_SEND)? "s": "S", port);
955 }
956
957 void
958 db_show_port_id(
959 db_expr_t addr,
960 boolean_t have_addr,
961 db_expr_t count,
962 char * modif)
963 {
964 thread_act_t thr_act;
965
966 if (!have_addr) {
967 thr_act = current_act();
968 if (thr_act == THR_ACT_NULL) {
969 db_error("No thr_act\n");
970 /*NOTREACHED*/
971 }
972 } else
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);
976 db_error(0);
977 /*NOTREACHED*/
978 }
979 if (db_port_iterate(thr_act, db_option(modif,'s'), TRUE))
980 db_printf("\n");
981 }
982
983 /*
984 * Useful system state when the world has hung.
985 */
986 void
987 db_system_stats()
988 {
989 extern void db_sched(void);
990
991 db_sched();
992 iprintf("\n");
993 db_vm();
994 iprintf("\n");
995 iprintf("\n");
996 db_printf("current_{thread/task} 0x%x 0x%x\n",
997 current_thread(),current_task());
998 }
999
1000 void db_show_one_runq(run_queue_t runq);
1001
1002 void
1003 db_show_runq(
1004 db_expr_t addr,
1005 boolean_t have_addr,
1006 db_expr_t count,
1007 char * modif)
1008 {
1009 processor_set_t pset = &default_pset;
1010 processor_t proc;
1011 run_queue_t runq;
1012 boolean_t showedany = FALSE;
1013
1014 #if NCPUS > 1 /* This code has not been tested. */
1015 queue_iterate(&pset->processors, proc, processor_t, processors) {
1016 runq = &proc->runq;
1017 if (runq->count > 0) {
1018 db_printf("PROCESSOR %x IN SET %x\n", proc, pset);
1019 db_show_one_runq(runq);
1020 showedany = TRUE;
1021 }
1022 }
1023 #endif /* NCPUS > 1 */
1024 #ifndef NCPUS
1025 #error NCPUS undefined
1026 #endif
1027 runq = &pset->runq;
1028 if (runq->count > 0) {
1029 db_printf("PROCESSOR SET %x\n", pset);
1030 db_show_one_runq(runq);
1031 showedany = TRUE;
1032 }
1033 if (!showedany)
1034 db_printf("No runnable threads\n");
1035 }
1036
1037 void
1038 db_show_one_runq(
1039 run_queue_t runq)
1040 {
1041 int i, task_id, thr_act_id;
1042 queue_t q;
1043 thread_act_t thr_act;
1044 thread_t thread;
1045 task_t task;
1046
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);
1057 }
1058 db_printf("\n");
1059 }
1060 }
1061 }