/* * arch/mips/kernel/stacktrace.c * * Stack trace management functions * * Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp> */ #include <linux/sched.h> #include <linux/stacktrace.h> #include <asm/stacktrace.h> /* * Save stack-backtrace addresses into a stack_trace buffer: */ static void save_raw_context_stack(struct stack_trace *trace, unsigned long reg29) { unsigned long *sp = (unsigned long *)reg29; unsigned long addr; while (!kstack_end(sp)) { addr = *sp++; if (__kernel_text_address(addr)) { if (trace->skip > 0) trace->skip--; else trace->entries[trace->nr_entries++] = addr; if (trace->nr_entries >= trace->max_entries) break; } } } static void save_context_stack(struct stack_trace *trace, struct task_struct *task, struct pt_regs *regs) { unsigned long sp = regs->regs[29]; #ifdef CONFIG_KALLSYMS unsigned long ra = regs->regs[31]; unsigned long pc = regs->cp0_epc; if (raw_show_trace || !__kernel_text_address(pc)) { unsigned long stack_page = (unsigned long)task_stack_page(task); if (stack_page && sp >= stack_page && sp <= stack_page + THREAD_SIZE - 32) save_raw_context_stack(trace, sp); return; } do { if (trace->skip > 0) trace->skip--; else trace->entries[trace->nr_entries++] = pc; if (trace->nr_entries >= trace->max_entries) break; pc = unwind_stack(task, &sp, pc, &ra); } while (pc); #else save_raw_context_stack(trace, sp); #endif } /* * Save stack-backtrace addresses into a stack_trace buffer. */ void save_stack_trace(struct stack_trace *trace, struct task_struct *task) { struct pt_regs dummyregs; struct pt_regs *regs = &dummyregs; WARN_ON(trace->nr_entries || !trace->max_entries); if (task && task != current) { regs->regs[29] = task->thread.reg29; regs->regs[31] = 0; regs->cp0_epc = task->thread.reg31; } else { if (!task) task = current; prepare_frametrace(regs); } save_context_stack(trace, task, regs); }