~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/kernel/trace/trace_probe.c

Version: ~ [ linux-5.12 ] ~ [ linux-5.11.16 ] ~ [ linux-5.10.32 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.114 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.188 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.231 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.267 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.267 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 /*
  3  * Common code for probe-based Dynamic events.
  4  *
  5  * 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  */
 12 #define pr_fmt(fmt)     "trace_probe: " fmt
 13 
 14 #include "trace_probe.h"
 15 
 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[] = {
 22         "common_type",
 23         "common_flags",
 24         "common_preempt_count",
 25         "common_pid",
 26         "common_tgid",
 27         FIELD_STRING_IP,
 28         FIELD_STRING_RETIP,
 29         FIELD_STRING_FUNC,
 30 };
 31 
 32 /* Printing  in basic type function template */
 33 #define DEFINE_BASIC_PRINT_TYPE_FUNC(tname, type, fmt)                  \
 34 int PRINT_TYPE_FUNC_NAME(tname)(struct trace_seq *s, void *data, void *ent)\
 35 {                                                                       \
 36         trace_seq_printf(s, fmt, *(type *)data);                        \
 37         return !trace_seq_has_overflowed(s);                            \
 38 }                                                                       \
 39 const char PRINT_TYPE_FMT_NAME(tname)[] = fmt;
 40 
 41 DEFINE_BASIC_PRINT_TYPE_FUNC(u8,  u8,  "%u")
 42 DEFINE_BASIC_PRINT_TYPE_FUNC(u16, u16, "%u")
 43 DEFINE_BASIC_PRINT_TYPE_FUNC(u32, u32, "%u")
 44 DEFINE_BASIC_PRINT_TYPE_FUNC(u64, u64, "%Lu")
 45 DEFINE_BASIC_PRINT_TYPE_FUNC(s8,  s8,  "%d")
 46 DEFINE_BASIC_PRINT_TYPE_FUNC(s16, s16, "%d")
 47 DEFINE_BASIC_PRINT_TYPE_FUNC(s32, s32, "%d")
 48 DEFINE_BASIC_PRINT_TYPE_FUNC(s64, s64, "%Ld")
 49 DEFINE_BASIC_PRINT_TYPE_FUNC(x8,  u8,  "0x%x")
 50 DEFINE_BASIC_PRINT_TYPE_FUNC(x16, u16, "0x%x")
 51 DEFINE_BASIC_PRINT_TYPE_FUNC(x32, u32, "0x%x")
 52 DEFINE_BASIC_PRINT_TYPE_FUNC(x64, u64, "0x%Lx")
 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 
 61 /* Print type function for string type */
 62 int PRINT_TYPE_FUNC_NAME(string)(struct trace_seq *s, void *data, void *ent)
 63 {
 64         int len = *(u32 *)data >> 16;
 65 
 66         if (!len)
 67                 trace_seq_puts(s, "(fault)");
 68         else
 69                 trace_seq_printf(s, "\"%s\"",
 70                                  (const char *)get_loc_data(data, ent));
 71         return !trace_seq_has_overflowed(s);
 72 }
 73 
 74 const char PRINT_TYPE_FMT_NAME(string)[] = "\\\"%s\\\"";
 75 
 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         /* Basic types */
 82         ASSIGN_FETCH_TYPE(u8,  u8,  0),
 83         ASSIGN_FETCH_TYPE(u16, u16, 0),
 84         ASSIGN_FETCH_TYPE(u32, u32, 0),
 85         ASSIGN_FETCH_TYPE(u64, u64, 0),
 86         ASSIGN_FETCH_TYPE(s8,  u8,  1),
 87         ASSIGN_FETCH_TYPE(s16, u16, 1),
 88         ASSIGN_FETCH_TYPE(s32, u32, 1),
 89         ASSIGN_FETCH_TYPE(s64, u64, 1),
 90         ASSIGN_FETCH_TYPE_ALIAS(x8,  u8,  u8,  0),
 91         ASSIGN_FETCH_TYPE_ALIAS(x16, u16, u16, 0),
 92         ASSIGN_FETCH_TYPE_ALIAS(x32, u32, u32, 0),
 93         ASSIGN_FETCH_TYPE_ALIAS(x64, u64, u64, 0),
 94         ASSIGN_FETCH_TYPE_ALIAS(symbol, ADDR_FETCH_TYPE, ADDR_FETCH_TYPE, 0),
 95 
 96         ASSIGN_FETCH_TYPE_END
 97 };
 98 
 99 static const struct fetch_type *find_fetch_type(const char *type)
