/* * Kernel and userspace stack tracing. * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * * Copyright (C) 2001 - 2013 Tensilica Inc. * Copyright (C) 2015 Cadence Design Systems Inc.
*/ #include <linux/export.h> #include <linux/sched.h> #include <linux/stacktrace.h>
if (pc == 0 || pc >= TASK_SIZE || ufn(&frame, data)) return;
if (IS_ENABLED(CONFIG_USER_ABI_CALL0_ONLY) ||
(IS_ENABLED(CONFIG_USER_ABI_CALL0_PROBE) &&
!(regs->ps & PS_WOE_MASK))) return;
/* Two steps: * * 1. Look through the register window for the * previous PCs in the call trace. * * 2. Look on the stack.
*/
/* Step 1. */ /* Rotate WINDOWSTART to move the bit corresponding to * the current window to the bit #0.
*/
windowstart = (windowstart << WSBITS | windowstart) >> windowbase;
/* Look for bits that are set, they correspond to * valid windows.
*/ for (index = WSBITS - 1; (index > 0) && depth; depth--, index--) if (windowstart & (1 << index)) { /* Get the PC from a0 and a1. */
pc = MAKE_PC_FROM_RA(a0, pc); /* Read a0 and a1 from the * corresponding position in AREGs.
*/
a0 = regs->areg[index * 4];
a1 = regs->areg[index * 4 + 1];
frame.pc = pc;
frame.sp = a1;
if (pc == 0 || pc >= TASK_SIZE || ufn(&frame, data)) return;
}
/* Step 2. */ /* We are done with the register window, we need to * look through the stack.
*/ if (!depth) return;
/* Start from the a1 register. */ /* a1 = regs->areg[1]; */ while (a0 != 0 && depth--) {
pc = MAKE_PC_FROM_RA(a0, pc);
/* Check if the region is OK to access. */ if (!access_ok(&SPILL_SLOT(a1, 0), 8)) return; /* Copy a1, a0 from user space stack frame. */ if (__get_user(a0, &SPILL_SLOT(a1, 0)) ||
__get_user(a1, &SPILL_SLOT(a1, 1))) return;
frame.pc = pc;
frame.sp = a1;
if (pc == 0 || pc >= TASK_SIZE || ufn(&frame, data)) return;
}
}
EXPORT_SYMBOL(xtensa_backtrace_user);
/* 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 (r->skip) {
--r->skip; return 0;
} if (!kernel_text_address(frame->pc)) return 0;
r->addr = frame->pc; return 1;
}
/* * level == 0 is for the return address from the caller of this function, * not from this function itself.
*/ unsignedlong return_address(unsigned level)
{ struct return_addr_data r = {
.skip = level,
};
walk_stackframe(stack_pointer(NULL), return_address_cb, &r); return r.addr;
}
EXPORT_SYMBOL(return_address);
Messung V0.5
¤ Dauer der Verarbeitung: 0.22 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.