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