Linux Audio

Check our new training course

Loading...
v6.2
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Code for replacing ftrace calls with jumps.
  4 *
  5 * Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com>
  6 *
  7 * Thanks goes out to P.A. Semi, Inc for supplying me with a PPC64 box.
  8 *
  9 * Added function graph tracer code, taken from x86 that was written
 10 * by Frederic Weisbecker, and ported to PPC by Steven Rostedt.
 11 *
 12 */
 13
 14#define pr_fmt(fmt) "ftrace-powerpc: " fmt
 15
 16#include <linux/spinlock.h>
 17#include <linux/hardirq.h>
 18#include <linux/uaccess.h>
 19#include <linux/module.h>
 20#include <linux/ftrace.h>
 21#include <linux/percpu.h>
 22#include <linux/init.h>
 23#include <linux/list.h>
 24
 
 25#include <asm/cacheflush.h>
 26#include <asm/code-patching.h>
 27#include <asm/ftrace.h>
 28#include <asm/syscall.h>
 29#include <asm/inst.h>
 30
 31/*
 32 * We generally only have a single long_branch tramp and at most 2 or 3 plt
 33 * tramps generated. But, we don't use the plt tramps currently. We also allot
 34 * 2 tramps after .text and .init.text. So, we only end up with around 3 usable
 35 * tramps in total. Set aside 8 just to be sure.
 36 */
 37#define	NUM_FTRACE_TRAMPS	8
 38static unsigned long ftrace_tramps[NUM_FTRACE_TRAMPS];
 39
 40static ppc_inst_t
 
 41ftrace_call_replace(unsigned long ip, unsigned long addr, int link)
 42{
 43	ppc_inst_t op;
 44
 45	addr = ppc_function_entry((void *)addr);
 46
 47	/* if (link) set op to 'bl' else 'b' */
 48	create_branch(&op, (u32 *)ip, addr, link ? BRANCH_SET_LINK : 0);
 49
 50	return op;
 51}
 52
 53static inline int
 54ftrace_modify_code(unsigned long ip, ppc_inst_t old, ppc_inst_t new)
 55{
 56	ppc_inst_t replaced;
 57
 58	/*
 59	 * Note:
 60	 * We are paranoid about modifying text, as if a bug was to happen, it
 61	 * could cause us to read or write to someplace that could cause harm.
 62	 * Carefully read and modify the code with probe_kernel_*(), and make
 63	 * sure what we read is what we expected it to be before modifying it.
 64	 */
 65
 66	/* read the text we want to modify */
 67	if (copy_inst_from_kernel_nofault(&replaced, (void *)ip))
 68		return -EFAULT;
 69
 70	/* Make sure it is what we expect it to be */
 71	if (!ppc_inst_equal(replaced, old)) {
 72		pr_err("%p: replaced (%08lx) != old (%08lx)", (void *)ip,
 73		       ppc_inst_as_ulong(replaced), ppc_inst_as_ulong(old));
 74		return -EINVAL;
 75	}
 76
 77	/* replace the text with the new text */
 78	return patch_instruction((u32 *)ip, new);
 
 
 
 79}
 80
 81/*
 82 * Helper functions that are the same for both PPC64 and PPC32.
 83 */
 84static int test_24bit_addr(unsigned long ip, unsigned long addr)
 85{
 86	addr = ppc_function_entry((void *)addr);
 87
 88	return is_offset_in_branch_range(addr - ip);
 
 89}
 90
 91static int is_bl_op(ppc_inst_t op)
 92{
 93	return (ppc_inst_val(op) & ~PPC_LI_MASK) == PPC_RAW_BL(0);
 94}
 95
 96static int is_b_op(ppc_inst_t op)
 97{
 98	return (ppc_inst_val(op) & ~PPC_LI_MASK) == PPC_RAW_BRANCH(0);
 99}
