void xtensa_backtrace_kernel()

in kernel/stacktrace.c [115:163]


void xtensa_backtrace_kernel(struct pt_regs *regs, unsigned int depth,
			     int (*kfn)(struct stackframe *frame, void *data),
			     int (*ufn)(struct stackframe *frame, void *data),
			     void *data)
{
	unsigned long pc = regs->depc > VALID_DOUBLE_EXCEPTION_ADDRESS ?
		regs->depc : regs->pc;
	unsigned long sp_start, sp_end;
	unsigned long a0 = regs->areg[0];
	unsigned long a1 = regs->areg[1];

	sp_start = a1 & ~(THREAD_SIZE - 1);
	sp_end = sp_start + THREAD_SIZE;

	/* Spill the register window to the stack first. */
	spill_registers();

	/* Read the stack frames one by one and create the PC
	 * from the a0 and a1 registers saved there.
	 */
	while (a1 > sp_start && a1 < sp_end && depth--) {
		struct stackframe frame;

		frame.pc = pc;
		frame.sp = a1;

		if (kernel_text_address(pc) && kfn(&frame, data))
			return;

		if (pc == (unsigned long)&common_exception_return) {
			regs = (struct pt_regs *)a1;
			if (user_mode(regs)) {
				if (ufn == NULL)
					return;
				xtensa_backtrace_user(regs, depth, ufn, data);
				return;
			}
			a0 = regs->areg[0];
			a1 = regs->areg[1];
			continue;
		}

		sp_start = a1;

		pc = MAKE_PC_FROM_RA(a0, pc);
		a0 = SPILL_SLOT(a1, 0);
		a1 = SPILL_SLOT(a1, 1);
	}
}