#include "opt_ddb.h"
#include <sys/param.h>
#include <sys/proc.h>
#include <sys/systm.h>
#include <machine/cpufunc.h>
#include <machine/md_var.h>
#include <machine/db_machdep.h>
#include <ddb/db_sym.h>
#include <ddb/db_access.h>
#include <ddb/db_output.h>
#include <ddb/db_variables.h>
#include <ddb/db_interface.h>
#include <ia64/unwind/decode.h>
#include <ia64/unwind/stackframe.h>
#if 0
#define UNWIND_DIAGNOSTIC
#endif
#define debug_frame_dump_XXX(uwf) \
printf("Frame Dump: \n bsp = 0x%lx \n pfs = 0x%lx, SOL(pfs) = %lu \n rp = 0x%lx \n", \
uwf->bsp, uwf->pfs, IA64_CFM_SOL(uwf->pfs), uwf->rp); \
void
initunwindframe(struct unwind_frame *uwf, struct trapframe *tf);
void
rewindframe(struct unwind_frame *uwf, db_addr_t ip);
void
db_stack_trace_print(db_expr_t addr, bool have_addr, db_expr_t count,
const char *modif, void (*pr)(const char *, ...))
{
char c;
const char *cp = modif;
bool trace_thread = false;
bool trace_user = false;
struct trapframe *tf;
struct unwind_frame current_frame;
db_addr_t ip;
const char *name;
db_sym_t sym;
db_expr_t offset;
while ((c = *cp++) != 0) {
trace_thread |= c == 't';
trace_user |= c == 'u';
}
if (trace_user) {
(*pr)("User-space stack tracing not implemented yet. \n");
return;
}
if (!have_addr) {
(*pr)("--Kernel Call Trace-- \n");
tf = DDB_REGS;
ip = tf->tf_special.iip + ((tf->tf_special.psr >> 41) & 3);
initunwindframe(¤t_frame, tf);
#ifdef UNWIND_DIAGNOSTIC
struct unwind_frame *uwf = ¤t_frame;
debug_frame_dump_XXX(uwf);
#endif
KASSERT(ip >= kernstart);
patchunwindframe(¤t_frame, ip - kernstart, kernstart);
#ifdef UNWIND_DIAGNOSTIC
debug_frame_dump_XXX(uwf);
#endif
while(ip) {
sym = db_search_symbol(ip, DB_STGY_ANY, &offset);
db_symbol_values(sym, &name, NULL);
(*pr)("%s(...)\n", name);
ip = current_frame.rp;
if(!ip) break;
rewindframe(¤t_frame, ip);
}
return;
} else (*pr) ("Unwind from arbitrary addresses unimplemented. \n");
if (trace_thread) {
(*pr)("trace by pid unimplemented. \n");
return;
}
else {
(*pr)("trace from arbitrary trap frame address unimplemented. \n");
}
}
extern db_addr_t ia64_unwindtab;
extern vsize_t ia64_unwindtablen;
void
initunwindframe(struct unwind_frame *uwf, struct trapframe *tf)
{
uwf->rp = tf->tf_special.rp;
uwf->bsp = tf->tf_special.bspstore + tf->tf_special.ndirty;
uwf->bsp = ia64_bsp_adjust_ret(uwf->bsp, IA64_CFM_SOF(tf->tf_special.cfm));
#ifdef UNWIND_DIAGNOSTIC
printf("inituwframe(): SOF(cfm) = %lu \n", IA64_CFM_SOF(tf->tf_special.cfm));
#endif
uwf->pfs = tf->tf_special.pfs;
uwf->sp = uwf->psp = tf->tf_special.sp;
}
void
rewindframe(struct unwind_frame *uwf, db_addr_t ip)
{
uwf->bsp = ia64_bsp_adjust_ret(uwf->bsp, IA64_CFM_SOL(uwf->pfs));
uwf->sp = uwf->psp;
#ifdef UNWIND_DIAGNOSTIC
debug_frame_dump_XXX(uwf);
#endif
KASSERT(ip >= kernstart);
patchunwindframe(uwf, ip - kernstart, kernstart);
#ifdef UNWIND_DIAGNOSTIC
debug_frame_dump_XXX(uwf);
#endif
}