100
101static unsigned long find_bl_target(unsigned long ip, ppc_inst_t op)
102{
103	int offset;
104
105	offset = PPC_LI(ppc_inst_val(op));
106	/* make it signed */
107	if (offset & 0x02000000)
108		offset |= 0xfe000000;
109
110	return ip + (long)offset;
111}
112
113#ifdef CONFIG_MODULES
114static int
115__ftrace_make_nop(struct module *mod,
116		  struct dyn_ftrace *rec, unsigned long addr)
117{
118	unsigned long entry, ptr, tramp;
119	unsigned long ip = rec->ip;
120	ppc_inst_t op, pop;
121
122	/* read where this goes */
123	if (copy_inst_from_kernel_nofault(&op, (void *)ip)) {
124		pr_err("Fetching opcode failed.\n");
125		return -EFAULT;
126	}
127
128	/* Make sure that this is still a 24bit jump */
129	if (!is_bl_op(op)) {
130		pr_err("Not expected bl: opcode is %08lx\n", ppc_inst_as_ulong(op));
131		return -EINVAL;
132	}
133
134	/* lets find where the pointer goes */
135	tramp = find_bl_target(ip, op);
136
137	pr_devel("ip:%lx jumps to %lx", ip, tramp);
138
139	if (module_trampoline_target(mod, tramp, &ptr)) {
140		pr_err("Failed to get trampoline target\n");
141		return -EFAULT;
142	}
143
144	pr_devel("trampoline target %lx", ptr);
145
146	entry = ppc_global_function_entry((void *)addr);
147	/* This should match what was called */
148	if (ptr != entry) {
149		pr_err("addr %lx does not match expected %lx\n", ptr, entry);
150		return -EINVAL;
151	}
152
153	if (IS_ENABLED(CONFIG_MPROFILE_KERNEL)) {
154		if (copy_inst_from_kernel_nofault(&op, (void *)(ip - 4))) {
155			pr_err("Fetching instruction at %lx failed.\n", ip - 4);
156			return -EFAULT;
157		}
158
159		/* We expect either a mflr r0, or a std r0, LRSAVE(r1) */
160		if (!ppc_inst_equal(op, ppc_inst(PPC_RAW_MFLR(_R0))) &&
161		    !ppc_inst_equal(op, ppc_inst(PPC_INST_STD_LR))) {
162			pr_err("Unexpected instruction %08lx around bl _mcount\n",
163			       ppc_inst_as_ulong(op));
164			return -EINVAL;
165		}
166	} else if (IS_ENABLED(CONFIG_PPC64)) {
167		/*
168		 * Check what is in the next instruction. We can see ld r2,40(r1), but
169		 * on first pass after boot we will see mflr r0.
170		 */
171		if (copy_inst_from_kernel_nofault(&op, (void *)(ip + 4))) {
172			pr_err("Fetching op failed.\n");
173			return -EFAULT;
174		}
175
176		if (!ppc_inst_equal(op,  ppc_inst(PPC_INST_LD_TOC))) {
177			pr_err("Expected %08lx found %08lx\n", PPC_INST_LD_TOC,
178			       ppc_inst_as_ulong(op));
179			return -EINVAL;
180		}
181	}
182
 
 
 
 
 
 
183	/*
184	 * When using -mprofile-kernel or PPC32 there is no load to jump over.
185	 *
186	 * Otherwise our original call site looks like:
187	 *
188	 * bl <tramp>
189	 * ld r2,XX(r1)
190	 *
191	 * Milton Miller pointed out that we can not simply nop the branch.
192	 * If a task was preempted when calling a trace function, the nops
193	 * will remove the way to restore the TOC in r2 and the r2 TOC will
194	 * get corrupted.
195	 *
196	 * Use a b +8 to jump over the load.
197	 */
198	if (IS_ENABLED(CONFIG_MPROFILE_KERNEL) || IS_ENABLED(CONFIG_PPC32))
199		pop = ppc_inst(PPC_RAW_NOP());
200	else
201		pop = ppc_inst(PPC_RAW_BRANCH(8));	/* b +8 */
202
203	if (patch_instruction((u32 *)ip, pop)) {
204		pr_err("Patching NOP failed.\n");
205		return -EPERM;
206	}
207
208	return 0;
209}
210#else
211static int __ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, unsigned long addr)
212{
213	return 0;
214}
215#endif /* CONFIG_MODULES */
216
217static unsigned long find_ftrace_tramp(unsigned long ip)
218{
219	int i;
220
221	/*
222	 * We have the compiler generated long_branch tramps at the end
223	 * and we prefer those
224	 */
225	for (i = NUM_FTRACE_TRAMPS - 1; i >= 0; i--)
226		if (!ftrace_tramps[i])
227			continue;
228		else if (is_offset_in_branch_range(ftrace_tramps[i] - ip))
229			return ftrace_tramps[i];
230
231	return 0;
232}
233
234static int add_ftrace_tramp(unsigned long tramp)
235{
236	int i;
237
238	for (i = 0; i < NUM_FTRACE_TRAMPS; i++)
239		if (!ftrace_tramps[i]) {
240			ftrace_tramps[i] = tramp;
241			return 0;
242		}
243
244	return -1;
245}
246
247/*
248 * If this is a compiler generated long_branch trampoline (essentially, a
249 * trampoline that has a branch to _mcount()), we re-write the branch to
250 * instead go to ftrace_[regs_]caller() and note down the location of this
251 * trampoline.
252 */
253static int setup_mcount_compiler_tramp(unsigned long tramp)
254{
255	int i;
256	ppc_inst_t op;
257	unsigned long ptr;
258
259	/* Is this a known long jump tramp? */
260	for (i = 0; i < NUM_FTRACE_TRAMPS; i++)
261		if (ftrace_tramps[i] == tramp)
262			return 0;
263
264	/* New trampoline -- read where this goes */
265	if (copy_inst_from_kernel_nofault(&op, (void *)tramp)) {
266		pr_debug("Fetching opcode failed.\n");
267		return -1;
268	}
269
270	/* Is this a 24 bit branch? */
271	if (!is_b_op(op)) {
272		pr_debug("Trampoline is not a long branch tramp.\n");
273		return -1;
274	}
275
276	/* lets find where the pointer goes */
277	ptr = find_bl_target(tramp, op);
278
279	if (ptr != ppc_global_function_entry((void *)_mcount)) {
280		pr_debug("Trampoline target %p is not _mcount\n", (void *)ptr);
281		return -1;
282	}
283
284	/* Let's re-write the tramp to go to ftrace_[regs_]caller */
285	if (IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_REGS))
286		ptr = ppc_global_function_entry((void *)ftrace_regs_caller);
287	else
288		ptr = ppc_global_function_entry((void *)ftrace_caller);
289
290	if (patch_branch((u32 *)tramp, ptr, 0)) {
291		pr_debug("REL24 out of range!\n");
292		return -1;
293	}
 
294
295	if (add_ftrace_tramp(tramp)) {
296		pr_debug("No tramp locations left\n");
297		return -1;
298	}
299
300	return 0;
301}
302
303static int __ftrace_make_nop_kernel(struct dyn_ftrace *rec, unsigned long addr)
 
 
 
304{
305	unsigned long tramp, ip = rec->ip;
306	ppc_inst_t op;
 
 
307
308	/* Read where this goes */
309	if (copy_inst_from_kernel_nofault(&op, (void *)ip)) {
310		pr_err("Fetching opcode failed.\n");
311		return -EFAULT;
312	}
313
314	/* Make sure that this is still a 24bit jump */
315	if (!is_bl_op(op)) {
316		pr_err("Not expected bl: opcode is %08lx\n", ppc_inst_as_ulong(op));
317		return -EINVAL;
318	}
319
320	/* Let's find where the pointer goes */
321	tramp = find_bl_target(ip, op);
322
 
 
 
 
 
 
 
 
323	pr_devel("ip:%lx jumps to %lx", ip, tramp);
324
325	if (setup_mcount_compiler_tramp(tramp)) {
326		/* Are other trampolines reachable? */
327		if (!find_ftrace_tramp(ip)) {
328			pr_err("No ftrace trampolines reachable from %ps\n",
329					(void *)ip);
330			return -EINVAL;
331		}
332	}
333
334	if (patch_instruction((u32 *)ip, ppc_inst(PPC_RAW_NOP()))) {
335		pr_err("Patching NOP failed.\n");
336		return -EPERM;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
337	}
338
 
 
 
 
 
339	return 0;
340}
 
 
341
342int ftrace_make_nop(struct module *mod,
343		    struct dyn_ftrace *rec, unsigned long addr)
344{
345	unsigned long ip = rec->ip;
346	ppc_inst_t old, new;
347
348	/*
349	 * If the calling address is more that 24 bits away,
350	 * then we had to use a trampoline to make the call.
351	 * Otherwise just update the call site.
352	 */
353	if (test_24bit_addr(ip, addr)) {
354		/* within range */
355		old = ftrace_call_replace(ip, addr, 1);
356		new = ppc_inst(PPC_RAW_NOP());
357		return ftrace_modify_code(ip, old, new);
358	} else if (core_kernel_text(ip)) {
359		return __ftrace_make_nop_kernel(rec, addr);
360	} else if (!IS_ENABLED(CONFIG_MODULES)) {
361		return -EINVAL;
362	}
363
 
364	/*
365	 * Out of range jumps are called from modules.
366	 * We should either already have a pointer to the module
367	 * or it has been passed in.
368	 */
369	if (!rec->arch.mod) {
370		if (!mod) {
371			pr_err("No module loaded addr=%lx\n", addr);
372			return -EFAULT;
373		}
374		rec->arch.mod = mod;
375	} else if (mod) {
376		if (mod != rec->arch.mod) {
377			pr_err("Record mod %p not equal to passed in mod %p\n",
378			       rec->arch.mod, mod);
379			return -EINVAL;
380		}
381		/* nothing to do if mod == rec->arch.mod */
382	} else
383		mod = rec->arch.mod;
384
385	return __ftrace_make_nop(mod, rec, addr);
 
 
 
 
386}
387
388#ifdef CONFIG_MODULES
 
