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 | 4320 | "\t args: <name>=fetcharg[:type]\n" |
| 4321 | 4321 | "\t fetcharg: (%<register>|$<efield>), @<address>, @<symbol>[+|-<offset>],\n" |
| 4322 | 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 | 4324 | #ifdef CONFIG_PROBE_EVENTS_BTF_ARGS |
| 4325 | 4325 | "\t [(structname[,field])]<argname>[->field[->field|.field...]],\n" |
| 4326 | 4326 | "\t [(structname[,field])](fetcharg)->field[->field|.field...],\n" |
| 4327 | 4327 | #endif |
| 4328 | 4328 | #else |
| 4329 | − "\t $stack<index>, $stack, $retval, $comm,\n" | |
| 4329 | + "\t $stack<index>, $stack, $retval, $comm, $current\n" | |
| 4330 | 4330 | #endif |
| 4331 | 4331 | "\t +|-[u]<offset>(<fetcharg>), \\imm-value, \\\"imm-string\"\n" |
| 4332 | 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 | 692 | int i, is_ptr, ret; |
| 693 | 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 | 698 | return -EINVAL; |
| 697 | 699 | |
| 698 | 700 | is_ptr = split_next_field(varname, &field, ctx); |
| @@ -705,6 +707,20 @@ static int parse_btf_arg(char *varname, · 6 unmodified lines | ||
| 705 | 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 | 724 | if (ctx->flags & TPARG_FL_RETURN && !strcmp(varname, "$retval")) { |
| 709 | 725 | code->op = FETCH_OP_RETVAL; |
| 710 | 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 | 778 | found: |
| 763 | 779 | type = btf_type_skip_modifiers(ctx->btf, tid, NULL); |
| 780 | +found_type: | |
| 764 | 781 | if (!type) { |
| 765 | 782 | trace_probe_log_err(ctx->offset, BAD_BTF_TID); |
| 766 | 783 | return -EINVAL; |
| @@ -1270,6 +1287,24 @@ static int parse_probe_vars(char *orig_arg, const struct fetch_type *t, · 503 unmodified lines | ||
| 1270 | 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 | 1308 | #ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API |
| 1274 | 1309 | len = str_has_prefix(arg, "arg"); |
| 1275 | 1310 | if (len) { |
| @@ -92,6 +92,7 @@ typedef int (*print_type_func_t)(struct trace_seq *, void *, void *); · 91 unmodified lines | ||
| 92 | 92 | FETCH_OP(RETVAL, none), /* Return value */ \ |
| 93 | 93 | FETCH_OP(IMM, imm), /* Immediate: .immediate */ \ |
| 94 | 94 | FETCH_OP(COMM, none), /* Current comm */ \ |
| 95 | + FETCH_OP(CURRENT, none), /* Current task_struct address */\ | |
| 95 | 96 | FETCH_OP(ARG, param), /* Argument: .param = index */ \ |
| 96 | 97 | FETCH_OP(FOFFS, imm), /* File offset: .immediate */ \ |
| 97 | 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 | 112 | case FETCH_OP_IMMSTR: |
| 113 | 113 | *val = (unsigned long)code->data; |
| 114 | 114 | break; |
| 115 | + case FETCH_OP_CURRENT: | |
| 116 | + *val = (unsigned long)current; | |
| 117 | + break; | |
| 115 | 118 | default: |
| 116 | 119 | return -EILSEQ; |
| 117 | 120 | } |