aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/kernel/entry_32.S5
-rw-r--r--arch/x86/kernel/ftrace.c48
-rw-r--r--include/linux/ftrace.h5
-rw-r--r--kernel/trace/ftrace.c35
4 files changed, 72 insertions, 21 deletions
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S
index 7def9fd5c1e6..958af86186c4 100644
--- a/arch/x86/kernel/entry_32.S
+++ b/arch/x86/kernel/entry_32.S
@@ -1174,6 +1174,11 @@ ftrace_call:
1174 popl %edx 1174 popl %edx
1175 popl %ecx 1175 popl %ecx
1176 popl %eax 1176 popl %eax
1177#ifdef CONFIG_FUNCTION_GRAPH_TRACER
1178.globl ftrace_graph_call
1179ftrace_graph_call:
1180 jmp ftrace_stub
1181#endif
1177 1182
1178.globl ftrace_stub 1183.globl ftrace_stub
1179ftrace_stub: 1184ftrace_stub:
diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c
index 26b2d92d48b3..7ef914e6a2f6 100644
--- a/arch/x86/kernel/ftrace.c
+++ b/arch/x86/kernel/ftrace.c
@@ -111,7 +111,6 @@ static void ftrace_mod_code(void)
111 */ 111 */
112 mod_code_status = probe_kernel_write(mod_code_ip, mod_code_newcode, 112 mod_code_status = probe_kernel_write(mod_code_ip, mod_code_newcode,
113 MCOUNT_INSN_SIZE); 113 MCOUNT_INSN_SIZE);
114
115} 114}
116 115
117void ftrace_nmi_enter(void) 116void ftrace_nmi_enter(void)
@@ -325,7 +324,51 @@ int __init ftrace_dyn_arch_init(void *data)
325 324
326#ifdef CONFIG_FUNCTION_GRAPH_TRACER 325#ifdef CONFIG_FUNCTION_GRAPH_TRACER
327 326
328#ifndef CONFIG_DYNAMIC_FTRACE 327#ifdef CONFIG_DYNAMIC_FTRACE
328extern void ftrace_graph_call(void);
329
330static int ftrace_mod_jmp(unsigned long ip,
331 int old_offset, int new_offset)
332{
333 unsigned char code[MCOUNT_INSN_SIZE];
334
335 if (probe_kernel_read(code, (void *)ip, MCOUNT_INSN_SIZE))
336 return -EFAULT;
337
338 if (code[0] != 0xe9 || old_offset != *(int *)(&code[1]))
339 return -EINVAL;
340
341 *(int *)(&code[1]) = new_offset;
342
343 if (do_ftrace_mod_code(ip, &code))
344 return -EPERM;
345
346 return 0;
347}
348
349int ftrace_enable_ftrace_graph_caller(void)
350{
351 unsigned long ip = (unsigned long)(&ftrace_graph_call);
352 int old_offset, new_offset;
353
354 old_offset = (unsigned long)(&ftrace_stub) - (ip + MCOUNT_INSN_SIZE);
355 new_offset = (unsigned long)(&ftrace_graph_caller) - (ip + MCOUNT_INSN_SIZE);
356
357 return ftrace_mod_jmp(ip, old_offset, new_offset);
358}
359
360int ftrace_disable_ftrace_graph_caller(void)
361{
362 unsigned long ip = (unsigned long)(&ftrace_graph_call);
363 int old_offset, new_offset;
364
365 old_offset = (unsigned long)(&ftrace_graph_caller) - (ip + MCOUNT_INSN_SIZE);
366 new_offset = (unsigned long)(&ftrace_stub) - (ip + MCOUNT_INSN_SIZE);
367
368 return ftrace_mod_jmp(ip, old_offset, new_offset);
369}
370
371#else /* CONFIG_DYNAMIC_FTRACE */
329 372
330/* 373/*
331 * These functions are picked from those used on 374 * These functions are picked from those used on
@@ -343,6 +386,7 @@ void ftrace_nmi_exit(void)
343{ 386{
344 atomic_dec(&in_nmi); 387 atomic_dec(&in_nmi);
345} 388}
389
346#endif /* !CONFIG_DYNAMIC_FTRACE */ 390#endif /* !CONFIG_DYNAMIC_FTRACE */
347 391
348/* Add a function return address to the trace stack on thread info.*/ 392/* Add a function return address to the trace stack on thread info.*/
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index fc2d54987198..f9792c0d73f6 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -117,6 +117,11 @@ extern void ftrace_call(void);
117extern void mcount_call(void); 117extern void mcount_call(void);
118#ifdef CONFIG_FUNCTION_GRAPH_TRACER 118#ifdef CONFIG_FUNCTION_GRAPH_TRACER
119extern void ftrace_graph_caller(void); 119extern void ftrace_graph_caller(void);
120extern int ftrace_enable_ftrace_graph_caller(void);
121extern int ftrace_disable_ftrace_graph_caller(void);
122#else
123static inline int ftrace_enable_ftrace_graph_caller(void) { return 0; }
124static inline int ftrace_disable_ftrace_graph_caller(void) { return 0; }
120#endif 125#endif
121 126
122/** 127/**
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 00d98c65fad0..5f7c8642d58b 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -281,6 +281,8 @@ enum {
281 FTRACE_UPDATE_TRACE_FUNC = (1 << 2), 281 FTRACE_UPDATE_TRACE_FUNC = (1 << 2),
282 FTRACE_ENABLE_MCOUNT = (1 << 3), 282 FTRACE_ENABLE_MCOUNT = (1 << 3),
283 FTRACE_DISABLE_MCOUNT = (1 << 4), 283 FTRACE_DISABLE_MCOUNT = (1 << 4),
284 FTRACE_START_FUNC_RET = (1 << 5),
285 FTRACE_STOP_FUNC_RET = (1 << 6),
284}; 286};
285 287
286static int ftrace_filtered; 288static int ftrace_filtered;
@@ -465,14 +467,7 @@ __ftrace_replace_code(struct dyn_ftrace *rec, int enable)
465 unsigned long ip, fl; 467 unsigned long ip, fl;
466 unsigned long ftrace_addr; 468 unsigned long ftrace_addr;
467 469
468#ifdef CONFIG_FUNCTION_GRAPH_TRACER
469 if (ftrace_tracing_type == FTRACE_TYPE_ENTER)
470 ftrace_addr = (unsigned long)ftrace_caller;
471 else
472 ftrace_addr = (unsigned long)ftrace_graph_caller;
473#else
474 ftrace_addr = (unsigned long)ftrace_caller; 470 ftrace_addr = (unsigned long)ftrace_caller;
475#endif
476 471
477 ip = rec->ip; 472 ip = rec->ip;
478 473
@@ -605,6 +600,11 @@ static int __ftrace_modify_code(void *data)
605 if (*command & FTRACE_UPDATE_TRACE_FUNC) 600 if (*command & FTRACE_UPDATE_TRACE_FUNC)
606 ftrace_update_ftrace_func(ftrace_trace_function); 601 ftrace_update_ftrace_func(ftrace_trace_function);
607 602
603 if (*command & FTRACE_START_FUNC_RET)
604 ftrace_enable_ftrace_graph_caller();
605 else if (*command & FTRACE_STOP_FUNC_RET)
606 ftrace_disable_ftrace_graph_caller();
607
608 return 0; 608 return 0;
609} 609}
610 610
@@ -629,10 +629,8 @@ static void ftrace_startup_enable(int command)
629 ftrace_run_update_code(command); 629 ftrace_run_update_code(command);
630} 630}
631 631
632static void ftrace_startup(void) 632static void ftrace_startup(int command)
633{ 633{
634 int command = 0;
635
636 if (unlikely(ftrace_disabled)) 634 if (unlikely(ftrace_disabled))
637 return; 635 return;
638 636
@@ -645,10 +643,8 @@ static void ftrace_startup(void)
645 mutex_unlock(&ftrace_start_lock); 643 mutex_unlock(&ftrace_start_lock);
646} 644}
647 645
648static void ftrace_shutdown(void) 646static void ftrace_shutdown(int command)
649{ 647{
650 int command = 0;
651
652 if (unlikely(ftrace_disabled)) 648 if (unlikely(ftrace_disabled))
653 return; 649 return;
654 650
@@ -1453,8 +1449,9 @@ device_initcall(ftrace_nodyn_init);
1453 1449
1454static inline int ftrace_init_dyn_debugfs(struct dentry *d_tracer) { return 0; } 1450static inline int ftrace_init_dyn_debugfs(struct dentry *d_tracer) { return 0; }
1455static inline void ftrace_startup_enable(int command) { } 1451static inline void ftrace_startup_enable(int command) { }
1456# define ftrace_startup() do { } while (0) 1452/* Keep as macros so we do not need to define the commands */
1457# define ftrace_shutdown() do { } while (0) 1453# define ftrace_startup(command) do { } while (0)
1454# define ftrace_shutdown(command) do { } while (0)
1458# define ftrace_startup_sysctl() do { } while (0) 1455# define ftrace_startup_sysctl() do { } while (0)
1459# define ftrace_shutdown_sysctl() do { } while (0) 1456# define ftrace_shutdown_sysctl() do { } while (0)
1460#endif /* CONFIG_DYNAMIC_FTRACE */ 1457#endif /* CONFIG_DYNAMIC_FTRACE */
@@ -1585,7 +1582,7 @@ int register_ftrace_function(struct ftrace_ops *ops)
1585 } 1582 }
1586 1583
1587 ret = __register_ftrace_function(ops); 1584 ret = __register_ftrace_function(ops);
1588 ftrace_startup(); 1585 ftrace_startup(0);
1589 1586
1590out: 1587out:
1591 mutex_unlock(&ftrace_sysctl_lock); 1588 mutex_unlock(&ftrace_sysctl_lock);
@@ -1604,7 +1601,7 @@ int unregister_ftrace_function(struct ftrace_ops *ops)
1604 1601
1605 mutex_lock(&ftrace_sysctl_lock); 1602 mutex_lock(&ftrace_sysctl_lock);
1606 ret = __unregister_ftrace_function(ops); 1603 ret = __unregister_ftrace_function(ops);
1607 ftrace_shutdown(); 1604 ftrace_shutdown(0);
1608 mutex_unlock(&ftrace_sysctl_lock); 1605 mutex_unlock(&ftrace_sysctl_lock);
1609 1606
1610 return ret; 1607 return ret;
@@ -1751,7 +1748,7 @@ int register_ftrace_graph(trace_func_graph_ret_t retfunc,
1751 ftrace_tracing_type = FTRACE_TYPE_RETURN; 1748 ftrace_tracing_type = FTRACE_TYPE_RETURN;
1752 ftrace_graph_return = retfunc; 1749 ftrace_graph_return = retfunc;
1753 ftrace_graph_entry = entryfunc; 1750 ftrace_graph_entry = entryfunc;
1754 ftrace_startup(); 1751 ftrace_startup(FTRACE_START_FUNC_RET);
1755 1752
1756out: 1753out:
1757 mutex_unlock(&ftrace_sysctl_lock); 1754 mutex_unlock(&ftrace_sysctl_lock);
@@ -1765,7 +1762,7 @@ void unregister_ftrace_graph(void)
1765 atomic_dec(&ftrace_graph_active); 1762 atomic_dec(&ftrace_graph_active);
1766 ftrace_graph_return = (trace_func_graph_ret_t)ftrace_stub; 1763 ftrace_graph_return = (trace_func_graph_ret_t)ftrace_stub;
1767 ftrace_graph_entry = (trace_func_graph_ent_t)ftrace_stub; 1764 ftrace_graph_entry = (trace_func_graph_ent_t)ftrace_stub;
1768 ftrace_shutdown(); 1765 ftrace_shutdown(FTRACE_STOP_FUNC_RET);
1769 /* Restore normal tracing type */ 1766 /* Restore normal tracing type */
1770 ftrace_tracing_type = FTRACE_TYPE_ENTER; 1767 ftrace_tracing_type = FTRACE_TYPE_ENTER;
1771 1768