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