#include <sys/param.h>
#include <sys/systm.h>
#include <machine/db_machdep.h>
#include <ddb/db_access.h>
#include <ddb/db_interface.h>
#include <ddb/db_sym.h>
#include <ddb/db_output.h>
extern unsigned char cpu_exception_handler_supervisor[];
extern unsigned char cpu_exception_handler_user[];
db_regs_t ddb_regs;
#define INKERNEL(va) (((vaddr_t)(va)) & (1ULL << 63))
void
db_stack_trace_print(db_expr_t addr, int have_addr, db_expr_t count,
char *modif, int (*pr)(const char *, ...))
{
vaddr_t frame, lastframe, ra, subr;
char c, *cp = modif;
db_expr_t offset;
Elf_Sym * sym;
const char *name;
int kernel_only = 1;
while ((c = *cp++) != 0) {
if (c == 'u')
kernel_only = 0;
if (c == 't') {
db_printf("tracing threads not yet supported\n");
return;
}
}
if (!have_addr) {
ra = ddb_regs.tf_ra;
frame = ddb_regs.tf_s[0];
} else {
db_read_bytes(addr - 16, sizeof(vaddr_t), (char *)&frame);
db_read_bytes(addr - 8, sizeof(vaddr_t), (char *)&ra);
}
while (count != 0 && frame != 0) {
if (INKERNEL(frame)) {
sym = db_search_symbol(ra, DB_STGY_ANY, &offset);
db_symbol_values(sym, &name, NULL);
} else {
sym = NULL;
name = NULL;
}
if (name == NULL || strcmp(name, "end") == 0) {
(*pr)("%llx() at 0x%lx", ra, ra);
} else {
(*pr)("%s() at ", name);
db_printsym(ra, DB_STGY_PROC, pr);
}
(*pr)("\n");
if ((frame & 0x7) != 0) {
(*pr)("bad frame pointer: 0x%lx\n", frame);
break;
}
subr = 0;
if (sym != NULL)
subr = ra - (vaddr_t)offset;
lastframe = frame;
if (subr == (vaddr_t)cpu_exception_handler_supervisor ||
subr == (vaddr_t)cpu_exception_handler_user) {
struct trapframe *tf = (struct trapframe *)frame;
db_read_bytes((vaddr_t)&tf->tf_ra, sizeof(ra),
(char *)&ra);
db_read_bytes((vaddr_t)&tf->tf_s[0], sizeof(frame),
(char *)&frame);
} else {
db_read_bytes(frame - 16, sizeof(frame),
(char *)&frame);
if (frame == 0)
break;
if ((frame & 0x7) != 0) {
(*pr)("bad frame pointer: 0x%lx\n", frame);
break;
}
db_read_bytes(frame - 8, sizeof(ra), (char *)&ra);
}
if (INKERNEL(frame)) {
if (frame <= lastframe) {
(*pr)("bad frame pointer: 0x%lx\n", frame);
break;
}
} else {
if (kernel_only) {
(*pr)("end of kernel\n");
break;
}
}
--count;
}
(*pr)("end trace frame: 0x%lx, count: %d\n", frame, count);
}