389/*
390 * Examine the existing instructions for __ftrace_make_call.
391 * They should effectively be a NOP, and follow formal constraints,
392 * depending on the ABI. Return false if they don't.
393 */
394static bool expected_nop_sequence(void *ip, ppc_inst_t op0, ppc_inst_t op1)
 
 
395{
396	if (IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_REGS))
397		return ppc_inst_equal(op0, ppc_inst(PPC_RAW_NOP()));
398	else
399		return ppc_inst_equal(op0, ppc_inst(PPC_RAW_BRANCH(8))) &&
400		       ppc_inst_equal(op1, ppc_inst(PPC_INST_LD_TOC));
 
 
 
 
 
 
 
401}
 
 
 
 
 
 
 
 
 
 
402
403static int
404__ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
405{
406	ppc_inst_t op[2];
407	void *ip = (void *)rec->ip;
408	unsigned long entry, ptr, tramp;
409	struct module *mod = rec->arch.mod;
410
411	/* read where this goes */
412	if (copy_inst_from_kernel_nofault(op, ip))
413		return -EFAULT;
414
415	if (!IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_REGS) &&
416	    copy_inst_from_kernel_nofault(op + 1, ip + 4))
417		return -EFAULT;
418
419	if (!expected_nop_sequence(ip, op[0], op[1])) {
420		pr_err("Unexpected call sequence at %p: %08lx %08lx\n", ip,
421		       ppc_inst_as_ulong(op[0]), ppc_inst_as_ulong(op[1]));
422		return -EINVAL;
423	}
424
425	/* If we never set up ftrace trampoline(s), then bail */
426	if (!mod->arch.tramp ||
427	    (IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_REGS) && !mod->arch.tramp_regs)) {
428		pr_err("No ftrace trampoline\n");
429		return -EINVAL;
430	}
431
432	if (IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_REGS) && rec->flags & FTRACE_FL_REGS)
433		tramp = mod->arch.tramp_regs;
434	else
435		tramp = mod->arch.tramp;
436
437	if (module_trampoline_target(mod, tramp, &ptr)) {
438		pr_err("Failed to get trampoline target\n");
439		return -EFAULT;
440	}
441
442	pr_devel("trampoline target %lx", ptr);
443
444	entry = ppc_global_function_entry((void *)addr);
445	/* This should match what was called */
446	if (ptr != entry) {
447		pr_err("addr %lx does not match expected %lx\n", ptr, entry);
448		return -EINVAL;
449	}
450
451	if (patch_branch(ip, tramp, BRANCH_SET_LINK)) {
452		pr_err("REL24 out of range!\n");
453		return -EINVAL;
454	}
455
456	return 0;
457}
458#else
459static int __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
 
 
460{
461	return 0;
462}
463#endif /* CONFIG_MODULES */
464
465static int __ftrace_make_call_kernel(struct dyn_ftrace *rec, unsigned long addr)
 
 
466{
467	ppc_inst_t op;
468	void *ip = (void *)rec->ip;
469	unsigned long tramp, entry, ptr;
470
471	/* Make sure we're being asked to patch branch to a known ftrace addr */
472	entry = ppc_global_function_entry((void *)ftrace_caller);
473	ptr = ppc_global_function_entry((void *)addr);
474
475	if (ptr != entry && IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_REGS))
476		entry = ppc_global_function_entry((void *)ftrace_regs_caller);
477
478	if (ptr != entry) {
479		pr_err("Unknown ftrace addr to patch: %ps\n", (void *)ptr);
480		return -EINVAL;
481	}
482
483	/* Make sure we have a nop */
484	if (copy_inst_from_kernel_nofault(&op, ip)) {
485		pr_err("Unable to read ftrace location %p\n", ip);
486		return -EFAULT;
487	}
488
489	if (!ppc_inst_equal(op, ppc_inst(PPC_RAW_NOP()))) {
490		pr_err("Unexpected call sequence at %p: %08lx\n",
491		       ip, ppc_inst_as_ulong(op));
492		return -EINVAL;
493	}
494
495	tramp = find_ftrace_tramp((unsigned long)ip);
496	if (!tramp) {
497		pr_err("No ftrace trampolines reachable from %ps\n", ip);
498		return -EINVAL;
499	}
500
501	if (patch_branch(ip, tramp, BRANCH_SET_LINK)) {
502		pr_err("Error patching branch to ftrace tramp!\n");
 
 
 
503		return -EINVAL;
504	}
505
 
 
 
 
 
