All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH bpf-next 00/13] bpf: add btf func info support
@ 2018-10-12 18:54 Yonghong Song
  2018-10-12 18:54 ` [PATCH bpf-next 01/13] bpf: btf: Break up btf_type_is_void() Yonghong Song
                   ` (4 more replies)
  0 siblings, 5 replies; 12+ messages in thread
From: Yonghong Song @ 2018-10-12 18:54 UTC (permalink / raw)
  To: ast, kafai, daniel, netdev; +Cc: kernel-team

The BTF support was added to kernel by Commit 69b693f0aefa
("bpf: btf: Introduce BPF Type Format (BTF)"), which introduced
.BTF section into ELF file and is primarily
used for map pretty print.
pahole is used to convert dwarf to BTF for ELF files.

The next step would be add func type info and debug line info
into BTF. For debug line info, it is desirable to encode
source code directly in the BTF to ease deployment and
introspection.

The func type and debug line info are relative to byte code offset.
Also since byte codes may need to be relocated by the loader,
func info and line info are placed in a different section,
.BTF.ext, so the loader could manupilate it according to how
byte codes are placed, before loading into the kernel.

LLVM commit https://reviews.llvm.org/rL344366 (in llvm trunk)
now can generate type/func/line info.
For the below example, with a llvm compiler built with Debug mode,
the following is generated:

  -bash-4.2$ cat test.c
  int foo(int (*bar)(int)) { return bar(5); }
  -bash-4.2$ clang -target bpf -g -O2 -mllvm -debug-only=btf -c test.c
  Type Table:
  [1] FUNC name_off=1 info=0x0c000001 size/type=2
        param_type=3
  [2] INT name_off=11 info=0x01000000 size/type=4
        desc=0x01000020
  [3] PTR name_off=0 info=0x02000000 size/type=4
  [4] FUNC_PROTO name_off=0 info=0x0d000001 size/type=2
        param_type=2

  String Table:
  0 : 
  1 : foo
  5 : .text
  11 : int
  15 : test.c
  22 : int foo(int (*bar)(int)) { return bar(5); }

  FuncInfo Table:
  sec_name_off=5
        insn_offset=<Omitted> type_id=1

  LineInfo Table:
  sec_name_off=5
        insn_offset=<Omitted> file_name_off=15 line_off=22 line_num=1 column_num=0
        insn_offset=<Omitted> file_name_off=15 line_off=22 line_num=1 column_num=35
        insn_offset=<Omitted> file_name_off=15 line_off=22 line_num=1 column_num=28

In the above, type and string tables are in .BTF section, and
func and line info tables in .BTF.ext. The "<Omitted>" is the
insn offset which is not available during the dump time but
resolved during later compilation process.
Following the format specification at Patch #9 and examine the
raw data in .BTF.ext section, we have
  FuncInfo Table:
  sec_name_off=5
        insn_offset=0 type_id=1

  LineInfo Table:
  sec_name_off=5
        insn_offset=0  file_name_off=15 line_off=22 line_num=1 column_num=0
        insn_offset=8  file_name_off=15 line_off=22 line_num=1 column_num=35
        insn_offset=24 file_name_off=15 line_off=22 line_num=1 column_num=28
In the above insn_offset is the byte offset.

With this support, better ksym for bpf programs and functions can be
generated. Below is a demonstration from Patch #13.
  $ 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

For the patchset,
Patch #1  refactors the code to break up btf_type_is_void().
Patch #2  introduces new BTF types BTF_KIND_FUNC and BTF_KIND_FUNC_PROTO.
Patch #3  syncs btf.h header to tools directory.
Patch #4  adds btf func/func_proto self tests in test_btf.
Patch #5  adds kernel interface to load func_info to kernel
          and pass func_info to userspace.
Patch #6  syncs bpf.h header to tools directory.
Patch #7  adds news btf/func_info related fields in libbpf
          program load function.
Patch #8  extends selftest test_btf to test load/retrieve func_type info.
Patch #9  adds .BTF.ext func info support.
Patch #10 changes Makefile to avoid using pahole if llvm is capable of
          generating BTF sections.
Patch #11 refactors to have btf_get_from_id() in libbpf for reuse.
Patch #12 enhance test_btf file testing to test func info.
Patch #13 adds bpftool support for func signature dump.

