Lucas De MarchiFix common misspellings25985ed15 years agoHistory
1948 lines · 48.1 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 <linux/limits.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 MAX_STRING_SIZE PATH_MAX#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 *,				 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, void *ent)\{									\	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_rloc: data relative location, compatible with u32 */#define make_data_rloc(len, roffs)	\	(((u32)(len) << 16) | ((u32)(roffs) & 0xffff))#define get_rloc_len(dl)	((u32)(dl) >> 16)#define get_rloc_offs(dl)	((u32)(dl) & 0xffff) static inline void *get_rloc_data(u32 *dl){	return (u8 *)dl + get_rloc_offs(*dl);} /* For data_loc conversion */static inline void *get_loc_data(u32 *dl, void *ent){	return (u8 *)ent + get_rloc_offs(*dl);} /* * Convert data_rloc to data_loc: *  data_rloc stores the offset from data_rloc itself, but data_loc *  stores the offset from event entry. */#define convert_rloc_to_loc(dl, offs)	((u32)(dl) + (offs)) /* For defining macros, define string/string_size types */typedef u32 string;typedef u32 string_size; /* Print type function for string type */static __kprobes int PRINT_TYPE_FUNC_NAME(string)(struct trace_seq *s,						  const char *name,						  void *data, void *ent){	int len = *(u32 *)data >> 16; 	if (!len)		return trace_seq_printf(s, " %s=(fault)", name);	else		return trace_seq_printf(s, " %s=\"%s\"", name,					(const char *)get_loc_data(data, ent));}static const char PRINT_TYPE_FMT_NAME(string)[] = "\\\"%s\\\""; /* 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(method, type)	fetch_##method##_##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(method) \DEFINE_FETCH_##method(u8)		\DEFINE_FETCH_##method(u16)		\DEFINE_FETCH_##method(u32)		\DEFINE_FETCH_##method(u64) #define CHECK_FETCH_FUNCS(method, fn)			\	(((FETCH_FUNC_NAME(method, u8) == fn) ||	\	  (FETCH_FUNC_NAME(method, u16) == fn) ||	\	  (FETCH_FUNC_NAME(method, u32) == fn) ||	\	  (FETCH_FUNC_NAME(method, u64) == fn) ||	\	  (FETCH_FUNC_NAME(method, string) == fn) ||	\	  (FETCH_FUNC_NAME(method, string_size) == fn)) \	 && (fn != NULL)) /* 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)/* No string on the register */#define fetch_reg_string NULL#define fetch_reg_string_size NULL #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)/* No string on the stack entry */#define fetch_stack_string NULL#define fetch_stack_string_size NULL #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)/* No string on the retval */#define fetch_retval_string NULL#define fetch_retval_string_size NULL #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)/* * Fetch a null-terminated string. Caller MUST set *(u32 *)dest with max * length and relative data location. */static __kprobes void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs,						      void *addr, void *dest){	long ret;	int maxlen = get_rloc_len(*(u32 *)dest);	u8 *dst = get_rloc_data(dest);	u8 *src = addr;	mm_segment_t old_fs = get_fs();	if (!maxlen)		return;	/*	 * Try to get string again, since the string can be changed while	 * probing.	 */	set_fs(KERNEL_DS);	pagefault_disable();	do		ret = __copy_from_user_inatomic(dst++, src++, 1);	while (dst[-1] && ret == 0 && src - (u8 *)addr < maxlen);	dst[-1] = '\0';	pagefault_enable();	set_fs(old_fs); 	if (ret < 0) {	/* Failed to fetch string */		((u8 *)get_rloc_data(dest))[0] = '\0';		*(u32 *)dest = make_data_rloc(0, get_rloc_offs(*(u32 *)dest));	} else		*(u32 *)dest = make_data_rloc(src - (u8 *)addr,					      get_rloc_offs(*(u32 *)dest));}/* Return the length of string -- including null terminal byte */static __kprobes void FETCH_FUNC_NAME(memory, string_size)(struct pt_regs *regs,							void *addr, void *dest){	int ret, len = 0;	u8 c;	mm_segment_t old_fs = get_fs(); 	set_fs(KERNEL_DS);	pagefault_disable();	do {		ret = __copy_from_user_inatomic(&c, (u8 *)addr + len, 1);		len++;	} while (c && ret == 0 && len < MAX_STRING_SIZE);	pagefault_enable();	set_fs(old_fs); 	if (ret < 0)	/* Failed to check the length */		*(u32 *)dest = 0;	else		*(u32 *)dest = len;} /* 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)DEFINE_FETCH_symbol(string)DEFINE_FETCH_symbol(string_size) /* 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)DEFINE_FETCH_deref(string)DEFINE_FETCH_deref(string_size) static __kprobes void free_deref_fetch_param(struct deref_fetch_param *data){	if (CHECK_FETCH_FUNCS(deref, data->orig.fn))		free_deref_fetch_param(data->orig.data);	else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn))		free_symbol_cache(data->orig.data);	kfree(data);} /* Bitfield fetch function */struct bitfield_fetch_param {	struct fetch_param orig;	unsigned char hi_shift;	unsigned char low_shift;}; #define DEFINE_FETCH_bitfield(type)					\static __kprobes void FETCH_FUNC_NAME(bitfield, type)(struct pt_regs *regs,\					    void *data, void *dest)	\{									\	struct bitfield_fetch_param *bprm = data;			\	type buf = 0;							\	call_fetch(&bprm->orig, regs, &buf);				\	if (buf) {							\		buf <<= bprm->hi_shift;					\		buf >>= bprm->low_shift;				\	}								\	*(type *)dest = buf;						\}DEFINE_BASIC_FETCH_FUNCS(bitfield)#define fetch_bitfield_string NULL#define fetch_bitfield_string_size NULL static __kprobes voidfree_bitfield_fetch_param(struct bitfield_fetch_param *data){	/*	 * Don't check the bitfield itself, because this must be the	 * last fetch function.	 */	if (CHECK_FETCH_FUNCS(deref, data->orig.fn))		free_deref_fetch_param(data->orig.data);	else if (CHECK_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) /* Fetch types */enum {	FETCH_MTD_reg = 0,	FETCH_MTD_stack,	FETCH_MTD_retval,	FETCH_MTD_memory,	FETCH_MTD_symbol,	FETCH_MTD_deref,	FETCH_MTD_bitfield,	FETCH_MTD_END,}; #define ASSIGN_FETCH_FUNC(method, type)	\	[FETCH_MTD_##method] = FETCH_FUNC_NAME(method, type) #define __ASSIGN_FETCH_TYPE(_name, ptype, ftype, _size, sign, _fmttype)	\	{.name = _name,				\	 .size = _size,					\	 .is_signed = sign,				\	 .print = PRINT_TYPE_FUNC_NAME(ptype),		\	 .fmt = PRINT_TYPE_FMT_NAME(ptype),		\	 .fmttype = _fmttype,				\	 .fetch = {					\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),			\ASSIGN_FETCH_FUNC(bitfield, ftype),			\	  }						\	} #define ASSIGN_FETCH_TYPE(ptype, ftype, sign)			\	__ASSIGN_FETCH_TYPE(#ptype, ptype, ftype, sizeof(ftype), sign, #ptype) #define FETCH_TYPE_STRING 0#define FETCH_TYPE_STRSIZE 1 /* 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 */	const char	*fmttype;	/* Name in format file */	/* Fetch functions */	fetch_func_t	fetch[FETCH_MTD_END];} fetch_type_table[] = {	/* Special types */	[FETCH_TYPE_STRING] = __ASSIGN_FETCH_TYPE("string", string, string,					sizeof(u32), 1, "__data_loc char[]"),	[FETCH_TYPE_STRSIZE] = __ASSIGN_FETCH_TYPE("string_size", u32,					string_size, sizeof(u32), 0, "u32"),	/* Basic types */	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; 	/* Special case: bitfield */	if (*type == 'b') {		unsigned long bs;		type = strchr(type, '/');		if (!type)			goto fail;		type++;		if (strict_strtoul(type, 0, &bs))			goto fail;		switch (bs) {		case 8:			return find_fetch_type("u8");		case 16:			return find_fetch_type("u16");		case 32:			return find_fetch_type("u32");		case 64:			return find_fetch_type("u64");		default:			goto fail;		}	} 	for (i = 0; i < ARRAY_SIZE(fetch_type_table); i++)		if (strcmp(type, fetch_type_table[i].name) == 0)			return &fetch_type_table[i];fail:	return NULL;}

Lines 1–500 of 1948.