linux/arch/parisc/kernel/ftrace.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Code for tracing calls in Linux kernel.
   4 * Copyright (C) 2009-2016 Helge Deller <deller@gmx.de>
   5 *
   6 * based on code for x86 which is:
   7 * Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com>
   8 *
   9 * future possible enhancements:
  10 *      - add CONFIG_DYNAMIC_FTRACE
  11 *      - add CONFIG_STACK_TRACER
  12 */
  13
  14#include <linux/init.h>
  15#include <linux/ftrace.h>
  16
  17#include <asm/assembly.h>
  18#include <asm/sections.h>
  19#include <asm/ftrace.h>
  20
  21
  22#define __hot __attribute__ ((__section__ (".text.hot")))
  23
  24#ifdef CONFIG_FUNCTION_GRAPH_TRACER
  25/*
  26 * Hook the return address and push it in the stack of return addrs
  27 * in current thread info.
  28 */
  29static void __hot prepare_ftrace_return(unsigned long *parent,
  30                                        unsigned long self_addr)
  31{
  32        unsigned long old;
  33        struct ftrace_graph_ent trace;
  34        extern int parisc_return_to_handler;
  35
  36        if (unlikely(ftrace_graph_is_dead()))
  37                return;
  38
  39        if (unlikely(atomic_read(&current->tracing_graph_pause)))
  40                return;
  41
  42        old = *parent;
  43
  44        trace.func = self_addr;
  45        trace.depth = current->curr_ret_stack + 1;
  46
  47        /* Only trace if the calling function expects to */
  48        if (!ftrace_graph_entry(&trace))
  49                return;
  50
  51        if (ftrace_push_return_trace(old, self_addr, &trace.depth,
  52                                     0, NULL) == -EBUSY)
  53                return;
  54
  55        /* activate parisc_return_to_handler() as return point */
  56        *parent = (unsigned long) &parisc_return_to_handler;
  57}
  58#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
  59
  60void notrace __hot ftrace_function_trampoline(unsigned long parent,
  61                                unsigned long self_addr,
  62                                unsigned long org_sp_gr3)
  63{
  64        extern ftrace_func_t ftrace_trace_function;  /* depends on CONFIG_DYNAMIC_FTRACE */
  65        extern int ftrace_graph_entry_stub(struct ftrace_graph_ent *trace);
  66
  67        if (ftrace_trace_function != ftrace_stub) {
  68                /* struct ftrace_ops *op, struct pt_regs *regs); */
  69                ftrace_trace_function(parent, self_addr, NULL, NULL);
  70                return;
  71        }
  72
  73#ifdef CONFIG_FUNCTION_GRAPH_TRACER
  74        if (ftrace_graph_return != (trace_func_graph_ret_t) ftrace_stub ||
  75                ftrace_graph_entry != ftrace_graph_entry_stub) {
  76                unsigned long *parent_rp;
  77
  78                /* calculate pointer to %rp in stack */
  79                parent_rp = (unsigned long *) (org_sp_gr3 - RP_OFFSET);
  80                /* sanity check: parent_rp should hold parent */
  81                if (*parent_rp != parent)
  82                        return;
  83
  84                prepare_ftrace_return(parent_rp, self_addr);
  85                return;
  86        }
  87#endif
  88}
  89
  90