/*1* Dynamic function tracer architecture backend.2*3* Copyright IBM Corp. 20094*5* Author(s): Heiko Carstens <[email protected]>,6* Martin Schwidefsky <[email protected]>7*/89#include <linux/hardirq.h>10#include <linux/uaccess.h>11#include <linux/ftrace.h>12#include <linux/kernel.h>13#include <linux/types.h>14#include <linux/kprobes.h>15#include <trace/syscall.h>16#include <asm/asm-offsets.h>1718#ifdef CONFIG_64BIT19#define MCOUNT_OFFSET_RET 1220#else21#define MCOUNT_OFFSET_RET 2222#endif2324#ifdef CONFIG_DYNAMIC_FTRACE2526void ftrace_disable_code(void);27void ftrace_enable_insn(void);2829#ifdef CONFIG_64BIT30/*31* The 64-bit mcount code looks like this:32* stg %r14,8(%r15) # offset 033* > larl %r1,<&counter> # offset 634* > brasl %r14,_mcount # offset 1235* lg %r14,8(%r15) # offset 1836* Total length is 24 bytes. The middle two instructions of the mcount37* block get overwritten by ftrace_make_nop / ftrace_make_call.38* The 64-bit enabled ftrace code block looks like this:39* stg %r14,8(%r15) # offset 040* > lg %r1,__LC_FTRACE_FUNC # offset 641* > lgr %r0,%r0 # offset 1242* > basr %r14,%r1 # offset 1643* lg %r14,8(%15) # offset 1844* The return points of the mcount/ftrace function have the same offset 18.45* The 64-bit disable ftrace code block looks like this:46* stg %r14,8(%r15) # offset 047* > jg .+18 # offset 648* > lgr %r0,%r0 # offset 1249* > basr %r14,%r1 # offset 1650* lg %r14,8(%15) # offset 1851* The jg instruction branches to offset 24 to skip as many instructions52* as possible.53*/54asm(55" .align 4\n"56"ftrace_disable_code:\n"57" jg 0f\n"58" lgr %r0,%r0\n"59" basr %r14,%r1\n"60"0:\n"61" .align 4\n"62"ftrace_enable_insn:\n"63" lg %r1,"__stringify(__LC_FTRACE_FUNC)"\n");6465#define FTRACE_INSN_SIZE 66667#else /* CONFIG_64BIT */68/*69* The 31-bit mcount code looks like this:70* st %r14,4(%r15) # offset 071* > bras %r1,0f # offset 472* > .long _mcount # offset 873* > .long <&counter> # offset 1274* > 0: l %r14,0(%r1) # offset 1675* > l %r1,4(%r1) # offset 2076* basr %r14,%r14 # offset 2477* l %r14,4(%r15) # offset 2678* Total length is 30 bytes. The twenty bytes starting from offset 479* to offset 24 get overwritten by ftrace_make_nop / ftrace_make_call.80* The 31-bit enabled ftrace code block looks like this:81* st %r14,4(%r15) # offset 082* > l %r14,__LC_FTRACE_FUNC # offset 483* > j 0f # offset 884* > .fill 12,1,0x07 # offset 1285* 0: basr %r14,%r14 # offset 2486* l %r14,4(%r14) # offset 2687* The return points of the mcount/ftrace function have the same offset 26.88* The 31-bit disabled ftrace code block looks like this:89* st %r14,4(%r15) # offset 090* > j .+26 # offset 491* > j 0f # offset 892* > .fill 12,1,0x07 # offset 1293* 0: basr %r14,%r14 # offset 2494* l %r14,4(%r14) # offset 2695* The j instruction branches to offset 30 to skip as many instructions96* as possible.97*/98asm(99" .align 4\n"100"ftrace_disable_code:\n"101" j 1f\n"102" j 0f\n"103" .fill 12,1,0x07\n"104"0: basr %r14,%r14\n"105"1:\n"106" .align 4\n"107"ftrace_enable_insn:\n"108" l %r14,"__stringify(__LC_FTRACE_FUNC)"\n");109110#define FTRACE_INSN_SIZE 4111112#endif /* CONFIG_64BIT */113114115int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,116unsigned long addr)117{118if (probe_kernel_write((void *) rec->ip, ftrace_disable_code,119MCOUNT_INSN_SIZE))120return -EPERM;121return 0;122}123124int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)125{126if (probe_kernel_write((void *) rec->ip, ftrace_enable_insn,127FTRACE_INSN_SIZE))128return -EPERM;129return 0;130}131132int ftrace_update_ftrace_func(ftrace_func_t func)133{134return 0;135}136137int __init ftrace_dyn_arch_init(void *data)138{139*(unsigned long *) data = 0;140return 0;141}142143#endif /* CONFIG_DYNAMIC_FTRACE */144145#ifdef CONFIG_FUNCTION_GRAPH_TRACER146/*147* Hook the return address and push it in the stack of return addresses148* in current thread info.149*/150unsigned long __kprobes prepare_ftrace_return(unsigned long parent,151unsigned long ip)152{153struct ftrace_graph_ent trace;154155if (unlikely(atomic_read(¤t->tracing_graph_pause)))156goto out;157if (ftrace_push_return_trace(parent, ip, &trace.depth, 0) == -EBUSY)158goto out;159trace.func = (ip & PSW_ADDR_INSN) - MCOUNT_OFFSET_RET;160/* Only trace if the calling function expects to. */161if (!ftrace_graph_entry(&trace)) {162current->curr_ret_stack--;163goto out;164}165parent = (unsigned long) return_to_handler;166out:167return parent;168}169170#ifdef CONFIG_DYNAMIC_FTRACE171/*172* Patch the kernel code at ftrace_graph_caller location. The instruction173* there is branch relative and save to prepare_ftrace_return. To disable174* the call to prepare_ftrace_return we patch the bras offset to point175* directly after the instructions. To enable the call we calculate176* the original offset to prepare_ftrace_return and put it back.177*/178int ftrace_enable_ftrace_graph_caller(void)179{180unsigned short offset;181182offset = ((void *) prepare_ftrace_return -183(void *) ftrace_graph_caller) / 2;184return probe_kernel_write(ftrace_graph_caller + 2,185&offset, sizeof(offset));186}187188int ftrace_disable_ftrace_graph_caller(void)189{190static unsigned short offset = 0x0002;191192return probe_kernel_write(ftrace_graph_caller + 2,193&offset, sizeof(offset));194}195196#endif /* CONFIG_DYNAMIC_FTRACE */197#endif /* CONFIG_FUNCTION_GRAPH_TRACER */198199200