Since we can use the BTF to cast value to a structure pointer type, it is useful to introduce "$current" special variable support to fetcharg. User can define a fetcharg to access current task_struct properties using BTF info. e.g. $current->cpus_ptr Link: https://lore.kernel.org/all/178271366709.1176915.15320906169981578568.stgit@devnote2/
Showing the changes to kernel/trace (4 of 6 files). Show all
Unified · Split
| @@ -4320,13 +4320,13 @@ static const char readme_msg[] = · 4319 unmodified lines | |||
| 4320 | "\t args: <name>=fetcharg[:type]\n" | 4320 | "\t args: <name>=fetcharg[:type]\n" |
| 4321 | "\t fetcharg: (%<register>|$<efield>), @<address>, @<symbol>[+|-<offset>],\n" | 4321 | "\t fetcharg: (%<register>|$<efield>), @<address>, @<symbol>[+|-<offset>],\n" |
| 4322 | #ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API | 4322 | #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>, $current\n" |
| 4324 | #ifdef CONFIG_PROBE_EVENTS_BTF_ARGS | 4324 | #ifdef CONFIG_PROBE_EVENTS_BTF_ARGS |
| 4325 | "\t [(structname[,field])]<argname>[->field[->field|.field...]],\n" | 4325 | "\t [(structname[,field])]<argname>[->field[->field|.field...]],\n" |
| 4326 | "\t [(structname[,field])](fetcharg)->field[->field|.field...],\n" | 4326 | "\t [(structname[,field])](fetcharg)->field[->field|.field...],\n" |
| 4327 | #endif | 4327 | #endif |
| 4328 | #else | 4328 | #else |
| 4329 | "\t $stack<index>, $stack, $retval, $comm,\n" | 4329 | "\t $stack<index>, $stack, $retval, $comm, $current\n" |
| 4330 | #endif | 4330 | #endif |
| 4331 | "\t +|-[u]<offset>(<fetcharg>), \\imm-value, \\\"imm-string\"\n" | 4331 | "\t +|-[u]<offset>(<fetcharg>), \\imm-value, \\\"imm-string\"\n" |
| 4332 | "\t kernel return probes support: $retval, $arg<N>, $comm\n" | 4332 | "\t kernel return probes support: $retval, $arg<N>, $comm\n" |
| @@ -692,7 +692,9 @@ static int parse_btf_arg(char *varname, · 691 unmodified lines | |||
| 692 | int i, is_ptr, ret; | 692 | int i, is_ptr, ret; |
| 693 | u32 tid; | 693 | u32 tid; |
| 694 | 694 | ||
| 695 | if (!ctx->funcname && !(ctx->flags & TPARG_FL_TEVENT)) | 695 | /* Note: field is not separated at this point, so check prefix. */ |
| 696 | if (!str_has_prefix(varname, "$current") && | ||
| 697 | !ctx->funcname && !(ctx->flags & TPARG_FL_TEVENT)) | ||
| 696 | return -EINVAL; | 698 | return -EINVAL; |
| 697 | 699 | ||
| 698 | is_ptr = split_next_field(varname, &field, ctx); | 700 | is_ptr = split_next_field(varname, &field, ctx); |
| @@ -705,6 +707,20 @@ static int parse_btf_arg(char *varname, · 6 unmodified lines | |||
| 705 | return -EOPNOTSUPP; | 707 | return -EOPNOTSUPP; |
| 706 | } | 708 | } |
| 707 | 709 | ||
| 710 | if (!strcmp(varname, "$current")) { | ||
| 711 | code->op = FETCH_OP_CURRENT; | ||
| 712 | /* If no typecast is specified for $current, use task_struct by default */ | ||
| 713 | ret = bpf_find_btf_id("task_struct", BTF_KIND_STRUCT, &ctx->struct_btf); | ||
| 714 | if (ret < 0) { | ||
| 715 | trace_probe_log_err(ctx->offset, NO_BTF_ENTRY); | ||
| 716 | return -ENOENT; | ||
| 717 | } | ||
| 718 | tid = (u32)ret; | ||
| 719 | type = ctx->last_struct = | ||
| 720 | btf_type_skip_modifiers(ctx->struct_btf, tid, NULL); | ||
| 721 | goto found_type; | ||
| 722 | } | ||
| 723 | |||
| 708 | if (ctx->flags & TPARG_FL_RETURN && !strcmp(varname, "$retval")) { | 724 | if (ctx->flags & TPARG_FL_RETURN && !strcmp(varname, "$retval")) { |
| 709 | code->op = FETCH_OP_RETVAL; | 725 | code->op = FETCH_OP_RETVAL; |
| 710 | /* Check whether the function return type is not void, even with typecast. */ | 726 | /* Check whether the function return type is not void, even with typecast. */ |
| @@ -761,6 +777,7 @@ static int parse_btf_arg(char *varname, · 50 unmodified lines | |||
| 761 | 777 | ||
| 762 | found: | 778 | found: |
| 763 | type = btf_type_skip_modifiers(ctx->btf, tid, NULL); | 779 | type = btf_type_skip_modifiers(ctx->btf, tid, NULL); |
| 780 | found_type: | ||
| 764 | if (!type) { | 781 | if (!type) { |
| 765 | trace_probe_log_err(ctx->offset, BAD_BTF_TID); | 782 | trace_probe_log_err(ctx->offset, BAD_BTF_TID); |
| 766 | return -EINVAL; | 783 | return -EINVAL; |
| @@ -1270,6 +1287,24 @@ static int parse_probe_vars(char *orig_arg, const struct fetch_type *t, · 503 unmodified lines | |||
| 1270 | return 0; | 1287 | return 0; |
| 1271 | } | 1288 | } |
| 1272 | 1289 | ||
| 1290 | /* $current returns the address of the current task_struct. */ | ||
| 1291 | if (str_has_prefix(arg, "current")) { | ||
| 1292 | /* $current is only supported by kernel probe. */ | ||
| 1293 | if (!(ctx->flags & TPARG_FL_KERNEL)) { | ||
| 1294 | err = TP_ERR_BAD_VAR; | ||
| 1295 | goto inval; | ||
| 1296 | } | ||
| 1297 | arg += strlen("current"); | ||
| 1298 | if (*arg == '-' && IS_ENABLED(CONFIG_PROBE_EVENTS_BTF_ARGS)) | ||
| 1299 | return parse_btf_arg(orig_arg, pcode, end, ctx); | ||
| 1300 | |||
| 1301 | if (*arg != '\0') | ||
| 1302 | goto inval; | ||
| 1303 | |||
| 1304 | code->op = FETCH_OP_CURRENT; | ||
| 1305 | return 0; | ||
| 1306 | } | ||
| 1307 | |||
| 1273 | #ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API | 1308 | #ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API |
| 1274 | len = str_has_prefix(arg, "arg"); | 1309 | len = str_has_prefix(arg, "arg"); |
| 1275 | if (len) { | 1310 | if (len) { |
| @@ -92,6 +92,7 @@ typedef int (*print_type_func_t)(struct trace_seq *, void *, void *); · 91 unmodified lines | |||
| 92 | FETCH_OP(RETVAL, none), /* Return value */ \ | 92 | FETCH_OP(RETVAL, none), /* Return value */ \ |
| 93 | FETCH_OP(IMM, imm), /* Immediate: .immediate */ \ | 93 | FETCH_OP(IMM, imm), /* Immediate: .immediate */ \ |
| 94 | FETCH_OP(COMM, none), /* Current comm */ \ | 94 | FETCH_OP(COMM, none), /* Current comm */ \ |
| 95 | FETCH_OP(CURRENT, none), /* Current task_struct address */\ | ||
| 95 | FETCH_OP(ARG, param), /* Argument: .param = index */ \ | 96 | FETCH_OP(ARG, param), /* Argument: .param = index */ \ |
| 96 | FETCH_OP(FOFFS, imm), /* File offset: .immediate */ \ | 97 | FETCH_OP(FOFFS, imm), /* File offset: .immediate */ \ |
| 97 | FETCH_OP(IMMSTR, string), /* Allocated string: .data */ \ | 98 | FETCH_OP(IMMSTR, string), /* Allocated string: .data */ \ |
| @@ -112,6 +112,9 @@ process_common_fetch_insn(struct fetch_insn *code, unsigned long *val) · 111 unmodified lines | |||
| 112 | case FETCH_OP_IMMSTR: | 112 | case FETCH_OP_IMMSTR: |
| 113 | *val = (unsigned long)code->data; | 113 | *val = (unsigned long)code->data; |
| 114 | break; | 114 | break; |
| 115 | case FETCH_OP_CURRENT: | ||
| 116 | *val = (unsigned long)current; | ||
| 117 | break; | ||
| 115 | default: | 118 | default: |
| 116 | return -EILSEQ; | 119 | return -EILSEQ; |
| 117 | } | 120 | } |