FreeBSD/Linux Kernel Cross Reference
sys/ddb/db_print.c
1 /*
2 * Mach Operating System
3 * Copyright (c) 1991,1990 Carnegie Mellon University
4 * All Rights Reserved.
5 *
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.
11 *
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.
15 *
16 * Carnegie Mellon requests users of this software to return to
17 *
18 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
19 * School of Computer Science
20 * Carnegie Mellon University
21 * Pittsburgh PA 15213-3890
22 *
23 * any improvements or extensions that they make and grant Carnegie Mellon
24 * the rights to redistribute these changes.
25 */
26 /*
27 * HISTORY
28 * $Log: db_print.c,v $
29 * Revision 2.19 93/03/09 10:53:44 danner
30 * String protos.
31 * [93/03/07 af]
32 *
33 * Revision 2.18 93/01/14 17:25:33 danner
34 * 64bit cleanup.
35 * [92/11/30 af]
36 *
37 * Revision 2.17 92/08/05 18:02:39 jfriedl
38 * Removed silly prototypes.
39 *
40 * Revision 2.16 92/05/21 17:07:35 jfriedl
41 * Removed unused variable from db_show_regs().
42 * [92/05/16 jfriedl]
43 *
44 * Revision 2.15 92/05/04 11:24:08 danner
45 * Converted some db_printsyms to db_task_printsyms.
46 * [92/04/10 danner]
47 *
48 * Revision 2.14 92/04/01 19:31:37 rpd
49 * Changed db_print_thread so that both display formats
50 * show the floating-point-used status of the thread.
51 * [92/03/16 rpd]
52 *
53 * Revision 2.13 92/02/20 18:34:28 elf
54 * Fixed typo.
55 * [92/02/20 elf]
56 *
57 * Revision 2.12 92/02/19 15:07:47 elf
58 * Added db_thread_fp_used, to avoid machine-dependent conditionals.
59 * [92/02/19 rpd]
60 *
61 * Added 'F' flag to db_thread_stat showing if the thread has a valid
62 * FPU context. Tested on i386 and pmax.
63 * [92/02/17 kivinen]
64 *
65 * Revision 2.11 91/11/12 11:50:32 rvb
66 * Added OPTION_USER ("/u") to db_show_all_threads, db_show_one_thread,
67 * db_show_one_task. Without it, we display old-style information.
68 * [91/10/31 rpd]
69 *
70 * Revision 2.10 91/10/09 16:01:48 af
71 * Supported "show registers" for non current thread.
72 * Changed display format of thread and task information.
73 * Changed "show thread" to print current thread information
74 * if no thread is specified.
75 * Added "show_one_task" for "show task" command.
76 * Added IPC port print routines for "show ipc_port" command.
77 * [91/08/29 tak]
78 *
79 * Revision 2.9 91/08/03 18:17:19 jsb
80 * In db_print_thread, if the thread is swapped and there is a
81 * continuation function, print the function name in parentheses
82 * instead of '(swapped)'.
83 * [91/07/04 09:59:27 jsb]
84 *
85 * Revision 2.8 91/07/31 17:30:43 dbg
86 * Revise scheduling state machine.
87 * [91/07/30 16:43:42 dbg]
88 *
89 * Revision 2.7 91/07/09 23:15:57 danner
90 * Fixed a few printf that should be db_printfs.
91 * [91/07/08 danner]
92 *
93 * Revision 2.6 91/05/14 15:35:25 mrt
94 * Correcting copyright
95 *
96 * Revision 2.5 91/02/05 17:06:53 mrt
97 * Changed to new Mach copyright
98 * [91/01/31 16:18:56 mrt]
99 *
100 * Revision 2.4 90/10/25 14:43:54 rwd
101 * Changed db_show_regs to print unsigned.
102 * [90/10/19 rpd]
103 * Generalized the watchpoint support.
104 * [90/10/16 rwd]
105 *
106 * Revision 2.3 90/09/09 23:19:52 rpd
107 * Avoid totally incorrect guesses of symbol names for small values.
108 * [90/08/30 17:39:08 af]
109 *
110 * Revision 2.2 90/08/27 21:51:49 dbg
111 * Insist that 'show thread' be called with an explicit address.
112 * [90/08/22 dbg]
113 *
114 * Fix type for db_maxoff.
115 * [90/08/20 dbg]
116 *
117 * Do not dereference the "valuep" field of a variable directly,
118 * call the new db_read/write_variable functions instead.
119 * Reflected changes in symbol lookup functions.
120 * [90/08/20 af]
121 * Reduce lint.
122 * [90/08/10 14:33:44 dbg]
123 *
124 * Created.
125 * [90/07/25 dbg]
126 *
127 */
128 /*
129 * Author: David B. Golub, Carnegie Mellon University
130 * Date: 7/90
131 */
132
133 /*
134 * Miscellaneous printing.
135 */
136 #include <mach/port.h>
137 #include <kern/strings.h>
138 #include <kern/task.h>
139 #include <kern/thread.h>
140 #include <kern/queue.h>
141 #include <ipc/ipc_port.h>
142 #include <ipc/ipc_space.h>
143
144 #include <machine/db_machdep.h>
145 #include <machine/thread.h>
146
147 #include <ddb/db_lex.h>
148 #include <ddb/db_variables.h>
149 #include <ddb/db_sym.h>
150 #include <ddb/db_task_thread.h>
151
152 extern unsigned int db_maxoff;
153
154 /* ARGSUSED */
155 void
156 db_show_regs(addr, have_addr, count, modif)
157 db_expr_t addr;
158 boolean_t have_addr;
159 db_expr_t count;
160 char *modif;
161 {
162 register struct db_variable *regp;
163 db_expr_t value;
164 db_addr_t offset;
165 char * name;
166 register i;
167 struct db_var_aux_param aux_param;
168 task_t task = TASK_NULL;
169
170 aux_param.modif = modif;
171 aux_param.thread = THREAD_NULL;
172 if (db_option(modif, 't')) {
173 if (have_addr) {
174 if (!db_check_thread_address_valid((thread_t)addr))
175 return;
176 aux_param.thread = (thread_t)addr;
177 } else
178 aux_param.thread = db_default_thread;
179 if (aux_param.thread != THREAD_NULL)
180 task = aux_param.thread->task;
181 }
182 for (regp = db_regs; regp < db_eregs; regp++) {
183 if (regp->max_level > 1) {
184 db_printf("bad multi-suffixed register %s\n", regp->name);
185 continue;
186 }
187 aux_param.level = regp->max_level;
188 for (i = regp->low; i <= regp->high; i++) {
189 aux_param.suffix[0] = i;
190 db_read_write_variable(regp, &value, DB_VAR_GET, &aux_param);
191 if (regp->max_level > 0)
192 db_printf("%s%d%*s", regp->name, i,
193 12-strlen(regp->name)-((i<10)?1:2), "");
194 else
195 db_printf("%-12s", regp->name);
196 db_printf("%#*N", 2+2*sizeof(vm_offset_t), value);
197 db_find_xtrn_task_sym_and_offset((db_addr_t)value, &name,
198 &offset, task);
199 if (name != 0 && offset <= db_maxoff && offset != value) {
200 db_printf("\t%s", name);
201 if (offset != 0)
202 db_printf("+%#r", offset);
203 }
204 db_printf("\n");
205 }
206 }
207 }
208
209 #define OPTION_LONG 0x001 /* long print option */
210 #define OPTION_USER 0x002 /* print ps-like stuff */
211 #define OPTION_INDENT 0x100 /* print with indent */
212 #define OPTION_THREAD_TITLE 0x200 /* print thread title */
213 #define OPTION_TASK_TITLE 0x400 /* print thread title */
214
215 #ifndef DB_TASK_NAME
216 #define DB_TASK_NAME(task) /* no task name */
217 #define DB_TASK_NAME_TITLE "" /* no task name */
218 #endif DB_TASK_NAME
219
220 #ifndef db_thread_fp_used
221 #define db_thread_fp_used(thread) FALSE
222 #endif
223
224 char *
225 db_thread_stat(thread, status)
226 register thread_t thread;
227 char *status;
228 {
229 register char *p = status;
230
231 *p++ = (thread->state & TH_RUN) ? 'R' : '.';
232 *p++ = (thread->state & TH_WAIT) ? 'W' : '.';
233 *p++ = (thread->state & TH_SUSP) ? 'S' : '.';
234 *p++ = (thread->state & TH_SWAPPED) ? 'O' : '.';
235 *p++ = (thread->state & TH_UNINT) ? 'N' : '.';
236 /* show if the FPU has been used */
237 *p++ = db_thread_fp_used(thread) ? 'F' : '.';
238 *p++ = 0;
239 return(status);
240 }
241
242 void
243 db_print_thread(thread, thread_id, flag)
244 thread_t thread;
245 int thread_id;
246 int flag;
247 {
248 if (flag & OPTION_USER) {
249 char status[8];
250 char *indent = "";
251
252 if (flag & OPTION_LONG) {
253 if (flag & OPTION_INDENT)
254 indent = " ";
255 if (flag & OPTION_THREAD_TITLE) {
256 db_printf("%s ID: THREAD STAT STACK PCB", indent);
257 db_printf(" SUS PRI CONTINUE,WAIT_FUNC\n");
258 }
259 db_printf("%s%3d%c %0*X %s %0*X %0*X %3d %3d ",
260 indent, thread_id,
261 (thread == current_thread())? '#': ':',
262 2*sizeof(vm_offset_t), thread,
263 db_thread_stat(thread, status),
264 2*sizeof(vm_offset_t), thread->kernel_stack,
265 2*sizeof(vm_offset_t), thread->pcb,
266 thread->suspend_count, thread->sched_pri);
267 if ((thread->state & TH_SWAPPED) && thread->swap_func) {
268 db_task_printsym((db_addr_t)thread->swap_func,
269 DB_STGY_ANY, kernel_task);
270 db_printf(", ");
271 }
272 if (thread->state & TH_WAIT)
273 db_task_printsym((db_addr_t)thread->wait_event,
274 DB_STGY_ANY, kernel_task);
275 db_printf("\n");
276 } else {
277 if (thread_id % 3 == 0) {
278 if (flag & OPTION_INDENT)
279 db_printf("\n ");
280 } else
281 db_printf(" ");
282 db_printf("%3d%c(%0*X,%s)", thread_id,
283 (thread == current_thread())? '#': ':',
284 2*sizeof(vm_offset_t), thread,
285 db_thread_stat(thread, status));
286 }
287 } else {
288 if (flag & OPTION_INDENT)
289 db_printf(" %3d (%0*X) ", thread_id,
290 2*sizeof(vm_offset_t), thread);
291 else
292 db_printf("(%0*X) ", 2*sizeof(vm_offset_t), thread);
293 db_printf("%c%c%c%c%c",
294 (thread->state & TH_RUN) ? 'R' : ' ',
295 (thread->state & TH_WAIT) ? 'W' : ' ',
296 (thread->state & TH_SUSP) ? 'S' : ' ',
297 (thread->state & TH_UNINT)? 'N' : ' ',
298 db_thread_fp_used(thread) ? 'F' : ' ');
299 if (thread->state & TH_SWAPPED) {
300 if (thread->swap_func) {
301 db_printf("(");
302 db_task_printsym((db_addr_t)thread->swap_func,
303 DB_STGY_ANY, kernel_task);
304 db_printf(")");
305 } else {
306 db_printf("(swapped)");
307 }
308 }
309 if (thread->state & TH_WAIT) {
310 db_printf(" ");
311 db_task_printsym((db_addr_t)thread->wait_event,
312 DB_STGY_ANY, kernel_task);
313 }
314 db_printf("\n");
315 }
316 }
317
318 void
319 db_print_task(task, task_id, flag)
320 task_t task;
321 int task_id;
322 int flag;
323 {
324 thread_t thread;
325 int thread_id;
326
327 if (flag & OPTION_USER) {
328 if (flag & OPTION_TASK_TITLE) {
329 db_printf(" ID: TASK MAP THD SUS PR %s",
330 DB_TASK_NAME_TITLE);
331 if ((flag & OPTION_LONG) == 0)
332 db_printf(" THREADS");
333 db_printf("\n");
334 }
335 db_printf("%3d: %0*X %0*X %3d %3d %2d ",
336 task_id, 2*sizeof(vm_offset_t), task,
337 2*sizeof(vm_offset_t), task->map, task->thread_count,
338 task->suspend_count, task->priority);
339 DB_TASK_NAME(task);
340 if (flag & OPTION_LONG) {
341 if (flag & OPTION_TASK_TITLE)
342 flag |= OPTION_THREAD_TITLE;
343 db_printf("\n");
344 } else if (task->thread_count <= 1)
345 flag &= ~OPTION_INDENT;
346 thread_id = 0;
347 queue_iterate(&task->thread_list, thread, thread_t, thread_list) {
348 db_print_thread(thread, thread_id, flag);
349 flag &= ~OPTION_THREAD_TITLE;
350 thread_id++;
351 }
352 if ((flag & OPTION_LONG) == 0)
353 db_printf("\n");
354 } else {
355 if (flag & OPTION_TASK_TITLE)
356 db_printf(" TASK THREADS\n");
357 db_printf("%3d (%0*X): ", task_id, 2*sizeof(vm_offset_t), task);
358 if (task->thread_count == 0) {
359 db_printf("no threads\n");
360 } else {
361 if (task->thread_count > 1) {
362 db_printf("%d threads: \n", task->thread_count);
363 flag |= OPTION_INDENT;
364 } else
365 flag &= ~OPTION_INDENT;
366 thread_id = 0;
367 queue_iterate(&task->thread_list, thread,
368 thread_t, thread_list)
369 db_print_thread(thread, thread_id++, flag);
370 }
371 }
372 }
373
374 /*ARGSUSED*/
375 void
376 db_show_all_threads(addr, have_addr, count, modif)
377 db_expr_t addr;
378 boolean_t have_addr;
379 db_expr_t count;
380 char * modif;
381 {
382 task_t task;
383 int task_id;
384 int flag;
385 processor_set_t pset;
386
387 flag = OPTION_TASK_TITLE|OPTION_INDENT;
388 if (db_option(modif, 'u'))
389 flag |= OPTION_USER;
390 if (db_option(modif, 'l'))
391 flag |= OPTION_LONG;
392
393 task_id = 0;
394 queue_iterate(&all_psets, pset, processor_set_t, all_psets) {
395 queue_iterate(&pset->tasks, task, task_t, pset_tasks) {
396 db_print_task(task, task_id, flag);
397 flag &= ~OPTION_TASK_TITLE;
398 task_id++;
399 }
400 }
401 }
402
403 /*ARGSUSED*/
404 void
405 db_show_one_thread(addr, have_addr, count, modif)
406 db_expr_t addr;
407 boolean_t have_addr;
408 db_expr_t count;
409 char * modif;
410 {
411 int flag;
412 int thread_id;
413 thread_t thread;
414
415 flag = OPTION_THREAD_TITLE;
416 if (db_option(modif, 'u'))
417 flag |= OPTION_USER;
418 if (db_option(modif, 'l'))
419 flag |= OPTION_LONG;
420
421 if (!have_addr) {
422 thread = current_thread();
423 if (thread == THREAD_NULL) {
424 db_error("No thread\n");
425 /*NOTREACHED*/
426 }
427 } else
428 thread = (thread_t) addr;
429
430 if ((thread_id = db_lookup_thread(thread)) < 0) {
431 db_printf("bad thread address %#X\n", addr);
432 db_error(0);
433 /*NOTREACHED*/
434 }
435
436 if (flag & OPTION_USER) {
437 db_printf("TASK%d(%0*X):\n",
438 db_lookup_task(thread->task),
439 2*sizeof(vm_offset_t), thread->task);
440 db_print_thread(thread, thread_id, flag);
441 } else {
442 db_printf("task %d(%0*X): thread %d",
443 db_lookup_task(thread->task),
444 2*sizeof(vm_offset_t), thread->task, thread_id);
445 db_print_thread(thread, thread_id, flag);
446 }
447 }
448
449 /*ARGSUSED*/
450 void
451 db_show_one_task(addr, have_addr, count, modif)
452 db_expr_t addr;
453 boolean_t have_addr;
454 db_expr_t count;
455 char * modif;
456 {
457 int flag;
458 int task_id;
459 task_t task;
460
461 flag = OPTION_TASK_TITLE;
462 if (db_option(modif, 'u'))
463 flag |= OPTION_USER;
464 if (db_option(modif, 'l'))
465 flag |= OPTION_LONG;
466
467 if (!have_addr) {
468 task = db_current_task();
469 if (task == TASK_NULL) {
470 db_error("No task\n");
471 /*NOTREACHED*/
472 }
473 } else
474 task = (task_t) addr;
475
476 if ((task_id = db_lookup_task(task)) < 0) {
477 db_printf("bad task address %#X\n", addr);
478 db_error(0);
479 /*NOTREACHED*/
480 }
481
482 db_print_task(task, task_id, flag);
483 }
484
485 int
486 db_port_iterate(thread, func)
487 thread_t thread;
488 void (*func)();
489 {
490 ipc_entry_t entry;
491 int index;
492 int n = 0;
493 int size;
494 ipc_space_t space;
495
496 space = thread->task->itk_space;
497 entry = space->is_table;
498 size = space->is_table_size;
499 for (index = 0; index < size; index++, entry++) {
500 if (entry->ie_bits & MACH_PORT_TYPE_PORT_RIGHTS)
501 (*func)(index, (ipc_port_t) entry->ie_object,
502 entry->ie_bits, n++);
503 }
504 return(n);
505 }
506
507 ipc_port_t
508 db_lookup_port(thread, id)
509 thread_t thread;
510 int id;
511 {
512 register ipc_space_t space;
513 register ipc_entry_t entry;
514
515 if (thread == THREAD_NULL)
516 return(0);
517 space = thread->task->itk_space;
518 if (id < 0 || id >= space->is_table_size)
519 return(0);
520 entry = &space->is_table[id];
521 if (entry->ie_bits & MACH_PORT_TYPE_PORT_RIGHTS)
522 return((ipc_port_t)entry->ie_object);
523 return(0);
524 }
525
526 static void
527 db_print_port_id(id, port, bits, n)
528 int id;
529 ipc_port_t port;
530 unsigned bits;
531 int n;
532 {
533 if (n != 0 && n % 3 == 0)
534 db_printf("\n");
535 db_printf("\tport%d(%s,%x)", id,
536 (bits & MACH_PORT_TYPE_RECEIVE)? "r":
537 (bits & MACH_PORT_TYPE_SEND)? "s": "S", port);
538 }
539
540 /* ARGSUSED */
541 void
542 db_show_port_id(addr, have_addr, count, modif)
543 db_expr_t addr;
544 boolean_t have_addr;
545 db_expr_t count;
546 char * modif;
547 {
548 thread_t thread;
549
550 if (!have_addr) {
551 thread = current_thread();
552 if (thread == THREAD_NULL) {
553 db_error("No thread\n");
554 /*NOTREACHED*/
555 }
556 } else
557 thread = (thread_t) addr;
558 if (db_lookup_thread(thread) < 0) {
559 db_printf("Bad thread address %#X\n", addr);
560 db_error(0);
561 /*NOTREACHED*/
562 }
563 if (db_port_iterate(thread, db_print_port_id))
564 db_printf("\n");
565 }
Cache object: 440fd43c4294701d0ad7502cd23f49b2
|