| .. | .. | 
|---|
| 13 | 13 |   | 
|---|
| 14 | 14 |  #include "trace_probe.h" | 
|---|
| 15 | 15 |   | 
|---|
| 16 |  | -const char *reserved_field_names[] = {  | 
|---|
 | 16 | +#undef C  | 
|---|
 | 17 | +#define C(a, b)		b  | 
|---|
 | 18 | +  | 
|---|
 | 19 | +static const char *trace_probe_err_text[] = { ERRORS };  | 
|---|
 | 20 | +  | 
|---|
 | 21 | +static const char *reserved_field_names[] = {  | 
|---|
| 17 | 22 |  	"common_type", | 
|---|
| 18 | 23 |  	"common_flags", | 
|---|
| 19 | 24 |  	"common_preempt_count", | 
|---|
| .. | .. | 
|---|
| 26 | 31 |   | 
|---|
| 27 | 32 |  /* Printing  in basic type function template */ | 
|---|
| 28 | 33 |  #define DEFINE_BASIC_PRINT_TYPE_FUNC(tname, type, fmt)			\ | 
|---|
| 29 |  | -int PRINT_TYPE_FUNC_NAME(tname)(struct trace_seq *s, const char *name,	\  | 
|---|
| 30 |  | -				void *data, void *ent)			\  | 
|---|
 | 34 | +int PRINT_TYPE_FUNC_NAME(tname)(struct trace_seq *s, void *data, void *ent)\  | 
|---|
| 31 | 35 |  {									\ | 
|---|
| 32 |  | -	trace_seq_printf(s, " %s=" fmt, name, *(type *)data);		\  | 
|---|
 | 36 | +	trace_seq_printf(s, fmt, *(type *)data);			\  | 
|---|
| 33 | 37 |  	return !trace_seq_has_overflowed(s);				\ | 
|---|
| 34 | 38 |  }									\ | 
|---|
| 35 |  | -const char PRINT_TYPE_FMT_NAME(tname)[] = fmt;				\  | 
|---|
| 36 |  | -NOKPROBE_SYMBOL(PRINT_TYPE_FUNC_NAME(tname));  | 
|---|
 | 39 | +const char PRINT_TYPE_FMT_NAME(tname)[] = fmt;  | 
|---|
| 37 | 40 |   | 
|---|
| 38 | 41 |  DEFINE_BASIC_PRINT_TYPE_FUNC(u8,  u8,  "%u") | 
|---|
| 39 | 42 |  DEFINE_BASIC_PRINT_TYPE_FUNC(u16, u16, "%u") | 
|---|
| .. | .. | 
|---|
| 48 | 51 |  DEFINE_BASIC_PRINT_TYPE_FUNC(x32, u32, "0x%x") | 
|---|
| 49 | 52 |  DEFINE_BASIC_PRINT_TYPE_FUNC(x64, u64, "0x%Lx") | 
|---|
| 50 | 53 |   | 
|---|
 | 54 | +int PRINT_TYPE_FUNC_NAME(symbol)(struct trace_seq *s, void *data, void *ent)  | 
|---|
 | 55 | +{  | 
|---|
 | 56 | +	trace_seq_printf(s, "%pS", (void *)*(unsigned long *)data);  | 
|---|
 | 57 | +	return !trace_seq_has_overflowed(s);  | 
|---|
 | 58 | +}  | 
|---|
 | 59 | +const char PRINT_TYPE_FMT_NAME(symbol)[] = "%pS";  | 
|---|
 | 60 | +  | 
|---|
| 51 | 61 |  /* Print type function for string type */ | 
|---|
| 52 |  | -int PRINT_TYPE_FUNC_NAME(string)(struct trace_seq *s, const char *name,  | 
|---|
| 53 |  | -				 void *data, void *ent)  | 
|---|
 | 62 | +int PRINT_TYPE_FUNC_NAME(string)(struct trace_seq *s, void *data, void *ent)  | 
|---|
| 54 | 63 |  { | 
|---|
| 55 | 64 |  	int len = *(u32 *)data >> 16; | 
|---|
| 56 | 65 |   | 
|---|
| 57 | 66 |  	if (!len) | 
|---|
| 58 |  | -		trace_seq_printf(s, " %s=(fault)", name);  | 
|---|
 | 67 | +		trace_seq_puts(s, "(fault)");  | 
|---|
| 59 | 68 |  	else | 
|---|
| 60 |  | -		trace_seq_printf(s, " %s=\"%s\"", name,  | 
|---|
 | 69 | +		trace_seq_printf(s, "\"%s\"",  | 
|---|
| 61 | 70 |  				 (const char *)get_loc_data(data, ent)); | 
|---|
| 62 | 71 |  	return !trace_seq_has_overflowed(s); | 
|---|
| 63 | 72 |  } | 
|---|
| 64 |  | -NOKPROBE_SYMBOL(PRINT_TYPE_FUNC_NAME(string));  | 
|---|
| 65 | 73 |   | 
|---|
| 66 | 74 |  const char PRINT_TYPE_FMT_NAME(string)[] = "\\\"%s\\\""; | 
|---|
| 67 | 75 |   | 
|---|
| 68 |  | -#define CHECK_FETCH_FUNCS(method, fn)			\  | 
|---|
| 69 |  | -	(((FETCH_FUNC_NAME(method, u8) == fn) ||	\  | 
|---|
| 70 |  | -	  (FETCH_FUNC_NAME(method, u16) == fn) ||	\  | 
|---|
| 71 |  | -	  (FETCH_FUNC_NAME(method, u32) == fn) ||	\  | 
|---|
| 72 |  | -	  (FETCH_FUNC_NAME(method, u64) == fn) ||	\  | 
|---|
| 73 |  | -	  (FETCH_FUNC_NAME(method, string) == fn) ||	\  | 
|---|
| 74 |  | -	  (FETCH_FUNC_NAME(method, string_size) == fn)) \  | 
|---|
| 75 |  | -	 && (fn != NULL))  | 
|---|
 | 76 | +/* Fetch type information table */  | 
|---|
 | 77 | +static const struct fetch_type probe_fetch_types[] = {  | 
|---|
 | 78 | +	/* Special types */  | 
|---|
 | 79 | +	__ASSIGN_FETCH_TYPE("string", string, string, sizeof(u32), 1,  | 
|---|
 | 80 | +			    "__data_loc char[]"),  | 
|---|
 | 81 | +	__ASSIGN_FETCH_TYPE("ustring", string, string, sizeof(u32), 1,  | 
|---|
 | 82 | +			    "__data_loc char[]"),  | 
|---|
 | 83 | +	/* Basic types */  | 
|---|
 | 84 | +	ASSIGN_FETCH_TYPE(u8,  u8,  0),  | 
|---|
 | 85 | +	ASSIGN_FETCH_TYPE(u16, u16, 0),  | 
|---|
 | 86 | +	ASSIGN_FETCH_TYPE(u32, u32, 0),  | 
|---|
 | 87 | +	ASSIGN_FETCH_TYPE(u64, u64, 0),  | 
|---|
 | 88 | +	ASSIGN_FETCH_TYPE(s8,  u8,  1),  | 
|---|
 | 89 | +	ASSIGN_FETCH_TYPE(s16, u16, 1),  | 
|---|
 | 90 | +	ASSIGN_FETCH_TYPE(s32, u32, 1),  | 
|---|
 | 91 | +	ASSIGN_FETCH_TYPE(s64, u64, 1),  | 
|---|
 | 92 | +	ASSIGN_FETCH_TYPE_ALIAS(x8,  u8,  u8,  0),  | 
|---|
 | 93 | +	ASSIGN_FETCH_TYPE_ALIAS(x16, u16, u16, 0),  | 
|---|
 | 94 | +	ASSIGN_FETCH_TYPE_ALIAS(x32, u32, u32, 0),  | 
|---|
 | 95 | +	ASSIGN_FETCH_TYPE_ALIAS(x64, u64, u64, 0),  | 
|---|
 | 96 | +	ASSIGN_FETCH_TYPE_ALIAS(symbol, ADDR_FETCH_TYPE, ADDR_FETCH_TYPE, 0),  | 
|---|
| 76 | 97 |   | 
|---|
| 77 |  | -/* Data fetch function templates */  | 
|---|
| 78 |  | -#define DEFINE_FETCH_reg(type)						\  | 
|---|
| 79 |  | -void FETCH_FUNC_NAME(reg, type)(struct pt_regs *regs, void *offset, void *dest)	\  | 
|---|
| 80 |  | -{									\  | 
|---|
| 81 |  | -	*(type *)dest = (type)regs_get_register(regs,			\  | 
|---|
| 82 |  | -				(unsigned int)((unsigned long)offset));	\  | 
|---|
| 83 |  | -}									\  | 
|---|
| 84 |  | -NOKPROBE_SYMBOL(FETCH_FUNC_NAME(reg, type));  | 
|---|
| 85 |  | -DEFINE_BASIC_FETCH_FUNCS(reg)  | 
|---|
| 86 |  | -/* No string on the register */  | 
|---|
| 87 |  | -#define fetch_reg_string	NULL  | 
|---|
| 88 |  | -#define fetch_reg_string_size	NULL  | 
|---|
| 89 |  | -  | 
|---|
| 90 |  | -#define DEFINE_FETCH_retval(type)					\  | 
|---|
| 91 |  | -void FETCH_FUNC_NAME(retval, type)(struct pt_regs *regs,		\  | 
|---|
| 92 |  | -				   void *dummy, void *dest)		\  | 
|---|
| 93 |  | -{									\  | 
|---|
| 94 |  | -	*(type *)dest = (type)regs_return_value(regs);			\  | 
|---|
| 95 |  | -}									\  | 
|---|
| 96 |  | -NOKPROBE_SYMBOL(FETCH_FUNC_NAME(retval, type));  | 
|---|
| 97 |  | -DEFINE_BASIC_FETCH_FUNCS(retval)  | 
|---|
| 98 |  | -/* No string on the retval */  | 
|---|
| 99 |  | -#define fetch_retval_string		NULL  | 
|---|
| 100 |  | -#define fetch_retval_string_size	NULL  | 
|---|
| 101 |  | -  | 
|---|
| 102 |  | -/* Dereference memory access function */  | 
|---|
| 103 |  | -struct deref_fetch_param {  | 
|---|
| 104 |  | -	struct fetch_param	orig;  | 
|---|
| 105 |  | -	long			offset;  | 
|---|
| 106 |  | -	fetch_func_t		fetch;  | 
|---|
| 107 |  | -	fetch_func_t		fetch_size;  | 
|---|
 | 98 | +	ASSIGN_FETCH_TYPE_END  | 
|---|
| 108 | 99 |  }; | 
|---|
| 109 | 100 |   | 
|---|
| 110 |  | -#define DEFINE_FETCH_deref(type)					\  | 
|---|
| 111 |  | -void FETCH_FUNC_NAME(deref, type)(struct pt_regs *regs,			\  | 
|---|
| 112 |  | -				  void *data, void *dest)		\  | 
|---|
| 113 |  | -{									\  | 
|---|
| 114 |  | -	struct deref_fetch_param *dprm = data;				\  | 
|---|
| 115 |  | -	unsigned long addr;						\  | 
|---|
| 116 |  | -	call_fetch(&dprm->orig, regs, &addr);				\  | 
|---|
| 117 |  | -	if (addr) {							\  | 
|---|
| 118 |  | -		addr += dprm->offset;					\  | 
|---|
| 119 |  | -		dprm->fetch(regs, (void *)addr, dest);			\  | 
|---|
| 120 |  | -	} else								\  | 
|---|
| 121 |  | -		*(type *)dest = 0;					\  | 
|---|
| 122 |  | -}									\  | 
|---|
| 123 |  | -NOKPROBE_SYMBOL(FETCH_FUNC_NAME(deref, type));  | 
|---|
| 124 |  | -DEFINE_BASIC_FETCH_FUNCS(deref)  | 
|---|
| 125 |  | -DEFINE_FETCH_deref(string)  | 
|---|
| 126 |  | -  | 
|---|
| 127 |  | -void FETCH_FUNC_NAME(deref, string_size)(struct pt_regs *regs,  | 
|---|
| 128 |  | -					 void *data, void *dest)  | 
|---|
| 129 |  | -{  | 
|---|
| 130 |  | -	struct deref_fetch_param *dprm = data;  | 
|---|
| 131 |  | -	unsigned long addr;  | 
|---|
| 132 |  | -  | 
|---|
| 133 |  | -	call_fetch(&dprm->orig, regs, &addr);  | 
|---|
| 134 |  | -	if (addr && dprm->fetch_size) {  | 
|---|
| 135 |  | -		addr += dprm->offset;  | 
|---|
| 136 |  | -		dprm->fetch_size(regs, (void *)addr, dest);  | 
|---|
| 137 |  | -	} else  | 
|---|
| 138 |  | -		*(string_size *)dest = 0;  | 
|---|
| 139 |  | -}  | 
|---|
| 140 |  | -NOKPROBE_SYMBOL(FETCH_FUNC_NAME(deref, string_size));  | 
|---|
| 141 |  | -  | 
|---|
| 142 |  | -static void update_deref_fetch_param(struct deref_fetch_param *data)  | 
|---|
| 143 |  | -{  | 
|---|
| 144 |  | -	if (CHECK_FETCH_FUNCS(deref, data->orig.fn))  | 
|---|
| 145 |  | -		update_deref_fetch_param(data->orig.data);  | 
|---|
| 146 |  | -	else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn))  | 
|---|
| 147 |  | -		update_symbol_cache(data->orig.data);  | 
|---|
| 148 |  | -}  | 
|---|
| 149 |  | -NOKPROBE_SYMBOL(update_deref_fetch_param);  | 
|---|
| 150 |  | -  | 
|---|
| 151 |  | -static void free_deref_fetch_param(struct deref_fetch_param *data)  | 
|---|
| 152 |  | -{  | 
|---|
| 153 |  | -	if (CHECK_FETCH_FUNCS(deref, data->orig.fn))  | 
|---|
| 154 |  | -		free_deref_fetch_param(data->orig.data);  | 
|---|
| 155 |  | -	else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn))  | 
|---|
| 156 |  | -		free_symbol_cache(data->orig.data);  | 
|---|
| 157 |  | -	kfree(data);  | 
|---|
| 158 |  | -}  | 
|---|
| 159 |  | -NOKPROBE_SYMBOL(free_deref_fetch_param);  | 
|---|
| 160 |  | -  | 
|---|
| 161 |  | -/* Bitfield fetch function */  | 
|---|
| 162 |  | -struct bitfield_fetch_param {  | 
|---|
| 163 |  | -	struct fetch_param	orig;  | 
|---|
| 164 |  | -	unsigned char		hi_shift;  | 
|---|
| 165 |  | -	unsigned char		low_shift;  | 
|---|
| 166 |  | -};  | 
|---|
| 167 |  | -  | 
|---|
| 168 |  | -#define DEFINE_FETCH_bitfield(type)					\  | 
|---|
| 169 |  | -void FETCH_FUNC_NAME(bitfield, type)(struct pt_regs *regs,		\  | 
|---|
| 170 |  | -				     void *data, void *dest)		\  | 
|---|
| 171 |  | -{									\  | 
|---|
| 172 |  | -	struct bitfield_fetch_param *bprm = data;			\  | 
|---|
| 173 |  | -	type buf = 0;							\  | 
|---|
| 174 |  | -	call_fetch(&bprm->orig, regs, &buf);				\  | 
|---|
| 175 |  | -	if (buf) {							\  | 
|---|
| 176 |  | -		buf <<= bprm->hi_shift;					\  | 
|---|
| 177 |  | -		buf >>= bprm->low_shift;				\  | 
|---|
| 178 |  | -	}								\  | 
|---|
| 179 |  | -	*(type *)dest = buf;						\  | 
|---|
| 180 |  | -}									\  | 
|---|
| 181 |  | -NOKPROBE_SYMBOL(FETCH_FUNC_NAME(bitfield, type));  | 
|---|
| 182 |  | -DEFINE_BASIC_FETCH_FUNCS(bitfield)  | 
|---|
| 183 |  | -#define fetch_bitfield_string		NULL  | 
|---|
| 184 |  | -#define fetch_bitfield_string_size	NULL  | 
|---|
| 185 |  | -  | 
|---|
| 186 |  | -static void  | 
|---|
| 187 |  | -update_bitfield_fetch_param(struct bitfield_fetch_param *data)  | 
|---|
| 188 |  | -{  | 
|---|
| 189 |  | -	/*  | 
|---|
| 190 |  | -	 * Don't check the bitfield itself, because this must be the  | 
|---|
| 191 |  | -	 * last fetch function.  | 
|---|
| 192 |  | -	 */  | 
|---|
| 193 |  | -	if (CHECK_FETCH_FUNCS(deref, data->orig.fn))  | 
|---|
| 194 |  | -		update_deref_fetch_param(data->orig.data);  | 
|---|
| 195 |  | -	else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn))  | 
|---|
| 196 |  | -		update_symbol_cache(data->orig.data);  | 
|---|
| 197 |  | -}  | 
|---|
| 198 |  | -  | 
|---|
| 199 |  | -static void  | 
|---|
| 200 |  | -free_bitfield_fetch_param(struct bitfield_fetch_param *data)  | 
|---|
| 201 |  | -{  | 
|---|
| 202 |  | -	/*  | 
|---|
| 203 |  | -	 * Don't check the bitfield itself, because this must be the  | 
|---|
| 204 |  | -	 * last fetch function.  | 
|---|
| 205 |  | -	 */  | 
|---|
| 206 |  | -	if (CHECK_FETCH_FUNCS(deref, data->orig.fn))  | 
|---|
| 207 |  | -		free_deref_fetch_param(data->orig.data);  | 
|---|
| 208 |  | -	else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn))  | 
|---|
| 209 |  | -		free_symbol_cache(data->orig.data);  | 
|---|
| 210 |  | -  | 
|---|
| 211 |  | -	kfree(data);  | 
|---|
| 212 |  | -}  | 
|---|
| 213 |  | -  | 
|---|
| 214 |  | -void FETCH_FUNC_NAME(comm, string)(struct pt_regs *regs,  | 
|---|
| 215 |  | -					  void *data, void *dest)  | 
|---|
| 216 |  | -{  | 
|---|
| 217 |  | -	int maxlen = get_rloc_len(*(u32 *)dest);  | 
|---|
| 218 |  | -	u8 *dst = get_rloc_data(dest);  | 
|---|
| 219 |  | -	long ret;  | 
|---|
| 220 |  | -  | 
|---|
| 221 |  | -	if (!maxlen)  | 
|---|
| 222 |  | -		return;  | 
|---|
| 223 |  | -  | 
|---|
| 224 |  | -	ret = strlcpy(dst, current->comm, maxlen);  | 
|---|
| 225 |  | -	*(u32 *)dest = make_data_rloc(ret, get_rloc_offs(*(u32 *)dest));  | 
|---|
| 226 |  | -}  | 
|---|
| 227 |  | -NOKPROBE_SYMBOL(FETCH_FUNC_NAME(comm, string));  | 
|---|
| 228 |  | -  | 
|---|
| 229 |  | -void FETCH_FUNC_NAME(comm, string_size)(struct pt_regs *regs,  | 
|---|
| 230 |  | -					       void *data, void *dest)  | 
|---|
| 231 |  | -{  | 
|---|
| 232 |  | -	*(u32 *)dest = strlen(current->comm) + 1;  | 
|---|
| 233 |  | -}  | 
|---|
| 234 |  | -NOKPROBE_SYMBOL(FETCH_FUNC_NAME(comm, string_size));  | 
|---|
| 235 |  | -  | 
|---|
| 236 |  | -static const struct fetch_type *find_fetch_type(const char *type,  | 
|---|
| 237 |  | -						const struct fetch_type *ftbl)  | 
|---|
 | 101 | +static const struct fetch_type *find_fetch_type(const char *type)  | 
