]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - include/linux/ftrace.h
mm/memory_hotplug: export generic_online_page()
[linux.git] / include / linux / ftrace.h
index 8a8cb3c401b269600489e453ce8c9cbc65bcd86b..7247d35c3d160af210f35e07393fd04da361326b 100644 (file)
@@ -51,6 +51,7 @@ static inline void early_trace_init(void) { }
 
 struct module;
 struct ftrace_hash;
+struct ftrace_direct_func;
 
 #if defined(CONFIG_FUNCTION_TRACER) && defined(CONFIG_MODULES) && \
        defined(CONFIG_DYNAMIC_FTRACE)
@@ -142,24 +143,30 @@ ftrace_func_t ftrace_ops_get_func(struct ftrace_ops *ops);
  * PID     - Is affected by set_ftrace_pid (allows filtering on those pids)
  * RCU     - Set when the ops can only be called when RCU is watching.
  * TRACE_ARRAY - The ops->private points to a trace_array descriptor.
+ * PERMANENT - Set when the ops is permanent and should not be affected by
+ *             ftrace_enabled.
+ * DIRECT - Used by the direct ftrace_ops helper for direct functions
+ *            (internal ftrace only, should not be used by others)
  */
 enum {
-       FTRACE_OPS_FL_ENABLED                   = 1 << 0,
-       FTRACE_OPS_FL_DYNAMIC                   = 1 << 1,
-       FTRACE_OPS_FL_SAVE_REGS                 = 1 << 2,
-       FTRACE_OPS_FL_SAVE_REGS_IF_SUPPORTED    = 1 << 3,
-       FTRACE_OPS_FL_RECURSION_SAFE            = 1 << 4,
-       FTRACE_OPS_FL_STUB                      = 1 << 5,
-       FTRACE_OPS_FL_INITIALIZED               = 1 << 6,
-       FTRACE_OPS_FL_DELETED                   = 1 << 7,
-       FTRACE_OPS_FL_ADDING                    = 1 << 8,
-       FTRACE_OPS_FL_REMOVING                  = 1 << 9,
-       FTRACE_OPS_FL_MODIFYING                 = 1 << 10,
-       FTRACE_OPS_FL_ALLOC_TRAMP               = 1 << 11,
-       FTRACE_OPS_FL_IPMODIFY                  = 1 << 12,
-       FTRACE_OPS_FL_PID                       = 1 << 13,
-       FTRACE_OPS_FL_RCU                       = 1 << 14,
-       FTRACE_OPS_FL_TRACE_ARRAY               = 1 << 15,
+       FTRACE_OPS_FL_ENABLED                   = BIT(0),
+       FTRACE_OPS_FL_DYNAMIC                   = BIT(1),
+       FTRACE_OPS_FL_SAVE_REGS                 = BIT(2),
+       FTRACE_OPS_FL_SAVE_REGS_IF_SUPPORTED    = BIT(3),
+       FTRACE_OPS_FL_RECURSION_SAFE            = BIT(4),
+       FTRACE_OPS_FL_STUB                      = BIT(5),
+       FTRACE_OPS_FL_INITIALIZED               = BIT(6),
+       FTRACE_OPS_FL_DELETED                   = BIT(7),
+       FTRACE_OPS_FL_ADDING                    = BIT(8),
+       FTRACE_OPS_FL_REMOVING                  = BIT(9),
+       FTRACE_OPS_FL_MODIFYING                 = BIT(10),
+       FTRACE_OPS_FL_ALLOC_TRAMP               = BIT(11),
+       FTRACE_OPS_FL_IPMODIFY                  = BIT(12),
+       FTRACE_OPS_FL_PID                       = BIT(13),
+       FTRACE_OPS_FL_RCU                       = BIT(14),
+       FTRACE_OPS_FL_TRACE_ARRAY               = BIT(15),
+       FTRACE_OPS_FL_PERMANENT                 = BIT(16),
+       FTRACE_OPS_FL_DIRECT                    = BIT(17),
 };
 
 #ifdef CONFIG_DYNAMIC_FTRACE
@@ -239,6 +246,70 @@ static inline void ftrace_free_init_mem(void) { }
 static inline void ftrace_free_mem(struct module *mod, void *start, void *end) { }
 #endif /* CONFIG_FUNCTION_TRACER */
 
+struct ftrace_func_entry {
+       struct hlist_node hlist;
+       unsigned long ip;
+       unsigned long direct; /* for direct lookup only */
+};
+
+struct dyn_ftrace;
+
+#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
+extern int ftrace_direct_func_count;
+int register_ftrace_direct(unsigned long ip, unsigned long addr);
+int unregister_ftrace_direct(unsigned long ip, unsigned long addr);
+int modify_ftrace_direct(unsigned long ip, unsigned long old_addr, unsigned long new_addr);
+struct ftrace_direct_func *ftrace_find_direct_func(unsigned long addr);
+int ftrace_modify_direct_caller(struct ftrace_func_entry *entry,
+                               struct dyn_ftrace *rec,
+                               unsigned long old_addr,
+                               unsigned long new_addr);
+#else
+# define ftrace_direct_func_count 0
+static inline int register_ftrace_direct(unsigned long ip, unsigned long addr)
+{
+       return -ENOTSUPP;
+}
+static inline int unregister_ftrace_direct(unsigned long ip, unsigned long addr)
+{
+       return -ENOTSUPP;
+}
+static inline int modify_ftrace_direct(unsigned long ip,
+                                      unsigned long old_addr, unsigned long new_addr)
+{
+       return -ENOTSUPP;
+}
+static inline struct ftrace_direct_func *ftrace_find_direct_func(unsigned long addr)
+{
+       return NULL;
+}
+static inline int ftrace_modify_direct_caller(struct ftrace_func_entry *entry,
+                                             struct dyn_ftrace *rec,
+                                             unsigned long old_addr,
+                                             unsigned long new_addr)
+{
+       return -ENODEV;
+}
+#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
+
+#ifndef CONFIG_HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
+/*
+ * This must be implemented by the architecture.
+ * It is the way the ftrace direct_ops helper, when called
+ * via ftrace (because there's other callbacks besides the
+ * direct call), can inform the architecture's trampoline that this
+ * routine has a direct caller, and what the caller is.
+ *
+ * For example, in x86, it returns the direct caller
+ * callback function via the regs->orig_ax parameter.
+ * Then in the ftrace trampoline, if this is set, it makes
+ * the return from the trampoline jump to the direct caller
+ * instead of going back to the function it just traced.
+ */
+static inline void arch_ftrace_set_direct_caller(struct pt_regs *regs,
+                                                unsigned long addr) { }
+#endif /* CONFIG_HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
+
 #ifdef CONFIG_STACK_TRACER
 
 extern int stack_tracer_enabled;
