1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
| /*
| * MIPS specific _mcount support
| *
| * This file is subject to the terms and conditions of the GNU General Public
| * License. See the file "COPYING" in the main directory of this archive for
| * more details.
| *
| * Copyright (C) 2009 Lemote Inc. & DSLab, Lanzhou University, China
| * Copyright (C) 2010 DSLab, Lanzhou University, China
| * Author: Wu Zhangjin <wuzhangjin@gmail.com>
| */
|
| #include <asm/export.h>
| #include <asm/regdef.h>
| #include <asm/stackframe.h>
| #include <asm/ftrace.h>
|
| .text
| .set noreorder
| .set noat
|
| .macro MCOUNT_SAVE_REGS
| PTR_SUBU sp, PT_SIZE
| PTR_S ra, PT_R31(sp)
| PTR_S AT, PT_R1(sp)
| PTR_S a0, PT_R4(sp)
| PTR_S a1, PT_R5(sp)
| PTR_S a2, PT_R6(sp)
| PTR_S a3, PT_R7(sp)
| #ifdef CONFIG_64BIT
| PTR_S a4, PT_R8(sp)
| PTR_S a5, PT_R9(sp)
| PTR_S a6, PT_R10(sp)
| PTR_S a7, PT_R11(sp)
| #endif
| .endm
|
| .macro MCOUNT_RESTORE_REGS
| PTR_L ra, PT_R31(sp)
| PTR_L AT, PT_R1(sp)
| PTR_L a0, PT_R4(sp)
| PTR_L a1, PT_R5(sp)
| PTR_L a2, PT_R6(sp)
| PTR_L a3, PT_R7(sp)
| #ifdef CONFIG_64BIT
| PTR_L a4, PT_R8(sp)
| PTR_L a5, PT_R9(sp)
| PTR_L a6, PT_R10(sp)
| PTR_L a7, PT_R11(sp)
| #endif
| PTR_ADDIU sp, PT_SIZE
| .endm
|
| .macro RETURN_BACK
| jr ra
| move ra, AT
| .endm
|
| /*
| * The -mmcount-ra-address option of gcc 4.5 uses register $12 to pass
| * the location of the parent's return address.
| */
| #define MCOUNT_RA_ADDRESS_REG $12
|
| #ifdef CONFIG_DYNAMIC_FTRACE
|
| NESTED(ftrace_caller, PT_SIZE, ra)
| .globl _mcount
| _mcount:
| EXPORT_SYMBOL(_mcount)
| b ftrace_stub
| #ifdef CONFIG_32BIT
| addiu sp,sp,8
| #else
| nop
| #endif
|
| /* When tracing is activated, it calls ftrace_caller+8 (aka here) */
| MCOUNT_SAVE_REGS
| #ifdef KBUILD_MCOUNT_RA_ADDRESS
| PTR_S MCOUNT_RA_ADDRESS_REG, PT_R12(sp)
| #endif
|
| PTR_SUBU a0, ra, 8 /* arg1: self address */
| PTR_LA t1, _stext
| sltu t2, a0, t1 /* t2 = (a0 < _stext) */
| PTR_LA t1, _etext
| sltu t3, t1, a0 /* t3 = (a0 > _etext) */
| or t1, t2, t3
| beqz t1, ftrace_call
| nop
| #if defined(KBUILD_MCOUNT_RA_ADDRESS) && defined(CONFIG_32BIT)
| PTR_SUBU a0, a0, 16 /* arg1: adjust to module's recorded callsite */
| #else
| PTR_SUBU a0, a0, 12
| #endif
|
| .globl ftrace_call
| ftrace_call:
| nop /* a placeholder for the call to a real tracing function */
| move a1, AT /* arg2: parent's return address */
|
| #ifdef CONFIG_FUNCTION_GRAPH_TRACER
| .globl ftrace_graph_call
| ftrace_graph_call:
| nop
| nop
| #endif
|
| MCOUNT_RESTORE_REGS
| .globl ftrace_stub
| ftrace_stub:
| RETURN_BACK
| END(ftrace_caller)
|
| #else /* ! CONFIG_DYNAMIC_FTRACE */
|
| NESTED(_mcount, PT_SIZE, ra)
| EXPORT_SYMBOL(_mcount)
| PTR_LA t1, ftrace_stub
| PTR_L t2, ftrace_trace_function /* Prepare t2 for (1) */
| beq t1, t2, fgraph_trace
| nop
|
| MCOUNT_SAVE_REGS
|
| move a0, ra /* arg1: self return address */
| jalr t2 /* (1) call *ftrace_trace_function */
| move a1, AT /* arg2: parent's return address */
|
| MCOUNT_RESTORE_REGS
|
| fgraph_trace:
| #ifdef CONFIG_FUNCTION_GRAPH_TRACER
| PTR_LA t1, ftrace_stub
| PTR_L t3, ftrace_graph_return
| bne t1, t3, ftrace_graph_caller
| nop
| PTR_LA t1, ftrace_graph_entry_stub
| PTR_L t3, ftrace_graph_entry
| bne t1, t3, ftrace_graph_caller
| nop
| #endif
|
| #ifdef CONFIG_32BIT
| addiu sp, sp, 8
| #endif
|
| .globl ftrace_stub
| ftrace_stub:
| RETURN_BACK
| END(_mcount)
|
| #endif /* ! CONFIG_DYNAMIC_FTRACE */
|
| #ifdef CONFIG_FUNCTION_GRAPH_TRACER
|
| NESTED(ftrace_graph_caller, PT_SIZE, ra)
| #ifndef CONFIG_DYNAMIC_FTRACE
| MCOUNT_SAVE_REGS
| #endif
|
| /* arg1: Get the location of the parent's return address */
| #ifdef KBUILD_MCOUNT_RA_ADDRESS
| #ifdef CONFIG_DYNAMIC_FTRACE
| PTR_L a0, PT_R12(sp)
| #else
| move a0, MCOUNT_RA_ADDRESS_REG
| #endif
| bnez a0, 1f /* non-leaf func: stored in MCOUNT_RA_ADDRESS_REG */
| nop
| #endif
| PTR_LA a0, PT_R1(sp) /* leaf func: the location in current stack */
| 1:
|
| /* arg2: Get self return address */
| #ifdef CONFIG_DYNAMIC_FTRACE
| PTR_L a1, PT_R31(sp)
| #else
| move a1, ra
| #endif
|
| /* arg3: Get frame pointer of current stack */
| #ifdef CONFIG_64BIT
| PTR_LA a2, PT_SIZE(sp)
| #else
| PTR_LA a2, (PT_SIZE+8)(sp)
| #endif
|
| jal prepare_ftrace_return
| nop
| MCOUNT_RESTORE_REGS
| #ifndef CONFIG_DYNAMIC_FTRACE
| #ifdef CONFIG_32BIT
| addiu sp, sp, 8
| #endif
| #endif
| RETURN_BACK
| END(ftrace_graph_caller)
|
| .align 2
| .globl return_to_handler
| return_to_handler:
| PTR_SUBU sp, PT_SIZE
| PTR_S v0, PT_R2(sp)
|
| jal ftrace_return_to_handler
| PTR_S v1, PT_R3(sp)
|
| /* restore the real parent address: v0 -> ra */
| move ra, v0
|
| PTR_L v0, PT_R2(sp)
| PTR_L v1, PT_R3(sp)
| jr ra
| PTR_ADDIU sp, PT_SIZE
| #endif /* CONFIG_FUNCTION_GRAPH_TRACER */
|
| .set at
| .set reorder
|
|