506	return 0;
507}
 
 
508
509int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
510{
511	unsigned long ip = rec->ip;
512	ppc_inst_t old, new;
513
514	/*
515	 * If the calling address is more that 24 bits away,
516	 * then we had to use a trampoline to make the call.
517	 * Otherwise just update the call site.
518	 */
519	if (test_24bit_addr(ip, addr)) {
520		/* within range */
521		old = ppc_inst(PPC_RAW_NOP());
522		new = ftrace_call_replace(ip, addr, 1);
523		return ftrace_modify_code(ip, old, new);
524	} else if (core_kernel_text(ip)) {
525		return __ftrace_make_call_kernel(rec, addr);
526	} else if (!IS_ENABLED(CONFIG_MODULES)) {
527		/* We should not get here without modules */
528		return -EINVAL;
529	}
530
 
531	/*
532	 * Out of range jumps are called from modules.
533	 * Being that we are converting from nop, it had better
534	 * already have a module defined.
535	 */
536	if (!rec->arch.mod) {
537		pr_err("No module loaded\n");
538		return -EINVAL;
539	}
540
541	return __ftrace_make_call(rec, addr);
 
 
 
 
542}
543
544#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
545#ifdef CONFIG_MODULES
546static int
547__ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
548					unsigned long addr)
549{
550	ppc_inst_t op;
551	unsigned long ip = rec->ip;
552	unsigned long entry, ptr, tramp;
553	struct module *mod = rec->arch.mod;
554
555	/* If we never set up ftrace trampolines, then bail */
556	if (!mod->arch.tramp || !mod->arch.tramp_regs) {
557		pr_err("No ftrace trampoline\n");
558		return -EINVAL;
559	}
560
561	/* read where this goes */
562	if (copy_inst_from_kernel_nofault(&op, (void *)ip)) {
563		pr_err("Fetching opcode failed.\n");
564		return -EFAULT;
565	}
566
567	/* Make sure that this is still a 24bit jump */
568	if (!is_bl_op(op)) {
569		pr_err("Not expected bl: opcode is %08lx\n", ppc_inst_as_ulong(op));
570		return -EINVAL;
571	}
572
573	/* lets find where the pointer goes */
574	tramp = find_bl_target(ip, op);
575	entry = ppc_global_function_entry((void *)old_addr);
576
577	pr_devel("ip:%lx jumps to %lx", ip, tramp);
578
579	if (tramp != entry) {
580		/* old_addr is not within range, so we must have used a trampoline */
581		if (module_trampoline_target(mod, tramp, &ptr)) {
582			pr_err("Failed to get trampoline target\n");
583			return -EFAULT;
584		}
585
586		pr_devel("trampoline target %lx", ptr);
587
588		/* This should match what was called */
589		if (ptr != entry) {
590			pr_err("addr %lx does not match expected %lx\n", ptr, entry);
591			return -EINVAL;
592		}
593	}
594
595	/* The new target may be within range */
596	if (test_24bit_addr(ip, addr)) {
597		/* within range */
598		if (patch_branch((u32 *)ip, addr, BRANCH_SET_LINK)) {
599			pr_err("REL24 out of range!\n");
600			return -EINVAL;
601		}
602
603		return 0;
604	}
605
606	if (rec->flags & FTRACE_FL_REGS)
607		tramp = mod->arch.tramp_regs;
608	else
609		tramp = mod->arch.tramp;
610
611	if (module_trampoline_target(mod, tramp, &ptr)) {
612		pr_err("Failed to get trampoline target\n");
613		return -EFAULT;
614	}
615
616	pr_devel("trampoline target %lx", ptr);
617
618	entry = ppc_global_function_entry((void *)addr);
619	/* This should match what was called */
620	if (ptr != entry) {
621		pr_err("addr %lx does not match expected %lx\n", ptr, entry);
622		return -EINVAL;
623	}
624
625	if (patch_branch((u32 *)ip, tramp, BRANCH_SET_LINK)) {
626		pr_err("REL24 out of range!\n");
627		return -EINVAL;
628	}
629
630	return 0;
631}
632#else
633static int __ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr, unsigned long addr)
634{
635	return 0;
636}
637#endif
638
639int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
640			unsigned long addr)
641{
642	unsigned long ip = rec->ip;
643	ppc_inst_t old, new;
644
645	/*
646	 * If the calling address is more that 24 bits away,
647	 * then we had to use a trampoline to make the call.
648	 * Otherwise just update the call site.
649	 */
650	if (test_24bit_addr(ip, addr) && test_24bit_addr(ip, old_addr)) {
651		/* within range */
652		old = ftrace_call_replace(ip, old_addr, 1);
653		new = ftrace_call_replace(ip, addr, 1);
654		return ftrace_modify_code(ip, old, new);
655	} else if (core_kernel_text(ip)) {
656		/*
657		 * We always patch out of range locations to go to the regs
658		 * variant, so there is nothing to do here
659		 */
660		return 0;
661	} else if (!IS_ENABLED(CONFIG_MODULES)) {
662		/* We should not get here without modules */
663		return -EINVAL;
664	}
665
666	/*
667	 * Out of range jumps are called from modules.
668	 */
669	if (!rec->arch.mod) {
670		pr_err("No module loaded\n");
671		return -EINVAL;
 
672	}
673
674	return __ftrace_modify_call(rec, old_addr, addr);
675}
676#endif
677
678int ftrace_update_ftrace_func(ftrace_func_t func)
679{
680	unsigned long ip = (unsigned long)(&ftrace_call);
681	ppc_inst_t old, new;
682	int ret;
683
684	old = ppc_inst_read((u32 *)&ftrace_call);
685	new = ftrace_call_replace(ip, (unsigned long)func, 1);
686	ret = ftrace_modify_code(ip, old, new);
687
688	/* Also update the regs callback function */
689	if (IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_REGS) && !ret) {
690		ip = (unsigned long)(&ftrace_regs_call);
691		old = ppc_inst_read((u32 *)&ftrace_regs_call);
692		new = ftrace_call_replace(ip, (unsigned long)func, 1);
693		ret = ftrace_modify_code(ip, old, new);
694	}
695
696	return ret;
697}
698
699/*
700 * Use the default ftrace_modify_all_code, but without
701 * stop_machine().
702 */
703void arch_ftrace_update_code(int command)
704{
705	ftrace_modify_all_code(command);
706}
707
708#ifdef CONFIG_PPC64
709#define PACATOC offsetof(struct paca_struct, kernel_toc)
710
711extern unsigned int ftrace_tramp_text[], ftrace_tramp_init[];
712
713void ftrace_free_init_tramp(void)
714{
715	int i;
716
717	for (i = 0; i < NUM_FTRACE_TRAMPS && ftrace_tramps[i]; i++)
718		if (ftrace_tramps[i] == (unsigned long)ftrace_tramp_init) {
719			ftrace_tramps[i] = 0;
720			return;
721		}
722}
723
724int __init ftrace_dyn_arch_init(void)
725{
726	int i;
727	unsigned int *tramp[] = { ftrace_tramp_text, ftrace_tramp_init };
728	u32 stub_insns[] = {
729		PPC_RAW_LD(_R12, _R13, PACATOC),
730		PPC_RAW_ADDIS(_R12, _R12, 0),
731		PPC_RAW_ADDI(_R12, _R12, 0),
732		PPC_RAW_MTCTR(_R12),
733		PPC_RAW_BCTR()
734	};
735	unsigned long addr;
736	long reladdr;
737
738	if (IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_REGS))
739		addr = ppc_global_function_entry((void *)ftrace_regs_caller);
740	else
741		addr = ppc_global_function_entry((void *)ftrace_caller);
742
743	reladdr = addr - kernel_toc_addr();
744
745	if (reladdr >= SZ_2G || reladdr < -(long)SZ_2G) {
746		pr_err("Address of %ps out of range of kernel_toc.\n",
747				(void *)addr);
748		return -1;
749	}
750
751	for (i = 0; i < 2; i++) {
752		memcpy(tramp[i], stub_insns, sizeof(stub_insns));
753		tramp[i][1] |= PPC_HA(reladdr);
754		tramp[i][2] |= PPC_LO(reladdr);
755		add_ftrace_tramp((unsigned long)tramp[i]);
756	}
757
758	return 0;
759}
760#endif
761
762#ifdef CONFIG_FUNCTION_GRAPH_TRACER
763
 
