From nobody Sun Feb 8 18:31:34 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C63131A23BE; Tue, 22 Apr 2025 18:33:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745346815; cv=none; b=EVAbXjGZfAvgY6miJ96eCWW9uhtlZttyxudOyWhqjmXkRw0KHzpKdnP0d6HlpbOTPAOoFIPC9h3A7G+3pFx3Sq+/f/QBPndyf4llwFfEW3ftslFbiCaoK0JX0WzU9g+56ONkcpOILVEXfC599QUk+OPazvTu4gi6dBo20NdxzgU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745346815; c=relaxed/simple; bh=fu2QT+dyiaaWloVQYHKF0+VR5yRpgBCxGsh7w+juC18=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:To:Cc; b=Utp06CNF/1OITAnloocdRIolQZMHQDYiGnONCHqV1nS6Mc+weAQ4bJOGrmOsUIHvyiMCGzThY9pElyDczLZS1EVchrsKpuY9HiYD6kuu1nDaNsa9rH3NruDTO47HcTk+p9Jl5BTft8B0pJasyJR+Zob1LvmhBSSMRe4wz0MCjbM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=oBdg2owC; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="oBdg2owC" Received: by smtp.kernel.org (Postfix) with ESMTPS id 3A4A8C4CEEE; Tue, 22 Apr 2025 18:33:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1745346815; bh=fu2QT+dyiaaWloVQYHKF0+VR5yRpgBCxGsh7w+juC18=; h=From:Date:Subject:To:Cc:Reply-To:From; b=oBdg2owCXdkOZb03x0xOrzmuFaCPkmkHnmEYon7ikoBoJvS/9YUiBgWeThbXhSkhQ 715xeaBzM22cwG1d5JoczbabVwsigP9VSX14ThKsnX2yfrWJaslHtTD1wZ8+30UIBz 4W8ym3m3zVw2aoJL1panzraGDRCStmcpYEjgy3fY6okzYlVDCuQ9Gfg+f1gIgoJDp/ szVeHusghtehE1/Krxt3260NkSBmYO46NTPvE5P3keUc0Fr8io7cbRAT8zm//fIT95 KPZn1ypooejoPCsrRdHmDB0lBYdNzpqKWdgzjk+qVW73aToESSTGVTWQkuh9IbDyN0 5I+wdCMHhalzg== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1A46CC369D7; Tue, 22 Apr 2025 18:33:35 +0000 (UTC) From: Paul Cacheux via B4 Relay Date: Tue, 22 Apr 2025 20:33:13 +0200 Subject: [PATCH] tracing: fix race when creating trace probe log error message Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250422-fix-trace-probe-log-race-v1-1-d2728d42cacb@gmail.com> X-B4-Tracking: v=1; b=H4sIAOjgB2gC/x3MQQqAIBCF4avErBswSbCuEi3SJhsIjTEikO6et Pzgf69AJmHKMDYFhG7OnGJF1zbg9yUGQl6rQSttVK8VbvzgJYsnPCU5wiMF/Om9HVZLZnOdgTo /hWr7X0/z+37sLDWIagAAAA== X-Change-ID: 20250420-fix-trace-probe-log-race-cc89d8e5fb15 To: Steven Rostedt , Masami Hiramatsu , Mathieu Desnoyers Cc: linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org, Paul Cacheux X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1745346813; l=65097; i=paulcacheux@gmail.com; s=20250422; h=from:subject:message-id; bh=ZxlkmC/MMKZHlglxRiW100ETEQg5jrB6k9qzOrmAuIs=; b=q2Mxf70VFXk6jJCcsqa5VbZ1JHuJmyp9eTuWNWoFqAiId0GYmOanFRPYCkCbq4bqfdkIMAp5o psx3pyz1rMZBikwnLrUsw/Y9TzUIQOcuTwhkoOB6NsoWiaAIGgFWl3P X-Developer-Key: i=paulcacheux@gmail.com; a=ed25519; pk=8UguSecyECHKHp0YLS7hTEDob0ctFMr3ygBTeAmrFHs= X-Endpoint-Received: by B4 Relay for paulcacheux@gmail.com/20250422 with auth_id=386 X-Original-From: Paul Cacheux Reply-To: paulcacheux@gmail.com From: Paul Cacheux When creating a trace probe a global variable is modified and this data used when an error is raised and the error message generated. Modification of this global variable is done without any lock and multiple trace operations will race, causing some potential issues when generating the error. This commit moves away from the global variable and passes the error context as a regular function argument. Fixes: ab105a4fb894 ("tracing: Use tracing error_log with probe events") Signed-off-by: Paul Cacheux --- As reported in [1] a race exists in the shared trace probe log used to build error messages. This can cause kernel crashes when building the actual error message, but the race happens even for non-error tracefs uses, it's just not visible. Reproducer first reported that is still crashing: # 'p4' is invalid command which make kernel run into trace_probe_log_err() cd /sys/kernel/debug/tracing while true; do echo 'p4:myprobe1 do_sys_openat2 dfd=3D%ax filename=3D%dx flags=3D%cx m= ode=3D+4($stack)' >> kprobe_events & echo 'p4:myprobe2 do_sys_openat2' >> kprobe_events & echo 'p4:myprobe3 do_sys_openat2 dfd=3D%ax filename=3D%dx' >> kprobe_ev= ents & done; The original email suggested to use a mutex or to allocate the trace_probe_log on the stack. The mutex can cause performance issues, and require high confidence in the correctness of the current trace_probe_log_clear calls. This patch implements the stack solution instead and passes a pointer to using functions. [1] https://lore.kernel.org/all/20221121081103.3070449-1-zhengyejian1@huawe= i.com/T/ --- kernel/trace/trace_eprobe.c | 40 ++++--- kernel/trace/trace_fprobe.c | 84 +++++++------- kernel/trace/trace_kprobe.c | 75 ++++++------ kernel/trace/trace_probe.c | 274 +++++++++++++++++++++++-----------------= ---- kernel/trace/trace_probe.h | 21 ++-- kernel/trace/trace_uprobe.c | 58 +++++----- 6 files changed, 287 insertions(+), 265 deletions(-) diff --git a/kernel/trace/trace_eprobe.c b/kernel/trace/trace_eprobe.c index c08355c3ef32b4124ac944d7e3a03efb66492269..5dc5e722d3d2f53a963c3fe7536= bc8adc177c867 100644 --- a/kernel/trace/trace_eprobe.c +++ b/kernel/trace/trace_eprobe.c @@ -795,7 +795,8 @@ find_and_get_event(const char *system, const char *even= t_name) return NULL; } =20 -static int trace_eprobe_tp_update_arg(struct trace_eprobe *ep, const char = *argv[], int i) +static int trace_eprobe_tp_update_arg(struct trace_eprobe *ep, const char = *argv[], int i, + struct trace_probe_log *tpl) { struct traceprobe_parse_context ctx =3D { .event =3D ep->event, @@ -803,7 +804,7 @@ static int trace_eprobe_tp_update_arg(struct trace_epro= be *ep, const char *argv[ }; int ret; =20 - ret =3D traceprobe_parse_probe_arg(&ep->tp, i, argv[i], &ctx); + ret =3D traceprobe_parse_probe_arg(&ep->tp, i, argv[i], &ctx, tpl); /* Handle symbols "@" */ if (!ret) ret =3D traceprobe_update_arg(&ep->tp.args[i]); @@ -812,14 +813,17 @@ static int trace_eprobe_tp_update_arg(struct trace_ep= robe *ep, const char *argv[ return ret; } =20 -static int trace_eprobe_parse_filter(struct trace_eprobe *ep, int argc, co= nst char *argv[]) +static int trace_eprobe_parse_filter(struct trace_eprobe *ep, + struct trace_probe_log *tpl, + int argc, + const char *argv[]) { struct event_filter *dummy =3D NULL; int i, ret, len =3D 0; char *p; =20 if (argc =3D=3D 0) { - trace_probe_log_err(0, NO_EP_FILTER); + trace_probe_log_err(tpl, 0, NO_EP_FILTER); return -EINVAL; } =20 @@ -879,22 +883,22 @@ static int __trace_eprobe_create(int argc, const char= *argv[]) if (argc < 2 || argv[0][0] !=3D 'e') return -ECANCELED; =20 - trace_probe_log_init("event_probe", argc, argv); + struct trace_probe_log tpl =3D trace_probe_log_create("event_probe", argc= , argv); =20 event =3D strchr(&argv[0][1], ':'); if (event) { event++; ret =3D traceprobe_parse_event_name(&event, &group, gbuf, - event - argv[0]); + event - argv[0], &tpl); if (ret) goto parse_error; } =20 - trace_probe_log_set_index(1); + trace_probe_log_set_index(&tpl, 1); sys_event =3D argv[1]; - ret =3D traceprobe_parse_event_name(&sys_event, &sys_name, buf2, 0); + ret =3D traceprobe_parse_event_name(&sys_event, &sys_name, buf2, 0, &tpl); if (ret || !sys_event || !sys_name) { - trace_probe_log_err(0, NO_EVENT_INFO); + trace_probe_log_err(&tpl, 0, NO_EVENT_INFO); goto parse_error; } =20 @@ -913,8 +917,8 @@ static int __trace_eprobe_create(int argc, const char *= argv[]) } =20 if (argc - 2 > MAX_TRACE_ARGS) { - trace_probe_log_set_index(2); - trace_probe_log_err(0, TOO_MANY_ARGS); + trace_probe_log_set_index(&tpl, 2); + trace_probe_log_err(&tpl, 0, TOO_MANY_ARGS); ret =3D -E2BIG; goto error; } @@ -927,7 +931,7 @@ static int __trace_eprobe_create(int argc, const char *= argv[]) if (IS_ERR(ep)) { ret =3D PTR_ERR(ep); if (ret =3D=3D -ENODEV) - trace_probe_log_err(0, BAD_ATTACH_EVENT); + trace_probe_log_err(&tpl, 0, BAD_ATTACH_EVENT); /* This must return -ENOMEM or missing event, else there is a bug */ WARN_ON_ONCE(ret !=3D -ENOMEM && ret !=3D -ENODEV); ep =3D NULL; @@ -935,8 +939,8 @@ static int __trace_eprobe_create(int argc, const char *= argv[]) } =20 if (filter_idx) { - trace_probe_log_set_index(filter_idx); - ret =3D trace_eprobe_parse_filter(ep, filter_cnt, argv + filter_idx); + trace_probe_log_set_index(&tpl, filter_idx); + ret =3D trace_eprobe_parse_filter(ep, &tpl, filter_cnt, argv + filter_id= x); if (ret) goto parse_error; } else @@ -945,8 +949,8 @@ static int __trace_eprobe_create(int argc, const char *= argv[]) argc -=3D 2; argv +=3D 2; /* parse arguments */ for (i =3D 0; i < argc; i++) { - trace_probe_log_set_index(i + 2); - ret =3D trace_eprobe_tp_update_arg(ep, argv, i); + trace_probe_log_set_index(&tpl, i + 2); + ret =3D trace_eprobe_tp_update_arg(ep, argv, i, &tpl); if (ret) goto error; } @@ -958,8 +962,8 @@ static int __trace_eprobe_create(int argc, const char *= argv[]) ret =3D trace_probe_register_event_call(&ep->tp); if (ret) { if (ret =3D=3D -EEXIST) { - trace_probe_log_set_index(0); - trace_probe_log_err(0, EVENT_EXIST); + trace_probe_log_set_index(&tpl, 0); + trace_probe_log_err(&tpl, 0, EVENT_EXIST); } goto error; } diff --git a/kernel/trace/trace_fprobe.c b/kernel/trace/trace_fprobe.c index b40fa59159ac521ef17aa3318db35de5ef491576..00905ac8f212511ca0d8d71c81c= 9a2a28087fd5d 100644 --- a/kernel/trace/trace_fprobe.c +++ b/kernel/trace/trace_fprobe.c @@ -837,26 +837,27 @@ static bool trace_fprobe_has_same_fprobe(struct trace= _fprobe *orig, return false; } =20 -static int append_trace_fprobe(struct trace_fprobe *tf, struct trace_fprob= e *to) +static int append_trace_fprobe(struct trace_fprobe *tf, struct trace_fprob= e *to, + struct trace_probe_log *tpl) { int ret; =20 if (trace_fprobe_is_return(tf) !=3D trace_fprobe_is_return(to) || trace_fprobe_is_tracepoint(tf) !=3D trace_fprobe_is_tracepoint(to)) { - trace_probe_log_set_index(0); - trace_probe_log_err(0, DIFF_PROBE_TYPE); + trace_probe_log_set_index(tpl, 0); + trace_probe_log_err(tpl, 0, DIFF_PROBE_TYPE); return -EEXIST; } ret =3D trace_probe_compare_arg_type(&tf->tp, &to->tp); if (ret) { /* Note that argument starts index =3D 2 */ - trace_probe_log_set_index(ret + 1); - trace_probe_log_err(0, DIFF_ARG_TYPE); + trace_probe_log_set_index(tpl, ret + 1); + trace_probe_log_err(tpl, 0, DIFF_ARG_TYPE); return -EEXIST; } if (trace_fprobe_has_same_fprobe(to, tf)) { - trace_probe_log_set_index(0); - trace_probe_log_err(0, SAME_PROBE); + trace_probe_log_set_index(tpl, 0); + trace_probe_log_err(tpl, 0, SAME_PROBE); return -EEXIST; } =20 @@ -875,7 +876,7 @@ static int append_trace_fprobe(struct trace_fprobe *tf,= struct trace_fprobe *to) } =20 /* Register a trace_probe and probe_event */ -static int register_trace_fprobe(struct trace_fprobe *tf) +static int register_trace_fprobe(struct trace_fprobe *tf, struct trace_pro= be_log *tpl) { struct trace_fprobe *old_tf; int ret; @@ -885,14 +886,14 @@ static int register_trace_fprobe(struct trace_fprobe = *tf) old_tf =3D find_trace_fprobe(trace_probe_name(&tf->tp), trace_probe_group_name(&tf->tp)); if (old_tf) - return append_trace_fprobe(tf, old_tf); + return append_trace_fprobe(tf, old_tf, tpl); =20 /* Register new event */ ret =3D register_fprobe_event(tf); if (ret) { if (ret =3D=3D -EEXIST) { - trace_probe_log_set_index(0); - trace_probe_log_err(0, EVENT_EXIST); + trace_probe_log_set_index(tpl, 0); + trace_probe_log_err(tpl, 0, EVENT_EXIST); } else pr_warn("Failed to register probe event(%d)\n", ret); return ret; @@ -1030,7 +1031,7 @@ static struct notifier_block tracepoint_module_nb =3D= { }; #endif /* CONFIG_MODULES */ =20 -static int parse_symbol_and_return(int argc, const char *argv[], +static int parse_symbol_and_return(struct trace_probe_log *tpl, int argc, = const char *argv[], char **symbol, bool *is_return, bool is_tracepoint) { @@ -1043,7 +1044,7 @@ static int parse_symbol_and_return(int argc, const ch= ar *argv[], if (!is_tracepoint && !strcmp(tmp, "%return")) { *is_return =3D true; } else { - trace_probe_log_err(len, BAD_ADDR_SUFFIX); + trace_probe_log_err(tpl, len, BAD_ADDR_SUFFIX); return -EINVAL; } *symbol =3D kmemdup_nul(argv[1], len, GFP_KERNEL); @@ -1061,7 +1062,7 @@ static int parse_symbol_and_return(int argc, const ch= ar *argv[], tmp++; if (*tmp) { /* find a wrong character. */ - trace_probe_log_err(tmp - *symbol, BAD_TP_NAME); + trace_probe_log_err(tpl, tmp - *symbol, BAD_TP_NAME); kfree(*symbol); *symbol =3D NULL; return -EINVAL; @@ -1073,8 +1074,8 @@ static int parse_symbol_and_return(int argc, const ch= ar *argv[], tmp =3D strstr(argv[i], "$retval"); if (tmp && !isalnum(tmp[7]) && tmp[7] !=3D '_') { if (is_tracepoint) { - trace_probe_log_set_index(i); - trace_probe_log_err(tmp - argv[i], RETVAL_ON_PROBE); + trace_probe_log_set_index(tpl, i); + trace_probe_log_err(tpl, tmp - argv[i], RETVAL_ON_PROBE); kfree(*symbol); *symbol =3D NULL; return -EINVAL; @@ -1089,7 +1090,8 @@ static int parse_symbol_and_return(int argc, const ch= ar *argv[], DEFINE_FREE(module_put, struct module *, if (_T) module_put(_T)) =20 static int trace_fprobe_create_internal(int argc, const char *argv[], - struct traceprobe_parse_context *ctx) + struct traceprobe_parse_context *ctx, + struct trace_probe_log *tpl) { /* * Argument syntax: @@ -1140,24 +1142,24 @@ static int trace_fprobe_create_internal(int argc, c= onst char *argv[], =20 if (argv[0][1] !=3D '\0') { if (argv[0][1] !=3D ':') { - trace_probe_log_set_index(0); - trace_probe_log_err(1, BAD_MAXACT); + trace_probe_log_set_index(tpl, 0); + trace_probe_log_err(tpl, 1, BAD_MAXACT); return -EINVAL; } event =3D &argv[0][2]; } =20 - trace_probe_log_set_index(1); + trace_probe_log_set_index(tpl, 1); =20 /* a symbol(or tracepoint) must be specified */ - ret =3D parse_symbol_and_return(argc, argv, &symbol, &is_return, is_trace= point); + ret =3D parse_symbol_and_return(tpl, argc, argv, &symbol, &is_return, is_= tracepoint); if (ret < 0) return -EINVAL; =20 - trace_probe_log_set_index(0); + trace_probe_log_set_index(tpl, 0); if (event) { ret =3D traceprobe_parse_event_name(&event, &group, gbuf, - event - argv[0]); + event - argv[0], tpl); if (ret) return -EINVAL; } @@ -1191,8 +1193,8 @@ static int trace_fprobe_create_internal(int argc, con= st char *argv[], tpoint =3D TRACEPOINT_STUB; ctx->funcname =3D symbol; } else { - trace_probe_log_set_index(1); - trace_probe_log_err(0, NO_TRACEPOINT); + trace_probe_log_set_index(tpl, 1); + trace_probe_log_err(tpl, 0, NO_TRACEPOINT); return -EINVAL; } } else @@ -1200,7 +1202,7 @@ static int trace_fprobe_create_internal(int argc, con= st char *argv[], =20 argc -=3D 2; argv +=3D 2; new_argv =3D traceprobe_expand_meta_args(argc, argv, &new_argc, - abuf, MAX_BTF_ARGS_LEN, ctx); + abuf, MAX_BTF_ARGS_LEN, ctx, tpl); if (IS_ERR(new_argv)) return PTR_ERR(new_argv); if (new_argv) { @@ -1208,8 +1210,8 @@ static int trace_fprobe_create_internal(int argc, con= st char *argv[], argv =3D new_argv; } if (argc > MAX_TRACE_ARGS) { - trace_probe_log_set_index(2); - trace_probe_log_err(0, TOO_MANY_ARGS); + trace_probe_log_set_index(tpl, 2); + trace_probe_log_err(tpl, 0, TOO_MANY_ARGS); return -E2BIG; } =20 @@ -1229,9 +1231,9 @@ static int trace_fprobe_create_internal(int argc, con= st char *argv[], =20 /* parse arguments */ for (i =3D 0; i < argc; i++) { - trace_probe_log_set_index(i + 2); + trace_probe_log_set_index(tpl, i + 2); ctx->offset =3D 0; - ret =3D traceprobe_parse_probe_arg(&tf->tp, i, argv[i], ctx); + ret =3D traceprobe_parse_probe_arg(&tf->tp, i, argv[i], ctx, tpl); if (ret) return ret; /* This can be -ENOMEM */ } @@ -1240,8 +1242,8 @@ static int trace_fprobe_create_internal(int argc, con= st char *argv[], tf->fp.entry_handler =3D trace_fprobe_entry_handler; tf->fp.entry_data_size =3D traceprobe_get_entry_data_size(&tf->tp); if (ALIGN(tf->fp.entry_data_size, sizeof(long)) > MAX_FPROBE_DATA_SIZE) { - trace_probe_log_set_index(2); - trace_probe_log_err(0, TOO_MANY_EARGS); + trace_probe_log_set_index(tpl, 2); + trace_probe_log_err(tpl, 0, TOO_MANY_EARGS); return -E2BIG; } } @@ -1251,15 +1253,15 @@ static int trace_fprobe_create_internal(int argc, c= onst char *argv[], if (ret < 0) return ret; =20 - ret =3D register_trace_fprobe(tf); + ret =3D register_trace_fprobe(tf, tpl); if (ret) { - trace_probe_log_set_index(1); + trace_probe_log_set_index(tpl, 1); if (ret =3D=3D -EILSEQ) - trace_probe_log_err(0, BAD_INSN_BNDRY); + trace_probe_log_err(tpl, 0, BAD_INSN_BNDRY); else if (ret =3D=3D -ENOENT) - trace_probe_log_err(0, BAD_PROBE_ADDR); + trace_probe_log_err(tpl, 0, BAD_PROBE_ADDR); else if (ret !=3D -ENOMEM && ret !=3D -EEXIST) - trace_probe_log_err(0, FAIL_REG_PROBE); + trace_probe_log_err(tpl, 0, FAIL_REG_PROBE); return -EINVAL; } =20 @@ -1276,10 +1278,12 @@ static int trace_fprobe_create_cb(int argc, const c= har *argv[]) }; int ret; =20 - trace_probe_log_init("trace_fprobe", argc, argv); - ret =3D trace_fprobe_create_internal(argc, argv, &ctx); + struct trace_probe_log tpl =3D trace_probe_log_create( + "trace_fprobe", + argc, + argv); + ret =3D trace_fprobe_create_internal(argc, argv, &ctx, &tpl); traceprobe_finish_parse(&ctx); - trace_probe_log_clear(); return ret; } =20 diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index 2703b96d8990649ebcfeefde0ae1a8b1960659a6..c5ec7ff03d62f480fa7981937ad= b505f0358a61f 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c @@ -591,20 +591,21 @@ static bool trace_kprobe_has_same_kprobe(struct trace= _kprobe *orig, return false; } =20 -static int append_trace_kprobe(struct trace_kprobe *tk, struct trace_kprob= e *to) +static int append_trace_kprobe(struct trace_kprobe *tk, struct trace_kprob= e *to, + struct trace_probe_log *tpl) { int ret; =20 ret =3D trace_probe_compare_arg_type(&tk->tp, &to->tp); if (ret) { /* Note that argument starts index =3D 2 */ - trace_probe_log_set_index(ret + 1); - trace_probe_log_err(0, DIFF_ARG_TYPE); + trace_probe_log_set_index(tpl, ret + 1); + trace_probe_log_err(tpl, 0, DIFF_ARG_TYPE); return -EEXIST; } if (trace_kprobe_has_same_kprobe(to, tk)) { - trace_probe_log_set_index(0); - trace_probe_log_err(0, SAME_PROBE); + trace_probe_log_set_index(tpl, 0); + trace_probe_log_err(tpl, 0, SAME_PROBE); return -EEXIST; } =20 @@ -629,7 +630,7 @@ static int append_trace_kprobe(struct trace_kprobe *tk,= struct trace_kprobe *to) } =20 /* Register a trace_probe and probe_event */ -static int register_trace_kprobe(struct trace_kprobe *tk) +static int register_trace_kprobe(struct trace_kprobe *tk, struct trace_pro= be_log *tpl) { struct trace_kprobe *old_tk; int ret; @@ -640,19 +641,19 @@ static int register_trace_kprobe(struct trace_kprobe = *tk) trace_probe_group_name(&tk->tp)); if (old_tk) { if (trace_kprobe_is_return(tk) !=3D trace_kprobe_is_return(old_tk)) { - trace_probe_log_set_index(0); - trace_probe_log_err(0, DIFF_PROBE_TYPE); + trace_probe_log_set_index(tpl, 0); + trace_probe_log_err(tpl, 0, DIFF_PROBE_TYPE); return -EEXIST; } - return append_trace_kprobe(tk, old_tk); + return append_trace_kprobe(tk, old_tk, tpl); } =20 /* Register new event */ ret =3D register_kprobe_event(tk); if (ret) { if (ret =3D=3D -EEXIST) { - trace_probe_log_set_index(0); - trace_probe_log_err(0, EVENT_EXIST); + trace_probe_log_set_index(tpl, 0); + trace_probe_log_err(tpl, 0, EVENT_EXIST); } else pr_warn("Failed to register probe event(%d)\n", ret); return ret; @@ -834,7 +835,8 @@ static int trace_kprobe_entry_handler(struct kretprobe_= instance *ri, struct pt_regs *regs); =20 static int trace_kprobe_create_internal(int argc, const char *argv[], - struct traceprobe_parse_context *ctx) + struct traceprobe_parse_context *ctx, + struct trace_probe_log *tpl) { /* * Argument syntax: @@ -894,7 +896,7 @@ static int trace_kprobe_create_internal(int argc, const= char *argv[], =20 if (isdigit(argv[0][1])) { if (!is_return) { - trace_probe_log_err(1, BAD_MAXACT_TYPE); + trace_probe_log_err(tpl, 1, BAD_MAXACT_TYPE); return -EINVAL; } if (event) @@ -902,21 +904,21 @@ static int trace_kprobe_create_internal(int argc, con= st char *argv[], else len =3D strlen(&argv[0][1]); if (len > MAX_EVENT_NAME_LEN - 1) { - trace_probe_log_err(1, BAD_MAXACT); + trace_probe_log_err(tpl, 1, BAD_MAXACT); return -EINVAL; } memcpy(buf, &argv[0][1], len); buf[len] =3D '\0'; ret =3D kstrtouint(buf, 0, &maxactive); if (ret || !maxactive) { - trace_probe_log_err(1, BAD_MAXACT); + trace_probe_log_err(tpl, 1, BAD_MAXACT); return -EINVAL; } /* kretprobes instances are iterated over via a list. The * maximum should stay reasonable. */ if (maxactive > KRETPROBE_MAXACTIVE_MAX) { - trace_probe_log_err(1, MAXACT_TOO_BIG); + trace_probe_log_err(tpl, 1, MAXACT_TOO_BIG); return -EINVAL; } } @@ -924,7 +926,7 @@ static int trace_kprobe_create_internal(int argc, const= char *argv[], /* try to parse an address. if that fails, try to read the * input as a symbol. */ if (kstrtoul(argv[1], 0, (unsigned long *)&addr)) { - trace_probe_log_set_index(1); + trace_probe_log_set_index(tpl, 1); /* Check whether uprobe event specified */ if (strchr(argv[1], '/') && strchr(argv[1], ':')) return -ECANCELED; @@ -940,7 +942,7 @@ static int trace_kprobe_create_internal(int argc, const= char *argv[], *tmp =3D '\0'; is_return =3D true; } else { - trace_probe_log_err(tmp - symbol, BAD_ADDR_SUFFIX); + trace_probe_log_err(tpl, tmp - symbol, BAD_ADDR_SUFFIX); return -EINVAL; } } @@ -948,15 +950,15 @@ static int trace_kprobe_create_internal(int argc, con= st char *argv[], /* TODO: support .init module functions */ ret =3D traceprobe_split_symbol_offset(symbol, &offset); if (ret || offset < 0 || offset > UINT_MAX) { - trace_probe_log_err(0, BAD_PROBE_ADDR); + trace_probe_log_err(tpl, 0, BAD_PROBE_ADDR); return -EINVAL; } ret =3D validate_probe_symbol(symbol); if (ret) { if (ret =3D=3D -EADDRNOTAVAIL) - trace_probe_log_err(0, NON_UNIQ_SYMBOL); + trace_probe_log_err(tpl, 0, NON_UNIQ_SYMBOL); else - trace_probe_log_err(0, BAD_PROBE_ADDR); + trace_probe_log_err(tpl, 0, BAD_PROBE_ADDR); return -EINVAL; } if (is_return) @@ -966,15 +968,15 @@ static int trace_kprobe_create_internal(int argc, con= st char *argv[], ctx->flags |=3D TPARG_FL_FENTRY; /* Defer the ENOENT case until register kprobe */ if (ret =3D=3D -EINVAL && is_return) { - trace_probe_log_err(0, BAD_RETPROBE); + trace_probe_log_err(tpl, 0, BAD_RETPROBE); return -EINVAL; } } =20 - trace_probe_log_set_index(0); + trace_probe_log_set_index(tpl, 0); if (event) { ret =3D traceprobe_parse_event_name(&event, &group, gbuf, - event - argv[0]); + event - argv[0], tpl); if (ret) return ret; } @@ -994,7 +996,7 @@ static int trace_kprobe_create_internal(int argc, const= char *argv[], argc -=3D 2; argv +=3D 2; ctx->funcname =3D symbol; new_argv =3D traceprobe_expand_meta_args(argc, argv, &new_argc, - abuf, MAX_BTF_ARGS_LEN, ctx); + abuf, MAX_BTF_ARGS_LEN, ctx, tpl); if (IS_ERR(new_argv)) { ret =3D PTR_ERR(new_argv); new_argv =3D NULL; @@ -1005,8 +1007,8 @@ static int trace_kprobe_create_internal(int argc, con= st char *argv[], argv =3D new_argv; } if (argc > MAX_TRACE_ARGS) { - trace_probe_log_set_index(2); - trace_probe_log_err(0, TOO_MANY_ARGS); + trace_probe_log_set_index(tpl, 2); + trace_probe_log_err(tpl, 0, TOO_MANY_ARGS); return -E2BIG; } =20 @@ -1026,9 +1028,9 @@ static int trace_kprobe_create_internal(int argc, con= st char *argv[], =20 /* parse arguments */ for (i =3D 0; i < argc; i++) { - trace_probe_log_set_index(i + 2); + trace_probe_log_set_index(tpl, i + 2); ctx->offset =3D 0; - ret =3D traceprobe_parse_probe_arg(&tk->tp, i, argv[i], ctx); + ret =3D traceprobe_parse_probe_arg(&tk->tp, i, argv[i], ctx, tpl); if (ret) return ret; /* This can be -ENOMEM */ } @@ -1043,15 +1045,15 @@ static int trace_kprobe_create_internal(int argc, c= onst char *argv[], if (ret < 0) return ret; =20 - ret =3D register_trace_kprobe(tk); + ret =3D register_trace_kprobe(tk, tpl); if (ret) { - trace_probe_log_set_index(1); + trace_probe_log_set_index(tpl, 1); if (ret =3D=3D -EILSEQ) - trace_probe_log_err(0, BAD_INSN_BNDRY); + trace_probe_log_err(tpl, 0, BAD_INSN_BNDRY); else if (ret =3D=3D -ENOENT) - trace_probe_log_err(0, BAD_PROBE_ADDR); + trace_probe_log_err(tpl, 0, BAD_PROBE_ADDR); else if (ret !=3D -ENOMEM && ret !=3D -EEXIST) - trace_probe_log_err(0, FAIL_REG_PROBE); + trace_probe_log_err(tpl, 0, FAIL_REG_PROBE); return ret; } /* @@ -1068,12 +1070,11 @@ static int trace_kprobe_create_cb(int argc, const c= har *argv[]) struct traceprobe_parse_context ctx =3D { .flags =3D TPARG_FL_KERNEL }; int ret; =20 - trace_probe_log_init("trace_kprobe", argc, argv); + struct trace_probe_log tpl =3D trace_probe_log_create("trace_kprobe", arg= c, argv); =20 - ret =3D trace_kprobe_create_internal(argc, argv, &ctx); + ret =3D trace_kprobe_create_internal(argc, argv, &ctx, &tpl); =20 traceprobe_finish_parse(&ctx); - trace_probe_log_clear(); return ret; } =20 diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c index 2eeecb6c95eea55502b83af6775b7b6f0cc5ab94..e16de6a8688d7e6ded5a340e39a= af220e9b2e483 100644 --- a/kernel/trace/trace_probe.c +++ b/kernel/trace/trace_probe.c @@ -153,45 +153,41 @@ static const struct fetch_type *find_fetch_type(const= char *type, unsigned long return NULL; } =20 -static struct trace_probe_log trace_probe_log; - -void trace_probe_log_init(const char *subsystem, int argc, const char **ar= gv) -{ - trace_probe_log.subsystem =3D subsystem; - trace_probe_log.argc =3D argc; - trace_probe_log.argv =3D argv; - trace_probe_log.index =3D 0; -} - -void trace_probe_log_clear(void) +struct trace_probe_log trace_probe_log_create(const char *subsystem, int a= rgc, const char **argv) { - memset(&trace_probe_log, 0, sizeof(trace_probe_log)); + struct trace_probe_log tpl =3D { + .subsystem =3D subsystem, + .argc =3D argc, + .argv =3D argv, + .index =3D 0, + }; + return tpl; } =20 -void trace_probe_log_set_index(int index) +void trace_probe_log_set_index(struct trace_probe_log *tpl, int index) { - trace_probe_log.index =3D index; + tpl->index =3D index; } =20 -void __trace_probe_log_err(int offset, int err_type) +void __trace_probe_log_err(struct trace_probe_log *tpl, int offset, int er= r_type) { char *command, *p; int i, len =3D 0, pos =3D 0; =20 - if (!trace_probe_log.argv) + if (!tpl->argv) return; =20 /* Recalculate the length and allocate buffer */ - for (i =3D 0; i < trace_probe_log.argc; i++) { - if (i =3D=3D trace_probe_log.index) + for (i =3D 0; i < tpl->argc; i++) { + if (i =3D=3D tpl->index) pos =3D len; - len +=3D strlen(trace_probe_log.argv[i]) + 1; + len +=3D strlen(tpl->argv[i]) + 1; } command =3D kzalloc(len, GFP_KERNEL); if (!command) return; =20 - if (trace_probe_log.index >=3D trace_probe_log.argc) { + if (tpl->index >=3D tpl->argc) { /** * Set the error position is next to the last arg + space. * Note that len includes the terminal null and the cursor @@ -203,15 +199,15 @@ void __trace_probe_log_err(int offset, int err_type) =20 /* And make a command string from argv array */ p =3D command; - for (i =3D 0; i < trace_probe_log.argc; i++) { - len =3D strlen(trace_probe_log.argv[i]); - strcpy(p, trace_probe_log.argv[i]); + for (i =3D 0; i < tpl->argc; i++) { + len =3D strlen(tpl->argv[i]); + strcpy(p, tpl->argv[i]); p[len] =3D ' '; p +=3D len + 1; } *(p - 1) =3D '\0'; =20 - tracing_log_err(NULL, trace_probe_log.subsystem, command, + tracing_log_err(NULL, tpl->subsystem, command, trace_probe_err_text, err_type, pos + offset); =20 kfree(command); @@ -240,7 +236,7 @@ int traceprobe_split_symbol_offset(char *symbol, long *= offset) =20 /* @buf must has MAX_EVENT_NAME_LEN size */ int traceprobe_parse_event_name(const char **pevent, const char **pgroup, - char *buf, int offset) + char *buf, int offset, struct trace_probe_log *tpl) { const char *slash, *event =3D *pevent; int len; @@ -251,16 +247,16 @@ int traceprobe_parse_event_name(const char **pevent, = const char **pgroup, =20 if (slash) { if (slash =3D=3D event) { - trace_probe_log_err(offset, NO_GROUP_NAME); + trace_probe_log_err(tpl, offset, NO_GROUP_NAME); return -EINVAL; } if (slash - event + 1 > MAX_EVENT_NAME_LEN) { - trace_probe_log_err(offset, GROUP_TOO_LONG); + trace_probe_log_err(tpl, offset, GROUP_TOO_LONG); return -EINVAL; } strscpy(buf, event, slash - event + 1); if (!is_good_system_name(buf)) { - trace_probe_log_err(offset, BAD_GROUP_NAME); + trace_probe_log_err(tpl, offset, BAD_GROUP_NAME); return -EINVAL; } *pgroup =3D buf; @@ -274,14 +270,14 @@ int traceprobe_parse_event_name(const char **pevent, = const char **pgroup, *pevent =3D NULL; return 0; } - trace_probe_log_err(offset, NO_EVENT_NAME); + trace_probe_log_err(tpl, offset, NO_EVENT_NAME); return -EINVAL; } else if (len >=3D MAX_EVENT_NAME_LEN) { - trace_probe_log_err(offset, EVENT_TOO_LONG); + trace_probe_log_err(tpl, offset, EVENT_TOO_LONG); return -EINVAL; } if (!is_good_name(event)) { - trace_probe_log_err(offset, BAD_EVENT_NAME); + trace_probe_log_err(tpl, offset, BAD_EVENT_NAME); return -EINVAL; } return 0; @@ -350,7 +346,8 @@ static bool btf_type_is_char_array(struct btf *btf, con= st struct btf_type *type) =20 static int check_prepare_btf_string_fetch(char *typename, struct fetch_insn **pcode, - struct traceprobe_parse_context *ctx) + struct traceprobe_parse_context *ctx, + struct trace_probe_log *tpl) { struct btf *btf =3D ctx->btf; =20 @@ -366,7 +363,7 @@ static int check_prepare_btf_string_fetch(char *typenam= e, struct fetch_insn *code =3D *pcode + 1; =20 if (code->op =3D=3D FETCH_OP_END) { - trace_probe_log_err(ctx->offset, TOO_MANY_OPS); + trace_probe_log_err(tpl, ctx->offset, TOO_MANY_OPS); return -E2BIG; } if (typename[0] =3D=3D 'u') @@ -378,7 +375,7 @@ static int check_prepare_btf_string_fetch(char *typenam= e, return 0; } /* Other types are not available for string */ - trace_probe_log_err(ctx->offset, BAD_TYPE4STR); + trace_probe_log_err(tpl, ctx->offset, BAD_TYPE4STR); return -EINVAL; } =20 @@ -491,7 +488,8 @@ static void clear_btf_context(struct traceprobe_parse_c= ontext *ctx) =20 /* Return 1 if the field separater is arrow operator ('->') */ static int split_next_field(char *varname, char **next_field, - struct traceprobe_parse_context *ctx) + struct traceprobe_parse_context *ctx, + struct trace_probe_log *tpl) { char *field; int ret =3D 0; @@ -506,7 +504,7 @@ static int split_next_field(char *varname, char **next_= field, field[0] =3D '\0'; field +=3D 1; } else { - trace_probe_log_err(ctx->offset + field - varname, BAD_HYPHEN); + trace_probe_log_err(tpl, ctx->offset + field - varname, BAD_HYPHEN); return -EINVAL; } *next_field =3D field; @@ -521,7 +519,8 @@ static int split_next_field(char *varname, char **next_= field, */ static int parse_btf_field(char *fieldname, const struct btf_type *type, struct fetch_insn **pcode, struct fetch_insn *end, - struct traceprobe_parse_context *ctx) + struct traceprobe_parse_context *ctx, + struct trace_probe_log *tpl) { struct fetch_insn *code =3D *pcode; const struct btf_member *field; @@ -533,13 +532,13 @@ static int parse_btf_field(char *fieldname, const str= uct btf_type *type, do { /* Outer loop for solving arrow operator ('->') */ if (BTF_INFO_KIND(type->info) !=3D BTF_KIND_PTR) { - trace_probe_log_err(ctx->offset, NO_PTR_STRCT); + trace_probe_log_err(tpl, ctx->offset, NO_PTR_STRCT); return -EINVAL; } /* Convert a struct pointer type to a struct type */ type =3D btf_type_skip_modifiers(ctx->btf, type->type, &tid); if (!type) { - trace_probe_log_err(ctx->offset, BAD_BTF_TID); + trace_probe_log_err(tpl, ctx->offset, BAD_BTF_TID); return -EINVAL; } =20 @@ -547,7 +546,7 @@ static int parse_btf_field(char *fieldname, const struc= t btf_type *type, do { /* Inner loop for solving dot operator ('.') */ next =3D NULL; - is_ptr =3D split_next_field(fieldname, &next, ctx); + is_ptr =3D split_next_field(fieldname, &next, ctx, tpl); if (is_ptr < 0) return is_ptr; =20 @@ -555,11 +554,11 @@ static int parse_btf_field(char *fieldname, const str= uct btf_type *type, field =3D btf_find_struct_member(ctx->btf, type, fieldname, &anon_offs); if (IS_ERR(field)) { - trace_probe_log_err(ctx->offset, BAD_BTF_TID); + trace_probe_log_err(tpl, ctx->offset, BAD_BTF_TID); return PTR_ERR(field); } if (!field) { - trace_probe_log_err(ctx->offset, NO_BTF_FIELD); + trace_probe_log_err(tpl, ctx->offset, NO_BTF_FIELD); return -ENOENT; } /* Add anonymous structure/union offset */ @@ -576,7 +575,7 @@ static int parse_btf_field(char *fieldname, const struc= t btf_type *type, =20 type =3D btf_type_skip_modifiers(ctx->btf, field->type, &tid); if (!type) { - trace_probe_log_err(ctx->offset, BAD_BTF_TID); + trace_probe_log_err(tpl, ctx->offset, BAD_BTF_TID); return -EINVAL; } =20 @@ -585,7 +584,7 @@ static int parse_btf_field(char *fieldname, const struc= t btf_type *type, } while (!is_ptr && fieldname); =20 if (++code =3D=3D end) { - trace_probe_log_err(ctx->offset, TOO_MANY_OPS); + trace_probe_log_err(tpl, ctx->offset, TOO_MANY_OPS); return -EINVAL; } code->op =3D FETCH_OP_DEREF; /* TODO: user deref support */ @@ -603,7 +602,8 @@ static int __store_entry_arg(struct trace_probe *tp, in= t argnum); =20 static int parse_btf_arg(char *varname, struct fetch_insn **pcode, struct fetch_insn *end, - struct traceprobe_parse_context *ctx) + struct traceprobe_parse_context *ctx, + struct trace_probe_log *tpl) { struct fetch_insn *code =3D *pcode; const struct btf_param *params; @@ -615,12 +615,12 @@ static int parse_btf_arg(char *varname, if (WARN_ON_ONCE(!ctx->funcname)) return -EINVAL; =20 - is_ptr =3D split_next_field(varname, &field, ctx); + is_ptr =3D split_next_field(varname, &field, ctx, tpl); if (is_ptr < 0) return is_ptr; if (!is_ptr && field) { /* dot-connected field on an argument is not supported. */ - trace_probe_log_err(ctx->offset + field - varname, + trace_probe_log_err(tpl, ctx->offset + field - varname, NOSUP_DAT_ARG); return -EOPNOTSUPP; } @@ -630,14 +630,14 @@ static int parse_btf_arg(char *varname, /* Check whether the function return type is not void */ if (query_btf_context(ctx) =3D=3D 0) { if (ctx->proto->type =3D=3D 0) { - trace_probe_log_err(ctx->offset, NO_RETVAL); + trace_probe_log_err(tpl, ctx->offset, NO_RETVAL); return -ENOENT; } tid =3D ctx->proto->type; goto found; } if (field) { - trace_probe_log_err(ctx->offset + field - varname, + trace_probe_log_err(tpl, ctx->offset + field - varname, NO_BTF_ENTRY); return -ENOENT; } @@ -647,7 +647,7 @@ static int parse_btf_arg(char *varname, if (!ctx->btf) { ret =3D query_btf_context(ctx); if (ret < 0 || ctx->nr_params =3D=3D 0) { - trace_probe_log_err(ctx->offset, NO_BTF_ENTRY); + trace_probe_log_err(tpl, ctx->offset, NO_BTF_ENTRY); return PTR_ERR(params); } } @@ -676,13 +676,13 @@ static int parse_btf_arg(char *varname, goto found; } } - trace_probe_log_err(ctx->offset, NO_BTFARG); + trace_probe_log_err(tpl, ctx->offset, NO_BTFARG); return -ENOENT; =20 found: type =3D btf_type_skip_modifiers(ctx->btf, tid, &tid); if (!type) { - trace_probe_log_err(ctx->offset, BAD_BTF_TID); + trace_probe_log_err(tpl, ctx->offset, BAD_BTF_TID); return -EINVAL; } /* Initialize the last type information */ @@ -691,7 +691,7 @@ static int parse_btf_arg(char *varname, ctx->last_bitsize =3D 0; if (field) { ctx->offset +=3D field - varname; - return parse_btf_field(field, type, pcode, end, ctx); + return parse_btf_field(field, type, pcode, end, ctx, tpl); } return 0; } @@ -709,7 +709,8 @@ static const struct fetch_type *find_fetch_type_from_bt= f_type( } =20 static int parse_btf_bitfield(struct fetch_insn **pcode, - struct traceprobe_parse_context *ctx) + struct traceprobe_parse_context *ctx, + struct trace_probe_log *tpl) { struct fetch_insn *code =3D *pcode; =20 @@ -718,7 +719,7 @@ static int parse_btf_bitfield(struct fetch_insn **pcode, =20 code++; if (code->op !=3D FETCH_OP_NOP) { - trace_probe_log_err(ctx->offset, TOO_MANY_OPS); + trace_probe_log_err(tpl, ctx->offset, TOO_MANY_OPS); return -EINVAL; } *pcode =3D code; @@ -743,16 +744,18 @@ static int query_btf_context(struct traceprobe_parse_= context *ctx) =20 static int parse_btf_arg(char *varname, struct fetch_insn **pcode, struct fetch_insn *end, - struct traceprobe_parse_context *ctx) + struct traceprobe_parse_context *ctx, + struct trace_probe_log *tpl) { - trace_probe_log_err(ctx->offset, NOSUP_BTFARG); + trace_probe_log_err(tpl, ctx->offset, NOSUP_BTFARG); return -EOPNOTSUPP; } =20 static int parse_btf_bitfield(struct fetch_insn **pcode, - struct traceprobe_parse_context *ctx) + struct traceprobe_parse_context *ctx, + struct trace_probe_log *tpl) { - trace_probe_log_err(ctx->offset, NOSUP_BTFARG); + trace_probe_log_err(tpl, ctx->offset, NOSUP_BTFARG); return -EOPNOTSUPP; } =20 @@ -761,7 +764,8 @@ static int parse_btf_bitfield(struct fetch_insn **pcode, =20 static int check_prepare_btf_string_fetch(char *typename, struct fetch_insn **pcode, - struct traceprobe_parse_context *ctx) + struct traceprobe_parse_context *ctx, + struct trace_probe_log *tpl) { return 0; } @@ -906,7 +910,8 @@ NOKPROBE_SYMBOL(store_trace_entry_data) static int parse_probe_vars(char *orig_arg, const struct fetch_type *t, struct fetch_insn **pcode, struct fetch_insn *end, - struct traceprobe_parse_context *ctx) + struct traceprobe_parse_context *ctx, + struct trace_probe_log *tpl) { struct fetch_insn *code =3D *pcode; int err =3D TP_ERR_BAD_VAR; @@ -940,7 +945,7 @@ static int parse_probe_vars(char *orig_arg, const struc= t fetch_type *t, code->op =3D FETCH_OP_RETVAL; return 0; } - return parse_btf_arg(orig_arg, pcode, end, ctx); + return parse_btf_arg(orig_arg, pcode, end, ctx, tpl); } =20 len =3D str_has_prefix(arg, "stack"); @@ -1012,7 +1017,7 @@ static int parse_probe_vars(char *orig_arg, const str= uct fetch_type *t, #endif =20 inval: - __trace_probe_log_err(ctx->offset, err); + __trace_probe_log_err(tpl, ctx->offset, err); return -EINVAL; } =20 @@ -1027,12 +1032,12 @@ static int str_to_immediate(char *str, unsigned lon= g *imm) return -EINVAL; } =20 -static int __parse_imm_string(char *str, char **pbuf, int offs) +static int __parse_imm_string(char *str, char **pbuf, int offs, struct tra= ce_probe_log *tpl) { size_t len =3D strlen(str); =20 if (str[len - 1] !=3D '"') { - trace_probe_log_err(offs + len, IMMSTR_NO_CLOSE); + trace_probe_log_err(tpl, offs + len, IMMSTR_NO_CLOSE); return -EINVAL; } *pbuf =3D kstrndup(str, len - 1, GFP_KERNEL); @@ -1045,7 +1050,8 @@ static int __parse_imm_string(char *str, char **pbuf,= int offs) static int parse_probe_arg(char *arg, const struct fetch_type *type, struct fetch_insn **pcode, struct fetch_insn *end, - struct traceprobe_parse_context *ctx) + struct traceprobe_parse_context *ctx, + struct trace_probe_log *tpl) { struct fetch_insn *code =3D *pcode; unsigned long param; @@ -1056,13 +1062,13 @@ parse_probe_arg(char *arg, const struct fetch_type = *type, =20 switch (arg[0]) { case '$': - ret =3D parse_probe_vars(arg, type, pcode, end, ctx); + ret =3D parse_probe_vars(arg, type, pcode, end, ctx, tpl); break; =20 case '%': /* named register */ if (ctx->flags & (TPARG_FL_TEVENT | TPARG_FL_FPROBE)) { /* eprobe and fprobe do not handle registers */ - trace_probe_log_err(ctx->offset, BAD_VAR); + trace_probe_log_err(tpl, ctx->offset, BAD_VAR); break; } ret =3D regs_query_register_offset(arg + 1); @@ -1071,14 +1077,14 @@ parse_probe_arg(char *arg, const struct fetch_type = *type, code->param =3D (unsigned int)ret; ret =3D 0; } else - trace_probe_log_err(ctx->offset, BAD_REG_NAME); + trace_probe_log_err(tpl, ctx->offset, BAD_REG_NAME); break; =20 case '@': /* memory, file-offset or symbol */ if (isdigit(arg[1])) { ret =3D kstrtoul(arg + 1, 0, ¶m); if (ret) { - trace_probe_log_err(ctx->offset, BAD_MEM_ADDR); + trace_probe_log_err(tpl, ctx->offset, BAD_MEM_ADDR); break; } /* load address */ @@ -1087,12 +1093,12 @@ parse_probe_arg(char *arg, const struct fetch_type = *type, } else if (arg[1] =3D=3D '+') { /* kprobes don't support file offsets */ if (ctx->flags & TPARG_FL_KERNEL) { - trace_probe_log_err(ctx->offset, FILE_ON_KPROBE); + trace_probe_log_err(tpl, ctx->offset, FILE_ON_KPROBE); return -EINVAL; } ret =3D kstrtol(arg + 2, 0, &offset); if (ret) { - trace_probe_log_err(ctx->offset, BAD_FILE_OFFS); + trace_probe_log_err(tpl, ctx->offset, BAD_FILE_OFFS); break; } =20 @@ -1101,7 +1107,7 @@ parse_probe_arg(char *arg, const struct fetch_type *t= ype, } else { /* uprobes don't support symbols */ if (!(ctx->flags & TPARG_FL_KERNEL)) { - trace_probe_log_err(ctx->offset, SYM_ON_UPROBE); + trace_probe_log_err(tpl, ctx->offset, SYM_ON_UPROBE); return -EINVAL; } /* Preserve symbol for updating */ @@ -1110,7 +1116,7 @@ parse_probe_arg(char *arg, const struct fetch_type *t= ype, if (!code->data) return -ENOMEM; if (++code =3D=3D end) { - trace_probe_log_err(ctx->offset, TOO_MANY_OPS); + trace_probe_log_err(tpl, ctx->offset, TOO_MANY_OPS); return -EINVAL; } code->op =3D FETCH_OP_IMM; @@ -1118,7 +1124,7 @@ parse_probe_arg(char *arg, const struct fetch_type *t= ype, } /* These are fetching from memory */ if (++code =3D=3D end) { - trace_probe_log_err(ctx->offset, TOO_MANY_OPS); + trace_probe_log_err(tpl, ctx->offset, TOO_MANY_OPS); return -EINVAL; } *pcode =3D code; @@ -1137,20 +1143,20 @@ parse_probe_arg(char *arg, const struct fetch_type = *type, arg++; /* Skip '+', because kstrtol() rejects it. */ tmp =3D strchr(arg, '('); if (!tmp) { - trace_probe_log_err(ctx->offset, DEREF_NEED_BRACE); + trace_probe_log_err(tpl, ctx->offset, DEREF_NEED_BRACE); return -EINVAL; } *tmp =3D '\0'; ret =3D kstrtol(arg, 0, &offset); if (ret) { - trace_probe_log_err(ctx->offset, BAD_DEREF_OFFS); + trace_probe_log_err(tpl, ctx->offset, BAD_DEREF_OFFS); break; } ctx->offset +=3D (tmp + 1 - arg) + (arg[0] !=3D '-' ? 1 : 0); arg =3D tmp + 1; tmp =3D strrchr(arg, ')'); if (!tmp) { - trace_probe_log_err(ctx->offset + strlen(arg), + trace_probe_log_err(tpl, ctx->offset + strlen(arg), DEREF_OPEN_BRACE); return -EINVAL; } else { @@ -1158,17 +1164,17 @@ parse_probe_arg(char *arg, const struct fetch_type = *type, int cur_offs =3D ctx->offset; =20 *tmp =3D '\0'; - ret =3D parse_probe_arg(arg, t2, &code, end, ctx); + ret =3D parse_probe_arg(arg, t2, &code, end, ctx, tpl); if (ret) break; ctx->offset =3D cur_offs; if (code->op =3D=3D FETCH_OP_COMM || code->op =3D=3D FETCH_OP_DATA) { - trace_probe_log_err(ctx->offset, COMM_CANT_DEREF); + trace_probe_log_err(tpl, ctx->offset, COMM_CANT_DEREF); return -EINVAL; } if (++code =3D=3D end) { - trace_probe_log_err(ctx->offset, TOO_MANY_OPS); + trace_probe_log_err(tpl, ctx->offset, TOO_MANY_OPS); return -EINVAL; } *pcode =3D code; @@ -1181,7 +1187,7 @@ parse_probe_arg(char *arg, const struct fetch_type *t= ype, break; case '\\': /* Immediate value */ if (arg[1] =3D=3D '"') { /* Immediate string */ - ret =3D __parse_imm_string(arg + 2, &tmp, ctx->offset + 2); + ret =3D __parse_imm_string(arg + 2, &tmp, ctx->offset + 2, tpl); if (ret) break; code->op =3D FETCH_OP_DATA; @@ -1189,7 +1195,7 @@ parse_probe_arg(char *arg, const struct fetch_type *t= ype, } else { ret =3D str_to_immediate(arg + 1, &code->immediate); if (ret) - trace_probe_log_err(ctx->offset + 1, BAD_IMM); + trace_probe_log_err(tpl, ctx->offset + 1, BAD_IMM); else code->op =3D FETCH_OP_IMM; } @@ -1198,16 +1204,16 @@ parse_probe_arg(char *arg, const struct fetch_type = *type, if (isalpha(arg[0]) || arg[0] =3D=3D '_') { /* BTF variable */ if (!tparg_is_function_entry(ctx->flags) && !tparg_is_function_return(ctx->flags)) { - trace_probe_log_err(ctx->offset, NOSUP_BTFARG); + trace_probe_log_err(tpl, ctx->offset, NOSUP_BTFARG); return -EINVAL; } - ret =3D parse_btf_arg(arg, pcode, end, ctx); + ret =3D parse_btf_arg(arg, pcode, end, ctx, tpl); break; } } if (!ret && code->op =3D=3D FETCH_OP_NOP) { /* Parsed, but do not find fetch method */ - trace_probe_log_err(ctx->offset, BAD_FETCH_ARG); + trace_probe_log_err(tpl, ctx->offset, BAD_FETCH_ARG); ret =3D -EINVAL; } return ret; @@ -1250,7 +1256,8 @@ static int __parse_bitfield_probe_arg(const char *bf, =20 /* Split type part from @arg and return it. */ static char *parse_probe_arg_type(char *arg, struct probe_arg *parg, - struct traceprobe_parse_context *ctx) + struct traceprobe_parse_context *ctx, + struct trace_probe_log *tpl) { char *t =3D NULL, *t2, *t3; int offs; @@ -1265,22 +1272,22 @@ static char *parse_probe_arg_type(char *arg, struct= probe_arg *parg, if (!t3) { offs =3D t2 + strlen(t2) - arg; =20 - trace_probe_log_err(ctx->offset + offs, + trace_probe_log_err(tpl, ctx->offset + offs, ARRAY_NO_CLOSE); return ERR_PTR(-EINVAL); } else if (t3[1] !=3D '\0') { - trace_probe_log_err(ctx->offset + t3 + 1 - arg, + trace_probe_log_err(tpl, ctx->offset + t3 + 1 - arg, BAD_ARRAY_SUFFIX); return ERR_PTR(-EINVAL); } *t3 =3D '\0'; if (kstrtouint(t2, 0, &parg->count) || !parg->count) { - trace_probe_log_err(ctx->offset + t2 - arg, + trace_probe_log_err(tpl, ctx->offset + t2 - arg, BAD_ARRAY_NUM); return ERR_PTR(-EINVAL); } if (parg->count > MAX_ARRAY_LEN) { - trace_probe_log_err(ctx->offset + t2 - arg, + trace_probe_log_err(tpl, ctx->offset + t2 - arg, ARRAY_TOO_BIG); return ERR_PTR(-EINVAL); } @@ -1297,7 +1304,7 @@ static char *parse_probe_arg_type(char *arg, struct p= robe_arg *parg, strncmp(arg, "\\\"", 2) =3D=3D 0)) { /* The type of $comm must be "string", and not an array type. */ if (parg->count || (t && strcmp(t, "string"))) { - trace_probe_log_err(ctx->offset + offs, NEED_STRING_TYPE); + trace_probe_log_err(tpl, ctx->offset + offs, NEED_STRING_TYPE); return ERR_PTR(-EINVAL); } parg->type =3D find_fetch_type("string", ctx->flags); @@ -1305,7 +1312,7 @@ static char *parse_probe_arg_type(char *arg, struct p= robe_arg *parg, parg->type =3D find_fetch_type(t, ctx->flags); =20 if (!parg->type) { - trace_probe_log_err(ctx->offset + offs, BAD_TYPE); + trace_probe_log_err(tpl, ctx->offset + offs, BAD_TYPE); return ERR_PTR(-EINVAL); } =20 @@ -1317,7 +1324,8 @@ static int finalize_fetch_insn(struct fetch_insn *cod= e, struct probe_arg *parg, char *type, int type_offset, - struct traceprobe_parse_context *ctx) + struct traceprobe_parse_context *ctx, + struct trace_probe_log *tpl) { struct fetch_insn *scode; int ret; @@ -1329,7 +1337,7 @@ static int finalize_fetch_insn(struct fetch_insn *cod= e, if (code->op !=3D FETCH_OP_REG && code->op !=3D FETCH_OP_STACK && code->op !=3D FETCH_OP_RETVAL && code->op !=3D FETCH_OP_ARG && code->op !=3D FETCH_OP_DEREF && code->op !=3D FETCH_OP_TP_ARG) { - trace_probe_log_err(ctx->offset + type_offset, + trace_probe_log_err(tpl, ctx->offset + type_offset, BAD_SYMSTRING); return -EINVAL; } @@ -1337,7 +1345,7 @@ static int finalize_fetch_insn(struct fetch_insn *cod= e, if (code->op !=3D FETCH_OP_DEREF && code->op !=3D FETCH_OP_UDEREF && code->op !=3D FETCH_OP_IMM && code->op !=3D FETCH_OP_COMM && code->op !=3D FETCH_OP_DATA && code->op !=3D FETCH_OP_TP_ARG) { - trace_probe_log_err(ctx->offset + type_offset, + trace_probe_log_err(tpl, ctx->offset + type_offset, BAD_STRING); return -EINVAL; } @@ -1357,7 +1365,7 @@ static int finalize_fetch_insn(struct fetch_insn *cod= e, */ code++; if (code->op !=3D FETCH_OP_NOP) { - trace_probe_log_err(ctx->offset, TOO_MANY_OPS); + trace_probe_log_err(tpl, ctx->offset, TOO_MANY_OPS); return -EINVAL; } } @@ -1381,7 +1389,7 @@ static int finalize_fetch_insn(struct fetch_insn *cod= e, } else { code++; if (code->op !=3D FETCH_OP_NOP) { - trace_probe_log_err(ctx->offset, TOO_MANY_OPS); + trace_probe_log_err(tpl, ctx->offset, TOO_MANY_OPS); return -E2BIG; } code->op =3D FETCH_OP_ST_RAW; @@ -1396,13 +1404,13 @@ static int finalize_fetch_insn(struct fetch_insn *c= ode, /* Bitfield needs a special fetch_insn. */ ret =3D __parse_bitfield_probe_arg(type, parg->type, &code); if (ret) { - trace_probe_log_err(ctx->offset + type_offset, BAD_BITFIELD); + trace_probe_log_err(tpl, ctx->offset + type_offset, BAD_BITFIELD); return ret; } } else if (IS_ENABLED(CONFIG_PROBE_EVENTS_BTF_ARGS) && ctx->last_type) { /* If user not specified the type, try parsing BTF bitfield. */ - ret =3D parse_btf_bitfield(&code, ctx); + ret =3D parse_btf_bitfield(&code, ctx, tpl); if (ret) return ret; } @@ -1412,12 +1420,12 @@ static int finalize_fetch_insn(struct fetch_insn *c= ode, if (scode->op !=3D FETCH_OP_ST_MEM && scode->op !=3D FETCH_OP_ST_STRING && scode->op !=3D FETCH_OP_ST_USTRING) { - trace_probe_log_err(ctx->offset + type_offset, BAD_STRING); + trace_probe_log_err(tpl, ctx->offset + type_offset, BAD_STRING); return -EINVAL; } code++; if (code->op !=3D FETCH_OP_NOP) { - trace_probe_log_err(ctx->offset, TOO_MANY_OPS); + trace_probe_log_err(tpl, ctx->offset, TOO_MANY_OPS); return -E2BIG; } code->op =3D FETCH_OP_LP_ARRAY; @@ -1434,7 +1442,8 @@ static int finalize_fetch_insn(struct fetch_insn *cod= e, /* String length checking wrapper */ static int traceprobe_parse_probe_arg_body(const char *argv, ssize_t *size, struct probe_arg *parg, - struct traceprobe_parse_context *ctx) + struct traceprobe_parse_context *ctx, + struct trace_probe_log *tpl) { struct fetch_insn *code, *tmp =3D NULL; char *type, *arg __free(kfree) =3D NULL; @@ -1442,10 +1451,10 @@ static int traceprobe_parse_probe_arg_body(const ch= ar *argv, ssize_t *size, =20 len =3D strlen(argv); if (len > MAX_ARGSTR_LEN) { - trace_probe_log_err(ctx->offset, ARG_TOO_LONG); + trace_probe_log_err(tpl, ctx->offset, ARG_TOO_LONG); return -E2BIG; } else if (len =3D=3D 0) { - trace_probe_log_err(ctx->offset, NO_ARG_BODY); + trace_probe_log_err(tpl, ctx->offset, NO_ARG_BODY); return -EINVAL; } =20 @@ -1457,7 +1466,7 @@ static int traceprobe_parse_probe_arg_body(const char= *argv, ssize_t *size, if (!parg->comm) return -ENOMEM; =20 - type =3D parse_probe_arg_type(arg, parg, ctx); + type =3D parse_probe_arg_type(arg, parg, ctx, tpl); if (IS_ERR(type)) return PTR_ERR(type); =20 @@ -1468,7 +1477,7 @@ static int traceprobe_parse_probe_arg_body(const char= *argv, ssize_t *size, =20 ctx->last_type =3D NULL; ret =3D parse_probe_arg(arg, parg->type, &code, &code[FETCH_INSN_MAX - 1], - ctx); + ctx, tpl); if (ret < 0) goto fail; =20 @@ -1478,7 +1487,7 @@ static int traceprobe_parse_probe_arg_body(const char= *argv, ssize_t *size, if (!type) { parg->type =3D find_fetch_type_from_btf_type(ctx); } else if (strstr(type, "string")) { - ret =3D check_prepare_btf_string_fetch(type, &code, ctx); + ret =3D check_prepare_btf_string_fetch(type, &code, ctx, tpl); if (ret) goto fail; } @@ -1497,7 +1506,7 @@ static int traceprobe_parse_probe_arg_body(const char= *argv, ssize_t *size, parg->count); } =20 - ret =3D finalize_fetch_insn(code, parg, type, type ? type - arg : 0, ctx); + ret =3D finalize_fetch_insn(code, parg, type, type ? type - arg : 0, ctx,= tpl); if (ret < 0) goto fail; =20 @@ -1568,7 +1577,8 @@ static char *generate_probe_arg_name(const char *arg,= int idx) } =20 int traceprobe_parse_probe_arg(struct trace_probe *tp, int i, const char *= arg, - struct traceprobe_parse_context *ctx) + struct traceprobe_parse_context *ctx, + struct trace_probe_log *tpl) { struct probe_arg *parg =3D &tp->args[i]; const char *body; @@ -1577,10 +1587,10 @@ int traceprobe_parse_probe_arg(struct trace_probe *= tp, int i, const char *arg, body =3D strchr(arg, '=3D'); if (body) { if (body - arg > MAX_ARG_NAME_LEN) { - trace_probe_log_err(0, ARG_NAME_TOO_LONG); + trace_probe_log_err(tpl, 0, ARG_NAME_TOO_LONG); return -EINVAL; } else if (body =3D=3D arg) { - trace_probe_log_err(0, NO_ARG_NAME); + trace_probe_log_err(tpl, 0, NO_ARG_NAME); return -EINVAL; } parg->name =3D kmemdup_nul(arg, body - arg, GFP_KERNEL); @@ -1593,16 +1603,16 @@ int traceprobe_parse_probe_arg(struct trace_probe *= tp, int i, const char *arg, return -ENOMEM; =20 if (!is_good_name(parg->name)) { - trace_probe_log_err(0, BAD_ARG_NAME); + trace_probe_log_err(tpl, 0, BAD_ARG_NAME); return -EINVAL; } if (traceprobe_conflict_field_name(parg->name, tp->args, i)) { - trace_probe_log_err(0, USED_ARG_NAME); + trace_probe_log_err(tpl, 0, USED_ARG_NAME); return -EINVAL; } ctx->offset =3D body - arg; /* Parse fetch argument */ - return traceprobe_parse_probe_arg_body(body, &tp->size, parg, ctx); + return traceprobe_parse_probe_arg_body(body, &tp->size, parg, ctx, tpl); } =20 void traceprobe_free_probe_arg(struct probe_arg *arg) @@ -1622,17 +1632,17 @@ void traceprobe_free_probe_arg(struct probe_arg *ar= g) } =20 static int argv_has_var_arg(int argc, const char *argv[], int *args_idx, - struct traceprobe_parse_context *ctx) + struct traceprobe_parse_context *ctx, struct trace_probe_log *tpl) { int i, found =3D 0; =20 for (i =3D 0; i < argc; i++) if (str_has_prefix(argv[i], "$arg")) { - trace_probe_log_set_index(i + 2); + trace_probe_log_set_index(tpl, i + 2); =20 if (!tparg_is_function_entry(ctx->flags) && !tparg_is_function_return(ctx->flags)) { - trace_probe_log_err(0, NOFENTRY_ARGS); + trace_probe_log_err(tpl, 0, NOFENTRY_ARGS); return -EINVAL; } =20 @@ -1642,12 +1652,12 @@ static int argv_has_var_arg(int argc, const char *a= rgv[], int *args_idx, } =20 if (argv[i][4] !=3D '*') { - trace_probe_log_err(0, BAD_VAR); + trace_probe_log_err(tpl, 0, BAD_VAR); return -EINVAL; } =20 if (*args_idx >=3D 0 && *args_idx < argc) { - trace_probe_log_err(0, DOUBLE_ARGS); + trace_probe_log_err(tpl, 0, DOUBLE_ARGS); return -EINVAL; } found =3D 1; @@ -1659,23 +1669,24 @@ static int argv_has_var_arg(int argc, const char *a= rgv[], int *args_idx, =20 static int sprint_nth_btf_arg(int idx, const char *type, char *buf, int bufsize, - struct traceprobe_parse_context *ctx) + struct traceprobe_parse_context *ctx, + struct trace_probe_log *tpl) { const char *name; int ret; =20 if (idx >=3D ctx->nr_params) { - trace_probe_log_err(0, NO_BTFARG); + trace_probe_log_err(tpl, 0, NO_BTFARG); return -ENOENT; } name =3D btf_name_by_offset(ctx->btf, ctx->params[idx].name_off); if (!name) { - trace_probe_log_err(0, NO_BTF_ENTRY); + trace_probe_log_err(tpl, 0, NO_BTF_ENTRY); return -ENOENT; } ret =3D snprintf(buf, bufsize, "%s%s", name, type); if (ret >=3D bufsize) { - trace_probe_log_err(0, ARGS_2LONG); + trace_probe_log_err(tpl, 0, ARGS_2LONG); return -E2BIG; } return ret; @@ -1684,13 +1695,14 @@ static int sprint_nth_btf_arg(int idx, const char *= type, /* Return new_argv which must be freed after use */ const char **traceprobe_expand_meta_args(int argc, const char *argv[], int *new_argc, char *buf, int bufsize, - struct traceprobe_parse_context *ctx) + struct traceprobe_parse_context *ctx, + struct trace_probe_log *tpl) { const struct btf_param *params =3D NULL; int i, j, n, used, ret, args_idx =3D -1; const char **new_argv __free(kfree) =3D NULL; =20 - ret =3D argv_has_var_arg(argc, argv, &args_idx, ctx); + ret =3D argv_has_var_arg(argc, argv, &args_idx, ctx, tpl); if (ret < 0) return ERR_PTR(ret); =20 @@ -1703,7 +1715,7 @@ const char **traceprobe_expand_meta_args(int argc, co= nst char *argv[], if (ret < 0 || ctx->nr_params =3D=3D 0) { if (args_idx !=3D -1) { /* $arg* requires BTF info */ - trace_probe_log_err(0, NOSUP_BTFARG); + trace_probe_log_err(tpl, 0, NOSUP_BTFARG); return (const char **)params; } *new_argc =3D argc; @@ -1721,11 +1733,11 @@ const char **traceprobe_expand_meta_args(int argc, = const char *argv[], =20 used =3D 0; for (i =3D 0, j =3D 0; i < argc; i++) { - trace_probe_log_set_index(i + 2); + trace_probe_log_set_index(tpl, i + 2); if (i =3D=3D args_idx) { for (n =3D 0; n < ctx->nr_params; n++) { ret =3D sprint_nth_btf_arg(n, "", buf + used, - bufsize - used, ctx); + bufsize - used, ctx, tpl); if (ret < 0) return ERR_PTR(ret); =20 @@ -1740,12 +1752,12 @@ const char **traceprobe_expand_meta_args(int argc, = const char *argv[], =20 n =3D simple_strtoul(argv[i] + 4, &type, 10); if (type && !(*type =3D=3D ':' || *type =3D=3D '\0')) { - trace_probe_log_err(0, BAD_VAR); + trace_probe_log_err(tpl, 0, BAD_VAR); return ERR_PTR(-ENOENT); } /* Note: $argN starts from $arg1 */ ret =3D sprint_nth_btf_arg(n - 1, type, buf + used, - bufsize - used, ctx); + bufsize - used, ctx, tpl); if (ret < 0) return ERR_PTR(ret); new_argv[j++] =3D buf + used; diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h index 854e5668f5ee5ab4e489ca6c88f4260516dc1cbe..158ce3a436aaf5a4da5f81320e6= 9bf321d72f4c3 100644 --- a/kernel/trace/trace_probe.h +++ b/kernel/trace/trace_probe.h @@ -422,12 +422,16 @@ struct traceprobe_parse_context { int offset; }; =20 +struct trace_probe_log; + extern int traceprobe_parse_probe_arg(struct trace_probe *tp, int i, const char *argv, - struct traceprobe_parse_context *ctx); + struct traceprobe_parse_context *ctx, + struct trace_probe_log *tpl); const char **traceprobe_expand_meta_args(int argc, const char *argv[], int *new_argc, char *buf, int bufsize, - struct traceprobe_parse_context *ctx); + struct traceprobe_parse_context *ctx, + struct trace_probe_log *tpl); extern int traceprobe_expand_dentry_args(int argc, const char *argv[], cha= r **buf); =20 extern int traceprobe_update_arg(struct probe_arg *arg); @@ -441,7 +445,7 @@ void traceprobe_finish_parse(struct traceprobe_parse_co= ntext *ctx); =20 extern int traceprobe_split_symbol_offset(char *symbol, long *offset); int traceprobe_parse_event_name(const char **pevent, const char **pgroup, - char *buf, int offset); + char *buf, int offset, struct trace_probe_log *tpl); =20 enum probe_print_type { PROBE_PRINT_NORMAL, @@ -563,13 +567,12 @@ struct trace_probe_log { int index; }; =20 -void trace_probe_log_init(const char *subsystem, int argc, const char **ar= gv); -void trace_probe_log_set_index(int index); -void trace_probe_log_clear(void); -void __trace_probe_log_err(int offset, int err); +struct trace_probe_log trace_probe_log_create(const char *subsystem, int a= rgc, const char **argv); +void trace_probe_log_set_index(struct trace_probe_log *tpl, int index); +void __trace_probe_log_err(struct trace_probe_log *tpl, int offset, int er= r); =20 -#define trace_probe_log_err(offs, err) \ - __trace_probe_log_err(offs, TP_ERR_##err) +#define trace_probe_log_err(tpl, offs, err) \ + __trace_probe_log_err(tpl, offs, TP_ERR_##err) =20 struct uprobe_dispatch_data { struct trace_uprobe *tu; diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c index 3386439ec9f674392aeaaca632b0e13ba15248ef..d00b16256f29e820c4ba21fb101= b843a99624c6b 100644 --- a/kernel/trace/trace_uprobe.c +++ b/kernel/trace/trace_uprobe.c @@ -441,20 +441,21 @@ static bool trace_uprobe_has_same_uprobe(struct trace= _uprobe *orig, return false; } =20 -static int append_trace_uprobe(struct trace_uprobe *tu, struct trace_uprob= e *to) +static int append_trace_uprobe(struct trace_probe_log *tpl, struct trace_u= probe *tu, + struct trace_uprobe *to) { int ret; =20 ret =3D trace_probe_compare_arg_type(&tu->tp, &to->tp); if (ret) { /* Note that argument starts index =3D 2 */ - trace_probe_log_set_index(ret + 1); - trace_probe_log_err(0, DIFF_ARG_TYPE); + trace_probe_log_set_index(tpl, ret + 1); + trace_probe_log_err(tpl, 0, DIFF_ARG_TYPE); return -EEXIST; } if (trace_uprobe_has_same_uprobe(to, tu)) { - trace_probe_log_set_index(0); - trace_probe_log_err(0, SAME_PROBE); + trace_probe_log_set_index(tpl, 0); + trace_probe_log_err(tpl, 0, SAME_PROBE); return -EEXIST; } =20 @@ -493,7 +494,7 @@ static int validate_ref_ctr_offset(struct trace_uprobe = *new) } =20 /* Register a trace_uprobe and probe_event */ -static int register_trace_uprobe(struct trace_uprobe *tu) +static int register_trace_uprobe(struct trace_probe_log *tpl, struct trace= _uprobe *tu) { struct trace_uprobe *old_tu; int ret; @@ -509,18 +510,18 @@ static int register_trace_uprobe(struct trace_uprobe = *tu) trace_probe_group_name(&tu->tp)); if (old_tu) { if (is_ret_probe(tu) !=3D is_ret_probe(old_tu)) { - trace_probe_log_set_index(0); - trace_probe_log_err(0, DIFF_PROBE_TYPE); + trace_probe_log_set_index(tpl, 0); + trace_probe_log_err(tpl, 0, DIFF_PROBE_TYPE); return -EEXIST; } - return append_trace_uprobe(tu, old_tu); + return append_trace_uprobe(tpl, tu, old_tu); } =20 ret =3D register_uprobe_event(tu); if (ret) { if (ret =3D=3D -EEXIST) { - trace_probe_log_set_index(0); - trace_probe_log_err(0, EVENT_EXIST); + trace_probe_log_set_index(tpl, 0); + trace_probe_log_err(tpl, 0, EVENT_EXIST); } else pr_warn("Failed to register probe event(%d)\n", ret); return ret; @@ -563,11 +564,11 @@ static int __trace_uprobe_create(int argc, const char= **argv) if (argc < 2) return -ECANCELED; =20 - trace_probe_log_init("trace_uprobe", argc, argv); + struct trace_probe_log tpl =3D trace_probe_log_create("trace_uprobe", arg= c, argv); =20 if (argc - 2 > MAX_TRACE_ARGS) { - trace_probe_log_set_index(2); - trace_probe_log_err(0, TOO_MANY_ARGS); + trace_probe_log_set_index(&tpl, 2); + trace_probe_log_err(&tpl, 0, TOO_MANY_ARGS); return -E2BIG; } =20 @@ -588,18 +589,17 @@ static int __trace_uprobe_create(int argc, const char= **argv) return -ECANCELED; } =20 - trace_probe_log_set_index(1); /* filename is the 2nd argument */ + trace_probe_log_set_index(&tpl, 1); /* filename is the 2nd argument */ =20 *arg++ =3D '\0'; ret =3D kern_path(filename, LOOKUP_FOLLOW, &path); if (ret) { - trace_probe_log_err(0, FILE_NOT_FOUND); + trace_probe_log_err(&tpl, 0, FILE_NOT_FOUND); kfree(filename); - trace_probe_log_clear(); return ret; } if (!d_is_reg(path.dentry)) { - trace_probe_log_err(0, NO_REGULAR_FILE); + trace_probe_log_err(&tpl, 0, NO_REGULAR_FILE); ret =3D -EINVAL; goto fail_address_parse; } @@ -611,12 +611,12 @@ static int __trace_uprobe_create(int argc, const char= **argv) if (!rctr_end) { ret =3D -EINVAL; rctr_end =3D rctr + strlen(rctr); - trace_probe_log_err(rctr_end - filename, + trace_probe_log_err(&tpl, rctr_end - filename, REFCNT_OPEN_BRACE); goto fail_address_parse; } else if (rctr_end[1] !=3D '\0') { ret =3D -EINVAL; - trace_probe_log_err(rctr_end + 1 - filename, + trace_probe_log_err(&tpl, rctr_end + 1 - filename, BAD_REFCNT_SUFFIX); goto fail_address_parse; } @@ -625,7 +625,7 @@ static int __trace_uprobe_create(int argc, const char *= *argv) *rctr_end =3D '\0'; ret =3D kstrtoul(rctr, 0, &ref_ctr_offset); if (ret) { - trace_probe_log_err(rctr - filename, BAD_REFCNT); + trace_probe_log_err(&tpl, rctr - filename, BAD_REFCNT); goto fail_address_parse; } } @@ -637,7 +637,7 @@ static int __trace_uprobe_create(int argc, const char *= *argv) *tmp =3D '\0'; is_return =3D true; } else { - trace_probe_log_err(tmp - filename, BAD_ADDR_SUFFIX); + trace_probe_log_err(&tpl, tmp - filename, BAD_ADDR_SUFFIX); ret =3D -EINVAL; goto fail_address_parse; } @@ -646,15 +646,15 @@ static int __trace_uprobe_create(int argc, const char= **argv) /* Parse uprobe offset. */ ret =3D kstrtoul(arg, 0, &offset); if (ret) { - trace_probe_log_err(arg - filename, BAD_UPROBE_OFFS); + trace_probe_log_err(&tpl, arg - filename, BAD_UPROBE_OFFS); goto fail_address_parse; } =20 /* setup a probe */ - trace_probe_log_set_index(0); + trace_probe_log_set_index(&tpl, 0); if (event) { ret =3D traceprobe_parse_event_name(&event, &group, gbuf, - event - argv[0]); + event - argv[0], &tpl); if (ret) goto fail_address_parse; } @@ -699,8 +699,8 @@ static int __trace_uprobe_create(int argc, const char *= *argv) .flags =3D (is_return ? TPARG_FL_RETURN : 0) | TPARG_FL_USER, }; =20 - trace_probe_log_set_index(i + 2); - ret =3D traceprobe_parse_probe_arg(&tu->tp, i, argv[i], &ctx); + trace_probe_log_set_index(&tpl, i + 2); + ret =3D traceprobe_parse_probe_arg(&tu->tp, i, argv[i], &ctx, &tpl); traceprobe_finish_parse(&ctx); if (ret) goto error; @@ -711,18 +711,16 @@ static int __trace_uprobe_create(int argc, const char= **argv) if (ret < 0) goto error; =20 - ret =3D register_trace_uprobe(tu); + ret =3D register_trace_uprobe(&tpl, tu); if (!ret) goto out; =20 error: free_trace_uprobe(tu); out: - trace_probe_log_clear(); return ret; =20 fail_address_parse: - trace_probe_log_clear(); path_put(&path); kfree(filename); =20 --- base-commit: a33b5a08cbbdd7aadff95f40cbb45ab86841679e change-id: 20250420-fix-trace-probe-log-race-cc89d8e5fb15 Best regards, --=20 Paul Cacheux