History

tracing/probes: Support field specifier option for typecast

Add a field specifier option for the typecast. This works like container_of() macro. (STRUCT[,FIELD[.FIELD2...]])VAR This is equivalent to : container_of(VAR, struct STRUCT, FIELD[.FIELD2...]) For example: echo "f tick_nohz_handler next_tick=(tick_sched,sched_timer)timer->next_tick" >> dynamic_events This will trace tick_nohz_handler() with its tick_sched::next_tick which is converted from @timer by contianer_of(tick, struct tick_sched, sched_timer). So, if you enabkle both fprobes:tick_nohz_handler__entry and timer:hrtimer_expire_entry events, we will see something like: <idle>-0 [002] d.h1. 3778.087272: hrtimer_expire_entry: hrtimer=00000000d63db328 f unction=tick_nohz_handler now=3777450051040 <idle>-0 [002] d.h1. 3778.087281: tick_nohz_handler__entry: (tick_nohz_handler+0x4 /0x140) next_tick=3777450000000 Link: https://lore.kernel.org/all/178271365745.1176915.725923927180862257.stgit@devnote2/

Masami Hiramatsu (Google) committed 4 months ago

Commit f2183451 parent 52c76ec6 files · +135 −64Browse files

Unified · Split

6 files
  1. Documentation/trace/eprobetrace.rst +4 −1
  2. Documentation/trace/fprobetrace.rst +5 −3
  3. Documentation/trace/kprobetrace.rst +5 −3
  4. kernel/trace/trace.c +2 −2
  5. kernel/trace/trace_probe.c +115 −54
  6. kernel/trace/trace_probe.h +4 −1