764extern void ftrace_graph_call(void);
765extern void ftrace_graph_stub(void);
766
767static int ftrace_modify_ftrace_graph_caller(bool enable)
768{
769	unsigned long ip = (unsigned long)(&ftrace_graph_call);
770	unsigned long addr = (unsigned long)(&ftrace_graph_caller);
771	unsigned long stub = (unsigned long)(&ftrace_graph_stub);
772	ppc_inst_t old, new;
773
774	if (IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_ARGS))
775		return 0;
776
777	old = ftrace_call_replace(ip, enable ? stub : addr, 0);
778	new = ftrace_call_replace(ip, enable ? addr : stub, 0);
779
780	return ftrace_modify_code(ip, old, new);
781}
782
783int ftrace_enable_ftrace_graph_caller(void)
784{
785	return ftrace_modify_ftrace_graph_caller(true);
786}
787
788int ftrace_disable_ftrace_graph_caller(void)
789{
790	return ftrace_modify_ftrace_graph_caller(false);
 
 
 
 
 
 
 
 
791}
 
792
793/*
794 * Hook the return address and push it in the stack of return addrs
795 * in current thread info. Return the address we want to divert to.
796 */
797static unsigned long
798__prepare_ftrace_return(unsigned long parent, unsigned long ip, unsigned long sp)
799{
 
800	unsigned long return_hooker;
801	int bit;
802
803	if (unlikely(ftrace_graph_is_dead()))
804		goto out;
805
806	if (unlikely(atomic_read(&current->tracing_graph_pause)))
807		goto out;
808
809	bit = ftrace_test_recursion_trylock(ip, parent);
810	if (bit < 0)
811		goto out;
812
813	return_hooker = ppc_function_entry(return_to_handler);
814
815	if (!function_graph_enter(parent, ip, 0, (unsigned long *)sp))
816		parent = return_hooker;
 
 
 
 
 
 
 
 
817
818	ftrace_test_recursion_unlock(bit);
819out:
820	return parent;
821}
 
