diff options
author | Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> | 2011-02-04 07:52:05 -0500 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2011-02-07 06:18:11 -0500 |
commit | 1ff511e35ed87cc2ebade9e678e4a2fe39b6f9c5 (patch) | |
tree | b16cff475673db75aef773cc1118734a2172066a /kernel/trace/trace_kprobe.c | |
parent | e3745369986ddcdaa19f70e2d24e658876b97e84 (diff) |
tracing/kprobes: Add bitfield type
Add bitfield type for tracing arguments on kprobe-tracer. The syntax of
a bitfield type is:
b<bit-size>@<bit-offset>/<container-size>
e.g.
Accessing 2 bits-width field with 4 bits-offset in 32 bits-width data at
4 bytes offseted from the address pointed by AX register:
+4(%ax):b2@4/32
Since the width of container data depends on the arch, so I just added
the container-size at the end.
Cc: 2nddept-manager@sdl.hitachi.co.jp
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
LKML-Reference: <20110204125205.9507.11363.stgit@ltc236.sdl.hitachi.co.jp>
Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'kernel/trace/trace_kprobe.c')
-rw-r--r-- | kernel/trace/trace_kprobe.c | 104 |
1 files changed, 103 insertions, 1 deletions
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index c6ed88660856..ccdc542022c3 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c | |||
@@ -353,6 +353,43 @@ static __kprobes void free_deref_fetch_param(struct deref_fetch_param *data) | |||
353 | kfree(data); | 353 | kfree(data); |
354 | } | 354 | } |
355 | 355 | ||
356 | /* Bitfield fetch function */ | ||
357 | struct bitfield_fetch_param { | ||
358 | struct fetch_param orig; | ||
359 | unsigned char hi_shift; | ||
360 | unsigned char low_shift; | ||
361 | }; | ||
362 | |||
363 | #define DEFINE_FETCH_bitfield(type) \ | ||
364 | static __kprobes void FETCH_FUNC_NAME(bitfield, type)(struct pt_regs *regs,\ | ||
365 | void *data, void *dest) \ | ||
366 | { \ | ||
367 | struct bitfield_fetch_param *bprm = data; \ | ||
368 | type buf = 0; \ | ||
369 | call_fetch(&bprm->orig, regs, &buf); \ | ||
370 | if (buf) { \ | ||
371 | buf <<= bprm->hi_shift; \ | ||
372 | buf >>= bprm->low_shift; \ | ||
373 | } \ | ||
374 | *(type *)dest = buf; \ | ||
375 | } | ||
376 | DEFINE_BASIC_FETCH_FUNCS(bitfield) | ||
377 | #define fetch_bitfield_string NULL | ||
378 | #define fetch_bitfield_string_size NULL | ||
379 | |||
380 | static __kprobes void | ||
381 | free_bitfield_fetch_param(struct bitfield_fetch_param *data) | ||
382 | { | ||
383 | /* | ||
384 | * Don't check the bitfield itself, because this must be the | ||
385 | * last fetch function. | ||
386 | */ | ||
387 | if (CHECK_FETCH_FUNCS(deref, data->orig.fn)) | ||
388 | free_deref_fetch_param(data->orig.data); | ||
389 | else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn)) | ||
390 | free_symbol_cache(data->orig.data); | ||
391 | kfree(data); | ||
392 | } | ||
356 | /* Default (unsigned long) fetch type */ | 393 | /* Default (unsigned long) fetch type */ |
357 | #define __DEFAULT_FETCH_TYPE(t) u##t | 394 | #define __DEFAULT_FETCH_TYPE(t) u##t |
358 | #define _DEFAULT_FETCH_TYPE(t) __DEFAULT_FETCH_TYPE(t) | 395 | #define _DEFAULT_FETCH_TYPE(t) __DEFAULT_FETCH_TYPE(t) |
@@ -367,6 +404,7 @@ enum { | |||
367 | FETCH_MTD_memory, | 404 | FETCH_MTD_memory, |
368 | FETCH_MTD_symbol, | 405 | FETCH_MTD_symbol, |
369 | FETCH_MTD_deref, | 406 | FETCH_MTD_deref, |
407 | FETCH_MTD_bitfield, | ||
370 | FETCH_MTD_END, | 408 | FETCH_MTD_END, |
371 | }; | 409 | }; |
372 | 410 | ||
@@ -387,6 +425,7 @@ ASSIGN_FETCH_FUNC(retval, ftype), \ | |||
387 | ASSIGN_FETCH_FUNC(memory, ftype), \ | 425 | ASSIGN_FETCH_FUNC(memory, ftype), \ |
388 | ASSIGN_FETCH_FUNC(symbol, ftype), \ | 426 | ASSIGN_FETCH_FUNC(symbol, ftype), \ |
389 | ASSIGN_FETCH_FUNC(deref, ftype), \ | 427 | ASSIGN_FETCH_FUNC(deref, ftype), \ |
428 | ASSIGN_FETCH_FUNC(bitfield, ftype), \ | ||
390 | } \ | 429 | } \ |
391 | } | 430 | } |
392 | 431 | ||
@@ -430,9 +469,33 @@ static const struct fetch_type *find_fetch_type(const char *type) | |||
430 | if (!type) | 469 | if (!type) |
431 | type = DEFAULT_FETCH_TYPE_STR; | 470 | type = DEFAULT_FETCH_TYPE_STR; |
432 | 471 | ||
472 | /* Special case: bitfield */ | ||
473 | if (*type == 'b') { | ||
474 | unsigned long bs; | ||
475 | type = strchr(type, '/'); | ||
476 | if (!type) | ||
477 | goto fail; | ||
478 | type++; | ||
479 | if (strict_strtoul(type, 0, &bs)) | ||
480 | goto fail; | ||
481 | switch (bs) { | ||
482 | case 8: | ||
483 | return find_fetch_type("u8"); | ||
484 | case 16: | ||
485 | return find_fetch_type("u16"); | ||
486 | case 32: | ||
487 | return find_fetch_type("u32"); | ||
488 | case 64: | ||
489 | return find_fetch_type("u64"); | ||
490 | default: | ||
491 | goto fail; | ||
492 | } | ||
493 | } | ||
494 | |||
433 | for (i = 0; i < ARRAY_SIZE(fetch_type_table); i++) | 495 | for (i = 0; i < ARRAY_SIZE(fetch_type_table); i++) |
434 | if (strcmp(type, fetch_type_table[i].name) == 0) | 496 | if (strcmp(type, fetch_type_table[i].name) == 0) |
435 | return &fetch_type_table[i]; | 497 | return &fetch_type_table[i]; |
498 | fail: | ||
436 | return NULL; | 499 | return NULL; |
437 | } | 500 | } |
438 | 501 | ||
@@ -586,7 +649,9 @@ error: | |||
586 | 649 | ||
587 | static void free_probe_arg(struct probe_arg *arg) | 650 | static void free_probe_arg(struct probe_arg *arg) |
588 | { | 651 | { |
589 | if (CHECK_FETCH_FUNCS(deref, arg->fetch.fn)) | 652 | if (CHECK_FETCH_FUNCS(bitfield, arg->fetch.fn)) |
653 | free_bitfield_fetch_param(arg->fetch.data); | ||
654 | else if (CHECK_FETCH_FUNCS(deref, arg->fetch.fn)) | ||
590 | free_deref_fetch_param(arg->fetch.data); | 655 | free_deref_fetch_param(arg->fetch.data); |
591 | else if (CHECK_FETCH_FUNCS(symbol, arg->fetch.fn)) | 656 | else if (CHECK_FETCH_FUNCS(symbol, arg->fetch.fn)) |
592 | free_symbol_cache(arg->fetch.data); | 657 | free_symbol_cache(arg->fetch.data); |
@@ -806,6 +871,41 @@ static int __parse_probe_arg(char *arg, const struct fetch_type *t, | |||
806 | return ret; | 871 | return ret; |
807 | } | 872 | } |
808 | 873 | ||
874 | #define BYTES_TO_BITS(nb) ((BITS_PER_LONG * (nb)) / sizeof(long)) | ||
875 | |||
876 | /* Bitfield type needs to be parsed into a fetch function */ | ||
877 | static int __parse_bitfield_probe_arg(const char *bf, | ||
878 | const struct fetch_type *t, | ||
879 | struct fetch_param *f) | ||
880 | { | ||
881 | struct bitfield_fetch_param *bprm; | ||
882 | unsigned long bw, bo; | ||
883 | char *tail; | ||
884 | |||
885 | if (*bf != 'b') | ||
886 | return 0; | ||
887 | |||
888 | bprm = kzalloc(sizeof(*bprm), GFP_KERNEL); | ||
889 | if (!bprm) | ||
890 | return -ENOMEM; | ||
891 | bprm->orig = *f; | ||
892 | f->fn = t->fetch[FETCH_MTD_bitfield]; | ||
893 | f->data = (void *)bprm; | ||
894 | |||
895 | bw = simple_strtoul(bf + 1, &tail, 0); /* Use simple one */ | ||
896 | if (bw == 0 || *tail != '@') | ||
897 | return -EINVAL; | ||
898 | |||
899 | bf = tail + 1; | ||
900 | bo = simple_strtoul(bf, &tail, 0); | ||
901 | if (tail == bf || *tail != '/') | ||
902 | return -EINVAL; | ||
903 | |||
904 | bprm->hi_shift = BYTES_TO_BITS(t->size) - (bw + bo); | ||
905 | bprm->low_shift = bprm->hi_shift + bo; | ||
906 | return (BYTES_TO_BITS(t->size) < (bw + bo)) ? -EINVAL : 0; | ||
907 | } | ||
908 | |||
809 | /* String length checking wrapper */ | 909 | /* String length checking wrapper */ |
810 | static int parse_probe_arg(char *arg, struct trace_probe *tp, | 910 | static int parse_probe_arg(char *arg, struct trace_probe *tp, |
811 | struct probe_arg *parg, int is_return) | 911 | struct probe_arg *parg, int is_return) |
@@ -835,6 +935,8 @@ static int parse_probe_arg(char *arg, struct trace_probe *tp, | |||
835 | parg->offset = tp->size; | 935 | parg->offset = tp->size; |
836 | tp->size += parg->type->size; | 936 | tp->size += parg->type->size; |
837 | ret = __parse_probe_arg(arg, parg->type, &parg->fetch, is_return); | 937 | ret = __parse_probe_arg(arg, parg->type, &parg->fetch, is_return); |
938 | if (ret >= 0) | ||
939 | ret = __parse_bitfield_probe_arg(t, parg->type, &parg->fetch); | ||
838 | if (ret >= 0) { | 940 | if (ret >= 0) { |
839 | parg->fetch_size.fn = get_fetch_size_function(parg->type, | 941 | parg->fetch_size.fn = get_fetch_size_function(parg->type, |
840 | parg->fetch.fn); | 942 | parg->fetch.fn); |