Linux Kernel
3.7.1
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
arch
ia64
oprofile
backtrace.c
Go to the documentation of this file.
1
13
#include <
linux/oprofile.h
>
14
#include <linux/sched.h>
15
#include <
linux/mm.h
>
16
#include <asm/ptrace.h>
17
18
/*
19
* For IA64 we need to perform a complex little dance to get both
20
* the struct pt_regs and a synthetic struct switch_stack in place
21
* to allow the unwind code to work. This dance requires our unwind
22
* using code to be called from a function called from unw_init_running().
23
* There we only get a single void* data pointer, so use this struct
24
* to hold all the data we need during the unwind.
25
*/
26
typedef
struct
27
{
28
unsigned
int
depth
;
29
struct
pt_regs
*
regs
;
30
struct
unw_frame_info
frame
;
31
unsigned
long
*
prev_pfs_loc
;
/* state for WAR for old spinlock ool code */
32
}
ia64_backtrace_t
;
33
34
/* Returns non-zero if the PC is in the Interrupt Vector Table */
35
static
__inline__
int
in_ivt_code(
unsigned
long
pc
)
36
{
37
extern
char
ia64_ivt
[];
38
return
(pc >= (
u_long
)ia64_ivt && pc < (
u_long
)ia64_ivt+32768);
39
}
40
41
/*
42
* Unwind to next stack frame.
43
*/
44
static
__inline__
int
next_frame
(
ia64_backtrace_t
*
bt
)
45
{
46
/*
47
* Avoid unsightly console message from unw_unwind() when attempting
48
* to unwind through the Interrupt Vector Table which has no unwind
49
* information.
50
*/
51
if
(in_ivt_code(bt->
frame
.ip))
52
return
0;
53
54
/*
55
* WAR for spinlock contention from leaf functions. ia64_spinlock_contention_pre3_4
56
* has ar.pfs == r0. Leaf functions do not modify ar.pfs so ar.pfs remains
57
* as 0, stopping the backtrace. Record the previous ar.pfs when the current
58
* IP is in ia64_spinlock_contention_pre3_4 then unwind, if pfs_loc has not changed
59
* after unwind then use pt_regs.ar_pfs which is where the real ar.pfs is for
60
* leaf functions.
61
*/
62
if
(bt->
prev_pfs_loc
&& bt->
regs
&& bt->
frame
.pfs_loc == bt->
prev_pfs_loc
)
63
bt->
frame
.pfs_loc = &bt->
regs
->ar_pfs;
64
bt->
prev_pfs_loc
=
NULL
;
65
66
return
unw_unwind
(&bt->
frame
) == 0;
67
}
68
69
70
static
void
do_ia64_backtrace(
struct
unw_frame_info
*
info
,
void
*vdata)
71
{
72
ia64_backtrace_t
*bt = vdata;
73
struct
switch_stack
*
sw
;
74
int
count
= 0;
75
u_long
pc
,
sp
;
76
77
sw = (
struct
switch_stack
*)(info+1);
78
/* padding from unw_init_running */
79
sw = (
struct
switch_stack
*)(((
unsigned
long
)sw + 15) & ~15);
80
81
unw_init_frame_info
(&bt->
frame
,
current
, sw);
82
83
/* skip over interrupt frame and oprofile calls */
84
do
{
85
unw_get_sp(&bt->
frame
, &sp);
86
if
(sp >= (
u_long
)bt->
regs
)
87
break
;
88
if
(!
next_frame
(bt))
89
return
;
90
}
while
(count++ < 200);
91
92
/* finally, grab the actual sample */
93
while
(bt->
depth
-- &&
next_frame
(bt)) {
94
unw_get_ip(&bt->
frame
, &pc);
95
oprofile_add_trace
(pc);
96
if
(
unw_is_intr_frame
(&bt->
frame
)) {
97
/*
98
* Interrupt received on kernel stack; this can
99
* happen when timer interrupt fires while processing
100
* a softirq from the tail end of a hardware interrupt
101
* which interrupted a system call. Don't laugh, it
102
* happens! Splice the backtrace into two parts to
103
* avoid spurious cycles in the gprof output.
104
*/
105
/* TODO: split rather than drop the 2nd half */
106
break
;
107
}
108
}
109
}
110
111
void
112
ia64_backtrace
(
struct
pt_regs
*
const
regs
,
unsigned
int
depth
)
113
{
114
ia64_backtrace_t
bt
;
115
unsigned
long
flags
;
116
117
/*
118
* On IA64 there is little hope of getting backtraces from
119
* user space programs -- the problems of getting the unwind
120
* information from arbitrary user programs are extreme.
121
*/
122
if
(
user_mode
(regs))
123
return
;
124
125
bt.
depth
=
depth
;
126
bt.
regs
=
regs
;
127
bt.
prev_pfs_loc
=
NULL
;
128
local_irq_save
(flags);
129
unw_init_running
(do_ia64_backtrace, &bt);
130
local_irq_restore
(flags);
131
}
Generated on Thu Jan 10 2013 13:04:03 for Linux Kernel by
1.8.2