822
823#ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
824void ftrace_graph_func(unsigned long ip, unsigned long parent_ip,
825		       struct ftrace_ops *op, struct ftrace_regs *fregs)
826{
827	fregs->regs.link = __prepare_ftrace_return(parent_ip, ip, fregs->regs.gpr[1]);
828}
829#else
830unsigned long prepare_ftrace_return(unsigned long parent, unsigned long ip,
831				    unsigned long sp)
832{
833	return __prepare_ftrace_return(parent, ip, sp);
834}
835#endif
836#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
837
838#ifdef CONFIG_PPC64_ELF_ABI_V1
839char *arch_ftrace_match_adjust(char *str, const char *search)
840{
841	if (str[0] == '.' && search[0] != '.')
842		return str + 1;
843	else
844		return str;
845}
846#endif /* CONFIG_PPC64_ELF_ABI_V1 */
v4.17
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Code for replacing ftrace calls with jumps.
  4 *
  5 * Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com>
  6 *
  7 * Thanks goes out to P.A. Semi, Inc for supplying me with a PPC64 box.
  8 *
  9 * Added function graph tracer code, taken from x86 that was written
 10 * by Frederic Weisbecker, and ported to PPC by Steven Rostedt.
 11 *
 12 */
 13
 14#define pr_fmt(fmt) "ftrace-powerpc: " fmt
 15
 16#include <linux/spinlock.h>
 17#include <linux/hardirq.h>
 18#include <linux/uaccess.h>
 19#include <linux/module.h>
 20#include <linux/ftrace.h>
 21#include <linux/percpu.h>
 22#include <linux/init.h>
 23#include <linux/list.h>
 24
 25#include <asm/asm-prototypes.h>
 26#include <asm/cacheflush.h>
 27#include <asm/code-patching.h>
 28#include <asm/ftrace.h>
 29#include <asm/syscall.h>
 
 30
 
 
 
 
 
 
 
 
 31
 32#ifdef CONFIG_DYNAMIC_FTRACE
 33static unsigned int
 34ftrace_call_replace(unsigned long ip, unsigned long addr, int link)
 35{
 36	unsigned int op;
 37
 38	addr = ppc_function_entry((void *)addr);
 39
 40	/* if (link) set op to 'bl' else 'b' */
 41	op = create_branch((unsigned int *)ip, addr, link ? 1 : 0);
 42
 43	return op;
 44}
 45
 46static int
 47ftrace_modify_code(unsigned long ip, unsigned int old, unsigned int new)
 48{
 49	unsigned int replaced;
 50
 51	/*
 52	 * Note:
 53	 * We are paranoid about modifying text, as if a bug was to happen, it
 54	 * could cause us to read or write to someplace that could cause harm.
 55	 * Carefully read and modify the code with probe_kernel_*(), and make
 56	 * sure what we read is what we expected it to be before modifying it.
 57	 */
 58
 59	/* read the text we want to modify */
 60	if (probe_kernel_read(&replaced, (void *)ip, MCOUNT_INSN_SIZE))
 61		return -EFAULT;
 62
 63	/* Make sure it is what we expect it to be */
 64	if (replaced != old) {
 65		pr_err("%p: replaced (%#x) != old (%#x)",
 66		(void *)ip, replaced, old);
 67		return -EINVAL;
 68	}
 69
 70	/* replace the text with the new text */
 71	if (patch_instruction((unsigned int *)ip, new))
 72		return -EPERM;
 73
 74	return 0;
 75}
 76
 77/*
 78 * Helper functions that are the same for both PPC64 and PPC32.
 79 */
 80static int test_24bit_addr(unsigned long ip, unsigned long addr)
 81{
 82	addr = ppc_function_entry((void *)addr);
 83
 84	/* use the create_branch to verify that this offset can be branched */
 85	return create_branch((unsigned int *)ip, addr, 0);
 86}
 87
 88#ifdef CONFIG_MODULES
 
 
 
 89
 90static int is_bl_op(unsigned int op)
 91{
 92	return (op & 0xfc000003) == 0x48000001;
 93}
 94
 95static unsigned long find_bl_target(unsigned long ip, unsigned int op)
 96{
 97	static int offset;
 98
 99	offset = (op & 0x03fffffc);
100	/* make it signed */
101	if (offset & 0x02000000)
102		offset |= 0xfe000000;
103
104	return ip + (long)offset;
105}
106
107#ifdef CONFIG_PPC64
108static int
109__ftrace_make_nop(struct module *mod,
110		  struct dyn_ftrace *rec, unsigned long addr)
111{
112	unsigned long entry, ptr, tramp;
113	unsigned long ip = rec->ip;
114	unsigned int op, pop;
115
116	/* read where this goes */
117	if (probe_kernel_read(&op, (void *)ip, sizeof(int))) {
118		pr_err("Fetching opcode failed.\n");
119		return -EFAULT;
120	}
121
122	/* Make sure that that this is still a 24bit jump */
123	if (!is_bl_op(op)) {
124		pr_err("Not expected bl: opcode is %x\n", op);
125		return -EINVAL;
126	}
127
128	/* lets find where the pointer goes */
129	tramp = find_bl_target(ip, op);
130
131	pr_devel("ip:%lx jumps to %lx", ip, tramp);
132
133	if (module_trampoline_target(mod, tramp, &ptr)) {
134		pr_err("Failed to get trampoline target\n");
135		return -EFAULT;
136	}
137
138	pr_devel("trampoline target %lx", ptr);
139
140	entry = ppc_global_function_entry((void *)addr);
141	/* This should match what was called */
142	if (ptr != entry) {
143		pr_err("addr %lx does not match expected %lx\n", ptr, entry);
144		return -EINVAL;
145	}
146
147#ifdef CC_USING_MPROFILE_KERNEL
148	/* When using -mkernel_profile there is no load to jump over */
149	pop = PPC_INST_NOP;
 
 
150
151	if (probe_kernel_read(&op, (void *)(ip - 4), 4)) {
152		pr_err("Fetching instruction at %lx failed.\n", ip - 4);
153		return -EFAULT;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
154	}
155
156	/* We expect either a mflr r0, or a std r0, LRSAVE(r1) */
157	if (op != PPC_INST_MFLR && op != PPC_INST_STD_LR) {
158		pr_err("Unexpected instruction %08x around bl _mcount\n", op);
159		return -EINVAL;
160	}
161#else
162	/*
163	 * Our original call site looks like:
 
 
164	 *
165	 * bl <tramp>
166	 * ld r2,XX(r1)
167	 *
168	 * Milton Miller pointed out that we can not simply nop the branch.
169	 * If a task was preempted when calling a trace function, the nops
170	 * will remove the way to restore the TOC in r2 and the r2 TOC will
171	 * get corrupted.
172	 *
173	 * Use a b +8 to jump over the load.
174	 */
 
 
 
 
175
176	pop = PPC_INST_BRANCH | 8;	/* b +8 */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
177
178	/*
179	 * Check what is in the next instruction. We can see ld r2,40(r1), but
180	 * on first pass after boot we will see mflr r0.
181	 */
182	if (probe_kernel_read(&op, (void *)(ip+4), MCOUNT_INSN_SIZE)) {
183		pr_err("Fetching op failed.\n");
184		return -EFAULT;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
185	}
186
187	if (op != PPC_INST_LD_TOC) {
188		pr_err("Expected %08x found %08x\n", PPC_INST_LD_TOC, op);
189		return -EINVAL;
 
 
 
 
 
 
190	}
191#endif /* CC_USING_MPROFILE_KERNEL */
192
193	if (patch_instruction((unsigned int *)ip, pop)) {
194		pr_err("Patching NOP failed.\n");
195		return -EPERM;
196	}
197
198	return 0;
199}
200
201#else /* !PPC64 */
202static int
203__ftrace_make_nop(struct module *mod,
204		  struct dyn_ftrace *rec, unsigned long addr)
205{
206	unsigned int op;
207	unsigned int jmp[4];
208	unsigned long ip = rec->ip;
209	unsigned long tramp;
210
211	if (probe_kernel_read(&op, (void *)ip, MCOUNT_INSN_SIZE))
 
 
212		return -EFAULT;
 
213
214	/* Make sure that that this is still a 24bit jump */
215	if (!is_bl_op(op)) {
216		pr_err("Not expected bl: opcode is %x\n", op);
217		return -EINVAL;
218	}
219
220	/* lets find where the pointer goes */
221	tramp = find_bl_target(ip, op);
222
223	/*
224	 * On PPC32 the trampoline looks like:
225	 *  0x3d, 0x80, 0x00, 0x00  lis r12,sym@ha
226	 *  0x39, 0x8c, 0x00, 0x00  addi r12,r12,sym@l
227	 *  0x7d, 0x89, 0x03, 0xa6  mtctr r12
228	 *  0x4e, 0x80, 0x04, 0x20  bctr
229	 */
230
231	pr_devel("ip:%lx jumps to %lx", ip, tramp);
232
233	/* Find where the trampoline jumps to */
234	if (probe_kernel_read(jmp, (void *)tramp, sizeof(jmp))) {
235		pr_err("Failed to read %lx\n", tramp);
236		return -EFAULT;
 
 
 
237	}
238
239	pr_devel(" %08x %08x ", jmp[0], jmp[1]);
240
241	/* verify that this is what we expect it to be */
242	if (((jmp[0] & 0xffff0000) != 0x3d800000) ||
243	    ((jmp[1] & 0xffff0000) != 0x398c0000) ||
244	    (jmp[2] != 0x7d8903a6) ||
245	    (jmp[3] != 0x4e800420)) {
246		pr_err("Not a trampoline\n");
247		return -EINVAL;
248	}
249
250	tramp = (jmp[1] & 0xffff) |
251		((jmp[0] & 0xffff) << 16);
252	if (tramp & 0x8000)
253		tramp -= 0x10000;
254
255	pr_devel(" %lx ", tramp);
256
257	if (tramp != addr) {
258		pr_err("Trampoline location %08lx does not match addr\n",
259		       tramp);
260		return -EINVAL;
261	}
262
263	op = PPC_INST_NOP;
264
265	if (patch_instruction((unsigned int *)ip, op))
266		return -EPERM;
267
268	return 0;
269}
270#endif /* PPC64 */
271#endif /* CONFIG_MODULES */
272
273int ftrace_make_nop(struct module *mod,
274		    struct dyn_ftrace *rec, unsigned long addr)
275{
276	unsigned long ip = rec->ip;
277	unsigned int old, new;
278
279	/*
280	 * If the calling address is more that 24 bits away,
281	 * then we had to use a trampoline to make the call.
282	 * Otherwise just update the call site.
283	 */
284	if (test_24bit_addr(ip, addr)) {
285		/* within range */
286		old = ftrace_call_replace(ip, addr, 1);
287		new = PPC_INST_NOP;
288		return ftrace_modify_code(ip, old, new);
 
 
 
 
289	}
290
291#ifdef CONFIG_MODULES
292	/*
293	 * Out of range jumps are called from modules.
294	 * We should either already have a pointer to the module
295	 * or it has been passed in.
296	 */
297	if (!rec->arch.mod) {
298		if (!mod) {
299			pr_err("No module loaded addr=%lx\n", addr);
300			return -EFAULT;
301		}
302		rec->arch.mod = mod;
303	} else if (mod) {
304		if (mod != rec->arch.mod) {
305			pr_err("Record mod %p not equal to passed in mod %p\n",
306			       rec->arch.mod, mod);
307			return -EINVAL;
308		}
309		/* nothing to do if mod == rec->arch.mod */
310	} else
311		mod = rec->arch.mod;
312
313	return __ftrace_make_nop(mod, rec, addr);
314#else
315	/* We should not get here without modules */
316	return -EINVAL;
317#endif /* CONFIG_MODULES */
318}
319
320#ifdef CONFIG_MODULES
321#ifdef CONFIG_PPC64
322/*
323 * Examine the existing instructions for __ftrace_make_call.
324 * They should effectively be a NOP, and follow formal constraints,
325 * depending on the ABI. Return false if they don't.
326 */
327#ifndef CC_USING_MPROFILE_KERNEL
328static int
329expected_nop_sequence(void *ip, unsigned int op0, unsigned int op1)
330{
331	/*
332	 * We expect to see:
333	 *
334	 * b +8
335	 * ld r2,XX(r1)
336	 *
337	 * The load offset is different depending on the ABI. For simplicity
338	 * just mask it out when doing the compare.
339	 */
340	if ((op0 != 0x48000008) || ((op1 & 0xffff0000) != 0xe8410000))
341		return 0;
342	return 1;
343}
344#else
345static int
346expected_nop_sequence(void *ip, unsigned int op0, unsigned int op1)
347{
348	/* look for patched "NOP" on ppc64 with -mprofile-kernel */
349	if (op0 != PPC_INST_NOP)
350		return 0;
351	return 1;
352}
353#endif
354
355static int
356__ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
357{
358	unsigned int op[2];
359	void *ip = (void *)rec->ip;
 
 
360
361	/* read where this goes */
362	if (probe_kernel_read(op, ip, sizeof(op)))
 
 
 
 
363		return -EFAULT;
364
365	if (!expected_nop_sequence(ip, op[0], op[1])) {
366		pr_err("Unexpected call sequence at %p: %x %x\n",
367		ip, op[0], op[1]);
368		return -EINVAL;
369	}
370
371	/* If we never set up a trampoline to ftrace_caller, then bail */
372	if (!rec->arch.mod->arch.tramp) {
 
373		pr_err("No ftrace trampoline\n");
374		return -EINVAL;
375	}
376
377	/* Ensure branch is within 24 bits */
378	if (!create_branch(ip, rec->arch.mod->arch.tramp, BRANCH_SET_LINK)) {
379		pr_err("Branch out of range\n");
 
 
 
 
 
 
 
 
 
 
 
 
 
380		return -EINVAL;
381	}
382
383	if (patch_branch(ip, rec->arch.mod->arch.tramp, BRANCH_SET_LINK)) {
384		pr_err("REL24 out of range!\n");
385		return -EINVAL;
386	}
387
388	return 0;
389}
390
391#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
392int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
393			unsigned long addr)
394{
395	return ftrace_make_call(rec, addr);
396}
397#endif
398
399#else  /* !CONFIG_PPC64: */
400static int
401__ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
402{
403	unsigned int op;
404	unsigned long ip = rec->ip;
 
 
 
 
 
 
 
 
 
 
 
 
 
405
406	/* read where this goes */
407	if (probe_kernel_read(&op, (void *)ip, MCOUNT_INSN_SIZE))
 
408		return -EFAULT;
 
409
410	/* It should be pointing to a nop */
411	if (op != PPC_INST_NOP) {
412		pr_err("Expected NOP but have %x\n", op);
413		return -EINVAL;
414	}
415
416	/* If we never set up a trampoline to ftrace_caller, then bail */
417	if (!rec->arch.mod->arch.tramp) {
418		pr_err("No ftrace trampoline\n");
419		return -EINVAL;
420	}
421
422	/* create the branch to the trampoline */
423	op = create_branch((unsigned int *)ip,
424			   rec->arch.mod->arch.tramp, BRANCH_SET_LINK);
425	if (!op) {
426		pr_err("REL24 out of range!\n");
427		return -EINVAL;
428	}
429
430	pr_devel("write to %lx\n", rec->ip);
431
432	if (patch_instruction((unsigned int *)ip, op))
433		return -EPERM;
434
435	return 0;
436}
437#endif /* CONFIG_PPC64 */
438#endif /* CONFIG_MODULES */
439
440int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
441{
442	unsigned long ip = rec->ip;
443	unsigned int old, new;
444
445	/*
446	 * If the calling address is more that 24 bits away,
447	 * then we had to use a trampoline to make the call.
448	 * Otherwise just update the call site.
449	 */
450	if (test_24bit_addr(ip, addr)) {
451		/* within range */
452		old = PPC_INST_NOP;
453		new = ftrace_call_replace(ip, addr, 1);
454		return ftrace_modify_code(ip, old, new);
 
 
 
 
 
455	}
456
457#ifdef CONFIG_MODULES
458	/*
459	 * Out of range jumps are called from modules.
460	 * Being that we are converting from nop, it had better
461	 * already have a module defined.
462	 */
463	if (!rec->arch.mod) {
464		pr_err("No module loaded\n");
465		return -EINVAL;
466	}
467
468	return __ftrace_make_call(rec, addr);
469#else
470	/* We should not get here without modules */
471	return -EINVAL;
472#endif /* CONFIG_MODULES */
473}
474
475int ftrace_update_ftrace_func(ftrace_func_t func)
 
 
 
 
476{
477	unsigned long ip = (unsigned long)(&ftrace_call);
478	unsigned int old, new;
479	int ret;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
480
481	old = *(unsigned int *)&ftrace_call;
482	new = ftrace_call_replace(ip, (unsigned long)func, 1);
483	ret = ftrace_modify_code(ip, old, new);
 
484
485	return ret;
 
 
 
 
 
486}
 
