]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ddb/orig/db_print.c
bec8f3f26aede3c9a60f7cc7d828da0affcd564c
[apple/xnu.git] / osfmk / ddb / orig / db_print.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23 /*
24 * @OSF_COPYRIGHT@
25 */
26 /*
27 * HISTORY
28 *
29 * Revision 1.1.1.1 1998/09/22 21:05:48 wsanchez
30 * Import of Mac OS X kernel (~semeria)
31 *
32 * Revision 1.2 1998/04/29 17:35:25 mburg
33 * MK7.3 merger
34 *
35 * Revision 1.2.85.1 1998/02/03 09:24:09 gdt
36 * Merge up to MK7.3
37 * [1998/02/03 09:10:24 gdt]
38 *
39 * Revision 1.2.81.1 1997/03/27 18:46:38 barbou
40 * ri-osc CR1565 - clean up db_print_act, removing old !USER code
41 * which had gotten stale (the option made little sense here anyway).
42 * Added routine db_show_one_thread() to take either act/shuttle and
43 * do something sensible. [dwm] Also rationalize plain, /u and /l
44 * output for "show act", "show task" and "show all acts".
45 * [1995/08/28 15:47:00 bolinger]
46 * [97/02/25 barbou]
47 *
48 * Revision 1.2.31.13 1996/01/09 19:16:02 devrcs
49 * Alpha kdebug Changes:
50 * Correct various header spacing to account for 64-bit addresses.
51 * Modify db_show_all_*() functions, so the can be called from kdebug.
52 * ( There's no way to call with "char *modif", so added NULL check. )
53 * Changed db_error() calls to DB_ERROR() macro, so we return on error
54 * on Alpha (we gotta return to kdebug).
55 * Changed declarations of 'register foo' to 'register int foo'.
56 * [1995/12/01 21:42:20 jfraser]
57 *
58 * Merged '64-bit safe' changes from DEC alpha port.
59 * [1995/11/21 18:03:24 jfraser]
60 *
61 * Revision 1.2.31.12 1995/10/09 17:03:30 devrcs
62 * Merge forward.
63 * [1995/08/24 20:56:42 watkins]
64 *
65 * Revision 1.2.59.1 1995/08/04 17:03:17 watkins
66 * Change to stack per shuttle model.
67 * [1995/07/19 20:26:13 watkins]
68 *
69 * Revision 1.2.31.11 1995/09/18 19:08:49 devrcs
70 * Merge forward.
71 * [1995/08/24 20:56:42 watkins]
72 *
73 * Revision 1.2.59.1 1995/08/04 17:03:17 watkins
74 * Change to stack per shuttle model.
75 * [1995/07/19 20:26:13 watkins]
76 *
77 * Revision 1.2.31.10 1995/05/19 15:43:04 bernadat
78 * Fixed db_print_act for empty activations.
79 * Let thread swapping be configurable.
80 * [95/05/19 bernadat]
81 *
82 * Revision 1.2.31.9 1995/05/14 18:10:25 dwm
83 * ri-osc CR1304 - merge (nmk19_latest - nmk19b1) diffs into mainline.
84 * mk6 CR938 - restore mach_msg hot path
85 * remove use of now-defunct fields in thread [mmp,dwm]
86 * [1995/05/14 17:25:05 dwm]
87 *
88 * Revision 1.2.31.8 1995/04/07 18:53:00 barbou
89 * VM Merge - Task Swapper.
90 * Renamed TH_SWAPPED to TH_STACK_HANDOFF and swap_func to continuation
91 * to resolve name conflict.
92 * From kernel/kdb/kdb_mach.c:
93 * Put in changes for swapping.
94 * [1991/11/21 20:32:15 mmp]
95 * [94/07/27 barbou]
96 * [95/03/08 barbou]
97 *
98 * Revision 1.2.31.7 1995/02/28 01:58:38 dwm
99 * mk6 CR1120 - Merge mk6pro_shared into cnmk_shared
100 * * Rev1.2.43.1 1995/01/27 22:01:26 bolinger
101 * * Fix ri-osc CR977: Make "show space" and "show ipc_port" give
102 * * accurate count of ports active in IPC space. Make "show ipc_port"
103 * * output task-visible port name.
104 * [1995/02/28 01:12:46 dwm]
105 *
106 * Revision 1.2.31.6 1995/02/23 21:43:34 alanl
107 * Fix db_show_one_task_vm for thread_act_ts.
108 * [95/01/09 rwd]
109 *
110 * Merged with DIPC2_SHARED.
111 * [95/01/04 alanl]
112 *
113 * Revision 1.2.31.5 1995/01/10 04:49:52 devrcs
114 * mk6 CR801 - merge up from nmk18b4 to nmk18b7
115 * Fix "sh thr/ul"; no cont. to print, fix pri/policy format.
116 * * Rev 1.2.31.4 1994/10/11 16:35:58 emcmanus
117 * Added "show runq" and "show shuttle".
118 * [1994/12/09 20:36:49 dwm]
119 *
120 * mk6 CR668 - 1.3b26 merge
121 * * Revision 1.2.8.6 1994/05/06 18:39:37 tmt
122 * Merged osc1.3dec/shared with osc1.3b19
123 * Merge Alpha changes into osc1.312b source code.
124 * 64bit cleanup.
125 * * End1.3merge
126 * [1994/11/04 08:49:52 dwm]
127 *
128 * Revision 1.2.31.3 1994/09/23 01:20:51 ezf
129 * change marker to not FREE
130 * [1994/09/22 21:10:41 ezf]
131 *
132 * Revision 1.2.31.2 1994/06/14 17:21:05 bolinger
133 * Merge up to NMK17.2.
134 * [1994/06/14 17:20:35 bolinger]
135 *
136 * Revision 1.2.23.4 1994/04/15 18:41:31 paire
137 * Changed interface of db_task_from_space routine.
138 * [94/03/31 paire]
139 *
140 * Revision 1.2.23.3 1994/03/07 16:37:48 paire
141 * Merge with Intel R1_1
142 * Change from NMK14.10 [1993/11/15 16:06:21 rwd]
143 *
144 * Enhanced pretty print routine and added db_task_from_space.
145 * Change from NMK14.10 [93/09/24 sjs]
146 * [94/02/21 paire]
147 *
148 * Exported ANSI prototype of db_port_kmsg_count routine.
149 * Added header file include for the declaration of db_norma_ipc routine.
150 * [94/02/15 paire]
151 *
152 * Revision 1.2.23.2 1994/02/11 14:21:58 paire
153 * Added new vm_print.h header file for db_vm declaration.
154 * [94/02/09 paire]
155 *
156 * Revision 1.2.23.1 1994/02/08 10:58:19 bernadat
157 * print out msgcount for each port in db_port_iterate
158 * Change from NORMA_MK14.6(August 93) [1993/07/27 12:35:17 mmp]
159 *
160 * Removed defintion of db_maxoff (got from <ddb/db_sym.h>).
161 * [93/08/12 paire]
162 *
163 * Show ipc_space_remote msg counts only if NORMA_IPC is on
164 * [93/07/21 bernadat]
165 *
166 * Add /s option to "show ipc_port" to pick out port sets.
167 * Change from NORMA_MK14.6 [1993/02/17 16:29:54 dwm]
168 * [93/07/16 bernadat]
169 * [94/02/07 bernadat]
170 *
171 * Revision 1.2.20.8 1994/06/08 19:11:15 dswartz
172 * Preemption merge.
173 * [1994/06/08 19:10:18 dswartz]
174 *
175 * Revision 1.2.20.7 1994/04/30 21:28:24 bolinger
176 * Thread control ops synchronization: now that TH_SUSP is back,
177 * enable ddb to show it when printing thread state.
178 * [1994/04/28 21:55:42 bolinger]
179 *
180 * Revision 1.2.20.6 1994/03/17 22:35:31 dwm
181 * The infamous name change: thread_activation + thread_shuttle = thread.
182 * [1994/03/17 21:25:46 dwm]
183 *
184 * Revision 1.2.20.5 1994/01/26 15:43:37 bolinger
185 * Move kernel_stack from thread to activation.
186 * [1994/01/25 21:53:11 bolinger]
187 *
188 * Revision 1.2.20.4 1994/01/12 17:50:44 dwm
189 * Coloc: initial restructuring to follow Utah model.
190 * [1994/01/12 17:13:12 dwm]
191 *
192 * Revision 1.2.20.3 1993/11/18 18:11:47 dwm
193 * Coloc: remove continuations entirely; they are incompatible
194 * with migration, and their volume is obfuscatory.
195 * [1993/11/18 18:06:27 dwm]
196 *
197 * Revision 1.2.20.2 1993/10/12 16:38:50 dwm
198 * CoLoc: neuter continuations, ifdef USE_CONTINUATIONS.
199 * [1993/10/12 16:14:46 dwm]
200 *
201 * Revision 1.2.8.4 1993/08/11 20:38:06 elliston
202 * Add ANSI Prototypes. CR #9523.
203 * [1993/08/11 03:33:51 elliston]
204 *
205 * Revision 1.2.8.3 1993/07/27 18:27:55 elliston
206 * Add ANSI prototypes. CR #9523.
207 * [1993/07/27 18:12:39 elliston]
208 *
209 * Revision 1.2.8.2 1993/06/09 02:20:35 gm
210 * CR9176 - ANSI C violations: trailing tokens on CPP
211 * directives, extra semicolons after decl_ ..., asm keywords
212 * [1993/06/07 18:57:22 jeffc]
213 *
214 * Removed a '#if MACH_FIXPRI' which somehow survived the purge. CR #9131.
215 * [1993/05/11 20:56:00 dswartz]
216 *
217 * Revision 1.2 1993/04/19 16:02:50 devrcs
218 * Added printout of thread scheduling policy to long form
219 * of thread display.
220 * [93/01/28 jat]
221 *
222 * Changes from mk78:
223 * Removed unused variable from db_show_regs().
224 * [92/05/16 jfriedl]
225 * Converted some db_printsyms to db_task_printsyms.
226 * [92/04/10 danner]
227 * Changed db_print_thread so that both display formats
228 * show the floating-point-used status of the thread.
229 * [92/03/16 rpd]
230 * [93/02/02 bruel]
231 *
232 * Revision 1.1 1992/09/30 02:01:18 robert
233 * Initial revision
234 *
235 * $EndLog$
236 */
237 /* CMU_HIST */
238 /*
239 * Revision 2.11.3.2 92/04/08 15:43:10 jeffreyh
240 * Added i option to show thread. This gives wait state information.
241 * [92/04/08 sjs]
242 *
243 * Revision 2.11.3.1 92/03/03 16:13:34 jeffreyh
244 * Pick up changes from TRUNK
245 * [92/02/26 11:00:01 jeffreyh]
246 *
247 * Revision 2.13 92/02/20 18:34:28 elf
248 * Fixed typo.
249 * [92/02/20 elf]
250 *
251 * Revision 2.12 92/02/19 15:07:47 elf
252 * Added db_thread_fp_used, to avoid machine-dependent conditionals.
253 * [92/02/19 rpd]
254 *
255 * Added 'F' flag to db_thread_stat showing if the thread has a valid
256 * FPU context. Tested on i386 and pmax.
257 * [92/02/17 kivinen]
258 *
259 * Revision 2.11 91/11/12 11:50:32 rvb
260 * Added OPTION_USER ("/u") to db_show_all_threads, db_show_one_thread,
261 * db_show_one_task. Without it, we display old-style information.
262 * [91/10/31 rpd]
263 *
264 * Revision 2.10 91/10/09 16:01:48 af
265 * Supported "show registers" for non current thread.
266 * Changed display format of thread and task information.
267 * Changed "show thread" to print current thread information
268 * if no thread is specified.
269 * Added "show_one_task" for "show task" command.
270 * Added IPC port print routines for "show ipc_port" command.
271 * [91/08/29 tak]
272 *
273 * Revision 2.9 91/08/03 18:17:19 jsb
274 * In db_print_thread, if the thread is swapped and there is a
275 * continuation function, print the function name in parentheses
276 * instead of '(swapped)'.
277 * [91/07/04 09:59:27 jsb]
278 *
279 * Revision 2.8 91/07/31 17:30:43 dbg
280 * Revise scheduling state machine.
281 * [91/07/30 16:43:42 dbg]
282 *
283 * Revision 2.7 91/07/09 23:15:57 danner
284 * Fixed a few printf that should be db_printfs.
285 * [91/07/08 danner]
286 *
287 * Revision 2.6 91/05/14 15:35:25 mrt
288 * Correcting copyright
289 *
290 * Revision 2.5 91/02/05 17:06:53 mrt
291 * Changed to new Mach copyright
292 * [91/01/31 16:18:56 mrt]
293 *
294 * Revision 2.4 90/10/25 14:43:54 rwd
295 * Changed db_show_regs to print unsigned.
296 * [90/10/19 rpd]
297 * Generalized the watchpoint support.
298 * [90/10/16 rwd]
299 *
300 * Revision 2.3 90/09/09 23:19:52 rpd
301 * Avoid totally incorrect guesses of symbol names for small values.
302 * [90/08/30 17:39:08 af]
303 *
304 * Revision 2.2 90/08/27 21:51:49 dbg
305 * Insist that 'show thread' be called with an explicit address.
306 * [90/08/22 dbg]
307 *
308 * Fix type for db_maxoff.
309 * [90/08/20 dbg]
310 *
311 * Do not dereference the "valuep" field of a variable directly,
312 * call the new db_read/write_variable functions instead.
313 * Reflected changes in symbol lookup functions.
314 * [90/08/20 af]
315 * Reduce lint.
316 * [90/08/10 14:33:44 dbg]
317 *
318 * Created.
319 * [90/07/25 dbg]
320 *
321 */
322 /* CMU_ENDHIST */
323 /*
324 * Mach Operating System
325 * Copyright (c) 1991,1990 Carnegie Mellon University
326 * All Rights Reserved.
327 *
328 * Permission to use, copy, modify and distribute this software and its
329 * documentation is hereby granted, provided that both the copyright
330 * notice and this permission notice appear in all copies of the
331 * software, derivative works or modified versions, and any portions
332 * thereof, and that both notices appear in supporting documentation.
333 *
334 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
335 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
336 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
337 *
338 * Carnegie Mellon requests users of this software to return to
339 *
340 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
341 * School of Computer Science
342 * Carnegie Mellon University
343 * Pittsburgh PA 15213-3890
344 *
345 * any improvements or extensions that they make and grant Carnegie Mellon
346 * the rights to redistribute these changes.
347 */
348 /*
349 */
350 /*
351 * Author: David B. Golub, Carnegie Mellon University
352 * Date: 7/90
353 */
354
355 /*
356 * Miscellaneous printing.
357 */
358 #include <dipc.h>
359 #include <task_swapper.h>
360
361 #include <string.h> /* For strlen() */
362 #include <mach/port.h>
363 #include <kern/task.h>
364 #include <kern/thread.h>
365 #include <kern/thread_swap.h>
366 #include <kern/queue.h>
367 #include <ipc/ipc_port.h>
368 #include <ipc/ipc_space.h>
369 #include <ipc/ipc_pset.h>
370 #include <vm/vm_print.h> /* for db_vm() */
371
372 #include <machine/db_machdep.h>
373 #include <machine/thread.h>
374
375 #include <ddb/db_lex.h>
376 #include <ddb/db_variables.h>
377 #include <ddb/db_sym.h>
378 #include <ddb/db_task_thread.h>
379 #include <ddb/db_command.h>
380 #include <ddb/db_output.h> /* For db_printf() */
381 #include <ddb/db_print.h>
382
383 #include <kern/sf.h>
384 #include <kern/sp_mk.h> /*** ??? fix so this can be removed ***/
385
386 #if TASK_SWAPPER
387 #include <kern/task_swap.h>
388 #endif /* TASK_SWAPPER */
389
390 /* Prototypes for functions local to this file. XXX -- should be static!
391 */
392
393 char *db_act_stat(
394 register thread_act_t thr_act,
395 char *status);
396
397 char *db_act_swap_stat(
398 register thread_act_t thr_act,
399 char *status);
400
401 void db_print_task(
402 task_t task,
403 int task_id,
404 int flag);
405
406 void db_reset_print_entry(
407 void);
408
409 void db_print_one_entry(
410 ipc_entry_t entry,
411 int index,
412 mach_port_name_t name,
413 boolean_t is_pset);
414
415 int db_port_iterate(
416 thread_act_t thr_act,
417 boolean_t is_pset,
418 boolean_t do_output);
419
420 ipc_port_t db_lookup_port(
421 thread_act_t thr_act,
422 int id);
423
424 static void db_print_port_id(
425 int id,
426 ipc_port_t port,
427 unsigned bits,
428 int n);
429
430 void db_print_act(
431 thread_act_t thr_act,
432 int act_id,
433 int flag);
434
435 void db_print_space(
436 task_t task,
437 int task_id,
438 int flag);
439
440 void db_print_task_vm(
441 task_t task,
442 int task_id,
443 boolean_t title,
444 char *modif);
445
446 void db_system_stats(void);
447
448
449 void
450 db_show_regs(
451 db_expr_t addr,
452 boolean_t have_addr,
453 db_expr_t count,
454 char *modif)
455 {
456 register struct db_variable *regp;
457 db_expr_t value;
458 db_addr_t offset;
459 char * name;
460 register int i;
461 struct db_var_aux_param aux_param;
462 task_t task = TASK_NULL;
463
464 aux_param.modif = modif;
465 aux_param.thr_act = THR_ACT_NULL;
466 if (db_option(modif, 't')) {
467 if (have_addr) {
468 if (!db_check_act_address_valid((thread_act_t)addr))
469 return;
470 aux_param.thr_act = (thread_act_t)addr;
471 } else
472 aux_param.thr_act = db_default_act;
473 if (aux_param.thr_act != THR_ACT_NULL)
474 task = aux_param.thr_act->task;
475 }
476 for (regp = db_regs; regp < db_eregs; regp++) {
477 if (regp->max_level > 1) {
478 db_printf("bad multi-suffixed register %s\n", regp->name);
479 continue;
480 }
481 aux_param.level = regp->max_level;
482 for (i = regp->low; i <= regp->high; i++) {
483 aux_param.suffix[0] = i;
484 db_read_write_variable(regp, &value, DB_VAR_GET, &aux_param);
485 if (regp->max_level > 0)
486 db_printf("%s%d%*s", regp->name, i,
487 12-strlen(regp->name)-((i<10)?1:2), "");
488 else
489 db_printf("%-12s", regp->name);
490 db_printf("%#*N", 2+2*sizeof(vm_offset_t), value);
491 db_find_xtrn_task_sym_and_offset((db_addr_t)value, &name,
492 &offset, task);
493 if (name != 0 && offset <= db_maxoff && offset != value) {
494 db_printf("\t%s", name);
495 if (offset != 0)
496 db_printf("+%#r", offset);
497 }
498 db_printf("\n");
499 }
500 }
501 }
502
503 #define OPTION_LONG 0x001 /* long print option */
504 #define OPTION_USER 0x002 /* print ps-like stuff */
505 #define OPTION_INDENT 0x100 /* print with indent */
506 #define OPTION_THREAD_TITLE 0x200 /* print thread title */
507 #define OPTION_TASK_TITLE 0x400 /* print thread title */
508
509 #ifndef DB_TASK_NAME
510 #define DB_TASK_NAME(task) /* no task name */
511 #define DB_TASK_NAME_TITLE "" /* no task name */
512 #endif /* DB_TASK_NAME */
513
514 #ifndef db_act_fp_used
515 #define db_act_fp_used(thr_act) FALSE
516 #endif
517
518 char *
519 db_act_stat(
520 register thread_act_t thr_act,
521 char *status)
522 {
523 register char *p = status;
524
525 if (!thr_act->active) {
526 *p++ = 'D',
527 *p++ = 'y',
528 *p++ = 'i',
529 *p++ = 'n',
530 *p++ = 'g';
531 *p++ = ' ';
532 } else if (!thr_act->thread) {
533 *p++ = 'E',
534 *p++ = 'm',
535 *p++ = 'p',
536 *p++ = 't',
537 *p++ = 'y';
538 *p++ = ' ';
539 } else {
540 thread_t athread = thr_act->thread;
541
542 *p++ = (athread->state & TH_RUN) ? 'R' : '.';
543 *p++ = (athread->state & TH_WAIT) ? 'W' : '.';
544 *p++ = (athread->state & TH_SUSP) ? 'S' : '.';
545 *p++ = (athread->state & TH_SWAPPED_OUT) ? 'O' : '.';
546 *p++ = (athread->state & TH_UNINT) ? 'N' : '.';
547 /* show if the FPU has been used */
548 *p++ = db_act_fp_used(thr_act) ? 'F' : '.';
549 }
550 *p++ = 0;
551 return(status);
552 }
553
554 char *
555 db_act_swap_stat(
556 register thread_act_t thr_act,
557 char *status)
558 {
559 register char *p = status;
560
561 #if THREAD_SWAPPER
562 switch (thr_act->swap_state & TH_SW_STATE) {
563 case TH_SW_UNSWAPPABLE:
564 *p++ = 'U';
565 break;
566 case TH_SW_IN:
567 *p++ = 'I';
568 break;
569 case TH_SW_GOING_OUT:
570 *p++ = 'G';
571 break;
572 case TH_SW_WANT_IN:
573 *p++ = 'W';
574 break;
575 case TH_SW_OUT:
576 *p++ = 'O';
577 break;
578 case TH_SW_COMING_IN:
579 *p++ = 'C';
580 break;
581 default:
582 *p++ = '?';
583 break;
584 }
585 *p++ = (thr_act->swap_state & TH_SW_TASK_SWAPPING) ? 'T' : '.';
586 #endif /* THREAD_SWAPPER */
587 *p++ = 0;
588
589 return status;
590 }
591
592 char *policy_list[] = { "TS", "RR", "??", "FF",
593 "??", "??", "??", "BE"};
594
595 void
596 db_print_act(
597 thread_act_t thr_act,
598 int act_id,
599 int flag)
600 {
601 thread_t athread;
602 char status[8];
603 char swap_status[3];
604 char *indent = "";
605 int policy;
606
607 if (!thr_act) {
608 db_printf("db_print_act(NULL)!\n");
609 return;
610 }
611
612 athread = thr_act->thread;
613 if (flag & OPTION_USER) {
614
615 if (flag & OPTION_LONG) {
616 if (flag & OPTION_INDENT)
617 indent = " ";
618 if (flag & OPTION_THREAD_TITLE) {
619 db_printf("%s ID: ACT STAT SW STACK SHUTTLE", indent);
620 db_printf(" SUS PRI WAIT_FUNC\n");
621 }
622 policy = (athread ? athread->policy : 2);
623 db_printf("%s%3d%c %0*X %s %s %0*X %0*X %3d %3d/%s ",
624 indent, act_id,
625 (thr_act == current_act())? '#': ':',
626 2*sizeof(vm_offset_t), thr_act,
627 db_act_stat(thr_act, status),
628 db_act_swap_stat(thr_act, swap_status),
629 2*sizeof(vm_offset_t), (athread ?athread->kernel_stack:0),
630 2*sizeof(vm_offset_t), athread,
631 thr_act->suspend_count,
632 (athread ? athread->sched_pri : 999), /* XXX */
633 policy_list[policy-1]);
634 if (athread) {
635 /* no longer TH_SWAP, no continuation to print */
636 if (athread->state & TH_WAIT)
637 db_task_printsym((db_addr_t)athread->wait_event,
638 DB_STGY_ANY, kernel_task);
639 }
640 db_printf("\n");
641 } else {
642 if (act_id % 3 == 0) {
643 if (flag & OPTION_INDENT)
644 db_printf("\n ");
645 } else
646 db_printf(" ");
647 db_printf("%3d%c(%0*X,%s)", act_id,
648 (thr_act == current_act())? '#': ':',
649 2*sizeof(vm_offset_t), thr_act,
650 db_act_stat(thr_act, status));
651 }
652 } else {
653 if (flag & OPTION_INDENT)
654 db_printf(" %3d (%0*X) ", act_id,
655 2*sizeof(vm_offset_t), thr_act);
656 else
657 db_printf("(%0*X) ", 2*sizeof(vm_offset_t), thr_act);
658 if (athread) {
659 db_printf("%c%c%c%c%c",
660 (athread->state & TH_RUN) ? 'R' : ' ',
661 (athread->state & TH_WAIT) ? 'W' : ' ',
662 (athread->state & TH_SUSP) ? 'S' : ' ',
663 (athread->state & TH_UNINT)? 'N' : ' ',
664 db_act_fp_used(thr_act) ? 'F' : ' ');
665 /* Obsolete TH_STACK_HANDOFF code, left for now; might enhance
666 * to print out safe_points instead */
667 if (athread->state & TH_STACK_HANDOFF) {
668 if (athread->continuation) {
669 db_printf("(");
670 db_task_printsym((db_addr_t)athread->continuation,
671 DB_STGY_ANY, kernel_task);
672 db_printf(")");
673 } else {
674 db_printf("(handoff)");
675 }
676 }
677 if (athread->state & TH_WAIT) {
678 db_printf(" ");
679 db_task_printsym((db_addr_t)athread->wait_event,
680 DB_STGY_ANY, kernel_task);
681 }
682 } else
683 db_printf("Empty");
684 db_printf("\n");
685 }
686 }
687
688 void
689 db_print_task(
690 task_t task,
691 int task_id,
692 int flag)
693 {
694 thread_act_t thr_act;
695 int act_id;
696 char sstate;
697
698 if (flag & OPTION_USER) {
699 if (flag & OPTION_TASK_TITLE) {
700 db_printf(" ID: TASK MAP THD RES SUS PR SW %s",
701 DB_TASK_NAME_TITLE);
702 if ((flag & OPTION_LONG) == 0)
703 db_printf(" ACTS");
704 db_printf("\n");
705 }
706 #if TASK_SWAPPER
707 switch ((int) task->swap_state) {
708 case TASK_SW_IN:
709 sstate = 'I';
710 break;
711 case TASK_SW_OUT:
712 sstate = 'O';
713 break;
714 case TASK_SW_GOING_OUT:
715 sstate = 'G';
716 break;
717 case TASK_SW_COMING_IN:
718 sstate = 'C';
719 break;
720 case TASK_SW_UNSWAPPABLE:
721 sstate = 'U';
722 break;
723 default:
724 sstate = '?';
725 break;
726 }
727 #else /* TASK_SWAPPER */
728 sstate = 'I';
729 #endif /* TASK_SWAPPER */
730 /*** ??? fix me ***/
731 db_printf("%3d: %0*X %0*X %3d %3d %3d %2d %c ",
732 task_id, 2*sizeof(vm_offset_t), task,
733 2*sizeof(vm_offset_t), task->map,
734 task->thr_act_count, task->res_act_count,
735 task->suspend_count,
736 ((mk_sp_attributes_t)(task->sp_attributes))->priority,
737 sstate);
738 DB_TASK_NAME(task);
739 if (flag & OPTION_LONG) {
740 if (flag & OPTION_TASK_TITLE)
741 flag |= OPTION_THREAD_TITLE;
742 db_printf("\n");
743 } else if (task->thr_act_count <= 1)
744 flag &= ~OPTION_INDENT;
745 act_id = 0;
746 queue_iterate(&task->thr_acts, thr_act, thread_act_t, thr_acts) {
747 db_print_act(thr_act, act_id, flag);
748 flag &= ~OPTION_THREAD_TITLE;
749 act_id++;
750 }
751 if ((flag & OPTION_LONG) == 0)
752 db_printf("\n");
753 } else {
754 if (flag & OPTION_LONG) {
755 if (flag & OPTION_TASK_TITLE) {
756 db_printf(" TASK ACT\n");
757 if (task->thr_act_count > 1)
758 flag |= OPTION_THREAD_TITLE;
759 }
760 }
761 db_printf("%3d (%0*X): ", task_id, 2*sizeof(vm_offset_t), task);
762 if (task->thr_act_count == 0) {
763 db_printf("no threads\n");
764 } else {
765 if (task->thr_act_count > 1) {
766 db_printf("%d threads: \n", task->thr_act_count);
767 flag |= OPTION_INDENT;
768 } else
769 flag &= ~OPTION_INDENT;
770 act_id = 0;
771 queue_iterate(&task->thr_acts, thr_act,
772 thread_act_t, thr_acts) {
773 db_print_act(thr_act, act_id++, flag);
774 flag &= ~OPTION_THREAD_TITLE;
775 }
776 }
777 }
778 }
779
780 void
781 db_print_space(
782 task_t task,
783 int task_id,
784 int flag)
785 {
786 ipc_space_t space;
787 thread_act_t act = (thread_act_t)queue_first(&task->thr_acts);
788 int count;
789
790 count = 0;
791 space = task->itk_space;
792 if (act)
793 count = db_port_iterate(act, FALSE, FALSE);
794 db_printf("%3d: %08x %08x %08x %sactive %d\n",
795 task_id, task, space, task->map,
796 space->is_active? "":"!", count);
797 }
798
799 void
800 db_print_task_vm(
801 task_t task,
802 int task_id,
803 boolean_t title,
804 char *modif)
805 {
806 vm_map_t map;
807 pmap_t pmap;
808 vm_size_t size;
809 long resident;
810 long wired;
811
812 if (title) {
813 db_printf("id task map pmap virtual rss pg rss mem wir pg wir mem\n");
814 }
815
816 map = task->map;
817 pmap = vm_map_pmap(map);
818
819 size = db_vm_map_total_size(map);
820 resident = pmap->stats.resident_count;
821 wired = pmap->stats.wired_count;
822
823 db_printf("%2d %08x %08x %08x %7dK %6d %6dK %6d %6dK\n",
824 task_id,
825 task,
826 map,
827 pmap,
828 size / 1024,
829 resident, (resident * PAGE_SIZE) / 1024,
830 wired, (wired * PAGE_SIZE) / 1024);
831 }
832
833
834 void
835 db_show_one_task_vm(
836 db_expr_t addr,
837 boolean_t have_addr,
838 db_expr_t count,
839 char *modif)
840 {
841 thread_act_t thread;
842 task_t task;
843 int task_id;
844
845 if (have_addr == FALSE) {
846 if ((thread = db_default_act) == THR_ACT_NULL) {
847 if ((thread = current_act()) == THR_ACT_NULL) {
848 db_printf("no thread.\n");
849 return;
850 }
851 }
852 task = thread->task;
853 } else {
854 task = (task_t) addr;
855 }
856
857 task_id = db_lookup_task(task);
858 if (task_id < 0) {
859 db_printf("0x%x is not a task_t\n", addr);
860 return;
861 }
862
863 db_print_task_vm(task, task_id, TRUE, modif);
864 }
865
866 void
867 db_show_all_task_vm(
868 db_expr_t addr,
869 boolean_t have_addr,
870 db_expr_t count,
871 char *modif)
872 {
873 task_t task;
874 int task_id;
875 boolean_t title = TRUE;
876 processor_set_t pset;
877
878 task_id = 0;
879 queue_iterate(&all_psets, pset, processor_set_t, all_psets) {
880 queue_iterate(&pset->tasks, task, task_t, pset_tasks) {
881 db_print_task_vm(task, task_id, title, modif);
882 title = FALSE;
883 task_id++;
884 }
885 }
886 }
887
888 void
889 db_show_all_acts(
890 db_expr_t addr,
891 boolean_t have_addr,
892 db_expr_t count,
893 char * modif)
894 {
895 task_t task;
896 int task_id;
897 int flag;
898 processor_set_t pset;
899
900 flag = OPTION_TASK_TITLE|OPTION_INDENT;
901 if (db_option(modif, 'u'))
902 flag |= OPTION_USER;
903 if (db_option(modif, 'l'))
904 flag |= OPTION_LONG;
905
906 task_id = 0;
907 queue_iterate(&all_psets, pset, processor_set_t, all_psets) {
908 queue_iterate(&pset->tasks, task, task_t, pset_tasks) {
909 db_print_task(task, task_id, flag);
910 flag &= ~OPTION_TASK_TITLE;
911 task_id++;
912 if ((flag & (OPTION_LONG|OPTION_INDENT)) == OPTION_INDENT)
913 db_printf("\n");
914 }
915 }
916 }
917
918 void
919 db_show_one_space(
920 db_expr_t addr,
921 boolean_t have_addr,
922 db_expr_t count,
923 char * modif)
924 {
925 int flag;
926 int task_id;
927 task_t task;
928
929 flag = OPTION_TASK_TITLE;
930 if (db_option(modif, 'u'))
931 flag |= OPTION_USER;
932 if (db_option(modif, 'l'))
933 flag |= OPTION_LONG;
934
935 if (!have_addr) {
936 task = db_current_task();
937 if (task == TASK_NULL) {
938 db_error("No task\n");
939 /*NOTREACHED*/
940 }
941 } else
942 task = (task_t) addr;
943
944 if ((task_id = db_lookup_task(task)) < 0) {
945 db_printf("bad task address 0x%x\n", addr);
946 db_error(0);
947 /*NOTREACHED*/
948 }
949
950 db_printf(" ID: TASK SPACE MAP COUNT\n");
951 db_print_space(task, task_id, flag);
952 }
953
954 void
955 db_show_all_spaces(
956 db_expr_t addr,
957 boolean_t have_addr,
958 db_expr_t count,
959 char * modif)
960 {
961 task_t task;
962 int task_id = 0;
963 int flag;
964 processor_set_t pset;
965
966 flag = OPTION_TASK_TITLE|OPTION_INDENT;
967 if (db_option(modif, 'u'))
968 flag |= OPTION_USER;
969 if (db_option(modif, 'l'))
970 flag |= OPTION_LONG;
971
972 db_printf(" ID: TASK SPACE MAP COUNT\n");
973 queue_iterate(&all_psets, pset, processor_set_t, all_psets) {
974 queue_iterate(&pset->tasks, task, task_t, pset_tasks) {
975 db_print_space(task, task_id, flag);
976 task_id++;
977 }
978 }
979 }
980
981 db_addr_t
982 db_task_from_space(
983 ipc_space_t space,
984 int *task_id)
985 {
986 task_t task;
987 int tid = 0;
988 processor_set_t pset;
989
990 queue_iterate(&all_psets, pset, processor_set_t, all_psets) {
991 queue_iterate(&pset->tasks, task, task_t, pset_tasks) {
992 if (task->itk_space == space) {
993 *task_id = tid;
994 return (db_addr_t)task;
995 }
996 tid++;
997 }
998 }
999 *task_id = 0;
1000 return (0);
1001 }
1002
1003 void
1004 db_show_one_act(
1005 db_expr_t addr,
1006 boolean_t have_addr,
1007 db_expr_t count,
1008 char * modif)
1009 {
1010 int flag;
1011 int act_id;
1012 thread_act_t thr_act;
1013
1014 flag = OPTION_THREAD_TITLE;
1015 if (db_option(modif, 'u'))
1016 flag |= OPTION_USER;
1017 if (db_option(modif, 'l'))
1018 flag |= OPTION_LONG;
1019
1020 if (!have_addr) {
1021 thr_act = current_act();
1022 if (thr_act == THR_ACT_NULL) {
1023 db_error("No thr_act\n");
1024 /*NOTREACHED*/
1025 }
1026 } else
1027 thr_act = (thread_act_t) addr;
1028
1029 if ((act_id = db_lookup_act(thr_act)) < 0) {
1030 db_printf("bad thr_act address %#x\n", addr);
1031 db_error(0);
1032 /*NOTREACHED*/
1033 }
1034
1035 if (flag & OPTION_USER) {
1036 db_printf("TASK%d(%0*X):\n",
1037 db_lookup_task(thr_act->task),
1038 2*sizeof(vm_offset_t), thr_act->task);
1039 db_print_act(thr_act, act_id, flag);
1040 } else {
1041 db_printf("task %d(%0*Xx): thr_act %d",
1042 db_lookup_task(thr_act->task),
1043 2*sizeof(vm_offset_t), thr_act->task, act_id);
1044 db_print_act(thr_act, act_id, flag);
1045 }
1046 if (db_option(modif, 'i') && thr_act->thread &&
1047 (thr_act->thread->state & TH_WAIT) &&
1048 thr_act->thread->kernel_stack == 0) {
1049
1050 db_printf("Wait State: option 0x%x\n",
1051 thr_act->thread->ith_option);
1052 }
1053 }
1054
1055 void
1056 db_show_one_task(
1057 db_expr_t addr,
1058 boolean_t have_addr,
1059 db_expr_t count,
1060 char * modif)
1061 {
1062 int flag;
1063 int task_id;
1064 task_t task;
1065
1066 flag = OPTION_TASK_TITLE|OPTION_INDENT;
1067 if (db_option(modif, 'u'))
1068 flag |= OPTION_USER;
1069 if (db_option(modif, 'l'))
1070 flag |= OPTION_LONG;
1071
1072 if (!have_addr) {
1073 task = db_current_task();
1074 if (task == TASK_NULL) {
1075 db_error("No task\n");
1076 /*NOTREACHED*/
1077 }
1078 } else
1079 task = (task_t) addr;
1080
1081 if ((task_id = db_lookup_task(task)) < 0) {
1082 db_printf("bad task address 0x%x\n", addr);
1083 db_error(0);
1084 /*NOTREACHED*/
1085 }
1086
1087 db_print_task(task, task_id, flag);
1088 }
1089
1090 void
1091 db_show_shuttle(
1092 db_expr_t addr,
1093 boolean_t have_addr,
1094 db_expr_t count,
1095 char * modif)
1096 {
1097 thread_shuttle_t shuttle;
1098 thread_act_t thr_act;
1099
1100 if (have_addr)
1101 shuttle = (thread_shuttle_t) addr;
1102 else {
1103 thr_act = current_act();
1104 if (thr_act == THR_ACT_NULL) {
1105 db_error("No thr_act\n");
1106 /*NOTREACHED*/
1107 }
1108 shuttle = thr_act->thread;
1109 if (shuttle == THREAD_NULL) {
1110 db_error("No shuttle associated with current thr_act\n");
1111 /*NOTREACHED*/
1112 }
1113 }
1114 db_printf("shuttle %x:\n", shuttle);
1115 if (shuttle->top_act == THR_ACT_NULL)
1116 db_printf(" no activations\n");
1117 else {
1118 db_printf(" activations:");
1119 for (thr_act = shuttle->top_act; thr_act != THR_ACT_NULL;
1120 thr_act = thr_act->lower) {
1121 if (thr_act != shuttle->top_act)
1122 printf(" from");
1123 printf(" $task%d.%d(%x)", db_lookup_task(thr_act->task),
1124 db_lookup_act(thr_act), thr_act);
1125 }
1126 db_printf("\n");
1127 }
1128 }
1129
1130 #define db_pset_kmsg_count(port) \
1131 (ipc_list_count((port)->ip_pset->ips_messages.imq_messages.ikmq_base))
1132
1133 int
1134 db_port_kmsg_count(
1135 ipc_port_t port)
1136 {
1137 return (port->ip_pset ? db_pset_kmsg_count(port) : port->ip_msgcount);
1138 }
1139
1140 static int db_print_ent_cnt = 0;
1141
1142 void db_reset_print_entry(
1143 void)
1144 {
1145 db_print_ent_cnt = 0;
1146 }
1147
1148 void
1149 db_print_one_entry(
1150 ipc_entry_t entry,
1151 int index,
1152 mach_port_t name,
1153 boolean_t is_pset)
1154 {
1155 ipc_port_t aport = (ipc_port_t)entry->ie_object;
1156 unsigned bits = entry->ie_bits;
1157
1158 if (is_pset && !aport->ip_pset)
1159 return;
1160 if (db_print_ent_cnt && db_print_ent_cnt % 2 == 0)
1161 db_printf("\n");
1162 if (!name)
1163 db_printf("\t%s%d[%x]",
1164 !is_pset && aport->ip_pset ? "pset" : "port",
1165 index,
1166 MACH_PORT_MAKE(index, IE_BITS_GEN(bits)));
1167 else
1168 db_printf("\t%s[%x]",
1169 !is_pset && aport->ip_pset ? "pset" : "port",
1170 name);
1171 if (!is_pset) {
1172 db_printf("(%s,%x,%d)",
1173 (bits & MACH_PORT_TYPE_RECEIVE)? "r":
1174 (bits & MACH_PORT_TYPE_SEND)? "s": "S",
1175 aport,
1176 db_port_kmsg_count(aport));
1177 db_print_ent_cnt++;
1178 }
1179 else {
1180 db_printf("(%s,%x,set=%x,%d)",
1181 (bits & MACH_PORT_TYPE_RECEIVE)? "r":
1182 (bits & MACH_PORT_TYPE_SEND)? "s": "S",
1183 aport,
1184 aport->ip_pset,
1185 db_pset_kmsg_count(aport));
1186 db_print_ent_cnt++;
1187 }
1188 }
1189
1190 int
1191 db_port_iterate(
1192 thread_act_t thr_act,
1193 boolean_t is_pset,
1194 boolean_t do_output)
1195 {
1196 ipc_entry_t entry;
1197 ipc_tree_entry_t tentry;
1198 int index;
1199 int size;
1200 int count;
1201 ipc_space_t space;
1202
1203 count = 0;
1204 space = thr_act->task->itk_space;
1205 entry = space->is_table;
1206 size = space->is_table_size;
1207 db_reset_print_entry();
1208 for (index = 0; index < size; ++index, ++entry) {
1209 if (entry->ie_bits & MACH_PORT_TYPE_PORT_RIGHTS) {
1210 if (do_output)
1211 db_print_one_entry(entry,
1212 index, (mach_port_t)0, is_pset);
1213 ++count;
1214 }
1215 }
1216 for (tentry = ipc_splay_traverse_start(&space->is_tree);
1217 tentry != ITE_NULL;
1218 tentry = ipc_splay_traverse_next(&space->is_tree, FALSE)) {
1219 entry = &tentry->ite_entry;
1220 if (entry->ie_bits & MACH_PORT_TYPE_PORT_RIGHTS) {
1221 if (do_output)
1222 db_print_one_entry(entry,
1223 0, tentry->ite_name, is_pset);
1224 ++count;
1225 }
1226 }
1227 return (count);
1228 }
1229
1230 ipc_port_t
1231 db_lookup_port(
1232 thread_act_t thr_act,
1233 int id)
1234 {
1235 register ipc_space_t space;
1236 register ipc_entry_t entry;
1237
1238 if (thr_act == THR_ACT_NULL)
1239 return(0);
1240 space = thr_act->task->itk_space;
1241 if (id < 0 || id >= space->is_table_size)
1242 return(0);
1243 entry = &space->is_table[id];
1244 if (entry->ie_bits & MACH_PORT_TYPE_PORT_RIGHTS)
1245 return((ipc_port_t)entry->ie_object);
1246 return(0);
1247 }
1248
1249 static void
1250 db_print_port_id(
1251 int id,
1252 ipc_port_t port,
1253 unsigned bits,
1254 int n)
1255 {
1256 if (n != 0 && n % 3 == 0)
1257 db_printf("\n");
1258 db_printf("\tport%d(%s,%x)", id,
1259 (bits & MACH_PORT_TYPE_RECEIVE)? "r":
1260 (bits & MACH_PORT_TYPE_SEND)? "s": "S", port);
1261 }
1262
1263 void
1264 db_show_port_id(
1265 db_expr_t addr,
1266 boolean_t have_addr,
1267 db_expr_t count,
1268 char * modif)
1269 {
1270 thread_act_t thr_act;
1271
1272 if (!have_addr) {
1273 thr_act = current_act();
1274 if (thr_act == THR_ACT_NULL) {
1275 db_error("No thr_act\n");
1276 /*NOTREACHED*/
1277 }
1278 } else
1279 thr_act = (thread_act_t) addr;
1280 if (db_lookup_act(thr_act) < 0) {
1281 db_printf("Bad thr_act address 0x%x\n", addr);
1282 db_error(0);
1283 /*NOTREACHED*/
1284 }
1285 if (db_port_iterate(thr_act, db_option(modif,'s'), TRUE))
1286 db_printf("\n");
1287 }
1288
1289 /*
1290 * Useful system state when the world has hung.
1291 */
1292 void
1293 db_system_stats()
1294 {
1295 extern void db_device(void);
1296 extern void db_sched(void);
1297 #if DIPC
1298 extern void db_dipc_stats(void);
1299 extern void db_show_kkt(void);
1300 #endif /* DIPC */
1301
1302 db_sched();
1303 iprintf("\n");
1304 db_vm();
1305 iprintf("\n");
1306 db_device();
1307 #if DIPC
1308 iprintf("\n");
1309 db_dipc_stats();
1310 iprintf("\n");
1311 db_show_kkt();
1312 #endif /* DIPC */
1313 iprintf("\n");
1314 db_printf("current_{thread/task} 0x%x 0x%x\n",
1315 current_thread(),current_task());
1316 }
1317
1318 void db_show_one_runq(run_queue_t runq);
1319
1320 void
1321 db_show_runq(
1322 db_expr_t addr,
1323 boolean_t have_addr,
1324 db_expr_t count,
1325 char * modif)
1326 {
1327 processor_set_t pset;
1328 processor_t proc;
1329 run_queue_t runq;
1330 boolean_t showedany = FALSE;
1331
1332 queue_iterate(&all_psets, pset, processor_set_t, all_psets) {
1333 #if NCPUS > 1 /* This code has not been tested. */
1334 queue_iterate(&pset->processors, proc, processor_t, processors) {
1335 runq = &proc->runq;
1336 if (runq->count > 0) {
1337 db_printf("PROCESSOR %x IN SET %x\n", proc, pset);
1338 db_show_one_runq(runq);
1339 showedany = TRUE;
1340 }
1341 }
1342 #endif /* NCPUS > 1 */
1343 #ifndef NCPUS
1344 #error NCPUS undefined
1345 #endif
1346 runq = &pset->runq;
1347 if (runq->count > 0) {
1348 db_printf("PROCESSOR SET %x\n", pset);
1349 db_show_one_runq(runq);
1350 showedany = TRUE;
1351 }
1352 }
1353 if (!showedany)
1354 db_printf("No runnable threads\n");
1355 }
1356
1357 void
1358 db_show_one_runq(
1359 run_queue_t runq)
1360 {
1361 int i, task_id, thr_act_id;
1362 queue_t q;
1363 thread_act_t thr_act;
1364 thread_t thread;
1365 task_t task;
1366
1367 printf("PRI TASK.ACTIVATION\n");
1368 for (i = runq->low, q = runq->runq + i; i < NRQS; i++, q++) {
1369 if (!queue_empty(q)) {
1370 db_printf("%3d:", i);
1371 queue_iterate(q, thread, thread_t, links) {
1372 thr_act = thread->top_act;
1373 task = thr_act->task;
1374 task_id = db_lookup_task(task);
1375 thr_act_id = db_lookup_task_act(task, thr_act);
1376 db_printf(" %d.%d", task_id, thr_act_id);
1377 }
1378 db_printf("\n");
1379 }
1380 }
1381 }