#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/user.h>
#include <machine/db_machdep.h>
#include <ddb/db_interface.h>
#include <ddb/db_sym.h>
#include <ddb/db_output.h>
db_regs_t ddb_regs;
#define INKERNEL(va) (((vaddr_t)(va)) >= VM_MIN_KERNEL_ADDRESS)
#define FR_RFP (0)
#define FR_RLV (+1)
void
db_stack_trace_print(db_expr_t addr, int have_addr, db_expr_t count,
char *modif, int (*pr)(const char *, ...))
{
u_int32_t *frame, *lastframe;
char c, *cp = modif;
int kernel_only = 1;
int trace_thread = 0;
vaddr_t scp;
while ((c = *cp++) != 0) {
if (c == 'u')
kernel_only = 0;
if (c == 't')
trace_thread = 1;
}
if (!have_addr) {
frame = (u_int32_t *)(ddb_regs.tf_r11);
scp = ddb_regs.tf_pc;
} else {
if (trace_thread) {
struct proc *p;
struct user *u;
(*pr) ("trace: pid %d ", (int)addr);
p = tfind(addr);
if (p == NULL) {
(*pr)("not found\n");
return;
}
u = p->p_addr;
frame = (u_int32_t *)(u->u_pcb.pcb_un.un_32.pcb32_r11);
(*pr)("at %p\n", frame);
scp = u->u_pcb.pcb_un.un_32.pcb32_pc;
} else
frame = (u_int32_t *)(addr);
}
lastframe = NULL;
while (count-- && frame != NULL) {
db_printsym(scp, DB_STGY_PROC, pr);
(*pr)("\n\trlv=0x%08x rfp=0x%08x\n", frame[FR_RLV], frame[FR_RFP]);
scp = frame[FR_RLV];
if (frame[FR_RFP] == 0)
break;
lastframe = frame;
frame = (u_int32_t *)(frame[FR_RFP]);
if (INKERNEL((int)frame)) {
if (frame <= lastframe) {
(*pr)("Bad frame pointer: %p\n", frame);
break;
}
} else if (INKERNEL((int)lastframe)) {
if (kernel_only)
break;
} else {
if (frame <= lastframe) {
(*pr)("Bad user frame pointer: %p\n",
frame);
break;
}
}
}
}