linux/arch/arm/kernel/stacktrace.c
<<
>>
Prefs
   1#include <linux/module.h>
   2#include <linux/sched.h>
   3#include <linux/stacktrace.h>
   4
   5#include "stacktrace.h"
   6
   7int walk_stackframe(unsigned long fp, unsigned long low, unsigned long high,
   8                    int (*fn)(struct stackframe *, void *), void *data)
   9{
  10        struct stackframe *frame;
  11
  12        do {
  13                /*
  14                 * Check current frame pointer is within bounds
  15                 */
  16                if (fp < (low + 12) || fp + 4 >= high)
  17                        break;
  18
  19                frame = (struct stackframe *)(fp - 12);
  20
  21                if (fn(frame, data))
  22                        break;
  23
  24                /*
  25                 * Update the low bound - the next frame must always
  26                 * be at a higher address than the current frame.
  27                 */
  28                low = fp + 4;
  29                fp = frame->fp;
  30        } while (fp);
  31
  32        return 0;
  33}
  34EXPORT_SYMBOL(walk_stackframe);
  35
  36#ifdef CONFIG_STACKTRACE
  37struct stack_trace_data {
  38        struct stack_trace *trace;
  39        unsigned int no_sched_functions;
  40        unsigned int skip;
  41};
  42
  43static int save_trace(struct stackframe *frame, void *d)
  44{
  45        struct stack_trace_data *data = d;
  46        struct stack_trace *trace = data->trace;
  47        unsigned long addr = frame->lr;
  48
  49        if (data->no_sched_functions && in_sched_functions(addr))
  50                return 0;
  51        if (data->skip) {
  52                data->skip--;
  53                return 0;
  54        }
  55
  56        trace->entries[trace->nr_entries++] = addr;
  57
  58        return trace->nr_entries >= trace->max_entries;
  59}
  60
  61void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
  62{
  63        struct stack_trace_data data;
  64        unsigned long fp, base;
  65
  66        data.trace = trace;
  67        data.skip = trace->skip;
  68        base = (unsigned long)task_stack_page(tsk);
  69
  70        if (tsk != current) {
  71#ifdef CONFIG_SMP
  72                /*
  73                 * What guarantees do we have here that 'tsk'
  74                 * is not running on another CPU?
  75                 */
  76                BUG();
  77#else
  78                data.no_sched_functions = 1;
  79                fp = thread_saved_fp(tsk);
  80#endif
  81        } else {
  82                data.no_sched_functions = 0;
  83                asm("mov %0, fp" : "=r" (fp));
  84        }
  85
  86        walk_stackframe(fp, base, base + THREAD_SIZE, save_trace, &data);
  87        if (trace->nr_entries < trace->max_entries)
  88                trace->entries[trace->nr_entries++] = ULONG_MAX;
  89}
  90
  91void save_stack_trace(struct stack_trace *trace)
  92{
  93        save_stack_trace_tsk(current, trace);
  94}
  95EXPORT_SYMBOL_GPL(save_stack_trace);
  96#endif
  97
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.