diff options
Diffstat (limited to 'kernel/trace/trace_functions_graph.c')
| -rw-r--r-- | kernel/trace/trace_functions_graph.c | 56 |
1 files changed, 53 insertions, 3 deletions
diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c index b5c09242683d..e08c030b8f38 100644 --- a/kernel/trace/trace_functions_graph.c +++ b/kernel/trace/trace_functions_graph.c | |||
| @@ -114,16 +114,37 @@ ftrace_push_return_trace(unsigned long ret, unsigned long func, int *depth, | |||
| 114 | return -EBUSY; | 114 | return -EBUSY; |
| 115 | } | 115 | } |
| 116 | 116 | ||
| 117 | /* | ||
| 118 | * The curr_ret_stack is an index to ftrace return stack of | ||
| 119 | * current task. Its value should be in [0, FTRACE_RETFUNC_ | ||
| 120 | * DEPTH) when the function graph tracer is used. To support | ||
| 121 | * filtering out specific functions, it makes the index | ||
| 122 | * negative by subtracting huge value (FTRACE_NOTRACE_DEPTH) | ||
| 123 | * so when it sees a negative index the ftrace will ignore | ||
| 124 | * the record. And the index gets recovered when returning | ||
| 125 | * from the filtered function by adding the FTRACE_NOTRACE_ | ||
| 126 | * DEPTH and then it'll continue to record functions normally. | ||
| 127 | * | ||
| 128 | * The curr_ret_stack is initialized to -1 and get increased | ||
| 129 | * in this function. So it can be less than -1 only if it was | ||
| 130 | * filtered out via ftrace_graph_notrace_addr() which can be | ||
| 131 | * set from set_graph_notrace file in debugfs by user. | ||
| 132 | */ | ||
| 133 | if (current->curr_ret_stack < -1) | ||
| 134 | return -EBUSY; | ||
| 135 | |||
| 117 | calltime = trace_clock_local(); | 136 | calltime = trace_clock_local(); |
| 118 | 137 | ||
| 119 | index = ++current->curr_ret_stack; | 138 | index = ++current->curr_ret_stack; |
| 139 | if (ftrace_graph_notrace_addr(func)) | ||
| 140 | current->curr_ret_stack -= FTRACE_NOTRACE_DEPTH; | ||
| 120 | barrier(); | 141 | barrier(); |
| 121 | current->ret_stack[index].ret = ret; | 142 | current->ret_stack[index].ret = ret; |
| 122 | current->ret_stack[index].func = func; | 143 | current->ret_stack[index].func = func; |
| 123 | current->ret_stack[index].calltime = calltime; | 144 | current->ret_stack[index].calltime = calltime; |
| 124 | current->ret_stack[index].subtime = 0; | 145 | current->ret_stack[index].subtime = 0; |
| 125 | current->ret_stack[index].fp = frame_pointer; | 146 | current->ret_stack[index].fp = frame_pointer; |
| 126 | *depth = index; | 147 | *depth = current->curr_ret_stack; |
| 127 | 148 | ||
| 128 | return 0; | 149 | return 0; |
| 129 | } | 150 | } |
| @@ -137,7 +158,17 @@ ftrace_pop_return_trace(struct ftrace_graph_ret *trace, unsigned long *ret, | |||
| 137 | 158 | ||
| 138 | index = current->curr_ret_stack; | 159 | index = current->curr_ret_stack; |
| 139 | 160 | ||
| 140 | if (unlikely(index < 0)) { | 161 | /* |
| 162 | * A negative index here means that it's just returned from a | ||
| 163 | * notrace'd function. Recover index to get an original | ||
| 164 | * return address. See ftrace_push_return_trace(). | ||
| 165 | * | ||
| 166 | * TODO: Need to check whether the stack gets corrupted. | ||
| 167 | */ | ||
| 168 | if (index < 0) | ||
| 169 | index += FTRACE_NOTRACE_DEPTH; | ||
| 170 | |||
| 171 | if (unlikely(index < 0 || index >= FTRACE_RETFUNC_DEPTH)) { | ||
| 141 | ftrace_graph_stop(); | 172 | ftrace_graph_stop(); |
| 142 | WARN_ON(1); | 173 | WARN_ON(1); |
| 143 | /* Might as well panic, otherwise we have no where to go */ | 174 | /* Might as well panic, otherwise we have no where to go */ |
| @@ -193,6 +224,15 @@ unsigned long ftrace_return_to_handler(unsigned long frame_pointer) | |||
| 193 | trace.rettime = trace_clock_local(); | 224 | trace.rettime = trace_clock_local(); |
| 194 | barrier(); | 225 | barrier(); |
| 195 | current->curr_ret_stack--; | 226 | current->curr_ret_stack--; |
| 227 | /* | ||
| 228 | * The curr_ret_stack can be less than -1 only if it was | ||
| 229 | * filtered out and it's about to return from the function. | ||
| 230 | * Recover the index and continue to trace normal functions. | ||
| 231 | */ | ||
| 232 | if (current->curr_ret_stack < -1) { | ||
| 233 | current->curr_ret_stack += FTRACE_NOTRACE_DEPTH; | ||
| 234 | return ret; | ||
| 235 | } | ||
| 196 | 236 | ||
| 197 | /* | 237 | /* |
| 198 | * The trace should run after decrementing the ret counter | 238 | * The trace should run after decrementing the ret counter |
| @@ -259,10 +299,20 @@ int trace_graph_entry(struct ftrace_graph_ent *trace) | |||
| 259 | 299 | ||
| 260 | /* trace it when it is-nested-in or is a function enabled. */ | 300 | /* trace it when it is-nested-in or is a function enabled. */ |
| 261 | if ((!(trace->depth || ftrace_graph_addr(trace->func)) || | 301 | if ((!(trace->depth || ftrace_graph_addr(trace->func)) || |
| 262 | ftrace_graph_ignore_irqs()) || | 302 | ftrace_graph_ignore_irqs()) || (trace->depth < 0) || |
| 263 | (max_depth && trace->depth >= max_depth)) | 303 | (max_depth && trace->depth >= max_depth)) |
| 264 | return 0; | 304 | return 0; |
| 265 | 305 | ||
| 306 | /* | ||
| 307 | * Do not trace a function if it's filtered by set_graph_notrace. | ||
| 308 | * Make the index of ret stack negative to indicate that it should | ||
| 309 | * ignore further functions. But it needs its own ret stack entry | ||
| 310 | * to recover the original index in order to continue tracing after | ||
| 311 | * returning from the function. | ||
| 312 | */ | ||
| 313 | if (ftrace_graph_notrace_addr(trace->func)) | ||
| 314 | return 1; | ||
| 315 | |||
| 266 | local_irq_save(flags); | 316 | local_irq_save(flags); |
| 267 | cpu = raw_smp_processor_id(); | 317 | cpu = raw_smp_processor_id(); |
| 268 | data = per_cpu_ptr(tr->trace_buffer.data, cpu); | 318 | data = per_cpu_ptr(tr->trace_buffer.data, cpu); |
