vfio/pci: return -EFAULT if copy_to_user fails
[linux-2.6-block.git] / arch / s390 / oprofile / backtrace.c
CommitLineData
a53c8fab 1/*
d0f4c16f 2 * S390 Version
a53c8fab 3 * Copyright IBM Corp. 2005
d0f4c16f
AK
4 * Author(s): Andreas Krebbel <Andreas.Krebbel@de.ibm.com>
5 */
6
7#include <linux/oprofile.h>
8
9#include <asm/processor.h> /* for struct stack_frame */
10
11static 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) {
d0f4c16f
AK
19 if (sp < low || sp > high - sizeof(*sf))
20 return sp;
21 sf = (struct stack_frame *) sp;
22 (*depth)--;
9cb1ccec 23 oprofile_add_trace(sf->gprs[8]);
d0f4c16f
AK
24
25 /* Follow the backchain. */
26 while (*depth) {
27 low = sp;
9cb1ccec 28 sp = sf->back_chain;
d0f4c16f
AK
29 if (!sp)
30 break;
31 if (sp <= low || sp > high - sizeof(*sf))
32 return sp;
33 sf = (struct stack_frame *) sp;
34 (*depth)--;
9cb1ccec 35 oprofile_add_trace(sf->gprs[8]);
d0f4c16f
AK
36
37 }
38
39 if (*depth == 0)
40 break;
41
42 /* Zero backchain detected, check for interrupt frame. */
43 sp = (unsigned long) (sf + 1);
44 if (sp <= low || sp > high - sizeof(*regs))
45 return sp;
46 regs = (struct pt_regs *) sp;
47 (*depth)--;
9cb1ccec 48 oprofile_add_trace(sf->gprs[8]);
d0f4c16f
AK
49 low = sp;
50 sp = regs->gprs[15];
51 }
52 return sp;
53}
54
55void s390_backtrace(struct pt_regs * const regs, unsigned int depth)
56{
232f5dd7 57 unsigned long head, frame_size;
d0f4c16f
AK
58 struct stack_frame* head_sf;
59
7d256175 60 if (user_mode(regs))
d0f4c16f
AK
61 return;
62
232f5dd7 63 frame_size = STACK_FRAME_OVERHEAD + sizeof(struct pt_regs);
d0f4c16f
AK
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
232f5dd7
HC
72 head = __show_trace(&depth, head,
73 S390_lowcore.async_stack + frame_size - ASYNC_SIZE,
74 S390_lowcore.async_stack + frame_size);
d0f4c16f
AK
75
76 __show_trace(&depth, head, S390_lowcore.thread_info,
77 S390_lowcore.thread_info + THREAD_SIZE);
78}