Documentation/trace/eprobetrace.rst+4−1
@@ -49,7 +49,10 @@ Synopsis of eprobe_events · 48 unmodified lines
49 (STRUCT)FIELD->MEMBER[->MEMBER] : If BTF is supported, typecast FIELD to49 (STRUCT)FIELD->MEMBER[->MEMBER] : If BTF is supported, typecast FIELD to
50 a pointer to STRUCT and then derference the pointer defined by50 a pointer to STRUCT and then derference the pointer defined by
51 ->MEMBER. Note that when this is used, the FIELD name does not51 ->MEMBER. Note that when this is used, the FIELD name does not
52 need to be prefixed with a '$'.52 need to be prefixed with a '$'. ASGN can be specified optionally.
53 If ASGN is specified, FIELD will be cast to the same offset
54 position as the ASGN member, rather than to the beginning of
55 the STRUCT.
53 (STRUCT)(FETCHARG)->MEMBER[->MEMBER] : typecast can nest, so the above can56 (STRUCT)(FETCHARG)->MEMBER[->MEMBER] : typecast can nest, so the above can
54 also be used with another FETCHARG instead of FIELD.57 also be used with another FETCHARG instead of FIELD.
55 58
Documentation/trace/fprobetrace.rst+5−3
@@ -57,10 +57,12 @@ Synopsis of fprobe-events · 56 unmodified lines
57 (u8/u16/u32/u64/s8/s16/s32/s64), hexadecimal types57 (u8/u16/u32/u64/s8/s16/s32/s64), hexadecimal types
58 (x8/x16/x32/x64), "char", "string", "ustring", "symbol", "symstr"58 (x8/x16/x32/x64), "char", "string", "ustring", "symbol", "symstr"
59 and bitfield are supported.59 and bitfield are supported.
60 (STRUCT)FIELD->MEMBER[->MEMBER] : If BTF is supported, typecast FIELD to60 (STRUCT[,ASGN])FIELD->MEMBER[->MEMBER] : If BTF is supported, typecast FIELD to
61 a pointer to STRUCT and then derference the pointer defined by61 a pointer to STRUCT and then derference the pointer defined by
62 ->MEMBER.62 ->MEMBER. ASGN can be specified optionally. If ASGN is specified,
63 (STRUCT)(FETCHARG)->MEMBER[->MEMBER] : typecast can nest, so the above can63 FIELD will be cast to the same offset position as the ASGN member,
64 rather than to the beginning of the STRUCT.
65 (STRUCT[,ASGN])(FETCHARG)->MEMBER[->MEMBER] : typecast can nest, so the above can
64 also be used with another FETCHARG instead of FIELD.66 also be used with another FETCHARG instead of FIELD.
65 67
66 (\*1) This is available only when BTF is enabled.68 (\*1) This is available only when BTF is enabled.
Documentation/trace/kprobetrace.rst+5−3
@@ -61,11 +61,13 @@ Synopsis of kprobe_events · 60 unmodified lines
61 (x8/x16/x32/x64), VFS layer common type(%pd/%pD), "char",61 (x8/x16/x32/x64), VFS layer common type(%pd/%pD), "char",
62 "string", "ustring", "symbol", "symstr" and bitfield are62 "string", "ustring", "symbol", "symstr" and bitfield are
63 supported.63 supported.
64 (STRUCT)FIELD->MEMBER[->MEMBER] : If BTF is supported, typecast FIELD to64 (STRUCT[,ASGN])FIELD->MEMBER[->MEMBER] : If BTF is supported, typecast FIELD to
65 a pointer to STRUCT and then derference the pointer defined by65 a pointer to STRUCT and then derference the pointer defined by
66 ->MEMBER. Note that this is available only when the probe is66 ->MEMBER. Note that this is available only when the probe is
67 on function entry.67 on function entry. ASGN can be specified optionally. If ASGN
68 (STRUCT)(FETCHARG)->MEMBER[->MEMBER] : typecast can nest, so the above can68 is specified, FIELD will be cast to the same offset position
69 as the ASGN member, rather than to the beginning of the STRUCT.
70 (STRUCT[,ASGN])(FETCHARG)->MEMBER[->MEMBER] : typecast can nest, so the above can
69 also be used with another FETCHARG instead of FIELD.71 also be used with another FETCHARG instead of FIELD.
70 72
71 (\*1) only for the probe on function entry (offs == 0). Note, this argument access73 (\*1) only for the probe on function entry (offs == 0). Note, this argument access
kernel/trace/trace.c+2−2
@@ -4322,8 +4322,8 @@ static const char readme_msg[] = · 4321 unmodified lines
4322#ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API4322#ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API
4323 "\t $stack<index>, $stack, $retval, $comm, $arg<N>,\n"4323 "\t $stack<index>, $stack, $retval, $comm, $arg<N>,\n"
4324#ifdef CONFIG_PROBE_EVENTS_BTF_ARGS4324#ifdef CONFIG_PROBE_EVENTS_BTF_ARGS
4325 "\t [(structname)]<argname>[->field[->field|.field...]],\n"4325 "\t [(structname[,field])]<argname>[->field[->field|.field...]],\n"
4326 "\t [(structname)](fetcharg)->field[->field|.field...],\n"4326 "\t [(structname[,field])](fetcharg)->field[->field|.field...],\n"
4327#endif4327#endif
4328#else4328#else
4329 "\t $stack<index>, $stack, $retval, $comm,\n"4329 "\t $stack<index>, $stack, $retval, $comm,\n"
kernel/trace/trace_probe.c+115−54
@@ -568,6 +568,64 @@ static int split_next_field(char *varname, char **next_field, · 567 unmodified lines
568 return ret;568 return ret;
569}569}
570 570
571/* Inner loop for solving dot operator ('.'). Return bit-offset of the given field */
572static int get_bitoffset_of_field(char **pfieldname, const struct btf_type **ptype,
573 struct traceprobe_parse_context *ctx)
574{
575 const struct btf_type *type = *ptype;
576 const struct btf_member *field;
577 struct btf *btf = ctx_btf(ctx);
578 char *fieldname = *pfieldname;
579 int bitoffs = 0;
580 u32 anon_offs;
581 char *next;
582 int is_ptr;
583
584 do {
585 next = NULL;
586 is_ptr = split_next_field(fieldname, &next, ctx);
587 if (is_ptr < 0)
588 return is_ptr;
589
590 anon_offs = 0;
591 field = btf_find_struct_member(btf, type, fieldname,
592 &anon_offs);
593 if (IS_ERR(field)) {
594 trace_probe_log_err(ctx->offset, BAD_BTF_TID);
595 return PTR_ERR(field);
596 }
597 if (!field) {
598 trace_probe_log_err(ctx->offset, NO_BTF_FIELD);
599 return -ENOENT;
600 }
601 /* Add anonymous structure/union offset */
602 bitoffs += anon_offs;
603
604 /* Accumulate the bit-offsets of the dot-connected fields */
605 if (btf_type_kflag(type)) {
606 bitoffs += BTF_MEMBER_BIT_OFFSET(field->offset);
607 ctx->last_bitsize = BTF_MEMBER_BITFIELD_SIZE(field->offset);
608 } else {
609 bitoffs += field->offset;
610 ctx->last_bitsize = 0;
611 }
612
613 type = btf_type_skip_modifiers(btf, field->type, NULL);
614 if (!type) {
615 trace_probe_log_err(ctx->offset, BAD_BTF_TID);
616 return -EINVAL;
617 }
618
619 if (next)
620 ctx->offset += next - fieldname;
621 fieldname = next;
622 } while (!is_ptr && fieldname);
623
624 *pfieldname = fieldname;
625 *ptype = type;
626
627 return bitoffs;
628}
571/*629/*
572 * Parse the field of data structure. The @type must be a pointer type630 * Parse the field of data structure. The @type must be a pointer type
573 * pointing the target data structure type.631 * pointing the target data structure type.
@@ -577,15 +635,13 @@ static int parse_btf_field(char *fieldname, const struct btf_type *type, · 3 unmodified lines
577 struct traceprobe_parse_context *ctx)635 struct traceprobe_parse_context *ctx)
578{636{
579 struct fetch_insn *code = *pcode;637 struct fetch_insn *code = *pcode;
580 const struct btf_member *field;
581 u32 bitoffs, anon_offs;
582 bool is_struct = ctx->struct_btf != NULL;
583 struct btf *btf = ctx_btf(ctx);638 struct btf *btf = ctx_btf(ctx);
584 char *next;639 bool is_first_field = true;
585 int is_ptr;640 int bitoffs;
586 641
587 do {642 do {
588 if (!is_struct) {643 /* For the first field of typecast, @type will be the target structure type. */
644 if (!(is_first_field && ctx->struct_btf)) {
589 /* Outer loop for solving arrow operator ('->') */645 /* Outer loop for solving arrow operator ('->') */
590 if (BTF_INFO_KIND(type->info) != BTF_KIND_PTR) {646 if (BTF_INFO_KIND(type->info) != BTF_KIND_PTR) {
591 trace_probe_log_err(ctx->offset, NO_PTR_STRCT);647 trace_probe_log_err(ctx->offset, NO_PTR_STRCT);
@@ -599,60 +655,25 @@ static int parse_btf_field(char *fieldname, const struct btf_type *type, · 7 unmodified lines
599 return -EINVAL;655 return -EINVAL;
600 }656 }
601 }657 }
602 /* Only the first type can skip being a pointer */
603 is_struct = false;
604
605 bitoffs = 0;
606 do {
607 /* Inner loop for solving dot operator ('.') */
608 next = NULL;
609 is_ptr = split_next_field(fieldname, &next, ctx);
610 if (is_ptr < 0)
611 return is_ptr;
612
613 anon_offs = 0;
614 field = btf_find_struct_member(btf, type, fieldname,
615 &anon_offs);
616 if (IS_ERR(field)) {
617 trace_probe_log_err(ctx->offset, BAD_BTF_TID);
618 return PTR_ERR(field);
619 }
620 if (!field) {
621 trace_probe_log_err(ctx->offset, NO_BTF_FIELD);
622 return -ENOENT;
623 }
624 /* Add anonymous structure/union offset */
625 bitoffs += anon_offs;
626
627 /* Accumulate the bit-offsets of the dot-connected fields */
628 if (btf_type_kflag(type)) {
629 bitoffs += BTF_MEMBER_BIT_OFFSET(field->offset);
630 ctx->last_bitsize = BTF_MEMBER_BITFIELD_SIZE(field->offset);
631 } else {
632 bitoffs += field->offset;
633 ctx->last_bitsize = 0;
634 }
635
636 type = btf_type_skip_modifiers(btf, field->type, NULL);
637 if (!type) {
638 trace_probe_log_err(ctx->offset, BAD_BTF_TID);
639 return -EINVAL;
640 }
641
642 ctx->offset += next - fieldname;
643 fieldname = next;
644 } while (!is_ptr && fieldname);
645 658
659 bitoffs = get_bitoffset_of_field(&fieldname, &type, ctx);
660 if (bitoffs < 0)
661 return bitoffs;
646 if (++code == end) {662 if (++code == end) {
647 trace_probe_log_err(ctx->offset, TOO_MANY_OPS);663 trace_probe_log_err(ctx->offset, TOO_MANY_OPS);
648 return -EINVAL;664 return -EINVAL;
649 }665 }
650 code->op = FETCH_OP_DEREF; /* TODO: user deref support */666 code->op = FETCH_OP_DEREF; /* TODO: user deref support */
651 code->offset = bitoffs / 8;667 code->offset = bitoffs / 8;
668 if (is_first_field && ctx->struct_btf) {
669 /* The first field can be typecasted with field option. */
670 code->offset -= ctx->prefix_byteoffs;
671 }
652 *pcode = code;672 *pcode = code;
653 673
654 ctx->last_bitoffs = bitoffs % 8;674 ctx->last_bitoffs = bitoffs % 8;
655 ctx->last_type = type;675 ctx->last_type = type;
676 is_first_field = false;
656 } while (fieldname);677 } while (fieldname);
657 678
658 return 0;679 return 0;
@@ -808,6 +829,46 @@ static int query_btf_struct(const char *sname, struct traceprobe_parse_context * · 149 unmodified lines
808 return 0;829 return 0;
809}830}
810 831
832static int parse_btf_casttype(char *casttype, struct traceprobe_parse_context *ctx)
833{
834 char *field;
835 int ret;
836
837 /* Field option - evaluated later. */
838 field = strchr(casttype, ',');
839 if (field)
840 *field++ = '\0';
841
842 ret = query_btf_struct(casttype, ctx);
843 if (ret < 0) {
844 trace_probe_log_err(ctx->offset, NO_PTR_STRCT);
845 return -EINVAL;
846 }
847
848 if (field) {
849 struct btf_type *type = (struct btf_type *)ctx->last_struct;
850
851 ctx->offset += field - casttype;
852 ret = get_bitoffset_of_field(&field, &ctx->last_struct, ctx);
853 if (ret < 0)
854 return ret;
855 if (ret % 8) {
856 trace_probe_log_err(ctx->offset, TYPECAST_NOT_ALIGNED);
857 return -EINVAL;
858 }
859 if (field != NULL) {
860 /* this means @field skips an arrow operator ("->"). */
861 trace_probe_log_err(ctx->offset - 2, TYPECAST_BAD_ARROW);
862 return -EINVAL;
863 }
864 ctx->prefix_byteoffs = ret / 8;
865 /* Restore the original struct type (overwritten by get_bitoffset_of_field) */
866 ctx->last_struct = type;
867 }
868
869 return ret;
870}
871
811/* Find the matching closing parenthesis for a given opening parenthesis. */872/* Find the matching closing parenthesis for a given opening parenthesis. */
812static char *find_matched_close_paren(char *s)873static char *find_matched_close_paren(char *s)
813{874{
@@ -940,14 +1001,14 @@ static int handle_typecast(char *arg, struct fetch_insn **pcode, · 126 unmodified lines
940 tmp = close + 2; /* Skip ">" after inner variable name */1001 tmp = close + 2; /* Skip ">" after inner variable name */
941 1002
942 /* resolve the typecast struct name */1003 /* resolve the typecast struct name */
943 ret = query_btf_struct(arg + 1, ctx);1004 ctx->offset = orig_offset + 1; /* for the '(' */
944 if (ret < 0) {1005 ret = parse_btf_casttype(arg + 1, ctx);
945 trace_probe_log_err(orig_offset + 1, NO_PTR_STRCT);1006 if (ret < 0)
946 return -EINVAL;1007 return ret;
947 }
948 1008
949 ctx->offset = orig_offset + tmp - arg;1009 ctx->offset = orig_offset + tmp - arg;
950 ret = parse_btf_field(tmp, ctx->last_struct, pcode, end, ctx);1010 ret = parse_btf_field(tmp, ctx->last_struct, pcode, end, ctx);
1011 ctx->prefix_byteoffs = 0;
951 return ret;1012 return ret;
952}1013}
953 1014
kernel/trace/trace_probe.h+4−1
@@ -451,6 +451,7 @@ struct traceprobe_parse_context { · 450 unmodified lines
451 unsigned int flags;451 unsigned int flags;
452 int offset;452 int offset;
453 int nested_level;453 int nested_level;
454 int prefix_byteoffs; /* The byte offset of the prefix field of typecast */
454};455};
455 456
456/* Each typecast consumes nested level. So the max number of typecast is 3. */457/* Each typecast consumes nested level. So the max number of typecast is 3. */
@@ -594,7 +595,9 @@ extern int traceprobe_define_arg_fields(struct trace_event_call *event_call, · 137 unmodified lines
594 C(TYPECAST_NOT_EVENT, "Typecasts are only for eprobe fields"), \595 C(TYPECAST_NOT_EVENT, "Typecasts are only for eprobe fields"), \
595 C(TYPECAST_REQ_FIELD, "Typecast requires a field access"), \596 C(TYPECAST_REQ_FIELD, "Typecast requires a field access"), \
596 C(TOO_MANY_NESTED, "Too many nested typecasts/dereferences"), \597 C(TOO_MANY_NESTED, "Too many nested typecasts/dereferences"), \
597 C(TYPECAST_SYM_OFFSET, "@SYM+/-OFFSET with typecast needs parentheses")598 C(TYPECAST_SYM_OFFSET, "@SYM+/-OFFSET with typecast needs parentheses"), \
599 C(TYPECAST_NOT_ALIGNED, "Typecast field option is not byte-aligned"), \
600 C(TYPECAST_BAD_ARROW, "Typecast field option does not support -> operator"),
598 601
599#undef C602#undef C
600#define C(a, b) TP_ERR_##a603#define C(a, b) TP_ERR_##a