Yonghong Song (13):
  bpf: btf: Break up btf_type_is_void()
  bpf: btf: Add BTF_KIND_FUNC and BTF_KIND_FUNC_PROTO
  tools/bpf: sync kernel btf.h header
  tools/bpf: add btf func/func_proto unit tests in selftest test_btf
  bpf: get better bpf_prog ksyms based on btf func type_id
  tools/bpf: sync kernel uapi bpf.h header to tools directory
  tools/bpf: add new fields for program load in lib/bpf
  tools/bpf: extends test_btf to test load/retrieve func_type info
  tools/bpf: add support to read .BTF.ext sections
  tools/bpf: do not use pahole if clang/llvm can generate BTF sections
  tools/bpf: refactor to implement btf_get_from_id() in lib/bpf
  tools/bpf: enhance test_btf file testing to test func info
  tools/bpf: bpftool: add support for jited func types

 include/linux/bpf.h                          |   2 +
 include/linux/bpf_verifier.h                 |   1 +
 include/linux/btf.h                          |   2 +
 include/uapi/linux/bpf.h                     |  11 +
 include/uapi/linux/btf.h                     |   9 +-
 kernel/bpf/btf.c                             | 322 +++++++++--
 kernel/bpf/core.c                            |   9 +
 kernel/bpf/syscall.c                         |  86 ++-
 kernel/bpf/verifier.c                        |  50 ++
 samples/bpf/Makefile                         |   8 +
 tools/bpf/bpftool/btf_dumper.c               |  96 ++++
 tools/bpf/bpftool/main.h                     |   2 +
 tools/bpf/bpftool/map.c                      |  68 +--
 tools/bpf/bpftool/prog.c                     |  54 ++
 tools/include/uapi/linux/bpf.h               |  11 +
 tools/include/uapi/linux/btf.h               |   9 +-
 tools/lib/bpf/bpf.c                          |   3 +
 tools/lib/bpf/bpf.h                          |   3 +
 tools/lib/bpf/btf.c                          | 305 ++++++++++
 tools/lib/bpf/btf.h                          |  32 ++
 tools/lib/bpf/libbpf.c                       |  53 +-
 tools/testing/selftests/bpf/Makefile         |   8 +
 tools/testing/selftests/bpf/test_btf.c       | 566 ++++++++++++++++++-
 tools/testing/selftests/bpf/test_btf_haskv.c |  16 +-
 tools/testing/selftests/bpf/test_btf_nokv.c  |  16 +-
 25 files changed, 1613 insertions(+), 129 deletions(-)

-- 
2.17.1

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH bpf-next 01/13] bpf: btf: Break up btf_type_is_void()
  2018-10-12 18:54 [PATCH bpf-next 00/13] bpf: add btf func info support Yonghong Song
@ 2018-10-12 18:54 ` Yonghong Song
  2018-10-15 21:50   ` Daniel Borkmann
  2018-10-12 18:54 ` [PATCH bpf-next 02/13] bpf: btf: Add BTF_KIND_FUNC and BTF_KIND_FUNC_PROTO Yonghong Song
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 12+ messages in thread
From: Yonghong Song @ 2018-10-12 18:54 UTC (permalink / raw)
  To: ast, kafai, daniel, netdev; +Cc: kernel-team

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 <kafai@fb.com>
---
 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;
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH bpf-next 02/13] bpf: btf: Add BTF_KIND_FUNC and BTF_KIND_FUNC_PROTO
  2018-10-12 18:54 [PATCH bpf-next 00/13] bpf: add btf func info support Yonghong Song
  2018-10-12 18:54 ` [PATCH bpf-next 01/13] bpf: btf: Break up btf_type_is_void() Yonghong Song
