aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--kernel/trace/trace_kprobe.c12
-rw-r--r--kernel/trace/trace_probe.c62
-rw-r--r--kernel/trace/trace_probe.h4
3 files changed, 68 insertions, 10 deletions
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index 4727a13824f0..fec67188c4d2 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -366,7 +366,7 @@ static bool within_notrace_func(struct trace_kprobe *tk)
366/* Internal register function - just handle k*probes and flags */ 366/* Internal register function - just handle k*probes and flags */
367static int __register_trace_kprobe(struct trace_kprobe *tk) 367static int __register_trace_kprobe(struct trace_kprobe *tk)
368{ 368{
369 int ret; 369 int i, ret;
370 370
371 if (trace_probe_is_registered(&tk->tp)) 371 if (trace_probe_is_registered(&tk->tp))
372 return -EINVAL; 372 return -EINVAL;
@@ -377,6 +377,12 @@ static int __register_trace_kprobe(struct trace_kprobe *tk)
377 return -EINVAL; 377 return -EINVAL;
378 } 378 }
379 379
380 for (i = 0; i < tk->tp.nr_args; i++) {
381 ret = traceprobe_update_arg(&tk->tp.args[i]);
382 if (ret)
383 return ret;
384 }
385
380 /* Set/clear disabled flag according to tp->flag */ 386 /* Set/clear disabled flag according to tp->flag */
381 if (trace_probe_is_enabled(&tk->tp)) 387 if (trace_probe_is_enabled(&tk->tp))
382 tk->rp.kp.flags &= ~KPROBE_FLAG_DISABLED; 388 tk->rp.kp.flags &= ~KPROBE_FLAG_DISABLED;
@@ -928,6 +934,7 @@ process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
928{ 934{
929 unsigned long val; 935 unsigned long val;
930 936
937retry:
931 /* 1st stage: get value from context */ 938 /* 1st stage: get value from context */
932 switch (code->op) { 939 switch (code->op) {
933 case FETCH_OP_REG: 940 case FETCH_OP_REG:
@@ -953,6 +960,9 @@ process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
953 val = regs_get_kernel_argument(regs, code->param); 960 val = regs_get_kernel_argument(regs, code->param);
954 break; 961 break;
955#endif 962#endif
963 case FETCH_NOP_SYMBOL: /* Ignore a place holder */
964 code++;
965 goto retry;
956 default: 966 default:
957 return -EILSEQ; 967 return -EILSEQ;
958 } 968 }
diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
index 333cda6d2633..5b3d573b3dcf 100644
--- a/kernel/trace/trace_probe.c
+++ b/kernel/trace/trace_probe.c
@@ -251,16 +251,16 @@ parse_probe_arg(char *arg, const struct fetch_type *type,
251 if (!(flags & TPARG_FL_KERNEL)) 251 if (!(flags & TPARG_FL_KERNEL))
252 return -EINVAL; 252 return -EINVAL;
253 253
254 ret = traceprobe_split_symbol_offset(arg + 1, &offset); 254 /* Preserve symbol for updating */
255 if (ret) 255 code->op = FETCH_NOP_SYMBOL;
256 break; 256 code->data = kstrdup(arg + 1, GFP_KERNEL);
257 if (!code->data)
258 return -ENOMEM;
259 if (++code == end)
260 return -E2BIG;
257 261
258 code->op = FETCH_OP_IMM; 262 code->op = FETCH_OP_IMM;
259 code->immediate = 263 code->immediate = 0;
260 (unsigned long)kallsyms_lookup_name(arg + 1);
261 if (!code->immediate)
262 return -ENOENT;
263 code->immediate += offset;
264 } 264 }
265 /* These are fetching from memory */ 265 /* These are fetching from memory */
266 if (++code == end) 266 if (++code == end)
@@ -480,6 +480,11 @@ int traceprobe_parse_probe_arg(char *arg, ssize_t *size,
480 memcpy(parg->code, tmp, sizeof(*code) * (code - tmp + 1)); 480 memcpy(parg->code, tmp, sizeof(*code) * (code - tmp + 1));
481 481
482fail: 482fail:
483 if (ret) {
484 for (code = tmp; code < tmp + FETCH_INSN_MAX; code++)
485 if (code->op == FETCH_NOP_SYMBOL)
486 kfree(code->data);
487 }
483 kfree(tmp); 488 kfree(tmp);
484 489
485 return ret; 490 return ret;
@@ -504,12 +509,53 @@ int traceprobe_conflict_field_name(const char *name,
504 509
505void traceprobe_free_probe_arg(struct probe_arg *arg) 510void traceprobe_free_probe_arg(struct probe_arg *arg)
506{ 511{
512 struct fetch_insn *code = arg->code;
513
514 while (code && code->op != FETCH_OP_END) {
515 if (code->op == FETCH_NOP_SYMBOL)
516 kfree(code->data);
517 code++;
518 }
507 kfree(arg->code); 519 kfree(arg->code);
508 kfree(arg->name); 520 kfree(arg->name);
509 kfree(arg->comm); 521 kfree(arg->comm);
510 kfree(arg->fmt); 522 kfree(arg->fmt);
511} 523}
512 524
525int traceprobe_update_arg(struct probe_arg *arg)
526{
527 struct fetch_insn *code = arg->code;
528 long offset;
529 char *tmp;
530 char c;
531 int ret = 0;
532
533 while (code && code->op != FETCH_OP_END) {
534 if (code->op == FETCH_NOP_SYMBOL) {
535 if (code[1].op != FETCH_OP_IMM)
536 return -EINVAL;
537
538 tmp = strpbrk("+-", code->data);
539 if (tmp)
540 c = *tmp;
541 ret = traceprobe_split_symbol_offset(code->data,
542 &offset);
543 if (ret)
544 return ret;
545
546 code[1].immediate =
547 (unsigned long)kallsyms_lookup_name(code->data);
548 if (tmp)
549 *tmp = c;
550 if (!code[1].immediate)
551 return -ENOENT;
552 code[1].immediate += offset;
553 }
554 code++;
555 }
556 return 0;
557}
558
513/* When len=0, we just calculate the needed length */ 559/* When len=0, we just calculate the needed length */
514#define LEN_OR_ZERO (len ? len - pos : 0) 560#define LEN_OR_ZERO (len ? len - pos : 0)
515static int __set_print_fmt(struct trace_probe *tp, char *buf, int len, 561static int __set_print_fmt(struct trace_probe *tp, char *buf, int len,
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
index 09f62171cc23..974afc1a3e73 100644
--- a/kernel/trace/trace_probe.h
+++ b/kernel/trace/trace_probe.h
@@ -100,6 +100,7 @@ enum fetch_op {
100 // Stage 5 (loop) op 100 // Stage 5 (loop) op
101 FETCH_OP_LP_ARRAY, /* Array: .param = loop count */ 101 FETCH_OP_LP_ARRAY, /* Array: .param = loop count */
102 FETCH_OP_END, 102 FETCH_OP_END,
103 FETCH_NOP_SYMBOL, /* Unresolved Symbol holder */
103}; 104};
104 105
105struct fetch_insn { 106struct fetch_insn {
@@ -116,6 +117,7 @@ struct fetch_insn {
116 unsigned char rshift; 117 unsigned char rshift;
117 }; 118 };
118 unsigned long immediate; 119 unsigned long immediate;
120 void *data;
119 }; 121 };
120}; 122};
121 123
@@ -276,7 +278,7 @@ extern int traceprobe_parse_probe_arg(char *arg, ssize_t *size,
276extern int traceprobe_conflict_field_name(const char *name, 278extern int traceprobe_conflict_field_name(const char *name,
277 struct probe_arg *args, int narg); 279 struct probe_arg *args, int narg);
278 280
279extern void traceprobe_update_arg(struct probe_arg *arg); 281extern int traceprobe_update_arg(struct probe_arg *arg);
280extern void traceprobe_free_probe_arg(struct probe_arg *arg); 282extern void traceprobe_free_probe_arg(struct probe_arg *arg);
281 283
282extern int traceprobe_split_symbol_offset(char *symbol, long *offset); 284extern int traceprobe_split_symbol_offset(char *symbol, long *offset);