diff options
author | Steven Rostedt <srostedt@redhat.com> | 2009-02-11 01:19:54 -0500 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2009-02-22 18:48:54 -0500 |
commit | 465428884765b43d642a967915e16c6c7cacbe8e (patch) | |
tree | bee656decba5598493b920efab53ec4ca95afa08 /arch/powerpc/kernel/ftrace.c | |
parent | 6794c78243bfda020ab184d6d578944f8e90d26c (diff) |
powerpc64, tracing: add function graph tracer with dynamic tracing
This is the port of the function graph tracer to PowerPC with
dynamic tracing.
Geoff Lavand tested on PS3.
Tested-by: Geoff Levand <geoffrey.levand@am.sony.com>
Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Steven Rostedt <srostedt@redhat.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/kernel/ftrace.c')
-rw-r--r-- | arch/powerpc/kernel/ftrace.c | 47 |
1 files changed, 41 insertions, 6 deletions
diff --git a/arch/powerpc/kernel/ftrace.c b/arch/powerpc/kernel/ftrace.c index c9b1547f65a5..7538b944fa52 100644 --- a/arch/powerpc/kernel/ftrace.c +++ b/arch/powerpc/kernel/ftrace.c | |||
@@ -43,7 +43,8 @@ static unsigned char *ftrace_nop_replace(void) | |||
43 | return (char *)&ftrace_nop; | 43 | return (char *)&ftrace_nop; |
44 | } | 44 | } |
45 | 45 | ||
46 | static unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr) | 46 | static unsigned char * |
47 | ftrace_call_replace(unsigned long ip, unsigned long addr, int link) | ||
47 | { | 48 | { |
48 | static unsigned int op; | 49 | static unsigned int op; |
49 | 50 | ||
@@ -55,8 +56,9 @@ static unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr) | |||
55 | */ | 56 | */ |
56 | addr = GET_ADDR(addr); | 57 | addr = GET_ADDR(addr); |
57 | 58 | ||
58 | /* Set to "bl addr" */ | 59 | /* if (link) set op to 'bl' else 'b' */ |
59 | op = 0x48000001 | (ftrace_calc_offset(ip, addr) & 0x03fffffc); | 60 | op = 0x48000000 | (link ? 1 : 0); |
61 | op |= (ftrace_calc_offset(ip, addr) & 0x03fffffc); | ||
60 | 62 | ||
61 | /* | 63 | /* |
62 | * No locking needed, this must be called via kstop_machine | 64 | * No locking needed, this must be called via kstop_machine |
@@ -344,7 +346,7 @@ int ftrace_make_nop(struct module *mod, | |||
344 | */ | 346 | */ |
345 | if (test_24bit_addr(ip, addr)) { | 347 | if (test_24bit_addr(ip, addr)) { |
346 | /* within range */ | 348 | /* within range */ |
347 | old = ftrace_call_replace(ip, addr); | 349 | old = ftrace_call_replace(ip, addr, 1); |
348 | new = ftrace_nop_replace(); | 350 | new = ftrace_nop_replace(); |
349 | return ftrace_modify_code(ip, old, new); | 351 | return ftrace_modify_code(ip, old, new); |
350 | } | 352 | } |
@@ -484,7 +486,7 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) | |||
484 | if (test_24bit_addr(ip, addr)) { | 486 | if (test_24bit_addr(ip, addr)) { |
485 | /* within range */ | 487 | /* within range */ |
486 | old = ftrace_nop_replace(); | 488 | old = ftrace_nop_replace(); |
487 | new = ftrace_call_replace(ip, addr); | 489 | new = ftrace_call_replace(ip, addr, 1); |
488 | return ftrace_modify_code(ip, old, new); | 490 | return ftrace_modify_code(ip, old, new); |
489 | } | 491 | } |
490 | 492 | ||
@@ -513,7 +515,7 @@ int ftrace_update_ftrace_func(ftrace_func_t func) | |||
513 | int ret; | 515 | int ret; |
514 | 516 | ||
515 | memcpy(old, &ftrace_call, MCOUNT_INSN_SIZE); | 517 | memcpy(old, &ftrace_call, MCOUNT_INSN_SIZE); |
516 | new = ftrace_call_replace(ip, (unsigned long)func); | 518 | new = ftrace_call_replace(ip, (unsigned long)func, 1); |
517 | ret = ftrace_modify_code(ip, old, new); | 519 | ret = ftrace_modify_code(ip, old, new); |
518 | 520 | ||
519 | return ret; | 521 | return ret; |
@@ -532,6 +534,39 @@ int __init ftrace_dyn_arch_init(void *data) | |||
532 | 534 | ||
533 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | 535 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER |
534 | 536 | ||
537 | #ifdef CONFIG_DYNAMIC_FTRACE | ||
538 | extern void ftrace_graph_call(void); | ||
539 | extern void ftrace_graph_stub(void); | ||
540 | |||
541 | int ftrace_enable_ftrace_graph_caller(void) | ||
542 | { | ||
543 | unsigned long ip = (unsigned long)(&ftrace_graph_call); | ||
544 | unsigned long addr = (unsigned long)(&ftrace_graph_caller); | ||
545 | unsigned long stub = (unsigned long)(&ftrace_graph_stub); | ||
546 | unsigned char old[MCOUNT_INSN_SIZE], *new; | ||
547 | |||
548 | new = ftrace_call_replace(ip, stub, 0); | ||
549 | memcpy(old, new, MCOUNT_INSN_SIZE); | ||
550 | new = ftrace_call_replace(ip, addr, 0); | ||
551 | |||
552 | return ftrace_modify_code(ip, old, new); | ||
553 | } | ||
554 | |||
555 | int ftrace_disable_ftrace_graph_caller(void) | ||
556 | { | ||
557 | unsigned long ip = (unsigned long)(&ftrace_graph_call); | ||
558 | unsigned long addr = (unsigned long)(&ftrace_graph_caller); | ||
559 | unsigned long stub = (unsigned long)(&ftrace_graph_stub); | ||
560 | unsigned char old[MCOUNT_INSN_SIZE], *new; | ||
561 | |||
562 | new = ftrace_call_replace(ip, addr, 0); | ||
563 | memcpy(old, new, MCOUNT_INSN_SIZE); | ||
564 | new = ftrace_call_replace(ip, stub, 0); | ||
565 | |||
566 | return ftrace_modify_code(ip, old, new); | ||
567 | } | ||
568 | #endif /* CONFIG_DYNAMIC_FTRACE */ | ||
569 | |||
535 | /* | 570 | /* |
536 | * Hook the return address and push it in the stack of return addrs | 571 | * Hook the return address and push it in the stack of return addrs |
537 | * in current thread info. | 572 | * in current thread info. |