|---|
| 238 | 102 |  { | 
|---|
| 239 | 103 |  	int i; | 
|---|
| 240 | 104 |   | 
|---|
| .. | .. | 
|---|
| 255 | 119 |   | 
|---|
| 256 | 120 |  		switch (bs) { | 
|---|
| 257 | 121 |  		case 8: | 
|---|
| 258 |  | -			return find_fetch_type("u8", ftbl);  | 
|---|
 | 122 | +			return find_fetch_type("u8");  | 
|---|
| 259 | 123 |  		case 16: | 
|---|
| 260 |  | -			return find_fetch_type("u16", ftbl);  | 
|---|
 | 124 | +			return find_fetch_type("u16");  | 
|---|
| 261 | 125 |  		case 32: | 
|---|
| 262 |  | -			return find_fetch_type("u32", ftbl);  | 
|---|
 | 126 | +			return find_fetch_type("u32");  | 
|---|
| 263 | 127 |  		case 64: | 
|---|
| 264 |  | -			return find_fetch_type("u64", ftbl);  | 
|---|
 | 128 | +			return find_fetch_type("u64");  | 
|---|
| 265 | 129 |  		default: | 
|---|
| 266 | 130 |  			goto fail; | 
|---|
| 267 | 131 |  		} | 
|---|
| 268 | 132 |  	} | 
|---|
| 269 | 133 |   | 
|---|
| 270 |  | -	for (i = 0; ftbl[i].name; i++) {  | 
|---|
| 271 |  | -		if (strcmp(type, ftbl[i].name) == 0)  | 
|---|
| 272 |  | -			return &ftbl[i];  | 
|---|
 | 134 | +	for (i = 0; probe_fetch_types[i].name; i++) {  | 
|---|
 | 135 | +		if (strcmp(type, probe_fetch_types[i].name) == 0)  | 
|---|
 | 136 | +			return &probe_fetch_types[i];  | 
|---|
| 273 | 137 |  	} | 
|---|
| 274 | 138 |   | 
|---|
| 275 | 139 |  fail: | 
|---|
| 276 | 140 |  	return NULL; | 
|---|
| 277 | 141 |  } | 
|---|
| 278 | 142 |   | 
|---|
| 279 |  | -/* Special function : only accept unsigned long */  | 
|---|
| 280 |  | -static void fetch_kernel_stack_address(struct pt_regs *regs, void *dummy, void *dest)  | 
|---|
 | 143 | +static struct trace_probe_log trace_probe_log;  | 
|---|
 | 144 | +  | 
|---|
 | 145 | +void trace_probe_log_init(const char *subsystem, int argc, const char **argv)  | 
|---|
| 281 | 146 |  { | 
|---|
| 282 |  | -	*(unsigned long *)dest = kernel_stack_pointer(regs);  | 
|---|
 | 147 | +	trace_probe_log.subsystem = subsystem;  | 
|---|
 | 148 | +	trace_probe_log.argc = argc;  | 
|---|
 | 149 | +	trace_probe_log.argv = argv;  | 
|---|
 | 150 | +	trace_probe_log.index = 0;  | 
|---|
| 283 | 151 |  } | 
|---|
| 284 |  | -NOKPROBE_SYMBOL(fetch_kernel_stack_address);  | 
|---|
| 285 | 152 |   | 
|---|
| 286 |  | -static void fetch_user_stack_address(struct pt_regs *regs, void *dummy, void *dest)  | 
|---|
 | 153 | +void trace_probe_log_clear(void)  | 
|---|
| 287 | 154 |  { | 
|---|
| 288 |  | -	*(unsigned long *)dest = user_stack_pointer(regs);  | 
|---|
 | 155 | +	memset(&trace_probe_log, 0, sizeof(trace_probe_log));  | 
|---|
| 289 | 156 |  } | 
|---|
| 290 |  | -NOKPROBE_SYMBOL(fetch_user_stack_address);  | 
|---|
| 291 | 157 |   | 
|---|
| 292 |  | -static fetch_func_t get_fetch_size_function(const struct fetch_type *type,  | 
|---|
| 293 |  | -					    fetch_func_t orig_fn,  | 
|---|
| 294 |  | -					    const struct fetch_type *ftbl)  | 
|---|
 | 158 | +void trace_probe_log_set_index(int index)  | 
|---|
| 295 | 159 |  { | 
|---|
| 296 |  | -	int i;  | 
|---|
 | 160 | +	trace_probe_log.index = index;  | 
|---|
 | 161 | +}  | 
|---|
| 297 | 162 |   | 
|---|
| 298 |  | -	if (type != &ftbl[FETCH_TYPE_STRING])  | 
|---|
| 299 |  | -		return NULL;	/* Only string type needs size function */  | 
|---|
 | 163 | +void __trace_probe_log_err(int offset, int err_type)  | 
