From patchwork Tue Aug 22 16:26:02 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Masami Hiramatsu (Google)" X-Patchwork-Id: 136588 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:b82d:0:b0:3f2:4152:657d with SMTP id z13csp3807819vqi; Tue, 22 Aug 2023 11:19:21 -0700 (PDT) X-Google-Smtp-Source: AGHT+IHYtWeyNUJR/84X4cqES7/bh8/bDGI+ys6uKr+Y8m1P9E8ptzx4AAUr6Tbi4ENoVHdQaO+V X-Received: by 2002:a17:90b:90b:b0:269:2195:c322 with SMTP id bo11-20020a17090b090b00b002692195c322mr7593192pjb.41.1692728361060; Tue, 22 Aug 2023 11:19:21 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1692728361; cv=none; d=google.com; s=arc-20160816; b=WeP+kaagFITs+sRxy4Ky3CY/4W5wCyErESHa+yPhloD0r2SNLgf02GK/X16fO9keE7 8LljRc5k7UD5qgUTVpX8XaSTouKtHZaX9dFpSL2GGHE3D8sw86Q6h7LBFekyYmZNgx37 O735ZbT0qyAa027FVqIp33mIulLYCuH/CwFPBt2t2lAR7hd/vc1we5H8bJwjSEdIO1hx 3DEJRq8yXEMbqigO11pPWJISoJWyV1YsmnUM/OPf1XuMazWGOJ7FpdbQ2hrtFes4eE0X xRUoOpZaPlPWwrlCnklQj1HwnXBvCgsu8+EjdO6xUqdHgnTPCqTf8LXRHfPNKn1ii0oZ nJvg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=gFvAH2/zRcC8XxlydGIqvKVXy4WGkvh/pRWOlxTg24Y=; fh=raxTTJvC+dSJYbgfX5JG5gvrVjxTZXczN0HF8iDayLY=; b=1IDQClIV/pu9oGVwWtPfQDuSzl5guxvM0fx6G+LhZgYdW09fH7Dgf4XvnFvxutP1Wv uNXgDlvtY5DUZs8Id9bgpnrTMqMFBBVaUYV8vZ+NUYRBCqtySx6l6oBmKd18fdQxU3bc CB1k7jDAbJoMurOlxfUjyS/I+Gly2oJLgLhVgzjXlMWw/WXcyF96Yxqcbldmdg589++S BfA03s1qEX4dbVXhbpuNmssKd1p15REcEk2fgkmEIPcLVIeHuILTmPQCun/BDAMrz6jz 6S8knXnr0ejW5IWIR2XG8NP4PzIIl458dXVF2gohzSCjL6kBoBkGOkzq2UtlDKNZlc8X f6PQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b="Cnr1S/Sy"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net. [2620:137:e000::1:18]) by mx.google.com with ESMTPS id z16-20020a656650000000b005694a49d062si5534404pgv.314.2023.08.22.11.19.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 22 Aug 2023 11:19:21 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:18 as permitted sender) client-ip=2620:137:e000::1:18; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b="Cnr1S/Sy"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id E0F5F36488; Tue, 22 Aug 2023 10:22:50 -0700 (PDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237709AbjHVQ0M (ORCPT + 99 others); Tue, 22 Aug 2023 12:26:12 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37346 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237665AbjHVQ0M (ORCPT ); Tue, 22 Aug 2023 12:26:12 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2798FCEF; Tue, 22 Aug 2023 09:26:08 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id B44B265A54; Tue, 22 Aug 2023 16:26:07 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 37C10C433C8; Tue, 22 Aug 2023 16:26:05 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1692721567; bh=M0yvt9XhZlKteG4rq6911+5kqkZiiyrV8Vdh/k3iy5w=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Cnr1S/Sy+0F8FIgeXlSiDjs0zBxioLjRU8WEycgszF7j8sH3oAV19R6G/LCSqP5MX bq0bNyiiZInyYvTzj5cbMQ358j/IzLo6XaImnUW71BV0tyknHqFTG8NTczk9gwr7hH QZKVkYVzg5dHAySTy6lpfkkb1gtqYhEA2eo8UoggUwy8+4LuQ8x647hWn+EyMG9iIp AWql+EFY8AmMU2NM520W3qAfpzxcnnu+jM8h5mGqkS0DuGNpXjNoOIDfJbSd2iawVB ee8y5q1hQQKAJlnLtP6wKxsjVzsUnhnesHIO8WwFm+etWOrfhyMGrY+9VmsFiUajZM ShenasIwP0G7g== From: "Masami Hiramatsu (Google)" To: linux-trace-kernel@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Steven Rostedt , mhiramat@kernel.org, Martin KaFai Lau , bpf@vger.kernel.org, Sven Schnelle , Alexei Starovoitov Subject: [PATCH v6 3/9] tracing/probes: Add a function to search a member of a struct/union Date: Wed, 23 Aug 2023 01:26:02 +0900 Message-Id: <169272156248.160970.8868479822371129043.stgit@devnote2> X-Mailer: git-send-email 2.34.1 In-Reply-To: <169272153143.160970.15584603734373446082.stgit@devnote2> References: <169272153143.160970.15584603734373446082.stgit@devnote2> User-Agent: StGit/0.19 MIME-Version: 1.0 X-Spam-Status: No, score=-7.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_HI, SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1774954334246606944 X-GMAIL-MSGID: 1774954334246606944 From: Masami Hiramatsu (Google) Add btf_find_struct_member() API to search a member of a given data structure or union from the member's name. Signed-off-by: Masami Hiramatsu (Google) Reviewed-by: Alan Maguire Acked-by: Steven Rostedt (Google) --- Changes in v3: - Remove simple input check. - Fix unneeded IS_ERR_OR_NULL() check for btf_type_by_id(). - Move the code next to btf_get_func_param(). - Use for_each_member() macro instead of for-loop. - Use btf_type_skip_modifiers() instead of btf_type_by_id(). Changes in v4: - Use a stack for searching in anonymous members instead of nested call. Changes in v5: - Move the generic functions into a new file, trace_btf.c, for avoiding tree-merge conflict. - Return anon_offset for calculating correct offset from root struct. Changes in v6: - Allocate anon_stack from heap instead of stack. --- kernel/trace/trace_btf.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++ kernel/trace/trace_btf.h | 4 +++ 2 files changed, 73 insertions(+) diff --git a/kernel/trace/trace_btf.c b/kernel/trace/trace_btf.c index d70b8ee9af37..ca224d53bfdc 100644 --- a/kernel/trace/trace_btf.c +++ b/kernel/trace/trace_btf.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include #include +#include #include "trace_btf.h" @@ -51,3 +52,71 @@ const struct btf_param *btf_get_func_param(const struct btf_type *func_proto, s3 return NULL; } +#define BTF_ANON_STACK_MAX 16 + +struct btf_anon_stack { + u32 tid; + u32 offset; +}; + +/* + * Find a member of data structure/union by name and return it. + * Return NULL if not found, or -EINVAL if parameter is invalid. + * If the member is an member of anonymous union/structure, the offset + * of that anonymous union/structure is stored into @anon_offset. Caller + * can calculate the correct offset from the root data structure by + * adding anon_offset to the member's offset. + */ +const struct btf_member *btf_find_struct_member(struct btf *btf, + const struct btf_type *type, + const char *member_name, + u32 *anon_offset) +{ + struct btf_anon_stack *anon_stack; + const struct btf_member *member; + u32 tid, cur_offset = 0; + const char *name; + int i, top = 0; + + anon_stack = kcalloc(BTF_ANON_STACK_MAX, sizeof(*anon_stack), GFP_KERNEL); + if (!anon_stack) + return ERR_PTR(-ENOMEM); + +retry: + if (!btf_type_is_struct(type)) { + member = ERR_PTR(-EINVAL); + goto out; + } + + for_each_member(i, type, member) { + if (!member->name_off) { + /* Anonymous union/struct: push it for later use */ + type = btf_type_skip_modifiers(btf, member->type, &tid); + if (type && top < BTF_ANON_STACK_MAX) { + anon_stack[top].tid = tid; + anon_stack[top++].offset = + cur_offset + member->offset; + } + } else { + name = btf_name_by_offset(btf, member->name_off); + if (name && !strcmp(member_name, name)) { + if (anon_offset) + *anon_offset = cur_offset; + goto out; + } + } + } + if (top > 0) { + /* Pop from the anonymous stack and retry */ + tid = anon_stack[--top].tid; + cur_offset = anon_stack[top].offset; + type = btf_type_by_id(btf, tid); + goto retry; + } + member = NULL; + +out: + kfree(anon_stack); + return member; +} + diff --git a/kernel/trace/trace_btf.h b/kernel/trace/trace_btf.h index 98685e9a556c..4bc44bc261e6 100644 --- a/kernel/trace/trace_btf.h +++ b/kernel/trace/trace_btf.h @@ -5,3 +5,7 @@ const struct btf_type *btf_find_func_proto(const char *func_name, struct btf **btf_p); const struct btf_param *btf_get_func_param(const struct btf_type *func_proto, s32 *nr); +const struct btf_member *btf_find_struct_member(struct btf *btf, + const struct btf_type *type, + const char *member_name, + u32 *anon_offset); From patchwork Tue Aug 22 16:26:22 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Masami Hiramatsu (Google)" X-Patchwork-Id: 136569 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:b82d:0:b0:3f2:4152:657d with SMTP id z13csp3745979vqi; Tue, 22 Aug 2023 09:34:40 -0700 (PDT) X-Google-Smtp-Source: AGHT+IFqElEMG2IZhxNJfSqhaY6EnThdQ9+w5Enj1X0h6T1BCUqpktFVnV2jFbG1woj43Fn6RaGf X-Received: by 2002:aa7:db4a:0:b0:525:501d:9bd3 with SMTP id n10-20020aa7db4a000000b00525501d9bd3mr6816967edt.32.1692722080479; Tue, 22 Aug 2023 09:34:40 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1692722080; cv=none; d=google.com; s=arc-20160816; b=F4URir4fj4SqBLH8n7/nE1S3rt7j+e/RXSBAuJpLX+w5ZamO4gbRB9CeYs3Dd0VFS7 mfIAQDnnxqZgqC0Za2JSW9R70bXZoWoa0eU6d9xaIJwzmcmwizGAxZTiiXP4vjybYS6Y rmLiKkOg8UUR2hvvKEeTTkMOBGH4KvWe7m+0kC4QL4KoLST5nRxtYuUI0tM2Ii3xa2l8 RYIiNXxcBu6RbfHoUKJEl1WA+PIqRiw0y1j2FUCI4yQsKhSNWzoOwh3NG2/a9pUZ1xOo VmxVEPwggFWMp8hRRIpwg/3qOdc5KjULrKcFdL3SZ1qSz0vZgyuTfa1E9BV+3dEDoDll RZ+A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=rObf8DfBO7vBlnnQZnSVZYPVhxUw8cRIef1rYzB3A+E=; fh=raxTTJvC+dSJYbgfX5JG5gvrVjxTZXczN0HF8iDayLY=; b=U6Gd0nogp0UyuO37QB2Aya3WgvxJ+2Up7+TVFK+NIajRNKwx7Flq3JN91Et+x7RIDS P27ZNlBcZ8s2AveBh8yGr7TFqbRWRDzBz9txgXiW94vOSpXbZ5scpwt1mxtMhOgrQWPx EqXKM0XFzoICdqYyeXrYTVDl7wG62tRtxHQG6nYHU8r+ejk+VWpIHTvrgVYWcYHswLzl H4cL+C5iolY1WpGc16xKYyEVGfAtETSjgc0itc2owX2Q2XTbn8861VdYEypYXUQASfkG z6cXhLLegAmAfedmV7kpL7N+LBP+GcbwZ0qB/qxF0sdnHvIJaGUINDTjtcQ/Nkln74Tw WaEQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=LUxl+nhl; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id v21-20020aa7d815000000b0052a1dcd8416si400158edq.491.2023.08.22.09.34.06; Tue, 22 Aug 2023 09:34:40 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=LUxl+nhl; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237747AbjHVQ0l (ORCPT + 99 others); Tue, 22 Aug 2023 12:26:41 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47676 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237735AbjHVQ0l (ORCPT ); Tue, 22 Aug 2023 12:26:41 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2A7CEE4A; Tue, 22 Aug 2023 09:26:28 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id AEF6F65A5A; Tue, 22 Aug 2023 16:26:27 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 17C83C433C7; Tue, 22 Aug 2023 16:26:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1692721587; bh=xFDFZyQ1MAkGLSxsDn9WdVwyuO35Krqok9MRYlqd7UY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=LUxl+nhlKxlqrvIdyOlHtmVG4K/nqrN0oZIlcaof+zn55XNYLb62R42LVuNvJI6ts 16MwkiO+Xe3OUEZN6lSCqjdKvD2AK+ipDYYYnQKGkA/JDycdr47jwHoZzg/UD0Uvtm 3PUyGsabrvY60pkffyjmzEUAcnDSVB/G2ChFor79dpR0ip8vtt8kQng0ugAgC7rOHH u6eE2Sgfg4+W6a2QFssCumQtsP83K5mPi1Lx2y6UNdRRBSK0M6mEfPoy3N52ZJYfAX bOmi3uZXLPYjnyQCSXj1UpoG1c5XVEWQYXAGGNWoKCKCj2UUaZz5kEoOqeNrEf9+oe 1HlBYXZ3lJcTA== From: "Masami Hiramatsu (Google)" To: linux-trace-kernel@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Steven Rostedt , mhiramat@kernel.org, Martin KaFai Lau , bpf@vger.kernel.org, Sven Schnelle , Alexei Starovoitov Subject: [PATCH v6 5/9] tracing/probes: Support BTF field access from $retval Date: Wed, 23 Aug 2023 01:26:22 +0900 Message-Id: <169272158234.160970.2446691104240645205.stgit@devnote2> X-Mailer: git-send-email 2.34.1 In-Reply-To: <169272153143.160970.15584603734373446082.stgit@devnote2> References: <169272153143.160970.15584603734373446082.stgit@devnote2> User-Agent: StGit/0.19 MIME-Version: 1.0 X-Spam-Status: No, score=-7.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_HI, SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1774947748263636067 X-GMAIL-MSGID: 1774947748263636067 From: Masami Hiramatsu (Google) Support BTF argument on '$retval' for function return events including kretprobe and fprobe for accessing the return value. This also allows user to access its fields if the return value is a pointer of a data structure. E.g. # echo 'f getname_flags%return +0($retval->name):string' \ > dynamic_events # echo 1 > events/fprobes/getname_flags__exit/enable # ls > /dev/null # head -n 40 trace | tail ls-87 [000] ...1. 8067.616101: getname_flags__exit: (vfs_fstatat+0x3c/0x70 <- getname_flags) arg1="./function_profile_enabled" ls-87 [000] ...1. 8067.616108: getname_flags__exit: (vfs_fstatat+0x3c/0x70 <- getname_flags) arg1="./trace_stat" ls-87 [000] ...1. 8067.616115: getname_flags__exit: (vfs_fstatat+0x3c/0x70 <- getname_flags) arg1="./set_graph_notrace" ls-87 [000] ...1. 8067.616122: getname_flags__exit: (vfs_fstatat+0x3c/0x70 <- getname_flags) arg1="./set_graph_function" ls-87 [000] ...1. 8067.616129: getname_flags__exit: (vfs_fstatat+0x3c/0x70 <- getname_flags) arg1="./set_ftrace_notrace" ls-87 [000] ...1. 8067.616135: getname_flags__exit: (vfs_fstatat+0x3c/0x70 <- getname_flags) arg1="./set_ftrace_filter" ls-87 [000] ...1. 8067.616143: getname_flags__exit: (vfs_fstatat+0x3c/0x70 <- getname_flags) arg1="./touched_functions" ls-87 [000] ...1. 8067.616237: getname_flags__exit: (vfs_fstatat+0x3c/0x70 <- getname_flags) arg1="./enabled_functions" ls-87 [000] ...1. 8067.616245: getname_flags__exit: (vfs_fstatat+0x3c/0x70 <- getname_flags) arg1="./available_filter_functions" ls-87 [000] ...1. 8067.616253: getname_flags__exit: (vfs_fstatat+0x3c/0x70 <- getname_flags) arg1="./set_ftrace_notrace_pid" Signed-off-by: Masami Hiramatsu (Google) Acked-by: Steven Rostedt (Google) --- Changes in v2: - Use '$retval' instead of 'retval' because it is confusing. Changes in v3: - Introduce query_btf_context() to cache the btf related data (function prototype) for using common field analyzing code with function parameters. Changes in v3.1: - Return int error code from query_btf_context() if !CONFIG_PROBE_EVENTS_BTF_ARGS Changes in v4: - Fix wrong BTF access if query_btf_context() is failed in parse_btf_arg(). - Return error if $retval accesses a field but BTF is not found. --- kernel/trace/trace_probe.c | 187 ++++++++++++++++++++------------------------ kernel/trace/trace_probe.h | 1 2 files changed, 86 insertions(+), 102 deletions(-) diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c index 821f43e5c52b..7345e1af4db2 100644 --- a/kernel/trace/trace_probe.c +++ b/kernel/trace/trace_probe.c @@ -364,38 +364,46 @@ static const char *fetch_type_from_btf_type(struct btf *btf, return NULL; } -static const struct btf_param *find_btf_func_param(const char *funcname, s32 *nr, - struct btf **btf_p, bool tracepoint) +static int query_btf_context(struct traceprobe_parse_context *ctx) { const struct btf_param *param; - const struct btf_type *t; + const struct btf_type *type; struct btf *btf; + s32 nr; - if (!funcname || !nr) - return ERR_PTR(-EINVAL); + if (ctx->btf) + return 0; - t = btf_find_func_proto(funcname, &btf); - if (!t) - return (const struct btf_param *)t; + if (!ctx->funcname) + return -EINVAL; - param = btf_get_func_param(t, nr); - if (IS_ERR_OR_NULL(param)) - goto err; + type = btf_find_func_proto(ctx->funcname, &btf); + if (!type) + return -ENOENT; - /* Hide the first 'data' argument of tracepoint */ - if (tracepoint) { - (*nr)--; - param++; + ctx->btf = btf; + ctx->proto = type; + + /* ctx->params is optional, since func(void) will not have params. */ + nr = 0; + param = btf_get_func_param(type, &nr); + if (!IS_ERR_OR_NULL(param)) { + /* Hide the first 'data' argument of tracepoint */ + if (ctx->flags & TPARG_FL_TPOINT) { + nr--; + param++; + } } - if (*nr > 0) { - *btf_p = btf; - return param; + if (nr > 0) { + ctx->nr_params = nr; + ctx->params = param; + } else { + ctx->nr_params = 0; + ctx->params = NULL; } -err: - btf_put(btf); - return NULL; + return 0; } static void clear_btf_context(struct traceprobe_parse_context *ctx) @@ -403,6 +411,7 @@ static void clear_btf_context(struct traceprobe_parse_context *ctx) if (ctx->btf) { btf_put(ctx->btf); ctx->btf = NULL; + ctx->proto = NULL; ctx->params = NULL; ctx->nr_params = 0; } @@ -522,7 +531,7 @@ static int parse_btf_arg(char *varname, const struct btf_param *params; const struct btf_type *type; char *field = NULL; - int i, is_ptr; + int i, is_ptr, ret; u32 tid; if (WARN_ON_ONCE(!ctx->funcname)) @@ -538,17 +547,37 @@ static int parse_btf_arg(char *varname, return -EOPNOTSUPP; } - if (!ctx->params) { - params = find_btf_func_param(ctx->funcname, - &ctx->nr_params, &ctx->btf, - ctx->flags & TPARG_FL_TPOINT); - if (IS_ERR_OR_NULL(params)) { + if (ctx->flags & TPARG_FL_RETURN) { + if (strcmp(varname, "$retval") != 0) { + trace_probe_log_err(ctx->offset, NO_BTFARG); + return -ENOENT; + } + code->op = FETCH_OP_RETVAL; + /* Check whether the function return type is not void */ + if (query_btf_context(ctx) == 0) { + if (ctx->proto->type == 0) { + trace_probe_log_err(ctx->offset, NO_RETVAL); + return -ENOENT; + } + tid = ctx->proto->type; + goto found; + } + if (field) { + trace_probe_log_err(ctx->offset + field - varname, + NO_BTF_ENTRY); + return -ENOENT; + } + return 0; + } + + if (!ctx->btf) { + ret = query_btf_context(ctx); + if (ret < 0 || ctx->nr_params == 0) { trace_probe_log_err(ctx->offset, NO_BTF_ENTRY); return PTR_ERR(params); } - ctx->params = params; - } else - params = ctx->params; + } + params = ctx->params; for (i = 0; i < ctx->nr_params; i++) { const char *name = btf_name_by_offset(ctx->btf, params[i].name_off); @@ -559,7 +588,6 @@ static int parse_btf_arg(char *varname, code->param = i + 1; else code->param = i; - tid = params[i].type; goto found; } @@ -584,7 +612,7 @@ static int parse_btf_arg(char *varname, return 0; } -static const struct fetch_type *parse_btf_arg_type( +static const struct fetch_type *find_fetch_type_from_btf_type( struct traceprobe_parse_context *ctx) { struct btf *btf = ctx->btf; @@ -596,27 +624,6 @@ static const struct fetch_type *parse_btf_arg_type( return find_fetch_type(typestr, ctx->flags); } -static const struct fetch_type *parse_btf_retval_type( - struct traceprobe_parse_context *ctx) -{ - const char *typestr = NULL; - const struct btf_type *type; - struct btf *btf; - - if (ctx->funcname) { - /* Do not use ctx->btf, because it must be used with ctx->param */ - type = btf_find_func_proto(ctx->funcname, &btf); - if (type) { - type = btf_type_skip_modifiers(btf, type->type, NULL); - if (!IS_ERR_OR_NULL(type)) - typestr = fetch_type_from_btf_type(btf, type, ctx); - btf_put(btf); - } - } - - return find_fetch_type(typestr, ctx->flags); -} - static int parse_btf_bitfield(struct fetch_insn **pcode, struct traceprobe_parse_context *ctx) { @@ -639,30 +646,15 @@ static int parse_btf_bitfield(struct fetch_insn **pcode, return 0; } -static bool is_btf_retval_void(const char *funcname) -{ - const struct btf_type *t; - struct btf *btf; - bool ret; - - t = btf_find_func_proto(funcname, &btf); - if (!t) - return false; - - ret = (t->type == 0); - btf_put(btf); - return ret; -} #else static void clear_btf_context(struct traceprobe_parse_context *ctx) { ctx->btf = NULL; } -static const struct btf_param *find_btf_func_param(const char *funcname, s32 *nr, - struct btf **btf_p, bool tracepoint) +static int query_btf_context(struct traceprobe_parse_context *ctx) { - return ERR_PTR(-EOPNOTSUPP); + return -EOPNOTSUPP; } static int parse_btf_arg(char *varname, @@ -680,24 +672,23 @@ static int parse_btf_bitfield(struct fetch_insn **pcode, return -EOPNOTSUPP; } -#define parse_btf_arg_type(ctx) \ - find_fetch_type(NULL, ctx->flags) - -#define parse_btf_retval_type(ctx) \ +#define find_fetch_type_from_btf_type(ctx) \ find_fetch_type(NULL, ctx->flags) -#define is_btf_retval_void(funcname) (false) - #endif #define PARAM_MAX_STACK (THREAD_SIZE / sizeof(unsigned long)) -static int parse_probe_vars(char *arg, const struct fetch_type *t, - struct fetch_insn *code, +/* Parse $vars. @orig_arg points '$', which syncs to @ctx->offset */ +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) { - unsigned long param; + struct fetch_insn *code = *pcode; int err = TP_ERR_BAD_VAR; + char *arg = orig_arg + 1; + unsigned long param; int ret = 0; int len; @@ -716,18 +707,17 @@ static int parse_probe_vars(char *arg, const struct fetch_type *t, goto inval; } - if (strcmp(arg, "retval") == 0) { - if (ctx->flags & TPARG_FL_RETURN) { - if ((ctx->flags & TPARG_FL_KERNEL) && - is_btf_retval_void(ctx->funcname)) { - err = TP_ERR_NO_RETVAL; - goto inval; - } + if (str_has_prefix(arg, "retval")) { + if (!(ctx->flags & TPARG_FL_RETURN)) { + err = TP_ERR_RETVAL_ON_PROBE; + goto inval; + } + if (!(ctx->flags & TPARG_FL_KERNEL) || + !IS_ENABLED(CONFIG_PROBE_EVENTS_BTF_ARGS)) { code->op = FETCH_OP_RETVAL; return 0; } - err = TP_ERR_RETVAL_ON_PROBE; - goto inval; + return parse_btf_arg(orig_arg, pcode, end, ctx); } len = str_has_prefix(arg, "stack"); @@ -829,7 +819,7 @@ parse_probe_arg(char *arg, const struct fetch_type *type, switch (arg[0]) { case '$': - ret = parse_probe_vars(arg + 1, type, code, ctx); + ret = parse_probe_vars(arg, type, pcode, end, ctx); break; case '%': /* named register */ @@ -1126,12 +1116,9 @@ static int traceprobe_parse_probe_arg_body(const char *argv, ssize_t *size, goto fail; /* Update storing type if BTF is available */ - if (IS_ENABLED(CONFIG_PROBE_EVENTS_BTF_ARGS) && !t) { - if (ctx->last_type) - parg->type = parse_btf_arg_type(ctx); - else if (ctx->flags & TPARG_FL_RETURN) - parg->type = parse_btf_retval_type(ctx); - } + if (IS_ENABLED(CONFIG_PROBE_EVENTS_BTF_ARGS) && + !t && ctx->last_type) + parg->type = find_fetch_type_from_btf_type(ctx); ret = -EINVAL; /* Store operation */ @@ -1420,7 +1407,6 @@ const char **traceprobe_expand_meta_args(int argc, const char *argv[], const struct btf_param *params = NULL; int i, j, n, used, ret, args_idx = -1; const char **new_argv = NULL; - int nr_params; ret = argv_has_var_arg(argc, argv, &args_idx, ctx); if (ret < 0) @@ -1431,9 +1417,8 @@ const char **traceprobe_expand_meta_args(int argc, const char *argv[], return NULL; } - params = find_btf_func_param(ctx->funcname, &nr_params, &ctx->btf, - ctx->flags & TPARG_FL_TPOINT); - if (IS_ERR_OR_NULL(params)) { + ret = query_btf_context(ctx); + if (ret < 0 || ctx->nr_params == 0) { if (args_idx != -1) { /* $arg* requires BTF info */ trace_probe_log_err(0, NOSUP_BTFARG); @@ -1442,8 +1427,6 @@ const char **traceprobe_expand_meta_args(int argc, const char *argv[], *new_argc = argc; return NULL; } - ctx->params = params; - ctx->nr_params = nr_params; if (args_idx >= 0) *new_argc = argc + ctx->nr_params - 1; @@ -1458,7 +1441,7 @@ const char **traceprobe_expand_meta_args(int argc, const char *argv[], for (i = 0, j = 0; i < argc; i++) { trace_probe_log_set_index(i + 2); if (i == args_idx) { - for (n = 0; n < nr_params; n++) { + for (n = 0; n < ctx->nr_params; n++) { ret = sprint_nth_btf_arg(n, "", buf + used, bufsize - used, ctx); if (ret < 0) diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h index 6111f1ffca6c..9184c84833f8 100644 --- a/kernel/trace/trace_probe.h +++ b/kernel/trace/trace_probe.h @@ -385,6 +385,7 @@ struct traceprobe_parse_context { struct trace_event_call *event; /* BTF related parameters */ const char *funcname; /* Function name in BTF */ + const struct btf_type *proto; /* Prototype of the function */ const struct btf_param *params; /* Parameter of the function */ s32 nr_params; /* The number of the parameters */ struct btf *btf; /* The BTF to be used */ From patchwork Tue Aug 22 16:26:32 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Masami Hiramatsu (Google)" X-Patchwork-Id: 136583 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:b82d:0:b0:3f2:4152:657d with SMTP id z13csp3798475vqi; Tue, 22 Aug 2023 11:04:16 -0700 (PDT) X-Google-Smtp-Source: AGHT+IFeSChM/kfNl4O73NeY4Cf9hkUYeuKwsCBW48egphLczPytc7uG9Oqmyg7I2RkYLOntPXm0 X-Received: by 2002:a17:90a:d258:b0:268:5c3b:6f28 with SMTP id o24-20020a17090ad25800b002685c3b6f28mr7373296pjw.19.1692727455860; Tue, 22 Aug 2023 11:04:15 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1692727455; cv=none; d=google.com; s=arc-20160816; b=y9nC+EOqicPm0YBxpC90opaN4oc8k+vhpwsBgt8d2j6vDJreKVQo4RXq0XOfFKXx7/ r7E7HxXhQu2mwLgU38Iw9K0AY6w9p26Jin314RvCaEoOHwObqFtSpQQ1elCoe87DFbXA ESnMVTcRoym0zl6t7VFVkLI2WaF7wn21dLGo2QuZUDIdxgKmS3o93cLNMP6NEeuJdcMD UKf20KxzyfcYdwstcS6RHw0fA0k41JaMoS1g8pcCkPjLgr7qCDwPJ3vsGTBHH1D6Czg3 8Zm/6bgqmu9owmDxkx1O6kSLeHy5aeYyF5g0buliGcwJXmIWPJvhpOOQXd1unBXOJ7H3 060g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=6rgdKHbL/YHvd1W3hP+boI40Pjj2gXhMwxpovaLKdfo=; fh=raxTTJvC+dSJYbgfX5JG5gvrVjxTZXczN0HF8iDayLY=; b=BPzqRQDsWoG0nQLYbAxj25Y1VHWDiuuv6iDdoYvmTd7A6AJ9Ng0KNEmURzqBKRDDOX 4FRbfLM8Yqo72aV/zoYgeG7h+3EaZv9nmy7283gDrKgkfE8qkoJDJkKKDls4GIMBU8w+ np12jUtb9lHU/hmGK19w5S2nAsSay4ElMjzDw8/m8lbrNc85G5b4AB5eLb231yGKTpRj z2P0B/d465XdAZXUgpWFCX5aM0TBhBONffD1OrJTNH+ss8xR1DmKU8DpWRHI3KRnX41U E4FwTok9mS+MZv1sFRwrPjCkt+6a9EEybqP2Wv0g7KtW2Yau5Rpv/Y5X9Btr20mFgjsg t8Ug== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b="oq/3X6LY"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net. [2620:137:e000::1:18]) by mx.google.com with ESMTPS id d20-20020a17090ad99400b0026b38330c7asi11187906pjv.179.2023.08.22.11.04.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 22 Aug 2023 11:04:15 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:18 as permitted sender) client-ip=2620:137:e000::1:18; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b="oq/3X6LY"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 3D1DB9ED3; Tue, 22 Aug 2023 10:19:58 -0700 (PDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237765AbjHVQ0z (ORCPT + 99 others); Tue, 22 Aug 2023 12:26:55 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47642 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237735AbjHVQ0y (ORCPT ); Tue, 22 Aug 2023 12:26:54 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4A502CDD; Tue, 22 Aug 2023 09:26:38 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id C814A65A5B; Tue, 22 Aug 2023 16:26:37 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 39391C433C8; Tue, 22 Aug 2023 16:26:34 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1692721597; bh=z5HZQKxxeBH9fJjmD9jGaQHV/G79OpU0dTqpNG/QDZA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=oq/3X6LYWFJThLSdPdEL1gHoqZCZwmHEWwbLIlgsufVtvCw4fobzSpk+DfbaGjC05 71AMN2qkeTuShdudBf9UDlcVpvvitoN19mxRYt7RfhZRIyx6RIitE+Fp6OUesb9SaX prtIXhVk6eJvvG5BHegvUf4BtVnTBa06ub+y2d0cThDPxdpkAorpTc2ZwWyCjarlHK mJcbCMq32ihwMpltloyVUHeUociaZJUmukcUxIHAvRKmTxd+CHWIlXjpNIH3pEtywS wJovvqbYgrdIjsZQhIq+JMbL9JlIPCwZ3vSqSIBquCPxADiHZL3FXF0X0T3tsBOeOc IN5BLn02Q8alg== From: "Masami Hiramatsu (Google)" To: linux-trace-kernel@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Steven Rostedt , mhiramat@kernel.org, Martin KaFai Lau , bpf@vger.kernel.org, Sven Schnelle , Alexei Starovoitov Subject: [PATCH v6 6/9] tracing/probes: Add string type check with BTF Date: Wed, 23 Aug 2023 01:26:32 +0900 Message-Id: <169272159250.160970.1881112937198526188.stgit@devnote2> X-Mailer: git-send-email 2.34.1 In-Reply-To: <169272153143.160970.15584603734373446082.stgit@devnote2> References: <169272153143.160970.15584603734373446082.stgit@devnote2> User-Agent: StGit/0.19 MIME-Version: 1.0 X-Spam-Status: No, score=-7.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_HI, SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1774953384776910503 X-GMAIL-MSGID: 1774953384776910503 From: Masami Hiramatsu (Google) Add a string type checking with BTF information if possible. This will check whether the given BTF argument (and field) is signed char array or pointer to signed char. If not, it reject the 'string' type. If it is pointer to signed char, it adds a dereference opration so that it can correctly fetch the string data from memory. # echo 'f getname_flags%return retval->name:string' >> dynamic_events # echo 't sched_switch next->comm:string' >> dynamic_events The above cases, 'struct filename::name' is 'char *' and 'struct task_struct::comm' is 'char []'. But in both case, user can specify ':string' to fetch the string data. Signed-off-by: Masami Hiramatsu (Google) Acked-by: Steven Rostedt (Google) --- Changes in v3: - Use ctx->btf instead of traceprobe_get_btf(). --- kernel/trace/trace_probe.c | 89 +++++++++++++++++++++++++++++++++++++++++++- kernel/trace/trace_probe.h | 3 + 2 files changed, 89 insertions(+), 3 deletions(-) diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c index 7345e1af4db2..4dc74d73fc1d 100644 --- a/kernel/trace/trace_probe.c +++ b/kernel/trace/trace_probe.c @@ -310,6 +310,77 @@ static u32 btf_type_int(const struct btf_type *t) return *(u32 *)(t + 1); } +static bool btf_type_is_char_ptr(struct btf *btf, const struct btf_type *type) +{ + const struct btf_type *real_type; + u32 intdata; + s32 tid; + + real_type = btf_type_skip_modifiers(btf, type->type, &tid); + if (!real_type) + return false; + + if (BTF_INFO_KIND(real_type->info) != BTF_KIND_INT) + return false; + + intdata = btf_type_int(real_type); + return !(BTF_INT_ENCODING(intdata) & BTF_INT_SIGNED) + && BTF_INT_BITS(intdata) == 8; +} + +static bool btf_type_is_char_array(struct btf *btf, const struct btf_type *type) +{ + const struct btf_type *real_type; + const struct btf_array *array; + u32 intdata; + s32 tid; + + if (BTF_INFO_KIND(type->info) != BTF_KIND_ARRAY) + return false; + + array = (const struct btf_array *)(type + 1); + + real_type = btf_type_skip_modifiers(btf, array->type, &tid); + + intdata = btf_type_int(real_type); + return !(BTF_INT_ENCODING(intdata) & BTF_INT_SIGNED) + && BTF_INT_BITS(intdata) == 8; +} + +static int check_prepare_btf_string_fetch(char *typename, + struct fetch_insn **pcode, + struct traceprobe_parse_context *ctx) +{ + struct btf *btf = ctx->btf; + + if (!btf || !ctx->last_type) + return 0; + + /* char [] does not need any change. */ + if (btf_type_is_char_array(btf, ctx->last_type)) + return 0; + + /* char * requires dereference the pointer. */ + if (btf_type_is_char_ptr(btf, ctx->last_type)) { + struct fetch_insn *code = *pcode + 1; + + if (code->op == FETCH_OP_END) { + trace_probe_log_err(ctx->offset, TOO_MANY_OPS); + return -E2BIG; + } + if (typename[0] == 'u') + code->op = FETCH_OP_UDEREF; + else + code->op = FETCH_OP_DEREF; + code->offset = 0; + *pcode = code; + return 0; + } + /* Other types are not available for string */ + trace_probe_log_err(ctx->offset, BAD_TYPE4STR); + return -EINVAL; +} + static const char *fetch_type_from_btf_type(struct btf *btf, const struct btf_type *type, struct traceprobe_parse_context *ctx) @@ -675,6 +746,13 @@ static int parse_btf_bitfield(struct fetch_insn **pcode, #define find_fetch_type_from_btf_type(ctx) \ find_fetch_type(NULL, ctx->flags) +static int check_prepare_btf_string_fetch(char *typename, + struct fetch_insn **pcode, + struct traceprobe_parse_context *ctx) +{ + return 0; +} + #endif #define PARAM_MAX_STACK (THREAD_SIZE / sizeof(unsigned long)) @@ -1117,8 +1195,15 @@ static int traceprobe_parse_probe_arg_body(const char *argv, ssize_t *size, /* Update storing type if BTF is available */ if (IS_ENABLED(CONFIG_PROBE_EVENTS_BTF_ARGS) && - !t && ctx->last_type) - parg->type = find_fetch_type_from_btf_type(ctx); + ctx->last_type) { + if (!t) { + parg->type = find_fetch_type_from_btf_type(ctx); + } else if (strstr(t, "string")) { + ret = check_prepare_btf_string_fetch(t, &code, ctx); + if (ret) + goto fail; + } + } ret = -EINVAL; /* Store operation */ diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h index 9184c84833f8..7f929482e8d4 100644 --- a/kernel/trace/trace_probe.h +++ b/kernel/trace/trace_probe.h @@ -513,7 +513,8 @@ extern int traceprobe_define_arg_fields(struct trace_event_call *event_call, C(NOSUP_DAT_ARG, "Non pointer structure/union argument is not supported."),\ C(BAD_HYPHEN, "Failed to parse single hyphen. Forgot '>'?"), \ C(NO_BTF_FIELD, "This field is not found."), \ - C(BAD_BTF_TID, "Failed to get BTF type info."), + C(BAD_BTF_TID, "Failed to get BTF type info."),\ + C(BAD_TYPE4STR, "This type does not fit for string."), #undef C #define C(a, b) TP_ERR_##a