1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2d75f054aSHelge Deller /*
3d75f054aSHelge Deller * Code for tracing calls in Linux kernel.
4366dd4eaSHelge Deller * Copyright (C) 2009-2016 Helge Deller <deller@gmx.de>
5d75f054aSHelge Deller *
6d75f054aSHelge Deller * based on code for x86 which is:
7d75f054aSHelge Deller * Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com>
8d75f054aSHelge Deller *
9d75f054aSHelge Deller * future possible enhancements:
10d75f054aSHelge Deller * - add CONFIG_STACK_TRACER
11d75f054aSHelge Deller */
12d75f054aSHelge Deller
13d75f054aSHelge Deller #include <linux/init.h>
14d75f054aSHelge Deller #include <linux/ftrace.h>
156ca63662SSven Schnelle #include <linux/uaccess.h>
1652a22e6cSSven Schnelle #include <linux/kprobes.h>
1752a22e6cSSven Schnelle #include <linux/ptrace.h>
1898f29261SSven Schnelle #include <linux/jump_label.h>
19d75f054aSHelge Deller
20366dd4eaSHelge Deller #include <asm/assembly.h>
21d75f054aSHelge Deller #include <asm/sections.h>
22d75f054aSHelge Deller #include <asm/ftrace.h>
236ca63662SSven Schnelle #include <asm/patch.h>
24d75f054aSHelge Deller
2533def849SJoe Perches #define __hot __section(".text.hot")
264df3c9ecSHelge Deller
27d75f054aSHelge Deller #ifdef CONFIG_FUNCTION_GRAPH_TRACER
2898f29261SSven Schnelle static DEFINE_STATIC_KEY_FALSE(ftrace_graph_enable);
2998f29261SSven Schnelle
30d75f054aSHelge Deller /*
31d75f054aSHelge Deller * Hook the return address and push it in the stack of return addrs
32d75f054aSHelge Deller * in current thread info.
33d75f054aSHelge Deller */
prepare_ftrace_return(unsigned long * parent,unsigned long self_addr)344df3c9ecSHelge Deller static void __hot prepare_ftrace_return(unsigned long *parent,
354df3c9ecSHelge Deller unsigned long self_addr)
36d75f054aSHelge Deller {
37d75f054aSHelge Deller unsigned long old;
38366dd4eaSHelge Deller extern int parisc_return_to_handler;
39d75f054aSHelge Deller
403a46588eSSteven Rostedt (Red Hat) if (unlikely(ftrace_graph_is_dead()))
413a46588eSSteven Rostedt (Red Hat) return;
423a46588eSSteven Rostedt (Red Hat)
43d75f054aSHelge Deller if (unlikely(atomic_read(¤t->tracing_graph_pause)))
44d75f054aSHelge Deller return;
45d75f054aSHelge Deller
46d75f054aSHelge Deller old = *parent;
47d75f054aSHelge Deller
48a87532c7SSteven Rostedt (VMware) if (!function_graph_enter(old, self_addr, 0, NULL))
49366dd4eaSHelge Deller /* activate parisc_return_to_handler() as return point */
50366dd4eaSHelge Deller *parent = (unsigned long) &parisc_return_to_handler;
51366dd4eaSHelge Deller }
52d75f054aSHelge Deller #endif /* CONFIG_FUNCTION_GRAPH_TRACER */
53d75f054aSHelge Deller
5444382af8SSven Schnelle static ftrace_func_t ftrace_func;
5544382af8SSven Schnelle
ftrace_function_trampoline(unsigned long parent,unsigned long self_addr,unsigned long org_sp_gr3,struct ftrace_regs * fregs)562794f8ecSHelge Deller asmlinkage void notrace __hot ftrace_function_trampoline(unsigned long parent,
57d75f054aSHelge Deller unsigned long self_addr,
5852a22e6cSSven Schnelle unsigned long org_sp_gr3,
59d19ad077SSteven Rostedt (VMware) struct ftrace_regs *fregs)
60d75f054aSHelge Deller {
61d562aca3SSven Schnelle extern struct ftrace_ops *function_trace_op;
62d562aca3SSven Schnelle
6344382af8SSven Schnelle ftrace_func(self_addr, parent, function_trace_op, fregs);
64366dd4eaSHelge Deller
65d75f054aSHelge Deller #ifdef CONFIG_FUNCTION_GRAPH_TRACER
6698f29261SSven Schnelle if (static_branch_unlikely(&ftrace_graph_enable)) {
67d75f054aSHelge Deller unsigned long *parent_rp;
68d75f054aSHelge Deller
69d75f054aSHelge Deller /* calculate pointer to %rp in stack */
70366dd4eaSHelge Deller parent_rp = (unsigned long *) (org_sp_gr3 - RP_OFFSET);
71d75f054aSHelge Deller /* sanity check: parent_rp should hold parent */
72d75f054aSHelge Deller if (*parent_rp != parent)
73d75f054aSHelge Deller return;
74d75f054aSHelge Deller
75d75f054aSHelge Deller prepare_ftrace_return(parent_rp, self_addr);
76d75f054aSHelge Deller return;
77d75f054aSHelge Deller }
78d75f054aSHelge Deller #endif
79d75f054aSHelge Deller }
80d75f054aSHelge Deller
813a28164dSMax Kellermann #if defined(CONFIG_DYNAMIC_FTRACE) && defined(CONFIG_FUNCTION_GRAPH_TRACER)
ftrace_enable_ftrace_graph_caller(void)826ca63662SSven Schnelle int ftrace_enable_ftrace_graph_caller(void)
836ca63662SSven Schnelle {
8498f29261SSven Schnelle static_key_enable(&ftrace_graph_enable.key);
856ca63662SSven Schnelle return 0;
866ca63662SSven Schnelle }
876ca63662SSven Schnelle
ftrace_disable_ftrace_graph_caller(void)886ca63662SSven Schnelle int ftrace_disable_ftrace_graph_caller(void)
896ca63662SSven Schnelle {
90*9665bbefSJosh Poimboeuf static_key_disable(&ftrace_graph_enable.key);
916ca63662SSven Schnelle return 0;
926ca63662SSven Schnelle }
936ca63662SSven Schnelle #endif
946ca63662SSven Schnelle
956ca63662SSven Schnelle #ifdef CONFIG_DYNAMIC_FTRACE
ftrace_update_ftrace_func(ftrace_func_t func)966ca63662SSven Schnelle int ftrace_update_ftrace_func(ftrace_func_t func)
976ca63662SSven Schnelle {
9844382af8SSven Schnelle ftrace_func = func;
996ca63662SSven Schnelle return 0;
1006ca63662SSven Schnelle }
1016ca63662SSven Schnelle
ftrace_modify_call(struct dyn_ftrace * rec,unsigned long old_addr,unsigned long addr)10252a22e6cSSven Schnelle int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
10352a22e6cSSven Schnelle unsigned long addr)
10452a22e6cSSven Schnelle {
10552a22e6cSSven Schnelle return 0;
10652a22e6cSSven Schnelle }
10752a22e6cSSven Schnelle
ftrace_call_adjust(unsigned long addr)1086ca63662SSven Schnelle unsigned long ftrace_call_adjust(unsigned long addr)
1096ca63662SSven Schnelle {
1106ca63662SSven Schnelle return addr+(FTRACE_PATCHABLE_FUNCTION_SIZE-1)*4;
1116ca63662SSven Schnelle }
1126ca63662SSven Schnelle
ftrace_make_call(struct dyn_ftrace * rec,unsigned long addr)1136ca63662SSven Schnelle int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
1146ca63662SSven Schnelle {
1156ca63662SSven Schnelle u32 insn[FTRACE_PATCHABLE_FUNCTION_SIZE];
1166ca63662SSven Schnelle u32 *tramp;
1176ca63662SSven Schnelle int size, ret, i;
1186ca63662SSven Schnelle void *ip;
1196ca63662SSven Schnelle
1206ca63662SSven Schnelle #ifdef CONFIG_64BIT
1216ca63662SSven Schnelle unsigned long addr2 =
1226ca63662SSven Schnelle (unsigned long)dereference_function_descriptor((void *)addr);
1236ca63662SSven Schnelle
1246ca63662SSven Schnelle u32 ftrace_trampoline[] = {
1256ca63662SSven Schnelle 0x73c10208, /* std,ma r1,100(sp) */
1266ca63662SSven Schnelle 0x0c2110c1, /* ldd -10(r1),r1 */
1276ca63662SSven Schnelle 0xe820d002, /* bve,n (r1) */
1286ca63662SSven Schnelle addr2 >> 32,
1296ca63662SSven Schnelle addr2 & 0xffffffff,
1306ca63662SSven Schnelle 0xe83f1fd7, /* b,l,n .-14,r1 */
1316ca63662SSven Schnelle };
1326ca63662SSven Schnelle
1336ca63662SSven Schnelle u32 ftrace_trampoline_unaligned[] = {
1346ca63662SSven Schnelle addr2 >> 32,
1356ca63662SSven Schnelle addr2 & 0xffffffff,
1366ca63662SSven Schnelle 0x37de0200, /* ldo 100(sp),sp */
1376ca63662SSven Schnelle 0x73c13e01, /* std r1,-100(sp) */
1386ca63662SSven Schnelle 0x34213ff9, /* ldo -4(r1),r1 */
1396ca63662SSven Schnelle 0x50213fc1, /* ldd -20(r1),r1 */
1406ca63662SSven Schnelle 0xe820d002, /* bve,n (r1) */
1416ca63662SSven Schnelle 0xe83f1fcf, /* b,l,n .-20,r1 */
1426ca63662SSven Schnelle };
1436ca63662SSven Schnelle
1446ca63662SSven Schnelle BUILD_BUG_ON(ARRAY_SIZE(ftrace_trampoline_unaligned) >
1456ca63662SSven Schnelle FTRACE_PATCHABLE_FUNCTION_SIZE);
1466ca63662SSven Schnelle #else
1476ca63662SSven Schnelle u32 ftrace_trampoline[] = {
1486ca63662SSven Schnelle (u32)addr,
1496ca63662SSven Schnelle 0x6fc10080, /* stw,ma r1,40(sp) */
1506ca63662SSven Schnelle 0x48213fd1, /* ldw -18(r1),r1 */
1516ca63662SSven Schnelle 0xe820c002, /* bv,n r0(r1) */
1526ca63662SSven Schnelle 0xe83f1fdf, /* b,l,n .-c,r1 */
1536ca63662SSven Schnelle };
1546ca63662SSven Schnelle #endif
1556ca63662SSven Schnelle
1566ca63662SSven Schnelle BUILD_BUG_ON(ARRAY_SIZE(ftrace_trampoline) >
1576ca63662SSven Schnelle FTRACE_PATCHABLE_FUNCTION_SIZE);
1586ca63662SSven Schnelle
1596ca63662SSven Schnelle size = sizeof(ftrace_trampoline);
1606ca63662SSven Schnelle tramp = ftrace_trampoline;
1616ca63662SSven Schnelle
1626ca63662SSven Schnelle #ifdef CONFIG_64BIT
1636ca63662SSven Schnelle if (rec->ip & 0x4) {
1646ca63662SSven Schnelle size = sizeof(ftrace_trampoline_unaligned);
1656ca63662SSven Schnelle tramp = ftrace_trampoline_unaligned;
1666ca63662SSven Schnelle }
1676ca63662SSven Schnelle #endif
1686ca63662SSven Schnelle
1696ca63662SSven Schnelle ip = (void *)(rec->ip + 4 - size);
1706ca63662SSven Schnelle
171fe557319SChristoph Hellwig ret = copy_from_kernel_nofault(insn, ip, size);
1726ca63662SSven Schnelle if (ret)
1736ca63662SSven Schnelle return ret;
1746ca63662SSven Schnelle
1756ca63662SSven Schnelle for (i = 0; i < size / 4; i++) {
1766ca63662SSven Schnelle if (insn[i] != INSN_NOP)
1776ca63662SSven Schnelle return -EINVAL;
1786ca63662SSven Schnelle }
1796ca63662SSven Schnelle
1806ca63662SSven Schnelle __patch_text_multiple(ip, tramp, size);
1816ca63662SSven Schnelle return 0;
1826ca63662SSven Schnelle }
1836ca63662SSven Schnelle
ftrace_make_nop(struct module * mod,struct dyn_ftrace * rec,unsigned long addr)1846ca63662SSven Schnelle int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
1856ca63662SSven Schnelle unsigned long addr)
1866ca63662SSven Schnelle {
1876ca63662SSven Schnelle u32 insn[FTRACE_PATCHABLE_FUNCTION_SIZE];
1886ca63662SSven Schnelle int i;
1896ca63662SSven Schnelle
1906ca63662SSven Schnelle for (i = 0; i < ARRAY_SIZE(insn); i++)
1916ca63662SSven Schnelle insn[i] = INSN_NOP;
1926ca63662SSven Schnelle
193740f05f3SSven Schnelle __patch_text((void *)rec->ip, INSN_NOP);
1946ca63662SSven Schnelle __patch_text_multiple((void *)rec->ip + 4 - sizeof(insn),
195740f05f3SSven Schnelle insn, sizeof(insn)-4);
1966ca63662SSven Schnelle return 0;
1976ca63662SSven Schnelle }
1986ca63662SSven Schnelle #endif
19952a22e6cSSven Schnelle
20052a22e6cSSven Schnelle #ifdef CONFIG_KPROBES_ON_FTRACE
kprobe_ftrace_handler(unsigned long ip,unsigned long parent_ip,struct ftrace_ops * ops,struct ftrace_regs * fregs)20152a22e6cSSven Schnelle void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
202d19ad077SSteven Rostedt (VMware) struct ftrace_ops *ops, struct ftrace_regs *fregs)
20352a22e6cSSven Schnelle {
20452a22e6cSSven Schnelle struct kprobe_ctlblk *kcb;
205d19ad077SSteven Rostedt (VMware) struct pt_regs *regs;
206c536aa1cSSteven Rostedt (VMware) struct kprobe *p;
207c536aa1cSSteven Rostedt (VMware) int bit;
20852a22e6cSSven Schnelle
209ae0d1ea3SStephen Brennan if (unlikely(kprobe_ftrace_disabled))
210ae0d1ea3SStephen Brennan return;
211ae0d1ea3SStephen Brennan
212773c1670SSteven Rostedt (VMware) bit = ftrace_test_recursion_trylock(ip, parent_ip);
213c536aa1cSSteven Rostedt (VMware) if (bit < 0)
21452a22e6cSSven Schnelle return;
21552a22e6cSSven Schnelle
216d19ad077SSteven Rostedt (VMware) regs = ftrace_get_regs(fregs);
217c536aa1cSSteven Rostedt (VMware) p = get_kprobe((kprobe_opcode_t *)ip);
218c536aa1cSSteven Rostedt (VMware) if (unlikely(!p) || kprobe_disabled(p))
219c536aa1cSSteven Rostedt (VMware) goto out;
220c536aa1cSSteven Rostedt (VMware)
22152a22e6cSSven Schnelle if (kprobe_running()) {
22252a22e6cSSven Schnelle kprobes_inc_nmissed_count(p);
223c536aa1cSSteven Rostedt (VMware) goto out;
22452a22e6cSSven Schnelle }
22552a22e6cSSven Schnelle
22652a22e6cSSven Schnelle __this_cpu_write(current_kprobe, p);
22752a22e6cSSven Schnelle
22852a22e6cSSven Schnelle kcb = get_kprobe_ctlblk();
22952a22e6cSSven Schnelle kcb->kprobe_status = KPROBE_HIT_ACTIVE;
23052a22e6cSSven Schnelle
23152a22e6cSSven Schnelle regs->iaoq[0] = ip;
23252a22e6cSSven Schnelle regs->iaoq[1] = ip + 4;
23352a22e6cSSven Schnelle
23452a22e6cSSven Schnelle if (!p->pre_handler || !p->pre_handler(p, regs)) {
23552a22e6cSSven Schnelle regs->iaoq[0] = ip + 4;
23652a22e6cSSven Schnelle regs->iaoq[1] = ip + 8;
23752a22e6cSSven Schnelle
23852a22e6cSSven Schnelle if (unlikely(p->post_handler)) {
23952a22e6cSSven Schnelle kcb->kprobe_status = KPROBE_HIT_SSDONE;
24052a22e6cSSven Schnelle p->post_handler(p, regs, 0);
24152a22e6cSSven Schnelle }
24252a22e6cSSven Schnelle }
24352a22e6cSSven Schnelle __this_cpu_write(current_kprobe, NULL);
244c536aa1cSSteven Rostedt (VMware) out:
245c536aa1cSSteven Rostedt (VMware) ftrace_test_recursion_unlock(bit);
24652a22e6cSSven Schnelle }
24752a22e6cSSven Schnelle NOKPROBE_SYMBOL(kprobe_ftrace_handler);
24852a22e6cSSven Schnelle
arch_prepare_kprobe_ftrace(struct kprobe * p)24952a22e6cSSven Schnelle int arch_prepare_kprobe_ftrace(struct kprobe *p)
25052a22e6cSSven Schnelle {
25152a22e6cSSven Schnelle p->ainsn.insn = NULL;
25252a22e6cSSven Schnelle return 0;
25352a22e6cSSven Schnelle }
25452a22e6cSSven Schnelle #endif
255