150 lines
3.7 KiB
C
150 lines
3.7 KiB
C
|
/* $NetBSD: db_trace.c,v 1.1 2001/03/04 05:11:41 matt Exp $ */
|
||
|
|
||
|
/*
|
||
|
* Copyright (c) 1996 Scott K. Stevens
|
||
|
*
|
||
|
* Mach Operating System
|
||
|
* Copyright (c) 1991,1990 Carnegie Mellon University
|
||
|
* All Rights Reserved.
|
||
|
*
|
||
|
* Permission to use, copy, modify and distribute this software and its
|
||
|
* documentation is hereby granted, provided that both the copyright
|
||
|
* notice and this permission notice appear in all copies of the
|
||
|
* software, derivative works or modified versions, and any portions
|
||
|
* thereof, and that both notices appear in supporting documentation.
|
||
|
*
|
||
|
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
|
||
|
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
|
||
|
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
|
||
|
*
|
||
|
* Carnegie Mellon requests users of this software to return to
|
||
|
*
|
||
|
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
|
||
|
* School of Computer Science
|
||
|
* Carnegie Mellon University
|
||
|
* Pittsburgh PA 15213-3890
|
||
|
*
|
||
|
* any improvements or extensions that they make and grant Carnegie the
|
||
|
* rights to redistribute these changes.
|
||
|
*/
|
||
|
|
||
|
#include <sys/param.h>
|
||
|
#include <sys/proc.h>
|
||
|
#include <sys/user.h>
|
||
|
#include <machine/db_machdep.h>
|
||
|
|
||
|
#include <ddb/db_access.h>
|
||
|
#include <ddb/db_sym.h>
|
||
|
#include <ddb/db_output.h>
|
||
|
|
||
|
#define INKERNEL(va) (((vm_offset_t)(va)) >= VM_MIN_KERNEL_ADDRESS)
|
||
|
|
||
|
void
|
||
|
db_stack_trace_print(addr, have_addr, count, modif, pr)
|
||
|
db_expr_t addr;
|
||
|
int have_addr;
|
||
|
db_expr_t count;
|
||
|
char *modif;
|
||
|
void (*pr) __P((const char *, ...));
|
||
|
{
|
||
|
struct frame *frame, *lastframe;
|
||
|
char c, *cp = modif;
|
||
|
boolean_t kernel_only = TRUE;
|
||
|
boolean_t trace_thread = FALSE;
|
||
|
|
||
|
while ((c = *cp++) != 0) {
|
||
|
if (c == 'u')
|
||
|
kernel_only = FALSE;
|
||
|
if (c == 't')
|
||
|
trace_thread = TRUE;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* The frame pointer points to the top word of the stack frame so we
|
||
|
* need to adjust it by sizeof(struct frame) - sizeof(u_int))
|
||
|
* to get the address of the start of the frame structure.
|
||
|
*/
|
||
|
|
||
|
if (!have_addr)
|
||
|
frame = (struct frame *)(DDB_REGS->tf_r11
|
||
|
- (sizeof(struct frame) - sizeof(u_int)));
|
||
|
else {
|
||
|
if (trace_thread) {
|
||
|
struct proc *p;
|
||
|
struct user *u;
|
||
|
(*pr)("trace: pid %d ", (int)addr);
|
||
|
p = pfind(addr);
|
||
|
if (p == NULL) {
|
||
|
(*pr)("not found\n");
|
||
|
return;
|
||
|
}
|
||
|
if (!(p->p_flag & P_INMEM)) {
|
||
|
(*pr)("swapped out\n");
|
||
|
return;
|
||
|
}
|
||
|
u = p->p_addr;
|
||
|
frame = (struct frame *) (u->u_pcb.pcb_r11
|
||
|
- (sizeof(struct frame) - sizeof(u_int)));
|
||
|
(*pr)("at %p\n", frame);
|
||
|
} else
|
||
|
frame = (struct frame *)(addr - (sizeof(struct frame)
|
||
|
- sizeof(u_int)));
|
||
|
}
|
||
|
lastframe = NULL;
|
||
|
|
||
|
while (count--) {
|
||
|
db_expr_t offset;
|
||
|
char *name;
|
||
|
db_addr_t pc;
|
||
|
|
||
|
/* (*pr)("fp=%08x: fp=%08x sp=%08x lr=%08x pc=%08x\n",
|
||
|
(u_int)frame, frame->fr_fp, frame->fr_sp, frame->fr_lr,
|
||
|
frame->fr_pc);*/
|
||
|
|
||
|
pc = frame->fr_pc;
|
||
|
/* Adjust the PC so the same address is printed no matter what CPU */
|
||
|
if (cputype == CPU_ID_SA110 || cputype == CPU_ID_ARM810)
|
||
|
pc += 4;
|
||
|
if (!INKERNEL(pc))
|
||
|
break;
|
||
|
|
||
|
db_find_sym_and_offset(pc, &name, &offset);
|
||
|
if (name == NULL)
|
||
|
name = "?";
|
||
|
|
||
|
(*pr)("%s(", name);
|
||
|
db_printsym(pc, DB_STGY_PROC, pr);
|
||
|
(*pr)(")");
|
||
|
(*pr)("\n");
|
||
|
|
||
|
/*
|
||
|
* Switch to next frame up
|
||
|
*/
|
||
|
lastframe = frame;
|
||
|
frame = (struct frame *)(frame->fr_fp - (sizeof(struct frame)
|
||
|
- sizeof(u_int)));
|
||
|
|
||
|
if (frame == NULL)
|
||
|
break;
|
||
|
|
||
|
if (INKERNEL((int)frame)) {
|
||
|
/* staying in kernel */
|
||
|
if (frame <= lastframe) {
|
||
|
(*pr)("Bad frame pointer: %p\n", frame);
|
||
|
break;
|
||
|
}
|
||
|
} else if (INKERNEL((int)lastframe)) {
|
||
|
/* switch from user to kernel */
|
||
|
if (kernel_only)
|
||
|
break; /* kernel stack only */
|
||
|
} else {
|
||
|
/* in user */
|
||
|
if (frame <= lastframe) {
|
||
|
(*pr)("Bad user frame pointer: %p\n",
|
||
|
frame);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|