1632 lines · 39.3 KB · C
RawDownload
/* * Kprobes-based tracing events * * Created by Masami Hiramatsu <mhiramat@redhat.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */ #include <linux/module.h>#include <linux/uaccess.h>#include <linux/kprobes.h>#include <linux/seq_file.h>#include <linux/slab.h>#include <linux/smp.h>#include <linux/debugfs.h>#include <linux/types.h>#include <linux/string.h>#include <linux/ctype.h>#include <linux/ptrace.h>#include <linux/perf_event.h>#include <linux/stringify.h>#include <asm/bitsperlong.h> #include "trace.h"#include "trace_output.h" #define MAX_TRACE_ARGS 128#define MAX_ARGSTR_LEN 63#define MAX_EVENT_NAME_LEN 64#define KPROBE_EVENT_SYSTEM "kprobes" /* Reserved field names */#define FIELD_STRING_IP "__probe_ip"#define FIELD_STRING_RETIP "__probe_ret_ip"#define FIELD_STRING_FUNC "__probe_func" const char *reserved_field_names[] = {	"common_type",	"common_flags",	"common_preempt_count",	"common_pid",	"common_tgid",	"common_lock_depth",	FIELD_STRING_IP,	FIELD_STRING_RETIP,	FIELD_STRING_FUNC,}; /* Printing function type */typedef int (*print_type_func_t)(struct trace_seq *, const char *, void *);#define PRINT_TYPE_FUNC_NAME(type)	print_type_##type#define PRINT_TYPE_FMT_NAME(type)	print_type_format_##type /* Printing  in basic type function template */#define DEFINE_BASIC_PRINT_TYPE_FUNC(type, fmt, cast)			\static __kprobes int PRINT_TYPE_FUNC_NAME(type)(struct trace_seq *s,	\						const char *name, void *data)\{									\	return trace_seq_printf(s, " %s=" fmt, name, (cast)*(type *)data);\}									\static const char PRINT_TYPE_FMT_NAME(type)[] = fmt; DEFINE_BASIC_PRINT_TYPE_FUNC(u8, "%x", unsigned int)DEFINE_BASIC_PRINT_TYPE_FUNC(u16, "%x", unsigned int)DEFINE_BASIC_PRINT_TYPE_FUNC(u32, "%lx", unsigned long)DEFINE_BASIC_PRINT_TYPE_FUNC(u64, "%llx", unsigned long long)DEFINE_BASIC_PRINT_TYPE_FUNC(s8, "%d", int)DEFINE_BASIC_PRINT_TYPE_FUNC(s16, "%d", int)DEFINE_BASIC_PRINT_TYPE_FUNC(s32, "%ld", long)DEFINE_BASIC_PRINT_TYPE_FUNC(s64, "%lld", long long) /* Data fetch function type */typedef	void (*fetch_func_t)(struct pt_regs *, void *, void *); struct fetch_param {	fetch_func_t	fn;	void *data;}; static __kprobes void call_fetch(struct fetch_param *fprm,				 struct pt_regs *regs, void *dest){	return fprm->fn(regs, fprm->data, dest);} #define FETCH_FUNC_NAME(kind, type)	fetch_##kind##_##type/* * Define macro for basic types - we don't need to define s* types, because * we have to care only about bitwidth at recording time. */#define DEFINE_BASIC_FETCH_FUNCS(kind)  \DEFINE_FETCH_##kind(u8)			\DEFINE_FETCH_##kind(u16)		\DEFINE_FETCH_##kind(u32)		\DEFINE_FETCH_##kind(u64) #define CHECK_BASIC_FETCH_FUNCS(kind, fn)	\	((FETCH_FUNC_NAME(kind, u8) == fn) ||	\	 (FETCH_FUNC_NAME(kind, u16) == fn) ||	\	 (FETCH_FUNC_NAME(kind, u32) == fn) ||	\	 (FETCH_FUNC_NAME(kind, u64) == fn)) /* Data fetch function templates */#define DEFINE_FETCH_reg(type)						\static __kprobes void FETCH_FUNC_NAME(reg, type)(struct pt_regs *regs,	\					  void *offset, void *dest)	\{									\	*(type *)dest = (type)regs_get_register(regs,			\				(unsigned int)((unsigned long)offset));	\}DEFINE_BASIC_FETCH_FUNCS(reg) #define DEFINE_FETCH_stack(type)					\static __kprobes void FETCH_FUNC_NAME(stack, type)(struct pt_regs *regs,\					  void *offset, void *dest)	\{									\	*(type *)dest = (type)regs_get_kernel_stack_nth(regs,		\				(unsigned int)((unsigned long)offset));	\}DEFINE_BASIC_FETCH_FUNCS(stack) #define DEFINE_FETCH_retval(type)					\static __kprobes void FETCH_FUNC_NAME(retval, type)(struct pt_regs *regs,\					  void *dummy, void *dest)	\{									\	*(type *)dest = (type)regs_return_value(regs);			\}DEFINE_BASIC_FETCH_FUNCS(retval) #define DEFINE_FETCH_memory(type)					\static __kprobes void FETCH_FUNC_NAME(memory, type)(struct pt_regs *regs,\					  void *addr, void *dest)	\{									\	type retval;							\	if (probe_kernel_address(addr, retval))				\		*(type *)dest = 0;					\	else								\		*(type *)dest = retval;					\}DEFINE_BASIC_FETCH_FUNCS(memory) /* Memory fetching by symbol */struct symbol_cache {	char *symbol;	long offset;	unsigned long addr;}; static unsigned long update_symbol_cache(struct symbol_cache *sc){	sc->addr = (unsigned long)kallsyms_lookup_name(sc->symbol);	if (sc->addr)		sc->addr += sc->offset;	return sc->addr;} static void free_symbol_cache(struct symbol_cache *sc){	kfree(sc->symbol);	kfree(sc);} static struct symbol_cache *alloc_symbol_cache(const char *sym, long offset){	struct symbol_cache *sc; 	if (!sym || strlen(sym) == 0)		return NULL;	sc = kzalloc(sizeof(struct symbol_cache), GFP_KERNEL);	if (!sc)		return NULL; 	sc->symbol = kstrdup(sym, GFP_KERNEL);	if (!sc->symbol) {		kfree(sc);		return NULL;	}	sc->offset = offset; 	update_symbol_cache(sc);	return sc;} #define DEFINE_FETCH_symbol(type)					\static __kprobes void FETCH_FUNC_NAME(symbol, type)(struct pt_regs *regs,\					  void *data, void *dest)	\{									\	struct symbol_cache *sc = data;					\	if (sc->addr)							\		fetch_memory_##type(regs, (void *)sc->addr, dest);	\	else								\		*(type *)dest = 0;					\}DEFINE_BASIC_FETCH_FUNCS(symbol) /* Dereference memory access function */struct deref_fetch_param {	struct fetch_param orig;	long offset;}; #define DEFINE_FETCH_deref(type)					\static __kprobes void FETCH_FUNC_NAME(deref, type)(struct pt_regs *regs,\					    void *data, void *dest)	\{									\	struct deref_fetch_param *dprm = data;				\	unsigned long addr;						\	call_fetch(&dprm->orig, regs, &addr);				\	if (addr) {							\		addr += dprm->offset;					\		fetch_memory_##type(regs, (void *)addr, dest);		\	} else								\		*(type *)dest = 0;					\}DEFINE_BASIC_FETCH_FUNCS(deref) static __kprobes void free_deref_fetch_param(struct deref_fetch_param *data){	if (CHECK_BASIC_FETCH_FUNCS(deref, data->orig.fn))		free_deref_fetch_param(data->orig.data);	else if (CHECK_BASIC_FETCH_FUNCS(symbol, data->orig.fn))		free_symbol_cache(data->orig.data);	kfree(data);} /* Default (unsigned long) fetch type */#define __DEFAULT_FETCH_TYPE(t) u##t#define _DEFAULT_FETCH_TYPE(t) __DEFAULT_FETCH_TYPE(t)#define DEFAULT_FETCH_TYPE _DEFAULT_FETCH_TYPE(BITS_PER_LONG)#define DEFAULT_FETCH_TYPE_STR __stringify(DEFAULT_FETCH_TYPE) #define ASSIGN_FETCH_FUNC(kind, type)	\	.kind = FETCH_FUNC_NAME(kind, type) #define ASSIGN_FETCH_TYPE(ptype, ftype, sign)	\	{.name = #ptype,			\	 .size = sizeof(ftype),			\	 .is_signed = sign,			\	 .print = PRINT_TYPE_FUNC_NAME(ptype),	\	 .fmt = PRINT_TYPE_FMT_NAME(ptype),	\ASSIGN_FETCH_FUNC(reg, ftype),			\ASSIGN_FETCH_FUNC(stack, ftype),		\ASSIGN_FETCH_FUNC(retval, ftype),		\ASSIGN_FETCH_FUNC(memory, ftype),		\ASSIGN_FETCH_FUNC(symbol, ftype),		\ASSIGN_FETCH_FUNC(deref, ftype),		\	} /* Fetch type information table */static const struct fetch_type {	const char	*name;		/* Name of type */	size_t		size;		/* Byte size of type */	int		is_signed;	/* Signed flag */	print_type_func_t	print;	/* Print functions */	const char	*fmt;		/* Fromat string */	/* Fetch functions */	fetch_func_t	reg;	fetch_func_t	stack;	fetch_func_t	retval;	fetch_func_t	memory;	fetch_func_t	symbol;	fetch_func_t	deref;} fetch_type_table[] = {	ASSIGN_FETCH_TYPE(u8,  u8,  0),	ASSIGN_FETCH_TYPE(u16, u16, 0),	ASSIGN_FETCH_TYPE(u32, u32, 0),	ASSIGN_FETCH_TYPE(u64, u64, 0),	ASSIGN_FETCH_TYPE(s8,  u8,  1),	ASSIGN_FETCH_TYPE(s16, u16, 1),	ASSIGN_FETCH_TYPE(s32, u32, 1),	ASSIGN_FETCH_TYPE(s64, u64, 1),}; static const struct fetch_type *find_fetch_type(const char *type){	int i; 	if (!type)		type = DEFAULT_FETCH_TYPE_STR; 	for (i = 0; i < ARRAY_SIZE(fetch_type_table); i++)		if (strcmp(type, fetch_type_table[i].name) == 0)			return &fetch_type_table[i];	return NULL;} /* Special function : only accept unsigned long */static __kprobes void fetch_stack_address(struct pt_regs *regs,					  void *dummy, void *dest){	*(unsigned long *)dest = kernel_stack_pointer(regs);} /** * Kprobe event core functions */ struct probe_arg {	struct fetch_param	fetch;	unsigned int		offset;	/* Offset from argument entry */	const char		*name;	/* Name of this argument */	const char		*comm;	/* Command of this argument */	const struct fetch_type	*type;	/* Type of this argument */}; /* Flags for trace_probe */#define TP_FLAG_TRACE	1#define TP_FLAG_PROFILE	2 struct trace_probe {	struct list_head	list;	struct kretprobe	rp;	/* Use rp.kp for kprobe use */	unsigned long 		nhit;	unsigned int		flags;	/* For TP_FLAG_* */	const char		*symbol;	/* symbol name */	struct ftrace_event_class	class;	struct ftrace_event_call	call;	ssize_t			size;		/* trace entry size */	unsigned int		nr_args;	struct probe_arg	args[];}; #define SIZEOF_TRACE_PROBE(n)			\	(offsetof(struct trace_probe, args) +	\	(sizeof(struct probe_arg) * (n)))  static __kprobes int probe_is_return(struct trace_probe *tp){	return tp->rp.handler != NULL;} static __kprobes const char *probe_symbol(struct trace_probe *tp){	return tp->symbol ? tp->symbol : "unknown";} static int register_probe_event(struct trace_probe *tp);static void unregister_probe_event(struct trace_probe *tp); static DEFINE_MUTEX(probe_lock);static LIST_HEAD(probe_list); static int kprobe_dispatcher(struct kprobe *kp, struct pt_regs *regs);static int kretprobe_dispatcher(struct kretprobe_instance *ri,				struct pt_regs *regs); /* Check the name is good for event/group */static int check_event_name(const char *name){	if (!isalpha(*name) && *name != '_')		return 0;	while (*++name != '\0') {		if (!isalpha(*name) && !isdigit(*name) && *name != '_')			return 0;	}	return 1;} /* * Allocate new trace_probe and initialize it (including kprobes). */static struct trace_probe *alloc_trace_probe(const char *group,					     const char *event,					     void *addr,					     const char *symbol,					     unsigned long offs,					     int nargs, int is_return){	struct trace_probe *tp;	int ret = -ENOMEM; 	tp = kzalloc(SIZEOF_TRACE_PROBE(nargs), GFP_KERNEL);	if (!tp)		return ERR_PTR(ret); 	if (symbol) {		tp->symbol = kstrdup(symbol, GFP_KERNEL);		if (!tp->symbol)			goto error;		tp->rp.kp.symbol_name = tp->symbol;		tp->rp.kp.offset = offs;	} else		tp->rp.kp.addr = addr; 	if (is_return)		tp->rp.handler = kretprobe_dispatcher;	else		tp->rp.kp.pre_handler = kprobe_dispatcher; 	if (!event || !check_event_name(event)) {		ret = -EINVAL;		goto error;	} 	tp->call.class = &tp->class;	tp->call.name = kstrdup(event, GFP_KERNEL);	if (!tp->call.name)		goto error; 	if (!group || !check_event_name(group)) {		ret = -EINVAL;		goto error;	} 	tp->class.system = kstrdup(group, GFP_KERNEL);	if (!tp->class.system)		goto error; 	INIT_LIST_HEAD(&tp->list);	return tp;error:	kfree(tp->call.name);	kfree(tp->symbol);	kfree(tp);	return ERR_PTR(ret);} static void free_probe_arg(struct probe_arg *arg){	if (CHECK_BASIC_FETCH_FUNCS(deref, arg->fetch.fn))		free_deref_fetch_param(arg->fetch.data);	else if (CHECK_BASIC_FETCH_FUNCS(symbol, arg->fetch.fn))		free_symbol_cache(arg->fetch.data);	kfree(arg->name);	kfree(arg->comm);} static void free_trace_probe(struct trace_probe *tp){	int i; 	for (i = 0; i < tp->nr_args; i++)		free_probe_arg(&tp->args[i]); 	kfree(tp->call.class->system);	kfree(tp->call.name);	kfree(tp->symbol);	kfree(tp);} static struct trace_probe *find_probe_event(const char *event,					    const char *group){	struct trace_probe *tp; 	list_for_each_entry(tp, &probe_list, list)		if (strcmp(tp->call.name, event) == 0 &&		    strcmp(tp->call.class->system, group) == 0)			return tp;	return NULL;} /* Unregister a trace_probe and probe_event: call with locking probe_lock */static void unregister_trace_probe(struct trace_probe *tp){	if (probe_is_return(tp))		unregister_kretprobe(&tp->rp);	else		unregister_kprobe(&tp->rp.kp);	list_del(&tp->list);	unregister_probe_event(tp);} /* Register a trace_probe and probe_event */static int register_trace_probe(struct trace_probe *tp){	struct trace_probe *old_tp;	int ret; 	mutex_lock(&probe_lock); 	/* register as an event */	old_tp = find_probe_event(tp->call.name, tp->call.class->system);	if (old_tp) {		/* delete old event */		unregister_trace_probe(old_tp);		free_trace_probe(old_tp);	}	ret = register_probe_event(tp);	if (ret) {		pr_warning("Faild to register probe event(%d)\n", ret);		goto end;	} 	tp->rp.kp.flags |= KPROBE_FLAG_DISABLED;	if (probe_is_return(tp))		ret = register_kretprobe(&tp->rp);	else

Lines 1–500 of 1632.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t