blob: 21af28ffba3ae48a0344f7b358299fdf890e5a11 [file] [log] [blame]
Steven Rostedt (VMware)bcea3f92018-08-16 11:23:53 -04001// SPDX-License-Identifier: GPL-2.0
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +05302/*
3 * Common code for probe-based Dynamic events.
4 *
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +05305 * This code was copied from kernel/trace/trace_kprobe.c written by
6 * Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
7 *
8 * Updates to make this generic:
9 * Copyright (C) IBM Corporation, 2010-2011
10 * Author: Srikar Dronamraju
11 */
Masami Hiramatsu72576342017-02-07 20:21:28 +090012#define pr_fmt(fmt) "trace_probe: " fmt
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +053013
14#include "trace_probe.h"
15
16const char *reserved_field_names[] = {
17 "common_type",
18 "common_flags",
19 "common_preempt_count",
20 "common_pid",
21 "common_tgid",
22 FIELD_STRING_IP,
23 FIELD_STRING_RETIP,
24 FIELD_STRING_FUNC,
25};
26
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +053027/* Printing in basic type function template */
Masami Hiramatsu17ce3dc2016-08-18 17:57:50 +090028#define DEFINE_BASIC_PRINT_TYPE_FUNC(tname, type, fmt) \
Masami Hiramatsu56de7632018-04-25 21:16:36 +090029int PRINT_TYPE_FUNC_NAME(tname)(struct trace_seq *s, void *data, void *ent)\
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +053030{ \
Masami Hiramatsu56de7632018-04-25 21:16:36 +090031 trace_seq_printf(s, fmt, *(type *)data); \
Steven Rostedt (Red Hat)d2b01912014-11-12 17:19:51 -050032 return !trace_seq_has_overflowed(s); \
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +053033} \
Masami Hiramatsu17ce3dc2016-08-18 17:57:50 +090034const char PRINT_TYPE_FMT_NAME(tname)[] = fmt; \
35NOKPROBE_SYMBOL(PRINT_TYPE_FUNC_NAME(tname));
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +053036
Masami Hiramatsubdca79c22016-08-18 17:59:21 +090037DEFINE_BASIC_PRINT_TYPE_FUNC(u8, u8, "%u")
38DEFINE_BASIC_PRINT_TYPE_FUNC(u16, u16, "%u")
39DEFINE_BASIC_PRINT_TYPE_FUNC(u32, u32, "%u")
40DEFINE_BASIC_PRINT_TYPE_FUNC(u64, u64, "%Lu")
Masami Hiramatsu17ce3dc2016-08-18 17:57:50 +090041DEFINE_BASIC_PRINT_TYPE_FUNC(s8, s8, "%d")
42DEFINE_BASIC_PRINT_TYPE_FUNC(s16, s16, "%d")
43DEFINE_BASIC_PRINT_TYPE_FUNC(s32, s32, "%d")
44DEFINE_BASIC_PRINT_TYPE_FUNC(s64, s64, "%Ld")
45DEFINE_BASIC_PRINT_TYPE_FUNC(x8, u8, "0x%x")
46DEFINE_BASIC_PRINT_TYPE_FUNC(x16, u16, "0x%x")
47DEFINE_BASIC_PRINT_TYPE_FUNC(x32, u32, "0x%x")
48DEFINE_BASIC_PRINT_TYPE_FUNC(x64, u64, "0x%Lx")
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +053049
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +053050/* Print type function for string type */
Masami Hiramatsu56de7632018-04-25 21:16:36 +090051int PRINT_TYPE_FUNC_NAME(string)(struct trace_seq *s, void *data, void *ent)
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +053052{
53 int len = *(u32 *)data >> 16;
54
55 if (!len)
Masami Hiramatsu56de7632018-04-25 21:16:36 +090056 trace_seq_puts(s, "(fault)");
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +053057 else
Masami Hiramatsu56de7632018-04-25 21:16:36 +090058 trace_seq_printf(s, "\"%s\"",
Steven Rostedt (Red Hat)d2b01912014-11-12 17:19:51 -050059 (const char *)get_loc_data(data, ent));
60 return !trace_seq_has_overflowed(s);
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +053061}
Masami Hiramatsu3da0f182014-04-17 17:18:28 +090062NOKPROBE_SYMBOL(PRINT_TYPE_FUNC_NAME(string));
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +053063
Namhyung Kimb26c74e2013-11-26 14:19:59 +090064const char PRINT_TYPE_FMT_NAME(string)[] = "\\\"%s\\\"";
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +053065
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +053066#define CHECK_FETCH_FUNCS(method, fn) \
67 (((FETCH_FUNC_NAME(method, u8) == fn) || \
68 (FETCH_FUNC_NAME(method, u16) == fn) || \
69 (FETCH_FUNC_NAME(method, u32) == fn) || \
70 (FETCH_FUNC_NAME(method, u64) == fn) || \
71 (FETCH_FUNC_NAME(method, string) == fn) || \
72 (FETCH_FUNC_NAME(method, string_size) == fn)) \
73 && (fn != NULL))
74
75/* Data fetch function templates */
76#define DEFINE_FETCH_reg(type) \
Masami Hiramatsu3da0f182014-04-17 17:18:28 +090077void FETCH_FUNC_NAME(reg, type)(struct pt_regs *regs, void *offset, void *dest) \
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +053078{ \
79 *(type *)dest = (type)regs_get_register(regs, \
80 (unsigned int)((unsigned long)offset)); \
Masami Hiramatsu3da0f182014-04-17 17:18:28 +090081} \
82NOKPROBE_SYMBOL(FETCH_FUNC_NAME(reg, type));
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +053083DEFINE_BASIC_FETCH_FUNCS(reg)
84/* No string on the register */
85#define fetch_reg_string NULL
86#define fetch_reg_string_size NULL
87
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +053088#define DEFINE_FETCH_retval(type) \
Masami Hiramatsu3da0f182014-04-17 17:18:28 +090089void FETCH_FUNC_NAME(retval, type)(struct pt_regs *regs, \
90 void *dummy, void *dest) \
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +053091{ \
92 *(type *)dest = (type)regs_return_value(regs); \
Masami Hiramatsu3da0f182014-04-17 17:18:28 +090093} \
94NOKPROBE_SYMBOL(FETCH_FUNC_NAME(retval, type));
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +053095DEFINE_BASIC_FETCH_FUNCS(retval)
96/* No string on the retval */
97#define fetch_retval_string NULL
98#define fetch_retval_string_size NULL
99
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +0530100/* Dereference memory access function */
101struct deref_fetch_param {
102 struct fetch_param orig;
103 long offset;
Hyeoncheol Lee3925f4a2013-07-01 13:44:32 +0900104 fetch_func_t fetch;
105 fetch_func_t fetch_size;
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +0530106};
107
108#define DEFINE_FETCH_deref(type) \
Masami Hiramatsu3da0f182014-04-17 17:18:28 +0900109void FETCH_FUNC_NAME(deref, type)(struct pt_regs *regs, \
110 void *data, void *dest) \
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +0530111{ \
112 struct deref_fetch_param *dprm = data; \
113 unsigned long addr; \
114 call_fetch(&dprm->orig, regs, &addr); \
115 if (addr) { \
116 addr += dprm->offset; \
Hyeoncheol Lee3925f4a2013-07-01 13:44:32 +0900117 dprm->fetch(regs, (void *)addr, dest); \
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +0530118 } else \
119 *(type *)dest = 0; \
Masami Hiramatsu3da0f182014-04-17 17:18:28 +0900120} \
121NOKPROBE_SYMBOL(FETCH_FUNC_NAME(deref, type));
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +0530122DEFINE_BASIC_FETCH_FUNCS(deref)
123DEFINE_FETCH_deref(string)
Hyeoncheol Lee3925f4a2013-07-01 13:44:32 +0900124
Masami Hiramatsu3da0f182014-04-17 17:18:28 +0900125void FETCH_FUNC_NAME(deref, string_size)(struct pt_regs *regs,
126 void *data, void *dest)
Hyeoncheol Lee3925f4a2013-07-01 13:44:32 +0900127{
128 struct deref_fetch_param *dprm = data;
129 unsigned long addr;
130
131 call_fetch(&dprm->orig, regs, &addr);
132 if (addr && dprm->fetch_size) {
133 addr += dprm->offset;
134 dprm->fetch_size(regs, (void *)addr, dest);
135 } else
136 *(string_size *)dest = 0;
137}
Masami Hiramatsu3da0f182014-04-17 17:18:28 +0900138NOKPROBE_SYMBOL(FETCH_FUNC_NAME(deref, string_size));
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +0530139
Masami Hiramatsu3da0f182014-04-17 17:18:28 +0900140static void update_deref_fetch_param(struct deref_fetch_param *data)
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +0530141{
142 if (CHECK_FETCH_FUNCS(deref, data->orig.fn))
143 update_deref_fetch_param(data->orig.data);
144 else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn))
145 update_symbol_cache(data->orig.data);
146}
Masami Hiramatsu3da0f182014-04-17 17:18:28 +0900147NOKPROBE_SYMBOL(update_deref_fetch_param);
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +0530148
Masami Hiramatsu3da0f182014-04-17 17:18:28 +0900149static void free_deref_fetch_param(struct deref_fetch_param *data)
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +0530150{
151 if (CHECK_FETCH_FUNCS(deref, data->orig.fn))
152 free_deref_fetch_param(data->orig.data);
153 else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn))
154 free_symbol_cache(data->orig.data);
155 kfree(data);
156}
Masami Hiramatsu3da0f182014-04-17 17:18:28 +0900157NOKPROBE_SYMBOL(free_deref_fetch_param);
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +0530158
159/* Bitfield fetch function */
160struct bitfield_fetch_param {
161 struct fetch_param orig;
162 unsigned char hi_shift;
163 unsigned char low_shift;
164};
165
166#define DEFINE_FETCH_bitfield(type) \
Masami Hiramatsu3da0f182014-04-17 17:18:28 +0900167void FETCH_FUNC_NAME(bitfield, type)(struct pt_regs *regs, \
168 void *data, void *dest) \
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +0530169{ \
170 struct bitfield_fetch_param *bprm = data; \
171 type buf = 0; \
172 call_fetch(&bprm->orig, regs, &buf); \
173 if (buf) { \
174 buf <<= bprm->hi_shift; \
175 buf >>= bprm->low_shift; \
176 } \
177 *(type *)dest = buf; \
Masami Hiramatsu3da0f182014-04-17 17:18:28 +0900178} \
179NOKPROBE_SYMBOL(FETCH_FUNC_NAME(bitfield, type));
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +0530180DEFINE_BASIC_FETCH_FUNCS(bitfield)
181#define fetch_bitfield_string NULL
182#define fetch_bitfield_string_size NULL
183
Masami Hiramatsufbc19632014-04-17 17:18:00 +0900184static void
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +0530185update_bitfield_fetch_param(struct bitfield_fetch_param *data)
186{
187 /*
188 * Don't check the bitfield itself, because this must be the
189 * last fetch function.
190 */
191 if (CHECK_FETCH_FUNCS(deref, data->orig.fn))
192 update_deref_fetch_param(data->orig.data);
193 else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn))
194 update_symbol_cache(data->orig.data);
195}
196
Masami Hiramatsufbc19632014-04-17 17:18:00 +0900197static void
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +0530198free_bitfield_fetch_param(struct bitfield_fetch_param *data)
199{
200 /*
201 * Don't check the bitfield itself, because this must be the
202 * last fetch function.
203 */
204 if (CHECK_FETCH_FUNCS(deref, data->orig.fn))
205 free_deref_fetch_param(data->orig.data);
206 else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn))
207 free_symbol_cache(data->orig.data);
208
209 kfree(data);
210}
211
Omar Sandoval35abb672016-06-08 18:38:02 -0700212void FETCH_FUNC_NAME(comm, string)(struct pt_regs *regs,
213 void *data, void *dest)
214{
215 int maxlen = get_rloc_len(*(u32 *)dest);
216 u8 *dst = get_rloc_data(dest);
217 long ret;
218
219 if (!maxlen)
220 return;
221
222 ret = strlcpy(dst, current->comm, maxlen);
223 *(u32 *)dest = make_data_rloc(ret, get_rloc_offs(*(u32 *)dest));
224}
225NOKPROBE_SYMBOL(FETCH_FUNC_NAME(comm, string));
226
227void FETCH_FUNC_NAME(comm, string_size)(struct pt_regs *regs,
228 void *data, void *dest)
229{
230 *(u32 *)dest = strlen(current->comm) + 1;
231}
232NOKPROBE_SYMBOL(FETCH_FUNC_NAME(comm, string_size));
233
Namhyung Kim34fee3a2013-11-26 14:56:28 +0900234static const struct fetch_type *find_fetch_type(const char *type,
235 const struct fetch_type *ftbl)
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +0530236{
237 int i;
238
239 if (!type)
240 type = DEFAULT_FETCH_TYPE_STR;
241
242 /* Special case: bitfield */
243 if (*type == 'b') {
244 unsigned long bs;
245
246 type = strchr(type, '/');
247 if (!type)
248 goto fail;
249
250 type++;
Daniel Walterbcd83ea2012-09-26 22:08:38 +0200251 if (kstrtoul(type, 0, &bs))
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +0530252 goto fail;
253
254 switch (bs) {
255 case 8:
Namhyung Kim34fee3a2013-11-26 14:56:28 +0900256 return find_fetch_type("u8", ftbl);
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +0530257 case 16:
Namhyung Kim34fee3a2013-11-26 14:56:28 +0900258 return find_fetch_type("u16", ftbl);
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +0530259 case 32:
Namhyung Kim34fee3a2013-11-26 14:56:28 +0900260 return find_fetch_type("u32", ftbl);
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +0530261 case 64:
Namhyung Kim34fee3a2013-11-26 14:56:28 +0900262 return find_fetch_type("u64", ftbl);
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +0530263 default:
264 goto fail;
265 }
266 }
267
Namhyung Kim34fee3a2013-11-26 14:56:28 +0900268 for (i = 0; ftbl[i].name; i++) {
269 if (strcmp(type, ftbl[i].name) == 0)
270 return &ftbl[i];
271 }
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +0530272
273fail:
274 return NULL;
275}
276
277/* Special function : only accept unsigned long */
Masami Hiramatsu3da0f182014-04-17 17:18:28 +0900278static void fetch_kernel_stack_address(struct pt_regs *regs, void *dummy, void *dest)
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +0530279{
280 *(unsigned long *)dest = kernel_stack_pointer(regs);
281}
Masami Hiramatsu3da0f182014-04-17 17:18:28 +0900282NOKPROBE_SYMBOL(fetch_kernel_stack_address);
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +0530283
Masami Hiramatsu3da0f182014-04-17 17:18:28 +0900284static void fetch_user_stack_address(struct pt_regs *regs, void *dummy, void *dest)
Namhyung Kimb079d372013-07-03 18:34:23 +0900285{
286 *(unsigned long *)dest = user_stack_pointer(regs);
287}
Masami Hiramatsu3da0f182014-04-17 17:18:28 +0900288NOKPROBE_SYMBOL(fetch_user_stack_address);
Namhyung Kimb079d372013-07-03 18:34:23 +0900289
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +0530290static fetch_func_t get_fetch_size_function(const struct fetch_type *type,
Namhyung Kim34fee3a2013-11-26 14:56:28 +0900291 fetch_func_t orig_fn,
292 const struct fetch_type *ftbl)
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +0530293{
294 int i;
295
Namhyung Kim34fee3a2013-11-26 14:56:28 +0900296 if (type != &ftbl[FETCH_TYPE_STRING])
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +0530297 return NULL; /* Only string type needs size function */
298
299 for (i = 0; i < FETCH_MTD_END; i++)
300 if (type->fetch[i] == orig_fn)
Namhyung Kim34fee3a2013-11-26 14:56:28 +0900301 return ftbl[FETCH_TYPE_STRSIZE].fetch[i];
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +0530302
303 WARN_ON(1); /* This should not happen */
304
305 return NULL;
306}
307
308/* Split symbol and offset. */
Masami Hiramatsuc5d343b2018-03-17 21:38:10 +0900309int traceprobe_split_symbol_offset(char *symbol, long *offset)
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +0530310{
311 char *tmp;
312 int ret;
313
314 if (!offset)
315 return -EINVAL;
316
Masami Hiramatsuc5d343b2018-03-17 21:38:10 +0900317 tmp = strpbrk(symbol, "+-");
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +0530318 if (tmp) {
Masami Hiramatsuc5d343b2018-03-17 21:38:10 +0900319 ret = kstrtol(tmp, 0, offset);
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +0530320 if (ret)
321 return ret;
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +0530322 *tmp = '\0';
323 } else
324 *offset = 0;
325
326 return 0;
327}
328
329#define PARAM_MAX_STACK (THREAD_SIZE / sizeof(unsigned long))
330
331static int parse_probe_vars(char *arg, const struct fetch_type *t,
Namhyung Kimb079d372013-07-03 18:34:23 +0900332 struct fetch_param *f, bool is_return,
333 bool is_kprobe)
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +0530334{
335 int ret = 0;
336 unsigned long param;
337
338 if (strcmp(arg, "retval") == 0) {
339 if (is_return)
340 f->fn = t->fetch[FETCH_MTD_retval];
341 else
342 ret = -EINVAL;
343 } else if (strncmp(arg, "stack", 5) == 0) {
344 if (arg[5] == '\0') {
Namhyung Kimb079d372013-07-03 18:34:23 +0900345 if (strcmp(t->name, DEFAULT_FETCH_TYPE_STR))
346 return -EINVAL;
347
348 if (is_kprobe)
349 f->fn = fetch_kernel_stack_address;
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +0530350 else
Namhyung Kimb079d372013-07-03 18:34:23 +0900351 f->fn = fetch_user_stack_address;
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +0530352 } else if (isdigit(arg[5])) {
Daniel Walterbcd83ea2012-09-26 22:08:38 +0200353 ret = kstrtoul(arg + 5, 10, &param);
Namhyung Kimb079d372013-07-03 18:34:23 +0900354 if (ret || (is_kprobe && param > PARAM_MAX_STACK))
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +0530355 ret = -EINVAL;
356 else {
357 f->fn = t->fetch[FETCH_MTD_stack];
358 f->data = (void *)param;
359 }
360 } else
361 ret = -EINVAL;
Omar Sandoval35abb672016-06-08 18:38:02 -0700362 } else if (strcmp(arg, "comm") == 0) {
363 if (strcmp(t->name, "string") != 0 &&
364 strcmp(t->name, "string_size") != 0)
365 return -EINVAL;
366 f->fn = t->fetch[FETCH_MTD_comm];
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +0530367 } else
368 ret = -EINVAL;
369
370 return ret;
371}
372
373/* Recursive argument parser */
374static int parse_probe_arg(char *arg, const struct fetch_type *t,
Stephen Rothwelld9a16d32015-03-12 16:58:34 +1100375 struct fetch_param *f, bool is_return, bool is_kprobe,
376 const struct fetch_type *ftbl)
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +0530377{
378 unsigned long param;
379 long offset;
380 char *tmp;
Namhyung Kim34fee3a2013-11-26 14:56:28 +0900381 int ret = 0;
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +0530382
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +0530383 switch (arg[0]) {
384 case '$':
Namhyung Kimb079d372013-07-03 18:34:23 +0900385 ret = parse_probe_vars(arg + 1, t, f, is_return, is_kprobe);
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +0530386 break;
387
388 case '%': /* named register */
389 ret = regs_query_register_offset(arg + 1);
390 if (ret >= 0) {
391 f->fn = t->fetch[FETCH_MTD_reg];
392 f->data = (void *)(unsigned long)ret;
393 ret = 0;
394 }
395 break;
396
Namhyung Kimb7e0bf32013-11-25 13:42:47 +0900397 case '@': /* memory, file-offset or symbol */
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +0530398 if (isdigit(arg[1])) {
Daniel Walterbcd83ea2012-09-26 22:08:38 +0200399 ret = kstrtoul(arg + 1, 0, &param);
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +0530400 if (ret)
401 break;
402
403 f->fn = t->fetch[FETCH_MTD_memory];
404 f->data = (void *)param;
Namhyung Kimb7e0bf32013-11-25 13:42:47 +0900405 } else if (arg[1] == '+') {
406 /* kprobes don't support file offsets */
407 if (is_kprobe)
408 return -EINVAL;
409
410 ret = kstrtol(arg + 2, 0, &offset);
411 if (ret)
412 break;
413
414 f->fn = t->fetch[FETCH_MTD_file_offset];
415 f->data = (void *)offset;
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +0530416 } else {
Namhyung Kimb079d372013-07-03 18:34:23 +0900417 /* uprobes don't support symbols */
418 if (!is_kprobe)
419 return -EINVAL;
420
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +0530421 ret = traceprobe_split_symbol_offset(arg + 1, &offset);
422 if (ret)
423 break;
424
425 f->data = alloc_symbol_cache(arg + 1, offset);
426 if (f->data)
427 f->fn = t->fetch[FETCH_MTD_symbol];
428 }
429 break;
430
431 case '+': /* deref memory */
Daniel Walterbcd83ea2012-09-26 22:08:38 +0200432 arg++; /* Skip '+', because kstrtol() rejects it. */
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +0530433 case '-':
434 tmp = strchr(arg, '(');
435 if (!tmp)
436 break;
437
438 *tmp = '\0';
Daniel Walterbcd83ea2012-09-26 22:08:38 +0200439 ret = kstrtol(arg, 0, &offset);
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +0530440
441 if (ret)
442 break;
443
444 arg = tmp + 1;
445 tmp = strrchr(arg, ')');
446
447 if (tmp) {
448 struct deref_fetch_param *dprm;
449 const struct fetch_type *t2;
450
Namhyung Kim34fee3a2013-11-26 14:56:28 +0900451 t2 = find_fetch_type(NULL, ftbl);
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +0530452 *tmp = '\0';
453 dprm = kzalloc(sizeof(struct deref_fetch_param), GFP_KERNEL);
454
455 if (!dprm)
456 return -ENOMEM;
457
458 dprm->offset = offset;
Hyeoncheol Lee3925f4a2013-07-01 13:44:32 +0900459 dprm->fetch = t->fetch[FETCH_MTD_memory];
460 dprm->fetch_size = get_fetch_size_function(t,
461 dprm->fetch, ftbl);
Srikar Dronamrajuf3f096c2012-04-11 16:00:43 +0530462 ret = parse_probe_arg(arg, t2, &dprm->orig, is_return,
Stephen Rothwelld9a16d32015-03-12 16:58:34 +1100463 is_kprobe, ftbl);
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +0530464 if (ret)
465 kfree(dprm);
466 else {
467 f->fn = t->fetch[FETCH_MTD_deref];
468 f->data = (void *)dprm;
469 }
470 }
471 break;
472 }
473 if (!ret && !f->fn) { /* Parsed, but do not find fetch method */
474 pr_info("%s type has no corresponding fetch method.\n", t->name);
475 ret = -EINVAL;
476 }
477
478 return ret;
479}
480
481#define BYTES_TO_BITS(nb) ((BITS_PER_LONG * (nb)) / sizeof(long))
482
483/* Bitfield type needs to be parsed into a fetch function */
484static int __parse_bitfield_probe_arg(const char *bf,
485 const struct fetch_type *t,
486 struct fetch_param *f)
487{
488 struct bitfield_fetch_param *bprm;
489 unsigned long bw, bo;
490 char *tail;
491
492 if (*bf != 'b')
493 return 0;
494
495 bprm = kzalloc(sizeof(*bprm), GFP_KERNEL);
496 if (!bprm)
497 return -ENOMEM;
498
499 bprm->orig = *f;
500 f->fn = t->fetch[FETCH_MTD_bitfield];
501 f->data = (void *)bprm;
502 bw = simple_strtoul(bf + 1, &tail, 0); /* Use simple one */
503
504 if (bw == 0 || *tail != '@')
505 return -EINVAL;
506
507 bf = tail + 1;
508 bo = simple_strtoul(bf, &tail, 0);
509
510 if (tail == bf || *tail != '/')
511 return -EINVAL;
512
513 bprm->hi_shift = BYTES_TO_BITS(t->size) - (bw + bo);
514 bprm->low_shift = bprm->hi_shift + bo;
515
516 return (BYTES_TO_BITS(t->size) < (bw + bo)) ? -EINVAL : 0;
517}
518
519/* String length checking wrapper */
520int traceprobe_parse_probe_arg(char *arg, ssize_t *size,
Stephen Rothwelld9a16d32015-03-12 16:58:34 +1100521 struct probe_arg *parg, bool is_return, bool is_kprobe,
522 const struct fetch_type *ftbl)
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +0530523{
524 const char *t;
525 int ret;
526
527 if (strlen(arg) > MAX_ARGSTR_LEN) {
528 pr_info("Argument is too long.: %s\n", arg);
529 return -ENOSPC;
530 }
531 parg->comm = kstrdup(arg, GFP_KERNEL);
532 if (!parg->comm) {
533 pr_info("Failed to allocate memory for command '%s'.\n", arg);
534 return -ENOMEM;
535 }
536 t = strchr(parg->comm, ':');
537 if (t) {
538 arg[t - parg->comm] = '\0';
539 t++;
540 }
Omar Sandoval35abb672016-06-08 18:38:02 -0700541 /*
542 * The default type of $comm should be "string", and it can't be
543 * dereferenced.
544 */
545 if (!t && strcmp(arg, "$comm") == 0)
546 t = "string";
Namhyung Kim34fee3a2013-11-26 14:56:28 +0900547 parg->type = find_fetch_type(t, ftbl);
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +0530548 if (!parg->type) {
549 pr_info("Unsupported type: %s\n", t);
550 return -EINVAL;
551 }
552 parg->offset = *size;
553 *size += parg->type->size;
Stephen Rothwelld9a16d32015-03-12 16:58:34 +1100554 ret = parse_probe_arg(arg, parg->type, &parg->fetch, is_return,
555 is_kprobe, ftbl);
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +0530556
557 if (ret >= 0 && t != NULL)
558 ret = __parse_bitfield_probe_arg(t, parg->type, &parg->fetch);
559
560 if (ret >= 0) {
561 parg->fetch_size.fn = get_fetch_size_function(parg->type,
Namhyung Kim34fee3a2013-11-26 14:56:28 +0900562 parg->fetch.fn,
563 ftbl);
Srikar Dronamraju8ab83f52012-04-09 14:41:44 +0530564 parg->fetch_size.data = parg->fetch.data;
565 }
566
567 return ret;
568}
569
570/* Return 1 if name is reserved or already used by another argument */
571int traceprobe_conflict_field_name(const char *name,
572 struct probe_arg *args, int narg)
573{
574 int i;
575
576 for (i = 0; i < ARRAY_SIZE(reserved_field_names); i++)
577 if (strcmp(reserved_field_names[i], name) == 0)
578 return 1;
579
580 for (i = 0; i < narg; i++)
581 if (strcmp(args[i].name, name) == 0)
582 return 1;
583
584 return 0;
585}
586
587void traceprobe_update_arg(struct probe_arg *arg)
588{
589 if (CHECK_FETCH_FUNCS(bitfield, arg->fetch.fn))
590 update_bitfield_fetch_param(arg->fetch.data);
591 else if (CHECK_FETCH_FUNCS(deref, arg->fetch.fn))
592 update_deref_fetch_param(arg->fetch.data);
593 else if (CHECK_FETCH_FUNCS(symbol, arg->fetch.fn))
594 update_symbol_cache(arg->fetch.data);
595}
596
597void traceprobe_free_probe_arg(struct probe_arg *arg)
598{
599 if (CHECK_FETCH_FUNCS(bitfield, arg->fetch.fn))
600 free_bitfield_fetch_param(arg->fetch.data);
601 else if (CHECK_FETCH_FUNCS(deref, arg->fetch.fn))
602 free_deref_fetch_param(arg->fetch.data);
603 else if (CHECK_FETCH_FUNCS(symbol, arg->fetch.fn))
604 free_symbol_cache(arg->fetch.data);
605
606 kfree(arg->name);
607 kfree(arg->comm);
608}
609
Namhyung Kim5bf652a2013-07-03 16:09:02 +0900610static int __set_print_fmt(struct trace_probe *tp, char *buf, int len,
611 bool is_return)
612{
613 int i;
614 int pos = 0;
615
616 const char *fmt, *arg;
617
618 if (!is_return) {
619 fmt = "(%lx)";
620 arg = "REC->" FIELD_STRING_IP;
621 } else {
622 fmt = "(%lx <- %lx)";
623 arg = "REC->" FIELD_STRING_FUNC ", REC->" FIELD_STRING_RETIP;
624 }
625
626 /* When len=0, we just calculate the needed length */
627#define LEN_OR_ZERO (len ? len - pos : 0)
628
629 pos += snprintf(buf + pos, LEN_OR_ZERO, "\"%s", fmt);
630
631 for (i = 0; i < tp->nr_args; i++) {
632 pos += snprintf(buf + pos, LEN_OR_ZERO, " %s=%s",
633 tp->args[i].name, tp->args[i].type->fmt);
634 }
635
636 pos += snprintf(buf + pos, LEN_OR_ZERO, "\", %s", arg);
637
638 for (i = 0; i < tp->nr_args; i++) {
639 if (strcmp(tp->args[i].type->name, "string") == 0)
640 pos += snprintf(buf + pos, LEN_OR_ZERO,
641 ", __get_str(%s)",
642 tp->args[i].name);
643 else
644 pos += snprintf(buf + pos, LEN_OR_ZERO, ", REC->%s",
645 tp->args[i].name);
646 }
647
648#undef LEN_OR_ZERO
649
650 /* return the length of print_fmt */
651 return pos;
652}
653
654int set_print_fmt(struct trace_probe *tp, bool is_return)
655{
656 int len;
657 char *print_fmt;
658
659 /* First: called with 0 length to calculate the needed length */
660 len = __set_print_fmt(tp, NULL, 0, is_return);
661 print_fmt = kmalloc(len + 1, GFP_KERNEL);
662 if (!print_fmt)
663 return -ENOMEM;
664
665 /* Second: actually write the @print_fmt */
666 __set_print_fmt(tp, print_fmt, len + 1, is_return);
667 tp->call.print_fmt = print_fmt;
668
669 return 0;
670}
Masami Hiramatsueeb07b02018-04-25 21:17:05 +0900671
672int traceprobe_define_arg_fields(struct trace_event_call *event_call,
673 size_t offset, struct trace_probe *tp)
674{
675 int ret, i;
676
677 /* Set argument names as fields */
678 for (i = 0; i < tp->nr_args; i++) {
679 struct probe_arg *parg = &tp->args[i];
680
681 ret = trace_define_field(event_call, parg->type->fmttype,
682 parg->name,
683 offset + parg->offset,
684 parg->type->size,
685 parg->type->is_signed,
686 FILTER_OTHER);
687 if (ret)
688 return ret;
689 }
690 return 0;
691}