@@ -291,8 +362,6 @@ static inline void stack_tracer_enable(void) { }
 int ftrace_arch_code_modify_prepare(void);
 int ftrace_arch_code_modify_post_process(void);
 
-struct dyn_ftrace;
-
 enum ftrace_bug_type {
        FTRACE_BUG_UNKNOWN,
        FTRACE_BUG_INIT,
@@ -330,6 +399,7 @@ bool is_ftrace_trampoline(unsigned long addr);
  *  REGS_EN - the function is set up to save regs.
  *  IPMODIFY - the record allows for the IP address to be changed.
  *  DISABLED - the record is not ready to be touched yet
+ *  DIRECT   - there is a direct function to call
  *
  * When a new ftrace_ops is registered and wants a function to save
  * pt_regs, the rec->flag REGS is set. When the function has been
@@ -345,10 +415,12 @@ enum {
        FTRACE_FL_TRAMP_EN      = (1UL << 27),
        FTRACE_FL_IPMODIFY      = (1UL << 26),
        FTRACE_FL_DISABLED      = (1UL << 25),
+       FTRACE_FL_DIRECT        = (1UL << 24),
+       FTRACE_FL_DIRECT_EN     = (1UL << 23),
 };
 
-#define FTRACE_REF_MAX_SHIFT   25
-#define FTRACE_FL_BITS         7
+#define FTRACE_REF_MAX_SHIFT   23
+#define FTRACE_FL_BITS         9
 #define FTRACE_FL_MASKED_BITS  ((1UL << FTRACE_FL_BITS) - 1)
 #define FTRACE_FL_MASK         (FTRACE_FL_MASKED_BITS << FTRACE_REF_MAX_SHIFT)
 #define FTRACE_REF_MAX         ((1UL << FTRACE_REF_MAX_SHIFT) - 1)
@@ -499,7 +571,7 @@ static inline int ftrace_disable_ftrace_graph_caller(void) { return 0; }
 /**
  * ftrace_make_nop - convert code into nop
  * @mod: module structure if called by module load initialization
- * @rec: the mcount call site record
+ * @rec: the call site record (e.g. mcount/fentry)
  * @addr: the address that the call site should be calling
  *
  * This is a very sensitive operation and great care needs
@@ -520,9 +592,38 @@ static inline int ftrace_disable_ftrace_graph_caller(void) { return 0; }
 extern int ftrace_make_nop(struct module *mod,
                           struct dyn_ftrace *rec, unsigned long addr);
 
+
+/**
+ * ftrace_init_nop - initialize a nop call site
+ * @mod: module structure if called by module load initialization
+ * @rec: the call site record (e.g. mcount/fentry)
+ *
+ * This is a very sensitive operation and great care needs
+ * to be taken by the arch.  The operation should carefully
+ * read the location, check to see if what is read is indeed
+ * what we expect it to be, and then on success of the compare,
+ * it should write to the location.
+ *
+ * The code segment at @rec->ip should contain the contents created by
+ * the compiler
+ *
+ * Return must be:
+ *  0 on success
+ *  -EFAULT on error reading the location
+ *  -EINVAL on a failed compare of the contents
+ *  -EPERM  on error writing to the location
+ * Any other value will be considered a failure.
+ */
+#ifndef ftrace_init_nop
+static inline int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec)
+{
+       return ftrace_make_nop(mod, rec, MCOUNT_ADDR);
+}
+#endif
+
 /**
  * ftrace_make_call - convert a nop call site into a call to addr
- * @rec: the mcount call site record
+ * @rec: the call site record (e.g. mcount/fentry)
  * @addr: the address that the call site should call
  *
  * This is a very sensitive operation and great care needs
@@ -545,7 +646,7 @@ extern int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr);
 #ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
 /**
  * ftrace_modify_call - convert from one addr to another (no nop)
- * @rec: the mcount call site record
+ * @rec: the call site record (e.g. mcount/fentry)
  * @old_addr: the address expected to be currently called to
  * @addr: the address to change to
  *
@@ -709,6 +810,11 @@ static inline unsigned long get_lock_parent_ip(void)
 
 #ifdef CONFIG_FTRACE_MCOUNT_RECORD
 extern void ftrace_init(void);
+#ifdef CC_USING_PATCHABLE_FUNCTION_ENTRY
+#define FTRACE_CALLSITE_SECTION        "__patchable_function_entries"
+#else
+#define FTRACE_CALLSITE_SECTION        "__mcount_loc"
+#endif
 #else
 static inline void ftrace_init(void) { }
 #endif