|---|
 | 164 | +{  | 
|---|
 | 165 | +	char *command, *p;  | 
|---|
 | 166 | +	int i, len = 0, pos = 0;  | 
|---|
| 300 | 167 |   | 
|---|
| 301 |  | -	for (i = 0; i < FETCH_MTD_END; i++)  | 
|---|
| 302 |  | -		if (type->fetch[i] == orig_fn)  | 
|---|
| 303 |  | -			return ftbl[FETCH_TYPE_STRSIZE].fetch[i];  | 
|---|
 | 168 | +	if (!trace_probe_log.argv)  | 
|---|
 | 169 | +		return;  | 
|---|
| 304 | 170 |   | 
|---|
| 305 |  | -	WARN_ON(1);	/* This should not happen */  | 
|---|
 | 171 | +	/* Recalcurate the length and allocate buffer */  | 
|---|
 | 172 | +	for (i = 0; i < trace_probe_log.argc; i++) {  | 
|---|
 | 173 | +		if (i == trace_probe_log.index)  | 
|---|
 | 174 | +			pos = len;  | 
|---|
 | 175 | +		len += strlen(trace_probe_log.argv[i]) + 1;  | 
|---|
 | 176 | +	}  | 
|---|
 | 177 | +	command = kzalloc(len, GFP_KERNEL);  | 
|---|
 | 178 | +	if (!command)  | 
|---|
 | 179 | +		return;  | 
|---|
| 306 | 180 |   | 
|---|
| 307 |  | -	return NULL;  | 
|---|
 | 181 | +	if (trace_probe_log.index >= trace_probe_log.argc) {  | 
|---|
 | 182 | +		/**  | 
|---|
 | 183 | +		 * Set the error position is next to the last arg + space.  | 
|---|
 | 184 | +		 * Note that len includes the terminal null and the cursor  | 
|---|
 | 185 | +		 * appaers at pos + 1.  | 
|---|
 | 186 | +		 */  | 
|---|
 | 187 | +		pos = len;  | 
|---|
 | 188 | +		offset = 0;  | 
|---|
 | 189 | +	}  | 
|---|
 | 190 | +  | 
|---|
 | 191 | +	/* And make a command string from argv array */  | 
|---|
 | 192 | +	p = command;  | 
|---|
 | 193 | +	for (i = 0; i < trace_probe_log.argc; i++) {  | 
|---|
 | 194 | +		len = strlen(trace_probe_log.argv[i]);  | 
|---|
 | 195 | +		strcpy(p, trace_probe_log.argv[i]);  | 
|---|
 | 196 | +		p[len] = ' ';  | 
|---|
 | 197 | +		p += len + 1;  | 
|---|
 | 198 | +	}  | 
|---|
 | 199 | +	*(p - 1) = '\0';  | 
|---|
 | 200 | +  | 
|---|
 | 201 | +	tracing_log_err(NULL, trace_probe_log.subsystem, command,  | 
|---|
 | 202 | +			trace_probe_err_text, err_type, pos + offset);  | 
|---|
 | 203 | +  | 
|---|
 | 204 | +	kfree(command);  | 
|---|
| 308 | 205 |  } | 
|---|
| 309 | 206 |   | 
|---|
| 310 | 207 |  /* Split symbol and offset. */ | 
|---|
| .. | .. | 
|---|
| 328 | 225 |  	return 0; | 
|---|
| 329 | 226 |  } | 
|---|
| 330 | 227 |   | 
|---|
 | 228 | +/* @buf must has MAX_EVENT_NAME_LEN size */  | 
|---|
 | 229 | +int traceprobe_parse_event_name(const char **pevent, const char **pgroup,  | 
|---|
 | 230 | +				char *buf, int offset)  | 
|---|
 | 231 | +{  | 
|---|
 | 232 | +	const char *slash, *event = *pevent;  | 
|---|
 | 233 | +	int len;  | 
|---|
 | 234 | +  | 
|---|
 | 235 | +	slash = strchr(event, '/');  | 
|---|
 | 236 | +	if (slash) {  | 
|---|
 | 237 | +		if (slash == event) {  | 
|---|
 | 238 | +			trace_probe_log_err(offset, NO_GROUP_NAME);  | 
|---|
 | 239 | +			return -EINVAL;  | 
|---|
 | 240 | +		}  | 
|---|
 | 241 | +		if (slash - event + 1 > MAX_EVENT_NAME_LEN) {  | 
|---|
 | 242 | +			trace_probe_log_err(offset, GROUP_TOO_LONG);  | 
|---|
 | 243 | +			return -EINVAL;  | 
|---|
 | 244 | +		}  | 
|---|
 | 245 | +		strlcpy(buf, event, slash - event + 1);  | 
|---|
 | 246 | +		if (!is_good_name(buf)) {  | 
|---|
 | 247 | +			trace_probe_log_err(offset, BAD_GROUP_NAME);  | 
|---|
 | 248 | +			return -EINVAL;  | 
|---|
 | 249 | +		}  | 
|---|
 | 250 | +		*pgroup = buf;  | 
|---|
 | 251 | +		*pevent = slash + 1;  | 
|---|
 | 252 | +		offset += slash - event + 1;  | 
|---|
 | 253 | +		event = *pevent;  | 
|---|
 | 254 | +	}  | 
|---|
 | 255 | +	len = strlen(event);  | 
|---|
 | 256 | +	if (len == 0) {  | 
|---|
 | 257 | +		trace_probe_log_err(offset, NO_EVENT_NAME);  | 
|---|
 | 258 | +		return -EINVAL;  | 
|---|
 | 259 | +	} else if (len > MAX_EVENT_NAME_LEN) {  | 
|---|
 | 260 | +		trace_probe_log_err(offset, EVENT_TOO_LONG);  | 
|---|
 | 261 | +		return -EINVAL;  | 
|---|
 | 262 | +	}  | 
|---|
 | 263 | +	if (!is_good_name(event)) {  | 
|---|
 | 264 | +		trace_probe_log_err(offset, BAD_EVENT_NAME);  | 
|---|
 | 265 | +		return -EINVAL;  | 
|---|
 | 266 | +	}  | 
|---|
 | 267 | +	return 0;  | 
|---|
 | 268 | +}  | 
|---|
 | 269 | +  | 
|---|
| 331 | 270 |  #define PARAM_MAX_STACK (THREAD_SIZE / sizeof(unsigned long)) | 
|---|
| 332 | 271 |   | 
|---|
| 333 | 272 |  static int parse_probe_vars(char *arg, const struct fetch_type *t, | 
|---|
| 334 |  | -			    struct fetch_param *f, bool is_return,  | 
|---|
| 335 |  | -			    bool is_kprobe)  | 
|---|
 | 273 | +			struct fetch_insn *code, unsigned int flags, int offs)  | 
