aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMasami Hiramatsu <mhiramat@kernel.org>2018-08-28 12:18:43 -0400
committerSteven Rostedt (VMware) <rostedt@goodmis.org>2018-10-10 22:19:12 -0400
commita6682814f37124ec1e708cca8f44968445fa9dd7 (patch)
tree15e0eb29bad333cb4f69eaec38172680a4393ed7
parent59158ec4aef7d44be51a6f3e7e17fc64c32604eb (diff)
tracing/kprobes: Allow kprobe-events to record module symbol
Allow kprobe-events to record module symbols. Since data symbols in a non-loaded module doesn't exist, it fails to define such symbol as an argument of kprobe-event. But if the kprobe event is defined on that module, we can defer to resolve the symbol address. Note that if given symbol is not found, the event is kept unavailable. User can enable it but the event is not recorded. Link: http://lkml.kernel.org/r/153547312336.26502.11432902826345374463.stgit@devbox Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org> Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
-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);