]> git.saurik.com Git - apple/xnu.git/blob - osfmk/i386/db_trace.c
xnu-792.10.96.tar.gz
[apple/xnu.git] / osfmk / i386 / db_trace.c
1 /*
2 * Copyright (c) 2000-2005 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 * Mach Operating System
27 * Copyright (c) 1991,1990 Carnegie Mellon University
28 * All Rights Reserved.
29 *
30 * Permission to use, copy, modify and distribute this software and its
31 * documentation is hereby granted, provided that both the copyright
32 * notice and this permission notice appear in all copies of the
33 * software, derivative works or modified versions, and any portions
34 * thereof, and that both notices appear in supporting documentation.
35 *
36 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
37 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
38 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
39 *
40 * Carnegie Mellon requests users of this software to return to
41 *
42 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
43 * School of Computer Science
44 * Carnegie Mellon University
45 * Pittsburgh PA 15213-3890
46 *
47 * any improvements or extensions that they make and grant Carnegie Mellon
48 * the rights to redistribute these changes.
49 */
50 /*
51 */
52
53 #include <string.h>
54
55 #include <mach/boolean.h>
56 #include <vm/vm_map.h>
57 #include <kern/thread.h>
58 #include <kern/task.h>
59
60 #include <machine/asm.h>
61 #include <machine/db_machdep.h>
62 #include <machine/setjmp.h>
63 #include <mach/machine.h>
64 #include <mach/kmod.h>
65
66 #include <i386/mp.h>
67 #include <i386/pio.h>
68 #include <i386/cpuid.h>
69 #include <i386/proc_reg.h>
70 #include <i386/machine_routines.h>
71
72 #include <ddb/db_access.h>
73 #include <ddb/db_sym.h>
74 #include <ddb/db_variables.h>
75 #include <ddb/db_command.h>
76 #include <ddb/db_task_thread.h>
77 #include <ddb/db_output.h>
78
79 extern jmp_buf_t *db_recover;
80 struct x86_kernel_state32 ddb_null_kregs;
81 extern kmod_info_t *kmod;
82
83
84 /*
85 * Stack trace.
86 */
87
88 #define INKERNELSTACK(va, th) 1
89
90 #define DB_NUMARGS_MAX 5
91
92 struct i386_frame {
93 struct i386_frame *f_frame;
94 int f_retaddr;
95 int f_arg0;
96 };
97
98 #define TRAP 1
99 #define INTERRUPT 2
100 #define SYSCALL 3
101
102 db_addr_t db_user_trap_symbol_value = 0;
103 db_addr_t db_kernel_trap_symbol_value = 0;
104 db_addr_t db_interrupt_symbol_value = 0;
105 db_addr_t db_return_to_iret_symbol_value = 0;
106 db_addr_t db_syscall_symbol_value = 0;
107 boolean_t db_trace_symbols_found = FALSE;
108
109 struct i386_kregs {
110 char *name;
111 unsigned int offset;
112 } i386_kregs[] = {
113 { "ebx", (unsigned int)(&((struct x86_kernel_state32 *)0)->k_ebx) },
114 { "esp", (unsigned int)(&((struct x86_kernel_state32 *)0)->k_esp) },
115 { "ebp", (unsigned int)(&((struct x86_kernel_state32 *)0)->k_ebp) },
116 { "edi", (unsigned int)(&((struct x86_kernel_state32 *)0)->k_edi) },
117 { "esi", (unsigned int)(&((struct x86_kernel_state32 *)0)->k_esi) },
118 { "eip", (unsigned int)(&((struct x86_kernel_state32 *)0)->k_eip) },
119 { 0 }
120 };
121
122 /* Forward */
123
124 extern unsigned int * db_lookup_i386_kreg(
125 char *name,
126 int *kregp);
127 extern int db_i386_reg_value(
128 struct db_variable * vp,
129 db_expr_t * val,
130 int flag,
131 db_var_aux_param_t ap);
132 extern void db_find_trace_symbols(void);
133 extern int db_numargs(
134 struct i386_frame *fp,
135 task_t task);
136 extern void db_nextframe(
137 struct i386_frame **lfp,
138 struct i386_frame **fp,
139 db_addr_t *ip,
140 int frame_type,
141 thread_t thr_act);
142 extern int _setjmp(
143 jmp_buf_t * jb);
144
145 /*
146 * Machine register set.
147 */
148 struct db_variable db_regs[] = {
149 { "cs", (unsigned int *)&ddb_regs.cs, db_i386_reg_value, 0, 0, 0, 0, TRUE, 0, 0, (int *)0, 0 },
150 { "ds", (unsigned int *)&ddb_regs.ds, db_i386_reg_value, 0, 0, 0, 0, TRUE, 0, 0, (int *)0, 0 },
151 { "es", (unsigned int *)&ddb_regs.es, db_i386_reg_value, 0, 0, 0, 0, TRUE, 0, 0, (int *)0, 0 },
152 { "fs", (unsigned int *)&ddb_regs.fs, db_i386_reg_value, 0, 0, 0, 0, TRUE, 0, 0, (int *)0, 0 },
153 { "gs", (unsigned int *)&ddb_regs.gs, db_i386_reg_value, 0, 0, 0, 0, TRUE, 0, 0, (int *)0, 0 },
154 { "ss", (unsigned int *)&ddb_regs.ss, db_i386_reg_value, 0, 0, 0, 0, TRUE, 0, 0, (int *)0, 0 },
155 { "eax",(unsigned int *)&ddb_regs.eax, db_i386_reg_value, 0, 0, 0, 0, TRUE, 0, 0, (int *)0, 0 },
156 { "ecx",(unsigned int *)&ddb_regs.ecx, db_i386_reg_value, 0, 0, 0, 0, TRUE, 0, 0, (int *)0, 0 },
157 { "edx",(unsigned int *)&ddb_regs.edx, db_i386_reg_value, 0, 0, 0, 0, TRUE, 0, 0, (int *)0, 0 },
158 { "ebx",(unsigned int *)&ddb_regs.ebx, db_i386_reg_value, 0, 0, 0, 0, TRUE, 0, 0, (int *)0, 0 },
159 { "esp",(unsigned int *)&ddb_regs.uesp,db_i386_reg_value, 0, 0, 0, 0, TRUE, 0, 0, (int *)0, 0 },
160 { "ebp",(unsigned int *)&ddb_regs.ebp, db_i386_reg_value, 0, 0, 0, 0, TRUE, 0, 0, (int *)0, 0 },
161 { "esi",(unsigned int *)&ddb_regs.esi, db_i386_reg_value, 0, 0, 0, 0, TRUE, 0, 0, (int *)0, 0 },
162 { "edi",(unsigned int *)&ddb_regs.edi, db_i386_reg_value, 0, 0, 0, 0, TRUE, 0, 0, (int *)0, 0 },
163 { "eip",(unsigned int *)&ddb_regs.eip, db_i386_reg_value, 0, 0, 0, 0, TRUE, 0, 0, (int *)0, 0 },
164 { "efl",(unsigned int *)&ddb_regs.efl, db_i386_reg_value, 0, 0, 0, 0, TRUE, 0, 0, (int *)0, 0 }
165 };
166 struct db_variable *db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
167
168 unsigned int *
169 db_lookup_i386_kreg(
170 char *name,
171 int *kregp)
172 {
173 register struct i386_kregs *kp;
174
175 for (kp = i386_kregs; kp->name; kp++) {
176 if (strcmp(name, kp->name) == 0)
177 return((unsigned int *)((int)kregp + kp->offset));
178 }
179 return(0);
180 }
181
182 int
183 db_i386_reg_value(
184 struct db_variable *vp,
185 db_expr_t *valuep,
186 int flag,
187 db_var_aux_param_t ap)
188 {
189 extern char etext;
190 unsigned int *dp = 0;
191 db_expr_t null_reg = 0;
192 register thread_t thr_act = ap->thr_act;
193
194 if (db_option(ap->modif, 'u')) {
195 if (thr_act == THREAD_NULL) {
196 if ((thr_act = current_thread()) == THREAD_NULL)
197 db_error("no user registers\n");
198 }
199 if (thr_act == current_thread()) {
200 if (IS_USER_TRAP(&ddb_regs, &etext))
201 dp = vp->valuep;
202 }
203 } else {
204 if (thr_act == THREAD_NULL || thr_act == current_thread()) {
205 dp = vp->valuep;
206 } else {
207 if (thr_act &&
208 (thr_act->continuation != THREAD_CONTINUE_NULL) &&
209 thr_act->kernel_stack) {
210 int cpu;
211
212 for (cpu = 0; cpu < real_ncpus; cpu++) {
213 if (cpu_datap(cpu)->cpu_running == TRUE &&
214 cpu_datap(cpu)->cpu_active_thread == thr_act && cpu_datap(cpu)->cpu_kdb_saved_state) {
215 dp = (unsigned int *) (((unsigned int)cpu_datap(cpu)->cpu_kdb_saved_state) +
216 (((unsigned int) vp->valuep) -
217 (unsigned int) &ddb_regs));
218 break;
219 }
220 }
221 if (dp == 0 && thr_act)
222 dp = db_lookup_i386_kreg(vp->name,
223 (unsigned int *)(STACK_IKS(thr_act->kernel_stack)));
224 if (dp == 0)
225 dp = &null_reg;
226 } else if (thr_act &&
227 (thr_act->continuation != THREAD_CONTINUE_NULL)) {
228 /* only EIP is valid */
229 if (vp->valuep == (unsigned int *) &ddb_regs.eip) {
230 dp = (unsigned int *)(&thr_act->continuation);
231 } else {
232 dp = &null_reg;
233 }
234 }
235 }
236 }
237 if (dp == 0) {
238 int cpu;
239
240 if (!db_option(ap->modif, 'u')) {
241 for (cpu = 0; cpu < real_ncpus; cpu++) {
242 if (cpu_datap(cpu)->cpu_running == TRUE &&
243 cpu_datap(cpu)->cpu_active_thread == thr_act && cpu_datap(cpu)->cpu_kdb_saved_state) {
244 dp = (unsigned int *) (((unsigned int)cpu_datap(cpu)->cpu_kdb_saved_state) +
245 (((unsigned int) vp->valuep) -
246 (unsigned int) &ddb_regs));
247 break;
248 }
249 }
250 }
251 if (dp == 0) {
252 if (!thr_act || thr_act->machine.pcb == 0)
253 db_error("no pcb\n");
254 dp = (unsigned int *)((unsigned int)(thr_act->machine.pcb->iss) +
255 ((unsigned int)vp->valuep - (unsigned int)&ddb_regs));
256 }
257 }
258 if (flag == DB_VAR_SET)
259 *dp = *valuep;
260 else
261 *valuep = *dp;
262 return(0);
263 }
264
265 void
266 db_find_trace_symbols(void)
267 {
268 db_expr_t value;
269 boolean_t found_some;
270
271 found_some = FALSE;
272 if (db_value_of_name(CC_SYM_PREFIX "user_trap", &value)) {
273 db_user_trap_symbol_value = (db_addr_t) value;
274 found_some = TRUE;
275 }
276 if (db_value_of_name(CC_SYM_PREFIX "kernel_trap", &value)) {
277 db_kernel_trap_symbol_value = (db_addr_t) value;
278 found_some = TRUE;
279 }
280 if (db_value_of_name(CC_SYM_PREFIX "interrupt", &value)) {
281 db_interrupt_symbol_value = (db_addr_t) value;
282 found_some = TRUE;
283 }
284 if (db_value_of_name(CC_SYM_PREFIX "return_to_iret", &value)) {
285 db_return_to_iret_symbol_value = (db_addr_t) value;
286 found_some = TRUE;
287 }
288 if (db_value_of_name(CC_SYM_PREFIX "syscall", &value)) {
289 db_syscall_symbol_value = (db_addr_t) value;
290 found_some = TRUE;
291 }
292 if (found_some)
293 db_trace_symbols_found = TRUE;
294 }
295
296 /*
297 * Figure out how many arguments were passed into the frame at "fp".
298 */
299 int db_numargs_default = 5;
300
301 int
302 db_numargs(
303 struct i386_frame *fp,
304 task_t task)
305 {
306 int *argp;
307 int inst;
308 int args;
309 extern char etext;
310
311 argp = (int *)db_get_task_value((int)&fp->f_retaddr, 4, FALSE, task);
312 if (argp < (int *)VM_MIN_KERNEL_ADDRESS || (char *)argp > &etext)
313 args = db_numargs_default;
314 else if (!DB_CHECK_ACCESS((int)argp, 4, task))
315 args = db_numargs_default;
316 else {
317 inst = db_get_task_value((int)argp, 4, FALSE, task);
318 if ((inst & 0xff) == 0x59) /* popl %ecx */
319 args = 1;
320 else if ((inst & 0xffff) == 0xc483) /* addl %n, %esp */
321 args = ((inst >> 16) & 0xff) / 4;
322 else
323 args = db_numargs_default;
324 }
325 return (args);
326 }
327
328 struct interrupt_frame {
329 struct i386_frame *if_frame; /* point to next frame */
330 int if_retaddr; /* return address to _interrupt */
331 int if_unit; /* unit number */
332 int if_spl; /* saved spl */
333 int if_iretaddr; /* _return_to_{iret,iret_i} */
334 int if_edx; /* old sp(iret) or saved edx(iret_i) */
335 int if_ecx; /* saved ecx(iret_i) */
336 int if_eax; /* saved eax(iret_i) */
337 int if_eip; /* saved eip(iret_i) */
338 int if_cs; /* saved cs(iret_i) */
339 int if_efl; /* saved efl(iret_i) */
340 };
341
342 /*
343 * Figure out the next frame up in the call stack.
344 * For trap(), we print the address of the faulting instruction and
345 * proceed with the calling frame. We return the ip that faulted.
346 * If the trap was caused by jumping through a bogus pointer, then
347 * the next line in the backtrace will list some random function as
348 * being called. It should get the argument list correct, though.
349 * It might be possible to dig out from the next frame up the name
350 * of the function that faulted, but that could get hairy.
351 */
352 void
353 db_nextframe(
354 struct i386_frame **lfp, /* in/out */
355 struct i386_frame **fp, /* in/out */
356 db_addr_t *ip, /* out */
357 int frame_type, /* in */
358 thread_t thr_act) /* in */
359 {
360 x86_saved_state32_t *iss32;
361 extern char * trap_type[];
362 extern int TRAP_TYPES;
363
364 struct interrupt_frame *ifp;
365 task_t task = (thr_act != THREAD_NULL)? thr_act->task: TASK_NULL;
366
367 switch(frame_type) {
368 case TRAP:
369 /*
370 * We know that trap() has 1 argument and we know that
371 * it is an (x86_saved_state32_t *).
372 */
373 iss32 = (x86_saved_state32_t *)
374 db_get_task_value((int)&((*fp)->f_arg0),4,FALSE,task);
375
376 if (iss32->trapno >= 0 && iss32->trapno < TRAP_TYPES) {
377 db_printf(">>>>> %s trap at ",
378 trap_type[iss32->trapno]);
379 } else {
380 db_printf(">>>>> trap (number %d) at ",
381 iss32->trapno & 0xffff);
382 }
383 db_task_printsym(iss32->eip, DB_STGY_PROC, task);
384 db_printf(" <<<<<\n");
385 *fp = (struct i386_frame *)iss32->ebp;
386 *ip = (db_addr_t)iss32->eip;
387 break;
388 case INTERRUPT:
389 if (*lfp == 0) {
390 db_printf(">>>>> interrupt <<<<<\n");
391 goto miss_frame;
392 }
393 db_printf(">>>>> interrupt at ");
394 ifp = (struct interrupt_frame *)(*lfp);
395 *fp = ifp->if_frame;
396 if (ifp->if_iretaddr == db_return_to_iret_symbol_value) {
397 *ip = ((x86_saved_state32_t *) ifp->if_edx)->eip;
398 } else
399 *ip = (db_addr_t) ifp->if_eip;
400 db_task_printsym(*ip, DB_STGY_PROC, task);
401 db_printf(" <<<<<\n");
402 break;
403 case SYSCALL:
404 if (thr_act != THREAD_NULL && thr_act->machine.pcb) {
405 iss32 = (x86_saved_state32_t *)thr_act->machine.pcb->iss;
406
407 *ip = (db_addr_t)(iss32->eip);
408 *fp = (struct i386_frame *)(iss32->ebp);
409 }
410 break;
411 /* falling down for unknown case */
412 default:
413 miss_frame:
414 *ip = (db_addr_t)
415 db_get_task_value((int)&(*fp)->f_retaddr, 4, FALSE, task);
416 *lfp = *fp;
417 *fp = (struct i386_frame *)
418 db_get_task_value((int)&(*fp)->f_frame, 4, FALSE, task);
419 break;
420 }
421 }
422
423 void
424 db_stack_trace_cmd(
425 db_expr_t addr,
426 boolean_t have_addr,
427 db_expr_t count,
428 char *modif)
429 {
430 struct i386_frame *frame, *lastframe;
431 x86_saved_state32_t *iss32;
432 int *argp;
433 db_addr_t callpc, lastcallpc;
434 int frame_type;
435 boolean_t kernel_only = TRUE;
436 boolean_t trace_thread = FALSE;
437 boolean_t trace_all_threads = FALSE;
438 int thcount = 0;
439 char *filename;
440 int linenum;
441 task_t task;
442 thread_t th, top_act;
443 int user_frame;
444 int frame_count;
445 jmp_buf_t *prev;
446 jmp_buf_t db_jmp_buf;
447 queue_entry_t act_list;
448
449 if (!db_trace_symbols_found)
450 db_find_trace_symbols();
451
452 {
453 register char *cp = modif;
454 register char c;
455
456 while ((c = *cp++) != 0) {
457 if (c == 't')
458 trace_thread = TRUE;
459 if (c == 'T') {
460 trace_all_threads = TRUE;
461 trace_thread = TRUE;
462 }
463 if (c == 'u')
464 kernel_only = FALSE;
465 }
466 }
467
468 if (trace_all_threads) {
469 if (!have_addr && !trace_thread) {
470 have_addr = TRUE;
471 trace_thread = TRUE;
472 act_list = &(current_task()->threads);
473 addr = (db_expr_t) queue_first(act_list);
474 } else if (trace_thread) {
475 if (have_addr) {
476 if (!db_check_act_address_valid((thread_t)addr)) {
477 if (db_lookup_task((task_t)addr) == -1)
478 return;
479 act_list = &(((task_t)addr)->threads);
480 addr = (db_expr_t) queue_first(act_list);
481 } else {
482 act_list = &(((thread_t)addr)->task->threads);
483 thcount = db_lookup_task_act(((thread_t)addr)->task,
484 (thread_t)addr);
485 }
486 } else {
487 th = db_default_act;
488 if (th == THREAD_NULL)
489 th = current_thread();
490 if (th == THREAD_NULL) {
491 db_printf("no active thr_act\n");
492 return;
493 }
494 have_addr = TRUE;
495 act_list = &th->task->threads;
496 addr = (db_expr_t) queue_first(act_list);
497 }
498 }
499 }
500
501 if (count == -1)
502 count = 65535;
503
504 next_thread:
505 top_act = THREAD_NULL;
506
507 user_frame = 0;
508 frame_count = count;
509
510 if (!have_addr && !trace_thread) {
511 frame = (struct i386_frame *)ddb_regs.ebp;
512 callpc = (db_addr_t)ddb_regs.eip;
513 th = current_thread();
514 task = (th != THREAD_NULL)? th->task: TASK_NULL;
515 db_printf("thread 0x%x, current_thread() is 0x%x, ebp is 0x%x, eip is 0x%x\n", th, current_thread(), ddb_regs.ebp, ddb_regs.eip);
516 } else if (trace_thread) {
517 if (have_addr) {
518 th = (thread_t) addr;
519 if (!db_check_act_address_valid(th)) {
520 return;
521 }
522 } else {
523 th = db_default_act;
524 if (th == THREAD_NULL)
525 th = current_thread();
526 if (th == THREAD_NULL) {
527 db_printf("no active thread\n");
528 return;
529 }
530 }
531 if (trace_all_threads)
532 db_printf("---------- Thread 0x%x (#%d of %d) ----------\n",
533 addr, thcount, th->task->thread_count);
534
535 next_activation:
536 user_frame = 0;
537 // kprintf("th is %x, current_thread() is %x, ddb_regs.ebp is %x ddb_regs.eip is %x\n", th, current_thread(), ddb_regs.ebp, ddb_regs.eip);
538 task = th->task;
539 if (th == current_thread()) {
540 frame = (struct i386_frame *)ddb_regs.ebp;
541 callpc = (db_addr_t)ddb_regs.eip;
542 } else {
543 if (th->machine.pcb == 0) {
544 db_printf("thread has no pcb\n");
545 return;
546 }
547 if (!th) {
548 db_printf("thread has no shuttle\n");
549
550 goto thread_done;
551 }
552 else if ( (th->continuation != THREAD_CONTINUE_NULL) ||
553 th->kernel_stack == 0) {
554
555 db_printf("Continuation ");
556 db_task_printsym((db_expr_t)th->continuation,
557 DB_STGY_PROC, task);
558 db_printf("\n");
559
560 iss32 = (x86_saved_state32_t *)th->machine.pcb->iss;
561
562 frame = (struct i386_frame *) (iss32->ebp);
563 callpc = (db_addr_t) (iss32->eip);
564
565 } else {
566 int cpu;
567
568 for (cpu = 0; cpu < real_ncpus; cpu++) {
569 if (cpu_datap(cpu)->cpu_running == TRUE &&
570 cpu_datap(cpu)->cpu_active_thread == th &&
571 cpu_datap(cpu)->cpu_kdb_saved_state) {
572 break;
573 }
574 }
575 if (top_act != THREAD_NULL) {
576 /*
577 * Trying to get the backtrace of an activation
578 * which is not the top_most one in the RPC chain:
579 * use the activation's pcb.
580 */
581 iss32 = (x86_saved_state32_t *)th->machine.pcb->iss;
582
583 frame = (struct i386_frame *) (iss32->ebp);
584 callpc = (db_addr_t) (iss32->eip);
585 } else {
586 if (cpu == real_ncpus) {
587 register struct x86_kernel_state32 *iks;
588 int r;
589
590 iks = STACK_IKS(th->kernel_stack);
591 prev = db_recover;
592 if ((r = _setjmp(db_recover = &db_jmp_buf)) == 0) {
593 frame = (struct i386_frame *) (iks->k_ebp);
594 callpc = (db_addr_t) (iks->k_eip);
595 } else {
596 /*
597 * The kernel stack has probably been
598 * paged out (swapped out activation).
599 */
600 db_recover = prev;
601 if (r == 2) /* 'q' from db_more() */
602 db_error(0);
603 db_printf("<kernel stack (0x%x) error "
604 "(probably swapped out)>\n",
605 iks);
606 goto thread_done;
607 }
608 db_recover = prev;
609 } else {
610 db_printf(">>>>> active on cpu %d <<<<<\n",
611 cpu);
612
613 iss32 = (x86_saved_state32_t *)cpu_datap(cpu)->cpu_kdb_saved_state;
614
615 frame = (struct i386_frame *) (iss32->ebp);
616 callpc = (db_addr_t) (iss32->eip);
617 }
618 }
619 }
620 }
621 } else {
622 frame = (struct i386_frame *)addr;
623 th = (db_default_act)? db_default_act: current_thread();
624 task = (th != THREAD_NULL)? th->task: TASK_NULL;
625 callpc = (db_addr_t)db_get_task_value((int)&frame->f_retaddr,
626 4,
627 FALSE,
628 (user_frame) ? task : 0);
629 }
630
631 if (!INKERNELSTACK((unsigned)frame, th)) {
632 db_printf(">>>>> user space <<<<<\n");
633 if (kernel_only)
634 goto thread_done;
635 user_frame++;
636 }
637
638 lastframe = 0;
639 lastcallpc = (db_addr_t) 0;
640 while (frame_count-- && frame != 0) {
641 int narg = DB_NUMARGS_MAX;
642 char * name;
643 db_expr_t offset;
644 db_addr_t call_func = 0;
645 int r;
646 db_addr_t off;
647
648 db_symbol_values(NULL,
649 db_search_task_symbol_and_line(
650 callpc,
651 DB_STGY_XTRN,
652 &offset,
653 &filename,
654 &linenum,
655 (user_frame) ? task : 0,
656 &narg),
657 &name, (db_expr_t *)&call_func);
658 if ( name == NULL) {
659 db_find_task_sym_and_offset(callpc,
660 &name, &off, (user_frame) ? task : 0);
661 offset = (db_expr_t) off;
662 }
663
664 if (user_frame == 0) {
665 if (call_func && call_func == db_user_trap_symbol_value ||
666 call_func == db_kernel_trap_symbol_value) {
667 frame_type = TRAP;
668 narg = 1;
669 } else if (call_func &&
670 call_func == db_interrupt_symbol_value) {
671 frame_type = INTERRUPT;
672 goto next_frame;
673 } else if (call_func && call_func == db_syscall_symbol_value) {
674 frame_type = SYSCALL;
675 goto next_frame;
676 } else {
677 frame_type = 0;
678 prev = db_recover;
679 if ((r = _setjmp(db_recover = &db_jmp_buf)) == 0) {
680 if (narg < 0)
681 narg = db_numargs(frame,
682 (user_frame) ? task : 0);
683 db_recover = prev;
684 } else {
685 db_recover = prev;
686 goto thread_done;
687 }
688 }
689 } else {
690 frame_type = 0;
691 prev = db_recover;
692 if ((r = _setjmp(db_recover = &db_jmp_buf)) == 0) {
693 if (narg < 0)
694 narg = db_numargs(frame,
695 (user_frame) ? task : 0);
696 db_recover = prev;
697 } else {
698 db_recover = prev;
699 goto thread_done;
700 }
701 }
702
703 if (name == 0 || offset > db_maxoff) {
704 db_printf("0x%x 0x%x(", frame, callpc);
705 offset = 0;
706 } else
707 db_printf("0x%x %s(", frame, name);
708
709 argp = &frame->f_arg0;
710 while (narg > 0) {
711 int value;
712
713 prev = db_recover;
714 if ((r = _setjmp(db_recover = &db_jmp_buf)) == 0) {
715 value = db_get_task_value((int)argp,
716 4,
717 FALSE,
718 (user_frame) ? task : 0);
719 } else {
720 db_recover = prev;
721 if (r == 2) /* 'q' from db_more() */
722 db_error(0);
723 db_printf("... <stack error>)");
724 if (offset)
725 db_printf("+%x", offset);
726 if (filename) {
727 db_printf(" [%s", filename);
728 if (linenum > 0)
729 db_printf(":%d", linenum);
730 db_printf("]");
731 }
732 db_printf("\n");
733 goto thread_done;
734 }
735 db_recover = prev;
736 db_printf("%x", value);
737 argp++;
738 if (--narg != 0)
739 db_printf(",");
740 }
741 if (narg < 0)
742 db_printf("...");
743 db_printf(")");
744 if (offset) {
745 db_printf("+%x", offset);
746 }
747 if (filename) {
748 db_printf(" [%s", filename);
749 if (linenum > 0)
750 db_printf(":%d", linenum);
751 db_printf("]");
752 }
753 db_printf("\n");
754
755 next_frame:
756 lastcallpc = callpc;
757 db_nextframe(&lastframe, &frame, &callpc, frame_type,
758 (user_frame) ? th : THREAD_NULL);
759
760 if (frame == 0) {
761 if (th->task_threads.prev != THREAD_NULL) {
762 if (top_act == THREAD_NULL)
763 top_act = th;
764 th = th->task_threads.prev;
765 db_printf(">>>>> next activation 0x%x ($task%d.%d) <<<<<\n",
766 th,
767 db_lookup_task(th->task),
768 db_lookup_task_act(th->task, th));
769 goto next_activation;
770 }
771 /* end of chain */
772 break;
773 }
774 if (!INKERNELSTACK(lastframe, th) ||
775 !INKERNELSTACK((unsigned)frame, th))
776 user_frame++;
777 if (user_frame == 1) {
778 db_printf(">>>>> user space <<<<<\n");
779 if (kernel_only)
780 break;
781 }
782 if (frame <= lastframe) {
783 if ((INKERNELSTACK(lastframe, th) &&
784 !INKERNELSTACK(frame, th)))
785 continue;
786 db_printf("Bad frame pointer: 0x%x\n", frame);
787 break;
788 }
789 }
790
791 thread_done:
792 if (trace_all_threads) {
793 if (top_act != THREAD_NULL)
794 th = top_act;
795 th = (thread_t) queue_next(&th->task_threads);
796 if (! queue_end(act_list, (queue_entry_t) th)) {
797 db_printf("\n");
798 addr = (db_expr_t) th;
799 thcount++;
800 goto next_thread;
801
802 }
803 }
804 }
805
806 extern int kdp_vm_read(caddr_t, caddr_t, unsigned int );
807 extern boolean_t kdp_trans_off;
808 /*
809 * Print out 256 bytes of real storage
810 *
811 * dr [entaddr]
812 */
813 void db_display_real(db_expr_t addr, __unused int have_addr, __unused db_expr_t count, __unused char * modif) {
814
815 int i;
816 unsigned int xbuf[8];
817 unsigned read_result = 0;
818 /* Print 256 bytes */
819 for(i=0; i<8; i++) {
820
821 /* Do a physical read using kdp_vm_read(), rather than replicating the same
822 * facility
823 */
824 kdp_trans_off = 1;
825 read_result = kdp_vm_read(addr, &xbuf[0], 32);
826 kdp_trans_off = 0;
827
828 if (read_result != 32)
829 db_printf("Unable to read address\n");
830 else
831 db_printf("%016llX %08X %08X %08X %08X %08X %08X %08X %08X\n", addr, /* Print a line */
832 xbuf[0], xbuf[1], xbuf[2], xbuf[3],
833 xbuf[4], xbuf[5], xbuf[6], xbuf[7]);
834 addr = addr + 0x00000020; /* Point to next address */
835 }
836 db_next = addr;
837 }
838
839 /*
840 * Displays all of the kmods in the system.
841 *
842 * dk
843 */
844 void
845 db_display_kmod(__unused db_expr_t addr, __unused int have_addr, __unused db_expr_t count, __unused char *modif)
846 {
847
848 kmod_info_t *kmd;
849 unsigned int strt, end;
850
851 kmd = kmod; /* Start at the start */
852
853 db_printf("info addr start - end name ver\n");
854
855 while (kmd) { /* Dump 'em all */
856 strt = (unsigned int) kmd->address + kmd->hdr_size;
857 end = (unsigned int) kmd->address + kmd->size;
858 db_printf("%08X %08X %08X - %08X: %s, %s\n",
859 kmd, kmd->address, strt, end, kmd->name, kmd->version);
860 kmd = kmd->next;
861 }
862
863 return;
864 }