487
488static int __ftrace_replace_code(struct dyn_ftrace *rec, int enable)
 
489{
490	unsigned long ftrace_addr = (unsigned long)FTRACE_ADDR;
491	int ret;
492
493	ret = ftrace_update_record(rec, enable);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
494
495	switch (ret) {
496	case FTRACE_UPDATE_IGNORE:
497		return 0;
498	case FTRACE_UPDATE_MAKE_CALL:
499		return ftrace_make_call(rec, ftrace_addr);
500	case FTRACE_UPDATE_MAKE_NOP:
501		return ftrace_make_nop(NULL, rec, ftrace_addr);
502	}
503
504	return 0;
505}
 
506
507void ftrace_replace_code(int enable)
508{
509	struct ftrace_rec_iter *iter;
510	struct dyn_ftrace *rec;
511	int ret;
512
513	for (iter = ftrace_rec_iter_start(); iter;
514	     iter = ftrace_rec_iter_next(iter)) {
515		rec = ftrace_rec_iter_record(iter);
516		ret = __ftrace_replace_code(rec, enable);
517		if (ret) {
518			ftrace_bug(ret, rec);
519			return;
520		}
 
 
521	}
 
 
522}
523
524/*
525 * Use the default ftrace_modify_all_code, but without
526 * stop_machine().
527 */
528void arch_ftrace_update_code(int command)
529{
530	ftrace_modify_all_code(command);
531}
532
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
533int __init ftrace_dyn_arch_init(void)
534{
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
535	return 0;
536}
537#endif /* CONFIG_DYNAMIC_FTRACE */
538
539#ifdef CONFIG_FUNCTION_GRAPH_TRACER
540
541#ifdef CONFIG_DYNAMIC_FTRACE
542extern void ftrace_graph_call(void);
543extern void ftrace_graph_stub(void);
544
545int ftrace_enable_ftrace_graph_caller(void)
546{
547	unsigned long ip = (unsigned long)(&ftrace_graph_call);
548	unsigned long addr = (unsigned long)(&ftrace_graph_caller);
549	unsigned long stub = (unsigned long)(&ftrace_graph_stub);
550	unsigned int old, new;
 
 
 
551
552	old = ftrace_call_replace(ip, stub, 0);
553	new = ftrace_call_replace(ip, addr, 0);
554
555	return ftrace_modify_code(ip, old, new);
556}
557
 
 
 
 
 
