@@ -310,16 +310,14 @@ static u32 btf_type_int(const struct btf_type *t)
310310 return * (u32 * )(t + 1 );
311311}
312312
313- static const char * type_from_btf_id (struct btf * btf , s32 id )
313+ static const char * fetch_type_from_btf_type (struct btf * btf ,
314+ const struct btf_type * type ,
315+ struct traceprobe_parse_context * ctx )
314316{
315- const struct btf_type * t ;
316317 u32 intdata ;
317- s32 tid ;
318318
319319 /* TODO: const char * could be converted as a string */
320- t = btf_type_skip_modifiers (btf , id , & tid );
321-
322- switch (BTF_INFO_KIND (t -> info )) {
320+ switch (BTF_INFO_KIND (type -> info )) {
323321 case BTF_KIND_ENUM :
324322 /* enum is "int", so convert to "s32" */
325323 return "s32" ;
@@ -332,7 +330,7 @@ static const char *type_from_btf_id(struct btf *btf, s32 id)
332330 else
333331 return "x32" ;
334332 case BTF_KIND_INT :
335- intdata = btf_type_int (t );
333+ intdata = btf_type_int (type );
336334 if (BTF_INT_ENCODING (intdata ) & BTF_INT_SIGNED ) {
337335 switch (BTF_INT_BITS (intdata )) {
338336 case 8 :
@@ -355,6 +353,10 @@ static const char *type_from_btf_id(struct btf *btf, s32 id)
355353 case 64 :
356354 return "u64" ;
357355 }
356+ /* bitfield, size is encoded in the type */
357+ ctx -> last_bitsize = BTF_INT_BITS (intdata );
358+ ctx -> last_bitoffs += BTF_INT_OFFSET (intdata );
359+ return "u64" ;
358360 }
359361 }
360362 /* TODO: support other types */
@@ -406,15 +408,136 @@ static void clear_btf_context(struct traceprobe_parse_context *ctx)
406408 }
407409}
408410
409- static int parse_btf_arg (const char * varname , struct fetch_insn * code ,
411+ /* Return 1 if the field separater is arrow operator ('->') */
412+ static int split_next_field (char * varname , char * * next_field ,
413+ struct traceprobe_parse_context * ctx )
414+ {
415+ char * field ;
416+ int ret = 0 ;
417+
418+ field = strpbrk (varname , ".-" );
419+ if (field ) {
420+ if (field [0 ] == '-' && field [1 ] == '>' ) {
421+ field [0 ] = '\0' ;
422+ field += 2 ;
423+ ret = 1 ;
424+ } else if (field [0 ] == '.' ) {
425+ field [0 ] = '\0' ;
426+ field += 1 ;
427+ } else {
428+ trace_probe_log_err (ctx -> offset + field - varname , BAD_HYPHEN );
429+ return - EINVAL ;
430+ }
431+ * next_field = field ;
432+ }
433+
434+ return ret ;
435+ }
436+
437+ /*
438+ * Parse the field of data structure. The @type must be a pointer type
439+ * pointing the target data structure type.
440+ */
441+ static int parse_btf_field (char * fieldname , const struct btf_type * type ,
442+ struct fetch_insn * * pcode , struct fetch_insn * end ,
443+ struct traceprobe_parse_context * ctx )
444+ {
445+ struct fetch_insn * code = * pcode ;
446+ const struct btf_member * field ;
447+ u32 bitoffs , anon_offs ;
448+ char * next ;
449+ int is_ptr ;
450+ s32 tid ;
451+
452+ do {
453+ /* Outer loop for solving arrow operator ('->') */
454+ if (BTF_INFO_KIND (type -> info ) != BTF_KIND_PTR ) {
455+ trace_probe_log_err (ctx -> offset , NO_PTR_STRCT );
456+ return - EINVAL ;
457+ }
458+ /* Convert a struct pointer type to a struct type */
459+ type = btf_type_skip_modifiers (ctx -> btf , type -> type , & tid );
460+ if (!type ) {
461+ trace_probe_log_err (ctx -> offset , BAD_BTF_TID );
462+ return - EINVAL ;
463+ }
464+
465+ bitoffs = 0 ;
466+ do {
467+ /* Inner loop for solving dot operator ('.') */
468+ next = NULL ;
469+ is_ptr = split_next_field (fieldname , & next , ctx );
470+ if (is_ptr < 0 )
471+ return is_ptr ;
472+
473+ anon_offs = 0 ;
474+ field = btf_find_struct_member (ctx -> btf , type , fieldname ,
475+ & anon_offs );
476+ if (!field ) {
477+ trace_probe_log_err (ctx -> offset , NO_BTF_FIELD );
478+ return - ENOENT ;
479+ }
480+ /* Add anonymous structure/union offset */
481+ bitoffs += anon_offs ;
482+
483+ /* Accumulate the bit-offsets of the dot-connected fields */
484+ if (btf_type_kflag (type )) {
485+ bitoffs += BTF_MEMBER_BIT_OFFSET (field -> offset );
486+ ctx -> last_bitsize = BTF_MEMBER_BITFIELD_SIZE (field -> offset );
487+ } else {
488+ bitoffs += field -> offset ;
489+ ctx -> last_bitsize = 0 ;
490+ }
491+
492+ type = btf_type_skip_modifiers (ctx -> btf , field -> type , & tid );
493+ if (!type ) {
494+ trace_probe_log_err (ctx -> offset , BAD_BTF_TID );
495+ return - EINVAL ;
496+ }
497+
498+ ctx -> offset += next - fieldname ;
499+ fieldname = next ;
500+ } while (!is_ptr && fieldname );
501+
502+ if (++ code == end ) {
503+ trace_probe_log_err (ctx -> offset , TOO_MANY_OPS );
504+ return - EINVAL ;
505+ }
506+ code -> op = FETCH_OP_DEREF ; /* TODO: user deref support */
507+ code -> offset = bitoffs / 8 ;
508+ * pcode = code ;
509+
510+ ctx -> last_bitoffs = bitoffs % 8 ;
511+ ctx -> last_type = type ;
512+ } while (fieldname );
513+
514+ return 0 ;
515+ }
516+
517+ static int parse_btf_arg (char * varname ,
518+ struct fetch_insn * * pcode , struct fetch_insn * end ,
410519 struct traceprobe_parse_context * ctx )
411520{
521+ struct fetch_insn * code = * pcode ;
412522 const struct btf_param * params ;
413- int i ;
523+ const struct btf_type * type ;
524+ char * field = NULL ;
525+ int i , is_ptr ;
526+ u32 tid ;
414527
415528 if (WARN_ON_ONCE (!ctx -> funcname ))
416529 return - EINVAL ;
417530
531+ is_ptr = split_next_field (varname , & field , ctx );
532+ if (is_ptr < 0 )
533+ return is_ptr ;
534+ if (!is_ptr && field ) {
535+ /* dot-connected field on an argument is not supported. */
536+ trace_probe_log_err (ctx -> offset + field - varname ,
537+ NOSUP_DAT_ARG );
538+ return - EOPNOTSUPP ;
539+ }
540+
418541 if (!ctx -> params ) {
419542 params = find_btf_func_param (ctx -> funcname ,
420543 & ctx -> nr_params , & ctx -> btf ,
@@ -436,24 +559,39 @@ static int parse_btf_arg(const char *varname, struct fetch_insn *code,
436559 code -> param = i + 1 ;
437560 else
438561 code -> param = i ;
439- return 0 ;
562+
563+ tid = params [i ].type ;
564+ goto found ;
440565 }
441566 }
442567 trace_probe_log_err (ctx -> offset , NO_BTFARG );
443568 return - ENOENT ;
569+
570+ found :
571+ type = btf_type_skip_modifiers (ctx -> btf , tid , & tid );
572+ if (!type ) {
573+ trace_probe_log_err (ctx -> offset , BAD_BTF_TID );
574+ return - EINVAL ;
575+ }
576+ /* Initialize the last type information */
577+ ctx -> last_type = type ;
578+ ctx -> last_bitoffs = 0 ;
579+ ctx -> last_bitsize = 0 ;
580+ if (field ) {
581+ ctx -> offset += field - varname ;
582+ return parse_btf_field (field , type , pcode , end , ctx );
583+ }
584+ return 0 ;
444585}
445586
446- static const struct fetch_type * parse_btf_arg_type (int arg_idx ,
587+ static const struct fetch_type * parse_btf_arg_type (
447588 struct traceprobe_parse_context * ctx )
448589{
449590 struct btf * btf = ctx -> btf ;
450591 const char * typestr = NULL ;
451592
452- if (btf && ctx -> params ) {
453- if (ctx -> flags & TPARG_FL_TPOINT )
454- arg_idx -- ;
455- typestr = type_from_btf_id (btf , ctx -> params [arg_idx ].type );
456- }
593+ if (btf && ctx -> last_type )
594+ typestr = fetch_type_from_btf_type (btf , ctx -> last_type , ctx );
457595
458596 return find_fetch_type (typestr , ctx -> flags );
459597}
@@ -462,21 +600,45 @@ static const struct fetch_type *parse_btf_retval_type(
462600 struct traceprobe_parse_context * ctx )
463601{
464602 const char * typestr = NULL ;
465- const struct btf_type * t ;
603+ const struct btf_type * type ;
466604 struct btf * btf ;
467605
468606 if (ctx -> funcname ) {
469607 /* Do not use ctx->btf, because it must be used with ctx->param */
470- t = btf_find_func_proto (ctx -> funcname , & btf );
471- if (t ) {
472- typestr = type_from_btf_id (btf , t -> type );
608+ type = btf_find_func_proto (ctx -> funcname , & btf );
609+ if (type ) {
610+ type = btf_type_skip_modifiers (btf , type -> type , NULL );
611+ if (!IS_ERR_OR_NULL (type ))
612+ typestr = fetch_type_from_btf_type (btf , type , ctx );
473613 btf_put (btf );
474614 }
475615 }
476616
477617 return find_fetch_type (typestr , ctx -> flags );
478618}
479619
620+ static int parse_btf_bitfield (struct fetch_insn * * pcode ,
621+ struct traceprobe_parse_context * ctx )
622+ {
623+ struct fetch_insn * code = * pcode ;
624+
625+ if ((ctx -> last_bitsize % 8 == 0 ) && ctx -> last_bitoffs == 0 )
626+ return 0 ;
627+
628+ code ++ ;
629+ if (code -> op != FETCH_OP_NOP ) {
630+ trace_probe_log_err (ctx -> offset , TOO_MANY_OPS );
631+ return - EINVAL ;
632+ }
633+ * pcode = code ;
634+
635+ code -> op = FETCH_OP_MOD_BF ;
636+ code -> lshift = 64 - (ctx -> last_bitsize + ctx -> last_bitoffs );
637+ code -> rshift = 64 - ctx -> last_bitsize ;
638+ code -> basesize = 64 / 8 ;
639+ return 0 ;
640+ }
641+
480642static bool is_btf_retval_void (const char * funcname )
481643{
482644 const struct btf_type * t ;
@@ -503,14 +665,22 @@ static const struct btf_param *find_btf_func_param(const char *funcname, s32 *nr
503665 return ERR_PTR (- EOPNOTSUPP );
504666}
505667
506- static int parse_btf_arg (const char * varname , struct fetch_insn * code ,
668+ static int parse_btf_arg (char * varname ,
669+ struct fetch_insn * * pcode , struct fetch_insn * end ,
507670 struct traceprobe_parse_context * ctx )
508671{
509672 trace_probe_log_err (ctx -> offset , NOSUP_BTFARG );
510673 return - EOPNOTSUPP ;
511674}
512675
513- #define parse_btf_arg_type (idx , ctx ) \
676+ static int parse_btf_bitfield (struct fetch_insn * * pcode ,
677+ struct traceprobe_parse_context * ctx )
678+ {
679+ trace_probe_log_err (ctx -> offset , NOSUP_BTFARG );
680+ return - EOPNOTSUPP ;
681+ }
682+
683+ #define parse_btf_arg_type (ctx ) \
514684 find_fetch_type(NULL, ctx->flags)
515685
516686#define parse_btf_retval_type (ctx ) \
@@ -778,6 +948,8 @@ parse_probe_arg(char *arg, const struct fetch_type *type,
778948
779949 code -> op = deref ;
780950 code -> offset = offset ;
951+ /* Reset the last type if used */
952+ ctx -> last_type = NULL ;
781953 }
782954 break ;
783955 case '\\' : /* Immediate value */
@@ -801,7 +973,7 @@ parse_probe_arg(char *arg, const struct fetch_type *type,
801973 trace_probe_log_err (ctx -> offset , NOSUP_BTFARG );
802974 return - EINVAL ;
803975 }
804- ret = parse_btf_arg (arg , code , ctx );
976+ ret = parse_btf_arg (arg , pcode , end , ctx );
805977 break ;
806978 }
807979 }
@@ -947,16 +1119,17 @@ static int traceprobe_parse_probe_arg_body(const char *argv, ssize_t *size,
9471119 goto out ;
9481120 code [FETCH_INSN_MAX - 1 ].op = FETCH_OP_END ;
9491121
1122+ ctx -> last_type = NULL ;
9501123 ret = parse_probe_arg (arg , parg -> type , & code , & code [FETCH_INSN_MAX - 1 ],
9511124 ctx );
9521125 if (ret )
9531126 goto fail ;
9541127
9551128 /* Update storing type if BTF is available */
9561129 if (IS_ENABLED (CONFIG_PROBE_EVENTS_BTF_ARGS ) && !t ) {
957- if (code -> op == FETCH_OP_ARG )
958- parg -> type = parse_btf_arg_type (code -> param , ctx );
959- else if (code -> op == FETCH_OP_RETVAL )
1130+ if (ctx -> last_type )
1131+ parg -> type = parse_btf_arg_type (ctx );
1132+ else if (ctx -> flags & TPARG_FL_RETURN )
9601133 parg -> type = parse_btf_retval_type (ctx );
9611134 }
9621135
@@ -1031,6 +1204,11 @@ static int traceprobe_parse_probe_arg_body(const char *argv, ssize_t *size,
10311204 trace_probe_log_err (ctx -> offset + t - arg , BAD_BITFIELD );
10321205 goto fail ;
10331206 }
1207+ } else if (IS_ENABLED (CONFIG_PROBE_EVENTS_BTF_ARGS ) &&
1208+ ctx -> last_type ) {
1209+ ret = parse_btf_bitfield (& code , ctx );
1210+ if (ret )
1211+ goto fail ;
10341212 }
10351213 ret = - EINVAL ;
10361214 /* Loop(Array) operation */
0 commit comments