|---|
| 336 | 274 |  { | 
|---|
| 337 |  | -	int ret = 0;  | 
|---|
| 338 | 275 |  	unsigned long param; | 
|---|
 | 276 | +	int ret = 0;  | 
|---|
 | 277 | +	int len;  | 
|---|
| 339 | 278 |   | 
|---|
| 340 | 279 |  	if (strcmp(arg, "retval") == 0) { | 
|---|
| 341 |  | -		if (is_return)  | 
|---|
| 342 |  | -			f->fn = t->fetch[FETCH_MTD_retval];  | 
|---|
| 343 |  | -		else  | 
|---|
 | 280 | +		if (flags & TPARG_FL_RETURN) {  | 
|---|
 | 281 | +			code->op = FETCH_OP_RETVAL;  | 
|---|
 | 282 | +		} else {  | 
|---|
 | 283 | +			trace_probe_log_err(offs, RETVAL_ON_PROBE);  | 
|---|
| 344 | 284 |  			ret = -EINVAL; | 
|---|
| 345 |  | -	} else if (strncmp(arg, "stack", 5) == 0) {  | 
|---|
| 346 |  | -		if (arg[5] == '\0') {  | 
|---|
| 347 |  | -			if (strcmp(t->name, DEFAULT_FETCH_TYPE_STR))  | 
|---|
| 348 |  | -				return -EINVAL;  | 
|---|
| 349 |  | -  | 
|---|
| 350 |  | -			if (is_kprobe)  | 
|---|
| 351 |  | -				f->fn = fetch_kernel_stack_address;  | 
|---|
| 352 |  | -			else  | 
|---|
| 353 |  | -				f->fn = fetch_user_stack_address;  | 
|---|
| 354 |  | -		} else if (isdigit(arg[5])) {  | 
|---|
| 355 |  | -			ret = kstrtoul(arg + 5, 10, ¶m);  | 
|---|
| 356 |  | -			if (ret || (is_kprobe && param > PARAM_MAX_STACK))  | 
|---|
 | 285 | +		}  | 
|---|
 | 286 | +	} else if ((len = str_has_prefix(arg, "stack"))) {  | 
|---|
 | 287 | +		if (arg[len] == '\0') {  | 
|---|
 | 288 | +			code->op = FETCH_OP_STACKP;  | 
|---|
 | 289 | +		} else if (isdigit(arg[len])) {  | 
|---|
 | 290 | +			ret = kstrtoul(arg + len, 10, ¶m);  | 
|---|
 | 291 | +			if (ret) {  | 
|---|
 | 292 | +				goto inval_var;  | 
|---|
 | 293 | +			} else if ((flags & TPARG_FL_KERNEL) &&  | 
|---|
 | 294 | +				    param > PARAM_MAX_STACK) {  | 
|---|
 | 295 | +				trace_probe_log_err(offs, BAD_STACK_NUM);  | 
|---|
| 357 | 296 |  				ret = -EINVAL; | 
|---|
| 358 |  | -			else {  | 
|---|
| 359 |  | -				f->fn = t->fetch[FETCH_MTD_stack];  | 
|---|
| 360 |  | -				f->data = (void *)param;  | 
|---|
 | 297 | +			} else {  | 
|---|
 | 298 | +				code->op = FETCH_OP_STACK;  | 
|---|
 | 299 | +				code->param = (unsigned int)param;  | 
|---|
| 361 | 300 |  			} | 
|---|
| 362 | 301 |  		} else | 
|---|
| 363 |  | -			ret = -EINVAL;  | 
|---|
| 364 |  | -	} else if (strcmp(arg, "comm") == 0) {  | 
|---|
| 365 |  | -		if (strcmp(t->name, "string") != 0 &&  | 
|---|
| 366 |  | -		    strcmp(t->name, "string_size") != 0)  | 
|---|
 | 302 | +			goto inval_var;  | 
|---|
 | 303 | +	} else if (strcmp(arg, "comm") == 0 || strcmp(arg, "COMM") == 0) {  | 
|---|
 | 304 | +		code->op = FETCH_OP_COMM;  | 
|---|
 | 305 | +#ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API  | 
|---|
 | 306 | +	} else if (((flags & TPARG_FL_MASK) ==  | 
|---|
 | 307 | +		    (TPARG_FL_KERNEL | TPARG_FL_FENTRY)) &&  | 
|---|
 | 308 | +		   (len = str_has_prefix(arg, "arg"))) {  | 
|---|
 | 309 | +		ret = kstrtoul(arg + len, 10, ¶m);  | 
|---|
 | 310 | +		if (ret) {  | 
|---|
 | 311 | +			goto inval_var;  | 
|---|
 | 312 | +		} else if (!param || param > PARAM_MAX_STACK) {  | 
|---|
 | 313 | +			trace_probe_log_err(offs, BAD_ARG_NUM);  | 
|---|
| 367 | 314 |  			return -EINVAL; | 
|---|
| 368 |  | -		f->fn = t->fetch[FETCH_MTD_comm];  | 
|---|
 | 315 | +		}  | 
|---|
 | 316 | +		code->op = FETCH_OP_ARG;  | 
|---|
 | 317 | +		code->param = (unsigned int)param - 1;  | 
|---|
 | 318 | +#endif  | 
|---|
| 369 | 319 |  	} else | 
|---|
| 370 |  | -		ret = -EINVAL;  | 
|---|
 | 320 | +		goto inval_var;  | 
|---|
| 371 | 321 |   | 
|---|
| 372 | 322 |  	return ret; | 
|---|
 | 323 | +  | 
|---|
 | 324 | +inval_var:  | 
|---|
 | 325 | +	trace_probe_log_err(offs, BAD_VAR);  | 
|---|
 | 326 | +	return -EINVAL;  | 
|---|
 | 327 | +}  | 
|---|
 | 328 | +  | 
|---|
 | 329 | +static int str_to_immediate(char *str, unsigned long *imm)  | 
|---|
 | 330 | +{  | 
|---|
 | 331 | +	if (isdigit(str[0]))  | 
|---|
 | 332 | +		return kstrtoul(str, 0, imm);  | 
|---|
 | 333 | +	else if (str[0] == '-')  | 
|---|
 | 334 | +		return kstrtol(str, 0, (long *)imm);  | 
|---|
 | 335 | +	else if (str[0] == '+')  | 
|---|
 | 336 | +		return kstrtol(str + 1, 0, (long *)imm);  | 
|---|
 | 337 | +	return -EINVAL;  | 
|---|
 | 338 | +}  | 
|---|
 | 339 | +  | 
|---|
 | 340 | +static int __parse_imm_string(char *str, char **pbuf, int offs)  | 
|---|
 | 341 | +{  | 
|---|
 | 342 | +	size_t len = strlen(str);  | 
|---|
 | 343 | +  | 
|---|
 | 344 | +	if (str[len - 1] != '"') {  | 
|---|
 | 345 | +		trace_probe_log_err(offs + len, IMMSTR_NO_CLOSE);  | 
|---|
 | 346 | +		return -EINVAL;  | 
|---|
 | 347 | +	}  | 
|---|
 | 348 | +	*pbuf = kstrndup(str, len - 1, GFP_KERNEL);  | 
|---|
 | 349 | +	return 0;  | 
|---|
| 373 | 350 |  } | 
|---|
| 374 | 351 |   | 
|---|
| 375 | 352 |  /* Recursive argument parser */ | 
|---|
| 376 |  | -static int parse_probe_arg(char *arg, const struct fetch_type *t,  | 
|---|
| 377 |  | -		     struct fetch_param *f, bool is_return, bool is_kprobe,  | 
|---|
| 378 |  | -		     const struct fetch_type *ftbl)  | 
|---|
 | 353 | +static int  | 
|---|
 | 354 | +parse_probe_arg(char *arg, const struct fetch_type *type,  | 
|---|
 | 355 | +		struct fetch_insn **pcode, struct fetch_insn *end,  | 
|---|
 | 356 | +		unsigned int flags, int offs)  | 
|---|
| 379 | 357 |  { | 
|---|
 | 358 | +	struct fetch_insn *code = *pcode;  | 
|---|
| 380 | 359 |  	unsigned long param; | 
|---|
| 381 |  | -	long offset;  | 
|---|
 | 360 | +	int deref = FETCH_OP_DEREF;  | 
|---|
 | 361 | +	long offset = 0;  | 
|---|
| 382 | 362 |  	char *tmp; | 
|---|
| 383 | 363 |  	int ret = 0; | 
|---|
| 384 | 364 |   | 
|---|
| 385 | 365 |  	switch (arg[0]) { | 
|---|
| 386 | 366 |  	case '$': | 
|---|
| 387 |  | -		ret = parse_probe_vars(arg + 1, t, f, is_return, is_kprobe);  | 
|---|
 | 367 | +		ret = parse_probe_vars(arg + 1, type, code, flags, offs);  | 
|---|
| 388 | 368 |  		break; | 
|---|
| 389 | 369 |   | 
|---|
| 390 | 370 |  	case '%':	/* named register */ | 
|---|
| 391 | 371 |  		ret = regs_query_register_offset(arg + 1); | 
|---|
| 392 | 372 |  		if (ret >= 0) { | 
|---|
| 393 |  | -			f->fn = t->fetch[FETCH_MTD_reg];  | 
|---|
| 394 |  | -			f->data = (void *)(unsigned long)ret;  | 
|---|
 | 373 | +			code->op = FETCH_OP_REG;  | 
|---|
 | 374 | +			code->param = (unsigned int)ret;  | 
|---|
| 395 | 375 |  			ret = 0; | 
|---|
| 396 |  | -		}  | 
|---|
 | 376 | +		} else  | 
|---|
 | 377 | +			trace_probe_log_err(offs, BAD_REG_NAME);  | 
|---|
| 397 | 378 |  		break; | 
|---|
| 398 | 379 |   | 
|---|
| 399 | 380 |  	case '@':	/* memory, file-offset or symbol */ | 
|---|
| 400 | 381 |  		if (isdigit(arg[1])) { | 
|---|
| 401 | 382 |  			ret = kstrtoul(arg + 1, 0, ¶m); | 
|---|
| 402 |  | -			if (ret)  | 
|---|
 | 383 | +			if (ret) {  | 
|---|
 | 384 | +				trace_probe_log_err(offs, BAD_MEM_ADDR);  | 
|---|
| 403 | 385 |  				break; | 
|---|
| 404 |  | -  | 
|---|
| 405 |  | -			f->fn = t->fetch[FETCH_MTD_memory];  | 
|---|
| 406 |  | -			f->data = (void *)param;  | 
|---|
 | 386 | +			}  | 
|---|
 | 387 | +			/* load address */  | 
|---|
 | 388 | +			code->op = FETCH_OP_IMM;  | 
|---|
 | 389 | +			code->immediate = param;  | 
|---|
| 407 | 390 |  		} else if (arg[1] == '+') { | 
|---|
| 408 | 391 |  			/* kprobes don't support file offsets */ | 
|---|
| 409 |  | -			if (is_kprobe)  | 
|---|
 | 392 | +			if (flags & TPARG_FL_KERNEL) {  | 
|---|
 | 393 | +				trace_probe_log_err(offs, FILE_ON_KPROBE);  | 
|---|
| 410 | 394 |  				return -EINVAL; | 
|---|
| 411 |  | -  | 
|---|
 | 395 | +			}  | 
|---|
| 412 | 396 |  			ret = kstrtol(arg + 2, 0, &offset); | 
|---|
| 413 |  | -			if (ret)  | 
|---|
 | 397 | +			if (ret) {  | 
|---|
 | 398 | +				trace_probe_log_err(offs, BAD_FILE_OFFS);  | 
|---|
| 414 | 399 |  				break; | 
|---|
 | 400 | +			}  | 
|---|
| 415 | 401 |   | 
|---|
| 416 |  | -			f->fn = t->fetch[FETCH_MTD_file_offset];  | 
|---|
| 417 |  | -			f->data = (void *)offset;  | 
|---|
 | 402 | +			code->op = FETCH_OP_FOFFS;  | 
|---|
 | 403 | +			code->immediate = (unsigned long)offset;  // imm64?  | 
|---|
| 418 | 404 |  		} else { | 
|---|
| 419 | 405 |  			/* uprobes don't support symbols */ | 
|---|
| 420 |  | -			if (!is_kprobe)  | 
|---|
 | 406 | +			if (!(flags & TPARG_FL_KERNEL)) {  | 
|---|
 | 407 | +				trace_probe_log_err(offs, SYM_ON_UPROBE);  | 
|---|
| 421 | 408 |  				return -EINVAL; | 
|---|
| 422 |  | -  | 
|---|
| 423 |  | -			ret = traceprobe_split_symbol_offset(arg + 1, &offset);  | 
|---|
| 424 |  | -			if (ret)  | 
|---|
| 425 |  | -				break;  | 
|---|
| 426 |  | -  | 
|---|
| 427 |  | -			f->data = alloc_symbol_cache(arg + 1, offset);  | 
|---|
| 428 |  | -			if (f->data)  | 
|---|
| 429 |  | -				f->fn = t->fetch[FETCH_MTD_symbol];  | 
|---|
 | 409 | +			}  | 
|---|
 | 410 | +			/* Preserve symbol for updating */  | 
|---|
 | 411 | +			code->op = FETCH_NOP_SYMBOL;  | 
|---|
 | 412 | +			code->data = kstrdup(arg + 1, GFP_KERNEL);  | 
|---|
 | 413 | +			if (!code->data)  | 
|---|
 | 414 | +				return -ENOMEM;  | 
|---|
 | 415 | +			if (++code == end) {  | 
|---|
 | 416 | +				trace_probe_log_err(offs, TOO_MANY_OPS);  | 
|---|
 | 417 | +				return -EINVAL;  | 
|---|
 | 418 | +			}  | 
|---|
 | 419 | +			code->op = FETCH_OP_IMM;  | 
|---|
 | 420 | +			code->immediate = 0;  | 
|---|
| 430 | 421 |  		} | 
|---|
 | 422 | +		/* These are fetching from memory */  | 
|---|
 | 423 | +		if (++code == end) {  | 
|---|
 | 424 | +			trace_probe_log_err(offs, TOO_MANY_OPS);  | 
|---|
 | 425 | +			return -EINVAL;  | 
|---|
 | 426 | +		}  | 
|---|
 | 427 | +		*pcode = code;  | 
|---|
 | 428 | +		code->op = FETCH_OP_DEREF;  | 
|---|
 | 429 | +		code->offset = offset;  | 
|---|
| 431 | 430 |  		break; | 
|---|
| 432 | 431 |   | 
|---|
| 433 | 432 |  	case '+':	/* deref memory */ | 
|---|
| 434 |  | -		arg++;	/* Skip '+', because kstrtol() rejects it. */  | 
|---|
| 435 | 433 |  	case '-': | 
|---|
 | 434 | +		if (arg[1] == 'u') {  | 
|---|
 | 435 | +			deref = FETCH_OP_UDEREF;  | 
|---|
 | 436 | +			arg[1] = arg[0];  | 
|---|
 | 437 | +			arg++;  | 
|---|
 | 438 | +		}  | 
|---|
 | 439 | +		if (arg[0] == '+')  | 
|---|
 | 440 | +			arg++;	/* Skip '+', because kstrtol() rejects it. */  | 
|---|
| 436 | 441 |  		tmp = strchr(arg, '('); | 
|---|
| 437 |  | -		if (!tmp)  | 
|---|
| 438 |  | -			break;  | 
|---|
| 439 |  | -  | 
|---|
 | 442 | +		if (!tmp) {  | 
|---|
 | 443 | +			trace_probe_log_err(offs, DEREF_NEED_BRACE);  | 
|---|
 | 444 | +			return -EINVAL;  | 
|---|
 | 445 | +		}  | 
|---|
| 440 | 446 |  		*tmp = '\0'; | 
|---|
| 441 | 447 |  		ret = kstrtol(arg, 0, &offset); | 
|---|
| 442 |  | -  | 
|---|
| 443 |  | -		if (ret)  | 
|---|
 | 448 | +		if (ret) {  | 
|---|
 | 449 | +			trace_probe_log_err(offs, BAD_DEREF_OFFS);  | 
|---|
| 444 | 450 |  			break; | 
|---|
| 445 |  | -  | 
|---|
 | 451 | +		}  | 
|---|
 | 452 | +		offs += (tmp + 1 - arg) + (arg[0] != '-' ? 1 : 0);  | 
|---|
| 446 | 453 |  		arg = tmp + 1; | 
|---|
| 447 | 454 |  		tmp = strrchr(arg, ')'); | 
|---|
 | 455 | +		if (!tmp) {  | 
|---|
 | 456 | +			trace_probe_log_err(offs + strlen(arg),  | 
|---|
 | 457 | +					    DEREF_OPEN_BRACE);  | 
|---|
 | 458 | +			return -EINVAL;  | 
|---|
 | 459 | +		} else {  | 
|---|
 | 460 | +			const struct fetch_type *t2 = find_fetch_type(NULL);  | 
|---|
| 448 | 461 |   | 
|---|
| 449 |  | -		if (tmp) {  | 
|---|
| 450 |  | -			struct deref_fetch_param	*dprm;  | 
|---|
| 451 |  | -			const struct fetch_type		*t2;  | 
|---|
| 452 |  | -  | 
|---|
| 453 |  | -			t2 = find_fetch_type(NULL, ftbl);  | 
|---|
| 454 | 462 |  			*tmp = '\0'; | 
|---|
| 455 |  | -			dprm = kzalloc(sizeof(struct deref_fetch_param), GFP_KERNEL);  | 
|---|
| 456 |  | -  | 
|---|
| 457 |  | -			if (!dprm)  | 
|---|
| 458 |  | -				return -ENOMEM;  | 
|---|
| 459 |  | -  | 
|---|
| 460 |  | -			dprm->offset = offset;  | 
|---|
| 461 |  | -			dprm->fetch = t->fetch[FETCH_MTD_memory];  | 
|---|
| 462 |  | -			dprm->fetch_size = get_fetch_size_function(t,  | 
|---|
| 463 |  | -							dprm->fetch, ftbl);  | 
|---|
| 464 |  | -			ret = parse_probe_arg(arg, t2, &dprm->orig, is_return,  | 
|---|
| 465 |  | -							is_kprobe, ftbl);  | 
|---|
 | 463 | +			ret = parse_probe_arg(arg, t2, &code, end, flags, offs);  | 
|---|
| 466 | 464 |  			if (ret) | 
|---|
| 467 |  | -				kfree(dprm);  | 
|---|
| 468 |  | -			else {  | 
|---|
| 469 |  | -				f->fn = t->fetch[FETCH_MTD_deref];  | 
|---|
| 470 |  | -				f->data = (void *)dprm;  | 
|---|
 | 465 | +				break;  | 
|---|
 | 466 | +			if (code->op == FETCH_OP_COMM ||  | 
|---|
 | 467 | +			    code->op == FETCH_OP_DATA) {  | 
|---|
 | 468 | +				trace_probe_log_err(offs, COMM_CANT_DEREF);  | 
|---|
 | 469 | +				return -EINVAL;  | 
|---|
| 471 | 470 |  			} | 
|---|
 | 471 | +			if (++code == end) {  | 
|---|
 | 472 | +				trace_probe_log_err(offs, TOO_MANY_OPS);  | 
|---|
 | 473 | +				return -EINVAL;  | 
|---|
 | 474 | +			}  | 
|---|
 | 475 | +			*pcode = code;  | 
|---|
 | 476 | +  | 
|---|
 | 477 | +			code->op = deref;  | 
|---|
 | 478 | +			code->offset = offset;  | 
|---|
 | 479 | +		}  | 
|---|
 | 480 | +		break;  | 
|---|
 | 481 | +	case '\\':	/* Immediate value */  | 
|---|
 | 482 | +		if (arg[1] == '"') {	/* Immediate string */  | 
|---|
 | 483 | +			ret = __parse_imm_string(arg + 2, &tmp, offs + 2);  | 
|---|
 | 484 | +			if (ret)  | 
|---|
 | 485 | +				break;  | 
|---|
 | 486 | +			code->op = FETCH_OP_DATA;  | 
|---|
 | 487 | +			code->data = tmp;  | 
|---|
 | 488 | +		} else {  | 
|---|
 | 489 | +			ret = str_to_immediate(arg + 1, &code->immediate);  | 
|---|
 | 490 | +			if (ret)  | 
|---|
 | 491 | +				trace_probe_log_err(offs + 1, BAD_IMM);  | 
|---|
 | 492 | +			else  | 
|---|
 | 493 | +				code->op = FETCH_OP_IMM;  | 
|---|
| 472 | 494 |  		} | 
|---|
| 473 | 495 |  		break; | 
|---|
| 474 | 496 |  	} | 
|---|
| 475 |  | -	if (!ret && !f->fn) {	/* Parsed, but do not find fetch method */  | 
|---|
| 476 |  | -		pr_info("%s type has no corresponding fetch method.\n", t->name);  | 
|---|
 | 497 | +	if (!ret && code->op == FETCH_OP_NOP) {  | 
|---|
 | 498 | +		/* Parsed, but do not find fetch method */  | 
|---|
 | 499 | +		trace_probe_log_err(offs, BAD_FETCH_ARG);  | 
|---|
| 477 | 500 |  		ret = -EINVAL; | 
|---|
| 478 | 501 |  	} | 
|---|
| 479 |  | -  | 
|---|
| 480 | 502 |  	return ret; | 
|---|
| 481 | 503 |  } | 
|---|
| 482 | 504 |   | 
|---|
| .. | .. | 
|---|
| 485 | 507 |  /* Bitfield type needs to be parsed into a fetch function */ | 
|---|
| 486 | 508 |  static int __parse_bitfield_probe_arg(const char *bf, | 
|---|
| 487 | 509 |  				      const struct fetch_type *t, | 
|---|
| 488 |  | -				      struct fetch_param *f)  | 
|---|
 | 510 | +				      struct fetch_insn **pcode)  | 
|---|
| 489 | 511 |  { | 
|---|
| 490 |  | -	struct bitfield_fetch_param *bprm;  | 
|---|
 | 512 | +	struct fetch_insn *code = *pcode;  | 
|---|
| 491 | 513 |  	unsigned long bw, bo; | 
|---|
| 492 | 514 |  	char *tail; | 
|---|
| 493 | 515 |   | 
|---|
| 494 | 516 |  	if (*bf != 'b') | 
|---|
| 495 | 517 |  		return 0; | 
|---|
| 496 | 518 |   | 
|---|
| 497 |  | -	bprm = kzalloc(sizeof(*bprm), GFP_KERNEL);  | 
|---|
| 498 |  | -	if (!bprm)  | 
|---|
| 499 |  | -		return -ENOMEM;  | 
|---|
| 500 |  | -  | 
|---|
| 501 |  | -	bprm->orig = *f;  | 
|---|
| 502 |  | -	f->fn = t->fetch[FETCH_MTD_bitfield];  | 
|---|
| 503 |  | -	f->data = (void *)bprm;  | 
|---|
| 504 | 519 |  	bw = simple_strtoul(bf + 1, &tail, 0);	/* Use simple one */ | 
|---|
| 505 | 520 |   | 
|---|
| 506 | 521 |  	if (bw == 0 || *tail != '@') | 
|---|
| .. | .. | 
|---|
| 511 | 526 |   | 
|---|
| 512 | 527 |  	if (tail == bf || *tail != '/') | 
|---|
| 513 | 528 |  		return -EINVAL; | 
|---|
 | 529 | +	code++;  | 
|---|
 | 530 | +	if (code->op != FETCH_OP_NOP)  | 
|---|
 | 531 | +		return -EINVAL;  | 
|---|
 | 532 | +	*pcode = code;  | 
|---|
| 514 | 533 |   | 
|---|
| 515 |  | -	bprm->hi_shift = BYTES_TO_BITS(t->size) - (bw + bo);  | 
|---|
| 516 |  | -	bprm->low_shift = bprm->hi_shift + bo;  | 
|---|
 | 534 | +	code->op = FETCH_OP_MOD_BF;  | 
|---|
 | 535 | +	code->lshift = BYTES_TO_BITS(t->size) - (bw + bo);  | 
|---|
 | 536 | +	code->rshift = BYTES_TO_BITS(t->size) - bw;  | 
|---|
 | 537 | +	code->basesize = t->size;  | 
|---|
| 517 | 538 |   | 
|---|
| 518 | 539 |  	return (BYTES_TO_BITS(t->size) < (bw + bo)) ? -EINVAL : 0; | 
|---|
| 519 | 540 |  } | 
|---|
| 520 | 541 |   | 
|---|
| 521 | 542 |  /* String length checking wrapper */ | 
|---|
| 522 |  | -int traceprobe_parse_probe_arg(char *arg, ssize_t *size,  | 
|---|
| 523 |  | -		struct probe_arg *parg, bool is_return, bool is_kprobe,  | 
|---|
| 524 |  | -		const struct fetch_type *ftbl)  | 
|---|
 | 543 | +static int traceprobe_parse_probe_arg_body(char *arg, ssize_t *size,  | 
|---|
 | 544 | +		struct probe_arg *parg, unsigned int flags, int offset)  | 
|---|
| 525 | 545 |  { | 
|---|
| 526 |  | -	const char *t;  | 
|---|
| 527 |  | -	int ret;  | 
|---|
 | 546 | +	struct fetch_insn *code, *scode, *tmp = NULL;  | 
|---|
 | 547 | +	char *t, *t2, *t3;  | 
|---|
 | 548 | +	int ret, len;  | 
|---|
| 528 | 549 |   | 
|---|
| 529 |  | -	if (strlen(arg) > MAX_ARGSTR_LEN) {  | 
|---|
| 530 |  | -		pr_info("Argument is too long.: %s\n",  arg);  | 
|---|
| 531 |  | -		return -ENOSPC;  | 
|---|
 | 550 | +	len = strlen(arg);  | 
|---|
 | 551 | +	if (len > MAX_ARGSTR_LEN) {  | 
|---|
 | 552 | +		trace_probe_log_err(offset, ARG_TOO_LONG);  | 
|---|
 | 553 | +		return -EINVAL;  | 
|---|
 | 554 | +	} else if (len == 0) {  | 
|---|
 | 555 | +		trace_probe_log_err(offset, NO_ARG_BODY);  | 
|---|
 | 556 | +		return -EINVAL;  | 
|---|
| 532 | 557 |  	} | 
|---|
 | 558 | +  | 
|---|
| 533 | 559 |  	parg->comm = kstrdup(arg, GFP_KERNEL); | 
|---|
| 534 |  | -	if (!parg->comm) {  | 
|---|
| 535 |  | -		pr_info("Failed to allocate memory for command '%s'.\n", arg);  | 
|---|
 | 560 | +	if (!parg->comm)  | 
|---|
| 536 | 561 |  		return -ENOMEM; | 
|---|
| 537 |  | -	}  | 
|---|
| 538 |  | -	t = strchr(parg->comm, ':');  | 
|---|
 | 562 | +  | 
|---|
 | 563 | +	t = strchr(arg, ':');  | 
|---|
| 539 | 564 |  	if (t) { | 
|---|
| 540 |  | -		arg[t - parg->comm] = '\0';  | 
|---|
| 541 |  | -		t++;  | 
|---|
 | 565 | +		*t = '\0';  | 
|---|
 | 566 | +		t2 = strchr(++t, '[');  | 
|---|
 | 567 | +		if (t2) {  | 
|---|
 | 568 | +			*t2++ = '\0';  | 
|---|
 | 569 | +			t3 = strchr(t2, ']');  | 
|---|
 | 570 | +			if (!t3) {  | 
|---|
 | 571 | +				offset += t2 + strlen(t2) - arg;  | 
|---|
 | 572 | +				trace_probe_log_err(offset,  | 
|---|
 | 573 | +						    ARRAY_NO_CLOSE);  | 
|---|
 | 574 | +				return -EINVAL;  | 
|---|
 | 575 | +			} else if (t3[1] != '\0') {  | 
|---|
 | 576 | +				trace_probe_log_err(offset + t3 + 1 - arg,  | 
|---|
 | 577 | +						    BAD_ARRAY_SUFFIX);  | 
|---|
 | 578 | +				return -EINVAL;  | 
|---|
 | 579 | +			}  | 
|---|
 | 580 | +			*t3 = '\0';  | 
|---|
 | 581 | +			if (kstrtouint(t2, 0, &parg->count) || !parg->count) {  | 
|---|
 | 582 | +				trace_probe_log_err(offset + t2 - arg,  | 
|---|
 | 583 | +						    BAD_ARRAY_NUM);  | 
|---|
 | 584 | +				return -EINVAL;  | 
|---|
 | 585 | +			}  | 
|---|
 | 586 | +			if (parg->count > MAX_ARRAY_LEN) {  | 
|---|
 | 587 | +				trace_probe_log_err(offset + t2 - arg,  | 
|---|
 | 588 | +						    ARRAY_TOO_BIG);  | 
|---|
 | 589 | +				return -EINVAL;  | 
|---|
 | 590 | +			}  | 
|---|
 | 591 | +		}  | 
|---|
| 542 | 592 |  	} | 
|---|
 | 593 | +  | 
|---|
| 543 | 594 |  	/* | 
|---|
| 544 |  | -	 * The default type of $comm should be "string", and it can't be  | 
|---|
| 545 |  | -	 * dereferenced.  | 
|---|
 | 595 | +	 * Since $comm and immediate string can not be dereferred,  | 
|---|
 | 596 | +	 * we can find those by strcmp.  | 
|---|
| 546 | 597 |  	 */ | 
|---|
| 547 |  | -	if (!t && strcmp(arg, "$comm") == 0)  | 
|---|
| 548 |  | -		t = "string";  | 
|---|
| 549 |  | -	parg->type = find_fetch_type(t, ftbl);  | 
|---|
 | 598 | +	if (strcmp(arg, "$comm") == 0 || strcmp(arg, "$COMM") == 0 ||  | 
|---|
 | 599 | +	    strncmp(arg, "\\\"", 2) == 0) {  | 
|---|
 | 600 | +		/* The type of $comm must be "string", and not an array. */  | 
|---|
 | 601 | +		if (parg->count || (t && strcmp(t, "string")))  | 
|---|
 | 602 | +			return -EINVAL;  | 
|---|
 | 603 | +		parg->type = find_fetch_type("string");  | 
|---|
 | 604 | +	} else  | 
|---|
 | 605 | +		parg->type = find_fetch_type(t);  | 
|---|
| 550 | 606 |  	if (!parg->type) { | 
|---|
| 551 |  | -		pr_info("Unsupported type: %s\n", t);  | 
|---|
 | 607 | +		trace_probe_log_err(offset + (t ? (t - arg) : 0), BAD_TYPE);  | 
|---|
| 552 | 608 |  		return -EINVAL; | 
|---|
| 553 | 609 |  	} | 
|---|
| 554 | 610 |  	parg->offset = *size; | 
|---|
| 555 |  | -	*size += parg->type->size;  | 
|---|
| 556 |  | -	ret = parse_probe_arg(arg, parg->type, &parg->fetch, is_return,  | 
|---|
| 557 |  | -			      is_kprobe, ftbl);  | 
|---|
 | 611 | +	*size += parg->type->size * (parg->count ?: 1);  | 
|---|
| 558 | 612 |   | 
|---|
| 559 |  | -	if (ret >= 0 && t != NULL)  | 
|---|
| 560 |  | -		ret = __parse_bitfield_probe_arg(t, parg->type, &parg->fetch);  | 
|---|
| 561 |  | -  | 
|---|
| 562 |  | -	if (ret >= 0) {  | 
|---|
| 563 |  | -		parg->fetch_size.fn = get_fetch_size_function(parg->type,  | 
|---|
| 564 |  | -							      parg->fetch.fn,  | 
|---|
| 565 |  | -							      ftbl);  | 
|---|
| 566 |  | -		parg->fetch_size.data = parg->fetch.data;  | 
|---|
 | 613 | +	if (parg->count) {  | 
|---|
 | 614 | +		len = strlen(parg->type->fmttype) + 6;  | 
|---|
 | 615 | +		parg->fmt = kmalloc(len, GFP_KERNEL);  | 
|---|
 | 616 | +		if (!parg->fmt)  | 
|---|
 | 617 | +			return -ENOMEM;  | 
|---|
 | 618 | +		snprintf(parg->fmt, len, "%s[%d]", parg->type->fmttype,  | 
|---|
 | 619 | +			 parg->count);  | 
|---|
| 567 | 620 |  	} | 
|---|
 | 621 | +  | 
|---|
 | 622 | +	code = tmp = kcalloc(FETCH_INSN_MAX, sizeof(*code), GFP_KERNEL);  | 
|---|
 | 623 | +	if (!code)  | 
|---|
 | 624 | +		return -ENOMEM;  | 
|---|
 | 625 | +	code[FETCH_INSN_MAX - 1].op = FETCH_OP_END;  | 
|---|
 | 626 | +  | 
|---|
 | 627 | +	ret = parse_probe_arg(arg, parg->type, &code, &code[FETCH_INSN_MAX - 1],  | 
|---|
 | 628 | +			      flags, offset);  | 
|---|
 | 629 | +	if (ret)  | 
|---|
 | 630 | +		goto fail;  | 
|---|
 | 631 | +  | 
|---|
 | 632 | +	/* Store operation */  | 
|---|
 | 633 | +	if (!strcmp(parg->type->name, "string") ||  | 
|---|
 | 634 | +	    !strcmp(parg->type->name, "ustring")) {  | 
|---|
 | 635 | +		if (code->op != FETCH_OP_DEREF && code->op != FETCH_OP_UDEREF &&  | 
|---|
 | 636 | +		    code->op != FETCH_OP_IMM && code->op != FETCH_OP_COMM &&  | 
|---|
 | 637 | +		    code->op != FETCH_OP_DATA) {  | 
|---|
 | 638 | +			trace_probe_log_err(offset + (t ? (t - arg) : 0),  | 
|---|
 | 639 | +					    BAD_STRING);  | 
|---|
 | 640 | +			ret = -EINVAL;  | 
|---|
 | 641 | +			goto fail;  | 
|---|
 | 642 | +		}  | 
|---|
 | 643 | +		if ((code->op == FETCH_OP_IMM || code->op == FETCH_OP_COMM ||  | 
|---|
 | 644 | +		     code->op == FETCH_OP_DATA) || parg->count) {  | 
|---|
 | 645 | +			/*  | 
|---|
 | 646 | +			 * IMM, DATA and COMM is pointing actual address, those  | 
|---|
 | 647 | +			 * must be kept, and if parg->count != 0, this is an  | 
|---|
 | 648 | +			 * array of string pointers instead of string address  | 
|---|
 | 649 | +			 * itself.  | 
|---|
 | 650 | +			 */  | 
|---|
 | 651 | +			code++;  | 
|---|
 | 652 | +			if (code->op != FETCH_OP_NOP) {  | 
|---|
 | 653 | +				trace_probe_log_err(offset, TOO_MANY_OPS);  | 
|---|
 | 654 | +				ret = -EINVAL;  | 
|---|
 | 655 | +				goto fail;  | 
|---|
 | 656 | +			}  | 
|---|
 | 657 | +		}  | 
|---|
 | 658 | +		/* If op == DEREF, replace it with STRING */  | 
|---|
 | 659 | +		if (!strcmp(parg->type->name, "ustring") ||  | 
|---|
 | 660 | +		    code->op == FETCH_OP_UDEREF)  | 
|---|
 | 661 | +			code->op = FETCH_OP_ST_USTRING;  | 
|---|
 | 662 | +		else  | 
|---|
 | 663 | +			code->op = FETCH_OP_ST_STRING;  | 
|---|
 | 664 | +		code->size = parg->type->size;  | 
|---|
 | 665 | +		parg->dynamic = true;  | 
|---|
 | 666 | +	} else if (code->op == FETCH_OP_DEREF) {  | 
|---|
 | 667 | +		code->op = FETCH_OP_ST_MEM;  | 
|---|
 | 668 | +		code->size = parg->type->size;  | 
|---|
 | 669 | +	} else if (code->op == FETCH_OP_UDEREF) {  | 
|---|
 | 670 | +		code->op = FETCH_OP_ST_UMEM;  | 
|---|
 | 671 | +		code->size = parg->type->size;  | 
|---|
 | 672 | +	} else {  | 
|---|
 | 673 | +		code++;  | 
|---|
 | 674 | +		if (code->op != FETCH_OP_NOP) {  | 
|---|
 | 675 | +			trace_probe_log_err(offset, TOO_MANY_OPS);  | 
|---|
 | 676 | +			ret = -EINVAL;  | 
|---|
 | 677 | +			goto fail;  | 
|---|
 | 678 | +		}  | 
|---|
 | 679 | +		code->op = FETCH_OP_ST_RAW;  | 
|---|
 | 680 | +		code->size = parg->type->size;  | 
|---|
 | 681 | +	}  | 
|---|
 | 682 | +	scode = code;  | 
|---|
 | 683 | +	/* Modify operation */  | 
|---|
 | 684 | +	if (t != NULL) {  | 
|---|
 | 685 | +		ret = __parse_bitfield_probe_arg(t, parg->type, &code);  | 
|---|
 | 686 | +		if (ret) {  | 
|---|
 | 687 | +			trace_probe_log_err(offset + t - arg, BAD_BITFIELD);  | 
|---|
 | 688 | +			goto fail;  | 
|---|
 | 689 | +		}  | 
|---|
 | 690 | +	}  | 
|---|
 | 691 | +	/* Loop(Array) operation */  | 
|---|
 | 692 | +	if (parg->count) {  | 
|---|
 | 693 | +		if (scode->op != FETCH_OP_ST_MEM &&  | 
|---|
 | 694 | +		    scode->op != FETCH_OP_ST_STRING &&  | 
|---|
 | 695 | +		    scode->op != FETCH_OP_ST_USTRING) {  | 
|---|
 | 696 | +			trace_probe_log_err(offset + (t ? (t - arg) : 0),  | 
|---|
 | 697 | +					    BAD_STRING);  | 
|---|
 | 698 | +			ret = -EINVAL;  | 
|---|
 | 699 | +			goto fail;  | 
|---|
 | 700 | +		}  | 
|---|
 | 701 | +		code++;  | 
|---|
 | 702 | +		if (code->op != FETCH_OP_NOP) {  | 
|---|
 | 703 | +			trace_probe_log_err(offset, TOO_MANY_OPS);  | 
|---|
 | 704 | +			ret = -EINVAL;  | 
|---|
 | 705 | +			goto fail;  | 
|---|
 | 706 | +		}  | 
|---|
 | 707 | +		code->op = FETCH_OP_LP_ARRAY;  | 
|---|
 | 708 | +		code->param = parg->count;  | 
|---|
 | 709 | +	}  | 
|---|
 | 710 | +	code++;  | 
|---|
 | 711 | +	code->op = FETCH_OP_END;  | 
|---|
 | 712 | +  | 
|---|
 | 713 | +	/* Shrink down the code buffer */  | 
|---|
 | 714 | +	parg->code = kcalloc(code - tmp + 1, sizeof(*code), GFP_KERNEL);  | 
|---|
 | 715 | +	if (!parg->code)  | 
|---|
 | 716 | +		ret = -ENOMEM;  | 
|---|
 | 717 | +	else  | 
|---|
 | 718 | +		memcpy(parg->code, tmp, sizeof(*code) * (code - tmp + 1));  | 
|---|
 | 719 | +  | 
|---|
 | 720 | +fail:  | 
|---|
 | 721 | +	if (ret) {  | 
|---|
 | 722 | +		for (code = tmp; code < tmp + FETCH_INSN_MAX; code++)  | 
|---|
 | 723 | +			if (code->op == FETCH_NOP_SYMBOL ||  | 
|---|
 | 724 | +			    code->op == FETCH_OP_DATA)  | 
|---|
 | 725 | +				kfree(code->data);  | 
|---|
 | 726 | +	}  | 
|---|
 | 727 | +	kfree(tmp);  | 
|---|
| 568 | 728 |   | 
|---|
| 569 | 729 |  	return ret; | 
|---|
| 570 | 730 |  } | 
|---|
| 571 | 731 |   | 
|---|
| 572 | 732 |  /* Return 1 if name is reserved or already used by another argument */ | 
|---|
| 573 |  | -int traceprobe_conflict_field_name(const char *name,  | 
|---|
| 574 |  | -			       struct probe_arg *args, int narg)  | 
|---|
 | 733 | +static int traceprobe_conflict_field_name(const char *name,  | 
|---|
 | 734 | +					  struct probe_arg *args, int narg)  | 
|---|
| 575 | 735 |  { | 
|---|
| 576 | 736 |  	int i; | 
|---|
| 577 | 737 |   | 
|---|
| .. | .. | 
|---|
| 586 | 746 |  	return 0; | 
|---|
| 587 | 747 |  } | 
|---|
| 588 | 748 |   | 
|---|
| 589 |  | -void traceprobe_update_arg(struct probe_arg *arg)  | 
|---|
 | 749 | +int traceprobe_parse_probe_arg(struct trace_probe *tp, int i, char *arg,  | 
|---|
 | 750 | +				unsigned int flags)  | 
|---|
| 590 | 751 |  { | 
|---|
| 591 |  | -	if (CHECK_FETCH_FUNCS(bitfield, arg->fetch.fn))  | 
|---|
| 592 |  | -		update_bitfield_fetch_param(arg->fetch.data);  | 
|---|
| 593 |  | -	else if (CHECK_FETCH_FUNCS(deref, arg->fetch.fn))  | 
|---|
| 594 |  | -		update_deref_fetch_param(arg->fetch.data);  | 
|---|
| 595 |  | -	else if (CHECK_FETCH_FUNCS(symbol, arg->fetch.fn))  | 
|---|
| 596 |  | -		update_symbol_cache(arg->fetch.data);  | 
|---|
 | 752 | +	struct probe_arg *parg = &tp->args[i];  | 
|---|
 | 753 | +	char *body;  | 
|---|
 | 754 | +  | 
|---|
 | 755 | +	/* Increment count for freeing args in error case */  | 
|---|
 | 756 | +	tp->nr_args++;  | 
|---|
 | 757 | +  | 
|---|
 | 758 | +	body = strchr(arg, '=');  | 
|---|
 | 759 | +	if (body) {  | 
|---|
 | 760 | +		if (body - arg > MAX_ARG_NAME_LEN) {  | 
|---|
 | 761 | +			trace_probe_log_err(0, ARG_NAME_TOO_LONG);  | 
|---|
 | 762 | +			return -EINVAL;  | 
|---|
 | 763 | +		} else if (body == arg) {  | 
|---|
 | 764 | +			trace_probe_log_err(0, NO_ARG_NAME);  | 
|---|
 | 765 | +			return -EINVAL;  | 
|---|
 | 766 | +		}  | 
|---|
 | 767 | +		parg->name = kmemdup_nul(arg, body - arg, GFP_KERNEL);  | 
|---|
 | 768 | +		body++;  | 
|---|
 | 769 | +	} else {  | 
|---|
 | 770 | +		/* If argument name is omitted, set "argN" */  | 
|---|
 | 771 | +		parg->name = kasprintf(GFP_KERNEL, "arg%d", i + 1);  | 
|---|
 | 772 | +		body = arg;  | 
|---|
 | 773 | +	}  | 
|---|
 | 774 | +	if (!parg->name)  | 
|---|
 | 775 | +		return -ENOMEM;  | 
|---|
 | 776 | +  | 
|---|
 | 777 | +	if (!is_good_name(parg->name)) {  | 
|---|
 | 778 | +		trace_probe_log_err(0, BAD_ARG_NAME);  | 
|---|
 | 779 | +		return -EINVAL;  | 
|---|
 | 780 | +	}  | 
|---|
 | 781 | +	if (traceprobe_conflict_field_name(parg->name, tp->args, i)) {  | 
|---|
 | 782 | +		trace_probe_log_err(0, USED_ARG_NAME);  | 
|---|
 | 783 | +		return -EINVAL;  | 
|---|
 | 784 | +	}  | 
|---|
 | 785 | +	/* Parse fetch argument */  | 
|---|
 | 786 | +	return traceprobe_parse_probe_arg_body(body, &tp->size, parg, flags,  | 
|---|
 | 787 | +					       body - arg);  | 
|---|
| 597 | 788 |  } | 
|---|
| 598 | 789 |   | 
|---|
| 599 | 790 |  void traceprobe_free_probe_arg(struct probe_arg *arg) | 
|---|
| 600 | 791 |  { | 
|---|
| 601 |  | -	if (CHECK_FETCH_FUNCS(bitfield, arg->fetch.fn))  | 
|---|
| 602 |  | -		free_bitfield_fetch_param(arg->fetch.data);  | 
|---|
| 603 |  | -	else if (CHECK_FETCH_FUNCS(deref, arg->fetch.fn))  | 
|---|
| 604 |  | -		free_deref_fetch_param(arg->fetch.data);  | 
|---|
| 605 |  | -	else if (CHECK_FETCH_FUNCS(symbol, arg->fetch.fn))  | 
|---|
| 606 |  | -		free_symbol_cache(arg->fetch.data);  | 
|---|
 | 792 | +	struct fetch_insn *code = arg->code;  | 
|---|
| 607 | 793 |   | 
|---|
 | 794 | +	while (code && code->op != FETCH_OP_END) {  | 
|---|
 | 795 | +		if (code->op == FETCH_NOP_SYMBOL ||  | 
|---|
 | 796 | +		    code->op == FETCH_OP_DATA)  | 
|---|
 | 797 | +			kfree(code->data);  | 
|---|
 | 798 | +		code++;  | 
|---|
 | 799 | +	}  | 
|---|
 | 800 | +	kfree(arg->code);  | 
|---|
| 608 | 801 |  	kfree(arg->name); | 
|---|
| 609 | 802 |  	kfree(arg->comm); | 
|---|
 | 803 | +	kfree(arg->fmt);  | 
|---|
| 610 | 804 |  } | 
|---|
| 611 | 805 |   | 
|---|
 | 806 | +int traceprobe_update_arg(struct probe_arg *arg)  | 
|---|
 | 807 | +{  | 
|---|
 | 808 | +	struct fetch_insn *code = arg->code;  | 
|---|
 | 809 | +	long offset;  | 
|---|
 | 810 | +	char *tmp;  | 
|---|
 | 811 | +	char c;  | 
|---|
 | 812 | +	int ret = 0;  | 
|---|
 | 813 | +  | 
|---|
 | 814 | +	while (code && code->op != FETCH_OP_END) {  | 
|---|
 | 815 | +		if (code->op == FETCH_NOP_SYMBOL) {  | 
|---|
 | 816 | +			if (code[1].op != FETCH_OP_IMM)  | 
|---|
 | 817 | +				return -EINVAL;  | 
|---|
 | 818 | +  | 
|---|
 | 819 | +			tmp = strpbrk(code->data, "+-");  | 
|---|
 | 820 | +			if (tmp)  | 
|---|
 | 821 | +				c = *tmp;  | 
|---|
 | 822 | +			ret = traceprobe_split_symbol_offset(code->data,  | 
|---|
 | 823 | +							     &offset);  | 
|---|
 | 824 | +			if (ret)  | 
|---|
 | 825 | +				return ret;  | 
|---|
 | 826 | +  | 
|---|
 | 827 | +			code[1].immediate =  | 
|---|
 | 828 | +				(unsigned long)kallsyms_lookup_name(code->data);  | 
|---|
 | 829 | +			if (tmp)  | 
|---|
 | 830 | +				*tmp = c;  | 
|---|
 | 831 | +			if (!code[1].immediate)  | 
|---|
 | 832 | +				return -ENOENT;  | 
|---|
 | 833 | +			code[1].immediate += offset;  | 
|---|
 | 834 | +		}  | 
|---|
 | 835 | +		code++;  | 
|---|
 | 836 | +	}  | 
|---|
 | 837 | +	return 0;  | 
|---|
 | 838 | +}  | 
|---|
 | 839 | +  | 
|---|
 | 840 | +/* When len=0, we just calculate the needed length */  | 
|---|
 | 841 | +#define LEN_OR_ZERO (len ? len - pos : 0)  | 
|---|
| 612 | 842 |  static int __set_print_fmt(struct trace_probe *tp, char *buf, int len, | 
|---|
| 613 | 843 |  			   bool is_return) | 
|---|
| 614 | 844 |  { | 
|---|
| 615 |  | -	int i;  | 
|---|
 | 845 | +	struct probe_arg *parg;  | 
|---|
 | 846 | +	int i, j;  | 
|---|
| 616 | 847 |  	int pos = 0; | 
|---|
| 617 |  | -  | 
|---|
| 618 | 848 |  	const char *fmt, *arg; | 
|---|
| 619 | 849 |   | 
|---|
| 620 | 850 |  	if (!is_return) { | 
|---|
| .. | .. | 
|---|
| 625 | 855 |  		arg = "REC->" FIELD_STRING_FUNC ", REC->" FIELD_STRING_RETIP; | 
|---|
| 626 | 856 |  	} | 
|---|
| 627 | 857 |   | 
|---|
| 628 |  | -	/* When len=0, we just calculate the needed length */  | 
|---|
| 629 |  | -#define LEN_OR_ZERO (len ? len - pos : 0)  | 
|---|
| 630 |  | -  | 
|---|
| 631 | 858 |  	pos += snprintf(buf + pos, LEN_OR_ZERO, "\"%s", fmt); | 
|---|
| 632 | 859 |   | 
|---|
| 633 | 860 |  	for (i = 0; i < tp->nr_args; i++) { | 
|---|
| 634 |  | -		pos += snprintf(buf + pos, LEN_OR_ZERO, " %s=%s",  | 
|---|
| 635 |  | -				tp->args[i].name, tp->args[i].type->fmt);  | 
|---|
 | 861 | +		parg = tp->args + i;  | 
|---|
 | 862 | +		pos += snprintf(buf + pos, LEN_OR_ZERO, " %s=", parg->name);  | 
|---|
 | 863 | +		if (parg->count) {  | 
|---|
 | 864 | +			pos += snprintf(buf + pos, LEN_OR_ZERO, "{%s",  | 
|---|
 | 865 | +					parg->type->fmt);  | 
|---|
 | 866 | +			for (j = 1; j < parg->count; j++)  | 
|---|
 | 867 | +				pos += snprintf(buf + pos, LEN_OR_ZERO, ",%s",  | 
|---|
 | 868 | +						parg->type->fmt);  | 
|---|
 | 869 | +			pos += snprintf(buf + pos, LEN_OR_ZERO, "}");  | 
|---|
 | 870 | +		} else  | 
|---|
 | 871 | +			pos += snprintf(buf + pos, LEN_OR_ZERO, "%s",  | 
|---|
 | 872 | +					parg->type->fmt);  | 
|---|
| 636 | 873 |  	} | 
|---|
| 637 | 874 |   | 
|---|
| 638 | 875 |  	pos += snprintf(buf + pos, LEN_OR_ZERO, "\", %s", arg); | 
|---|
| 639 | 876 |   | 
|---|
| 640 | 877 |  	for (i = 0; i < tp->nr_args; i++) { | 
|---|
| 641 |  | -		if (strcmp(tp->args[i].type->name, "string") == 0)  | 
|---|
 | 878 | +		parg = tp->args + i;  | 
|---|
 | 879 | +		if (parg->count) {  | 
|---|
 | 880 | +			if ((strcmp(parg->type->name, "string") == 0) ||  | 
|---|
 | 881 | +			    (strcmp(parg->type->name, "ustring") == 0))  | 
|---|
 | 882 | +				fmt = ", __get_str(%s[%d])";  | 
|---|
 | 883 | +			else  | 
|---|
 | 884 | +				fmt = ", REC->%s[%d]";  | 
|---|
 | 885 | +			for (j = 0; j < parg->count; j++)  | 
|---|
 | 886 | +				pos += snprintf(buf + pos, LEN_OR_ZERO,  | 
|---|
 | 887 | +						fmt, parg->name, j);  | 
|---|
 | 888 | +		} else {  | 
|---|
 | 889 | +			if ((strcmp(parg->type->name, "string") == 0) ||  | 
|---|
 | 890 | +			    (strcmp(parg->type->name, "ustring") == 0))  | 
|---|
 | 891 | +				fmt = ", __get_str(%s)";  | 
|---|
 | 892 | +			else  | 
|---|
 | 893 | +				fmt = ", REC->%s";  | 
|---|
| 642 | 894 |  			pos += snprintf(buf + pos, LEN_OR_ZERO, | 
|---|
| 643 |  | -					", __get_str(%s)",  | 
|---|
| 644 |  | -					tp->args[i].name);  | 
|---|
| 645 |  | -		else  | 
|---|
| 646 |  | -			pos += snprintf(buf + pos, LEN_OR_ZERO, ", REC->%s",  | 
|---|
| 647 |  | -					tp->args[i].name);  | 
|---|
 | 895 | +					fmt, parg->name);  | 
|---|
 | 896 | +		}  | 
|---|
| 648 | 897 |  	} | 
|---|
| 649 |  | -  | 
|---|
| 650 |  | -#undef LEN_OR_ZERO  | 
|---|
| 651 | 898 |   | 
|---|
| 652 | 899 |  	/* return the length of print_fmt */ | 
|---|
| 653 | 900 |  	return pos; | 
|---|
| 654 | 901 |  } | 
|---|
 | 902 | +#undef LEN_OR_ZERO  | 
|---|
| 655 | 903 |   | 
|---|
| 656 |  | -int set_print_fmt(struct trace_probe *tp, bool is_return)  | 
|---|
 | 904 | +int traceprobe_set_print_fmt(struct trace_probe *tp, bool is_return)  | 
|---|
| 657 | 905 |  { | 
|---|
 | 906 | +	struct trace_event_call *call = trace_probe_event_call(tp);  | 
|---|
| 658 | 907 |  	int len; | 
|---|
| 659 | 908 |  	char *print_fmt; | 
|---|
| 660 | 909 |   | 
|---|
| .. | .. | 
|---|
| 666 | 915 |   | 
|---|
| 667 | 916 |  	/* Second: actually write the @print_fmt */ | 
|---|
| 668 | 917 |  	__set_print_fmt(tp, print_fmt, len + 1, is_return); | 
|---|
| 669 |  | -	tp->call.print_fmt = print_fmt;  | 
|---|
 | 918 | +	call->print_fmt = print_fmt;  | 
|---|
| 670 | 919 |   | 
|---|
| 671 | 920 |  	return 0; | 
|---|
| 672 | 921 |  } | 
|---|
 | 922 | +  | 
|---|
 | 923 | +int traceprobe_define_arg_fields(struct trace_event_call *event_call,  | 
|---|
 | 924 | +				 size_t offset, struct trace_probe *tp)  | 
|---|
 | 925 | +{  | 
|---|
 | 926 | +	int ret, i;  | 
|---|
 | 927 | +  | 
|---|
 | 928 | +	/* Set argument names as fields */  | 
|---|
 | 929 | +	for (i = 0; i < tp->nr_args; i++) {  | 
|---|
 | 930 | +		struct probe_arg *parg = &tp->args[i];  | 
|---|
 | 931 | +		const char *fmt = parg->type->fmttype;  | 
|---|
 | 932 | +		int size = parg->type->size;  | 
|---|
 | 933 | +  | 
|---|
 | 934 | +		if (parg->fmt)  | 
|---|
 | 935 | +			fmt = parg->fmt;  | 
|---|
 | 936 | +		if (parg->count)  | 
|---|
 | 937 | +			size *= parg->count;  | 
|---|
 | 938 | +		ret = trace_define_field(event_call, fmt, parg->name,  | 
|---|
 | 939 | +					 offset + parg->offset, size,  | 
|---|
 | 940 | +					 parg->type->is_signed,  | 
|---|
 | 941 | +					 FILTER_OTHER);  | 
|---|
 | 942 | +		if (ret)  | 
|---|
 | 943 | +			return ret;  | 
|---|
 | 944 | +	}  | 
|---|
 | 945 | +	return 0;  | 
|---|
 | 946 | +}  | 
|---|
 | 947 | +  | 
|---|
 | 948 | +static void trace_probe_event_free(struct trace_probe_event *tpe)  | 
|---|
 | 949 | +{  | 
|---|
 | 950 | +	kfree(tpe->class.system);  | 
|---|
 | 951 | +	kfree(tpe->call.name);  | 
|---|
 | 952 | +	kfree(tpe->call.print_fmt);  | 
|---|
 | 953 | +	kfree(tpe);  | 
|---|
 | 954 | +}  | 
|---|
 | 955 | +  | 
|---|
 | 956 | +int trace_probe_append(struct trace_probe *tp, struct trace_probe *to)  | 
|---|
 | 957 | +{  | 
|---|
 | 958 | +	if (trace_probe_has_sibling(tp))  | 
|---|
 | 959 | +		return -EBUSY;  | 
|---|
 | 960 | +  | 
|---|
 | 961 | +	list_del_init(&tp->list);  | 
|---|
 | 962 | +	trace_probe_event_free(tp->event);  | 
|---|
 | 963 | +  | 
|---|
 | 964 | +	tp->event = to->event;  | 
|---|
 | 965 | +	list_add_tail(&tp->list, trace_probe_probe_list(to));  | 
|---|
 | 966 | +  | 
|---|
 | 967 | +	return 0;  | 
|---|
 | 968 | +}  | 
|---|
 | 969 | +  | 
|---|
 | 970 | +void trace_probe_unlink(struct trace_probe *tp)  | 
|---|
 | 971 | +{  | 
|---|
 | 972 | +	list_del_init(&tp->list);  | 
|---|
 | 973 | +	if (list_empty(trace_probe_probe_list(tp)))  | 
|---|
 | 974 | +		trace_probe_event_free(tp->event);  | 
|---|
 | 975 | +	tp->event = NULL;  | 
|---|
 | 976 | +}  | 
|---|
 | 977 | +  | 
|---|
 | 978 | +void trace_probe_cleanup(struct trace_probe *tp)  | 
|---|
 | 979 | +{  | 
|---|
 | 980 | +	int i;  | 
|---|
 | 981 | +  | 
|---|
 | 982 | +	for (i = 0; i < tp->nr_args; i++)  | 
|---|
 | 983 | +		traceprobe_free_probe_arg(&tp->args[i]);  | 
|---|
 | 984 | +  | 
|---|
 | 985 | +	if (tp->event)  | 
|---|
 | 986 | +		trace_probe_unlink(tp);  | 
|---|
 | 987 | +}  | 
|---|
 | 988 | +  | 
|---|
 | 989 | +int trace_probe_init(struct trace_probe *tp, const char *event,  | 
|---|
 | 990 | +		     const char *group, bool alloc_filter)  | 
|---|
 | 991 | +{  | 
|---|
 | 992 | +	struct trace_event_call *call;  | 
|---|
 | 993 | +	size_t size = sizeof(struct trace_probe_event);  | 
|---|
 | 994 | +	int ret = 0;  | 
|---|
 | 995 | +  | 
|---|
 | 996 | +	if (!event || !group)  | 
|---|
 | 997 | +		return -EINVAL;  | 
|---|
 | 998 | +  | 
|---|
 | 999 | +	if (alloc_filter)  | 
|---|
 | 1000 | +		size += sizeof(struct trace_uprobe_filter);  | 
|---|
 | 1001 | +  | 
|---|
 | 1002 | +	tp->event = kzalloc(size, GFP_KERNEL);  | 
|---|
 | 1003 | +	if (!tp->event)  | 
|---|
 | 1004 | +		return -ENOMEM;  | 
|---|
 | 1005 | +  | 
|---|
 | 1006 | +	INIT_LIST_HEAD(&tp->event->files);  | 
|---|
 | 1007 | +	INIT_LIST_HEAD(&tp->event->class.fields);  | 
|---|
 | 1008 | +	INIT_LIST_HEAD(&tp->event->probes);  | 
|---|
 | 1009 | +	INIT_LIST_HEAD(&tp->list);  | 
|---|
 | 1010 | +	list_add(&tp->list, &tp->event->probes);  | 
|---|
 | 1011 | +  | 
|---|
 | 1012 | +	call = trace_probe_event_call(tp);  | 
|---|
 | 1013 | +	call->class = &tp->event->class;  | 
|---|
 | 1014 | +	call->name = kstrdup(event, GFP_KERNEL);  | 
|---|
 | 1015 | +	if (!call->name) {  | 
|---|
 | 1016 | +		ret = -ENOMEM;  | 
|---|
 | 1017 | +		goto error;  | 
|---|
 | 1018 | +	}  | 
|---|
 | 1019 | +  | 
|---|
 | 1020 | +	tp->event->class.system = kstrdup(group, GFP_KERNEL);  | 
|---|
 | 1021 | +	if (!tp->event->class.system) {  | 
|---|
 | 1022 | +		ret = -ENOMEM;  | 
|---|
 | 1023 | +		goto error;  | 
|---|
 | 1024 | +	}  | 
|---|
 | 1025 | +  | 
|---|
 | 1026 | +	return 0;  | 
|---|
 | 1027 | +  | 
|---|
 | 1028 | +error:  | 
|---|
 | 1029 | +	trace_probe_cleanup(tp);  | 
|---|
 | 1030 | +	return ret;  | 
|---|
 | 1031 | +}  | 
|---|
 | 1032 | +  | 
|---|
 | 1033 | +static struct trace_event_call *  | 
|---|
 | 1034 | +find_trace_event_call(const char *system, const char *event_name)  | 
|---|
 | 1035 | +{  | 
|---|
 | 1036 | +	struct trace_event_call *tp_event;  | 
|---|
 | 1037 | +	const char *name;  | 
|---|
 | 1038 | +  | 
|---|
 | 1039 | +	list_for_each_entry(tp_event, &ftrace_events, list) {  | 
|---|
 | 1040 | +		if (!tp_event->class->system ||  | 
|---|
 | 1041 | +		    strcmp(system, tp_event->class->system))  | 
|---|
 | 1042 | +			continue;  | 
|---|
 | 1043 | +		name = trace_event_name(tp_event);  | 
|---|
 | 1044 | +		if (!name || strcmp(event_name, name))  | 
|---|
 | 1045 | +			continue;  | 
|---|
 | 1046 | +		return tp_event;  | 
|---|
 | 1047 | +	}  | 
|---|
 | 1048 | +  | 
|---|
 | 1049 | +	return NULL;  | 
|---|
 | 1050 | +}  | 
|---|
 | 1051 | +  | 
|---|
 | 1052 | +int trace_probe_register_event_call(struct trace_probe *tp)  | 
|---|
 | 1053 | +{  | 
|---|
 | 1054 | +	struct trace_event_call *call = trace_probe_event_call(tp);  | 
|---|
 | 1055 | +	int ret;  | 
|---|
 | 1056 | +  | 
|---|
 | 1057 | +	lockdep_assert_held(&event_mutex);  | 
|---|
 | 1058 | +  | 
|---|
 | 1059 | +	if (find_trace_event_call(trace_probe_group_name(tp),  | 
|---|
 | 1060 | +				  trace_probe_name(tp)))  | 
|---|
 | 1061 | +		return -EEXIST;  | 
|---|
 | 1062 | +  | 
|---|
 | 1063 | +	ret = register_trace_event(&call->event);  | 
|---|
 | 1064 | +	if (!ret)  | 
|---|
 | 1065 | +		return -ENODEV;  | 
|---|
 | 1066 | +  | 
|---|
 | 1067 | +	ret = trace_add_event_call(call);  | 
|---|
 | 1068 | +	if (ret)  | 
|---|
 | 1069 | +		unregister_trace_event(&call->event);  | 
|---|
 | 1070 | +  | 
|---|
 | 1071 | +	return ret;  | 
|---|
 | 1072 | +}  | 
|---|
 | 1073 | +  | 
|---|
 | 1074 | +int trace_probe_add_file(struct trace_probe *tp, struct trace_event_file *file)  | 
|---|
 | 1075 | +{  | 
|---|
 | 1076 | +	struct event_file_link *link;  | 
|---|
 | 1077 | +  | 
|---|
 | 1078 | +	link = kmalloc(sizeof(*link), GFP_KERNEL);  | 
|---|
 | 1079 | +	if (!link)  | 
|---|
 | 1080 | +		return -ENOMEM;  | 
|---|
 | 1081 | +  | 
|---|
 | 1082 | +	link->file = file;  | 
|---|
 | 1083 | +	INIT_LIST_HEAD(&link->list);  | 
|---|
 | 1084 | +	list_add_tail_rcu(&link->list, &tp->event->files);  | 
|---|
 | 1085 | +	trace_probe_set_flag(tp, TP_FLAG_TRACE);  | 
|---|
 | 1086 | +	return 0;  | 
|---|
 | 1087 | +}  | 
|---|
 | 1088 | +  | 
|---|
 | 1089 | +struct event_file_link *trace_probe_get_file_link(struct trace_probe *tp,  | 
|---|
 | 1090 | +						  struct trace_event_file *file)  | 
|---|
 | 1091 | +{  | 
|---|
 | 1092 | +	struct event_file_link *link;  | 
|---|
 | 1093 | +  | 
|---|
 | 1094 | +	trace_probe_for_each_link(link, tp) {  | 
|---|
 | 1095 | +		if (link->file == file)  | 
|---|
 | 1096 | +			return link;  | 
|---|
 | 1097 | +	}  | 
|---|
 | 1098 | +  | 
|---|
 | 1099 | +	return NULL;  | 
|---|
 | 1100 | +}  | 
|---|
 | 1101 | +  | 
|---|
 | 1102 | +int trace_probe_remove_file(struct trace_probe *tp,  | 
|---|
 | 1103 | +			    struct trace_event_file *file)  | 
|---|
 | 1104 | +{  | 
|---|
 | 1105 | +	struct event_file_link *link;  | 
|---|
 | 1106 | +  | 
|---|
 | 1107 | +	link = trace_probe_get_file_link(tp, file);  | 
|---|
 | 1108 | +	if (!link)  | 
|---|
 | 1109 | +		return -ENOENT;  | 
|---|
 | 1110 | +  | 
|---|
 | 1111 | +	list_del_rcu(&link->list);  | 
|---|
 | 1112 | +	synchronize_rcu();  | 
|---|
 | 1113 | +	kfree(link);  | 
|---|
 | 1114 | +  | 
|---|
 | 1115 | +	if (list_empty(&tp->event->files))  | 
|---|
 | 1116 | +		trace_probe_clear_flag(tp, TP_FLAG_TRACE);  | 
|---|
 | 1117 | +  | 
|---|
 | 1118 | +	return 0;  | 
|---|
 | 1119 | +}  | 
|---|
 | 1120 | +  | 
|---|
 | 1121 | +/*  | 
|---|
 | 1122 | + * Return the smallest index of different type argument (start from 1).  | 
|---|
 | 1123 | + * If all argument types and name are same, return 0.  | 
|---|
 | 1124 | + */  | 
|---|
 | 1125 | +int trace_probe_compare_arg_type(struct trace_probe *a, struct trace_probe *b)  | 
|---|
 | 1126 | +{  | 
|---|
 | 1127 | +	int i;  | 
|---|
 | 1128 | +  | 
|---|
 | 1129 | +	/* In case of more arguments */  | 
|---|
 | 1130 | +	if (a->nr_args < b->nr_args)  | 
|---|
 | 1131 | +		return a->nr_args + 1;  | 
|---|
 | 1132 | +	if (a->nr_args > b->nr_args)  | 
|---|
 | 1133 | +		return b->nr_args + 1;  | 
|---|
 | 1134 | +  | 
|---|
 | 1135 | +	for (i = 0; i < a->nr_args; i++) {  | 
|---|
 | 1136 | +		if ((b->nr_args <= i) ||  | 
|---|
 | 1137 | +		    ((a->args[i].type != b->args[i].type) ||  | 
|---|
 | 1138 | +		     (a->args[i].count != b->args[i].count) ||  | 
|---|
 | 1139 | +		     strcmp(a->args[i].name, b->args[i].name)))  | 
|---|
 | 1140 | +			return i + 1;  | 
|---|
 | 1141 | +	}  | 
|---|
 | 1142 | +  | 
|---|
 | 1143 | +	return 0;  | 
|---|
 | 1144 | +}  | 
|---|
 | 1145 | +  | 
|---|
 | 1146 | +bool trace_probe_match_command_args(struct trace_probe *tp,  | 
|---|
 | 1147 | +				    int argc, const char **argv)  | 
|---|
 | 1148 | +{  | 
|---|
 | 1149 | +	char buf[MAX_ARGSTR_LEN + 1];  | 
|---|
 | 1150 | +	int i;  | 
|---|
 | 1151 | +  | 
|---|
 | 1152 | +	if (tp->nr_args < argc)  | 
|---|
 | 1153 | +		return false;  | 
|---|
 | 1154 | +  | 
|---|
 | 1155 | +	for (i = 0; i < argc; i++) {  | 
|---|
 | 1156 | +		snprintf(buf, sizeof(buf), "%s=%s",  | 
|---|
 | 1157 | +			 tp->args[i].name, tp->args[i].comm);  | 
|---|
 | 1158 | +		if (strcmp(buf, argv[i]))  | 
|---|
 | 1159 | +			return false;  | 
|---|
 | 1160 | +	}  | 
|---|
 | 1161 | +	return true;  | 
|---|
 | 1162 | +}  | 
|---|