@ 2018-10-12 18:54 ` Yonghong Song
  2018-10-15 22:30   ` Daniel Borkmann
  2018-10-15 22:36   ` Daniel Borkmann
  2018-10-12 18:54 ` [PATCH bpf-next 03/13] tools/bpf: sync kernel btf.h header Yonghong Song
                   ` (2 subsequent siblings)
  4 siblings, 2 replies; 12+ messages in thread
From: Yonghong Song @ 2018-10-12 18:54 UTC (permalink / raw)
  To: ast, kafai, daniel, netdev; +Cc: kernel-team

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 latest llvm trunk built with Debug mode, we have
  $ clang -target bpf -g -O2 -mllvm -debug-only=btf -c test.c
  Type Table:
  [1] FUNC name_off=1 info=0x0c000001 size/type=2
          param_type=3
  [2] INT name_off=11 info=0x01000000 size/type=4
          desc=0x01000020
  [3] PTR name_off=0 info=0x02000000 size/type=4
  [4] FUNC_PROTO name_off=0 info=0x0d000001 size/type=2
          param_type=2

  String Table:
  0 :
  1 : foo
  5 : .text
  11 : int
  15 : test.c
  22 : int foo(int (*bar)(int)) { return bar(5); }

  FuncInfo Table:
  sec_name_off=5
          insn_offset=<Omitted> type_id=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 <Omitted>),
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 <kafai@fb.com>
Signed-off-by: Yonghong Song <yhs@fb.com>
---
 include/uapi/linux/btf.h |   9 +-
 kernel/bpf/btf.c         | 277 ++++++++++++++++++++++++++++++++++-----
 2 files changed, 250 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..794a185f11bf 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -5,6 +5,7 @@
 #include <uapi/linux/types.h>
 #include <linux/seq_file.h>
 #include <linux/compiler.h>
+#include <linux/ctype.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/anon_inodes.h>
@@ -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,24 @@ 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];
+
+	if (!isalpha(*src) && *src != '_')
+		return false;
+
+	src++;
+	while (*src) {
+		if (!isalnum(*src) && *src != '_')
+			return false;
+		src++;
+	}
+
+	return true;
+}
+
 static const char *btf_name_by_offset(const struct btf *btf, u32 offset)
 {
 	if (!offset)
@@ -747,7 +782,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 +1207,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 +1230,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 +1258,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 +1289,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 +1598,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 +1843,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 +1991,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 +2064,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 +2097,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 +2152,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;
 		}
 	}
 
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH bpf-next 03/13] tools/bpf: sync kernel btf.h header
  2018-10-12 18:54 [PATCH bpf-next 00/13] bpf: add btf func info support Yonghong Song
  2018-10-12 18:54 ` [PATCH bpf-next 01/13] bpf: btf: Break up btf_type_is_void() Yonghong Song
  2018-10-12 18:54 ` [PATCH bpf-next 02/13] bpf: btf: Add BTF_KIND_FUNC and BTF_KIND_FUNC_PROTO Yonghong Song
@ 2018-10-12 18:54 ` Yonghong Song
  2018-10-12 18:54 ` [PATCH bpf-next 04/13] tools/bpf: add btf func/func_proto unit tests in selftest test_btf Yonghong Song
  2018-10-16 18:27 ` [PATCH bpf-next 00/13] bpf: add btf func info support Alexei Starovoitov
  4 siblings, 0 replies; 12+ messages in thread
From: Yonghong Song @ 2018-10-12 18:54 UTC (permalink / raw)
  To: ast, kafai, daniel, netdev; +Cc: kernel-team

The kernel uapi btf.h is synced to the tools directory.

Signed-off-by: Martin KaFai Lau <kafai@fb.com>
Signed-off-by: Yonghong Song <yhs@fb.com>
---
 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.
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH bpf-next 04/13] tools/bpf: add btf func/func_proto unit tests in selftest test_btf
  2018-10-12 18:54 [PATCH bpf-next 00/13] bpf: add btf func info support Yonghong Song
                   ` (2 preceding siblings ...)
  2018-10-12 18:54 ` [PATCH bpf-next 03/13] tools/bpf: sync kernel btf.h header Yonghong Song
@ 2018-10-12 18:54 ` Yonghong Song
  2018-10-16 18:27 ` [PATCH bpf-next 00/13] bpf: add btf func info support Alexei Starovoitov
  4 siblings, 0 replies; 12+ messages in thread
From: Yonghong Song @ 2018-10-12 18:54 UTC (permalink / raw)
  To: ast, kafai, daniel, netdev; +Cc: kernel-team

Add several BTF_KIND_FUNC and BTF_KIND_FUNC_PROTO
unit tests in bpf selftest test_btf.

Signed-off-by: Martin KaFai Lau <kafai@fb.com>
Signed-off-by: Yonghong Song <yhs@fb.com>
---
 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)
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH bpf-next 01/13] bpf: btf: Break up btf_type_is_void()
  2018-10-12 18:54 ` [PATCH bpf-next 01/13] bpf: btf: Break up btf_type_is_void() Yonghong Song
@ 2018-10-15 21:50   ` Daniel Borkmann
  0 siblings, 0 replies; 12+ messages in thread
