|
@@ -284,6 +284,64 @@ unsigned long ftrace_return_to_handler(unsigned long frame_pointer)
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * ftrace_graph_ret_addr - convert a potentially modified stack return address
|
|
|
+ * to its original value
|
|
|
+ *
|
|
|
+ * This function can be called by stack unwinding code to convert a found stack
|
|
|
+ * return address ('ret') to its original value, in case the function graph
|
|
|
+ * tracer has modified it to be 'return_to_handler'. If the address hasn't
|
|
|
+ * been modified, the unchanged value of 'ret' is returned.
|
|
|
+ *
|
|
|
+ * 'idx' is a state variable which should be initialized by the caller to zero
|
|
|
+ * before the first call.
|
|
|
+ *
|
|
|
+ * 'retp' is a pointer to the return address on the stack. It's ignored if
|
|
|
+ * the arch doesn't have HAVE_FUNCTION_GRAPH_RET_ADDR_PTR defined.
|
|
|
+ */
|
|
|
+#ifdef HAVE_FUNCTION_GRAPH_RET_ADDR_PTR
|
|
|
+unsigned long ftrace_graph_ret_addr(struct task_struct *task, int *idx,
|
|
|
+ unsigned long ret, unsigned long *retp)
|
|
|
+{
|
|
|
+ int index = task->curr_ret_stack;
|
|
|
+ int i;
|
|
|
+
|
|
|
+ if (ret != (unsigned long)return_to_handler)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ if (index < -1)
|
|
|
+ index += FTRACE_NOTRACE_DEPTH;
|
|
|
+
|
|
|
+ if (index < 0)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ for (i = 0; i <= index; i++)
|
|
|
+ if (task->ret_stack[i].retp == retp)
|
|
|
+ return task->ret_stack[i].ret;
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+#else /* !HAVE_FUNCTION_GRAPH_RET_ADDR_PTR */
|
|
|
+unsigned long ftrace_graph_ret_addr(struct task_struct *task, int *idx,
|
|
|
+ unsigned long ret, unsigned long *retp)
|
|
|
+{
|
|
|
+ int task_idx;
|
|
|
+
|
|
|
+ if (ret != (unsigned long)return_to_handler)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ task_idx = task->curr_ret_stack;
|
|
|
+
|
|
|
+ if (!task->ret_stack || task_idx < *idx)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ task_idx -= *idx;
|
|
|
+ (*idx)++;
|
|
|
+
|
|
|
+ return task->ret_stack[task_idx].ret;
|
|
|
+}
|
|
|
+#endif /* HAVE_FUNCTION_GRAPH_RET_ADDR_PTR */
|
|
|
+
|
|
|
int __trace_graph_entry(struct trace_array *tr,
|
|
|
struct ftrace_graph_ent *trace,
|
|
|
unsigned long flags,
|