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