|
|
1.1 root 1: /*
2: * Mach Operating System
3: * Copyright (c) 1991,1990 Carnegie Mellon University
4: * All Rights Reserved.
1.1.1.2 root 5: *
1.1 root 6: * Permission to use, copy, modify and distribute this software and its
7: * documentation is hereby granted, provided that both the copyright
8: * notice and this permission notice appear in all copies of the
9: * software, derivative works or modified versions, and any portions
10: * thereof, and that both notices appear in supporting documentation.
1.1.1.2 root 11: *
1.1 root 12: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
1.1.1.2 root 15: *
1.1 root 16: * Carnegie Mellon requests users of this software to return to
1.1.1.2 root 17: *
1.1 root 18: * Software Distribution Coordinator or [email protected]
19: * School of Computer Science
20: * Carnegie Mellon University
21: * Pittsburgh PA 15213-3890
1.1.1.2 root 22: *
1.1 root 23: * any improvements or extensions that they make and grant Carnegie Mellon
24: * the rights to redistribute these changes.
25: */
26: /*
27: * Author: David B. Golub, Carnegie Mellon University
28: * Date: 7/90
29: */
30:
31: #if MACH_KDB
32:
33: /*
34: * Miscellaneous printing.
35: */
1.1.1.3 ! root 36: #include <string.h>
1.1 root 37: #include <mach/port.h>
38: #include <kern/task.h>
39: #include <kern/thread.h>
40: #include <kern/queue.h>
41: #include <ipc/ipc_port.h>
42: #include <ipc/ipc_space.h>
43:
1.1.1.3 ! root 44: #include <machine/db_interface.h>
1.1 root 45: #include <machine/db_machdep.h>
46: #include <machine/thread.h>
47:
1.1.1.3 ! root 48: #include <ddb/db_command.h>
! 49: #include <ddb/db_output.h>
1.1 root 50: #include <ddb/db_lex.h>
51: #include <ddb/db_variables.h>
52: #include <ddb/db_sym.h>
53: #include <ddb/db_task_thread.h>
1.1.1.3 ! root 54: #include <ddb/db_print.h>
1.1 root 55:
56: extern unsigned int db_maxoff;
57:
58: /* ARGSUSED */
59: void
60: db_show_regs(addr, have_addr, count, modif)
61: db_expr_t addr;
62: boolean_t have_addr;
63: db_expr_t count;
64: char *modif;
65: {
66: register struct db_variable *regp;
67: db_expr_t value;
68: db_addr_t offset;
69: char * name;
1.1.1.3 ! root 70: register int i;
1.1 root 71: struct db_var_aux_param aux_param;
72: task_t task = TASK_NULL;
73:
74: aux_param.modif = modif;
75: aux_param.thread = THREAD_NULL;
76: if (db_option(modif, 't')) {
77: if (have_addr) {
78: if (!db_check_thread_address_valid((thread_t)addr))
79: return;
80: aux_param.thread = (thread_t)addr;
81: } else
82: aux_param.thread = db_default_thread;
83: if (aux_param.thread != THREAD_NULL)
84: task = aux_param.thread->task;
85: }
86: for (regp = db_regs; regp < db_eregs; regp++) {
87: if (regp->max_level > 1) {
88: db_printf("bad multi-suffixed register %s\n", regp->name);
89: continue;
90: }
91: aux_param.level = regp->max_level;
92: for (i = regp->low; i <= regp->high; i++) {
93: aux_param.suffix[0] = i;
94: db_read_write_variable(regp, &value, DB_VAR_GET, &aux_param);
95: if (regp->max_level > 0)
1.1.1.2 root 96: db_printf("%s%d%*s", regp->name, i,
1.1 root 97: 12-strlen(regp->name)-((i<10)?1:2), "");
98: else
99: db_printf("%-12s", regp->name);
100: db_printf("%#*N", 2+2*sizeof(vm_offset_t), value);
1.1.1.2 root 101: db_find_xtrn_task_sym_and_offset((db_addr_t)value, &name,
1.1 root 102: &offset, task);
103: if (name != 0 && offset <= db_maxoff && offset != value) {
104: db_printf("\t%s", name);
105: if (offset != 0)
106: db_printf("+%#r", offset);
107: }
108: db_printf("\n");
109: }
110: }
111: }
112:
113: #define OPTION_LONG 0x001 /* long print option */
114: #define OPTION_USER 0x002 /* print ps-like stuff */
115: #define OPTION_INDENT 0x100 /* print with indent */
116: #define OPTION_THREAD_TITLE 0x200 /* print thread title */
117: #define OPTION_TASK_TITLE 0x400 /* print thread title */
118:
119: #ifndef DB_TASK_NAME
120: #define DB_TASK_NAME(task) /* no task name */
121: #define DB_TASK_NAME_TITLE "" /* no task name */
1.1.1.2 root 122: #endif /* DB_TASK_NAME */
1.1 root 123:
124: #ifndef db_thread_fp_used
125: #define db_thread_fp_used(thread) FALSE
126: #endif
127:
128: char *
129: db_thread_stat(thread, status)
130: register thread_t thread;
131: char *status;
132: {
133: register char *p = status;
1.1.1.2 root 134:
1.1 root 135: *p++ = (thread->state & TH_RUN) ? 'R' : '.';
136: *p++ = (thread->state & TH_WAIT) ? 'W' : '.';
137: *p++ = (thread->state & TH_SUSP) ? 'S' : '.';
138: *p++ = (thread->state & TH_SWAPPED) ? 'O' : '.';
139: *p++ = (thread->state & TH_UNINT) ? 'N' : '.';
140: /* show if the FPU has been used */
141: *p++ = db_thread_fp_used(thread) ? 'F' : '.';
142: *p++ = 0;
143: return(status);
144: }
145:
146: void
147: db_print_thread(thread, thread_id, flag)
148: thread_t thread;
149: int thread_id;
150: int flag;
151: {
152: if (flag & OPTION_USER) {
153: char status[8];
154: char *indent = "";
155:
156: if (flag & OPTION_LONG) {
157: if (flag & OPTION_INDENT)
158: indent = " ";
159: if (flag & OPTION_THREAD_TITLE) {
160: db_printf("%s ID: THREAD STAT STACK PCB", indent);
161: db_printf(" SUS PRI CONTINUE,WAIT_FUNC\n");
162: }
163: db_printf("%s%3d%c %0*X %s %0*X %0*X %3d %3d ",
164: indent, thread_id,
165: (thread == current_thread())? '#': ':',
166: 2*sizeof(vm_offset_t), thread,
167: db_thread_stat(thread, status),
168: 2*sizeof(vm_offset_t), thread->kernel_stack,
169: 2*sizeof(vm_offset_t), thread->pcb,
170: thread->suspend_count, thread->sched_pri);
171: if ((thread->state & TH_SWAPPED) && thread->swap_func) {
172: db_task_printsym((db_addr_t)thread->swap_func,
173: DB_STGY_ANY, kernel_task);
174: db_printf(", ");
175: }
176: if (thread->state & TH_WAIT)
177: db_task_printsym((db_addr_t)thread->wait_event,
178: DB_STGY_ANY, kernel_task);
179: db_printf("\n");
180: } else {
181: if (thread_id % 3 == 0) {
182: if (flag & OPTION_INDENT)
183: db_printf("\n ");
184: } else
185: db_printf(" ");
1.1.1.2 root 186: db_printf("%3d%c(%0*X,%s)", thread_id,
1.1 root 187: (thread == current_thread())? '#': ':',
188: 2*sizeof(vm_offset_t), thread,
189: db_thread_stat(thread, status));
190: }
191: } else {
192: if (flag & OPTION_INDENT)
193: db_printf(" %3d (%0*X) ", thread_id,
194: 2*sizeof(vm_offset_t), thread);
195: else
196: db_printf("(%0*X) ", 2*sizeof(vm_offset_t), thread);
197: db_printf("%c%c%c%c%c",
198: (thread->state & TH_RUN) ? 'R' : ' ',
199: (thread->state & TH_WAIT) ? 'W' : ' ',
200: (thread->state & TH_SUSP) ? 'S' : ' ',
201: (thread->state & TH_UNINT)? 'N' : ' ',
202: db_thread_fp_used(thread) ? 'F' : ' ');
203: if (thread->state & TH_SWAPPED) {
204: if (thread->swap_func) {
205: db_printf("(");
1.1.1.2 root 206: db_task_printsym((db_addr_t)thread->swap_func,
1.1 root 207: DB_STGY_ANY, kernel_task);
208: db_printf(")");
209: } else {
210: db_printf("(swapped)");
211: }
212: }
213: if (thread->state & TH_WAIT) {
214: db_printf(" ");
1.1.1.2 root 215: db_task_printsym((db_addr_t)thread->wait_event,
1.1 root 216: DB_STGY_ANY, kernel_task);
217: }
218: db_printf("\n");
219: }
220: }
221:
222: void
223: db_print_task(task, task_id, flag)
224: task_t task;
225: int task_id;
226: int flag;
227: {
228: thread_t thread;
229: int thread_id;
230:
231: if (flag & OPTION_USER) {
232: if (flag & OPTION_TASK_TITLE) {
1.1.1.2 root 233: db_printf(" ID: TASK MAP THD SUS PR %s",
1.1 root 234: DB_TASK_NAME_TITLE);
235: if ((flag & OPTION_LONG) == 0)
236: db_printf(" THREADS");
237: db_printf("\n");
238: }
239: db_printf("%3d: %0*X %0*X %3d %3d %2d ",
240: task_id, 2*sizeof(vm_offset_t), task,
241: 2*sizeof(vm_offset_t), task->map, task->thread_count,
242: task->suspend_count, task->priority);
243: DB_TASK_NAME(task);
244: if (flag & OPTION_LONG) {
245: if (flag & OPTION_TASK_TITLE)
246: flag |= OPTION_THREAD_TITLE;
247: db_printf("\n");
248: } else if (task->thread_count <= 1)
249: flag &= ~OPTION_INDENT;
250: thread_id = 0;
251: queue_iterate(&task->thread_list, thread, thread_t, thread_list) {
252: db_print_thread(thread, thread_id, flag);
253: flag &= ~OPTION_THREAD_TITLE;
254: thread_id++;
255: }
256: if ((flag & OPTION_LONG) == 0)
257: db_printf("\n");
258: } else {
259: if (flag & OPTION_TASK_TITLE)
260: db_printf(" TASK THREADS\n");
261: db_printf("%3d (%0*X): ", task_id, 2*sizeof(vm_offset_t), task);
262: if (task->thread_count == 0) {
263: db_printf("no threads\n");
264: } else {
265: if (task->thread_count > 1) {
266: db_printf("%d threads: \n", task->thread_count);
267: flag |= OPTION_INDENT;
268: } else
269: flag &= ~OPTION_INDENT;
270: thread_id = 0;
271: queue_iterate(&task->thread_list, thread,
272: thread_t, thread_list)
273: db_print_thread(thread, thread_id++, flag);
274: }
275: }
276: }
277:
278: /*ARGSUSED*/
279: void
280: db_show_all_threads(addr, have_addr, count, modif)
281: db_expr_t addr;
282: boolean_t have_addr;
283: db_expr_t count;
284: char * modif;
285: {
286: task_t task;
287: int task_id;
288: int flag;
289: processor_set_t pset;
290:
291: flag = OPTION_TASK_TITLE|OPTION_INDENT;
292: if (db_option(modif, 'u'))
293: flag |= OPTION_USER;
294: if (db_option(modif, 'l'))
295: flag |= OPTION_LONG;
296:
297: task_id = 0;
298: queue_iterate(&all_psets, pset, processor_set_t, all_psets) {
299: queue_iterate(&pset->tasks, task, task_t, pset_tasks) {
300: db_print_task(task, task_id, flag);
301: flag &= ~OPTION_TASK_TITLE;
302: task_id++;
303: }
304: }
305: }
306:
307: db_addr_t
308: db_task_from_space(
309: ipc_space_t space,
310: int *task_id)
311: {
312: task_t task;
313: int tid = 0;
314: processor_set_t pset;
315:
316: queue_iterate(&all_psets, pset, processor_set_t, all_psets) {
317: queue_iterate(&pset->tasks, task, task_t, pset_tasks) {
318: if (task->itk_space == space) {
319: *task_id = tid;
320: return (db_addr_t)task;
321: }
322: tid++;
323: }
324: }
325: *task_id = 0;
326: return (0);
327: }
328:
329: /*ARGSUSED*/
330: void
331: db_show_one_thread(addr, have_addr, count, modif)
332: db_expr_t addr;
333: boolean_t have_addr;
334: db_expr_t count;
335: char * modif;
336: {
337: int flag;
338: int thread_id;
339: thread_t thread;
340:
341: flag = OPTION_THREAD_TITLE;
342: if (db_option(modif, 'u'))
343: flag |= OPTION_USER;
344: if (db_option(modif, 'l'))
345: flag |= OPTION_LONG;
346:
347: if (!have_addr) {
348: thread = current_thread();
349: if (thread == THREAD_NULL) {
350: db_error("No thread\n");
351: /*NOTREACHED*/
352: }
353: } else
354: thread = (thread_t) addr;
355:
356: if ((thread_id = db_lookup_thread(thread)) < 0) {
357: db_printf("bad thread address %#X\n", addr);
358: db_error(0);
359: /*NOTREACHED*/
360: }
361:
362: if (flag & OPTION_USER) {
363: db_printf("TASK%d(%0*X):\n",
364: db_lookup_task(thread->task),
365: 2*sizeof(vm_offset_t), thread->task);
366: db_print_thread(thread, thread_id, flag);
367: } else {
368: db_printf("task %d(%0*X): thread %d",
369: db_lookup_task(thread->task),
370: 2*sizeof(vm_offset_t), thread->task, thread_id);
371: db_print_thread(thread, thread_id, flag);
372: }
373: }
374:
375: /*ARGSUSED*/
376: void
377: db_show_one_task(addr, have_addr, count, modif)
378: db_expr_t addr;
379: boolean_t have_addr;
380: db_expr_t count;
381: char * modif;
382: {
383: int flag;
384: int task_id;
385: task_t task;
386:
387: flag = OPTION_TASK_TITLE;
388: if (db_option(modif, 'u'))
389: flag |= OPTION_USER;
390: if (db_option(modif, 'l'))
391: flag |= OPTION_LONG;
392:
393: if (!have_addr) {
394: task = db_current_task();
395: if (task == TASK_NULL) {
396: db_error("No task\n");
397: /*NOTREACHED*/
398: }
399: } else
400: task = (task_t) addr;
401:
402: if ((task_id = db_lookup_task(task)) < 0) {
403: db_printf("bad task address %#X\n", addr);
404: db_error(0);
405: /*NOTREACHED*/
406: }
407:
408: db_print_task(task, task_id, flag);
409: }
410:
411: int
412: db_port_iterate(thread, func)
413: thread_t thread;
414: void (*func)();
415: {
416: ipc_entry_t entry;
417: int index;
418: int n = 0;
419: int size;
420: ipc_space_t space;
421:
422: space = thread->task->itk_space;
423: entry = space->is_table;
424: size = space->is_table_size;
425: for (index = 0; index < size; index++, entry++) {
426: if (entry->ie_bits & MACH_PORT_TYPE_PORT_RIGHTS)
427: (*func)(index, (ipc_port_t) entry->ie_object,
428: entry->ie_bits, n++);
429: }
430: return(n);
431: }
432:
433: ipc_port_t
434: db_lookup_port(thread, id)
435: thread_t thread;
436: int id;
437: {
438: register ipc_space_t space;
439: register ipc_entry_t entry;
440:
441: if (thread == THREAD_NULL)
442: return(0);
443: space = thread->task->itk_space;
444: if (id < 0 || id >= space->is_table_size)
445: return(0);
446: entry = &space->is_table[id];
447: if (entry->ie_bits & MACH_PORT_TYPE_PORT_RIGHTS)
448: return((ipc_port_t)entry->ie_object);
449: return(0);
450: }
451:
452: static void
453: db_print_port_id(id, port, bits, n)
454: int id;
455: ipc_port_t port;
456: unsigned bits;
457: int n;
458: {
459: if (n != 0 && n % 3 == 0)
460: db_printf("\n");
461: db_printf("\tport%d(%s,%x)", id,
462: (bits & MACH_PORT_TYPE_RECEIVE)? "r":
463: (bits & MACH_PORT_TYPE_SEND)? "s": "S", port);
464: }
465:
466: static void
467: db_print_port_id_long(
468: int id,
469: ipc_port_t port,
470: unsigned bits,
471: int n)
472: {
473: if (n != 0)
474: db_printf("\n");
475: db_printf("\tport%d(%s, port=0x%x", id,
476: (bits & MACH_PORT_TYPE_RECEIVE)? "r":
477: (bits & MACH_PORT_TYPE_SEND)? "s": "S", port);
478: db_printf(", receiver_name=0x%x)", port->ip_receiver_name);
479: }
480:
481: /* ARGSUSED */
482: void
483: db_show_port_id(addr, have_addr, count, modif)
484: db_expr_t addr;
485: boolean_t have_addr;
486: db_expr_t count;
487: char * modif;
488: {
489: thread_t thread;
490:
491: if (!have_addr) {
492: thread = current_thread();
493: if (thread == THREAD_NULL) {
494: db_error("No thread\n");
495: /*NOTREACHED*/
496: }
497: } else
498: thread = (thread_t) addr;
499: if (db_lookup_thread(thread) < 0) {
500: db_printf("Bad thread address %#X\n", addr);
501: db_error(0);
502: /*NOTREACHED*/
503: }
504: if (db_option(modif, 'l'))
505: {
506: if (db_port_iterate(thread, db_print_port_id_long))
507: db_printf("\n");
508: return;
509: }
510: if (db_port_iterate(thread, db_print_port_id))
511: db_printf("\n");
512: }
513:
1.1.1.2 root 514: #endif /* MACH_KDB */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.