Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
backtrace.c
Go to the documentation of this file.
1 /*
2  * S390 Version
3  * Copyright IBM Corp. 2005
4  * Author(s): Andreas Krebbel <[email protected]>
5  */
6 
7 #include <linux/oprofile.h>
8 
9 #include <asm/processor.h> /* for struct stack_frame */
10 
11 static unsigned long
12 __show_trace(unsigned int *depth, unsigned long sp,
13  unsigned long low, unsigned long high)
14 {
15  struct stack_frame *sf;
16  struct pt_regs *regs;
17 
18  while (*depth) {
19  sp = sp & PSW_ADDR_INSN;
20  if (sp < low || sp > high - sizeof(*sf))
21  return sp;
22  sf = (struct stack_frame *) sp;
23  (*depth)--;
24  oprofile_add_trace(sf->gprs[8] & PSW_ADDR_INSN);
25 
26  /* Follow the backchain. */
27  while (*depth) {
28  low = sp;
29  sp = sf->back_chain & PSW_ADDR_INSN;
30  if (!sp)
31  break;
32  if (sp <= low || sp > high - sizeof(*sf))
33  return sp;
34  sf = (struct stack_frame *) sp;
35  (*depth)--;
36  oprofile_add_trace(sf->gprs[8] & PSW_ADDR_INSN);
37 
38  }
39 
40  if (*depth == 0)
41  break;
42 
43  /* Zero backchain detected, check for interrupt frame. */
44  sp = (unsigned long) (sf + 1);
45  if (sp <= low || sp > high - sizeof(*regs))
46  return sp;
47  regs = (struct pt_regs *) sp;
48  (*depth)--;
49  oprofile_add_trace(sf->gprs[8] & PSW_ADDR_INSN);
50  low = sp;
51  sp = regs->gprs[15];
52  }
53  return sp;
54 }
55 
56 void s390_backtrace(struct pt_regs * const regs, unsigned int depth)
57 {
58  unsigned long head;
59  struct stack_frame* head_sf;
60 
61  if (user_mode(regs))
62  return;
63 
64  head = regs->gprs[15];
65  head_sf = (struct stack_frame*)head;
66 
67  if (!head_sf->back_chain)
68  return;
69 
70  head = head_sf->back_chain;
71 
72  head = __show_trace(&depth, head, S390_lowcore.async_stack - ASYNC_SIZE,
73  S390_lowcore.async_stack);
74 
75  __show_trace(&depth, head, S390_lowcore.thread_info,
76  S390_lowcore.thread_info + THREAD_SIZE);
77 }