History

tracing/probes: Add $current variable support

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/

Masami Hiramatsu (Google) committed 4 months ago

Commit 738b78e1 parent f2183456 files · +44 −3Browse files

Unified · Split

6 files
  1. Documentation/trace/fprobetrace.rst +1 −0
  2. Documentation/trace/kprobetrace.rst +1 −0
  3. kernel/trace/trace.c +2 −2
  4. kernel/trace/trace_probe.c +36 −1
  5. kernel/trace/trace_probe.h +1 −0
  6. kernel/trace/trace_probe_tmpl.h +3 −0
Documentation/trace/fprobetrace.rst+1−0
@@ -50,6 +50,7 @@ Synopsis of fprobe-events · 49 unmodified lines
5050 $argN : Fetch the Nth function argument. (N >= 1) (\*2)
5151 $retval : Fetch return value.(\*3)
5252 $comm : Fetch current task comm.
53+ $current : Fetch the address of the current task_struct.
5354 +|-[u]OFFS(FETCHARG) : Fetch memory at FETCHARG +|- OFFS address.(\*4)(\*5)
5455 \IMM : Store an immediate value to the argument.
5556 NAME=FETCHARG : Set NAME as the argument name of FETCHARG.
Documentation/trace/kprobetrace.rst+1−0
@@ -53,6 +53,7 @@ Synopsis of kprobe_events · 52 unmodified lines
5353 $argN : Fetch the Nth function argument. (N >= 1) (\*1)
5454 $retval : Fetch return value.(\*2)
5555 $comm : Fetch current task comm.
56+ $current : Fetch the address of the current task_struct.
5657 +|-[u]OFFS(FETCHARG) : Fetch memory at FETCHARG +|- OFFS address.(\*3)(\*4)
5758 \IMM : Store an immediate value to the argument.
5859 NAME=FETCHARG : Set NAME as the argument name of FETCHARG.
kernel/trace/trace.c+2−2
@@ -4320,13 +4320,13 @@ static const char readme_msg[] = · 4319 unmodified lines
43204320 "\t args: <name>=fetcharg[:type]\n"
43214321 "\t fetcharg: (%<register>|$<efield>), @<address>, @<symbol>[+|-<offset>],\n"
43224322 #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"
43244324 #ifdef CONFIG_PROBE_EVENTS_BTF_ARGS
43254325 "\t [(structname[,field])]<argname>[->field[->field|.field...]],\n"
43264326 "\t [(structname[,field])](fetcharg)->field[->field|.field...],\n"
43274327 #endif
43284328 #else
4329− "\t $stack<index>, $stack, $retval, $comm,\n"
4329+ "\t $stack<index>, $stack, $retval, $comm, $current\n"
43304330 #endif
43314331 "\t +|-[u]<offset>(<fetcharg>), \\imm-value, \\\"imm-string\"\n"
43324332 "\t kernel return probes support: $retval, $arg<N>, $comm\n"
kernel/trace/trace_probe.c+36−1
@@ -692,7 +692,9 @@ static int parse_btf_arg(char *varname, · 691 unmodified lines
692692 int i, is_ptr, ret;
693693 u32 tid;
694694
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))
696698 return -EINVAL;
697699
698700 is_ptr = split_next_field(varname, &field, ctx);
@@ -705,6 +707,20 @@ static int parse_btf_arg(char *varname, · 6 unmodified lines
705707 return -EOPNOTSUPP;
706708 }
707709
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+
708724 if (ctx->flags & TPARG_FL_RETURN && !strcmp(varname, "$retval")) {
709725 code->op = FETCH_OP_RETVAL;
710726 /* 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
761777
762778 found:
763779 type = btf_type_skip_modifiers(ctx->btf, tid, NULL);
780+found_type:
764781 if (!type) {
765782 trace_probe_log_err(ctx->offset, BAD_BTF_TID);
766783 return -EINVAL;
@@ -1270,6 +1287,24 @@ static int parse_probe_vars(char *orig_arg, const struct fetch_type *t, · 503 unmodified lines
12701287 return 0;
12711288 }
12721289
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+
12731308 #ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API
12741309 len = str_has_prefix(arg, "arg");
12751310 if (len) {
kernel/trace/trace_probe.h+1−0
@@ -92,6 +92,7 @@ typedef int (*print_type_func_t)(struct trace_seq *, void *, void *); · 91 unmodified lines
9292 FETCH_OP(RETVAL, none), /* Return value */ \
9393 FETCH_OP(IMM, imm), /* Immediate: .immediate */ \
9494 FETCH_OP(COMM, none), /* Current comm */ \
95+ FETCH_OP(CURRENT, none), /* Current task_struct address */\
9596 FETCH_OP(ARG, param), /* Argument: .param = index */ \
9697 FETCH_OP(FOFFS, imm), /* File offset: .immediate */ \
9798 FETCH_OP(IMMSTR, string), /* Allocated string: .data */ \
kernel/trace/trace_probe_tmpl.h+3−0
@@ -112,6 +112,9 @@ process_common_fetch_insn(struct fetch_insn *code, unsigned long *val) · 111 unmodified lines
112112 case FETCH_OP_IMMSTR:
113113 *val = (unsigned long)code->data;
114114 break;
115+ case FETCH_OP_CURRENT:
116+ *val = (unsigned long)current;
117+ break;
115118 default:
116119 return -EILSEQ;
117120 }