aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt <rostedt@goodmis.org>2008-11-26 00:16:24 -0500
committerIngo Molnar <mingo@elte.hu>2008-11-26 00:52:54 -0500
commit5a45cfe1c64862e8cd3b0d79d7c4ba71c3118915 (patch)
tree0a7edf3a9dc88d74b7c7053445ac8aff033a75fa
parentdf4fc31558dd2a3a30292ddb3a64c2a5befcec73 (diff)
ftrace: use code patching for ftrace graph tracer
Impact: more efficient code for ftrace graph tracer This patch uses the dynamic patching, when available, to patch the function graph code into the kernel. This patch will ease the way for letting both function tracing and function graph tracing run together. Signed-off-by: Steven Rostedt <srostedt@redhat.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
-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