From: Daniel Borkmann @ 2018-10-15 21:50 UTC (permalink / raw)
  To: Yonghong Song, ast, kafai, netdev; +Cc: kernel-team

On 10/12/2018 08:54 PM, Yonghong Song wrote:
> 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 <kafai@fb.com>
> ---

Yonghong, your SoB is missing here.

Thanks,
Daniel

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH bpf-next 02/13] bpf: btf: Add BTF_KIND_FUNC and BTF_KIND_FUNC_PROTO
  2018-10-12 18:54 ` [PATCH bpf-next 02/13] bpf: btf: Add BTF_KIND_FUNC and BTF_KIND_FUNC_PROTO Yonghong Song
@ 2018-10-15 22:30   ` Daniel Borkmann
  2018-10-17  3:11     ` Yonghong Song
  2018-10-15 22:36   ` Daniel Borkmann
  1 sibling, 1 reply; 12+ messages in thread
From: Daniel Borkmann @ 2018-10-15 22:30 UTC (permalink / raw)
  To: Yonghong Song, ast, kafai, netdev; +Cc: kernel-team

On 10/12/2018 08:54 PM, Yonghong Song wrote:
> 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 latest llvm trunk built with Debug mode, we have
>   $ clang -target bpf -g -O2 -mllvm -debug-only=btf -c test.c
>   Type Table:
>   [1] FUNC name_off=1 info=0x0c000001 size/type=2
>           param_type=3
>   [2] INT name_off=11 info=0x01000000 size/type=4
>           desc=0x01000020
>   [3] PTR name_off=0 info=0x02000000 size/type=4
>   [4] FUNC_PROTO name_off=0 info=0x0d000001 size/type=2
>           param_type=2
> 
>   String Table:
>   0 :
>   1 : foo
>   5 : .text
>   11 : int
>   15 : test.c
>   22 : int foo(int (*bar)(int)) { return bar(5); }
> 
>   FuncInfo Table:
>   sec_name_off=5
>           insn_offset=<Omitted> type_id=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".

Should also "bar" be part of the string table (at least at some point in future)?
Iow, if verifier hints to an issue in the program when it would for example walk
pointers and rewrite ctx access, then it could dump the var name along with it.
It might be useful as well in combination with 22 from str table, when annotating
the source. We might need support for variadic functions, though. How is LLVM
handling the latter with the recent BTF support?

> In FuncInfo Table, for section .text, the function,
> with to-be-determined offset (marked as <Omitted>),
> 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 <kafai@fb.com>
> Signed-off-by: Yonghong Song <yhs@fb.com>

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH bpf-next 02/13] bpf: btf: Add BTF_KIND_FUNC and BTF_KIND_FUNC_PROTO
  2018-10-12 18:54 ` [PATCH bpf-next 02/13] bpf: btf: Add BTF_KIND_FUNC and BTF_KIND_FUNC_PROTO Yonghong Song
  2018-10-15 22:30   ` Daniel Borkmann
@ 2018-10-15 22:36   ` Daniel Borkmann
  2018-10-17  3:22     ` Yonghong Song
  1 sibling, 1 reply; 12+ messages in thread
From: Daniel Borkmann @ 2018-10-15 22:36 UTC (permalink / raw)
  To: Yonghong Song, ast, kafai, netdev; +Cc: kernel-team

On 10/12/2018 08:54 PM, Yonghong Song wrote:
[...]
> +static bool btf_name_valid_identifier(const struct btf *btf, u32 offset)
> +{
> +	/* offset must be valid */
> +	const char *src = &btf->strings[offset];
> +
> +	if (!isalpha(*src) && *src != '_')
> +		return false;
> +
> +	src++;
> +	while (*src) {
> +		if (!isalnum(*src) && *src != '_')
> +			return false;
> +		src++;
> +	}
> +
> +	return true;
> +}

Should there be an upper name length limit like KSYM_NAME_LEN? (Is it implied
by the kvmalloc() limit?)

>  static const char *btf_name_by_offset(const struct btf *btf, u32 offset)
>  {
>  	if (!offset)
> @@ -747,7 +782,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:

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH bpf-next 00/13] bpf: add btf func info support
  2018-10-12 18:54 [PATCH bpf-next 00/13] bpf: add btf func info support Yonghong Song
                   ` (3 preceding siblings ...)
  2018-10-12 18:54 ` [PATCH bpf-next 04/13] tools/bpf: add btf func/func_proto unit tests in selftest test_btf Yonghong Song
