#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: db_trace.c,v 1.37 2019/04/06 16:22:01 thorpej Exp $");
#include <sys/param.h>
#include <sys/proc.h>
#include <sys/cpu.h>
#include <sys/systm.h>
#include <machine/db_machdep.h>
#include <ddb/db_access.h>
#include <ddb/db_user.h>
#include <ddb/db_sym.h>
#include <ddb/db_interface.h>
#include <ddb/db_output.h>
#define INKERNEL(va) (((vaddr_t)(va)) >= USRSTACK)
#ifdef _KERNEL
#define ONINTSTACK(fr) ( \
(u_int)(fr) < (u_int)ddb_cpuinfo->eintstack && \
(u_int)(fr) >= (u_int)ddb_cpuinfo->eintstack - INT_STACK_SIZE \
)
#else
#define ONINTSTACK(fr) (0)
#endif
#ifdef _KERNEL
static db_addr_t
db_fetch_word(const void *uaddr)
{
u_int val;
if (ufetch_int(uaddr, &val) != 0)
val = (u_int)-1;
return val;
}
#endif
void
db_stack_trace_print(db_expr_t addr, bool have_addr,
db_expr_t count, const char *modif,
void (*pr)(const char *, ...))
{
struct frame *frame, *prevframe;
db_addr_t pc;
bool kernel_only = true;
bool trace_thread = false;
bool lwpaddr = false;
const char *cp = modif;
char c;
#ifdef _KERNEL
if (ddb_cpuinfo == NULL)
ddb_cpuinfo = curcpu();
#endif
while ((c = *cp++) != 0) {
if (c == 'a') {
lwpaddr = true;
trace_thread = true;
}
if (c == 't')
trace_thread = true;
if (c == 'u')
kernel_only = false;
}
if (!have_addr) {
frame = (struct frame *)DDB_TF->tf_out[6];
pc = DDB_TF->tf_pc;
} else {
if (trace_thread) {
struct proc *p;
struct pcb *pcb;
struct lwp *l;
if (lwpaddr) {
l = (struct lwp *)addr;
p = l->l_proc;
(*pr)("trace: pid %d ", p->p_pid);
} else {
(*pr)("trace: pid %d ", (int)addr);
#ifdef _KERNEL
p = proc_find_raw(addr);
if (p == NULL) {
(*pr)("not found\n");
return;
}
l = LIST_FIRST(&p->p_lwps);
KASSERT(l != NULL);
#else
(*pr)("no proc_find_raw() in crash\n");
return;
#endif
}
(*pr)("lid %d ", l->l_lid);
pcb = lwp_getpcb(l);
frame = (struct frame *)pcb->pcb_sp;
pc = pcb->pcb_pc;
(*pr)("at %p\n", frame);
} else {
frame = (struct frame *)addr;
pc = 0;
}
}
while (count--) {
int i;
db_expr_t offset;
const char *name;
db_addr_t prevpc;
#ifdef _KERNEL
#define FR(framep,field) (INKERNEL(framep) \
? (u_int)(framep)->field \
: db_fetch_word(&(framep)->field))
#else
#define FR(framep,field) ((u_int)(framep)->field)
#endif
prevpc = (db_addr_t)FR(frame, fr_pc);
prevframe = (struct frame *)FR(frame, fr_fp);
if (prevframe == NULL || (!INKERNEL(prevframe) && kernel_only))
return;
if ((ONINTSTACK(frame) && !ONINTSTACK(prevframe)) ||
(INKERNEL(frame) && !INKERNEL(prevframe))) {
prevpc = (db_addr_t)FR(frame, fr_local[1]);
}
name = NULL;
if (INKERNEL(pc))
db_find_sym_and_offset(pc, &name, &offset);
if (name == NULL)
(*pr)("0x%lx(", pc);
else
(*pr)("%s(", name);
for (i = 0; i < 6; i++)
(*pr)("0x%x%s", FR(frame, fr_arg[i]),
(i < 5) ? ", " : ") at ");
if (INKERNEL(prevpc))
db_printsym(prevpc, DB_STGY_PROC, pr);
else
(*pr)("0x%lx", prevpc);
(*pr)("\n");
pc = prevpc;
frame = prevframe;
}
}