Skip to content

Commit 763e34e

Browse files
committed
ftrace: Add register_ftrace_direct()
Add the start of the functionality to allow other trampolines to use the ftrace mcount/fentry/nop location. This adds two new functions: register_ftrace_direct() and unregister_ftrace_direct() Both take two parameters: the first is the instruction address of where the mcount/fentry/nop exists, and the second is the trampoline to have that location called. This will handle cases where ftrace is already used on that same location, and will make it still work, where the registered direct called trampoline will get called after all the registered ftrace callers are handled. Currently, it will not allow for IP_MODIFY functions to be called at the same locations, which include some kprobes and live kernel patching. At this point, no architecture supports this. This is only the start of implementing the framework. Signed-off-by: Steven Rostedt (VMware) <[email protected]>
1 parent 7e16f58 commit 763e34e

File tree

3 files changed

+306
-7
lines changed

3 files changed

+306
-7
lines changed

include/linux/ftrace.h

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,8 @@ ftrace_func_t ftrace_ops_get_func(struct ftrace_ops *ops);
144144
* TRACE_ARRAY - The ops->private points to a trace_array descriptor.
145145
* PERMANENT - Set when the ops is permanent and should not be affected by
146146
* ftrace_enabled.
147+
* DIRECT - Used by the direct ftrace_ops helper for direct functions
148+
* (internal ftrace only, should not be used by others)
147149
*/
148150
enum {
149151
FTRACE_OPS_FL_ENABLED = 1 << 0,
@@ -163,6 +165,7 @@ enum {
163165
FTRACE_OPS_FL_RCU = 1 << 14,
164166
FTRACE_OPS_FL_TRACE_ARRAY = 1 << 15,
165167
FTRACE_OPS_FL_PERMANENT = 1 << 16,
168+
FTRACE_OPS_FL_DIRECT = 1 << 17,
166169
};
167170

168171
#ifdef CONFIG_DYNAMIC_FTRACE
@@ -242,6 +245,32 @@ static inline void ftrace_free_init_mem(void) { }
242245
static inline void ftrace_free_mem(struct module *mod, void *start, void *end) { }
243246
#endif /* CONFIG_FUNCTION_TRACER */
244247

248+
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
249+
int register_ftrace_direct(unsigned long ip, unsigned long addr);
250+
int unregister_ftrace_direct(unsigned long ip, unsigned long addr);
251+
#else
252+
static inline int register_ftrace_direct(unsigned long ip, unsigned long addr)
253+
{
254+
return -ENODEV;
255+
}
256+
static inline int unregister_ftrace_direct(unsigned long ip, unsigned long addr)
257+
{
258+
return -ENODEV;
259+
}
260+
#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
261+
262+
#ifndef CONFIG_HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
263+
/*
264+
* This must be implemented by the architecture.
265+
* It is the way the ftrace direct_ops helper, when called
266+
* via ftrace (because there's other callbacks besides the
267+
* direct call), can inform the architecture's trampoline that this
268+
* routine has a direct caller, and what the caller is.
269+
*/
270+
static inline void arch_ftrace_set_direct_caller(struct pt_regs *regs,
271+
unsigned long addr) { }
272+
#endif /* CONFIG_HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
273+
245274
#ifdef CONFIG_STACK_TRACER
246275

247276
extern int stack_tracer_enabled;
@@ -333,6 +362,7 @@ bool is_ftrace_trampoline(unsigned long addr);
333362
* REGS_EN - the function is set up to save regs.
334363
* IPMODIFY - the record allows for the IP address to be changed.
335364
* DISABLED - the record is not ready to be touched yet
365+
* DIRECT - there is a direct function to call
336366
*
337367
* When a new ftrace_ops is registered and wants a function to save
338368
* pt_regs, the rec->flag REGS is set. When the function has been
@@ -348,10 +378,12 @@ enum {
348378
FTRACE_FL_TRAMP_EN = (1UL << 27),
349379
FTRACE_FL_IPMODIFY = (1UL << 26),
350380
FTRACE_FL_DISABLED = (1UL << 25),
381+
FTRACE_FL_DIRECT = (1UL << 24),
382+
FTRACE_FL_DIRECT_EN = (1UL << 23),
351383
};
352384

353-
#define FTRACE_REF_MAX_SHIFT 25
354-
#define FTRACE_FL_BITS 7
385+
#define FTRACE_REF_MAX_SHIFT 23
386+
#define FTRACE_FL_BITS 9
355387
#define FTRACE_FL_MASKED_BITS ((1UL << FTRACE_FL_BITS) - 1)
356388
#define FTRACE_FL_MASK (FTRACE_FL_MASKED_BITS << FTRACE_REF_MAX_SHIFT)
357389
#define FTRACE_REF_MAX ((1UL << FTRACE_REF_MAX_SHIFT) - 1)

kernel/trace/Kconfig

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ config HAVE_DYNAMIC_FTRACE
3333
config HAVE_DYNAMIC_FTRACE_WITH_REGS
3434
bool
3535

36+
config HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
37+
bool
38+
3639
config HAVE_FTRACE_MCOUNT_RECORD
3740
bool
3841
help
@@ -557,6 +560,11 @@ config DYNAMIC_FTRACE_WITH_REGS
557560
depends on DYNAMIC_FTRACE
558561
depends on HAVE_DYNAMIC_FTRACE_WITH_REGS
559562

563+
config DYNAMIC_FTRACE_WITH_DIRECT_CALLS
564+
def_bool y
565+
depends on DYNAMIC_FTRACE
566+
depends on HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
567+
560568
config FUNCTION_PROFILER
561569
bool "Kernel function profiler"
562570
depends on FUNCTION_TRACER

0 commit comments

Comments
 (0)