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