linux/arch/s390/kernel/stacktrace.c
<<
>>
Prefs
   1/*
   2 * Stack trace management functions
   3 *
   4 *  Copyright IBM Corp. 2006
   5 *  Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
   6 */
   7
   8#include <linux/sched.h>
   9#include <linux/stacktrace.h>
  10#include <linux/kallsyms.h>
  11#include <linux/module.h>
  12
  13static unsigned long save_context_stack(struct stack_trace *trace,
  14                                        unsigned long sp,
  15                                        unsigned long low,
  16                                        unsigned long high,
  17                                        int savesched)
  18{
  19        struct stack_frame *sf;
  20        struct pt_regs *regs;
  21        unsigned long addr;
  22
  23        while(1) {
  24                sp &= PSW_ADDR_INSN;
  25                if (sp < low || sp > high)
  26                        return sp;
  27                sf = (struct stack_frame *)sp;
  28                while(1) {
  29                        addr = sf->gprs[8] & PSW_ADDR_INSN;
  30                        if (!trace->skip)
  31                                trace->entries[trace->nr_entries++] = addr;
  32                        else
  33                                trace->skip--;
  34                        if (trace->nr_entries >= trace->max_entries)
  35                                return sp;
  36                        low = sp;
  37                        sp = sf->back_chain & PSW_ADDR_INSN;
  38                        if (!sp)
  39                                break;
  40                        if (sp <= low || sp > high - sizeof(*sf))
  41                                return sp;
  42                        sf = (struct stack_frame *)sp;
  43                }
  44                /* Zero backchain detected, check for interrupt frame. */
  45                sp = (unsigned long)(sf + 1);
  46                if (sp <= low || sp > high - sizeof(*regs))
  47                        return sp;
  48                regs = (struct pt_regs *)sp;
  49                addr = regs->psw.addr & PSW_ADDR_INSN;
  50                if (savesched || !in_sched_functions(addr)) {
  51                        if (!trace->skip)
  52                                trace->entries[trace->nr_entries++] = addr;
  53                        else
  54                                trace->skip--;
  55                }
  56                if (trace->nr_entries >= trace->max_entries)
  57                        return sp;
  58                low = sp;
  59                sp = regs->gprs[15];
  60        }
  61}
  62
  63void save_stack_trace(struct stack_trace *trace)
  64{
  65        register unsigned long sp asm ("15");
  66        unsigned long orig_sp, new_sp;
  67
  68        orig_sp = sp & PSW_ADDR_INSN;
  69        new_sp = save_context_stack(trace, orig_sp,
  70                                    S390_lowcore.panic_stack - PAGE_SIZE,
  71                                    S390_lowcore.panic_stack, 1);
  72        if (new_sp != orig_sp)
  73                return;
  74        new_sp = save_context_stack(trace, new_sp,
  75                                    S390_lowcore.async_stack - ASYNC_SIZE,
  76                                    S390_lowcore.async_stack, 1);
  77        if (new_sp != orig_sp)
  78                return;
  79        save_context_stack(trace, new_sp,
  80                           S390_lowcore.thread_info,
  81                           S390_lowcore.thread_info + THREAD_SIZE, 1);
  82}
  83EXPORT_SYMBOL_GPL(save_stack_trace);
  84
  85void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
  86{
  87        unsigned long sp, low, high;
  88
  89        sp = tsk->thread.ksp & PSW_ADDR_INSN;
  90        low = (unsigned long) task_stack_page(tsk);
  91        high = (unsigned long) task_pt_regs(tsk);
  92        save_context_stack(trace, sp, low, high, 0);
  93        if (trace->nr_entries < trace->max_entries)
  94                trace->entries[trace->nr_entries++] = ULONG_MAX;
  95}
  96EXPORT_SYMBOL_GPL(save_stack_trace_tsk);
  97