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