100 {
101         int i;
102 
103         if (!type)
104                 type = DEFAULT_FETCH_TYPE_STR;
105 
106         /* Special case: bitfield */
107         if (*type == 'b') {
108                 unsigned long bs;
109 
110                 type = strchr(type, '/');
111                 if (!type)
112                         goto fail;
113 
114                 type++;
115                 if (kstrtoul(type, 0, &bs))
116                         goto fail;
117 
118                 switch (bs) {
119                 case 8:
120                         return find_fetch_type("u8");
121                 case 16:
122                         return find_fetch_type("u16");
123                 case 32:
124                         return find_fetch_type("u32");
125                 case 64:
126                         return find_fetch_type("u64");
127                 default:
128                         goto fail;
129                 }
130         }
131 
132         for (i = 0; probe_fetch_types[i].name; i++) {
133                 if (strcmp(type, probe_fetch_types[i].name) == 0)
134                         return &probe_fetch_types[i];
135         }
136 
137 fail:
138         return NULL;
139 }
140 
141 static struct trace_probe_log trace_probe_log;
142 
143 void trace_probe_log_init(const char *subsystem, int argc, const char **argv)
144 {
145         trace_probe_log.subsystem = subsystem;
146         trace_probe_log.argc = argc;
147         trace_probe_log.argv = argv;
148         trace_probe_log.index = 0;
149 }
150 
151 void trace_probe_log_clear(void)
152 {
153         memset(&trace_probe_log, 0, sizeof(trace_probe_log));
154 }
155 
156 void trace_probe_log_set_index(int index)
157 {
158         trace_probe_log.index = index;
159 }
160 
161 void __trace_probe_log_err(int offset, int err_type)
162 {
163         char *command, *p;
164         int i, len = 0, pos = 0;
165 
166         if (!trace_probe_log.argv)
167                 return;
168 
169         /* Recalcurate the length and allocate buffer */
170         for (i = 0; i < trace_probe_log.argc; i++) {
171                 if (i == trace_probe_log.index)
172                         pos = len;
173                 len += strlen(trace_probe_log.argv[i]) + 1;
174         }
175         command = kzalloc(len, GFP_KERNEL);
176         if (!command)
177                 return;
178 
179         /* And make a command string from argv array */
180         p = command;
181         for (i = 0; i < trace_probe_log.argc; i++) {
182                 len = strlen(trace_probe_log.argv[i]);
183                 strcpy(p, trace_probe_log.argv[i]);
184                 p[len] = ' ';
185                 p += len + 1;
186         }
187         *(p - 1) = '\0';
188 
189         tracing_log_err(NULL, trace_probe_log.subsystem, command,
190                         trace_probe_err_text, err_type, pos + offset);
191 
192         kfree(command);
193 }
194 
195 /* Split symbol and offset. */
196 int traceprobe_split_symbol_offset(char *symbol, long *offset)
197 {
198         char *tmp;
199         int ret;
200 
201         if (!offset)
202                 return -EINVAL;
203 
204         tmp = strpbrk(symbol, "+-");
205         if (tmp) {
206                 ret = kstrtol(tmp, 0, offset);
207                 if (ret)
208                         return ret;
209                 *tmp = '\0';
210         } else
211                 *offset = 0;
212 
213         return 0;
214 }
215 
216 /* @buf must has MAX_EVENT_NAME_LEN size */
217 int traceprobe_parse_event_name(const char **pevent, const char **pgroup,
218                                 char *buf, int offset)
219 {
220         const char *slash, *event = *pevent;
221         int len;
222 
223         slash = strchr(event, '/');
224         if (slash) {
225                 if (slash == event) {
226                         trace_probe_log_err(offset, NO_GROUP_NAME);
227                         return -EINVAL;
228                 }
229                 if (slash - event + 1 > MAX_EVENT_NAME_LEN) {
230                         trace_probe_log_err(offset, GROUP_TOO_LONG);
231                         return -EINVAL;
232                 }
233                 strlcpy(buf, event, slash - event + 1);
234                 if (!is_good_name(buf)) {
235                         trace_probe_log_err(offset, BAD_GROUP_NAME);
236                         return -EINVAL;
237                 }
238                 *pgroup = buf;
239                 *pevent = slash + 1;
240                 offset += slash - event + 1;
241                 event = *pevent;
242         }
243         len = strlen(event);
244         if (len == 0) {
245                 trace_probe_log_err(offset, NO_EVENT_NAME);
246                 return -EINVAL;
247         } else if (len > MAX_EVENT_NAME_LEN) {
248                 trace_probe_log_err(offset, EVENT_TOO_LONG);
249                 return -EINVAL;
250         }
251         if (!is_good_name(event)) {
252                 trace_probe_log_err(offset, BAD_EVENT_NAME);
253                 return -EINVAL;
254         }
255         return 0;
256 }
257 
258 #define PARAM_MAX_STACK (THREAD_SIZE / sizeof(unsigned long))
259 
260 static int parse_probe_vars(char *arg, const struct fetch_type *t,
261                         struct fetch_insn *code, unsigned int flags, int offs)
262 {
263         unsigned long param;
264         int ret = 0;
265         int len;
266 
267         if (strcmp(arg, "retval") == 0) {
268                 if (flags & TPARG_FL_RETURN) {
269                         code->op = FETCH_OP_RETVAL;
270                 } else {
271                         trace_probe_log_err(offs, RETVAL_ON_PROBE);
272                         ret = -EINVAL;
273                 }
274         } else if ((len = str_has_prefix(arg, "stack"))) {
275                 if (arg[len] == '\0') {
276                         code->op = FETCH_OP_STACKP;
277                 } else if (isdigit(arg[len])) {
278                         ret = kstrtoul(arg + len, 10, &param);
279                         if (ret) {
280                                 goto inval_var;
281                         } else if ((flags & TPARG_FL_KERNEL) &&
282                                     param > PARAM_MAX_STACK) {
283                                 trace_probe_log_err(offs, BAD_STACK_NUM);
284                                 ret = -EINVAL;
285                         } else {
286                                 code->op = FETCH_OP_STACK;
287                                 code->param = (unsigned int)param;
288                         }
289                 } else
290                         goto inval_var;
291         } else if (strcmp(arg, "comm") == 0) {
292                 code->op = FETCH_OP_COMM;
293 #ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API
294         } else if (((flags & TPARG_FL_MASK) ==
295                     (TPARG_FL_KERNEL | TPARG_FL_FENTRY)) &&
296                    (len = str_has_prefix(arg, "arg"))) {
297                 ret = kstrtoul(arg + len, 10, &param);
298                 if (ret) {
299                         goto inval_var;
300                 } else if (!param || param > PARAM_MAX_STACK) {
301                         trace_probe_log_err(offs, BAD_ARG_NUM);
302                         return -EINVAL;
303                 }
304                 code->op = FETCH_OP_ARG;
305                 code->param = (unsigned int)param - 1;
306 #endif
307         } else
308                 goto inval_var;
309 
310         return ret;
311 
312 inval_var:
313         trace_probe_log_err(offs, BAD_VAR);
314         return -EINVAL;
315 }
316 
317 /* Recursive argument parser */
318 static int
319 parse_probe_arg(char *arg, const struct fetch_type *type,
320                 struct fetch_insn **pcode, struct fetch_insn *end,
321                 unsigned int flags, int offs)
322 {
323         struct fetch_insn *code = *pcode;
324         unsigned long param;
325         long offset = 0;
326         char *tmp;
327         int ret = 0;
328 
329         switch (arg[0]) {
330         case '$':
331                 ret = parse_probe_vars(arg + 1, type, code, flags, offs);
332                 break;
333 
334         case '%':       /* named register */
335                 ret = regs_query_register_offset(arg + 1);
336                 if (ret >= 0) {
337                         code->op = FETCH_OP_REG;
338                         code->param = (unsigned int)ret;
339                         ret = 0;
340                 } else
341                         trace_probe_log_err(offs, BAD_REG_NAME);
342                 break;
343 
344         case '@':       /* memory, file-offset or symbol */
345                 if (isdigit(arg[1])) {
346                         ret = kstrtoul(arg + 1, 0, &param);
347                         if (ret) {
348                                 trace_probe_log_err(offs, BAD_MEM_ADDR);
349                                 break;
350                         }
351                         /* load address */
352                         code->op = FETCH_OP_IMM;
353                         code->immediate = param;
354                 } else if (arg[1] == '+') {
355                         /* kprobes don't support file offsets */
356                         if (flags & TPARG_FL_KERNEL) {
357                                 trace_probe_log_err(offs, FILE_ON_KPROBE);
358                                 return -EINVAL;
359                         }
360                         ret = kstrtol(arg + 2, 0, &offset);
361                         if (ret) {
362                                 trace_probe_log_err(offs, BAD_FILE_OFFS);
363                                 break;
364                         }
365 
366                         code->op = FETCH_OP_FOFFS;
367                         code->immediate = (unsigned long)offset;  // imm64?
368                 } else {
369                         /* uprobes don't support symbols */
370                         if (!(flags & TPARG_FL_KERNEL)) {
371                                 trace_probe_log_err(offs, SYM_ON_UPROBE);
372                                 return -EINVAL;
373                         }
374                         /* Preserve symbol for updating */
375                         code->op = FETCH_NOP_SYMBOL;
376                         code->data = kstrdup(arg + 1, GFP_KERNEL);
377                         if (!code->data)
378                                 return -ENOMEM;
379                         if (++code == end) {
380                                 trace_probe_log_err(offs, TOO_MANY_OPS);
381                                 return -EINVAL;
382                         }
383                         code->op = FETCH_OP_IMM;
384                         code->immediate = 0;
385                 }
386                 /* These are fetching from memory */
387                 if (++code == end) {
388                         trace_probe_log_err(offs, TOO_MANY_OPS);
389                         return -EINVAL;
390                 }
391                 *pcode = code;
392                 code->op = FETCH_OP_DEREF;
393                 code->offset = offset;
394                 break;
395 
396         case '+':       /* deref memory */
397                 arg++;  /* Skip '+', because kstrtol() rejects it. */
398                 /* fall through */
399         case '-':
400                 tmp = strchr(arg, '(');
401                 if (!tmp) {
402                         trace_probe_log_err(offs, DEREF_NEED_BRACE);
403                         return -EINVAL;
404                 }
405                 *tmp = '\0';
406                 ret = kstrtol(arg, 0, &offset);
407                 if (ret) {
408                         trace_probe_log_err(offs, BAD_DEREF_OFFS);
409                         break;
410                 }
411                 offs += (tmp + 1 - arg) + (arg[0] != '-' ? 1 : 0);
412                 arg = tmp + 1;
413                 tmp = strrchr(arg, ')');
414                 if (!tmp) {
415                         trace_probe_log_err(offs + strlen(arg),
416                                             DEREF_OPEN_BRACE);
417                         return -EINVAL;
418                 } else {
419                         const struct fetch_type *t2 = find_fetch_type(NULL);
420 
421                         *tmp = '\0';
422                         ret = parse_probe_arg(arg, t2, &code, end, flags, offs);
423                         if (ret)
424                                 break;
425                         if (code->op == FETCH_OP_COMM) {
426                                 trace_probe_log_err(offs, COMM_CANT_DEREF);
427                                 return -EINVAL;
428                         }
429                         if (++code == end) {
430                                 trace_probe_log_err(offs, TOO_MANY_OPS);
431                                 return -EINVAL;
432                         }
433                         *pcode = code;
434 
435                         code->op = FETCH_OP_DEREF;
436                         code->offset = offset;
437                 }
438                 break;
439         }
440         if (!ret && code->op == FETCH_OP_NOP) {
441                 /* Parsed, but do not find fetch method */
442                 trace_probe_log_err(offs, BAD_FETCH_ARG);
443                 ret = -EINVAL;
444         }
445         return ret;
446 }
447 
448 #define BYTES_TO_BITS(nb)       ((BITS_PER_LONG * (nb)) / sizeof(long))
449 
450 /* Bitfield type needs to be parsed into a fetch function */
451 static int __parse_bitfield_probe_arg(const char *bf,
452                                       const struct fetch_type *t,
453                                       struct fetch_insn **pcode)
454 {
455         struct fetch_insn *code = *pcode;
456         unsigned long bw, bo;
457         char *tail;
458 
459         if (*bf != 'b')
460                 return 0;
461 
462         bw = simple_strtoul(bf + 1, &tail, 0);  /* Use simple one */
463 
464         if (bw == 0 || *tail != '@')
465                 return -EINVAL;
466 
467         bf = tail + 1;
468         bo = simple_strtoul(bf, &tail, 0);
469 
470         if (tail == bf || *tail != '/')
471                 return -EINVAL;
472         code++;
473         if (code->op != FETCH_OP_NOP)
474                 return -EINVAL;
475         *pcode = code;
476 
477         code->op = FETCH_OP_MOD_BF;
478         code->lshift = BYTES_TO_BITS(t->size) - (bw + bo);
479         code->rshift = BYTES_TO_BITS(t->size) - bw;
480         code->basesize = t->size;
481 
482         return (BYTES_TO_BITS(t->size) < (bw + bo)) ? -EINVAL : 0;
483 }
484 
485 /* String length checking wrapper */
486 static int traceprobe_parse_probe_arg_body(char *arg, ssize_t *size,
487                 struct probe_arg *parg, unsigned int flags, int offset)
488 {
489         struct fetch_insn *code, *scode, *tmp = NULL;
490         char *t, *t2, *t3;
491         int ret, len;
492 
493         len = strlen(arg);
494         if (len > MAX_ARGSTR_LEN) {
495                 trace_probe_log_err(offset, ARG_TOO_LONG);
496                 return -EINVAL;
497         } else if (len == 0) {
498                 trace_probe_log_err(offset, NO_ARG_BODY);
499                 return -EINVAL;
500         }
501 
502         parg->comm = kstrdup(arg, GFP_KERNEL);
503         if (!parg->comm)
504                 return -ENOMEM;
505 
506         t = strchr(arg, ':');
507         if (t) {
508                 *t = '\0';
509                 t2 = strchr(++t, '[');
510                 if (t2) {
511                         *t2++ = '\0';
512                         t3 = strchr(t2, ']');
513                         if (!t3) {
514                                 offset += t2 + strlen(t2) - arg;
515                                 trace_probe_log_err(offset,
516                                                     ARRAY_NO_CLOSE);
517                                 return -EINVAL;
518                         } else if (t3[1] != '\0') {
519                                 trace_probe_log_err(offset + t3 + 1 - arg,
520                                                     BAD_ARRAY_SUFFIX);
521                                 return -EINVAL;
522                         }
523                         *t3 = '\0';
524                         if (kstrtouint(t2, 0, &parg->count) || !parg->count) {
525                                 trace_probe_log_err(offset + t2 - arg,
526                                                     BAD_ARRAY_NUM);
527                                 return -EINVAL;
528                         }
529                         if (parg->count > MAX_ARRAY_LEN) {
530                                 trace_probe_log_err(offset + t2 - arg,
531                                                     ARRAY_TOO_BIG);
532                                 return -EINVAL;
533                         }
534                 }
535         }
536 
537         /* Since $comm can not be dereferred, we can find $comm by strcmp */
538         if (strcmp(arg, "$comm") == 0) {
539                 /* The type of $comm must be "string", and not an array. */
540                 if (parg->count || (t && strcmp(t, "string")))
541                         return -EINVAL;
542                 parg->type = find_fetch_type("string");
543         } else
544                 parg->type = find_fetch_type(t);
545         if (!parg->type) {
546                 trace_probe_log_err(offset + (t ? (t - arg) : 0), BAD_TYPE);
547                 return -EINVAL;
548         }
549         parg->offset = *size;
550         *size += parg->type->size * (parg->count ?: 1);
551 
552         if (parg->count) {
553                 len = strlen(parg->type->fmttype) + 6;
554                 parg->fmt = kmalloc(len, GFP_KERNEL);
555                 if (!parg->fmt)
556                         return -ENOMEM;
557                 snprintf(parg->fmt, len, "%s[%d]", parg->type->fmttype,
558                          parg->count);
559         }
560 
561         code = tmp = kcalloc(FETCH_INSN_MAX, sizeof(*code), GFP_KERNEL);
562         if (!code)
563                 return -ENOMEM;
564         code[FETCH_INSN_MAX - 1].op = FETCH_OP_END;
565 
566         ret = parse_probe_arg(arg, parg->type, &code, &code[FETCH_INSN_MAX - 1],
567                               flags, offset);
568         if (ret)
569                 goto fail;
570 
571         /* Store operation */
572         if (!strcmp(parg->type->name, "string")) {
573                 if (code->op != FETCH_OP_DEREF && code->op != FETCH_OP_IMM &&
574                     code->op != FETCH_OP_COMM) {
575                         trace_probe_log_err(offset + (t ? (t - arg) : 0),
576                                             BAD_STRING);
577                         ret = -EINVAL;
578                         goto fail;
579                 }
580                 if (code->op != FETCH_OP_DEREF || parg->count) {
581                         /*
582                          * IMM and COMM is pointing actual address, those must
583                          * be kept, and if parg->count != 0, this is an array
584                          * of string pointers instead of string address itself.
585                          */
586                         code++;
587                         if (code->op != FETCH_OP_NOP) {
588                                 trace_probe_log_err(offset, TOO_MANY_OPS);
589                                 ret = -EINVAL;
590                                 goto fail;
591                         }
592                 }
593                 code->op = FETCH_OP_ST_STRING;  /* In DEREF case, replace it */
594                 code->size = parg->type->size;
595                 parg->dynamic = true;
596         } else if (code->op == FETCH_OP_DEREF) {
597                 code->op = FETCH_OP_ST_MEM;
598                 code->size = parg->type->size;
599         } else {
600                 code++;
601                 if (code->op != FETCH_OP_NOP) {
602                         trace_probe_log_err(offset, TOO_MANY_OPS);
603                         ret = -EINVAL;
604                         goto fail;
605                 }
606                 code->op = FETCH_OP_ST_RAW;
607                 code->size = parg->type->size;
608         }
609         scode = code;
610         /* Modify operation */
611         if (t != NULL) {
612                 ret = __parse_bitfield_probe_arg(t, parg->type, &code);
613                 if (ret) {
614                         trace_probe_log_err(offset + t - arg, BAD_BITFIELD);
615                         goto fail;
616                 }
617         }
618         /* Loop(Array) operation */
619         if (parg->count) {
620                 if (scode->op != FETCH_OP_ST_MEM &&
621                     scode->op != FETCH_OP_ST_STRING) {
622                         trace_probe_log_err(offset + (t ? (t - arg) : 0),
623                                             BAD_STRING);
624                         ret = -EINVAL;
625                         goto fail;
626                 }
627                 code++;
628                 if (code->op != FETCH_OP_NOP) {
629                         trace_probe_log_err(offset, TOO_MANY_OPS);
630                         ret = -EINVAL;
631                         goto fail;
632                 }
633                 code->op = FETCH_OP_LP_ARRAY;
634                 code->param = parg->count;
635         }
636         code++;
637         code->op = FETCH_OP_END;
638 
639         /* Shrink down the code buffer */
640         parg->code = kcalloc(code - tmp + 1, sizeof(*code), GFP_KERNEL);
641         if (!parg->code)
642                 ret = -ENOMEM;
643         else
644                 memcpy(parg->code, tmp, sizeof(*code) * (code - tmp + 1));
645 
646 fail:
647         if (ret) {
648                 for (code = tmp; code < tmp + FETCH_INSN_MAX; code++)
649                         if (code->op == FETCH_NOP_SYMBOL)
650                                 kfree(code->data);
651         }
652         kfree(tmp);
653 
654         return ret;
655 }
656 
657 /* Return 1 if name is reserved or already used by another argument */
658 static int traceprobe_conflict_field_name(const char *name,
659                                           struct probe_arg *args, int narg)
660 {
661         int i;
662 
663         for (i = 0; i < ARRAY_SIZE(reserved_field_names); i++)
664                 if (strcmp(reserved_field_names[i], name) == 0)
665                         return 1;
666 
667         for (i = 0; i < narg; i++)
668                 if (strcmp(args[i].name, name) == 0)
669                         return 1;
670 
671         return 0;
672 }
673 
674 int traceprobe_parse_probe_arg(struct trace_probe *tp, int i, char *arg,
675                                 unsigned int flags)
676 {
677         struct probe_arg *parg = &tp->args[i];
678         char *body;
679 
680         /* Increment count for freeing args in error case */
681         tp->nr_args++;
682 
683         body = strchr(arg, '=');
684         if (body) {
685                 if (body - arg > MAX_ARG_NAME_LEN) {
686                         trace_probe_log_err(0, ARG_NAME_TOO_LONG);
687                         return -EINVAL;
688                 } else if (body == arg) {
689                         trace_probe_log_err(0, NO_ARG_NAME);
690                         return -EINVAL;
691                 }
692                 parg->name = kmemdup_nul(arg, body - arg, GFP_KERNEL);
693                 body++;
694         } else {
695                 /* If argument name is omitted, set "argN" */
696                 parg->name = kasprintf(GFP_KERNEL, "arg%d", i + 1);
697                 body = arg;
698         }
699         if (!parg->name)
700                 return -ENOMEM;
701 
702         if (!is_good_name(parg->name)) {
703                 trace_probe_log_err(0, BAD_ARG_NAME);
704                 return -EINVAL;
705         }
706         if (traceprobe_conflict_field_name(parg->name, tp->args, i)) {
707                 trace_probe_log_err(0, USED_ARG_NAME);
708                 return -EINVAL;
709         }
710         /* Parse fetch argument */
711         return traceprobe_parse_probe_arg_body(body, &tp->size, parg, flags,
712                                                body - arg);
713 }
714 
715 void traceprobe_free_probe_arg(struct probe_arg *arg)
716 {
717         struct fetch_insn *code = arg->code;
718 
719         while (code && code->op != FETCH_OP_END) {
720                 if (code->op == FETCH_NOP_SYMBOL)
721                         kfree(code->data);
722                 code++;
723         }
724         kfree(arg->code);
725         kfree(arg->name);
726         kfree(arg->comm);
727         kfree(arg->fmt);
728 }
729 
730 int traceprobe_update_arg(struct probe_arg *arg)
731 {
732         struct fetch_insn *code = arg->code;
733         long offset;
734         char *tmp;
735         char c;
736         int ret = 0;
737 
738         while (code && code->op != FETCH_OP_END) {
739                 if (code->op == FETCH_NOP_SYMBOL) {
740                         if (code[1].op != FETCH_OP_IMM)
741                                 return -EINVAL;
742 
743                         tmp = strpbrk(code->data, "+-");
744                         if (tmp)
745                                 c = *tmp;
746                         ret = traceprobe_split_symbol_offset(code->data,
747                                                              &offset);
748                         if (ret)
749                                 return ret;
750 
751                         code[1].immediate =
752                                 (unsigned long)kallsyms_lookup_name(code->data);
753                         if (tmp)
754                                 *tmp = c;
755                         if (!code[1].immediate)
756                                 return -ENOENT;
757                         code[1].immediate += offset;
758                 }
759                 code++;
760         }
761         return 0;
762 }
763 
764 /* When len=0, we just calculate the needed length */
765 #define LEN_OR_ZERO (len ? len - pos : 0)
766 static int __set_print_fmt(struct trace_probe *tp, char *buf, int len,
767                            bool is_return)
768 {
769         struct probe_arg *parg;
770         int i, j;
771         int pos = 0;
772         const char *fmt, *arg;
773 
774         if (!is_return) {
775                 fmt = "(%lx)";
776                 arg = "REC->" FIELD_STRING_IP;
777         } else {
778                 fmt = "(%lx <- %lx)";
779                 arg = "REC->" FIELD_STRING_FUNC ", REC->" FIELD_STRING_RETIP;
780         }
781 
782         pos += snprintf(buf + pos, LEN_OR_ZERO, "\"%s", fmt);
783 
784         for (i = 0; i < tp->nr_args; i++) {
785                 parg = tp->args + i;
786                 pos += snprintf(buf + pos, LEN_OR_ZERO, " %s=", parg->name);
787                 if (parg->count) {
788                         pos += snprintf(buf + pos, LEN_OR_ZERO, "{%s",
789                                         parg->type->fmt);
790                         for (j = 1; j < parg->count; j++)
791                                 pos += snprintf(buf + pos, LEN_OR_ZERO, ",%s",
792                                                 parg->type->fmt);
793                         pos += snprintf(buf + pos, LEN_OR_ZERO, "}");
794                 } else
795                         pos += snprintf(buf + pos, LEN_OR_ZERO, "%s",
796                                         parg->type->fmt);
797         }
798 
799         pos += snprintf(buf + pos, LEN_OR_ZERO, "\", %s", arg);
800 
801         for (i = 0; i < tp->nr_args; i++) {
802                 parg = tp->args + i;
803                 if (parg->count) {
804                         if (strcmp(parg->type->name, "string") == 0)
805                                 fmt = ", __get_str(%s[%d])";
806                         else
807                                 fmt = ", REC->%s[%d]";
808                         for (j = 0; j < parg->count; j++)
809                                 pos += snprintf(buf + pos, LEN_OR_ZERO,
810                                                 fmt, parg->name, j);
811                 } else {
812                         if (strcmp(parg->type->name, "string") == 0)
813                                 fmt = ", __get_str(%s)";
814                         else
815                                 fmt = ", REC->%s";
816                         pos += snprintf(buf + pos, LEN_OR_ZERO,
817                                         fmt, parg->name);
818                 }
819         }
820 
821         /* return the length of print_fmt */
822         return pos;
823 }
824 #undef LEN_OR_ZERO
825 
826 int traceprobe_set_print_fmt(struct trace_probe *tp, bool is_return)
827 {
828         int len;
829         char *print_fmt;
830 
831         /* First: called with 0 length to calculate the needed length */
832         len = __set_print_fmt(tp, NULL, 0, is_return);
833         print_fmt = kmalloc(len + 1, GFP_KERNEL);
834         if (!print_fmt)
835                 return -ENOMEM;
836 
837         /* Second: actually write the @print_fmt */
838         __set_print_fmt(tp, print_fmt, len + 1, is_return);
839         tp->call.print_fmt = print_fmt;
840 
841         return 0;
842 }
843 
844 int traceprobe_define_arg_fields(struct trace_event_call *event_call,
845                                  size_t offset, struct trace_probe *tp)
846 {
847         int ret, i;
848 
849         /* Set argument names as fields */
850         for (i = 0; i < tp->nr_args; i++) {
851                 struct probe_arg *parg = &tp->args[i];
852                 const char *fmt = parg->type->fmttype;
853                 int size = parg->type->size;
854 
855                 if (parg->fmt)
856                         fmt = parg->fmt;
857                 if (parg->count)
858                         size *= parg->count;
859                 ret = trace_define_field(event_call, fmt, parg->name,
860                                          offset + parg->offset, size,
861                                          parg->type->is_signed,
862                                          FILTER_OTHER);
863                 if (ret)
864                         return ret;
865         }
866         return 0;
867 }
868 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp