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