From patchwork Wed Oct 17 07:23:12 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yonghong Song X-Patchwork-Id: 985134 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=fb.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=fb.com header.i=@fb.com header.b="mkCLdrT6"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 42ZkDp0F0Jz9s9h for ; Wed, 17 Oct 2018 18:23:38 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727371AbeJQPRz (ORCPT ); Wed, 17 Oct 2018 11:17:55 -0400 Received: from mx0b-00082601.pphosted.com ([67.231.153.30]:44804 "EHLO mx0a-00082601.pphosted.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726622AbeJQPRz (ORCPT ); Wed, 17 Oct 2018 11:17:55 -0400 Received: from pps.filterd (m0001303.ppops.net [127.0.0.1]) by m0001303.ppops.net (8.16.0.22/8.16.0.22) with SMTP id w9H7M3Et025113 for ; Wed, 17 Oct 2018 00:23:34 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=fb.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-type; s=facebook; bh=FxpmUJ0scUWpk0GlCcGHg1NKk3kEhwgvAOcNgFXlW/U=; b=mkCLdrT6SYpANWzf0raJSovJICmb6RjmAVAK6OFMwuKRhKhZONU89Tqa7GevYb1PVcef mCTtQDkq3Pa81gVuAfsAFZ09Uuf0ONRyLPhxcAoGWo0XzhvMqnbqEY3eS04AWzPSKFVx uobElAZEVrXpZSvwF/rNULQEooHDWeCtM+A= Received: from mail.thefacebook.com ([199.201.64.23]) by m0001303.ppops.net with ESMTP id 2n5uyggtpp-2 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT) for ; Wed, 17 Oct 2018 00:23:34 -0700 Received: from mx-out.facebook.com (2620:10d:c081:10::13) by mail.thefacebook.com (2620:10d:c081:35::127) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA) id 15.1.1531.3; Wed, 17 Oct 2018 00:23:33 -0700 Received: by devbig003.ftw2.facebook.com (Postfix, from userid 128203) id 815D837021ED; Wed, 17 Oct 2018 00:23:15 -0700 (PDT) Smtp-Origin-Hostprefix: devbig From: Yonghong Song Smtp-Origin-Hostname: devbig003.ftw2.facebook.com To: , , , CC: Smtp-Origin-Cluster: ftw2c04 Subject: [PATCH bpf-next v2 01/13] bpf: btf: Break up btf_type_is_void() Date: Wed, 17 Oct 2018 00:23:12 -0700 Message-ID: <20181017072315.2766920-2-yhs@fb.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20181017072315.2766920-1-yhs@fb.com> References: <20181017072315.2766920-1-yhs@fb.com> X-FB-Internal: Safe MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2018-10-16_14:, , signatures=0 X-Proofpoint-Spam-Reason: safe X-FB-Internal: Safe Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org This patch breaks up btf_type_is_void() into btf_type_is_void() and btf_type_is_fwd(). It also adds btf_type_nosize() to better describe it is testing a type has nosize info. Signed-off-by: Martin KaFai Lau Signed-off-by: Yonghong Song --- kernel/bpf/btf.c | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index 378cef70341c..be406d8906ce 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -306,15 +306,22 @@ static bool btf_type_is_modifier(const struct btf_type *t) static bool btf_type_is_void(const struct btf_type *t) { - /* void => no type and size info. - * Hence, FWD is also treated as void. - */ - return t == &btf_void || BTF_INFO_KIND(t->info) == BTF_KIND_FWD; + return t == &btf_void; +} + +static bool btf_type_is_fwd(const struct btf_type *t) +{ + return BTF_INFO_KIND(t->info) == BTF_KIND_FWD; +} + +static bool btf_type_nosize(const struct btf_type *t) +{ + return btf_type_is_void(t) || btf_type_is_fwd(t); } -static bool btf_type_is_void_or_null(const struct btf_type *t) +static bool btf_type_nosize_or_null(const struct btf_type *t) { - return !t || btf_type_is_void(t); + return !t || btf_type_nosize(t); } /* union is only a special case of struct: @@ -826,7 +833,7 @@ const struct btf_type *btf_type_id_size(const struct btf *btf, u32 size = 0; size_type = btf_type_by_id(btf, size_type_id); - if (btf_type_is_void_or_null(size_type)) + if (btf_type_nosize_or_null(size_type)) return NULL; if (btf_type_has_size(size_type)) { @@ -842,7 +849,7 @@ const struct btf_type *btf_type_id_size(const struct btf *btf, size = btf->resolved_sizes[size_type_id]; size_type_id = btf->resolved_ids[size_type_id]; size_type = btf_type_by_id(btf, size_type_id); - if (btf_type_is_void(size_type)) + if (btf_type_nosize_or_null(size_type)) return NULL; } @@ -1164,7 +1171,7 @@ static int btf_modifier_resolve(struct btf_verifier_env *env, } /* "typedef void new_void", "const void"...etc */ - if (btf_type_is_void(next_type)) + if (btf_type_is_void(next_type) || btf_type_is_fwd(next_type)) goto resolved; if (!env_type_is_resolve_sink(env, next_type) && @@ -1178,7 +1185,7 @@ static int btf_modifier_resolve(struct btf_verifier_env *env, * pretty print). */ if (!btf_type_id_size(btf, &next_type_id, &next_type_size) && - !btf_type_is_void(btf_type_id_resolve(btf, &next_type_id))) { + !btf_type_nosize(btf_type_id_resolve(btf, &next_type_id))) { btf_verifier_log_type(env, v->t, "Invalid type_id"); return -EINVAL; } @@ -1205,7 +1212,7 @@ static int btf_ptr_resolve(struct btf_verifier_env *env, } /* "void *" */ - if (btf_type_is_void(next_type)) + if (btf_type_is_void(next_type) || btf_type_is_fwd(next_type)) goto resolved; if (!env_type_is_resolve_sink(env, next_type) && @@ -1235,7 +1242,7 @@ static int btf_ptr_resolve(struct btf_verifier_env *env, } if (!btf_type_id_size(btf, &next_type_id, &next_type_size) && - !btf_type_is_void(btf_type_id_resolve(btf, &next_type_id))) { + !btf_type_nosize(btf_type_id_resolve(btf, &next_type_id))) { btf_verifier_log_type(env, v->t, "Invalid type_id"); return -EINVAL; } @@ -1396,7 +1403,7 @@ static int btf_array_resolve(struct btf_verifier_env *env, /* Check array->index_type */ index_type_id = array->index_type; index_type = btf_type_by_id(btf, index_type_id); - if (btf_type_is_void_or_null(index_type)) { + if (btf_type_nosize_or_null(index_type)) { btf_verifier_log_type(env, v->t, "Invalid index"); return -EINVAL; } @@ -1415,7 +1422,7 @@ static int btf_array_resolve(struct btf_verifier_env *env, /* Check array->type */ elem_type_id = array->type; elem_type = btf_type_by_id(btf, elem_type_id); - if (btf_type_is_void_or_null(elem_type)) { + if (btf_type_nosize_or_null(elem_type)) { btf_verifier_log_type(env, v->t, "Invalid elem"); return -EINVAL; @@ -1615,7 +1622,7 @@ static int btf_struct_resolve(struct btf_verifier_env *env, const struct btf_type *member_type = btf_type_by_id(env->btf, member_type_id); - if (btf_type_is_void_or_null(member_type)) { + if (btf_type_nosize_or_null(member_type)) { btf_verifier_log_member(env, v->t, member, "Invalid member"); return -EINVAL; From patchwork Wed Oct 17 07:23:13 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yonghong Song X-Patchwork-Id: 985135 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=fb.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=fb.com header.i=@fb.com header.b="fzHyOsHm"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 42ZkDq2kDsz9s9h for ; Wed, 17 Oct 2018 18:23:39 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727521AbeJQPR5 (ORCPT ); Wed, 17 Oct 2018 11:17:57 -0400 Received: from mx0b-00082601.pphosted.com ([67.231.153.30]:44808 "EHLO mx0a-00082601.pphosted.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726999AbeJQPR4 (ORCPT ); Wed, 17 Oct 2018 11:17:56 -0400 Received: from pps.filterd (m0001303.ppops.net [127.0.0.1]) by m0001303.ppops.net (8.16.0.22/8.16.0.22) with SMTP id w9H7M3Ev025113 for ; Wed, 17 Oct 2018 00:23:35 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=fb.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-type; s=facebook; bh=9erzc/QXlP2Sj5NNo7IS73VEMHrsQCcBOP4o6WYH84k=; b=fzHyOsHmir4igfE865qjQzRVPoppBeOio9XpFCUTBRPrEnqLc1PY3kT11qdsV4H4WAN4 SWKgJdVzwbjcWXerxDx8HQR8jmY6/QJfDGAT+8uOq07/CRdx+PA3+VisHO7qOSqgWShG VVpYnwnvvuamj/RPwG2K1VwIwVWF+E1MdzA= Received: from mail.thefacebook.com ([199.201.64.23]) by m0001303.ppops.net with ESMTP id 2n5uyggtpp-4 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT) for ; Wed, 17 Oct 2018 00:23:35 -0700 Received: from mx-out.facebook.com (2620:10d:c081:10::13) by mail.thefacebook.com (2620:10d:c081:35::127) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA) id 15.1.1531.3; Wed, 17 Oct 2018 00:23:33 -0700 Received: by devbig003.ftw2.facebook.com (Postfix, from userid 128203) id 8763D3702247; Wed, 17 Oct 2018 00:23:15 -0700 (PDT) Smtp-Origin-Hostprefix: devbig From: Yonghong Song Smtp-Origin-Hostname: devbig003.ftw2.facebook.com To: , , , CC: Smtp-Origin-Cluster: ftw2c04 Subject: [PATCH bpf-next v2 02/13] bpf: btf: Add BTF_KIND_FUNC and BTF_KIND_FUNC_PROTO Date: Wed, 17 Oct 2018 00:23:13 -0700 Message-ID: <20181017072315.2766920-3-yhs@fb.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20181017072315.2766920-1-yhs@fb.com> References: <20181017072315.2766920-1-yhs@fb.com> X-FB-Internal: Safe MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2018-10-16_14:, , signatures=0 X-Proofpoint-Spam-Reason: safe X-FB-Internal: Safe Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org This patch adds BTF_KIND_FUNC and BTF_KIND_FUNC_PROTO support to the type section. BTF_KIND_FUNC_PROTO is used to specify the type of a function pointer. With this, BTF has a complete set of C types (except float). BTF_KIND_FUNC is used to specify the signature of a defined subprogram. BTF_KIND_FUNC_PROTO can be referenced by another type, e.g., a pointer type, and BTF_KIND_FUNC type cannot be referenced by another type. For both BTF_KIND_FUNC and BTF_KIND_FUNC_PROTO types, the func return type is in t->type (where t is a "struct btf_type" object). The func args are an array of u32s immediately following object "t". As a concrete example, for the C program below, $ cat test.c int foo(int (*bar)(int)) { return bar(5); } with LLVM patch https://reviews.llvm.org/D53261 in Debug mode, we have $ clang -target bpf -g -O2 -mllvm -debug-only=btf -c test.c Type Table: [1] FUNC NameOff=1 Info=0x0c000001 Size/Type=2 ParamType=3 [2] INT NameOff=11 Info=0x01000000 Size/Type=4 Desc=0x01000020 [3] PTR NameOff=0 Info=0x02000000 Size/Type=4 [4] FUNC_PROTO NameOff=0 Info=0x0d000001 Size/Type=2 ParamType=2 String Table: 0 : 1 : foo 5 : .text 11 : int 15 : test.c 22 : int foo(int (*bar)(int)) { return bar(5); } FuncInfo Table: SecNameOff=5 InsnOffset= TypeId=1 ... (Eventually we shall have bpftool to dump btf information like the above.) Function "foo" has a FUNC type (type_id = 1). The parameter of "foo" has type_id 3 which is PTR->FUNC_PROTO, where FUNC_PROTO refers to function pointer "bar". In FuncInfo Table, for section .text, the function, with to-be-determined offset (marked as ), has type_id=1 which refers to a FUNC type. This way, the function signature is available to both kernel and user space. Here, the insn offset is not available during the dump time as relocation is resolved pretty late in the compilation process. Signed-off-by: Martin KaFai Lau Signed-off-by: Yonghong Song --- include/uapi/linux/btf.h | 9 +- kernel/bpf/btf.c | 280 ++++++++++++++++++++++++++++++++++----- 2 files changed, 253 insertions(+), 36 deletions(-) diff --git a/include/uapi/linux/btf.h b/include/uapi/linux/btf.h index 972265f32871..63f8500e6f34 100644 --- a/include/uapi/linux/btf.h +++ b/include/uapi/linux/btf.h @@ -40,7 +40,8 @@ struct btf_type { /* "size" is used by INT, ENUM, STRUCT and UNION. * "size" tells the size of the type it is describing. * - * "type" is used by PTR, TYPEDEF, VOLATILE, CONST and RESTRICT. + * "type" is used by PTR, TYPEDEF, VOLATILE, CONST, RESTRICT, + * FUNC and FUNC_PROTO. * "type" is a type_id referring to another type. */ union { @@ -64,8 +65,10 @@ struct btf_type { #define BTF_KIND_VOLATILE 9 /* Volatile */ #define BTF_KIND_CONST 10 /* Const */ #define BTF_KIND_RESTRICT 11 /* Restrict */ -#define BTF_KIND_MAX 11 -#define NR_BTF_KINDS 12 +#define BTF_KIND_FUNC 12 /* Function */ +#define BTF_KIND_FUNC_PROTO 13 /* Function Prototype */ +#define BTF_KIND_MAX 13 +#define NR_BTF_KINDS 14 /* For some specific BTF_KIND, "struct btf_type" is immediately * followed by extra data. diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index be406d8906ce..763f8e06bc91 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -259,6 +260,8 @@ static const char * const btf_kind_str[NR_BTF_KINDS] = { [BTF_KIND_VOLATILE] = "VOLATILE", [BTF_KIND_CONST] = "CONST", [BTF_KIND_RESTRICT] = "RESTRICT", + [BTF_KIND_FUNC] = "FUNC", + [BTF_KIND_FUNC_PROTO] = "FUNC_PROTO", }; struct btf_kind_operations { @@ -281,6 +284,9 @@ struct btf_kind_operations { static const struct btf_kind_operations * const kind_ops[NR_BTF_KINDS]; static struct btf_type btf_void; +static int btf_resolve(struct btf_verifier_env *env, + const struct btf_type *t, u32 type_id); + static bool btf_type_is_modifier(const struct btf_type *t) { /* Some of them is not strictly a C modifier @@ -314,9 +320,20 @@ static bool btf_type_is_fwd(const struct btf_type *t) return BTF_INFO_KIND(t->info) == BTF_KIND_FWD; } +static bool btf_type_is_func(const struct btf_type *t) +{ + return BTF_INFO_KIND(t->info) == BTF_KIND_FUNC; +} + +static bool btf_type_is_func_proto(const struct btf_type *t) +{ + return BTF_INFO_KIND(t->info) == BTF_KIND_FUNC_PROTO; +} + static bool btf_type_nosize(const struct btf_type *t) { - return btf_type_is_void(t) || btf_type_is_fwd(t); + return btf_type_is_void(t) || btf_type_is_fwd(t) || + btf_type_is_func(t) || btf_type_is_func_proto(t); } static bool btf_type_nosize_or_null(const struct btf_type *t) @@ -433,6 +450,27 @@ static bool btf_name_offset_valid(const struct btf *btf, u32 offset) offset < btf->hdr.str_len; } +static bool btf_name_valid_identifier(const struct btf *btf, u32 offset) +{ + /* offset must be valid */ + const char *src = &btf->strings[offset]; + const char *src_limit; + + if (!isalpha(*src) && *src != '_') + return false; + + /* set a limit on identifier length */ + src_limit = src + KSYM_NAME_LEN; + src++; + while (*src && src < src_limit) { + if (!isalnum(*src) && *src != '_') + return false; + src++; + } + + return !*src; +} + static const char *btf_name_by_offset(const struct btf *btf, u32 offset) { if (!offset) @@ -747,7 +785,9 @@ static bool env_type_is_resolve_sink(const struct btf_verifier_env *env, /* int, enum or void is a sink */ return !btf_type_needs_resolve(next_type); case RESOLVE_PTR: - /* int, enum, void, struct or array is a sink for ptr */ + /* int, enum, void, struct, array or func_ptoto is a sink + * for ptr + */ return !btf_type_is_modifier(next_type) && !btf_type_is_ptr(next_type); case RESOLVE_STRUCT_OR_ARRAY: @@ -1170,6 +1210,14 @@ static int btf_modifier_resolve(struct btf_verifier_env *env, return -EINVAL; } + if (btf_type_is_func_proto(next_type)) { + if (env->resolve_mode == RESOLVE_PTR) + goto resolved; + + btf_verifier_log_type(env, v->t, "Invalid type_id"); + return -EINVAL; + } + /* "typedef void new_void", "const void"...etc */ if (btf_type_is_void(next_type) || btf_type_is_fwd(next_type)) goto resolved; @@ -1185,7 +1233,8 @@ static int btf_modifier_resolve(struct btf_verifier_env *env, * pretty print). */ if (!btf_type_id_size(btf, &next_type_id, &next_type_size) && - !btf_type_nosize(btf_type_id_resolve(btf, &next_type_id))) { + (!btf_type_nosize(btf_type_id_resolve(btf, &next_type_id)) || + btf_type_is_func(next_type))) { btf_verifier_log_type(env, v->t, "Invalid type_id"); return -EINVAL; } @@ -1212,7 +1261,8 @@ static int btf_ptr_resolve(struct btf_verifier_env *env, } /* "void *" */ - if (btf_type_is_void(next_type) || btf_type_is_fwd(next_type)) + if (btf_type_is_void(next_type) || btf_type_is_fwd(next_type) || + btf_type_is_func_proto(next_type)) goto resolved; if (!env_type_is_resolve_sink(env, next_type) && @@ -1242,7 +1292,8 @@ static int btf_ptr_resolve(struct btf_verifier_env *env, } if (!btf_type_id_size(btf, &next_type_id, &next_type_size) && - !btf_type_nosize(btf_type_id_resolve(btf, &next_type_id))) { + (!btf_type_nosize(btf_type_id_resolve(btf, &next_type_id)) || + btf_type_is_func(next_type))) { btf_verifier_log_type(env, v->t, "Invalid type_id"); return -EINVAL; } @@ -1550,6 +1601,14 @@ static s32 btf_struct_check_meta(struct btf_verifier_env *env, return -EINVAL; } + if (member->name_off && + !btf_name_valid_identifier(btf, member->name_off)) { + btf_verifier_log_member(env, t, member, + "Invalid member name:%s", + btf_name_by_offset(btf, member->name_off)); + return -EINVAL; + } + /* A member cannot be in type void */ if (!member->type || !BTF_TYPE_ID_VALID(member->type)) { btf_verifier_log_member(env, t, member, @@ -1787,6 +1846,142 @@ static struct btf_kind_operations enum_ops = { .seq_show = btf_enum_seq_show, }; +static s32 btf_func_check_meta(struct btf_verifier_env *env, + const struct btf_type *t, + u32 meta_left) +{ + u32 meta_needed = btf_type_vlen(t) * sizeof(u32); + + if (meta_left < meta_needed) { + btf_verifier_log_basic(env, t, + "meta_left:%u meta_needed:%u", + meta_left, meta_needed); + return -EINVAL; + } + + btf_verifier_log_type(env, t, NULL); + + return meta_needed; +} + +static void btf_func_log(struct btf_verifier_env *env, + const struct btf_type *t) +{ + u16 nr_args = btf_type_vlen(t), i; + u32 *args = (u32 *)(t + 1); + + btf_verifier_log(env, "return=%u args=(", t->type); + if (!nr_args) { + btf_verifier_log(env, "void"); + goto done; + } + + if (nr_args == 1 && !args[0]) { + /* Only one vararg */ + btf_verifier_log(env, "vararg"); + goto done; + } + + btf_verifier_log(env, "%u", args[0]); + for (i = 1; i < nr_args - 1; i++) + btf_verifier_log(env, ", %u", args[i]); + if (nr_args > 1) { + u32 last_arg = args[nr_args - 1]; + + if (last_arg) + btf_verifier_log(env, ", %u", last_arg); + else + btf_verifier_log(env, ", vararg"); + } + +done: + btf_verifier_log(env, ")"); +} + +static int btf_func_check(struct btf_verifier_env *env, + const struct btf_type *t, + u32 type_id) +{ + u16 nr_args = btf_type_vlen(t), i; + const struct btf *btf = env->btf; + const struct btf_type *ret_type; + u32 *args = (u32 *)(t + 1); + u32 ret_type_id; + int err; + + /* Check func return type which could be "void" (t->type == 0) */ + ret_type_id = t->type; + if (ret_type_id) { + /* return type is not "void" */ + ret_type = btf_type_by_id(btf, ret_type_id); + if (btf_type_needs_resolve(ret_type) && + !env_type_is_resolved(env, ret_type_id)) { + err = btf_resolve(env, ret_type, ret_type_id); + if (err) + return err; + } + + /* Ensure the return type is a type that has a size */ + if (!btf_type_id_size(btf, &ret_type_id, NULL)) { + btf_verifier_log_type(env, t, "Invalid return type"); + return -EINVAL; + } + } + + if (!nr_args) + return 0; + + /* Last func arg type_id could be 0 if it is a vararg */ + if (!args[nr_args - 1]) + nr_args--; + + err = 0; + for (i = 0; i < nr_args; i++) { + const struct btf_type *arg_type; + u32 arg_type_id; + + arg_type_id = args[i]; + arg_type = btf_type_by_id(btf, arg_type_id); + if (!arg_type) { + btf_verifier_log_type(env, t, "Invalid arg#%u", i + 1); + err = -EINVAL; + break; + } + + if (btf_type_needs_resolve(arg_type) && + !env_type_is_resolved(env, arg_type_id)) { + err = btf_resolve(env, arg_type, arg_type_id); + if (err) + break; + } + + if (!btf_type_id_size(btf, &arg_type_id, NULL)) { + btf_verifier_log_type(env, t, "Invalid arg#%u", i + 1); + err = -EINVAL; + break; + } + } + + return err; +} + +static struct btf_kind_operations func_ops = { + .check_meta = btf_func_check_meta, + .resolve = btf_df_resolve, + /* + * BPF_KIND_FUNC_PROTO cannot be directly referred by + * a struct's member. + * + * It should be a funciton pointer instead. + * (i.e. struct's member -> BTF_KIND_PTR -> BTF_KIND_FUNC_PROTO) + * + * Hence, there is no btf_func_check_member(). + */ + .check_member = btf_df_check_member, + .log_details = btf_func_log, + .seq_show = btf_df_seq_show, +}; + static const struct btf_kind_operations * const kind_ops[NR_BTF_KINDS] = { [BTF_KIND_INT] = &int_ops, [BTF_KIND_PTR] = &ptr_ops, @@ -1799,6 +1994,8 @@ static const struct btf_kind_operations * const kind_ops[NR_BTF_KINDS] = { [BTF_KIND_VOLATILE] = &modifier_ops, [BTF_KIND_CONST] = &modifier_ops, [BTF_KIND_RESTRICT] = &modifier_ops, + [BTF_KIND_FUNC] = &func_ops, + [BTF_KIND_FUNC_PROTO] = &func_ops, }; static s32 btf_check_meta(struct btf_verifier_env *env, @@ -1870,30 +2067,6 @@ static int btf_check_all_metas(struct btf_verifier_env *env) return 0; } -static int btf_resolve(struct btf_verifier_env *env, - const struct btf_type *t, u32 type_id) -{ - const struct resolve_vertex *v; - int err = 0; - - env->resolve_mode = RESOLVE_TBD; - env_stack_push(env, t, type_id); - while (!err && (v = env_stack_peak(env))) { - env->log_type_id = v->type_id; - err = btf_type_ops(v->t)->resolve(env, v); - } - - env->log_type_id = type_id; - if (err == -E2BIG) - btf_verifier_log_type(env, t, - "Exceeded max resolving depth:%u", - MAX_RESOLVE_DEPTH); - else if (err == -EEXIST) - btf_verifier_log_type(env, t, "Loop detected"); - - return err; -} - static bool btf_resolve_valid(struct btf_verifier_env *env, const struct btf_type *t, u32 type_id) @@ -1927,6 +2100,39 @@ static bool btf_resolve_valid(struct btf_verifier_env *env, return false; } +static int btf_resolve(struct btf_verifier_env *env, + const struct btf_type *t, u32 type_id) +{ + u32 save_log_type_id = env->log_type_id; + const struct resolve_vertex *v; + int err = 0; + + env->resolve_mode = RESOLVE_TBD; + env_stack_push(env, t, type_id); + while (!err && (v = env_stack_peak(env))) { + env->log_type_id = v->type_id; + err = btf_type_ops(v->t)->resolve(env, v); + } + + env->log_type_id = type_id; + if (err == -E2BIG) { + btf_verifier_log_type(env, t, + "Exceeded max resolving depth:%u", + MAX_RESOLVE_DEPTH); + } else if (err == -EEXIST) { + btf_verifier_log_type(env, t, "Loop detected"); + } + + /* Final sanity check */ + if (!err && !btf_resolve_valid(env, t, type_id)) { + btf_verifier_log_type(env, t, "Invalid resolve state"); + err = -EINVAL; + } + + env->log_type_id = save_log_type_id; + return err; +} + static int btf_check_all_types(struct btf_verifier_env *env) { struct btf *btf = env->btf; @@ -1949,10 +2155,18 @@ static int btf_check_all_types(struct btf_verifier_env *env) return err; } - if (btf_type_needs_resolve(t) && - !btf_resolve_valid(env, t, type_id)) { - btf_verifier_log_type(env, t, "Invalid resolve state"); - return -EINVAL; + if (btf_type_is_func(t) || btf_type_is_func_proto(t)) { + if (btf_type_is_func(t) && + (!btf_name_offset_valid(btf, t->name_off) || + !btf_name_valid_identifier(btf, t->name_off))) { + btf_verifier_log_type(env, t, + "Invalid type_id"); + return -EINVAL; + } + + err = btf_func_check(env, t, type_id); + if (err) + return err; } } From patchwork Wed Oct 17 07:23:14 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yonghong Song X-Patchwork-Id: 985133 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=fb.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=fb.com header.i=@fb.com header.b="fcKj8lLX"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 42ZkDg2gsnz9s9h for ; Wed, 17 Oct 2018 18:23:31 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727265AbeJQPRr (ORCPT ); Wed, 17 Oct 2018 11:17:47 -0400 Received: from mx0a-00082601.pphosted.com ([67.231.145.42]:35272 "EHLO mx0a-00082601.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726622AbeJQPRr (ORCPT ); Wed, 17 Oct 2018 11:17:47 -0400 Received: from pps.filterd (m0044010.ppops.net [127.0.0.1]) by mx0a-00082601.pphosted.com (8.16.0.22/8.16.0.22) with SMTP id w9H7JXaQ006929 for ; Wed, 17 Oct 2018 00:23:28 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=fb.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-type; s=facebook; bh=wLplk5Abj3aRQRESANhYmDtQK6pfYCo+QRcTmqHcZQI=; b=fcKj8lLX/osRaPNvGXphtk3o2DH4CvWNQ6YmcN0VLWjXvQJRqaTsIw/F6s6C+0q8fIMI ogeH6HoTTMq6ZzZw+qH1eXI8r3lXqecdmEgtaAsCAo0kj3sk2YnJsdrTAiBXoM0neyYk StfY7AOv7lK3B8U27aJxhn0agAnWgrICvDs= Received: from mail.thefacebook.com ([199.201.64.23]) by mx0a-00082601.pphosted.com with ESMTP id 2n60jkr0dn-2 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT) for ; Wed, 17 Oct 2018 00:23:28 -0700 Received: from mx-out.facebook.com (2620:10d:c081:10::13) by mail.thefacebook.com (2620:10d:c081:35::130) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA) id 15.1.1531.3; Wed, 17 Oct 2018 00:23:27 -0700 Received: by devbig003.ftw2.facebook.com (Postfix, from userid 128203) id 94C62370225C; Wed, 17 Oct 2018 00:23:15 -0700 (PDT) Smtp-Origin-Hostprefix: devbig From: Yonghong Song Smtp-Origin-Hostname: devbig003.ftw2.facebook.com To: , , , CC: Smtp-Origin-Cluster: ftw2c04 Subject: [PATCH bpf-next v2 03/13] tools/bpf: sync kernel btf.h header Date: Wed, 17 Oct 2018 00:23:14 -0700 Message-ID: <20181017072315.2766920-4-yhs@fb.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20181017072315.2766920-1-yhs@fb.com> References: <20181017072315.2766920-1-yhs@fb.com> X-FB-Internal: Safe MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2018-10-16_14:, , signatures=0 X-Proofpoint-Spam-Reason: safe X-FB-Internal: Safe Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org The kernel uapi btf.h is synced to the tools directory. Signed-off-by: Martin KaFai Lau Signed-off-by: Yonghong Song --- tools/include/uapi/linux/btf.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tools/include/uapi/linux/btf.h b/tools/include/uapi/linux/btf.h index 972265f32871..63f8500e6f34 100644 --- a/tools/include/uapi/linux/btf.h +++ b/tools/include/uapi/linux/btf.h @@ -40,7 +40,8 @@ struct btf_type { /* "size" is used by INT, ENUM, STRUCT and UNION. * "size" tells the size of the type it is describing. * - * "type" is used by PTR, TYPEDEF, VOLATILE, CONST and RESTRICT. + * "type" is used by PTR, TYPEDEF, VOLATILE, CONST, RESTRICT, + * FUNC and FUNC_PROTO. * "type" is a type_id referring to another type. */ union { @@ -64,8 +65,10 @@ struct btf_type { #define BTF_KIND_VOLATILE 9 /* Volatile */ #define BTF_KIND_CONST 10 /* Const */ #define BTF_KIND_RESTRICT 11 /* Restrict */ -#define BTF_KIND_MAX 11 -#define NR_BTF_KINDS 12 +#define BTF_KIND_FUNC 12 /* Function */ +#define BTF_KIND_FUNC_PROTO 13 /* Function Prototype */ +#define BTF_KIND_MAX 13 +#define NR_BTF_KINDS 14 /* For some specific BTF_KIND, "struct btf_type" is immediately * followed by extra data. From patchwork Wed Oct 17 07:23:15 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yonghong Song X-Patchwork-Id: 985137 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=fb.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=fb.com header.i=@fb.com header.b="oCHFUe5r"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 42ZkF13Wpbz9s9h for ; Wed, 17 Oct 2018 18:23:49 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727575AbeJQPSH (ORCPT ); Wed, 17 Oct 2018 11:18:07 -0400 Received: from mx0a-00082601.pphosted.com ([67.231.145.42]:51488 "EHLO mx0a-00082601.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726622AbeJQPSG (ORCPT ); Wed, 17 Oct 2018 11:18:06 -0400 Received: from pps.filterd (m0109334.ppops.net [127.0.0.1]) by mx0a-00082601.pphosted.com (8.16.0.22/8.16.0.22) with SMTP id w9H7MXdW024135 for ; Wed, 17 Oct 2018 00:23:47 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=fb.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-type; s=facebook; bh=w9eMA2Oh2NQxCij1cIZGCnqZURRydEy5ScOLlccwaLQ=; b=oCHFUe5rLYyd6t2RrAJkz6d7ArOpIs1PdB+5FtQ3KzxpY2+1Q3v+7bnxlUjy1HuoTW2O GpprrUxV8RcvoDuMXnNAgq1JJBLbv39MpkK3oF2NPoddHaMBcANDjegGp8SDHaFQKMsx 7y6bUxoauLn6Mt0O7chQckEZbjetiOxVuBk= Received: from mail.thefacebook.com ([199.201.64.23]) by mx0a-00082601.pphosted.com with ESMTP id 2n5xwv08va-2 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT) for ; Wed, 17 Oct 2018 00:23:47 -0700 Received: from mx-out.facebook.com (2620:10d:c081:10::13) by mail.thefacebook.com (2620:10d:c081:35::128) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA) id 15.1.1531.3; Wed, 17 Oct 2018 00:23:26 -0700 Received: by devbig003.ftw2.facebook.com (Postfix, from userid 128203) id A3A5E370225F; Wed, 17 Oct 2018 00:23:15 -0700 (PDT) Smtp-Origin-Hostprefix: devbig From: Yonghong Song Smtp-Origin-Hostname: devbig003.ftw2.facebook.com To: , , , CC: Smtp-Origin-Cluster: ftw2c04 Subject: [PATCH bpf-next v2 04/13] tools/bpf: add btf func/func_proto unit tests in selftest test_btf Date: Wed, 17 Oct 2018 00:23:15 -0700 Message-ID: <20181017072315.2766920-5-yhs@fb.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20181017072315.2766920-1-yhs@fb.com> References: <20181017072315.2766920-1-yhs@fb.com> X-FB-Internal: Safe MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2018-10-16_14:, , signatures=0 X-Proofpoint-Spam-Reason: safe X-FB-Internal: Safe Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Add several BTF_KIND_FUNC and BTF_KIND_FUNC_PROTO unit tests in bpf selftest test_btf. Signed-off-by: Martin KaFai Lau Signed-off-by: Yonghong Song --- tools/lib/bpf/btf.c | 4 + tools/testing/selftests/bpf/test_btf.c | 216 +++++++++++++++++++++++++ 2 files changed, 220 insertions(+) diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c index 449591aa9900..33095fc1860b 100644 --- a/tools/lib/bpf/btf.c +++ b/tools/lib/bpf/btf.c @@ -165,6 +165,10 @@ static int btf_parse_type_sec(struct btf *btf, btf_print_fn_t err_log) case BTF_KIND_ENUM: next_type += vlen * sizeof(struct btf_enum); break; + case BTF_KIND_FUNC: + case BTF_KIND_FUNC_PROTO: + next_type += vlen * sizeof(int); + break; case BTF_KIND_TYPEDEF: case BTF_KIND_PTR: case BTF_KIND_FWD: diff --git a/tools/testing/selftests/bpf/test_btf.c b/tools/testing/selftests/bpf/test_btf.c index f42b3396d622..b6461c3c5e11 100644 --- a/tools/testing/selftests/bpf/test_btf.c +++ b/tools/testing/selftests/bpf/test_btf.c @@ -1374,6 +1374,222 @@ static struct btf_raw_test raw_tests[] = { .map_create_err = true, }, +{ + .descr = "func pointer #1", + .raw_types = { + BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ + BTF_TYPE_INT_ENC(0, 0, 0, 32, 4), /* [2] */ + /* int (*func)(int, unsigned int) */ + BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_FUNC_PROTO, 0, 2), 1), /* [3] */ + 1, 2, + BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_PTR, 0, 0), 3), /* [4] */ + BTF_END_RAW, + }, + .str_sec = "", + .str_sec_size = sizeof(""), + .map_type = BPF_MAP_TYPE_ARRAY, + .map_name = "func_type_check_btf", + .key_size = sizeof(int), + .value_size = sizeof(int), + .key_type_id = 1, + .value_type_id = 1, + .max_entries = 4, +}, + +{ + .descr = "func pointer #2", + .raw_types = { + BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ + BTF_TYPE_INT_ENC(0, 0, 0, 32, 4), /* [2] */ + /* void (*func)(int, unsigned int, ....) */ + BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_FUNC_PROTO, 0, 3), 0), /* [3] */ + 1, 2, 0, + BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_PTR, 0, 0), 3), /* [4] */ + BTF_END_RAW, + }, + .str_sec = "", + .str_sec_size = sizeof(""), + .map_type = BPF_MAP_TYPE_ARRAY, + .map_name = "func_type_check_btf", + .key_size = sizeof(int), + .value_size = sizeof(int), + .key_type_id = 1, + .value_type_id = 1, + .max_entries = 4, +}, + +{ + .descr = "func pointer #3", + .raw_types = { + BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ + BTF_TYPE_INT_ENC(0, 0, 0, 32, 4), /* [2] */ + /* void (*func)(void, int, unsigned int) */ + BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_FUNC_PROTO, 0, 3), 0), /* [3] */ + 1, 0, 2, + BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_PTR, 0, 0), 3), /* [4] */ + BTF_END_RAW, + }, + .str_sec = "", + .str_sec_size = sizeof(""), + .map_type = BPF_MAP_TYPE_ARRAY, + .map_name = "func_type_check_btf", + .key_size = sizeof(int), + .value_size = sizeof(int), + .key_type_id = 1, + .value_type_id = 1, + .max_entries = 4, + .btf_load_err = true, + .err_str = "Invalid arg#2", +}, + +{ + .descr = "func pointer #4", + .raw_types = { + BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ + BTF_TYPE_INT_ENC(0, 0, 0, 32, 4), /* [2] */ + /* + * Testing: + * BTF_KIND_CONST => BTF_KIND_TYPEDEF => BTF_KIND_PTR => + * BTF_KIND_FUNC_PROTO + */ + /* typedef void (*func_ptr)(int, unsigned int) */ + BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_TYPEDEF, 0, 0), 5),/* [3] */ + /* const func_ptr */ + BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_CONST, 0, 0), 3), /* [4] */ + BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_PTR, 0, 0), 6), /* [5] */ + BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_FUNC_PROTO, 0, 2), 0), /* [6] */ + 1, 2, + BTF_END_RAW, + }, + .str_sec = "", + .str_sec_size = sizeof(""), + .map_type = BPF_MAP_TYPE_ARRAY, + .map_name = "func_type_check_btf", + .key_size = sizeof(int), + .value_size = sizeof(int), + .key_type_id = 1, + .value_type_id = 1, + .max_entries = 4, +}, + +{ + .descr = "func pointer #5", + .raw_types = { + BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ + BTF_TYPE_INT_ENC(0, 0, 0, 32, 4), /* [2] */ + /* + * Skipped the BTF_KIND_PTR. + * BTF_KIND_CONST => BTF_KIND_TYPEDEF => BTF_KIND_FUNC_PROTO + */ + BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_CONST, 0, 0), 4), /* [3] */ + BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_TYPEDEF, 0, 0), 5),/* [4] */ + BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_FUNC_PROTO, 0, 2), 0), /* [5] */ + 1, 2, + BTF_END_RAW, + }, + .str_sec = "", + .str_sec_size = sizeof(""), + .map_type = BPF_MAP_TYPE_ARRAY, + .map_name = "func_type_check_btf", + .key_size = sizeof(int), + .value_size = sizeof(int), + .key_type_id = 1, + .value_type_id = 1, + .max_entries = 4, + .btf_load_err = true, + .err_str = "Invalid type_id", +}, + +{ + /* Test btf_resolve() in btf_check_func() */ + .descr = "func pointer #6", + .raw_types = { + BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ + /* void (*func)(const void *) */ + BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_FUNC_PROTO, 0, 1), 0), /* [2] */ + 4, + BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_PTR, 0, 0), 2), /* [3] */ + BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_CONST, 0, 0), 5), /* [4] */ + BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_PTR, 0, 0), 0), /* [5] */ + BTF_END_RAW, + }, + .str_sec = "", + .str_sec_size = sizeof(""), + .map_type = BPF_MAP_TYPE_ARRAY, + .map_name = "func_type_check_btf", + .key_size = sizeof(int), + .value_size = sizeof(int), + .key_type_id = 1, + .value_type_id = 1, + .max_entries = 4, +}, + +{ + .descr = "func #1", + .raw_types = { + BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ + BTF_TYPE_INT_ENC(0, 0, 0, 32, 4), /* [2] */ + BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_FUNC, 0, 2), 1), /* [3] */ + 1, 2, + BTF_END_RAW, + }, + .str_sec = "\0A\0", + .str_sec_size = sizeof("\0A\0"), + .map_type = BPF_MAP_TYPE_ARRAY, + .map_name = "func_type_check_btf", + .key_size = sizeof(int), + .value_size = sizeof(int), + .key_type_id = 1, + .value_type_id = 1, + .max_entries = 4, +}, + +{ + .descr = "func #2", + .raw_types = { + BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ + BTF_TYPE_INT_ENC(0, 0, 0, 32, 4), /* [2] */ + BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_FUNC, 0, 2), 1), /* [3] */ + 1, 2, + BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_PTR, 0, 0), 3), /* [4] */ + BTF_END_RAW, + }, + .str_sec = "\0A\0", + .str_sec_size = sizeof("\0A\0"), + .map_type = BPF_MAP_TYPE_ARRAY, + .map_name = "func_type_check_btf", + .key_size = sizeof(int), + .value_size = sizeof(int), + .key_type_id = 1, + .value_type_id = 1, + .max_entries = 4, + .btf_load_err = true, + .err_str = "Invalid type_id", +}, + +{ + .descr = "func #3", + .raw_types = { + BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ + BTF_TYPE_INT_ENC(0, 0, 0, 32, 4), /* [2] */ + BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_TYPEDEF, 0, 0), 4),/* [3] */ + BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_FUNC, 0, 2), 0), /* [4] */ + 1, 2, + BTF_END_RAW, + }, + .str_sec = "\0A\0", + .str_sec_size = sizeof("\0A\0"), + .map_type = BPF_MAP_TYPE_ARRAY, + .map_name = "func_type_check_btf", + .key_size = sizeof(int), + .value_size = sizeof(int), + .key_type_id = 1, + .value_type_id = 1, + .max_entries = 4, + .btf_load_err = true, + .err_str = "Invalid type_id", +}, + }; /* struct btf_raw_test raw_tests[] */ static const char *get_next_str(const char *start, const char *end) From patchwork Wed Oct 17 07:23:40 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yonghong Song X-Patchwork-Id: 985140 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=fb.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=fb.com header.i=@fb.com header.b="ADfW+eW8"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 42ZkF62jHSz9s9h for ; Wed, 17 Oct 2018 18:23:54 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727628AbeJQPSL (ORCPT ); Wed, 17 Oct 2018 11:18:11 -0400 Received: from mx0a-00082601.pphosted.com ([67.231.145.42]:51512 "EHLO mx0a-00082601.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727193AbeJQPSL (ORCPT ); Wed, 17 Oct 2018 11:18:11 -0400 Received: from pps.filterd (m0109334.ppops.net [127.0.0.1]) by mx0a-00082601.pphosted.com (8.16.0.22/8.16.0.22) with SMTP id w9H7MXdh024135 for ; Wed, 17 Oct 2018 00:23:51 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=fb.com; h=from : to : cc : subject : date : message-id : mime-version : content-type; s=facebook; bh=AykvToNYKtC7o8WobdHmFpXaR5u9FeBtCisX03n1AA0=; b=ADfW+eW8VN/CLiI5x3ZSAclcCHePKOaPqBBO3dmq288TW5D+buPzIWxcegiJxLDNJZoi Bx7GdTYqgv1J7y4h/66NL3q/1EtfWJYinu60r/t8e/Gy/RtxF7i4iwVzw2cMGWlzQW3G 0xAO2nKJCvfgZ8vv6n/ZfKapLFIEFNLXHx4= Received: from mail.thefacebook.com ([199.201.64.23]) by mx0a-00082601.pphosted.com with ESMTP id 2n5xwv08va-13 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT) for ; Wed, 17 Oct 2018 00:23:51 -0700 Received: from mx-out.facebook.com (2620:10d:c081:10::13) by mail.thefacebook.com (2620:10d:c081:35::128) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA) id 15.1.1531.3; Wed, 17 Oct 2018 00:23:45 -0700 Received: by devbig003.ftw2.facebook.com (Postfix, from userid 128203) id 6C4ED3702247; Wed, 17 Oct 2018 00:23:44 -0700 (PDT) Smtp-Origin-Hostprefix: devbig From: Yonghong Song Smtp-Origin-Hostname: devbig003.ftw2.facebook.com To: , , , CC: Smtp-Origin-Cluster: ftw2c04 Subject: [PATCH bpf-next v2 05/13] bpf: get better bpf_prog ksyms based on btf func type_id Date: Wed, 17 Oct 2018 00:23:40 -0700 Message-ID: <20181017072344.2767700-1-yhs@fb.com> X-Mailer: git-send-email 2.17.1 X-FB-Internal: Safe MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2018-10-16_14:, , signatures=0 X-Proofpoint-Spam-Reason: safe X-FB-Internal: Safe Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org This patch added interface to load a program with the following additional information: . prog_btf_fd . func_info and func_info_len where func_info will provides function range and type_id corresponding to each function. If verifier agrees with function range provided by the user, the bpf_prog ksym for each function will use the func name provided in the type_id, which is supposed to provide better encoding as it is not limited by 16 bytes program name limitation and this is better for bpf program which contains multiple subprograms. The bpf_prog_info interface is also extended to return btf_id and jited_func_types, so user spaces can print out the function prototype for each jited function. Signed-off-by: Yonghong Song --- include/linux/bpf.h | 2 + include/linux/bpf_verifier.h | 1 + include/linux/btf.h | 2 + include/uapi/linux/bpf.h | 11 +++++ kernel/bpf/btf.c | 16 +++++++ kernel/bpf/core.c | 10 +++++ kernel/bpf/syscall.c | 83 +++++++++++++++++++++++++++++++++++- kernel/bpf/verifier.c | 46 ++++++++++++++++++++ 8 files changed, 170 insertions(+), 1 deletion(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index e60fff48288b..a99e038ce9c4 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -308,6 +308,8 @@ struct bpf_prog_aux { void *security; #endif struct bpf_prog_offload *offload; + struct btf *btf; + u32 type_id; /* type id for this prog/func */ union { struct work_struct work; struct rcu_head rcu; diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h index 9e8056ec20fa..e84782ec50ac 100644 --- a/include/linux/bpf_verifier.h +++ b/include/linux/bpf_verifier.h @@ -201,6 +201,7 @@ static inline bool bpf_verifier_log_needed(const struct bpf_verifier_log *log) struct bpf_subprog_info { u32 start; /* insn idx of function entry point */ u16 stack_depth; /* max. stack depth used by this function */ + u32 type_id; /* btf type_id for this subprog */ }; /* single container for all structs diff --git a/include/linux/btf.h b/include/linux/btf.h index e076c4697049..4611a53b5dd7 100644 --- a/include/linux/btf.h +++ b/include/linux/btf.h @@ -46,5 +46,7 @@ void btf_type_seq_show(const struct btf *btf, u32 type_id, void *obj, struct seq_file *m); int btf_get_fd_by_id(u32 id); u32 btf_id(const struct btf *btf); +bool btf_type_id_func(const struct btf *btf, u32 type_id); +const char *btf_get_name_by_id(const struct btf *btf, u32 type_id); #endif diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index f9187b41dff6..7ebbf4f06a65 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -332,6 +332,9 @@ union bpf_attr { * (context accesses, allowed helpers, etc). */ __u32 expected_attach_type; + __u32 prog_btf_fd; /* fd pointing to BTF type data */ + __u32 func_info_len; /* func_info length */ + __aligned_u64 func_info; /* func type info */ }; struct { /* anonymous struct used by BPF_OBJ_* commands */ @@ -2585,6 +2588,9 @@ struct bpf_prog_info { __u32 nr_jited_func_lens; __aligned_u64 jited_ksyms; __aligned_u64 jited_func_lens; + __u32 btf_id; + __u32 nr_jited_func_types; + __aligned_u64 jited_func_types; } __attribute__((aligned(8))); struct bpf_map_info { @@ -2896,4 +2902,9 @@ struct bpf_flow_keys { }; }; +struct bpf_func_info { + __u32 insn_offset; + __u32 type_id; +}; + #endif /* _UAPI__LINUX_BPF_H__ */ diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index 763f8e06bc91..9e97bbbafe9b 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -489,6 +489,15 @@ static const struct btf_type *btf_type_by_id(const struct btf *btf, u32 type_id) return btf->types[type_id]; } +bool btf_type_id_func(const struct btf *btf, u32 type_id) +{ + const struct btf_type *type = btf_type_by_id(btf, type_id); + + if (!type || !btf_type_is_func(type)) + return false; + return true; +} + /* * Regular int is not a bit field and it must be either * u8/u16/u32/u64. @@ -2582,3 +2591,10 @@ u32 btf_id(const struct btf *btf) { return btf->id; } + +const char *btf_get_name_by_id(const struct btf *btf, u32 type_id) +{ + const struct btf_type *t = btf_type_by_id(btf, type_id); + + return btf_name_by_offset(btf, t->name_off); +} diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c index defcf4df6d91..f5ba5d4cb259 100644 --- a/kernel/bpf/core.c +++ b/kernel/bpf/core.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -387,6 +388,7 @@ bpf_get_prog_addr_region(const struct bpf_prog *prog, static void bpf_get_prog_name(const struct bpf_prog *prog, char *sym) { const char *end = sym + KSYM_NAME_LEN; + const char *func_name; BUILD_BUG_ON(sizeof("bpf_prog_") + sizeof(prog->tag) * 2 + @@ -401,6 +403,14 @@ static void bpf_get_prog_name(const struct bpf_prog *prog, char *sym) sym += snprintf(sym, KSYM_NAME_LEN, "bpf_prog_"); sym = bin2hex(sym, prog->tag, sizeof(prog->tag)); + + /* prog->aux->name will be ignored if full btf name is available */ + if (prog->aux->btf) { + func_name = btf_get_name_by_id(prog->aux->btf, prog->aux->type_id); + snprintf(sym, (size_t)(end - sym), "_%s", func_name); + return; + } + if (prog->aux->name[0]) snprintf(sym, (size_t)(end - sym), "_%s", prog->aux->name); else diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index f4ecd6ed2252..4a8b9fe150bb 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -1133,6 +1133,7 @@ static void __bpf_prog_put(struct bpf_prog *prog, bool do_idr_lock) /* bpf_prog_free_id() must be called first */ bpf_prog_free_id(prog, do_idr_lock); bpf_prog_kallsyms_del_all(prog); + btf_put(prog->aux->btf); call_rcu(&prog->aux->rcu, __bpf_prog_put_rcu); } @@ -1356,8 +1357,45 @@ bpf_prog_load_check_attach_type(enum bpf_prog_type prog_type, } } +static int prog_check_btf(const struct bpf_prog *prog, const struct btf *btf, + union bpf_attr *attr) +{ + struct bpf_func_info __user *uinfo, info; + int i, nfuncs, usize; + u32 prev_offset; + + usize = sizeof(struct bpf_func_info); + if (attr->func_info_len % usize) + return -EINVAL; + + /* func_info section should have increasing and valid insn_offset + * and type should be BTF_KIND_FUNC. + */ + nfuncs = attr->func_info_len / usize; + uinfo = u64_to_user_ptr(attr->func_info); + for (i = 0; i < nfuncs; i++) { + if (copy_from_user(&info, uinfo, usize)) + return -EFAULT; + + if (!btf_type_id_func(btf, info.type_id)) + return -EINVAL; + + if (i == 0) { + if (info.insn_offset) + return -EINVAL; + prev_offset = 0; + } else if (info.insn_offset < prev_offset) { + return -EINVAL; + } + + prev_offset = info.insn_offset; + } + + return 0; +} + /* last field in 'union bpf_attr' used by this command */ -#define BPF_PROG_LOAD_LAST_FIELD expected_attach_type +#define BPF_PROG_LOAD_LAST_FIELD func_info static int bpf_prog_load(union bpf_attr *attr) { @@ -1444,6 +1482,24 @@ static int bpf_prog_load(union bpf_attr *attr) if (err) goto free_prog; + if (attr->func_info_len) { + struct btf *btf; + + btf = btf_get_by_fd(attr->prog_btf_fd); + if (IS_ERR(btf)) { + err = PTR_ERR(btf); + goto free_prog; + } + + err = prog_check_btf(prog, btf, attr); + if (err) { + btf_put(btf); + goto free_prog; + } + + prog->aux->btf = btf; + } + /* run eBPF verifier */ err = bpf_check(&prog, attr); if (err < 0) @@ -1476,6 +1532,7 @@ static int bpf_prog_load(union bpf_attr *attr) bpf_prog_kallsyms_del_subprogs(prog); free_used_maps(prog->aux); free_prog: + btf_put(prog->aux->btf); bpf_prog_uncharge_memlock(prog); free_prog_sec: security_bpf_prog_free(prog->aux); @@ -2121,6 +2178,30 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog, } } + if (prog->aux->btf) { + info.btf_id = btf_id(prog->aux->btf); + + ulen = info.nr_jited_func_types; + info.nr_jited_func_types = prog->aux->func_cnt; + if (info.nr_jited_func_types && ulen) { + if (bpf_dump_raw_ok()) { + u32 __user *user_types; + u32 func_type, i; + + ulen = min_t(u32, info.nr_jited_func_types, + ulen); + user_types = u64_to_user_ptr(info.jited_func_types); + for (i = 0; i < ulen; i++) { + func_type = prog->aux->func[i]->aux->type_id; + if (put_user(func_type, &user_types[i])) + return -EFAULT; + } + } else { + info.jited_func_types = 0; + } + } + } + done: if (copy_to_user(uinfo, &info, info_len) || put_user(info_len, &uattr->info.info_len)) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 3f93a548a642..01ecfe431cc2 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -4589,6 +4589,46 @@ static int check_cfg(struct bpf_verifier_env *env) return ret; } +static int check_btf_func(struct bpf_prog *prog, struct bpf_verifier_env *env, + union bpf_attr *attr) +{ + struct bpf_func_info *data; + int i, nfuncs, ret = 0; + + if (!attr->func_info_len) + return 0; + + nfuncs = attr->func_info_len / sizeof(struct bpf_func_info); + if (env->subprog_cnt != nfuncs) { + verbose(env, "number of funcs in func_info doesn't match number of subprogs\n"); + return -EINVAL; + } + + data = kvmalloc(attr->func_info_len, GFP_KERNEL | __GFP_NOWARN); + if (!data) + return -ENOMEM; + + if (copy_from_user(data, u64_to_user_ptr(attr->func_info), + attr->func_info_len)) { + ret = -EFAULT; + goto cleanup; + } + + for (i = 0; i < nfuncs; i++) { + if (env->subprog_info[i].start != data[i].insn_offset) { + verbose(env, "func_info BTF section doesn't match subprog layout in BPF program\n"); + ret = -EINVAL; + goto cleanup; + } + env->subprog_info[i].type_id = data[i].type_id; + } + + prog->aux->type_id = data[0].type_id; +cleanup: + kvfree(data); + return ret; +} + /* check %cur's range satisfies %old's */ static bool range_within(struct bpf_reg_state *old, struct bpf_reg_state *cur) @@ -5873,6 +5913,8 @@ static int jit_subprogs(struct bpf_verifier_env *env) func[i]->aux->name[0] = 'F'; func[i]->aux->stack_depth = env->subprog_info[i].stack_depth; func[i]->jit_requested = 1; + func[i]->aux->btf = prog->aux->btf; + func[i]->aux->type_id = env->subprog_info[i].type_id; func[i] = bpf_int_jit_compile(func[i]); if (!func[i]->jited) { err = -ENOTSUPP; @@ -6307,6 +6349,10 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr) if (ret < 0) goto skip_full_check; + ret = check_btf_func(env->prog, env, attr); + if (ret < 0) + goto skip_full_check; + ret = do_check(env); if (env->cur_state) { free_verifier_state(env->cur_state, true); From patchwork Wed Oct 17 07:23:41 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yonghong Song X-Patchwork-Id: 985142 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=fb.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=fb.com header.i=@fb.com header.b="X1zaP9dQ"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 42ZkFM168Vz9sCW for ; Wed, 17 Oct 2018 18:24:07 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727645AbeJQPSY (ORCPT ); Wed, 17 Oct 2018 11:18:24 -0400 Received: from mx0a-00082601.pphosted.com ([67.231.145.42]:49064 "EHLO mx0a-00082601.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727040AbeJQPSY (ORCPT ); Wed, 17 Oct 2018 11:18:24 -0400 Received: from pps.filterd (m0044008.ppops.net [127.0.0.1]) by mx0a-00082601.pphosted.com (8.16.0.22/8.16.0.22) with SMTP id w9H7O1x8002757 for ; Wed, 17 Oct 2018 00:24:04 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=fb.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-type; s=facebook; bh=pqlJB+0PjTfdZhgWK3UPgxg9a5HnMdmF5CtzpCumyKo=; b=X1zaP9dQs7V7LR+MaWBketLkzOTZJ8iTPBIa6vxJvChvFdVEGOt/k+QNjx+BbdFq/skQ gJQnLlsBfHxESNwclbmX0MeG9U9Xjw30A7+ZPalPTKKo4qVbuFZz3ulv+2TqYOrpalsL 1b0I6DZiPBW/Sd3VqVoOWP8+f3QTOg9yksw= Received: from mail.thefacebook.com ([199.201.64.23]) by mx0a-00082601.pphosted.com with ESMTP id 2n5ygyg5eg-7 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT) for ; Wed, 17 Oct 2018 00:24:04 -0700 Received: from mx-out.facebook.com (2620:10d:c081:10::13) by mail.thefacebook.com (2620:10d:c081:35::126) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA) id 15.1.1531.3; Wed, 17 Oct 2018 00:23:47 -0700 Received: by devbig003.ftw2.facebook.com (Postfix, from userid 128203) id 6F6F73702251; Wed, 17 Oct 2018 00:23:44 -0700 (PDT) Smtp-Origin-Hostprefix: devbig From: Yonghong Song Smtp-Origin-Hostname: devbig003.ftw2.facebook.com To: , , , CC: Smtp-Origin-Cluster: ftw2c04 Subject: [PATCH bpf-next v2 06/13] tools/bpf: sync kernel uapi bpf.h header to tools directory Date: Wed, 17 Oct 2018 00:23:41 -0700 Message-ID: <20181017072344.2767700-2-yhs@fb.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20181017072344.2767700-1-yhs@fb.com> References: <20181017072344.2767700-1-yhs@fb.com> X-FB-Internal: Safe MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2018-10-16_14:, , signatures=0 X-Proofpoint-Spam-Reason: safe X-FB-Internal: Safe Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org The kernel uapi bpf.h is synced to tools directory. Signed-off-by: Yonghong Song --- tools/include/uapi/linux/bpf.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index f9187b41dff6..7ebbf4f06a65 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -332,6 +332,9 @@ union bpf_attr { * (context accesses, allowed helpers, etc). */ __u32 expected_attach_type; + __u32 prog_btf_fd; /* fd pointing to BTF type data */ + __u32 func_info_len; /* func_info length */ + __aligned_u64 func_info; /* func type info */ }; struct { /* anonymous struct used by BPF_OBJ_* commands */ @@ -2585,6 +2588,9 @@ struct bpf_prog_info { __u32 nr_jited_func_lens; __aligned_u64 jited_ksyms; __aligned_u64 jited_func_lens; + __u32 btf_id; + __u32 nr_jited_func_types; + __aligned_u64 jited_func_types; } __attribute__((aligned(8))); struct bpf_map_info { @@ -2896,4 +2902,9 @@ struct bpf_flow_keys { }; }; +struct bpf_func_info { + __u32 insn_offset; + __u32 type_id; +}; + #endif /* _UAPI__LINUX_BPF_H__ */ From patchwork Wed Oct 17 07:23:42 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yonghong Song X-Patchwork-Id: 985139 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=fb.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=fb.com header.i=@fb.com header.b="PdsC4Gnh"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 42ZkF35K2Nz9sCW for ; Wed, 17 Oct 2018 18:23:51 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727616AbeJQPSJ (ORCPT ); Wed, 17 Oct 2018 11:18:09 -0400 Received: from mx0a-00082601.pphosted.com ([67.231.145.42]:44558 "EHLO mx0a-00082601.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727193AbeJQPSI (ORCPT ); Wed, 17 Oct 2018 11:18:08 -0400 Received: from pps.filterd (m0044012.ppops.net [127.0.0.1]) by mx0a-00082601.pphosted.com (8.16.0.22/8.16.0.22) with SMTP id w9H7Jltp018811 for ; Wed, 17 Oct 2018 00:23:49 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=fb.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-type; s=facebook; bh=TBoJxO4VciCsSadtPJmgj4Ki+/23Jn1/PDtNjgavnIA=; b=PdsC4GnhWLjWwtjmWOU9QpJ6bR66grLvexwAtfpFzq4KzS78XteGa+4liHPlZNEkBUTQ plsln0Xxyf2mCw3bs3rS4+tDiX7FSoR1mbjbC2gzgvlouWYQ0FLoc5/65Bp/GNQ+8TJS A8sfH4Kfcu9yTRBQsUVRgRZdqP9gl+ghrNA= Received: from mail.thefacebook.com ([199.201.64.23]) by mx0a-00082601.pphosted.com with ESMTP id 2n5ubkruwh-2 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT) for ; Wed, 17 Oct 2018 00:23:49 -0700 Received: from mx-out.facebook.com (2620:10d:c081:10::13) by mail.thefacebook.com (2620:10d:c081:35::130) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA) id 15.1.1531.3; Wed, 17 Oct 2018 00:23:48 -0700 Received: by devbig003.ftw2.facebook.com (Postfix, from userid 128203) id 7747C37021ED; Wed, 17 Oct 2018 00:23:44 -0700 (PDT) Smtp-Origin-Hostprefix: devbig From: Yonghong Song Smtp-Origin-Hostname: devbig003.ftw2.facebook.com To: , , , CC: Smtp-Origin-Cluster: ftw2c04 Subject: [PATCH bpf-next v2 07/13] tools/bpf: add new fields for program load in lib/bpf Date: Wed, 17 Oct 2018 00:23:42 -0700 Message-ID: <20181017072344.2767700-3-yhs@fb.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20181017072344.2767700-1-yhs@fb.com> References: <20181017072344.2767700-1-yhs@fb.com> X-FB-Internal: Safe MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2018-10-16_14:, , signatures=0 X-Proofpoint-Spam-Reason: safe X-FB-Internal: Safe Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org The new fields are added for program load in lib/bpf so application uses api bpf_load_program_xattr() is able to load program with btf and func_info data. This functionality will be used in next patch by bpf selftest test_btf. Signed-off-by: Yonghong Song --- tools/lib/bpf/bpf.c | 3 +++ tools/lib/bpf/bpf.h | 3 +++ 2 files changed, 6 insertions(+) diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c index d70a255cb05e..d8d48ab34220 100644 --- a/tools/lib/bpf/bpf.c +++ b/tools/lib/bpf/bpf.c @@ -196,6 +196,9 @@ int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr, attr.log_level = 0; attr.kern_version = load_attr->kern_version; attr.prog_ifindex = load_attr->prog_ifindex; + attr.prog_btf_fd = load_attr->prog_btf_fd; + attr.func_info_len = load_attr->func_info_len; + attr.func_info = ptr_to_u64(load_attr->func_info); memcpy(attr.prog_name, load_attr->name, min(name_len, BPF_OBJ_NAME_LEN - 1)); diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h index 258c3c178333..d2bdaffd7712 100644 --- a/tools/lib/bpf/bpf.h +++ b/tools/lib/bpf/bpf.h @@ -74,6 +74,9 @@ struct bpf_load_program_attr { const char *license; __u32 kern_version; __u32 prog_ifindex; + __u32 prog_btf_fd; + __u32 func_info_len; + const struct bpf_func_info *func_info; }; /* Flags to direct loading requirements */ From patchwork Wed Oct 17 07:23:43 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yonghong Song X-Patchwork-Id: 985138 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=fb.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=fb.com header.i=@fb.com header.b="kBzLZlX8"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 42ZkF261lZz9s9h for ; Wed, 17 Oct 2018 18:23:50 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727585AbeJQPSI (ORCPT ); Wed, 17 Oct 2018 11:18:08 -0400 Received: from mx0a-00082601.pphosted.com ([67.231.145.42]:35358 "EHLO mx0a-00082601.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727193AbeJQPSH (ORCPT ); Wed, 17 Oct 2018 11:18:07 -0400 Received: from pps.filterd (m0044010.ppops.net [127.0.0.1]) by mx0a-00082601.pphosted.com (8.16.0.22/8.16.0.22) with SMTP id w9H7Ja1E006932 for ; Wed, 17 Oct 2018 00:23:47 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=fb.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-type; s=facebook; bh=jhw32TX21lff7SMHeuRwx1M3ZAc9jSIfI/xefL/DjEU=; b=kBzLZlX8knjUc1iNtVkiVpnRJQu7b1UOK+4qSmiwx6wPyWBtgLqVSa8Lblydl3jd0sya BHmdyLM1i+19tPOFz8/7RUV3OPjuoDy8rKjWdr9i5ZdCUbkRIzxJ4cSKzEo6GRWh2Ayw dQpmSnbd8xwcYBJA1G8jvUAqB3r+XO4SEpU= Received: from mail.thefacebook.com ([199.201.64.23]) by mx0a-00082601.pphosted.com with ESMTP id 2n60jkr0e9-2 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT) for ; Wed, 17 Oct 2018 00:23:47 -0700 Received: from mx-out.facebook.com (2620:10d:c081:10::13) by mail.thefacebook.com (2620:10d:c081:35::129) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA) id 15.1.1531.3; Wed, 17 Oct 2018 00:23:46 -0700 Received: by devbig003.ftw2.facebook.com (Postfix, from userid 128203) id 7ED32370225C; Wed, 17 Oct 2018 00:23:44 -0700 (PDT) Smtp-Origin-Hostprefix: devbig From: Yonghong Song Smtp-Origin-Hostname: devbig003.ftw2.facebook.com To: , , , CC: Smtp-Origin-Cluster: ftw2c04 Subject: [PATCH bpf-next v2 08/13] tools/bpf: extends test_btf to test load/retrieve func_type info Date: Wed, 17 Oct 2018 00:23:43 -0700 Message-ID: <20181017072344.2767700-4-yhs@fb.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20181017072344.2767700-1-yhs@fb.com> References: <20181017072344.2767700-1-yhs@fb.com> X-FB-Internal: Safe MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2018-10-16_14:, , signatures=0 X-Proofpoint-Spam-Reason: safe X-FB-Internal: Safe Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org A two function bpf program is loaded with btf and func_info. After successful prog load, the bpf_get_info syscall is called to retrieve prog info to ensure the types returned from the kernel matches the types passed to the kernel from the user space. Several negative tests are also added to test loading/retriving of func_type info. Signed-off-by: Yonghong Song --- tools/testing/selftests/bpf/test_btf.c | 278 ++++++++++++++++++++++++- 1 file changed, 275 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/bpf/test_btf.c b/tools/testing/selftests/bpf/test_btf.c index b6461c3c5e11..e03a8cea4bb7 100644 --- a/tools/testing/selftests/bpf/test_btf.c +++ b/tools/testing/selftests/bpf/test_btf.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -22,9 +23,13 @@ #include "bpf_rlimit.h" #include "bpf_util.h" +#define MAX_INSNS 512 +#define MAX_SUBPROGS 16 + static uint32_t pass_cnt; static uint32_t error_cnt; static uint32_t skip_cnt; +static bool jit_enabled; #define CHECK(condition, format...) ({ \ int __ret = !!(condition); \ @@ -60,6 +65,24 @@ static int __base_pr(const char *format, ...) return err; } +static bool is_jit_enabled(void) +{ + const char *jit_sysctl = "/proc/sys/net/core/bpf_jit_enable"; + bool enabled = false; + int sysctl_fd; + + sysctl_fd = open(jit_sysctl, 0, O_RDONLY); + if (sysctl_fd != -1) { + char tmpc; + + if (read(sysctl_fd, &tmpc, sizeof(tmpc)) == 1) + enabled = (tmpc != '0'); + close(sysctl_fd); + } + + return enabled; +} + #define BTF_INFO_ENC(kind, root, vlen) \ ((!!(root) << 31) | ((kind) << 24) | ((vlen) & BTF_MAX_VLEN)) @@ -103,6 +126,7 @@ static struct args { bool get_info_test; bool pprint_test; bool always_log; + bool func_type_test; } args; static char btf_log_buf[BTF_LOG_BUF_SIZE]; @@ -2693,16 +2717,256 @@ static int test_pprint(void) return err; } +static struct btf_func_type_test { + const char *descr; + const char *str_sec; + __u32 raw_types[MAX_NR_RAW_TYPES]; + __u32 str_sec_size; + struct bpf_insn insns[MAX_INSNS]; + __u32 prog_type; + struct bpf_func_info func_info[MAX_SUBPROGS]; + __u32 func_info_len; + bool expected_prog_load_failure; +} func_type_test[] = { + +{ + .descr = "func_type test #1", + .str_sec = "\0int\0unsigned int\0funcA\0funcB", + .raw_types = { + BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ + BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 32, 4), /* [2] */ + BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_FUNC, 0, 2), 1), /* [3] */ + 1, 2, + BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_FUNC, 0, 2), 1), /* [4] */ + 2, 1, + BTF_END_RAW, + }, + .str_sec_size = sizeof("\0int\0unsigned int\0funcA\0funcB"), + .insns = { + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 2), + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + BPF_MOV64_IMM(BPF_REG_0, 2), + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_TRACEPOINT, + .func_info = { {0, 3}, {3, 4} }, + .func_info_len = 2 * sizeof(struct bpf_func_info), +}, + +{ + .descr = "func_type test #2", + .str_sec = "\0int\0unsigned int\0funcA\0funcB", + .raw_types = { + BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ + BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 32, 4), /* [2] */ + /* incorrect func type */ + BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_FUNC_PROTO, 0, 2), 1), /* [3] */ + 1, 2, + BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_FUNC, 0, 2), 1), /* [4] */ + 2, 1, + BTF_END_RAW, + }, + .str_sec_size = sizeof("\0int\0unsigned int\0funcA\0funcB"), + .insns = { + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 2), + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + BPF_MOV64_IMM(BPF_REG_0, 2), + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_TRACEPOINT, + .func_info = { {0, 3}, {3, 4} }, + .func_info_len = 2 * sizeof(struct bpf_func_info), + .expected_prog_load_failure = true, +}, + +{ + .descr = "func_type test #3", + .str_sec = "\0int\0unsigned int\0funcA\0funcB", + .raw_types = { + BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ + BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 32, 4), /* [2] */ + BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_FUNC, 0, 2), 1), /* [3] */ + 1, 2, + BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_FUNC, 0, 2), 1), /* [4] */ + 2, 1, + BTF_END_RAW, + }, + .str_sec_size = sizeof("\0int\0unsigned int\0funcA\0funcB"), + .insns = { + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 2), + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + BPF_MOV64_IMM(BPF_REG_0, 2), + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_TRACEPOINT, + .func_info = { {0, 3}, {3, 4} }, + /* incorrect func_info_len */ + .func_info_len = sizeof(struct bpf_func_info), + .expected_prog_load_failure = true, +}, + +{ + .descr = "func_type test #4", + .str_sec = "\0int\0unsigned int\0funcA\0funcB", + .raw_types = { + BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ + BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 32, 4), /* [2] */ + BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_FUNC, 0, 2), 1), /* [3] */ + 1, 2, + BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_FUNC, 0, 2), 1), /* [4] */ + 2, 1, + BTF_END_RAW, + }, + .str_sec_size = sizeof("\0int\0unsigned int\0funcA\0funcB"), + .insns = { + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 2), + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + BPF_MOV64_IMM(BPF_REG_0, 2), + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_TRACEPOINT, + /* incorrect func_info insn_offset */ + .func_info = { {0, 3}, {2, 4} }, + .func_info_len = 2 * sizeof(struct bpf_func_info), + .expected_prog_load_failure = true, +}, + +}; + +static size_t probe_prog_length(const struct bpf_insn *fp) +{ + size_t len; + + for (len = MAX_INSNS - 1; len > 0; --len) + if (fp[len].code != 0 || fp[len].imm != 0) + break; + return len + 1; +} + +static int do_test_func_type(int test_num) +{ + const struct btf_func_type_test *test = &func_type_test[test_num]; + __u32 func_lens[4], func_types[4], info_len; + struct bpf_load_program_attr attr = {}; + unsigned int raw_btf_size; + struct bpf_prog_info info = {}; + int btf_fd, prog_fd, err = 0; + void *raw_btf; + + fprintf(stderr, "%s......", test->descr); + raw_btf = btf_raw_create(&hdr_tmpl, test->raw_types, + test->str_sec, test->str_sec_size, + &raw_btf_size); + + if (!raw_btf) + return -1; + + *btf_log_buf = '\0'; + btf_fd = bpf_load_btf(raw_btf, raw_btf_size, + btf_log_buf, BTF_LOG_BUF_SIZE, + args.always_log); + free(raw_btf); + + if (CHECK(btf_fd == -1, "invalid btf_fd errno:%d", errno)) { + fprintf(stderr, "%s\n", btf_log_buf); + err = -1; + goto done; + } + + attr.prog_type = test->prog_type; + attr.insns = test->insns; + attr.insns_cnt = probe_prog_length(attr.insns); + attr.license = "GPL"; + attr.prog_btf_fd = btf_fd; + attr.func_info_len = test->func_info_len; + attr.func_info = test->func_info; + + *btf_log_buf = '\0'; + prog_fd = bpf_load_program_xattr(&attr, btf_log_buf, + BTF_LOG_BUF_SIZE); + if (test->expected_prog_load_failure && prog_fd == -1) { + err = 0; + goto done; + } + if (CHECK(prog_fd == -1, "invalid prog_id errno:%d", errno)) { + fprintf(stderr, "%s\n", btf_log_buf); + err = -1; + goto done; + } + if (!jit_enabled) { + skip_cnt++; + fprintf(stderr, "SKIPPED, please enable sysctl bpf_jit_enable\n"); + err = 0; + goto done; + } + + info_len = sizeof(struct bpf_prog_info); + info.nr_jited_func_types = 4; + info.nr_jited_func_lens = 4; + info.jited_func_types = ptr_to_u64(&func_types[0]); + info.jited_func_lens = ptr_to_u64(&func_lens[0]); + err = bpf_obj_get_info_by_fd(prog_fd, &info, &info_len); + if (CHECK(err == -1, "invalid get info errno:%d", errno)) { + fprintf(stderr, "%s\n", btf_log_buf); + err = -1; + goto done; + } + if (CHECK(info.nr_jited_func_lens != 2, + "incorrect info.nr_jited_func_lens %d\n", + info.nr_jited_func_lens)) { + err = -1; + goto done; + } + if (CHECK(info.nr_jited_func_types != 2, + "incorrect info.nr_jited_func_types %d\n", + info.nr_jited_func_types)) { + err = -1; + goto done; + } + if (CHECK(info.btf_id == 0, "incorrect btf_id = 0")) { + err = -1; + goto done; + } + if (CHECK(func_types[0] != test->func_info[0].type_id || + func_types[1] != test->func_info[1].type_id, + "incorrect func_types (%u, %u) expected (%u %d)", + func_types[0], func_types[1], + test->func_info[0].type_id, test->func_info[1].type_id)) { + err = -1; + goto done; + } + +done: + return err; +} + +static int test_func_type(void) +{ + unsigned int i; + int err = 0; + + for (i = 0; i < ARRAY_SIZE(func_type_test); i++) + err |= count_result(do_test_func_type(i)); + + return err; +} + static void usage(const char *cmd) { - fprintf(stderr, "Usage: %s [-l] [[-r test_num (1 - %zu)] | [-g test_num (1 - %zu)] | [-f test_num (1 - %zu)] | [-p]]\n", + fprintf(stderr, "Usage: %s [-l] [[-r test_num (1 - %zu)] |" + " [-g test_num (1 - %zu)] |" + " [-f test_num (1 - %zu)] | [-p] | [-k] ]\n", cmd, ARRAY_SIZE(raw_tests), ARRAY_SIZE(get_info_tests), ARRAY_SIZE(file_tests)); } static int parse_args(int argc, char **argv) { - const char *optstr = "lpf:r:g:"; + const char *optstr = "lpkf:r:g:"; int opt; while ((opt = getopt(argc, argv, optstr)) != -1) { @@ -2725,6 +2989,9 @@ static int parse_args(int argc, char **argv) case 'p': args.pprint_test = true; break; + case 'k': + args.func_type_test = true; + break; case 'h': usage(argv[0]); exit(0); @@ -2778,6 +3045,8 @@ int main(int argc, char **argv) if (args.always_log) libbpf_set_print(__base_pr, __base_pr, __base_pr); + jit_enabled = is_jit_enabled(); + if (args.raw_test) err |= test_raw(); @@ -2790,8 +3059,11 @@ int main(int argc, char **argv) if (args.pprint_test) err |= test_pprint(); + if (args.func_type_test) + err |= test_func_type(); + if (args.raw_test || args.get_info_test || args.file_test || - args.pprint_test) + args.pprint_test || args.func_type_test) goto done; err |= test_raw(); From patchwork Wed Oct 17 07:23:44 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yonghong Song X-Patchwork-Id: 985141 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=fb.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=fb.com header.i=@fb.com header.b="OlS8p/tn"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 42ZkFJ4Tq3z9sCW for ; Wed, 17 Oct 2018 18:24:04 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727633AbeJQPSW (ORCPT ); Wed, 17 Oct 2018 11:18:22 -0400 Received: from mx0a-00082601.pphosted.com ([67.231.145.42]:49032 "EHLO mx0a-00082601.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727040AbeJQPSW (ORCPT ); Wed, 17 Oct 2018 11:18:22 -0400 Received: from pps.filterd (m0044008.ppops.net [127.0.0.1]) by mx0a-00082601.pphosted.com (8.16.0.22/8.16.0.22) with SMTP id w9H7O06Z002748 for ; Wed, 17 Oct 2018 00:24:00 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=fb.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-type; s=facebook; bh=gNTAfacP65vf6NSd7MI7JbmJfN4ZkvAhueZvkN6ECdM=; b=OlS8p/tnaTEKA9rC3EaRZX0I3JjJWmioOqsFJcITHEdtxmQD2jjia1nYZCzq1GcPjiIv ZZRAGEjI6Ch+4bDuvd6x391xZYM/ChBM3JoOrL/Ti5vnpGEZIbpVGFiZvRIaYL4duxAx geBQ42X7w04ilND2oU4OKXPi2Ws4jraFzn8= Received: from maileast.thefacebook.com ([199.201.65.23]) by mx0a-00082601.pphosted.com with ESMTP id 2n5ygyg5ed-2 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT) for ; Wed, 17 Oct 2018 00:24:00 -0700 Received: from mx-out.facebook.com (2620:10d:c0a1:3::13) by mail.thefacebook.com (2620:10d:c021:18::173) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA) id 15.1.1531.3; Wed, 17 Oct 2018 00:23:55 -0700 Received: by devbig003.ftw2.facebook.com (Postfix, from userid 128203) id 854A73702247; Wed, 17 Oct 2018 00:23:44 -0700 (PDT) Smtp-Origin-Hostprefix: devbig From: Yonghong Song Smtp-Origin-Hostname: devbig003.ftw2.facebook.com To: , , , CC: Smtp-Origin-Cluster: ftw2c04 Subject: [PATCH bpf-next v2 09/13] tools/bpf: add support to read .BTF.ext sections Date: Wed, 17 Oct 2018 00:23:44 -0700 Message-ID: <20181017072344.2767700-5-yhs@fb.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20181017072344.2767700-1-yhs@fb.com> References: <20181017072344.2767700-1-yhs@fb.com> X-FB-Internal: Safe MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2018-10-16_14:, , signatures=0 X-Proofpoint-Spam-Reason: safe X-FB-Internal: Safe Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org The .BTF section is already available to encode types. These types can be used for map pretty print. The whole .BTF will be passed to the kernel as well for which kernel can verify and return to the user space for pretty print etc. The llvm patch at https://reviews.llvm.org/D53261 will generate .BTF section and one more section .BTF.ext. The .BTF.ext section encodes function type information and line information. For line information, the actual source code is encoded in the section, which makes compiler itself as an ideal place for section generation. The .BTF section does not depend on any other section, and .BTF.ext has dependency on .BTF for strings and types. The .BTF section can be directly loaded into the kernel, and the .BTF.ext section cannot. The loader may need to do some relocation and merging, similar to merging multiple code sections, before loading into the kernel. In this patch, only func type info is processed. The functionality is implemented in libbpf. Signed-off-by: Yonghong Song --- tools/lib/bpf/btf.c | 232 +++++++++++++++++++++++++++++++++++++++++ tools/lib/bpf/btf.h | 31 ++++++ tools/lib/bpf/libbpf.c | 53 +++++++++- 3 files changed, 312 insertions(+), 4 deletions(-) diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c index 33095fc1860b..4748e0bacd2b 100644 --- a/tools/lib/bpf/btf.c +++ b/tools/lib/bpf/btf.c @@ -37,6 +37,11 @@ struct btf { int fd; }; +struct btf_ext { + void *func_info; + __u32 func_info_len; +}; + static int btf_add_type(struct btf *btf, struct btf_type *t) { if (btf->types_size - btf->nr_types < 2) { @@ -397,3 +402,230 @@ const char *btf__name_by_offset(const struct btf *btf, __u32 offset) else return NULL; } + +static int btf_ext_validate_func_info(const struct btf_sec_func_info *sinfo, + __u32 size, btf_print_fn_t err_log) +{ + int sec_hdrlen = sizeof(struct btf_sec_func_info); + __u32 record_size = sizeof(struct bpf_func_info); + __u32 size_left = size, num_records; + __u64 total_record_size; + + while (size_left) { + if (size_left < sec_hdrlen) { + elog("BTF.ext func_info header not found"); + return -EINVAL; + } + + num_records = sinfo->num_func_info; + if (num_records == 0) { + elog("incorrect BTF.ext num_func_info"); + return -EINVAL; + } + + total_record_size = sec_hdrlen + + (__u64)num_records * record_size; + if (size_left < total_record_size) { + elog("incorrect BTF.ext num_func_info"); + return -EINVAL; + } + + size_left -= total_record_size; + sinfo = (void *)sinfo + total_record_size; + } + + return 0; +} +static int btf_ext_parse_hdr(__u8 *data, __u32 data_size, + btf_print_fn_t err_log) +{ + const struct btf_ext_header *hdr = (struct btf_ext_header *)data; + const struct btf_sec_func_info *sinfo; + __u32 meta_left, last_func_info_pos; + + if (data_size < sizeof(*hdr)) { + elog("BTF.ext header not found"); + return -EINVAL; + } + + if (hdr->magic != BTF_MAGIC) { + elog("Invalid BTF.ext magic:%x\n", hdr->magic); + return -EINVAL; + } + + if (hdr->version != BTF_VERSION) { + elog("Unsupported BTF.ext version:%u\n", hdr->version); + return -ENOTSUP; + } + + if (hdr->flags) { + elog("Unsupported BTF.ext flags:%x\n", hdr->flags); + return -ENOTSUP; + } + + meta_left = data_size - sizeof(*hdr); + if (!meta_left) { + elog("BTF.ext has no data\n"); + return -EINVAL; + } + + if (meta_left < hdr->func_info_off) { + elog("Invalid BTF.ext func_info section offset:%u\n", + hdr->func_info_off); + return -EINVAL; + } + + if (hdr->func_info_off & 0x02) { + elog("BTF.ext func_info section is not aligned to 4 bytes\n"); + return -EINVAL; + } + + last_func_info_pos = sizeof(*hdr) + hdr->func_info_off + + hdr->func_info_len; + if (last_func_info_pos > data_size) { + elog("Invalid BTF.ext func_info section size:%u\n", + hdr->func_info_len); + return -EINVAL; + } + + sinfo = (const struct btf_sec_func_info *)(data + sizeof(*hdr) + + hdr->func_info_off); + return btf_ext_validate_func_info(sinfo, hdr->func_info_len, + err_log); +} + +void btf_ext__free(struct btf_ext *btf_ext) +{ + if (!btf_ext) + return; + + free(btf_ext->func_info); + free(btf_ext); +} + +struct btf_ext *btf_ext__new(__u8 *data, __u32 size, btf_print_fn_t err_log) +{ + int hdrlen = sizeof(struct btf_ext_header); + const struct btf_ext_header *hdr; + struct btf_ext *btf_ext; + void *fdata; + int err; + + err = btf_ext_parse_hdr(data, size, err_log); + if (err) + return ERR_PTR(err); + + btf_ext = calloc(1, sizeof(struct btf_ext)); + if (!btf_ext) + return ERR_PTR(-ENOMEM); + + hdr = (const struct btf_ext_header *)data; + fdata = malloc(hdr->func_info_len); + if (!fdata) + return ERR_PTR(-ENOMEM); + + memcpy(fdata, data + hdrlen + hdr->func_info_off, hdr->func_info_len); + btf_ext->func_info = fdata; + btf_ext->func_info_len = hdr->func_info_len; + + return btf_ext; +} + +int btf_ext_reloc_init(struct btf *btf, struct btf_ext *btf_ext, + const char *sec_name, __u32 *btf_fd, + void **func_info, __u32 *func_info_len) +{ + int sec_hdrlen = sizeof(struct btf_sec_func_info); + int record_len = sizeof(struct bpf_func_info); + struct btf_sec_func_info *sinfo; + int i, remain_len, records_len; + const char *info_sec_name; + void *data; + + if (!btf || !btf_ext) { + *btf_fd = 0; + *func_info = NULL; + *func_info_len = 0; + return 0; + } + + sinfo = btf_ext->func_info; + remain_len = btf_ext->func_info_len; + *btf_fd = btf__fd(btf); + + while (remain_len > 0) { + records_len = sinfo->num_func_info * record_len; + info_sec_name = btf__name_by_offset(btf, sinfo->sec_name_off); + if (strcmp(info_sec_name, sec_name)) { + remain_len -= sec_hdrlen + records_len; + sinfo = (void *)sinfo + sec_hdrlen + records_len; + continue; + } + + data = malloc(records_len); + if (!data) + return -ENOMEM; + + memcpy(data, sinfo->data, records_len); + + /* adjust the insn_offset, the data in .BTF.ext is + * the actual byte offset, and the kernel expects + * the offset in term of bpf_insn. + */ + for (i = 0; i < sinfo->num_func_info; i++) + ((struct bpf_func_info *)data)[i].insn_offset + /= sizeof(struct bpf_insn); + + *func_info = data; + *func_info_len = records_len; + break; + } + + return 0; +} + +int btf_ext_reloc(struct btf *btf, struct btf_ext *btf_ext, + const char *sec_name, __u32 insns_cnt, + void **func_info, __u32 *func_info_len) +{ + int sec_hdrlen = sizeof(struct btf_sec_func_info); + int record_len = sizeof(struct bpf_func_info); + __u32 i, remain_len, records_len; + struct btf_sec_func_info *sinfo; + struct bpf_func_info *record; + const char *info_sec_name; + __u32 existing_flen; + void *data; + + if (!*func_info) + return 0; + + sinfo = btf_ext->func_info; + remain_len = btf_ext->func_info_len; + while (remain_len > 0) { + records_len = sinfo->num_func_info * record_len; + info_sec_name = btf__name_by_offset(btf, sinfo->sec_name_off); + if (strcmp(info_sec_name, sec_name)) { + remain_len -= sec_hdrlen + records_len; + sinfo = (void *)sinfo + sec_hdrlen + records_len; + continue; + } + + existing_flen = *func_info_len; + data = realloc(*func_info, existing_flen + records_len); + if (!data) + return -ENOMEM; + + memcpy(data + existing_flen, sinfo->data, records_len); + record = data + existing_flen; + for (i = 0; i < sinfo->num_func_info; i++) + record[i].insn_offset = + record[i].insn_offset/sizeof(struct bpf_insn) + + insns_cnt; + *func_info = data; + *func_info_len = existing_flen + records_len; + break; + } + + return 0; +} diff --git a/tools/lib/bpf/btf.h b/tools/lib/bpf/btf.h index b77e7080f7e7..8758098a7991 100644 --- a/tools/lib/bpf/btf.h +++ b/tools/lib/bpf/btf.h @@ -11,10 +11,32 @@ #endif #define BTF_ELF_SEC ".BTF" +#define BTF_EXT_ELF_SEC ".BTF.ext" struct btf; +struct btf_ext; struct btf_type; +struct btf_ext_header { + __u16 magic; + __u8 version; + __u8 flags; + __u32 hdr_len; + + /* All offsets are in bytes relative to the end of this header */ + __u32 func_info_off; + __u32 func_info_len; + __u32 line_info_off; + __u32 line_info_len; +}; + +struct btf_sec_func_info { + __u32 sec_name_off; + __u32 num_func_info; + /* followed by num_func_info number of bpf_func_info records */ + __u8 data[0]; +}; + typedef int (*btf_print_fn_t)(const char *, ...) __attribute__((format(printf, 1, 2))); @@ -29,4 +51,13 @@ LIBBPF_API int btf__resolve_type(const struct btf *btf, __u32 type_id); LIBBPF_API int btf__fd(const struct btf *btf); LIBBPF_API const char *btf__name_by_offset(const struct btf *btf, __u32 offset); +struct btf_ext *btf_ext__new(__u8 *data, __u32 size, btf_print_fn_t err_log); +void btf_ext__free(struct btf_ext *btf_ext); +int btf_ext_reloc_init(struct btf *btf, struct btf_ext *btf_ext, + const char *sec_name, __u32 *btf_fd, + void **func_info, __u32 *func_info_len); +int btf_ext_reloc(struct btf *btf, struct btf_ext *btf_ext, + const char *sec_name, __u32 insns_cnt, void **func_info, + __u32 *func_info_len); + #endif /* __LIBBPF_BTF_H */ diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index bd71efcc53be..2ea3b1467d47 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -151,6 +151,9 @@ struct bpf_program { bpf_program_clear_priv_t clear_priv; enum bpf_attach_type expected_attach_type; + __u32 btf_fd; + void *func_info; + __u32 func_info_len; }; struct bpf_map { @@ -207,6 +210,7 @@ struct bpf_object { struct list_head list; struct btf *btf; + struct btf_ext *btf_ext; void *priv; bpf_object_clear_priv_t clear_priv; @@ -783,6 +787,15 @@ static int bpf_object__elf_collect(struct bpf_object *obj, int flags) BTF_ELF_SEC, PTR_ERR(obj->btf)); obj->btf = NULL; } + } else if (strcmp(name, BTF_EXT_ELF_SEC) == 0) { + obj->btf_ext = btf_ext__new(data->d_buf, data->d_size, + __pr_debug); + if (IS_ERR(obj->btf_ext)) { + pr_warning("Error loading ELF section %s: %ld. Ignored and continue.\n", + BTF_EXT_ELF_SEC, + PTR_ERR(obj->btf_ext)); + obj->btf_ext = NULL; + } } else if (sh.sh_type == SHT_SYMTAB) { if (obj->efile.symbols) { pr_warning("bpf: multiple SYMTAB in %s\n", @@ -1166,6 +1179,7 @@ bpf_program__reloc_text(struct bpf_program *prog, struct bpf_object *obj, struct bpf_insn *insn, *new_insn; struct bpf_program *text; size_t new_cnt; + int err; if (relo->type != RELO_CALL) return -LIBBPF_ERRNO__RELOC; @@ -1188,6 +1202,16 @@ bpf_program__reloc_text(struct bpf_program *prog, struct bpf_object *obj, pr_warning("oom in prog realloc\n"); return -ENOMEM; } + + err = btf_ext_reloc(obj->btf, obj->btf_ext, text->section_name, + prog->insns_cnt, &prog->func_info, + &prog->func_info_len); + if (err) { + pr_warning("error in btf_ext_reloc for sec %s\n", + text->section_name); + return err; + } + memcpy(new_insn + prog->insns_cnt, text->insns, text->insns_cnt * sizeof(*insn)); prog->insns = new_insn; @@ -1207,7 +1231,19 @@ bpf_program__relocate(struct bpf_program *prog, struct bpf_object *obj) { int i, err; - if (!prog || !prog->reloc_desc) + if (!prog) + return 0; + + err = btf_ext_reloc_init(obj->btf, obj->btf_ext, prog->section_name, + &prog->btf_fd, &prog->func_info, + &prog->func_info_len); + if (err) { + pr_warning("err in btf_ext_reloc_init for sec %s\n", + prog->section_name); + return err; + } + + if (!prog->reloc_desc) return 0; for (i = 0; i < prog->nr_reloc; i++) { @@ -1297,7 +1333,8 @@ static int bpf_object__collect_reloc(struct bpf_object *obj) static int load_program(enum bpf_prog_type type, enum bpf_attach_type expected_attach_type, const char *name, struct bpf_insn *insns, int insns_cnt, - char *license, __u32 kern_version, int *pfd, int prog_ifindex) + char *license, __u32 kern_version, int *pfd, int prog_ifindex, + u32 btf_fd, struct bpf_func_info *func_info, u32 func_info_len) { struct bpf_load_program_attr load_attr; char *cp, errmsg[STRERR_BUFSIZE]; @@ -1313,6 +1350,9 @@ load_program(enum bpf_prog_type type, enum bpf_attach_type expected_attach_type, load_attr.license = license; load_attr.kern_version = kern_version; load_attr.prog_ifindex = prog_ifindex; + load_attr.prog_btf_fd = btf_fd; + load_attr.func_info = func_info; + load_attr.func_info_len = func_info_len; if (!load_attr.insns || !load_attr.insns_cnt) return -EINVAL; @@ -1396,7 +1436,9 @@ bpf_program__load(struct bpf_program *prog, err = load_program(prog->type, prog->expected_attach_type, prog->name, prog->insns, prog->insns_cnt, license, kern_version, &fd, - prog->prog_ifindex); + prog->prog_ifindex, + prog->btf_fd, prog->func_info, + prog->func_info_len); if (!err) prog->instances.fds[0] = fd; goto out; @@ -1428,7 +1470,9 @@ bpf_program__load(struct bpf_program *prog, prog->name, result.new_insn_ptr, result.new_insn_cnt, license, kern_version, &fd, - prog->prog_ifindex); + prog->prog_ifindex, + prog->btf_fd, prog->func_info, + prog->func_info_len); if (err) { pr_warning("Loading the %dth instance of program '%s' failed\n", @@ -1844,6 +1888,7 @@ void bpf_object__close(struct bpf_object *obj) bpf_object__elf_finish(obj); bpf_object__unload(obj); btf__free(obj->btf); + btf_ext__free(obj->btf_ext); for (i = 0; i < obj->nr_maps; i++) { zfree(&obj->maps[i].name); From patchwork Wed Oct 17 07:23:57 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yonghong Song X-Patchwork-Id: 985147 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=fb.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=fb.com header.i=@fb.com header.b="lGdnyjkV"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 42ZkG80Lgdz9sD9 for ; Wed, 17 Oct 2018 18:24:47 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727668AbeJQPTF (ORCPT ); Wed, 17 Oct 2018 11:19:05 -0400 Received: from mx0a-00082601.pphosted.com ([67.231.145.42]:59866 "EHLO mx0a-00082601.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727451AbeJQPTE (ORCPT ); Wed, 17 Oct 2018 11:19:04 -0400 Received: from pps.filterd (m0109333.ppops.net [127.0.0.1]) by mx0a-00082601.pphosted.com (8.16.0.22/8.16.0.22) with SMTP id w9H7Odbh005811 for ; Wed, 17 Oct 2018 00:24:44 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=fb.com; h=from : to : cc : subject : date : message-id : mime-version : content-type; s=facebook; bh=ulDTMnnNqhgKaZxhYq75mOacWmY/df6/ugwJNCxeh9E=; b=lGdnyjkVARadLUDqZkVt3zk4wElzeEg8P5N/bBsjNbp5ydFF/HIWUx3i/P0fKGQHJo+a cvdd68mUExe7E3CFP//Xel8KiS1G7oxc7bxlwYJ1M+aFJquFHRxAxfPO08P0rnpBIgSC y2JMksXCvUkpuFfyIUa+fpYHxpgLN+DOVHI= Received: from mail.thefacebook.com ([199.201.64.23]) by mx0a-00082601.pphosted.com with ESMTP id 2n60fgr0x9-6 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT) for ; Wed, 17 Oct 2018 00:24:44 -0700 Received: from mx-out.facebook.com (2620:10d:c081:10::13) by mail.thefacebook.com (2620:10d:c081:35::126) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA) id 15.1.1531.3; Wed, 17 Oct 2018 00:24:17 -0700 Received: by devbig003.ftw2.facebook.com (Postfix, from userid 128203) id 00B193702247; Wed, 17 Oct 2018 00:24:00 -0700 (PDT) Smtp-Origin-Hostprefix: devbig From: Yonghong Song Smtp-Origin-Hostname: devbig003.ftw2.facebook.com To: , , , CC: Smtp-Origin-Cluster: ftw2c04 Subject: [PATCH bpf-next v2 10/13] tools/bpf: do not use pahole if clang/llvm can generate BTF sections Date: Wed, 17 Oct 2018 00:23:57 -0700 Message-ID: <20181017072400.2768484-1-yhs@fb.com> X-Mailer: git-send-email 2.17.1 X-FB-Internal: Safe MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2018-10-16_14:, , signatures=0 X-Proofpoint-Spam-Reason: safe X-FB-Internal: Safe Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Add additional checks in tools/testing/selftests/bpf and samples/bpf such that if clang/llvm compiler can generate BTF sections, do not use pahole. Signed-off-by: Yonghong Song --- samples/bpf/Makefile | 8 ++++++++ tools/testing/selftests/bpf/Makefile | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile index be0a961450bc..870fe7ee2b69 100644 --- a/samples/bpf/Makefile +++ b/samples/bpf/Makefile @@ -208,12 +208,20 @@ endif BTF_LLC_PROBE := $(shell $(LLC) -march=bpf -mattr=help 2>&1 | grep dwarfris) BTF_PAHOLE_PROBE := $(shell $(BTF_PAHOLE) --help 2>&1 | grep BTF) BTF_OBJCOPY_PROBE := $(shell $(LLVM_OBJCOPY) --help 2>&1 | grep -i 'usage.*llvm') +BTF_LLVM_PROBE := $(shell echo "int main() { return 0; }" | \ + clang -target bpf -O2 -g -c -x c - -o ./llvm_btf_verify.o; \ + readelf -S ./llvm_btf_verify.o | grep BTF; \ + /bin/rm -f ./llvm_btf_verify.o) +ifneq ($(BTF_LLVM_PROBE),) + EXTRA_CFLAGS += -g +else ifneq ($(and $(BTF_LLC_PROBE),$(BTF_PAHOLE_PROBE),$(BTF_OBJCOPY_PROBE)),) EXTRA_CFLAGS += -g LLC_FLAGS += -mattr=dwarfris DWARF2BTF = y endif +endif # Trick to allow make to be run from this directory all: diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index d99dd6fc3fbe..8d5612724db8 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -121,7 +121,14 @@ $(OUTPUT)/test_xdp_noinline.o: CLANG_FLAGS += -fno-inline BTF_LLC_PROBE := $(shell $(LLC) -march=bpf -mattr=help 2>&1 | grep dwarfris) BTF_PAHOLE_PROBE := $(shell $(BTF_PAHOLE) --help 2>&1 | grep BTF) BTF_OBJCOPY_PROBE := $(shell $(LLVM_OBJCOPY) --help 2>&1 | grep -i 'usage.*llvm') +BTF_LLVM_PROBE := $(shell echo "int main() { return 0; }" | \ + clang -target bpf -O2 -g -c -x c - -o ./llvm_btf_verify.o; \ + readelf -S ./llvm_btf_verify.o | grep BTF; \ + /bin/rm -f ./llvm_btf_verify.o) +ifneq ($(BTF_LLVM_PROBE),) + CLANG_FLAGS += -g +else ifneq ($(BTF_LLC_PROBE),) ifneq ($(BTF_PAHOLE_PROBE),) ifneq ($(BTF_OBJCOPY_PROBE),) @@ -131,6 +138,7 @@ ifneq ($(BTF_OBJCOPY_PROBE),) endif endif endif +endif $(OUTPUT)/%.o: %.c $(CLANG) $(CLANG_FLAGS) \ From patchwork Wed Oct 17 07:23:58 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yonghong Song X-Patchwork-Id: 985143 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=fb.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=fb.com header.i=@fb.com header.b="GTJR5nLl"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 42ZkFs0Hs0z9sCW for ; Wed, 17 Oct 2018 18:24:33 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727365AbeJQPSu (ORCPT ); Wed, 17 Oct 2018 11:18:50 -0400 Received: from mx0b-00082601.pphosted.com ([67.231.153.30]:52852 "EHLO mx0a-00082601.pphosted.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1727023AbeJQPSu (ORCPT ); Wed, 17 Oct 2018 11:18:50 -0400 Received: from pps.filterd (m0089730.ppops.net [127.0.0.1]) by m0089730.ppops.net (8.16.0.22/8.16.0.22) with SMTP id w9H7NUEW028627 for ; Wed, 17 Oct 2018 00:24:29 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=fb.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-type; s=facebook; bh=s0VPtkZhZXotF7cbezZZHBu8ivhmb6v+12vaoNs8M6Q=; b=GTJR5nLlNJ+yWuont4akrqMoi3iTzjJwFIij+3DKrfNWqu+ML7C2FrfzKundb0TAkkVz 8+rG1K4EhGEwD7+y+pnjrnaSlUoMV0XRtD4gOnIMVOFz037WzGja5BAEiyce2iobpPGY tz88lRBjwIZY2Nap/B1wRjzTRBaHMpgfjYM= Received: from mail.thefacebook.com ([199.201.64.23]) by m0089730.ppops.net with ESMTP id 2n60gw80s6-9 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT) for ; Wed, 17 Oct 2018 00:24:29 -0700 Received: from mx-out.facebook.com (2620:10d:c081:10::13) by mail.thefacebook.com (2620:10d:c081:35::127) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA) id 15.1.1531.3; Wed, 17 Oct 2018 00:24:04 -0700 Received: by devbig003.ftw2.facebook.com (Postfix, from userid 128203) id 04C943702251; Wed, 17 Oct 2018 00:24:01 -0700 (PDT) Smtp-Origin-Hostprefix: devbig From: Yonghong Song Smtp-Origin-Hostname: devbig003.ftw2.facebook.com To: , , , CC: Smtp-Origin-Cluster: ftw2c04 Subject: [PATCH bpf-next v2 11/13] tools/bpf: refactor to implement btf_get_from_id() in lib/bpf Date: Wed, 17 Oct 2018 00:23:58 -0700 Message-ID: <20181017072400.2768484-2-yhs@fb.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20181017072400.2768484-1-yhs@fb.com> References: <20181017072400.2768484-1-yhs@fb.com> X-FB-Internal: Safe MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2018-10-16_14:, , signatures=0 X-Proofpoint-Spam-Reason: safe X-FB-Internal: Safe Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org The function get_btf() is implemented in tools/bpf/bpftool/map.c to get a btf structure given a map_info. This patch refactored this function to be function btf_get_from_id() in tools/lib/bpf so that it can be used later. Signed-off-by: Yonghong Song --- tools/bpf/bpftool/map.c | 68 ++-------------------------------------- tools/lib/bpf/btf.c | 69 +++++++++++++++++++++++++++++++++++++++++ tools/lib/bpf/btf.h | 18 ++++++----- 3 files changed, 81 insertions(+), 74 deletions(-) diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c index 7bf38f0e152e..1b8a75fa0471 100644 --- a/tools/bpf/bpftool/map.c +++ b/tools/bpf/bpftool/map.c @@ -215,70 +215,6 @@ static int do_dump_btf(const struct btf_dumper *d, return ret; } -static int get_btf(struct bpf_map_info *map_info, struct btf **btf) -{ - struct bpf_btf_info btf_info = { 0 }; - __u32 len = sizeof(btf_info); - __u32 last_size; - int btf_fd; - void *ptr; - int err; - - err = 0; - *btf = NULL; - btf_fd = bpf_btf_get_fd_by_id(map_info->btf_id); - if (btf_fd < 0) - return 0; - - /* we won't know btf_size until we call bpf_obj_get_info_by_fd(). so - * let's start with a sane default - 4KiB here - and resize it only if - * bpf_obj_get_info_by_fd() needs a bigger buffer. - */ - btf_info.btf_size = 4096; - last_size = btf_info.btf_size; - ptr = malloc(last_size); - if (!ptr) { - err = -ENOMEM; - goto exit_free; - } - - bzero(ptr, last_size); - btf_info.btf = ptr_to_u64(ptr); - err = bpf_obj_get_info_by_fd(btf_fd, &btf_info, &len); - - if (!err && btf_info.btf_size > last_size) { - void *temp_ptr; - - last_size = btf_info.btf_size; - temp_ptr = realloc(ptr, last_size); - if (!temp_ptr) { - err = -ENOMEM; - goto exit_free; - } - ptr = temp_ptr; - bzero(ptr, last_size); - btf_info.btf = ptr_to_u64(ptr); - err = bpf_obj_get_info_by_fd(btf_fd, &btf_info, &len); - } - - if (err || btf_info.btf_size > last_size) { - err = errno; - goto exit_free; - } - - *btf = btf__new((__u8 *)btf_info.btf, btf_info.btf_size, NULL); - if (IS_ERR(*btf)) { - err = PTR_ERR(*btf); - *btf = NULL; - } - -exit_free: - close(btf_fd); - free(ptr); - - return err; -} - static json_writer_t *get_btf_writer(void) { json_writer_t *jw = jsonw_new(stdout); @@ -765,7 +701,7 @@ static int do_dump(int argc, char **argv) prev_key = NULL; - err = get_btf(&info, &btf); + err = btf_get_from_id(info.btf_id, &btf); if (err) { p_err("failed to get btf"); goto exit_free; @@ -909,7 +845,7 @@ static int do_lookup(int argc, char **argv) } /* here means bpf_map_lookup_elem() succeeded */ - err = get_btf(&info, &btf); + err = btf_get_from_id(info.btf_id, &btf); if (err) { p_err("failed to get btf"); goto exit_free; diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c index 4748e0bacd2b..ab654628e966 100644 --- a/tools/lib/bpf/btf.c +++ b/tools/lib/bpf/btf.c @@ -42,6 +42,11 @@ struct btf_ext { __u32 func_info_len; }; +static inline __u64 ptr_to_u64(const void *ptr) +{ + return (__u64) (unsigned long) ptr; +} + static int btf_add_type(struct btf *btf, struct btf_type *t) { if (btf->types_size - btf->nr_types < 2) { @@ -403,6 +408,70 @@ const char *btf__name_by_offset(const struct btf *btf, __u32 offset) return NULL; } +int btf_get_from_id(__u32 id, struct btf **btf) +{ + struct bpf_btf_info btf_info = { 0 }; + __u32 len = sizeof(btf_info); + __u32 last_size; + int btf_fd; + void *ptr; + int err; + + err = 0; + *btf = NULL; + btf_fd = bpf_btf_get_fd_by_id(id); + if (btf_fd < 0) + return 0; + + /* we won't know btf_size until we call bpf_obj_get_info_by_fd(). so + * let's start with a sane default - 4KiB here - and resize it only if + * bpf_obj_get_info_by_fd() needs a bigger buffer. + */ + btf_info.btf_size = 4096; + last_size = btf_info.btf_size; + ptr = malloc(last_size); + if (!ptr) { + err = -ENOMEM; + goto exit_free; + } + + bzero(ptr, last_size); + btf_info.btf = ptr_to_u64(ptr); + err = bpf_obj_get_info_by_fd(btf_fd, &btf_info, &len); + + if (!err && btf_info.btf_size > last_size) { + void *temp_ptr; + + last_size = btf_info.btf_size; + temp_ptr = realloc(ptr, last_size); + if (!temp_ptr) { + err = -ENOMEM; + goto exit_free; + } + ptr = temp_ptr; + bzero(ptr, last_size); + btf_info.btf = ptr_to_u64(ptr); + err = bpf_obj_get_info_by_fd(btf_fd, &btf_info, &len); + } + + if (err || btf_info.btf_size > last_size) { + err = errno; + goto exit_free; + } + + *btf = btf__new((__u8 *)btf_info.btf, btf_info.btf_size, NULL); + if (IS_ERR(*btf)) { + err = PTR_ERR(*btf); + *btf = NULL; + } + +exit_free: + close(btf_fd); + free(ptr); + + return err; +} + static int btf_ext_validate_func_info(const struct btf_sec_func_info *sinfo, __u32 size, btf_print_fn_t err_log) { diff --git a/tools/lib/bpf/btf.h b/tools/lib/bpf/btf.h index 8758098a7991..975c8d2f43cb 100644 --- a/tools/lib/bpf/btf.h +++ b/tools/lib/bpf/btf.h @@ -50,14 +50,16 @@ LIBBPF_API __s64 btf__resolve_size(const struct btf *btf, __u32 type_id); LIBBPF_API int btf__resolve_type(const struct btf *btf, __u32 type_id); LIBBPF_API int btf__fd(const struct btf *btf); LIBBPF_API const char *btf__name_by_offset(const struct btf *btf, __u32 offset); +LIBBPF_API int btf_get_from_id(__u32 id, struct btf **btf); -struct btf_ext *btf_ext__new(__u8 *data, __u32 size, btf_print_fn_t err_log); -void btf_ext__free(struct btf_ext *btf_ext); -int btf_ext_reloc_init(struct btf *btf, struct btf_ext *btf_ext, - const char *sec_name, __u32 *btf_fd, - void **func_info, __u32 *func_info_len); -int btf_ext_reloc(struct btf *btf, struct btf_ext *btf_ext, - const char *sec_name, __u32 insns_cnt, void **func_info, - __u32 *func_info_len); +LIBBPF_API struct btf_ext *btf_ext__new(__u8 *data, __u32 size, + btf_print_fn_t err_log); +LIBBPF_API void btf_ext__free(struct btf_ext *btf_ext); +LIBBPF_API int btf_ext_reloc_init(struct btf *btf, struct btf_ext *btf_ext, + const char *sec_name, __u32 *btf_fd, + void **func_info, __u32 *func_info_len); +LIBBPF_API int btf_ext_reloc(struct btf *btf, struct btf_ext *btf_ext, + const char *sec_name, __u32 insns_cnt, + void **func_info, __u32 *func_info_len); #endif /* __LIBBPF_BTF_H */ From patchwork Wed Oct 17 07:23:59 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yonghong Song X-Patchwork-Id: 985145 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=fb.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=fb.com header.i=@fb.com header.b="CmTBxzcG"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 42ZkG26sXfz9s9h for ; Wed, 17 Oct 2018 18:24:42 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727657AbeJQPTA (ORCPT ); Wed, 17 Oct 2018 11:19:00 -0400 Received: from mx0a-00082601.pphosted.com ([67.231.145.42]:49688 "EHLO mx0a-00082601.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727154AbeJQPTA (ORCPT ); Wed, 17 Oct 2018 11:19:00 -0400 Received: from pps.filterd (m0148461.ppops.net [127.0.0.1]) by mx0a-00082601.pphosted.com (8.16.0.22/8.16.0.22) with SMTP id w9H7MNVM032027 for ; Wed, 17 Oct 2018 00:24:40 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=fb.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-type; s=facebook; bh=coy6eXGo/MAIXGmOrcTX1RAKCQpWna+hAL9u3JgaplA=; b=CmTBxzcGS6T+YbrvFgEctui/58HVySopmgIgeHxVbysB9kLaZJXcgtw9g8kp+JnaWdK/ DpGxyLWSAF7zdFvO0owtRY30aTRcwHz90gpc9YduY28GPQ8EEzehzl9gPf/qUVC5dGlN k3uNZ1gcO5EPQ5b5x8yAATs4d7H5B0ZzBNE= Received: from mail.thefacebook.com ([199.201.64.23]) by mx0a-00082601.pphosted.com with ESMTP id 2n5xk90apv-9 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT) for ; Wed, 17 Oct 2018 00:24:40 -0700 Received: from mx-out.facebook.com (2620:10d:c081:10::13) by mail.thefacebook.com (2620:10d:c081:35::129) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA) id 15.1.1531.3; Wed, 17 Oct 2018 00:24:05 -0700 Received: by devbig003.ftw2.facebook.com (Postfix, from userid 128203) id 0E4B937021ED; Wed, 17 Oct 2018 00:24:01 -0700 (PDT) Smtp-Origin-Hostprefix: devbig From: Yonghong Song Smtp-Origin-Hostname: devbig003.ftw2.facebook.com To: , , , CC: Smtp-Origin-Cluster: ftw2c04 Subject: [PATCH bpf-next v2 12/13] tools/bpf: enhance test_btf file testing to test func info Date: Wed, 17 Oct 2018 00:23:59 -0700 Message-ID: <20181017072400.2768484-3-yhs@fb.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20181017072400.2768484-1-yhs@fb.com> References: <20181017072400.2768484-1-yhs@fb.com> X-FB-Internal: Safe MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2018-10-16_14:, , signatures=0 X-Proofpoint-Spam-Reason: safe X-FB-Internal: Safe Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Change the bpf programs test_btf_haskv.c and test_btf_nokv.c to have two sections, and enhance test_btf.c test_file feature to test btf func_info returned by the kernel. Signed-off-by: Yonghong Song --- tools/testing/selftests/bpf/test_btf.c | 72 +++++++++++++++++++- tools/testing/selftests/bpf/test_btf_haskv.c | 16 ++++- tools/testing/selftests/bpf/test_btf_nokv.c | 16 ++++- 3 files changed, 99 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/bpf/test_btf.c b/tools/testing/selftests/bpf/test_btf.c index e03a8cea4bb7..0bbefb571426 100644 --- a/tools/testing/selftests/bpf/test_btf.c +++ b/tools/testing/selftests/bpf/test_btf.c @@ -2235,10 +2235,16 @@ static int file_has_btf_elf(const char *fn) static int do_test_file(unsigned int test_num) { const struct btf_file_test *test = &file_tests[test_num - 1]; + const char *expected_fnames[] = {"_dummy_tracepoint", + "test_long_fname_1", + "test_long_fname_2"}; + __u32 func_lens[10], func_types[10], info_len; + struct bpf_prog_info info = {}; struct bpf_object *obj = NULL; struct bpf_program *prog; + struct btf *btf = NULL; struct bpf_map *map; - int err; + int i, err, prog_fd; fprintf(stderr, "BTF libbpf test[%u] (%s): ", test_num, test->file); @@ -2271,6 +2277,7 @@ static int do_test_file(unsigned int test_num) err = bpf_object__load(obj); if (CHECK(err < 0, "bpf_object__load: %d", err)) goto done; + prog_fd = bpf_program__fd(prog); map = bpf_object__find_map_by_name(obj, "btf_map"); if (CHECK(!map, "btf_map not found")) { @@ -2285,6 +2292,69 @@ static int do_test_file(unsigned int test_num) test->btf_kv_notfound)) goto done; + if (!jit_enabled) + goto skip_jit; + + info_len = sizeof(struct bpf_prog_info); + info.nr_jited_func_types = ARRAY_SIZE(func_types); + info.nr_jited_func_lens = ARRAY_SIZE(func_lens); + info.jited_func_types = ptr_to_u64(&func_types[0]); + info.jited_func_lens = ptr_to_u64(&func_lens[0]); + + err = bpf_obj_get_info_by_fd(prog_fd, &info, &info_len); + + if (CHECK(err == -1, "invalid get info errno:%d", errno)) { + fprintf(stderr, "%s\n", btf_log_buf); + err = -1; + goto done; + } + if (CHECK(info.nr_jited_func_lens != 3, + "incorrect info.nr_jited_func_lens %d", + info.nr_jited_func_lens)) { + err = -1; + goto done; + } + if (CHECK(info.nr_jited_func_types != 3, + "incorrect info.nr_jited_func_types %d", + info.nr_jited_func_types)) { + err = -1; + goto done; + } + if (CHECK(info.btf_id == 0, "incorrect btf_id = 0")) { + err = -1; + goto done; + } + + err = btf_get_from_id(info.btf_id, &btf); + if (CHECK(err, "cannot get btf from kernel, err: %d", err)) + goto done; + + /* check three functions */ + for (i = 0; i < 3; i++) { + const struct btf_type *t; + const char *fname; + + t = btf__type_by_id(btf, func_types[i]); + if (CHECK(!t, "btf__type_by_id failure: id %u", + func_types[i])) { + err = -1; + goto done; + } + + fname = btf__name_by_offset(btf, t->name_off); + err = strcmp(fname, expected_fnames[i]); + /* for the second and third functions in .text section, + * the compiler may order them either way. + */ + if (i && err) + err = strcmp(fname, expected_fnames[3 - i]); + if (CHECK(err, "incorrect fname %s", fname ? : "")) { + err = -1; + goto done; + } + } + +skip_jit: fprintf(stderr, "OK"); done: diff --git a/tools/testing/selftests/bpf/test_btf_haskv.c b/tools/testing/selftests/bpf/test_btf_haskv.c index b21b876f475d..e5c79fe0ffdb 100644 --- a/tools/testing/selftests/bpf/test_btf_haskv.c +++ b/tools/testing/selftests/bpf/test_btf_haskv.c @@ -24,8 +24,8 @@ struct dummy_tracepoint_args { struct sock *sock; }; -SEC("dummy_tracepoint") -int _dummy_tracepoint(struct dummy_tracepoint_args *arg) +__attribute__((noinline)) +static int test_long_fname_2(struct dummy_tracepoint_args *arg) { struct ipv_counts *counts; int key = 0; @@ -42,4 +42,16 @@ int _dummy_tracepoint(struct dummy_tracepoint_args *arg) return 0; } +__attribute__((noinline)) +static int test_long_fname_1(struct dummy_tracepoint_args *arg) +{ + return test_long_fname_2(arg); +} + +SEC("dummy_tracepoint") +int _dummy_tracepoint(struct dummy_tracepoint_args *arg) +{ + return test_long_fname_1(arg); +} + char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/test_btf_nokv.c b/tools/testing/selftests/bpf/test_btf_nokv.c index 0ed8e088eebf..434188c37774 100644 --- a/tools/testing/selftests/bpf/test_btf_nokv.c +++ b/tools/testing/selftests/bpf/test_btf_nokv.c @@ -22,8 +22,8 @@ struct dummy_tracepoint_args { struct sock *sock; }; -SEC("dummy_tracepoint") -int _dummy_tracepoint(struct dummy_tracepoint_args *arg) +__attribute__((noinline)) +static int test_long_fname_2(struct dummy_tracepoint_args *arg) { struct ipv_counts *counts; int key = 0; @@ -40,4 +40,16 @@ int _dummy_tracepoint(struct dummy_tracepoint_args *arg) return 0; } +__attribute__((noinline)) +static int test_long_fname_1(struct dummy_tracepoint_args *arg) +{ + return test_long_fname_2(arg); +} + +SEC("dummy_tracepoint") +int _dummy_tracepoint(struct dummy_tracepoint_args *arg) +{ + return test_long_fname_1(arg); +} + char _license[] SEC("license") = "GPL"; From patchwork Wed Oct 17 07:24:00 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yonghong Song X-Patchwork-Id: 985144 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=fb.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=fb.com header.i=@fb.com header.b="rGJAG3t8"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 42ZkG14Sg5z9sCW for ; Wed, 17 Oct 2018 18:24:41 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727485AbeJQPS6 (ORCPT ); Wed, 17 Oct 2018 11:18:58 -0400 Received: from mx0a-00082601.pphosted.com ([67.231.145.42]:49180 "EHLO mx0a-00082601.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727154AbeJQPS6 (ORCPT ); Wed, 17 Oct 2018 11:18:58 -0400 Received: from pps.filterd (m0044008.ppops.net [127.0.0.1]) by mx0a-00082601.pphosted.com (8.16.0.22/8.16.0.22) with SMTP id w9H7O0YK002731 for ; Wed, 17 Oct 2018 00:24:38 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=fb.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-type; s=facebook; bh=8L6PYTAOmVP+lTzIDVkcKB83iSwSV7bKromJXQrsj0M=; b=rGJAG3t8AKtIH7bfTWJ/VaNkWeaz05v+el0x4sI9PegBZkbgy5m+QmbS7m3hgKuZcdlp kTxzaN7q8FTztekYoj9M9madSBYOo7IpRhl0CIBA/fp1eovOfK79zkuLfdNAeWXTWFR0 /QBK/6CDRno4g47sMOIMzNFvlRZ1xbQv2yQ= Received: from mail.thefacebook.com ([199.201.64.23]) by mx0a-00082601.pphosted.com with ESMTP id 2n5ygyg5fa-9 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT) for ; Wed, 17 Oct 2018 00:24:38 -0700 Received: from mx-out.facebook.com (2620:10d:c081:10::13) by mail.thefacebook.com (2620:10d:c081:35::130) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA) id 15.1.1531.3; Wed, 17 Oct 2018 00:24:04 -0700 Received: by devbig003.ftw2.facebook.com (Postfix, from userid 128203) id 164EF370225C; Wed, 17 Oct 2018 00:24:01 -0700 (PDT) Smtp-Origin-Hostprefix: devbig From: Yonghong Song Smtp-Origin-Hostname: devbig003.ftw2.facebook.com To: , , , CC: Smtp-Origin-Cluster: ftw2c04 Subject: [PATCH bpf-next v2 13/13] tools/bpf: bpftool: add support for jited func types Date: Wed, 17 Oct 2018 00:24:00 -0700 Message-ID: <20181017072400.2768484-4-yhs@fb.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20181017072400.2768484-1-yhs@fb.com> References: <20181017072400.2768484-1-yhs@fb.com> X-FB-Internal: Safe MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2018-10-16_14:, , signatures=0 X-Proofpoint-Spam-Reason: safe X-FB-Internal: Safe Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org This patch added support to print function signature if btf func_info is available. Note that ksym now uses function name instead of prog_name as prog_name has a limit of 16 bytes including ending '\0'. The following is a sample output for selftests test_btf with file test_btf_haskv.o: $ bpftool prog dump jited id 1 int _dummy_tracepoint(struct dummy_tracepoint_args * ): bpf_prog_b07ccb89267cf242__dummy_tracepoint: 0: push %rbp 1: mov %rsp,%rbp ...... 3c: add $0x28,%rbp 40: leaveq 41: retq int test_long_fname_1(struct dummy_tracepoint_args * ): bpf_prog_2dcecc18072623fc_test_long_fname_1: 0: push %rbp 1: mov %rsp,%rbp ...... 3a: add $0x28,%rbp 3e: leaveq 3f: retq int test_long_fname_2(struct dummy_tracepoint_args * ): bpf_prog_89d64e4abf0f0126_test_long_fname_2: 0: push %rbp 1: mov %rsp,%rbp ...... 80: add $0x28,%rbp 84: leaveq 85: retq Signed-off-by: Yonghong Song --- tools/bpf/bpftool/btf_dumper.c | 96 ++++++++++++++++++++++++++++++++++ tools/bpf/bpftool/main.h | 2 + tools/bpf/bpftool/prog.c | 54 +++++++++++++++++++ 3 files changed, 152 insertions(+) diff --git a/tools/bpf/bpftool/btf_dumper.c b/tools/bpf/bpftool/btf_dumper.c index 55bc512a1831..a31df4202335 100644 --- a/tools/bpf/bpftool/btf_dumper.c +++ b/tools/bpf/bpftool/btf_dumper.c @@ -249,3 +249,99 @@ int btf_dumper_type(const struct btf_dumper *d, __u32 type_id, { return btf_dumper_do_type(d, type_id, 0, data); } + +#define BTF_PRINT_STRING(str) \ + { \ + pos += snprintf(func_sig + pos, size - pos, str); \ + if (pos >= size) \ + return -1; \ + } +#define BTF_PRINT_ONE_ARG(fmt, arg) \ + { \ + pos += snprintf(func_sig + pos, size - pos, fmt, arg); \ + if (pos >= size) \ + return -1; \ + } +#define BTF_PRINT_TYPE_ONLY(type) \ + { \ + pos = __btf_dumper_type_only(btf, type, func_sig, \ + pos, size); \ + if (pos == -1) \ + return -1; \ + } + +static int __btf_dumper_type_only(struct btf *btf, __u32 type_id, + char *func_sig, int pos, int size) +{ + const struct btf_type *t = btf__type_by_id(btf, type_id); + const struct btf_array *array; + int i, vlen; + + switch (BTF_INFO_KIND(t->info)) { + case BTF_KIND_INT: + BTF_PRINT_ONE_ARG("%s ", + btf__name_by_offset(btf, t->name_off)); + break; + case BTF_KIND_STRUCT: + BTF_PRINT_ONE_ARG("struct %s ", + btf__name_by_offset(btf, t->name_off)); + break; + case BTF_KIND_UNION: + BTF_PRINT_ONE_ARG("union %s ", + btf__name_by_offset(btf, t->name_off)); + break; + case BTF_KIND_ENUM: + BTF_PRINT_ONE_ARG("enum %s ", + btf__name_by_offset(btf, t->name_off)); + break; + case BTF_KIND_ARRAY: + array = (struct btf_array *)(t + 1); + BTF_PRINT_TYPE_ONLY(array->type); + BTF_PRINT_ONE_ARG("[%d]", array->nelems); + break; + case BTF_KIND_PTR: + BTF_PRINT_TYPE_ONLY(t->type); + BTF_PRINT_STRING("* "); + break; + case BTF_KIND_UNKN: + case BTF_KIND_FWD: + case BTF_KIND_TYPEDEF: + return -1; + case BTF_KIND_VOLATILE: + BTF_PRINT_STRING("volatile "); + BTF_PRINT_TYPE_ONLY(t->type); + break; + case BTF_KIND_CONST: + BTF_PRINT_STRING("const "); + BTF_PRINT_TYPE_ONLY(t->type); + break; + case BTF_KIND_RESTRICT: + BTF_PRINT_STRING("restrict "); + BTF_PRINT_TYPE_ONLY(t->type); + break; + case BTF_KIND_FUNC: + case BTF_KIND_FUNC_PROTO: + BTF_PRINT_TYPE_ONLY(t->type); + BTF_PRINT_ONE_ARG("%s(", btf__name_by_offset(btf, t->name_off)); + vlen = BTF_INFO_VLEN(t->info); + for (i = 0; i < vlen; i++) { + __u32 arg_type = ((__u32 *)(t + 1))[i]; + + BTF_PRINT_TYPE_ONLY(arg_type); + if (i != (vlen - 1)) + BTF_PRINT_STRING(", "); + } + BTF_PRINT_STRING(")"); + break; + default: + return -1; + } + + return pos; +} + +int btf_dumper_type_only(struct btf *btf, __u32 type_id, char *func_sig, + int size) +{ + return __btf_dumper_type_only(btf, type_id, func_sig, 0, size); +} diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h index 28ee769bd11b..f887564476dc 100644 --- a/tools/bpf/bpftool/main.h +++ b/tools/bpf/bpftool/main.h @@ -168,6 +168,8 @@ struct btf_dumper { */ int btf_dumper_type(const struct btf_dumper *d, __u32 type_id, const void *data); +int btf_dumper_type_only(struct btf *btf, __u32 func_type_id, char *func_only, + int size); struct nlattr; struct ifinfomsg; diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c index 335028968dfb..e78632a30ea3 100644 --- a/tools/bpf/bpftool/prog.c +++ b/tools/bpf/bpftool/prog.c @@ -47,6 +47,7 @@ #include #include +#include #include #include "cfg.h" @@ -447,9 +448,11 @@ static int do_show(int argc, char **argv) static int do_dump(int argc, char **argv) { unsigned long *func_ksyms = NULL; + unsigned int *func_types = NULL; struct bpf_prog_info info = {}; unsigned int *func_lens = NULL; unsigned int nr_func_ksyms; + unsigned int nr_func_types; unsigned int nr_func_lens; struct dump_data dd = {}; __u32 len = sizeof(info); @@ -546,6 +549,16 @@ static int do_dump(int argc, char **argv) } } + nr_func_types = info.nr_jited_func_types; + if (nr_func_types) { + func_types = malloc(nr_func_types * sizeof(__u32)); + if (!func_types) { + p_err("mem alloc failed"); + close(fd); + goto err_free; + } + } + memset(&info, 0, sizeof(info)); *member_ptr = ptr_to_u64(buf); @@ -554,6 +567,8 @@ static int do_dump(int argc, char **argv) info.nr_jited_ksyms = nr_func_ksyms; info.jited_func_lens = ptr_to_u64(func_lens); info.nr_jited_func_lens = nr_func_lens; + info.jited_func_types = ptr_to_u64(func_types); + info.nr_jited_func_types = nr_func_types; err = bpf_obj_get_info_by_fd(fd, &info, &len); close(fd); @@ -577,6 +592,11 @@ static int do_dump(int argc, char **argv) goto err_free; } + if (info.nr_jited_func_types > nr_func_types) { + p_err("too many types returned"); + goto err_free; + } + if ((member_len == &info.jited_prog_len && info.jited_prog_insns == 0) || (member_len == &info.xlated_prog_len && @@ -585,6 +605,12 @@ static int do_dump(int argc, char **argv) goto err_free; } + if (info.btf_id && + info.nr_jited_func_lens != info.nr_jited_func_types) { + p_err("unequal jited func lens and types"); + goto err_free; + } + if (filepath) { fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0600); if (fd < 0) { @@ -618,7 +644,9 @@ static int do_dump(int argc, char **argv) struct kernel_sym *sym = NULL; char sym_name[SYM_MAX_NAME]; unsigned char *img = buf; + struct btf *btf = NULL; __u64 *ksyms = NULL; + char func_sig[1024]; __u32 *lens; __u32 i; @@ -627,6 +655,14 @@ static int do_dump(int argc, char **argv) ksyms = (__u64 *) info.jited_ksyms; } + if (info.btf_id) { + err = btf_get_from_id(info.btf_id, &btf); + if (err) { + p_err("failed to get btf"); + goto err_free; + } + } + if (json_output) jsonw_start_array(json_wtr); @@ -642,12 +678,28 @@ static int do_dump(int argc, char **argv) strcpy(sym_name, "unknown"); } + func_sig[0] = '\0'; + if (btf) { + err = btf_dumper_type_only(btf, + func_types[i], + func_sig, + sizeof(func_sig)); + if (err < 0) + func_sig[0] = '\0'; + } + if (json_output) { jsonw_start_object(json_wtr); + if (func_sig[0] != '\0') { + jsonw_name(json_wtr, "proto"); + jsonw_string(json_wtr, func_sig); + } jsonw_name(json_wtr, "name"); jsonw_string(json_wtr, sym_name); jsonw_name(json_wtr, "insns"); } else { + if (func_sig[0] != '\0') + printf("%s:\n", func_sig); printf("%s:\n", sym_name); } @@ -685,12 +737,14 @@ static int do_dump(int argc, char **argv) free(buf); free(func_ksyms); free(func_lens); + free(func_types); return 0; err_free: free(buf); free(func_ksyms); free(func_lens); + free(func_types); return -1; }