int pmc_save_kernel_callchain(uintptr_t *cc, int maxsamples, struct trapframe *tf) { uintptr_t pc, r, stackstart, stackend, fp; struct thread *td; int count; KASSERT(TRAPF_USERMODE(tf) == 0,("[arm,%d] not a kernel backtrace", __LINE__)); pc = PMC_TRAPFRAME_TO_PC(tf); *cc++ = pc; if ((td = curthread) == NULL) return (1); if (maxsamples <= 1) return (1); stackstart = (uintptr_t) td->td_kstack; stackend = (uintptr_t) td->td_kstack + td->td_kstack_pages * PAGE_SIZE; fp = PMC_TRAPFRAME_TO_FP(tf); if (!PMC_IN_KERNEL(pc) || !PMC_IN_KERNEL_STACK(fp, stackstart, stackend)) return (1); for (count = 1; count < maxsamples; count++) { /* Use saved lr as pc. */ r = fp - sizeof(uintptr_t); if (!PMC_IN_KERNEL_STACK(r, stackstart, stackend)) break; pc = *(uintptr_t *)r; if (!PMC_IN_KERNEL(pc)) break; *cc++ = pc; /* Switch to next frame up */ r = fp - 3 * sizeof(uintptr_t); if (!PMC_IN_KERNEL_STACK(r, stackstart, stackend)) break; fp = *(uintptr_t *)r; if (!PMC_IN_KERNEL_STACK(fp, stackstart, stackend)) break; } return (count); }
int pmc_save_kernel_callchain(uintptr_t *cc, int nframes, struct trapframe *tf) { int n; uint32_t instr; uintptr_t fp, pc, r, sp, stackstart, stackend; struct thread *td; KASSERT(TRAPF_USERMODE(tf) == 0,("[x86,%d] not a kernel backtrace", __LINE__)); td = curthread; pc = PMC_TRAPFRAME_TO_PC(tf); fp = PMC_TRAPFRAME_TO_FP(tf); sp = PMC_TRAPFRAME_TO_KERNEL_SP(tf); *cc++ = pc; r = fp + sizeof(uintptr_t); /* points to return address */ if (nframes <= 1) return (1); stackstart = (uintptr_t) td->td_kstack; stackend = (uintptr_t) td->td_kstack + td->td_kstack_pages * PAGE_SIZE; if (PMC_IN_TRAP_HANDLER(pc) || !PMC_IN_KERNEL(pc) || !PMC_IN_KERNEL_STACK(r, stackstart, stackend) || !PMC_IN_KERNEL_STACK(sp, stackstart, stackend) || !PMC_IN_KERNEL_STACK(fp, stackstart, stackend)) return (1); instr = *(uint32_t *) pc; /* * Determine whether the interrupted function was in the * processing of either laying down its stack frame or taking * it off. * * If we haven't started laying down a stack frame, or are * just about to return, then our caller's address is at * *sp, and we don't have a frame to unwind. */ if (PMC_AT_FUNCTION_PROLOGUE_PUSH_BP(instr) || PMC_AT_FUNCTION_EPILOGUE_RET(instr)) pc = *(uintptr_t *) sp; else if (PMC_AT_FUNCTION_PROLOGUE_MOV_SP_BP(instr)) { /* * The code was midway through laying down a frame. * At this point sp[0] has a frame back pointer, * and the caller's address is therefore at sp[1]. */ sp += sizeof(uintptr_t); if (!PMC_IN_KERNEL_STACK(sp, stackstart, stackend)) return (1); pc = *(uintptr_t *) sp; } else { /* * Not in the function prologue or epilogue. */ pc = *(uintptr_t *) r; fp = *(uintptr_t *) fp; } for (n = 1; n < nframes; n++) { *cc++ = pc; if (PMC_IN_TRAP_HANDLER(pc)) break; r = fp + sizeof(uintptr_t); if (!PMC_IN_KERNEL_STACK(fp, stackstart, stackend) || !PMC_IN_KERNEL_STACK(r, stackstart, stackend)) break; pc = *(uintptr_t *) r; fp = *(uintptr_t *) fp; } return (n); }