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