@ 2018-10-16 18:27 ` Alexei Starovoitov
  2018-10-17  3:25   ` Yonghong Song
  4 siblings, 1 reply; 12+ messages in thread
From: Alexei Starovoitov @ 2018-10-16 18:27 UTC (permalink / raw)
  To: Yonghong Song; +Cc: ast, kafai, daniel, netdev, kernel-team

On Fri, Oct 12, 2018 at 11:54:20AM -0700, Yonghong Song wrote:
> The BTF support was added to kernel by Commit 69b693f0aefa
> ("bpf: btf: Introduce BPF Type Format (BTF)"), which introduced
> .BTF section into ELF file and is primarily
> used for map pretty print.
> pahole is used to convert dwarf to BTF for ELF files.
> 
> The next step would be add func type info and debug line info
> into BTF. For debug line info, it is desirable to encode
> source code directly in the BTF to ease deployment and
> introspection.

it's kinda confusing that cover letter talks about line info next step,
but these kernel side patches are only for full prog name from btf.
It certainly makes sense for llvm to do both at the same time.
Please make the cover letter more clear.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH bpf-next 02/13] bpf: btf: Add BTF_KIND_FUNC and BTF_KIND_FUNC_PROTO
  2018-10-15 22:30   ` Daniel Borkmann
@ 2018-10-17  3:11     ` Yonghong Song
  0 siblings, 0 replies; 12+ messages in thread
From: Yonghong Song @ 2018-10-17  3:11 UTC (permalink / raw)
  To: Daniel Borkmann, Alexei Starovoitov, Martin Lau, netdev; +Cc: Kernel Team



On 10/15/18 3:30 PM, Daniel Borkmann wrote:
> On 10/12/2018 08:54 PM, Yonghong Song wrote:
>> 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 latest llvm trunk built with Debug mode, we have
>>    $ clang -target bpf -g -O2 -mllvm -debug-only=btf -c test.c
>>    Type Table:
>>    [1] FUNC name_off=1 info=0x0c000001 size/type=2
>>            param_type=3
>>    [2] INT name_off=11 info=0x01000000 size/type=4
>>            desc=0x01000020
>>    [3] PTR name_off=0 info=0x02000000 size/type=4
>>    [4] FUNC_PROTO name_off=0 info=0x0d000001 size/type=2
>>            param_type=2
>>
>>    String Table:
>>    0 :
>>    1 : foo
>>    5 : .text
>>    11 : int
>>    15 : test.c
>>    22 : int foo(int (*bar)(int)) { return bar(5); }
>>
>>    FuncInfo Table:
>>    sec_name_off=5
>>            insn_offset=<Omitted> type_id=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".
> 
> Should also "bar" be part of the string table (at least at some point in future)?

Yes, we can do it. The dwarf for the abovee example looks like

0x00000043:     DW_TAG_formal_parameter
                   DW_AT_location        (0x00000000
                      [0x0000000000000000,  0x0000000000000008): 
DW_OP_reg1 W1
                      [0x0000000000000008,  0x0000000000000018): 
DW_OP_reg2 W2)
                   DW_AT_name    ("bar")
                   DW_AT_decl_file       ("/home/yhs/tmp/t.c")
                   DW_AT_decl_line       (1)
                   DW_AT_type    (0x0000005a "subroutine int*")

0x0000005a:   DW_TAG_pointer_type
                 DW_AT_type      (0x0000005f "subroutine int")

0x0000005f:   DW_TAG_subroutine_type
                 DW_AT_type      (0x00000053 "int")
                 DW_AT_prototyped        (true)

0x00000064:     DW_TAG_formal_parameter
                   DW_AT_type    (0x00000053 "int")

0x00000069:     NULL

0x0000006a:   NULL

The current llvm implementation does not record func
parameter name, so "bar" got lost. We could associate
"bar" with pointer type in the future implementation.

> Iow, if verifier hints to an issue in the program when it would for example walk
> pointers and rewrite ctx access, then it could dump the var name along with it.
> It might be useful as well in combination with 22 from str table, when annotating
> the source. We might need support for variadic functions, though. How is LLVM
> handling the latter with the recent BTF support?

The LLVM implementation does support variadic functions.
The last type id 0 indicates a variadic function.

