Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ee08c6ec authored by Frederic Weisbecker's avatar Frederic Weisbecker Committed by Ingo Molnar
Browse files

tracing/ftrace: syscall tracing infrastructure, basics



Provide basic callbacks to do syscall tracing.

Signed-off-by: default avatarFrederic Weisbecker <fweisbec@gmail.com>
Acked-by: default avatarSteven Rostedt <rostedt@goodmis.org>
Cc: Lai Jiangshan <laijs@cn.fujitsu.com>
LKML-Reference: <1236401580-5758-2-git-send-email-fweisbec@gmail.com>
[ simplified it to a trace_printk() for now. ]
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent 4c6ed8f4
Loading
Loading
Loading
Loading
+21 −0
Original line number Original line Diff line number Diff line
@@ -503,4 +503,25 @@ static inline void trace_hw_branch_oops(void) {}


#endif /* CONFIG_HW_BRANCH_TRACER */
#endif /* CONFIG_HW_BRANCH_TRACER */


/*
 * A syscall entry in the ftrace syscalls array.
 *
 * @syscall_nr: syscall number
 */
struct syscall_trace_entry {
	int		syscall_nr;
};

#ifdef CONFIG_FTRACE_SYSCALLS
extern void start_ftrace_syscalls(void);
extern void stop_ftrace_syscalls(void);
extern void ftrace_syscall_enter(struct pt_regs *regs);
extern void ftrace_syscall_exit(struct pt_regs *regs);
#else
static inline void start_ftrace_syscalls(void) { }
static inline void stop_ftrace_syscalls(void) { }
static inline void ftrace_syscall_enter(struct pt_regs *regs) { }
static inline void ftrace_syscall_exit(struct pt_regs *regs) { }
#endif

#endif /* _LINUX_FTRACE_H */
#endif /* _LINUX_FTRACE_H */
+10 −0
Original line number Original line Diff line number Diff line
@@ -34,6 +34,9 @@ config HAVE_FTRACE_MCOUNT_RECORD
config HAVE_HW_BRANCH_TRACER
config HAVE_HW_BRANCH_TRACER
	bool
	bool


config HAVE_FTRACE_SYSCALLS
	bool

config TRACER_MAX_TRACE
config TRACER_MAX_TRACE
	bool
	bool


@@ -175,6 +178,13 @@ config EVENT_TRACER
	  allowing the user to pick and choose which trace point they
	  allowing the user to pick and choose which trace point they
	  want to trace.
	  want to trace.


config FTRACE_SYSCALLS
	bool "Trace syscalls"
	depends on HAVE_FTRACE_SYSCALLS
	select TRACING
	help
	  Basic tracer to catch the syscall entry and exit events.

config BOOT_TRACER
config BOOT_TRACER
	bool "Trace boot initcalls"
	bool "Trace boot initcalls"
	select TRACING
	select TRACING
+1 −0
Original line number Original line Diff line number Diff line
@@ -43,5 +43,6 @@ obj-$(CONFIG_BLK_DEV_IO_TRACE) += blktrace.o
obj-$(CONFIG_EVENT_TRACER) += trace_events.o
obj-$(CONFIG_EVENT_TRACER) += trace_events.o
obj-$(CONFIG_EVENT_TRACER) += events.o
obj-$(CONFIG_EVENT_TRACER) += events.o
obj-$(CONFIG_EVENT_TRACER) += trace_export.o
obj-$(CONFIG_EVENT_TRACER) += trace_export.o
obj-$(CONFIG_FTRACE_SYSCALLS) += trace_syscalls.o


libftrace-y := ftrace.o
libftrace-y := ftrace.o
+2 −0
Original line number Original line Diff line number Diff line
@@ -30,6 +30,8 @@ enum trace_type {
	TRACE_GRAPH_ENT,
	TRACE_GRAPH_ENT,
	TRACE_USER_STACK,
	TRACE_USER_STACK,
	TRACE_HW_BRANCHES,
	TRACE_HW_BRANCHES,
	TRACE_SYSCALL_ENTER,
	TRACE_SYSCALL_EXIT,
	TRACE_KMEM_ALLOC,
	TRACE_KMEM_ALLOC,
	TRACE_KMEM_FREE,
	TRACE_KMEM_FREE,
	TRACE_POWER,
	TRACE_POWER,
+113 −0
Original line number Original line Diff line number Diff line
#include <linux/ftrace.h>
#include <linux/kernel.h>

#include <asm/syscall.h>

#include "trace_output.h"
#include "trace.h"

static atomic_t refcount;

void start_ftrace_syscalls(void)
{
	unsigned long flags;
	struct task_struct *g, *t;

	if (atomic_inc_return(&refcount) != 1)
		goto out;

	read_lock_irqsave(&tasklist_lock, flags);

	do_each_thread(g, t) {
		set_tsk_thread_flag(t, TIF_SYSCALL_FTRACE);
	} while_each_thread(g, t);

	read_unlock_irqrestore(&tasklist_lock, flags);
out:
	atomic_dec(&refcount);
}

void stop_ftrace_syscalls(void)
{
	unsigned long flags;
	struct task_struct *g, *t;

	if (atomic_dec_return(&refcount))
		goto out;

	read_lock_irqsave(&tasklist_lock, flags);

	do_each_thread(g, t) {
		clear_tsk_thread_flag(t, TIF_SYSCALL_FTRACE);
	} while_each_thread(g, t);

	read_unlock_irqrestore(&tasklist_lock, flags);
out:
	atomic_inc(&refcount);
}

void ftrace_syscall_enter(struct pt_regs *regs)
{
	int syscall_nr;

	syscall_nr = syscall_get_nr(current, regs);

	trace_printk("syscall %d enter\n", syscall_nr);
}

void ftrace_syscall_exit(struct pt_regs *regs)
{
	int syscall_nr;

	syscall_nr = syscall_get_nr(current, regs);

	trace_printk("syscall %d exit\n", syscall_nr);
}

static int init_syscall_tracer(struct trace_array *tr)
{
	start_ftrace_syscalls();

	return 0;
}

static void reset_syscall_tracer(struct trace_array *tr)
{
	stop_ftrace_syscalls();
}

static struct trace_event syscall_enter_event = {
	.type		= TRACE_SYSCALL_ENTER,
};

static struct trace_event syscall_exit_event = {
	.type		= TRACE_SYSCALL_EXIT,
};

static struct tracer syscall_tracer __read_mostly = {
	.name		= "syscall",
	.init		= init_syscall_tracer,
	.reset		= reset_syscall_tracer
};

__init int register_ftrace_syscalls(void)
{
	int ret;

	ret = register_ftrace_event(&syscall_enter_event);
	if (!ret) {
		printk(KERN_WARNING "event %d failed to register\n",
		       syscall_enter_event.type);
		WARN_ON_ONCE(1);
	}

	ret = register_ftrace_event(&syscall_exit_event);
	if (!ret) {
		printk(KERN_WARNING "event %d failed to register\n",
		       syscall_exit_event.type);
		WARN_ON_ONCE(1);
	}

	return register_tracer(&syscall_tracer);
}
device_initcall(register_ftrace_syscalls);