#include <sys/param.h>
__KERNEL_RCSID(0, "$NetBSD: db_trace.c,v 1.33 2018/01/24 09:04:44 skrll Exp $");
#include <sys/proc.h>
#include <arm/armreg.h>
#include <arm/cpufunc.h>
#include <arm/pcb.h>
#include <machine/db_machdep.h>
#include <machine/vmparam.h>
#include <ddb/db_access.h>
#include <ddb/db_interface.h>
#include <ddb/db_sym.h>
#include <ddb/db_proc.h>
#include <ddb/db_output.h>
#define INKERNEL(va) (((vaddr_t)(va)) >= VM_MIN_KERNEL_ADDRESS)
#define FR_SCP (0)
#define FR_RLV (-1)
#define FR_RSP (-2)
#define FR_RFP (-3)
void
db_stack_trace_print(db_expr_t addr, bool have_addr,
db_expr_t count, const char *modif,
void (*pr)(const char *, ...))
{
struct trapframe *tf = NULL;
uint32_t *frame, *lastframe;
const char *cp = modif;
char c;
bool kernel_only = true;
bool trace_thread = false;
bool trace_full = false;
bool lwpaddr = false;
db_addr_t scp, pc;
int scp_offset;
while ((c = *cp++) != 0) {
if (c == 'a') {
lwpaddr = true;
trace_thread = true;
}
if (c == 'u')
kernel_only = false;
if (c == 't')
trace_thread = true;
if (c == 'f')
trace_full = true;
}
#ifdef _KERNEL
if (!have_addr)
frame = (uint32_t *)(DDB_REGS->tf_r11);
else
#endif
{
if (trace_thread) {
struct pcb *pcb;
proc_t p;
lwp_t l;
if (lwpaddr) {
db_read_bytes(addr, sizeof(l),
(char *)&l);
db_read_bytes((db_addr_t)l.l_proc,
sizeof(p), (char *)&p);
(*pr)("trace: pid %d ", p.p_pid);
} else {
proc_t *pp;
(*pr)("trace: pid %d ", (int)addr);
if ((pp = db_proc_find((pid_t)addr)) == 0) {
(*pr)("not found\n");
return;
}
db_read_bytes((db_addr_t)pp, sizeof(p), (char *)&p);
addr = (db_addr_t)p.p_lwps.lh_first;
db_read_bytes(addr, sizeof(l), (char *)&l);
}
(*pr)("lid %d ", l.l_lid);
pcb = lwp_getpcb(&l);
tf = lwp_trapframe(&l);
#ifndef _KERNEL
struct pcb pcbb;
db_read_bytes((db_addr_t)pcb, sizeof(*pcb),
(char *)&pcbb);
pcb = &pcbb;
#endif
frame = (uint32_t *)(pcb->pcb_r11);
(*pr)("at %p\n", frame);
} else
frame = (uint32_t *)(addr);
}
scp_offset = -(get_pc_str_offset() >> 2);
if (frame == NULL)
return;
lastframe = frame;
#ifndef _KERNEL
uint32_t frameb[4];
db_read_bytes((db_addr_t)(frame - 3), sizeof(frameb),
(char *)frameb);
frame = frameb + 3;
#endif
scp = frame[FR_SCP];
pc = scp;
while (count--) {
uint32_t savecode;
int r;
uint32_t *rp;
const char *sep;
scp = frame[FR_SCP];
(*pr)("%p: ", lastframe);
db_printsym(pc, DB_STGY_PROC, pr);
if (trace_full) {
(*pr)("\n\t");
(*pr)("pc =0x%08x rlv=0x%08x (", pc, frame[FR_RLV]);
db_printsym(frame[FR_RLV], DB_STGY_PROC, pr);
(*pr)(")\n");
(*pr)("\trsp=0x%08x rfp=0x%08x", frame[FR_RSP],
frame[FR_RFP]);
}
#ifndef _KERNEL
db_read_bytes((db_addr_t)((uint32_t *)scp + scp_offset),
sizeof(savecode), (void *)&savecode);
#else
if ((scp & 3) == 0) {
savecode = ((uint32_t *)scp)[scp_offset];
} else {
savecode = 0;
}
#endif
if (trace_full &&
(savecode & 0x0e100000) == 0x08000000) {
rp = frame - 4;
sep = "\n\t";
for (r = 10; r >= 0; r--) {
if (savecode & (1 << r)) {
(*pr)("%sr%d=0x%08x",
sep, r, *rp--);
sep = (frame - rp) % 4 == 2 ?
"\n\t" : " ";
}
}
}
(*pr)("\n");
if (frame[FR_RFP] == 0)
break;
pc = frame[FR_RLV];
frame = (uint32_t *)(frame[FR_RFP]);
if (frame == NULL)
break;
if (INKERNEL((int)frame)) {
if (frame <= lastframe) {
(*pr)("Bad frame pointer: %p\n", frame);
break;
}
} else if (INKERNEL((int)lastframe)) {
if (trace_thread) {
(*pr)("--- tf %p ---\n", tf);
}
if (kernel_only)
break;
} else {
if (frame <= lastframe) {
(*pr)("Bad user frame pointer: %p\n",
frame);
break;
}
}
lastframe = frame;
#ifndef _KERNEL
db_read_bytes((db_addr_t)(frame - 3), sizeof(frameb),
(char *)frameb);
frame = frameb + 3;
#endif
}
}