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