558int ftrace_disable_ftrace_graph_caller(void)
559{
560	unsigned long ip = (unsigned long)(&ftrace_graph_call);
561	unsigned long addr = (unsigned long)(&ftrace_graph_caller);
562	unsigned long stub = (unsigned long)(&ftrace_graph_stub);
563	unsigned int old, new;
564
565	old = ftrace_call_replace(ip, addr, 0);
566	new = ftrace_call_replace(ip, stub, 0);
567
568	return ftrace_modify_code(ip, old, new);
569}
570#endif /* CONFIG_DYNAMIC_FTRACE */
571
572/*
573 * Hook the return address and push it in the stack of return addrs
574 * in current thread info. Return the address we want to divert to.
575 */
576unsigned long prepare_ftrace_return(unsigned long parent, unsigned long ip)
 
577{
578	struct ftrace_graph_ent trace;
579	unsigned long return_hooker;
 
580
581	if (unlikely(ftrace_graph_is_dead()))
582		goto out;
583
584	if (unlikely(atomic_read(&current->tracing_graph_pause)))
585		goto out;
586
 
 
 
 
587	return_hooker = ppc_function_entry(return_to_handler);
588
589	trace.func = ip;
590	trace.depth = current->curr_ret_stack + 1;
591
592	/* Only trace if the calling function expects to */
593	if (!ftrace_graph_entry(&trace))
594		goto out;
595
596	if (ftrace_push_return_trace(parent, ip, &trace.depth, 0,
597				     NULL) == -EBUSY)
598		goto out;
599
600	parent = return_hooker;
601out:
602	return parent;
603}
604#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
605
606#if defined(CONFIG_FTRACE_SYSCALLS) && defined(CONFIG_PPC64)
607unsigned long __init arch_syscall_addr(int nr)
 
608{
609	return sys_call_table[nr*2];
610}
611#endif /* CONFIG_FTRACE_SYSCALLS && CONFIG_PPC64 */
 
 
 
 
 
 
 
612
613#ifdef PPC64_ELF_ABI_v1
614char *arch_ftrace_match_adjust(char *str, const char *search)
615{
616	if (str[0] == '.' && search[0] != '.')
617		return str + 1;
618	else
619		return str;
620}
621#endif /* PPC64_ELF_ABI_v1 */