> 
>> In FuncInfo Table, for section .text, the function,
>> with to-be-determined offset (marked as <Omitted>),
>> 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 <kafai@fb.com>
>> Signed-off-by: Yonghong Song <yhs@fb.com>

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH bpf-next 02/13] bpf: btf: Add BTF_KIND_FUNC and BTF_KIND_FUNC_PROTO
  2018-10-15 22:36   ` Daniel Borkmann
@ 2018-10-17  3:22     ` Yonghong Song
  0 siblings, 0 replies; 12+ messages in thread
From: Yonghong Song @ 2018-10-17  3:22 UTC (permalink / raw)
  To: Daniel Borkmann, Alexei Starovoitov, Martin Lau, netdev; +Cc: Kernel Team



On 10/15/18 3:36 PM, Daniel Borkmann wrote:
> On 10/12/2018 08:54 PM, Yonghong Song wrote:
> [...]
>> +static bool btf_name_valid_identifier(const struct btf *btf, u32 offset)
>> +{
>> +	/* offset must be valid */
>> +	const char *src = &btf->strings[offset];
>> +
>> +	if (!isalpha(*src) && *src != '_')
>> +		return false;
>> +
>> +	src++;
>> +	while (*src) {
>> +		if (!isalnum(*src) && *src != '_')
>> +			return false;
>> +		src++;
>> +	}
>> +
>> +	return true;
>> +}
> 
> Should there be an upper name length limit like KSYM_NAME_LEN? (Is it implied
> by the kvmalloc() limit?)

KSYM_NAME_LEN is good choice. Here, we check function names and 
struct/union member names. In C, based on
https://stackoverflow.com/questions/2352209/max-identifier-length,
the identifier max length is 63. Some compiler implementation may vary.
KSYM_NAME_LEN is 128.

> 
>>   static const char *btf_name_by_offset(const struct btf *btf, u32 offset)
>>   {
>>   	if (!offset)
>> @@ -747,7 +782,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:

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH bpf-next 00/13] bpf: add btf func info support
  2018-10-16 18:27 ` [PATCH bpf-next 00/13] bpf: add btf func info support Alexei Starovoitov
@ 2018-10-17  3:25   ` Yonghong Song
  0 siblings, 0 replies; 12+ messages in thread
From: Yonghong Song @ 2018-10-17  3:25 UTC (permalink / raw)
  To: Alexei Starovoitov
  Cc: Alexei Starovoitov, Martin Lau, daniel, netdev, Kernel Team



On 10/16/18 11:27 AM, Alexei Starovoitov wrote:
> On Fri, Oct 12, 2018 at 11:54:20AM -0700, Yonghong Song wrote:
>> The BTF support was added to kernel by Commit 69b693f0aefa
>> ("bpf: btf: Introduce BPF Type Format (BTF)"), which introduced
>> .BTF section into ELF file and is primarily
>> used for map pretty print.
>> pahole is used to convert dwarf to BTF for ELF files.
>>
>> The next step would be add func type info and debug line info
>> into BTF. For debug line info, it is desirable to encode
>> source code directly in the BTF to ease deployment and
>> introspection.
> 
> it's kinda confusing that cover letter talks about line info next step,
> but these kernel side patches are only for full prog name from btf.
> It certainly makes sense for llvm to do both at the same time.
> Please make the cover letter more clear.

Make sense. Will remove line_info stuff from the cover letter.

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2018-10-17 11:19 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-10-12 18:54 [PATCH bpf-next 00/13] bpf: add btf func info support Yonghong Song
2018-10-12 18:54 ` [PATCH bpf-next 01/13] bpf: btf: Break up btf_type_is_void() Yonghong Song
2018-10-15 21:50   ` Daniel Borkmann
2018-10-12 18:54 ` [PATCH bpf-next 02/13] bpf: btf: Add BTF_KIND_FUNC and BTF_KIND_FUNC_PROTO Yonghong Song
2018-10-15 22:30   ` Daniel Borkmann
2018-10-17  3:11     ` Yonghong Song
2018-10-15 22:36   ` Daniel Borkmann
2018-10-17  3:22     ` Yonghong Song
2018-10-12 18:54 ` [PATCH bpf-next 03/13] tools/bpf: sync kernel btf.h header Yonghong Song
2018-10-12 18:54 ` [PATCH bpf-next 04/13] tools/bpf: add btf func/func_proto unit tests in selftest test_btf Yonghong Song
2018-10-16 18:27 ` [PATCH bpf-next 00/13] bpf: add btf func info support Alexei Starovoitov
2018-10-17  3:25   ` Yonghong Song

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.