From patchwork Tue May 12 05:56:41 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alan Maguire X-Patchwork-Id: 219428 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-10.0 required=3.0 tests=DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, UNPARSEABLE_RELAY, URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3E5A7C54E4B for ; Tue, 12 May 2020 05:59:37 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 1BE002072B for ; Tue, 12 May 2020 05:59:36 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=oracle.com header.i=@oracle.com header.b="ApbcGl6f" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728614AbgELF7d (ORCPT ); Tue, 12 May 2020 01:59:33 -0400 Received: from userp2130.oracle.com ([156.151.31.86]:41984 "EHLO userp2130.oracle.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728073AbgELF7c (ORCPT ); Tue, 12 May 2020 01:59:32 -0400 Received: from pps.filterd (userp2130.oracle.com [127.0.0.1]) by userp2130.oracle.com (8.16.0.42/8.16.0.42) with SMTP id 04C5wF0B136159; Tue, 12 May 2020 05:59:14 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oracle.com; h=from : to : cc : subject : date : message-id : in-reply-to : references; s=corp-2020-01-29; bh=yJuAmPZM1OUF3tRynJ8B547l0BWMftUiitExbm+onbQ=; b=ApbcGl6fyOla9VRTSrjXGTw6xfkNw9sIjPEcZ9eYEZ6dR2fBputLjcjZfE89EyPWNnTb vU4ZlJ08K8+jvMMI91zTQbZQmHVzc/fLD5VUr4Fvg35V4tQdk0MWf6cqyrp2XL6EICJh BMdKp+a927y8HqcGQky9cZ+4BwX/lgrI9J0zLfaCc3Urw2FGvUMk7VPQ5hSmG6U2bppF LJZw1STTfGiFbDTBpxe9O/nu9fVAVLc1aLkTMh+fUqHk0cc0qlA2JScES7MldQ66CZ74 RPUwhEtnRRpF8eqg590a5tTihfRSFYjtEA2lY8IfyeK9PJAIqB5BMY9a7mGMOkgdi4ba Xg== Received: from userp3030.oracle.com (userp3030.oracle.com [156.151.31.80]) by userp2130.oracle.com with ESMTP id 30x3gmgwjj-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Tue, 12 May 2020 05:59:14 +0000 Received: from pps.filterd (userp3030.oracle.com [127.0.0.1]) by userp3030.oracle.com (8.16.0.42/8.16.0.42) with SMTP id 04C5rtoT051900; Tue, 12 May 2020 05:57:14 GMT Received: from aserv0122.oracle.com (aserv0122.oracle.com [141.146.126.236]) by userp3030.oracle.com with ESMTP id 30ydspr2ck-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 12 May 2020 05:57:14 +0000 Received: from abhmp0017.oracle.com (abhmp0017.oracle.com [141.146.116.23]) by aserv0122.oracle.com (8.14.4/8.14.4) with ESMTP id 04C5vC5R013762; Tue, 12 May 2020 05:57:12 GMT Received: from localhost.uk.oracle.com (/10.175.210.30) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Mon, 11 May 2020 22:57:12 -0700 From: Alan Maguire To: ast@kernel.org, daniel@iogearbox.net, bpf@vger.kernel.org Cc: joe@perches.com, linux@rasmusvillemoes.dk, arnaldo.melo@gmail.com, yhs@fb.com, kafai@fb.com, songliubraving@fb.com, andriin@fb.com, john.fastabend@gmail.com, kpsingh@chromium.org, linux-kernel@vger.kernel.org, netdev@vger.kernel.org, Alan Maguire Subject: [PATCH v2 bpf-next 3/7] checkpatch: add new BTF pointer format specifier Date: Tue, 12 May 2020 06:56:41 +0100 Message-Id: <1589263005-7887-4-git-send-email-alan.maguire@oracle.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1589263005-7887-1-git-send-email-alan.maguire@oracle.com> References: <1589263005-7887-1-git-send-email-alan.maguire@oracle.com> X-Proofpoint-Virus-Version: vendor=nai engine=6000 definitions=9618 signatures=668687 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 phishscore=0 suspectscore=0 mlxscore=0 adultscore=0 mlxlogscore=837 malwarescore=0 bulkscore=0 spamscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2003020000 definitions=main-2005120052 X-Proofpoint-Virus-Version: vendor=nai engine=6000 definitions=9618 signatures=668687 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 adultscore=0 mlxlogscore=872 clxscore=1015 spamscore=0 lowpriorityscore=0 phishscore=0 bulkscore=0 malwarescore=0 priorityscore=1501 mlxscore=0 suspectscore=0 impostorscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2003020000 definitions=main-2005120052 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org checkpatch complains about unknown format specifiers, so add the BTF format specifier we will implement in a subsequent patch to avoid errors. Signed-off-by: Alan Maguire --- scripts/checkpatch.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index eac40f0..8efbb23 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -6085,7 +6085,7 @@ sub process { $specifier = $1; $extension = $2; $qualifier = $3; - if ($extension !~ /[SsBKRraEehMmIiUDdgVCbGNOxtf]/ || + if ($extension !~ /[SsBKRraEehMmIiUDdgVCbGNOxtfT]/ || ($extension eq "f" && defined $qualifier && $qualifier !~ /^w/)) { $bad_specifier = $specifier; From patchwork Tue May 12 05:56:42 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alan Maguire X-Patchwork-Id: 219430 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-10.0 required=3.0 tests=DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, UNPARSEABLE_RELAY, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 606EEC54E8D for ; Tue, 12 May 2020 05:57:41 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 31D2C20733 for ; Tue, 12 May 2020 05:57:41 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=oracle.com header.i=@oracle.com header.b="nllyyVbV" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728447AbgELF5j (ORCPT ); Tue, 12 May 2020 01:57:39 -0400 Received: from userp2120.oracle.com ([156.151.31.85]:38366 "EHLO userp2120.oracle.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725536AbgELF5i (ORCPT ); Tue, 12 May 2020 01:57:38 -0400 Received: from pps.filterd (userp2120.oracle.com [127.0.0.1]) by userp2120.oracle.com (8.16.0.42/8.16.0.42) with SMTP id 04C5v2Mg113133; Tue, 12 May 2020 05:57:19 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oracle.com; h=from : to : cc : subject : date : message-id : in-reply-to : references; s=corp-2020-01-29; bh=rwzHChZRWZsWlLCx9irESYeGjGjDDjunYm5sfuxAcZA=; b=nllyyVbVzbckAmRuTuEimhjh8ScaLTJNMNawwFdnRE0RQN2VLfu4/9Lpr/kzUanrTdNc /am+xHBUex6BkKHIKou7ZdfMejDIhNtSjS7sLdCdt7zWxrlPGIif9CNPzDorpTaeZY4a mvSa2aTaZxgIAZh+JXvxBC9Cft3uksiG0P73mwQ0nlY7rJD1G1gUreqqh8GGey3Z2e8V y8X6CwesshDb++8DH5KbYPVbIrKUxocbm8HxFkmRVKn0Z/6qhU5xsrF2POQXPbRFsIuz 4QxV5s1oVFSTzXWYQYKrMHQ4PRH+CFvVWNGQ2/GAqu4/49QZ0wIlGbR1Sl/cjyPbzu+v 8A== Received: from aserp3030.oracle.com (aserp3030.oracle.com [141.146.126.71]) by userp2120.oracle.com with ESMTP id 30x3mbrv2k-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Tue, 12 May 2020 05:57:19 +0000 Received: from pps.filterd (aserp3030.oracle.com [127.0.0.1]) by aserp3030.oracle.com (8.16.0.42/8.16.0.42) with SMTP id 04C5rfbR060465; Tue, 12 May 2020 05:57:18 GMT Received: from userv0121.oracle.com (userv0121.oracle.com [156.151.31.72]) by aserp3030.oracle.com with ESMTP id 30x63p3pe0-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 12 May 2020 05:57:18 +0000 Received: from abhmp0017.oracle.com (abhmp0017.oracle.com [141.146.116.23]) by userv0121.oracle.com (8.14.4/8.13.8) with ESMTP id 04C5vGUB018008; Tue, 12 May 2020 05:57:16 GMT Received: from localhost.uk.oracle.com (/10.175.210.30) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Mon, 11 May 2020 22:57:16 -0700 From: Alan Maguire To: ast@kernel.org, daniel@iogearbox.net, bpf@vger.kernel.org Cc: joe@perches.com, linux@rasmusvillemoes.dk, arnaldo.melo@gmail.com, yhs@fb.com, kafai@fb.com, songliubraving@fb.com, andriin@fb.com, john.fastabend@gmail.com, kpsingh@chromium.org, linux-kernel@vger.kernel.org, netdev@vger.kernel.org, Alan Maguire Subject: [PATCH v2 bpf-next 4/7] printk: add type-printing %pT format specifier which uses BTF Date: Tue, 12 May 2020 06:56:42 +0100 Message-Id: <1589263005-7887-5-git-send-email-alan.maguire@oracle.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1589263005-7887-1-git-send-email-alan.maguire@oracle.com> References: <1589263005-7887-1-git-send-email-alan.maguire@oracle.com> X-Proofpoint-Virus-Version: vendor=nai engine=6000 definitions=9618 signatures=668687 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 mlxscore=0 spamscore=0 suspectscore=0 malwarescore=0 phishscore=0 adultscore=0 mlxlogscore=999 bulkscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2003020000 definitions=main-2005120052 X-Proofpoint-Virus-Version: vendor=nai engine=6000 definitions=9618 signatures=668687 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 priorityscore=1501 impostorscore=0 mlxscore=0 suspectscore=0 bulkscore=0 mlxlogscore=999 phishscore=0 malwarescore=0 lowpriorityscore=0 spamscore=0 adultscore=0 clxscore=1015 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2003020000 definitions=main-2005120052 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org printk supports multiple pointer object type specifiers (printing netdev features etc). Extend this support using BTF to cover arbitrary types. "%pT" specifies the typed format, and the pointer argument is a "struct btf_ptr *" where struct btf_ptr is as follows: struct btf_ptr { void *ptr; const char *type; u32 id; }; Either the "type" string ("struct sk_buff") or the BTF "id" can be used to identify the type to use in displaying the associated "ptr" value. A convenience function to create and point at the struct is provided: printk(KERN_INFO "%pT", BTF_PTR_TYPE(skb, struct sk_buff)); When invoked, BTF information is used to traverse the sk_buff * and display it. Support is present for structs, unions, enums, typedefs and core types (though in the latter case there's not much value in using this feature of course). Default output is indented, but compact output can be specified via the 'c' option. Type names/member values can be suppressed using the 'N' option. Zero values are not displayed by default but can be using the '0' option. Pointer values are obfuscated unless the 'x' option is specified. As an example: struct sk_buff *skb = alloc_skb(64, GFP_KERNEL); pr_info("%pT", BTF_PTR_TYPE(skb, struct sk_buff)); ...gives us: (struct sk_buff){ .transport_header = (__u16)65535, .mac_header = (__u16)65535, .end = (sk_buff_data_t)192, .head = (unsigned char *)000000006b71155a, .data = (unsigned char *)000000006b71155a, .truesize = (unsigned int)768, .users = (refcount_t){ .refs = (atomic_t){ .counter = (int)1, }, }, .extensions = (struct skb_ext *)00000000f486a130, } printk output is truncated at 1024 bytes. For cases where overflow is likely, the compact/no type names display modes may be used. Signed-off-by: Alan Maguire --- Documentation/core-api/printk-formats.rst | 15 ++++ include/linux/btf.h | 3 +- include/linux/printk.h | 16 +++++ lib/Kconfig | 16 +++++ lib/vsprintf.c | 113 ++++++++++++++++++++++++++++++ 5 files changed, 162 insertions(+), 1 deletion(-) diff --git a/Documentation/core-api/printk-formats.rst b/Documentation/core-api/printk-formats.rst index 8ebe46b1..5c66097 100644 --- a/Documentation/core-api/printk-formats.rst +++ b/Documentation/core-api/printk-formats.rst @@ -545,6 +545,21 @@ For printing netdev_features_t. Passed by reference. +BTF-based printing of pointer data +---------------------------------- +If '%pT' is specified, use the struct btf_ptr * along with kernel vmlinux +BPF Type Format (BTF) to show the typed data. For example, specifying + + printk(KERN_INFO "%pT", BTF_PTR_TYPE(skb, struct_sk_buff)); + +will utilize BTF information to traverse the struct sk_buff * and display it. + +Supported modifers are + 'c' compact output (no indentation, newlines etc) + 'N' do not show type names + 'x' show raw pointers (no obfuscation) + '0' show zero-valued data (it is not shown by default) + Thanks ====== diff --git a/include/linux/btf.h b/include/linux/btf.h index d571125..7b585ab 100644 --- a/include/linux/btf.h +++ b/include/linux/btf.h @@ -169,10 +169,11 @@ static inline const struct btf_member *btf_type_member(const struct btf_type *t) return (const struct btf_member *)(t + 1); } +struct btf *btf_parse_vmlinux(void); + #ifdef CONFIG_BPF_SYSCALL const struct btf_type *btf_type_by_id(const struct btf *btf, u32 type_id); const char *btf_name_by_offset(const struct btf *btf, u32 offset); -struct btf *btf_parse_vmlinux(void); struct btf *bpf_prog_get_target_btf(const struct bpf_prog *prog); #else static inline const struct btf_type *btf_type_by_id(const struct btf *btf, diff --git a/include/linux/printk.h b/include/linux/printk.h index fcde0772..3c3ea53 100644 --- a/include/linux/printk.h +++ b/include/linux/printk.h @@ -528,4 +528,20 @@ static inline void print_hex_dump_debug(const char *prefix_str, int prefix_type, #define print_hex_dump_bytes(prefix_str, prefix_type, buf, len) \ print_hex_dump_debug(prefix_str, prefix_type, 16, 1, buf, len, true) +/** + * struct btf_ptr is used for %pT (typed pointer) display; the + * additional type string/BTF id are used to render the pointer + * data as the appropriate type. + */ +struct btf_ptr { + void *ptr; + const char *type; + u32 id; +}; + +#define BTF_PTR_TYPE(ptrval, typeval) \ + (&((struct btf_ptr){.ptr = ptrval, .type = #typeval})) + +#define BTF_PTR_ID(ptrval, idval) \ + (&((struct btf_ptr){.ptr = ptrval, .id = idval})) #endif diff --git a/lib/Kconfig b/lib/Kconfig index 5d53f96..ac3a513 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -6,6 +6,22 @@ config BINARY_PRINTF def_bool n +config BTF_PRINTF + bool "print type information using BPF type format" + depends on DEBUG_INFO_BTF + default n + help + Print structures, unions etc pointed to by pointer argument using + printk() family of functions (vsnprintf, printk, trace_printk, etc). + For example, we can specify + printk(KERN_INFO, "%pT", skb); to print the skb + data structure content, including all nested type data. + Pointers within data structures displayed are not followed, and + are obfuscated where specified in line with normal pointer display. + via printk. + + Depends on availability of vmlinux BTF information. + menu "Library routines" config RAID6_PQ diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 7c488a1..f9276f8 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -43,6 +43,7 @@ #ifdef CONFIG_BLOCK #include #endif +#include #include "../mm/internal.h" /* For the trace_print_flags arrays */ @@ -2059,6 +2060,103 @@ char *fwnode_string(char *buf, char *end, struct fwnode_handle *fwnode, return widen_string(buf, buf - buf_start, end, spec); } +#if IS_ENABLED(CONFIG_BTF_PRINTF) +#define btf_modifier_flag(c) (c == 'c' ? BTF_SHOW_COMPACT : \ + c == 'N' ? BTF_SHOW_NONAME : \ + c == 'x' ? BTF_SHOW_PTR_RAW : \ + c == '0' ? BTF_SHOW_ZERO : 0) + +static noinline_for_stack +char *btf_string(char *buf, char *end, void *ptr, struct printf_spec spec, + const char *fmt) +{ + struct btf_ptr *bp = (struct btf_ptr *)ptr; + u8 btf_kind = BTF_KIND_TYPEDEF; + const struct btf_type *t; + const struct btf *btf; + char *buf_start = buf; + const char *btf_type; + u64 flags = 0, mod; + s32 btf_id; + + if (check_pointer(&buf, end, ptr, spec)) + return buf; + + if (check_pointer(&buf, end, bp->ptr, spec)) + return buf; + + while (isalnum(*fmt)) { + mod = btf_modifier_flag(*fmt); + if (!mod) + break; + flags |= mod; + fmt++; + } + + btf = bpf_get_btf_vmlinux(); + if (IS_ERR_OR_NULL(btf)) + return ptr_to_id(buf, end, bp->ptr, spec); + + if (bp->type != NULL) { + btf_type = bp->type; + + if (strncmp(bp->type, "struct ", strlen("struct ")) == 0) { + btf_kind = BTF_KIND_STRUCT; + btf_type += strlen("struct "); + } else if (strncmp(btf_type, "union ", strlen("union ")) == 0) { + btf_kind = BTF_KIND_UNION; + btf_type += strlen("union "); + } else if (strncmp(btf_type, "enum ", strlen("enum ")) == 0) { + btf_kind = BTF_KIND_ENUM; + btf_type += strlen("enum "); + } + + if (strlen(btf_type) == 0) + return ptr_to_id(buf, end, bp->ptr, spec); + + /* + * Assume type specified is a typedef as there's not much + * benefit in specifying int types other than wasting time + * on BTF lookups; we optimize for the most useful path. + * + * Fall back to BTF_KIND_INT if this fails. + */ + btf_id = btf_find_by_name_kind(btf, btf_type, btf_kind); + if (btf_id < 0) + btf_id = btf_find_by_name_kind(btf, btf_type, + BTF_KIND_INT); + } else if (bp->id > 0) + btf_id = bp->id; + else + return ptr_to_id(buf, end, bp->ptr, spec); + + if (btf_id > 0) + t = btf_type_by_id(btf, btf_id); + if (btf_id <= 0 || !t) + return ptr_to_id(buf, end, bp->ptr, spec); + + buf += btf_type_snprintf_show(btf, btf_id, bp->ptr, buf, + end - buf_start, flags); + + return widen_string(buf, buf - buf_start, end, spec); +} +#else +static noinline_for_stack +char *btf_string(char *buf, char *end, void *ptr, struct printf_spec spec, + const char *fmt) +{ + struct btf_ptr *bp = (struct btf_ptr *)ptr; + + if (check_pointer(&buf, end, ptr, spec)) + return buf; + + if (check_pointer(&buf, end, bp->ptr, spec)) + return buf; + + return ptr_to_id(buf, end, bp->ptr, spec); +} +#endif /* IS_ENABLED(CONFIG_BTF_PRINTF) */ + /* * Show a '%p' thing. A kernel extension is that the '%p' is followed * by an extra set of alphanumeric characters that are extended format @@ -2169,6 +2267,19 @@ char *fwnode_string(char *buf, char *end, struct fwnode_handle *fwnode, * P node name, including a possible unit address * - 'x' For printing the address. Equivalent to "%lx". * + * - 'T[cNx0]' For printing struct btf_ptr * data using BPF Type Format (BTF). + * + * Optional arguments are + * c compact (no indentation/newlines) + * N do not print type and member names + * x do not obfuscate pointers + * 0 show 0-valued data + * + * BPF_PTR_TYPE(ptr, type) can be used to place pointer and type string + * in the "struct btf_ptr *" expected; for example: + * + * printk(KERN_INFO "%pT", BTF_PTR_TYPE(skb, struct sk_buff)); + * * ** When making changes please also update: * Documentation/core-api/printk-formats.rst * @@ -2251,6 +2362,8 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr, if (!IS_ERR(ptr)) break; return err_ptr(buf, end, ptr, spec); + case 'T': + return btf_string(buf, end, ptr, spec, fmt + 1); } /* default is to _not_ leak addresses, hash before printing */ From patchwork Tue May 12 05:56:43 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alan Maguire X-Patchwork-Id: 219427 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-10.0 required=3.0 tests=DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, UNPARSEABLE_RELAY, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 03E26C54E8D for ; Tue, 12 May 2020 05:59:46 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id CF38F20836 for ; Tue, 12 May 2020 05:59:45 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=oracle.com header.i=@oracle.com header.b="NCEG82BG" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728821AbgELF7n (ORCPT ); Tue, 12 May 2020 01:59:43 -0400 Received: from userp2120.oracle.com ([156.151.31.85]:39790 "EHLO userp2120.oracle.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728796AbgELF7m (ORCPT ); Tue, 12 May 2020 01:59:42 -0400 Received: from pps.filterd (userp2120.oracle.com [127.0.0.1]) by userp2120.oracle.com (8.16.0.42/8.16.0.42) with SMTP id 04C5v2sv113189; Tue, 12 May 2020 05:59:22 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oracle.com; h=from : to : cc : subject : date : message-id : in-reply-to : references; s=corp-2020-01-29; bh=eKlXT6SV8ExVehScVkS65Re7NRVnE2ArusJ/wsmOHj4=; b=NCEG82BG3LPhaSOtgdZ4lQwuI1kPFsdNyKDlvO6Zt5SQTzW1NTzHXN5g3tGmQXCBMVMc PrCaGZwOVwEawlT8AEGCuhmSo7ezAwpAd8pC3LvZsZRP/Hae9is7gEGiRnyG4Z8GamKd 3k8sCbL1TtlSSVv97VZ21zyu/Qg+yLbA4wp7dmBcU8nrg9otLgmAmJ7aOhqNuQxt1bo8 H8+8VCFNnZi9YqH+1olyxW8NjJbfG+YY3Yf8DliiFjcHqsLVwF3CC35qFKnQ0hdOGAc3 57NPF+fzfz5VU1fnT7Da5ZVTwuXF9WllX82nuH9B9h3qCsq99C9AdXxvd7eTN/rDXfnn HQ== Received: from aserp3020.oracle.com (aserp3020.oracle.com [141.146.126.70]) by userp2120.oracle.com with ESMTP id 30x3mbrv9w-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Tue, 12 May 2020 05:59:22 +0000 Received: from pps.filterd (aserp3020.oracle.com [127.0.0.1]) by aserp3020.oracle.com (8.16.0.42/8.16.0.42) with SMTP id 04C5sW7x191669; Tue, 12 May 2020 05:57:21 GMT Received: from aserv0122.oracle.com (aserv0122.oracle.com [141.146.126.236]) by aserp3020.oracle.com with ESMTP id 30xbgh7u3p-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 12 May 2020 05:57:21 +0000 Received: from abhmp0017.oracle.com (abhmp0017.oracle.com [141.146.116.23]) by aserv0122.oracle.com (8.14.4/8.14.4) with ESMTP id 04C5vKQb013778; Tue, 12 May 2020 05:57:20 GMT Received: from localhost.uk.oracle.com (/10.175.210.30) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Mon, 11 May 2020 22:57:19 -0700 From: Alan Maguire To: ast@kernel.org, daniel@iogearbox.net, bpf@vger.kernel.org Cc: joe@perches.com, linux@rasmusvillemoes.dk, arnaldo.melo@gmail.com, yhs@fb.com, kafai@fb.com, songliubraving@fb.com, andriin@fb.com, john.fastabend@gmail.com, kpsingh@chromium.org, linux-kernel@vger.kernel.org, netdev@vger.kernel.org, Alan Maguire Subject: [PATCH v2 bpf-next 5/7] printk: extend test_printf to test %pT BTF-based format specifier Date: Tue, 12 May 2020 06:56:43 +0100 Message-Id: <1589263005-7887-6-git-send-email-alan.maguire@oracle.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1589263005-7887-1-git-send-email-alan.maguire@oracle.com> References: <1589263005-7887-1-git-send-email-alan.maguire@oracle.com> X-Proofpoint-Virus-Version: vendor=nai engine=6000 definitions=9618 signatures=668687 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 adultscore=0 mlxlogscore=999 spamscore=0 suspectscore=0 phishscore=0 bulkscore=0 mlxscore=0 malwarescore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2003020000 definitions=main-2005120052 X-Proofpoint-Virus-Version: vendor=nai engine=6000 definitions=9618 signatures=668687 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 priorityscore=1501 impostorscore=0 mlxscore=0 suspectscore=0 bulkscore=0 mlxlogscore=999 phishscore=0 malwarescore=0 lowpriorityscore=0 spamscore=0 adultscore=0 clxscore=1015 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2003020000 definitions=main-2005120052 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Add tests to verify basic type display and to iterate through all enums, structs, unions and typedefs ensuring expected behaviour occurs. Since test_printf can be built as a module we need to export a BTF kind iterator function to allow us to iterate over all names of a particular BTF kind. These changes add up to approximately 20,000 new tests covering all enum, struct, union and typedefs in vmlinux BTF. Individual tests are also added for int, char, struct, enum and typedefs which verify output is as expected. Signed-off-by: Alan Maguire --- include/linux/btf.h | 10 ++ kernel/bpf/btf.c | 35 ++++++ lib/test_printf.c | 301 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 346 insertions(+) diff --git a/include/linux/btf.h b/include/linux/btf.h index 7b585ab..7fa8926 100644 --- a/include/linux/btf.h +++ b/include/linux/btf.h @@ -188,4 +188,14 @@ static inline const char *btf_name_by_offset(const struct btf *btf, } #endif +/* Following function used for testing BTF-based printk-family support */ +#ifdef CONFIG_BTF_PRINTF +const char *btf_vmlinux_next_type_name(u8 kind, s32 *id); +#else +static inline const char *btf_vmlinux_next_type_name(u8 kind, s32 *id) +{ + return NULL; +} +#endif /* CONFIG_BTF_PRINTF */ + #endif diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index edf6455..99471dc 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -5249,3 +5249,38 @@ u32 btf_id(const struct btf *btf) { return btf->id; } + +#ifdef CONFIG_BTF_PRINTF +/* + * btf_vmlinux_next_type_name(): used in test_printf.c to + * iterate over types for testing. + * Exported as test_printf can be built as a module. + * + * @kind: BTF_KIND_* value + * @id: pointer to last id; value/result argument. When next + * type name is found, we set *id to associated id. + * Returns: + * Next type name, sets *id to associated id. + */ +const char *btf_vmlinux_next_type_name(u8 kind, s32 *id) +{ + const struct btf *btf = bpf_get_btf_vmlinux(); + const struct btf_type *t; + const char *name; + + if (!btf || !id) + return NULL; + + for ((*id)++; *id <= btf->nr_types; (*id)++) { + t = btf->types[*id]; + if (BTF_INFO_KIND(t->info) != kind) + continue; + name = btf_name_by_offset(btf, t->name_off); + if (name && strlen(name) > 0) + return name; + } + + return NULL; +} +EXPORT_SYMBOL_GPL(btf_vmlinux_next_type_name); +#endif /* CONFIG_BTF_PRINTF */ diff --git a/lib/test_printf.c b/lib/test_printf.c index 2d9f520..d37a3a2 100644 --- a/lib/test_printf.c +++ b/lib/test_printf.c @@ -23,6 +23,9 @@ #include #include +#include +#include +#include #include "../tools/testing/selftests/kselftest_module.h" @@ -644,6 +647,303 @@ static void __init fwnode_pointer(void) #endif } +#define __TEST_BTF(fmt, type, ptr, expected) \ + test(expected, "%pT"fmt, ptr) + +#define TEST_BTF_C(type, var, ...) \ + do { \ + type var = __VA_ARGS__; \ + struct btf_ptr *ptr = BTF_PTR_TYPE(&var, type); \ + pr_debug("type %s: %pTc", #type, ptr); \ + __TEST_BTF("c", type, ptr, "(" #type ")" #__VA_ARGS__); \ + } while (0) + +#define TEST_BTF(fmt, type, var, expected, ...) \ + do { \ + type var = __VA_ARGS__; \ + struct btf_ptr *ptr = BTF_PTR_TYPE(&var, type); \ + pr_debug("type %s: %pT"fmt, #type, ptr); \ + __TEST_BTF(fmt, type, ptr, expected); \ + } while (0) + +#define BTF_MAX_DATA_SIZE 65536 + +static void __init +btf_print_kind(u8 kind, const char *kind_name, u8 fillval) +{ + const char *fmt1 = "%pT", *fmt2 = "%pTN", *fmt3 = "%pT0"; + const char *name, *fmt = fmt1; + int res1, res2, res3, res4; + char type_name[256]; + u8 *dummy_data; + s32 id = 0; + char *buf; + + dummy_data = kzalloc(BTF_MAX_DATA_SIZE, GFP_KERNEL); + + /* fill our dummy data with supplied fillval. */ + memset(dummy_data, fillval, BTF_MAX_DATA_SIZE); + + buf = kzalloc(BTF_MAX_DATA_SIZE, GFP_KERNEL); + + for (;;) { + name = btf_vmlinux_next_type_name(kind, &id); + if (!name) + break; + + total_tests++; + + snprintf(type_name, sizeof(type_name), "%s%s", + kind_name, name); + + res1 = snprintf(buf, BTF_MAX_DATA_SIZE, fmt1, + BTF_PTR_TYPE(dummy_data, type_name)); + res2 = snprintf(buf, 0, fmt1, + BTF_PTR_TYPE(dummy_data, type_name)); + res3 = snprintf(buf, BTF_MAX_DATA_SIZE, fmt2, + BTF_PTR_TYPE(dummy_data, type_name)); + res4 = snprintf(buf, BTF_MAX_DATA_SIZE, fmt3, + BTF_PTR_TYPE(dummy_data, type_name)); + + /* + * Ensure return value is > 0 and identical irrespective + * of whether we pass in a big enough buffer; + * also ensure that printing names always results in as + * long/longer buffer length. + */ + if (res1 <= 0 || res2 <= 0 || res3 <= 0 || res4 <= 0) { + if (res3 <= 0) + fmt = fmt2; + if (res4 <= 0) + fmt = fmt3; + + pr_warn("snprintf(%s%s); %d <= 0 (fmt %s)", + kind_name, name, + res1 <= 0 ? res1 : res2 <= 0 ? res2 : + res3 <= 0 ? res3 : res4, fmt); + failed_tests++; + } else if (res1 != res2) { + pr_warn("snprintf(%s%s): %d (to buf) != %d (no buf)", + kind_name, name, res1, res2); + failed_tests++; + } else if (res3 > res2) { + pr_warn("snprintf(%s%s); %d (no names) > %d (names)", + kind_name, name, res3, res2); + failed_tests++; + } else { + pr_debug("Printed %s%s (%d bytes)", + kind_name, name, res1); + } + } + kfree(dummy_data); + kfree(buf); +} + +/* + * For BTF it is the struct btf_ptr * ptr field, not the pointer itself + * which gets displayed, so it is that we need to hash. + */ +static void __init +test_btf_hashed(const char *fmt, struct btf_ptr *p) +{ + char buf[PLAIN_BUF_SIZE]; + int ret; + + ret = plain_hash_to_buffer(p->ptr, buf, PLAIN_BUF_SIZE); + if (ret) + return; + + test(buf, fmt, p); +} + +#ifdef CONFIG_BTF_PRINTF + +static void __init btf_pointer_test_int(void) +{ + /* simple int */ + TEST_BTF_C(int, testint, 1234); + TEST_BTF("cN", int, testint, "1234", 1234); + /* zero value should be printed at toplevel */ + TEST_BTF("c", int, testint, "(int)0", 0); + TEST_BTF("cN", int, testint, "0", 0); + TEST_BTF("c0", int, testint, "(int)0", 0); + TEST_BTF("cN0", int, testint, "0", 0); + TEST_BTF_C(int, testint, -4567); + TEST_BTF("cN", int, testint, "-4567", -4567); +} + +static void __init btf_pointer_test_char(void) +{ + /* simple char */ + TEST_BTF_C(char, testchar, 100); + TEST_BTF("cN", char, testchar, "100", 100); + /* zero value should be printed at toplevel */ + TEST_BTF("c", char, testchar, "(char)0", 0); + TEST_BTF("cN", char, testchar, "0", 0); + TEST_BTF("c0", char, testchar, "(char)0", 0); + TEST_BTF("cN0", char, testchar, "0", 0); +} + +static void __init btf_pointer_test_typedef(void) +{ + /* simple typedef */ + TEST_BTF_C(phys_addr_t, testtype, 100); + TEST_BTF("cN", phys_addr_t, testtype, "1", 1); + /* zero value should be printed at toplevel */ + TEST_BTF("c", phys_addr_t, testtype, "(phys_addr_t)0", 0); + TEST_BTF("cN", phys_addr_t, testtype, "0", 0); + TEST_BTF("c0", phys_addr_t, testtype, "(phys_addr_t)0", 0); + TEST_BTF("cN0", phys_addr_t, testtype, "0", 0); + + /* typedef struct */ + TEST_BTF_C(atomic_t, testtype, {.counter = (int)1,}); + TEST_BTF("cN", atomic_t, testtype, "{1,}", {.counter = 1,}); + /* typedef with 0 value should be printed at toplevel */ + TEST_BTF("c", atomic_t, testtype, "(atomic_t){}", {.counter = 0,}); + TEST_BTF("cN", atomic_t, testtype, "{}", {.counter = 0,}); + TEST_BTF("c0", atomic_t, testtype, "(atomic_t){.counter = (int)0,}", + {.counter = 0,}); + TEST_BTF("cN0", atomic_t, testtype, "{0,}", {.counter = 0,}); + + /* typedef array */ + TEST_BTF("c", cpumask_t, testtype, + "(cpumask_t){.bits = (long unsigned int[])[1,],}", + { .bits = {1,}}); + TEST_BTF("cN", cpumask_t, testtype, "{[1,],}", + { .bits = {1,}}); + /* typedef with 0 value should be printed at toplevel */ + TEST_BTF("c", cpumask_t, testtype, "(cpumask_t){}", {{ 0 }}); +} + +static void __init btf_pointer_test_enum(void) +{ + /* enum where enum value does (and does not) exist */ + TEST_BTF_C(enum bpf_cmd, testenum, BPF_MAP_CREATE); + TEST_BTF("c", enum bpf_cmd, testenum, "(enum bpf_cmd)BPF_MAP_CREATE", + 0); + TEST_BTF("cN", enum bpf_cmd, testenum, "BPF_MAP_CREATE", + BPF_MAP_CREATE); + TEST_BTF("cN0", enum bpf_cmd, testenum, "BPF_MAP_CREATE", 0); + + TEST_BTF("c0", enum bpf_cmd, testenum, "(enum bpf_cmd)BPF_MAP_CREATE", + BPF_MAP_CREATE); + TEST_BTF("cN0", enum bpf_cmd, testenum, "BPF_MAP_CREATE", + BPF_MAP_CREATE); + TEST_BTF_C(enum bpf_cmd, testenum, 2000); + TEST_BTF("cN", enum bpf_cmd, testenum, "2000", 2000); +} + +static void __init btf_pointer_test_struct(void) +{ + /* simple struct */ + TEST_BTF_C(struct btf_enum, teststruct, + {.name_off = (__u32)3,.val = (__s32)-1,}); + TEST_BTF("cN", struct btf_enum, teststruct, "{3,-1,}", + { .name_off = 3, .val = -1,}); + TEST_BTF("cN", struct btf_enum, teststruct, "{-1,}", + { .name_off = 0, .val = -1,}); + TEST_BTF("cN0", struct btf_enum, teststruct, "{0,-1,}", + { .name_off = 0, .val = -1,}); + /* empty struct should be printed */ + TEST_BTF("c", struct btf_enum, teststruct, "(struct btf_enum){}", + { .name_off = 0, .val = 0,}); + TEST_BTF("cN", struct btf_enum, teststruct, "{}", + { .name_off = 0, .val = 0,}); + TEST_BTF("c0", struct btf_enum, teststruct, + "(struct btf_enum){.name_off = (__u32)0,.val = (__s32)0,}", + { .name_off = 0, .val = 0,}); + + /* struct with pointers */ + TEST_BTF("cx", struct skb_shared_info, testptr, + "(struct skb_shared_info){.frag_list = (struct sk_buff *)0000000000000001,}", + { .frag_list = (struct sk_buff *)1 }); + /* NULL pointer should not be displayed */ + TEST_BTF("cx", struct skb_shared_info, testptr, + "(struct skb_shared_info){}", + { .frag_list = (struct sk_buff *)0 }); + + /* struct with char array */ + TEST_BTF("c", struct bpf_prog_info, teststruct, + "(struct bpf_prog_info){.name = (char[])['f','o','o',],}", + { .name = "foo",}); + TEST_BTF("cN", struct bpf_prog_info, teststruct, + "{['f','o','o',],}", + {.name = "foo",}); + /* leading null char means do not display string */ + TEST_BTF("c", struct bpf_prog_info, teststruct, + "(struct bpf_prog_info){}", + {.name = {'\0', 'f', 'o', 'o'}}); + /* handle non-printable characters */ + TEST_BTF("c", struct bpf_prog_info, teststruct, + "(struct bpf_prog_info){.name = (char[])[1,2,3,],}", + { .name = {1, 2, 3, 0}}); + + /* struct with non-char array */ + TEST_BTF("c", struct __sk_buff, teststruct, + "(struct __sk_buff){.cb = (__u32[])[1,2,3,4,5,],}", + { .cb = {1, 2, 3, 4, 5,},}); + TEST_BTF("cN", struct __sk_buff, teststruct, + "{[1,2,3,4,5,],}", + { .cb = { 1, 2, 3, 4, 5},}); + /* For non-char, arrays, show non-zero values only */ + TEST_BTF("c", struct __sk_buff, teststruct, + "(struct __sk_buff){.cb = (__u32[])[1,],}", + { .cb = { 0, 0, 1, 0, 0},}); + + /* struct with struct array */ + TEST_BTF("c", struct bpf_struct_ops, teststruct, + "(struct bpf_struct_ops){.func_models = (struct btf_func_model[])[(struct btf_func_model){.ret_size = (u8)1,.nr_args = (u8)2,.arg_size = (u8[])[3,4,5,],},],}", + { .func_models = {{ .ret_size = 1, .nr_args = 2, + .arg_size = { 3, 4, 5,},}}}); + + /* struct with bitfields */ + TEST_BTF_C(struct bpf_insn, testbitfield, + {.code = (__u8)1,.dst_reg = 0x2,.src_reg = 0x3,.off = (__s16)4,.imm = (__s32)5,}); + TEST_BTF("cN", struct bpf_insn, testbitfield, "{1,0x2,0x3,4,5,}", + {.code = 1, .dst_reg = 0x2, .src_reg = 0x3, .off = 4, + .imm = 5,}); + + /* struct with anon struct/unions */ + TEST_BTF("cx", struct sk_buff, test_anon, + "(struct sk_buff){(union){(struct){(union){.dev = (struct net_device *)0000000000000001,.dev_scratch = (long unsigned int)1,},},.rbnode = (struct rb_node){.rb_left = (struct rb_node *)0000000000000001,},},}", + { .dev_scratch = 1 }); +} + +#endif /* CONFIG_BTF_PRINTF */ + +static void __init +btf_pointer(void) +{ + struct sk_buff *skb = alloc_skb(64, GFP_KERNEL); + u8 fillvals[2] = { 0x00, 0xff }; + int i; + +#ifdef CONFIG_BTF_PRINTF + btf_pointer_test_int(); + btf_pointer_test_char(); + btf_pointer_test_typedef(); + btf_pointer_test_enum(); + btf_pointer_test_struct(); +#endif /* CONFIG_BTF_PRINTF */ + + /* + * Iterate every instance of each kind, printing each associated type. + * This constitutes around 10k tests. + */ + for (i = 0; i < ARRAY_SIZE(fillvals); i++) { + btf_print_kind(BTF_KIND_STRUCT, "struct ", fillvals[i]); + btf_print_kind(BTF_KIND_UNION, "union ", fillvals[i]); + btf_print_kind(BTF_KIND_ENUM, "enum ", fillvals[i]); + btf_print_kind(BTF_KIND_TYPEDEF, "", fillvals[i]); + } + + /* verify unknown type falls back to hashed pointer display */ + test("(null)", "%pT", BTF_PTR_TYPE(NULL, "unknown_type")); + test_btf_hashed("%pT", BTF_PTR_TYPE(skb, "unknown_type")); + + kfree_skb(skb); +} + static void __init test_pointer(void) { @@ -668,6 +968,7 @@ static void __init fwnode_pointer(void) flags(); errptr(); fwnode_pointer(); + btf_pointer(); } static void __init selftest(void) From patchwork Tue May 12 05:56:45 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alan Maguire X-Patchwork-Id: 219429 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-10.0 required=3.0 tests=DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, UNPARSEABLE_RELAY, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id BFFC0C54E8D for ; Tue, 12 May 2020 05:57:48 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 9957F20746 for ; Tue, 12 May 2020 05:57:48 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=oracle.com header.i=@oracle.com header.b="VIucPbF/" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728697AbgELF5r (ORCPT ); Tue, 12 May 2020 01:57:47 -0400 Received: from userp2120.oracle.com ([156.151.31.85]:38430 "EHLO userp2120.oracle.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728651AbgELF5q (ORCPT ); Tue, 12 May 2020 01:57:46 -0400 Received: from pps.filterd (userp2120.oracle.com [127.0.0.1]) by userp2120.oracle.com (8.16.0.42/8.16.0.42) with SMTP id 04C5v2Al113134; Tue, 12 May 2020 05:57:28 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oracle.com; h=from : to : cc : subject : date : message-id : in-reply-to : references; s=corp-2020-01-29; bh=0muaH3bxesQMPeYQ7Ss9Y7YPtsK4pwaftH70/kxoCCU=; b=VIucPbF/5u7CL671xDKXQFAQSK53SAP+ZQvBPE0uAj75wHDD2ACX8PC870g6Kw5VHn8R mcQXn16oFH/8brXg07LCLv1tJGPn7rwfBU+x/oR4zAdW5G3jhTHbfDEAhKJN1gRZIi6g GhywIeHSTrhQewYJWYQHQBJjRSfJkbayxBPHzF+PprLPXkd++lRo3J4TWZ2ZvbYJytgF J5du9mQir2fL2kY0xETtw/5L9iZjwV6Q/Mz5D/iSC8qjn+vd9DwcZLeGiE1N3ICK3p5x WWc7FlthXJsbqxNWnUYiP75H9Jurppl8yJqxYNKfYIuNFBbTrNnEEeykNHFuptgZd5ur 8g== Received: from aserp3030.oracle.com (aserp3030.oracle.com [141.146.126.71]) by userp2120.oracle.com with ESMTP id 30x3mbrv33-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Tue, 12 May 2020 05:57:28 +0000 Received: from pps.filterd (aserp3030.oracle.com [127.0.0.1]) by aserp3030.oracle.com (8.16.0.42/8.16.0.42) with SMTP id 04C5rkEL060671; Tue, 12 May 2020 05:57:27 GMT Received: from aserv0122.oracle.com (aserv0122.oracle.com [141.146.126.236]) by aserp3030.oracle.com with ESMTP id 30x63p3pqn-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 12 May 2020 05:57:27 +0000 Received: from abhmp0017.oracle.com (abhmp0017.oracle.com [141.146.116.23]) by aserv0122.oracle.com (8.14.4/8.14.4) with ESMTP id 04C5vQBJ013789; Tue, 12 May 2020 05:57:26 GMT Received: from localhost.uk.oracle.com (/10.175.210.30) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Mon, 11 May 2020 22:57:26 -0700 From: Alan Maguire To: ast@kernel.org, daniel@iogearbox.net, bpf@vger.kernel.org Cc: joe@perches.com, linux@rasmusvillemoes.dk, arnaldo.melo@gmail.com, yhs@fb.com, kafai@fb.com, songliubraving@fb.com, andriin@fb.com, john.fastabend@gmail.com, kpsingh@chromium.org, linux-kernel@vger.kernel.org, netdev@vger.kernel.org, Alan Maguire Subject: [PATCH v2 bpf-next 7/7] bpf: add tests for %pT format specifier Date: Tue, 12 May 2020 06:56:45 +0100 Message-Id: <1589263005-7887-8-git-send-email-alan.maguire@oracle.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1589263005-7887-1-git-send-email-alan.maguire@oracle.com> References: <1589263005-7887-1-git-send-email-alan.maguire@oracle.com> X-Proofpoint-Virus-Version: vendor=nai engine=6000 definitions=9618 signatures=668687 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 mlxscore=0 spamscore=0 suspectscore=2 malwarescore=0 phishscore=0 adultscore=0 mlxlogscore=999 bulkscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2003020000 definitions=main-2005120052 X-Proofpoint-Virus-Version: vendor=nai engine=6000 definitions=9618 signatures=668687 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 priorityscore=1501 impostorscore=0 mlxscore=0 suspectscore=2 bulkscore=0 mlxlogscore=999 phishscore=0 malwarescore=0 lowpriorityscore=0 spamscore=0 adultscore=0 clxscore=1015 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2003020000 definitions=main-2005120052 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org tests verify we get > 0 return value from bpf_trace_print() using %pT format specifier with various modifiers/pointer values. Signed-off-by: Alan Maguire --- .../selftests/bpf/prog_tests/trace_printk_btf.c | 83 ++++++++++++++++++++++ .../selftests/bpf/progs/netif_receive_skb.c | 81 +++++++++++++++++++++ 2 files changed, 164 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/trace_printk_btf.c create mode 100644 tools/testing/selftests/bpf/progs/netif_receive_skb.c diff --git a/tools/testing/selftests/bpf/prog_tests/trace_printk_btf.c b/tools/testing/selftests/bpf/prog_tests/trace_printk_btf.c new file mode 100644 index 0000000..d7ee158 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/trace_printk_btf.c @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: GPL-2.0 +#include + +struct result { + int ret; + int subtest; + int num_subtest; +}; + +/* return value of bpf_trace_printk()s is stored; if nonzero we failed. */ +static void on_sample(void *ctx, int cpu, void *data, __u32 size) +{ + struct result *resp = (struct result *)data; + + *(struct result *)ctx = *resp; +} + +void test_trace_printk_btf(void) +{ + struct result res = { 0 }; + struct bpf_prog_load_attr attr = { + .file = "./netif_receive_skb.o", + }; + struct perf_buffer_opts pb_opts = {}; + struct bpf_program *prog = NULL; + struct perf_buffer *pb = NULL; + struct bpf_object *obj = NULL; + struct bpf_link *link = NULL; + struct bpf_map *perf_buf_map; + __u32 duration = 0; + int err, prog_fd; + + err = bpf_prog_load_xattr(&attr, &obj, &prog_fd); + if (CHECK(err, "prog_load raw tp", "err %d errno %d\n", err, errno)) + goto close_prog; + + prog = bpf_object__find_program_by_title(obj, + "tp_btf/netif_receive_skb"); + if (CHECK(!prog, "find_prog", "prog netif_receive_skb not found\n")) + goto close_prog; + + link = bpf_program__attach_raw_tracepoint(prog, NULL); + if (CHECK(IS_ERR(link), "attach_raw_tp", "err %ld\n", PTR_ERR(link))) + goto close_prog; + + perf_buf_map = bpf_object__find_map_by_name(obj, "perf_buf_map"); + if (CHECK(!perf_buf_map, "find_perf_buf_map", "not found\n")) + goto close_prog; + + /* set up perf buffer */ + pb_opts.sample_cb = on_sample; + pb_opts.ctx = &res; + pb = perf_buffer__new(bpf_map__fd(perf_buf_map), 1, &pb_opts); + if (CHECK(IS_ERR(pb), "perf_buf__new", "err %ld\n", PTR_ERR(pb))) + goto close_prog; + + /* generate receive event */ + system("ping -c 1 127.0.0.1 >/dev/null"); + + /* read perf buffer */ + err = perf_buffer__poll(pb, 100); + if (CHECK(err < 0, "perf_buffer__poll", "err %d\n", err)) + goto close_prog; + + /* + * Make sure netif_receive_skb program was triggered + * and it sent expected return values from bpf_trace_printk()s + * into ring buffer. + */ + if (CHECK(res.ret <= 0, + "bpf_trace_printk: got return value", + "ret <= 0 %d test %d\n", res.ret, res.subtest)) + goto close_prog; + + CHECK(res.subtest != res.num_subtest, "check all subtests ran", + "only ran %d of %d tests\n", res.subtest, res.num_subtest); + +close_prog: + perf_buffer__free(pb); + if (!IS_ERR_OR_NULL(link)) + bpf_link__destroy(link); + bpf_object__close(obj); +} diff --git a/tools/testing/selftests/bpf/progs/netif_receive_skb.c b/tools/testing/selftests/bpf/progs/netif_receive_skb.c new file mode 100644 index 0000000..b5148df --- /dev/null +++ b/tools/testing/selftests/bpf/progs/netif_receive_skb.c @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2020, Oracle and/or its affiliates. */ +#include +#include +#include +#include +#include + +char _license[] SEC("license") = "GPL"; + +struct { + __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); + __uint(key_size, sizeof(int)); + __uint(value_size, sizeof(int)); +} perf_buf_map SEC(".maps"); + +struct result { + int ret; + int subtest; + int num_subtest; +}; + +typedef struct { + int counter; +} atomic_t; +typedef struct refcount_struct { + atomic_t refs; +} refcount_t; + +struct sk_buff { + /* field names and sizes should match to those in the kernel */ + unsigned int len, data_len; + __u16 mac_len, hdr_len, queue_mapping; + struct net_device *dev; + /* order of the fields doesn't matter */ + refcount_t users; + unsigned char *data; + char __pkt_type_offset[0]; + char cb[48]; +}; + +#define CHECK_PRINTK(_fmt, _p, res) \ + do { \ + char fmt[] = _fmt; \ + ++(res)->num_subtest; \ + if ((res)->ret >= 0) { \ + ++(res)->subtest; \ + (res)->ret = bpf_trace_printk(fmt, sizeof(fmt), \ + (_p)); \ + } \ + } while (0) + +/* TRACE_EVENT(netif_receive_skb, + * TP_PROTO(struct sk_buff *skb), + */ +SEC("tp_btf/netif_receive_skb") +int BPF_PROG(trace_netif_receive_skb, struct sk_buff *skb) +{ + char skb_type[] = "struct sk_buff"; + struct __btf_ptr nullp = { .ptr = 0, .type = skb_type }; + struct __btf_ptr p = { .ptr = skb, .type = skb_type }; + struct result res = { 0, 0 }; + + CHECK_PRINTK("%pT\n", &p, &res); + CHECK_PRINTK("%pTc\n", &p, &res); + CHECK_PRINTK("%pTN\n", &p, &res); + CHECK_PRINTK("%pTx\n", &p, &res); + CHECK_PRINTK("%pT0\n", &p, &res); + CHECK_PRINTK("%pTcNx0\n", &p, &res); + CHECK_PRINTK("%pT\n", &nullp, &res); + CHECK_PRINTK("%pTc\n", &nullp, &res); + CHECK_PRINTK("%pTN\n", &nullp, &res); + CHECK_PRINTK("%pTx\n", &nullp, &res); + CHECK_PRINTK("%pT0\n", &nullp, &res); + CHECK_PRINTK("%pTcNx0\n", &nullp, &res); + + bpf_perf_event_output(ctx, &perf_buf_map, BPF_F_CURRENT_CPU, + &res, sizeof(res)); + + return 0; +}