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