lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Fri, 7 Dec 2018 16:42:32 -0800
From:   Martin KaFai Lau <kafai@...com>
To:     <netdev@...r.kernel.org>
CC:     Alexei Starovoitov <ast@...com>,
        Daniel Borkmann <daniel@...earbox.net>, <kernel-team@...com>
Subject: [PATCH bpf-next 7/7] bpf: libbpf: bpftool: Print bpf_line_info during prog dump

This patch adds print bpf_line_info function in 'prog dump jitted'
and 'prog dump xlated':

[root@...h-fb-vm1 bpf]# ~/devshare/fb-kernel/linux/tools/bpf/bpftool/bpftool prog dump jited pinned /sys/fs/bpf/test_btf_haskv
[...]
int test_long_fname_2(struct dummy_tracepoint_args * arg):
bpf_prog_44a040bf25481309_test_long_fname_2:
; static int test_long_fname_2(struct dummy_tracepoint_args *arg)
   0:	push   %rbp
   1:	mov    %rsp,%rbp
   4:	sub    $0x30,%rsp
   b:	sub    $0x28,%rbp
   f:	mov    %rbx,0x0(%rbp)
  13:	mov    %r13,0x8(%rbp)
  17:	mov    %r14,0x10(%rbp)
  1b:	mov    %r15,0x18(%rbp)
  1f:	xor    %eax,%eax
  21:	mov    %rax,0x20(%rbp)
  25:	xor    %esi,%esi
; int key = 0;
  27:	mov    %esi,-0x4(%rbp)
; if (!arg->sock)
  2a:	mov    0x8(%rdi),%rdi
; if (!arg->sock)
  2e:	cmp    $0x0,%rdi
  32:	je     0x0000000000000070
  34:	mov    %rbp,%rsi
; counts = bpf_map_lookup_elem(&btf_map, &key);
  37:	add    $0xfffffffffffffffc,%rsi
  3b:	movabs $0xffff8881139d7480,%rdi
  45:	add    $0x110,%rdi
  4c:	mov    0x0(%rsi),%eax
  4f:	cmp    $0x4,%rax
  53:	jae    0x000000000000005e
  55:	shl    $0x3,%rax
  59:	add    %rdi,%rax
  5c:	jmp    0x0000000000000060
  5e:	xor    %eax,%eax
; if (!counts)
  60:	cmp    $0x0,%rax
  64:	je     0x0000000000000070
; counts->v6++;
  66:	mov    0x4(%rax),%edi
  69:	add    $0x1,%rdi
  6d:	mov    %edi,0x4(%rax)
  70:	mov    0x0(%rbp),%rbx
  74:	mov    0x8(%rbp),%r13
  78:	mov    0x10(%rbp),%r14
  7c:	mov    0x18(%rbp),%r15
  80:	add    $0x28,%rbp
  84:	leaveq
  85:	retq
[...]

With linum:
[root@...h-fb-vm1 bpf]# ~/devshare/fb-kernel/linux/tools/bpf/bpftool/bpftool prog dump jited pinned /sys/fs/bpf/test_btf_haskv linum
int _dummy_tracepoint(struct dummy_tracepoint_args * arg):
bpf_prog_b07ccb89267cf242__dummy_tracepoint:
; return test_long_fname_1(arg); [file:/data/users/kafai/fb-kernel/linux/tools/testing/selftests/bpf/test_btf_haskv.c line_num:54 line_col:9]
   0:	push   %rbp
   1:	mov    %rsp,%rbp
   4:	sub    $0x28,%rsp
   b:	sub    $0x28,%rbp
   f:	mov    %rbx,0x0(%rbp)
  13:	mov    %r13,0x8(%rbp)
  17:	mov    %r14,0x10(%rbp)
  1b:	mov    %r15,0x18(%rbp)
  1f:	xor    %eax,%eax
  21:	mov    %rax,0x20(%rbp)
  25:	callq  0x000000000000851e
; return test_long_fname_1(arg); [file:/data/users/kafai/fb-kernel/linux/tools/testing/selftests/bpf/test_btf_haskv.c line_num:54 line_col:2]
  2a:	xor    %eax,%eax
  2c:	mov    0x0(%rbp),%rbx
  30:	mov    0x8(%rbp),%r13
  34:	mov    0x10(%rbp),%r14
  38:	mov    0x18(%rbp),%r15
  3c:	add    $0x28,%rbp
  40:	leaveq
  41:	retq
[...]

Signed-off-by: Martin KaFai Lau <kafai@...com>
Acked-by: Yonghong Song <yhs@...com>
---
 .../bpftool/Documentation/bpftool-prog.rst    |  16 +-
 tools/bpf/bpftool/bash-completion/bpftool     |   6 +-
 tools/bpf/bpftool/btf_dumper.c                |  64 +++++
 tools/bpf/bpftool/jit_disasm.c                |  23 +-
 tools/bpf/bpftool/main.h                      |  23 +-
 tools/bpf/bpftool/prog.c                      | 100 ++++++-
 tools/bpf/bpftool/xlated_dumper.c             |  30 ++-
 tools/bpf/bpftool/xlated_dumper.h             |   7 +-
 tools/lib/bpf/Build                           |   2 +-
 tools/lib/bpf/bpf_prog_linfo.c                | 253 ++++++++++++++++++
 tools/lib/bpf/libbpf.h                        |  13 +
 tools/lib/bpf/libbpf.map                      |   4 +
 12 files changed, 516 insertions(+), 25 deletions(-)
 create mode 100644 tools/lib/bpf/bpf_prog_linfo.c

diff --git a/tools/bpf/bpftool/Documentation/bpftool-prog.rst b/tools/bpf/bpftool/Documentation/bpftool-prog.rst
index 5524b6dccd85..7c30731a9b73 100644
--- a/tools/bpf/bpftool/Documentation/bpftool-prog.rst
+++ b/tools/bpf/bpftool/Documentation/bpftool-prog.rst
@@ -22,8 +22,8 @@ MAP COMMANDS
 =============
 
 |	**bpftool** **prog { show | list }** [*PROG*]
-|	**bpftool** **prog dump xlated** *PROG* [{**file** *FILE* | **opcodes** | **visual**}]
-|	**bpftool** **prog dump jited**  *PROG* [{**file** *FILE* | **opcodes**}]
+|	**bpftool** **prog dump xlated** *PROG* [{**file** *FILE* | **opcodes** | **visual** | **linum**}]
+|	**bpftool** **prog dump jited**  *PROG* [{**file** *FILE* | **opcodes** | **linum**}]
 |	**bpftool** **prog pin** *PROG* *FILE*
 |	**bpftool** **prog { load | loadall }** *OBJ* *PATH* [**type** *TYPE*] [**map** {**idx** *IDX* | **name** *NAME*} *MAP*] [**dev** *NAME*]
 |	**bpftool** **prog attach** *PROG* *ATTACH_TYPE* [*MAP*]
@@ -56,7 +56,7 @@ DESCRIPTION
 		  Output will start with program ID followed by program type and
 		  zero or more named attributes (depending on kernel version).
 
-	**bpftool prog dump xlated** *PROG* [{ **file** *FILE* | **opcodes** | **visual** }]
+	**bpftool prog dump xlated** *PROG* [{ **file** *FILE* | **opcodes** | **visual** | **linum** }]
 		  Dump eBPF instructions of the program from the kernel. By
 		  default, eBPF will be disassembled and printed to standard
 		  output in human-readable format. In this case, **opcodes**
@@ -69,13 +69,21 @@ DESCRIPTION
 		  built instead, and eBPF instructions will be presented with
 		  CFG in DOT format, on standard output.
 
-	**bpftool prog dump jited**  *PROG* [{ **file** *FILE* | **opcodes** }]
+		  If the prog has line_info available, the source line will
+		  be displayed by default.  If **linum** is specified,
+		  the filename, line number and line column will also be
+		  displayed on top of the source line.
+	**bpftool prog dump jited**  *PROG* [{ **file** *FILE* | **opcodes** | **linum** }]
 		  Dump jited image (host machine code) of the program.
 		  If *FILE* is specified image will be written to a file,
 		  otherwise it will be disassembled and printed to stdout.
 
 		  **opcodes** controls if raw opcodes will be printed.
 
+		  If the prog has line_info available, the source line will
+		  be displayed by default.  If **linum** is specified,
+		  the filename, line number and line column will also be
+		  displayed on top of the source line.
 	**bpftool prog pin** *PROG* *FILE*
 		  Pin program *PROG* as *FILE*.
 
diff --git a/tools/bpf/bpftool/bash-completion/bpftool b/tools/bpf/bpftool/bash-completion/bpftool
index 44c189ba072a..a57febd6abb1 100644
--- a/tools/bpf/bpftool/bash-completion/bpftool
+++ b/tools/bpf/bpftool/bash-completion/bpftool
@@ -191,7 +191,7 @@ _bpftool()
 
     # Deal with simplest keywords
     case $prev in
-        help|hex|opcodes|visual)
+        help|hex|opcodes|visual|linum)
             return 0
             ;;
         tag)
@@ -278,10 +278,10 @@ _bpftool()
                     *)
                         _bpftool_once_attr 'file'
                         if _bpftool_search_list 'xlated'; then
-                            COMPREPLY+=( $( compgen -W 'opcodes visual' -- \
+                            COMPREPLY+=( $( compgen -W 'opcodes visual linum' -- \
                                 "$cur" ) )
                         else
-                            COMPREPLY+=( $( compgen -W 'opcodes' -- \
+                            COMPREPLY+=( $( compgen -W 'opcodes linum' -- \
                                 "$cur" ) )
                         fi
                         return 0
diff --git a/tools/bpf/bpftool/btf_dumper.c b/tools/bpf/bpftool/btf_dumper.c
index c3fd3a7cb787..dbbf6ece6760 100644
--- a/tools/bpf/bpftool/btf_dumper.c
+++ b/tools/bpf/bpftool/btf_dumper.c
@@ -385,3 +385,67 @@ void btf_dumper_type_only(const struct btf *btf, __u32 type_id, char *func_sig,
 	if (err < 0)
 		func_sig[0] = '\0';
 }
+
+static const char *ltrim(const char *s)
+{
+	while (isspace(*s))
+		s++;
+
+	return s;
+}
+
+void btf_dump_linfo_plain(const struct btf *btf,
+			  const struct bpf_line_info *linfo,
+			  const char *prefix, bool linum)
+{
+	const char *line = btf__name_by_offset(btf, linfo->line_off);
+
+	if (!line)
+		return;
+	line = ltrim(line);
+
+	if (!prefix)
+		prefix = "";
+
+	if (linum) {
+		const char *file = btf__name_by_offset(btf, linfo->file_name_off);
+
+		/* More forgiving on file because linum option is
+		 * expected to provide more info than the already
+		 * available src line.
+		 */
+		if (!file)
+			file = "";
+
+		printf("%s%s [file:%s line_num:%u line_col:%u]\n",
+		       prefix, line, file,
+		       BPF_LINE_INFO_LINE_NUM(linfo->line_col),
+		       BPF_LINE_INFO_LINE_COL(linfo->line_col));
+	} else {
+		printf("%s%s\n", prefix, line);
+	}
+}
+
+void btf_dump_linfo_json(const struct btf *btf,
+			 const struct bpf_line_info *linfo, bool linum)
+{
+	const char *line = btf__name_by_offset(btf, linfo->line_off);
+
+	if (line)
+		jsonw_string_field(json_wtr, "src", ltrim(line));
+
+	if (linum) {
+		const char *file = btf__name_by_offset(btf, linfo->file_name_off);
+
+		if (file)
+			jsonw_string_field(json_wtr, "file", file);
+
+		if (BPF_LINE_INFO_LINE_NUM(linfo->line_col))
+			jsonw_int_field(json_wtr, "line_num",
+					BPF_LINE_INFO_LINE_NUM(linfo->line_col));
+
+		if (BPF_LINE_INFO_LINE_COL(linfo->line_col))
+			jsonw_int_field(json_wtr, "line_col",
+					BPF_LINE_INFO_LINE_COL(linfo->line_col));
+	}
+}
diff --git a/tools/bpf/bpftool/jit_disasm.c b/tools/bpf/bpftool/jit_disasm.c
index 545a92471c33..f381f8628ce9 100644
--- a/tools/bpf/bpftool/jit_disasm.c
+++ b/tools/bpf/bpftool/jit_disasm.c
@@ -21,6 +21,7 @@
 #include <dis-asm.h>
 #include <sys/stat.h>
 #include <limits.h>
+#include <libbpf.h>
 
 #include "json_writer.h"
 #include "main.h"
@@ -68,10 +69,16 @@ static int fprintf_json(void *out, const char *fmt, ...)
 }
 
 void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes,
-		       const char *arch, const char *disassembler_options)
+		       const char *arch, const char *disassembler_options,
+		       const struct btf *btf,
+		       const struct bpf_prog_linfo *prog_linfo,
+		       __u64 func_ksym, unsigned int func_idx,
+		       bool linum)
 {
+	const struct bpf_line_info *linfo = NULL;
 	disassembler_ftype disassemble;
 	struct disassemble_info info;
+	unsigned int nr_skip = 0;
 	int count, i, pc = 0;
 	char tpath[PATH_MAX];
 	bfd *bfdf;
@@ -127,12 +134,26 @@ void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes,
 	if (json_output)
 		jsonw_start_array(json_wtr);
 	do {
+		if (prog_linfo) {
+			linfo = bpf_prog_linfo__lfind_addr_func(prog_linfo,
+								func_ksym + pc,
+								func_idx,
+								nr_skip);
+			if (linfo)
+				nr_skip++;
+		}
+
 		if (json_output) {
 			jsonw_start_object(json_wtr);
 			oper_count = 0;
+			if (linfo)
+				btf_dump_linfo_json(btf, linfo, linum);
 			jsonw_name(json_wtr, "pc");
 			jsonw_printf(json_wtr, "\"0x%x\"", pc);
 		} else {
+			if (linfo)
+				btf_dump_linfo_plain(btf, linfo, "; ",
+						     linum);
 			printf("%4x:\t", pc);
 		}
 
diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h
index 0be0dd8f467f..d9393abdba78 100644
--- a/tools/bpf/bpftool/main.h
+++ b/tools/bpf/bpftool/main.h
@@ -138,6 +138,9 @@ struct pinned_obj {
 	struct hlist_node hash;
 };
 
+struct btf;
+struct bpf_line_info;
+
 int build_pinned_obj_table(struct pinned_obj_table *table,
 			   enum bpf_obj_type type);
 void delete_pinned_obj_table(struct pinned_obj_table *tab);
@@ -175,13 +178,23 @@ int map_parse_fd(int *argc, char ***argv);
 int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len);
 
 #ifdef HAVE_LIBBFD_SUPPORT
+struct bpf_prog_linfo;
 void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes,
-		       const char *arch, const char *disassembler_options);
+		       const char *arch, const char *disassembler_options,
+		       const struct btf *btf,
+		       const struct bpf_prog_linfo *prog_linfo,
+		       __u64 func_ksym, unsigned int func_idx,
+		       bool linum);
 int disasm_init(void);
 #else
 static inline
 void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes,
-		       const char *arch, const char *disassembler_options)
+		       const char *arch, const char *disassembler_options,
+		       const struct btf *btf,
+		       const struct bpf_prog_linfo *prog_linfo,
+		       __u64 func_ksym, unsigned int func_idx,
+		       bool linum)
+
 {
 }
 static inline int disasm_init(void)
@@ -217,6 +230,12 @@ int btf_dumper_type(const struct btf_dumper *d, __u32 type_id,
 void btf_dumper_type_only(const struct btf *btf, __u32 func_type_id,
 			  char *func_only, int size);
 
+void btf_dump_linfo_plain(const struct btf *btf,
+			  const struct bpf_line_info *linfo,
+			  const char *prefix, bool linum);
+void btf_dump_linfo_json(const struct btf *btf,
+			 const struct bpf_line_info *linfo, bool linum);
+
 struct nlattr;
 struct ifinfomsg;
 struct tcmsg;
diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c
index a9a51123454c..65b921ffd10a 100644
--- a/tools/bpf/bpftool/prog.c
+++ b/tools/bpf/bpftool/prog.c
@@ -423,24 +423,26 @@ static int do_show(int argc, char **argv)
 
 static int do_dump(int argc, char **argv)
 {
+	unsigned int finfo_rec_size, linfo_rec_size, jited_linfo_rec_size;
+	void *func_info = NULL, *linfo = NULL, *jited_linfo = NULL;
+	unsigned int finfo_cnt, linfo_cnt = 0, jited_linfo_cnt = 0;
+	struct bpf_prog_linfo *prog_linfo = NULL;
 	unsigned long *func_ksyms = NULL;
 	struct bpf_prog_info info = {};
 	unsigned int *func_lens = NULL;
 	const char *disasm_opt = NULL;
-	unsigned int finfo_rec_size;
 	unsigned int nr_func_ksyms;
 	unsigned int nr_func_lens;
 	struct dump_data dd = {};
 	__u32 len = sizeof(info);
 	struct btf *btf = NULL;
-	void *func_info = NULL;
-	unsigned int finfo_cnt;
 	unsigned int buf_size;
 	char *filepath = NULL;
 	bool opcodes = false;
 	bool visual = false;
 	char func_sig[1024];
 	unsigned char *buf;
+	bool linum = false;
 	__u32 *member_len;
 	__u64 *member_ptr;
 	ssize_t n;
@@ -484,6 +486,9 @@ static int do_dump(int argc, char **argv)
 	} else if (is_prefix(*argv, "visual")) {
 		visual = true;
 		NEXT_ARG();
+	} else if (is_prefix(*argv, "linum")) {
+		linum = true;
+		NEXT_ARG();
 	}
 
 	if (argc) {
@@ -543,6 +548,32 @@ static int do_dump(int argc, char **argv)
 		}
 	}
 
+	linfo_rec_size = info.line_info_rec_size;
+	if (info.line_info_cnt && linfo_rec_size && info.btf_id) {
+		linfo_cnt = info.line_info_cnt;
+		linfo = malloc(linfo_cnt * linfo_rec_size);
+		if (!linfo) {
+			p_err("mem alloc failed");
+			close(fd);
+			goto err_free;
+		}
+	}
+
+	jited_linfo_rec_size = info.jited_line_info_rec_size;
+	if (info.jited_line_info_cnt &&
+	    jited_linfo_rec_size &&
+	    info.nr_jited_ksyms &&
+	    info.nr_jited_func_lens &&
+	    info.btf_id) {
+		jited_linfo_cnt = info.jited_line_info_cnt;
+		jited_linfo = malloc(jited_linfo_cnt * jited_linfo_rec_size);
+		if (!jited_linfo) {
+			p_err("mem alloc failed");
+			close(fd);
+			goto err_free;
+		}
+	}
+
 	memset(&info, 0, sizeof(info));
 
 	*member_ptr = ptr_to_u64(buf);
@@ -554,6 +585,13 @@ static int do_dump(int argc, char **argv)
 	info.func_info_cnt = finfo_cnt;
 	info.func_info_rec_size = finfo_rec_size;
 	info.func_info = ptr_to_u64(func_info);
+	info.line_info_cnt = linfo_cnt;
+	info.line_info_rec_size = linfo_rec_size;
+	info.line_info = ptr_to_u64(linfo);
+	info.jited_line_info_cnt = jited_linfo_cnt;
+	info.jited_line_info_rec_size = jited_linfo_rec_size;
+	info.jited_line_info = ptr_to_u64(jited_linfo);
+
 
 	err = bpf_obj_get_info_by_fd(fd, &info, &len);
 	close(fd);
@@ -596,6 +634,30 @@ static int do_dump(int argc, char **argv)
 		finfo_cnt = 0;
 	}
 
+	if (linfo && info.line_info_cnt != linfo_cnt) {
+		p_err("incorrect line_info_cnt %u vs. expected %u",
+		      info.line_info_cnt, linfo_cnt);
+		goto err_free;
+	}
+
+	if (info.line_info_rec_size != linfo_rec_size) {
+		p_err("incorrect line_info_rec_size %u vs. expected %u",
+		      info.line_info_rec_size, linfo_rec_size);
+		goto err_free;
+	}
+
+	if (jited_linfo && info.jited_line_info_cnt != jited_linfo_cnt) {
+		p_err("incorrect jited_line_info_cnt %u vs. expected %u",
+		      info.jited_line_info_cnt, jited_linfo_cnt);
+		goto err_free;
+	}
+
+	if (info.jited_line_info_rec_size != jited_linfo_rec_size) {
+		p_err("incorrect jited_line_info_rec_size %u vs. expected %u",
+		      info.jited_line_info_rec_size, jited_linfo_rec_size);
+		goto err_free;
+	}
+
 	if ((member_len == &info.jited_prog_len &&
 	     info.jited_prog_insns == 0) ||
 	    (member_len == &info.xlated_prog_len &&
@@ -609,6 +671,12 @@ static int do_dump(int argc, char **argv)
 		goto err_free;
 	}
 
+	if (linfo_cnt) {
+		prog_linfo = bpf_prog_linfo__new(&info);
+		if (!prog_linfo)
+			p_err("error in processing bpf_line_info.  continue without it.");
+	}
+
 	if (filepath) {
 		fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0600);
 		if (fd < 0) {
@@ -690,8 +758,11 @@ static int do_dump(int argc, char **argv)
 					printf("%s:\n", sym_name);
 				}
 
-				disasm_print_insn(img, lens[i], opcodes, name,
-						  disasm_opt);
+				disasm_print_insn(img, lens[i], opcodes,
+						  name, disasm_opt, btf,
+						  prog_linfo, ksyms[i], i,
+						  linum);
+
 				img += lens[i];
 
 				if (json_output)
@@ -704,7 +775,7 @@ static int do_dump(int argc, char **argv)
 				jsonw_end_array(json_wtr);
 		} else {
 			disasm_print_insn(buf, *member_len, opcodes, name,
-					  disasm_opt);
+					  disasm_opt, btf, NULL, 0, 0, false);
 		}
 	} else if (visual) {
 		if (json_output)
@@ -718,11 +789,14 @@ static int do_dump(int argc, char **argv)
 		dd.btf = btf;
 		dd.func_info = func_info;
 		dd.finfo_rec_size = finfo_rec_size;
+		dd.prog_linfo = prog_linfo;
 
 		if (json_output)
-			dump_xlated_json(&dd, buf, *member_len, opcodes);
+			dump_xlated_json(&dd, buf, *member_len, opcodes,
+					 linum);
 		else
-			dump_xlated_plain(&dd, buf, *member_len, opcodes);
+			dump_xlated_plain(&dd, buf, *member_len, opcodes,
+					  linum);
 		kernel_syms_destroy(&dd);
 	}
 
@@ -730,6 +804,9 @@ static int do_dump(int argc, char **argv)
 	free(func_ksyms);
 	free(func_lens);
 	free(func_info);
+	free(linfo);
+	free(jited_linfo);
+	bpf_prog_linfo__free(prog_linfo);
 	return 0;
 
 err_free:
@@ -737,6 +814,9 @@ static int do_dump(int argc, char **argv)
 	free(func_ksyms);
 	free(func_lens);
 	free(func_info);
+	free(linfo);
+	free(jited_linfo);
+	bpf_prog_linfo__free(prog_linfo);
 	return -1;
 }
 
@@ -1138,8 +1218,8 @@ static int do_help(int argc, char **argv)
 
 	fprintf(stderr,
 		"Usage: %s %s { show | list } [PROG]\n"
-		"       %s %s dump xlated PROG [{ file FILE | opcodes | visual }]\n"
-		"       %s %s dump jited  PROG [{ file FILE | opcodes }]\n"
+		"       %s %s dump xlated PROG [{ file FILE | opcodes | visual | linum }]\n"
+		"       %s %s dump jited  PROG [{ file FILE | opcodes | linum }]\n"
 		"       %s %s pin   PROG FILE\n"
 		"       %s %s { load | loadall } OBJ  PATH \\\n"
 		"                         [type TYPE] [dev NAME] \\\n"
diff --git a/tools/bpf/bpftool/xlated_dumper.c b/tools/bpf/bpftool/xlated_dumper.c
index 131ecd175533..aef628dcccb6 100644
--- a/tools/bpf/bpftool/xlated_dumper.c
+++ b/tools/bpf/bpftool/xlated_dumper.c
@@ -41,6 +41,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/types.h>
+#include <libbpf.h>
 
 #include "disasm.h"
 #include "json_writer.h"
@@ -234,8 +235,9 @@ static const char *print_imm(void *private_data,
 }
 
 void dump_xlated_json(struct dump_data *dd, void *buf, unsigned int len,
-		      bool opcodes)
+		      bool opcodes, bool linum)
 {
+	const struct bpf_prog_linfo *prog_linfo = dd->prog_linfo;
 	const struct bpf_insn_cbs cbs = {
 		.cb_print	= print_insn_json,
 		.cb_call	= print_call,
@@ -246,6 +248,7 @@ void dump_xlated_json(struct dump_data *dd, void *buf, unsigned int len,
 	struct bpf_insn *insn = buf;
 	struct btf *btf = dd->btf;
 	bool double_insn = false;
+	unsigned int nr_skip = 0;
 	char func_sig[1024];
 	unsigned int i;
 
@@ -273,6 +276,16 @@ void dump_xlated_json(struct dump_data *dd, void *buf, unsigned int len,
 			}
 		}
 
+		if (prog_linfo) {
+			const struct bpf_line_info *linfo;
+
+			linfo = bpf_prog_linfo__lfind(prog_linfo, i, nr_skip);
+			if (linfo) {
+				btf_dump_linfo_json(btf, linfo, linum);
+				nr_skip++;
+			}
+		}
+
 		jsonw_name(json_wtr, "disasm");
 		print_bpf_insn(&cbs, insn + i, true);
 
@@ -307,8 +320,9 @@ void dump_xlated_json(struct dump_data *dd, void *buf, unsigned int len,
 }
 
 void dump_xlated_plain(struct dump_data *dd, void *buf, unsigned int len,
-		       bool opcodes)
+		       bool opcodes, bool linum)
 {
+	const struct bpf_prog_linfo *prog_linfo = dd->prog_linfo;
 	const struct bpf_insn_cbs cbs = {
 		.cb_print	= print_insn,
 		.cb_call	= print_call,
@@ -318,6 +332,7 @@ void dump_xlated_plain(struct dump_data *dd, void *buf, unsigned int len,
 	struct bpf_func_info *record;
 	struct bpf_insn *insn = buf;
 	struct btf *btf = dd->btf;
+	unsigned int nr_skip = 0;
 	bool double_insn = false;
 	char func_sig[1024];
 	unsigned int i;
@@ -340,6 +355,17 @@ void dump_xlated_plain(struct dump_data *dd, void *buf, unsigned int len,
 			}
 		}
 
+		if (prog_linfo) {
+			const struct bpf_line_info *linfo;
+
+			linfo = bpf_prog_linfo__lfind(prog_linfo, i, nr_skip);
+			if (linfo) {
+				btf_dump_linfo_plain(btf, linfo, "; ",
+						     linum);
+				nr_skip++;
+			}
+		}
+
 		double_insn = insn[i].code == (BPF_LD | BPF_IMM | BPF_DW);
 
 		printf("% 4d: ", i);
diff --git a/tools/bpf/bpftool/xlated_dumper.h b/tools/bpf/bpftool/xlated_dumper.h
index aec31723e1e5..a24f89df8cb2 100644
--- a/tools/bpf/bpftool/xlated_dumper.h
+++ b/tools/bpf/bpftool/xlated_dumper.h
@@ -40,6 +40,8 @@
 
 #define SYM_MAX_NAME	256
 
+struct bpf_prog_linfo;
+
 struct kernel_sym {
 	unsigned long address;
 	char name[SYM_MAX_NAME];
@@ -54,6 +56,7 @@ struct dump_data {
 	struct btf *btf;
 	void *func_info;
 	__u32 finfo_rec_size;
+	const struct bpf_prog_linfo *prog_linfo;
 	char scratch_buff[SYM_MAX_NAME + 8];
 };
 
@@ -61,9 +64,9 @@ void kernel_syms_load(struct dump_data *dd);
 void kernel_syms_destroy(struct dump_data *dd);
 struct kernel_sym *kernel_syms_search(struct dump_data *dd, unsigned long key);
 void dump_xlated_json(struct dump_data *dd, void *buf, unsigned int len,
-		      bool opcodes);
+		       bool opcodes, bool linum);
 void dump_xlated_plain(struct dump_data *dd, void *buf, unsigned int len,
-		       bool opcodes);
+		       bool opcodes, bool linum);
 void dump_xlated_for_graph(struct dump_data *dd, void *buf, void *buf_end,
 			   unsigned int start_index);
 
diff --git a/tools/lib/bpf/Build b/tools/lib/bpf/Build
index 7bc31c905018..197b40f5b5c6 100644
--- a/tools/lib/bpf/Build
+++ b/tools/lib/bpf/Build
@@ -1 +1 @@
-libbpf-y := libbpf.o bpf.o nlattr.o btf.o libbpf_errno.o str_error.o netlink.o
+libbpf-y := libbpf.o bpf.o nlattr.o btf.o libbpf_errno.o str_error.o netlink.o bpf_prog_linfo.o
diff --git a/tools/lib/bpf/bpf_prog_linfo.c b/tools/lib/bpf/bpf_prog_linfo.c
new file mode 100644
index 000000000000..b8af65145408
--- /dev/null
+++ b/tools/lib/bpf/bpf_prog_linfo.c
@@ -0,0 +1,253 @@
+// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
+/* Copyright (c) 2018 Facebook */
+
+#include <string.h>
+#include <stdlib.h>
+#include <linux/err.h>
+#include <linux/bpf.h>
+#include "libbpf.h"
+
+#ifndef min
+#define min(x, y) ((x) < (y) ? (x) : (y))
+#endif
+
+struct bpf_prog_linfo {
+	void *raw_linfo;
+	void *raw_jited_linfo;
+	__u32 *nr_jited_linfo_per_func;
+	__u32 *jited_linfo_func_idx;
+	__u32 nr_linfo;
+	__u32 nr_jited_func;
+	__u32 rec_size;
+	__u32 jited_rec_size;
+};
+
+static int dissect_jited_func(struct bpf_prog_linfo *prog_linfo,
+			      const __u64 *ksym_func, const __u32 *ksym_len)
+{
+	__u32 nr_jited_func, nr_linfo;
+	const void *raw_jited_linfo;
+	const __u64 *jited_linfo;
+	__u64 last_jited_linfo;
+	/*
+	 * Index to raw_jited_linfo:
+	 *      i: Index for searching the next ksym_func
+	 * prev_i: Index to the last found ksym_func
+	 */
+	__u32 i, prev_i;
+	__u32 f; /* Index to ksym_func */
+
+	raw_jited_linfo = prog_linfo->raw_jited_linfo;
+	jited_linfo = raw_jited_linfo;
+	if (ksym_func[0] != *jited_linfo)
+		goto errout;
+
+	prog_linfo->jited_linfo_func_idx[0] = 0;
+	nr_jited_func = prog_linfo->nr_jited_func;
+	nr_linfo = prog_linfo->nr_linfo;
+
+	for (prev_i = 0, i = 1, f = 1;
+	     i < nr_linfo && f < nr_jited_func;
+	     i++) {
+		raw_jited_linfo += prog_linfo->jited_rec_size;
+		last_jited_linfo = *jited_linfo;
+		jited_linfo = raw_jited_linfo;
+
+		if (ksym_func[f] == *jited_linfo) {
+			prog_linfo->jited_linfo_func_idx[f] = i;
+
+			/* Sanity check */
+			if (last_jited_linfo - ksym_func[f - 1] + 1 >
+			    ksym_len[f - 1])
+				goto errout;
+
+			prog_linfo->nr_jited_linfo_per_func[f - 1] =
+				i - prev_i;
+			prev_i = i;
+
+			/*
+			 * The ksym_func[f] is found in jited_linfo.
+			 * Look for the next one.
+			 */
+			f++;
+		} else if (*jited_linfo <= last_jited_linfo) {
+			/* Ensure the addr is increasing _within_ a func */
+			goto errout;
+		}
+	}
+
+	if (f != nr_jited_func)
+		goto errout;
+
+	prog_linfo->nr_jited_linfo_per_func[nr_jited_func - 1] =
+		nr_linfo - prev_i;
+
+	return 0;
+
+errout:
+	return -EINVAL;
+}
+
+void bpf_prog_linfo__free(struct bpf_prog_linfo *prog_linfo)
+{
+	if (!prog_linfo)
+		return;
+
+	free(prog_linfo->raw_linfo);
+	free(prog_linfo->raw_jited_linfo);
+	free(prog_linfo->nr_jited_linfo_per_func);
+	free(prog_linfo->jited_linfo_func_idx);
+	free(prog_linfo);
+}
+
+struct bpf_prog_linfo *bpf_prog_linfo__new(const struct bpf_prog_info *info)
+{
+	struct bpf_prog_linfo *prog_linfo;
+	__u32 nr_linfo, nr_jited_func;
+
+	nr_linfo = info->line_info_cnt;
+
+	/*
+	 * Test !info->line_info because the kernel may NULL
+	 * the ptr if kernel.kptr_restrict is set.
+	 */
+	if (!nr_linfo || !info->line_info)
+		return NULL;
+
+	/*
+	 * The min size that bpf_prog_linfo has to access for
+	 * searching purpose.
+	 */
+	if (info->line_info_rec_size <
+	    offsetof(struct bpf_line_info, file_name_off))
+		return NULL;
+
+	prog_linfo = calloc(1, sizeof(*prog_linfo));
+	if (!prog_linfo)
+		return NULL;
+
+	/* Copy xlated line_info */
+	prog_linfo->nr_linfo = nr_linfo;
+	prog_linfo->rec_size = info->line_info_rec_size;
+	prog_linfo->raw_linfo = malloc(nr_linfo * prog_linfo->rec_size);
+	if (!prog_linfo->raw_linfo)
+		goto err_free;
+	memcpy(prog_linfo->raw_linfo, (void *)(long)info->line_info,
+	       nr_linfo * prog_linfo->rec_size);
+
+	nr_jited_func = info->nr_jited_ksyms;
+	if (!nr_jited_func ||
+	    !info->jited_line_info ||
+	    info->jited_line_info_cnt != nr_linfo ||
+	    info->jited_line_info_rec_size < sizeof(__u64) ||
+	    info->nr_jited_func_lens != nr_jited_func ||
+	    !info->jited_ksyms ||
+	    !info->jited_func_lens)
+		/* Not enough info to provide jited_line_info */
+		return prog_linfo;
+
+	/* Copy jited_line_info */
+	prog_linfo->nr_jited_func = nr_jited_func;
+	prog_linfo->jited_rec_size = info->jited_line_info_rec_size;
+	prog_linfo->raw_jited_linfo = malloc(nr_linfo *
+					     prog_linfo->jited_rec_size);
+	if (!prog_linfo->raw_jited_linfo)
+		goto err_free;
+	memcpy(prog_linfo->raw_jited_linfo,
+	       (void *)(long)info->jited_line_info,
+	       nr_linfo * prog_linfo->jited_rec_size);
+
+	/* Number of jited_line_info per jited func */
+	prog_linfo->nr_jited_linfo_per_func = malloc(nr_jited_func *
+						     sizeof(__u32));
+	if (!prog_linfo->nr_jited_linfo_per_func)
+		goto err_free;
+
+	/*
+	 * For each jited func,
+	 * the start idx to the "linfo" and "jited_linfo" array,
+	 */
+	prog_linfo->jited_linfo_func_idx = malloc(nr_jited_func *
+						  sizeof(__u32));
+	if (!prog_linfo->jited_linfo_func_idx)
+		goto err_free;
+
+	if (dissect_jited_func(prog_linfo,
+			       (__u64 *)(long)info->jited_ksyms,
+			       (__u32 *)(long)info->jited_func_lens))
+		goto err_free;
+
+	return prog_linfo;
+
+err_free:
+	bpf_prog_linfo__free(prog_linfo);
+	return NULL;
+}
+
+const struct bpf_line_info *
+bpf_prog_linfo__lfind_addr_func(const struct bpf_prog_linfo *prog_linfo,
+				__u64 addr, __u32 func_idx, __u32 nr_skip)
+{
+	__u32 jited_rec_size, rec_size, nr_linfo, start, i;
+	const void *raw_jited_linfo, *raw_linfo;
+	const __u64 *jited_linfo;
+
+	if (func_idx >= prog_linfo->nr_jited_func)
+		return NULL;
+
+	nr_linfo = prog_linfo->nr_jited_linfo_per_func[func_idx];
+	if (nr_skip >= nr_linfo)
+		return NULL;
+
+	start = prog_linfo->jited_linfo_func_idx[func_idx] + nr_skip;
+	jited_rec_size = prog_linfo->jited_rec_size;
+	raw_jited_linfo = prog_linfo->raw_jited_linfo +
+		(start * jited_rec_size);
+	jited_linfo = raw_jited_linfo;
+	if (addr < *jited_linfo)
+		return NULL;
+
+	nr_linfo -= nr_skip;
+	rec_size = prog_linfo->rec_size;
+	raw_linfo = prog_linfo->raw_linfo + (start * rec_size);
+	for (i = 0; i < nr_linfo; i++) {
+		if (addr < *jited_linfo)
+			break;
+
+		raw_linfo += rec_size;
+		raw_jited_linfo += jited_rec_size;
+		jited_linfo = raw_jited_linfo;
+	}
+
+	return raw_linfo - rec_size;
+}
+
+const struct bpf_line_info *
+bpf_prog_linfo__lfind(const struct bpf_prog_linfo *prog_linfo,
+		      __u32 insn_off, __u32 nr_skip)
+{
+	const struct bpf_line_info *linfo;
+	__u32 rec_size, nr_linfo, i;
+	const void *raw_linfo;
+
+	nr_linfo = prog_linfo->nr_linfo;
+	if (nr_skip >= nr_linfo)
+		return NULL;
+
+	rec_size = prog_linfo->rec_size;
+	raw_linfo = prog_linfo->raw_linfo + (nr_skip * rec_size);
+	linfo = raw_linfo;
+	if (insn_off < linfo->insn_off)
+		return NULL;
+
+	nr_linfo -= nr_skip;
+	for (i = 0; i < nr_linfo; i++) {
+		if (insn_off < linfo->insn_off)
+			break;
+
+		raw_linfo += rec_size;
+		linfo = raw_linfo;
+	}
+
+	return raw_linfo - rec_size;
+}
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index f30c3d07bb7d..5f68d7b75215 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -342,6 +342,19 @@ int libbpf_nl_get_qdisc(int sock, unsigned int nl_pid, int ifindex,
 int libbpf_nl_get_filter(int sock, unsigned int nl_pid, int ifindex, int handle,
 			 libbpf_dump_nlmsg_t dump_filter_nlmsg, void *cookie);
 
+struct bpf_prog_linfo;
+struct bpf_prog_info;
+
+LIBBPF_API void bpf_prog_linfo__free(struct bpf_prog_linfo *prog_linfo);
+LIBBPF_API struct bpf_prog_linfo *
+bpf_prog_linfo__new(const struct bpf_prog_info *info);
+LIBBPF_API const struct bpf_line_info *
+bpf_prog_linfo__lfind_addr_func(const struct bpf_prog_linfo *prog_linfo,
+				__u64 addr, __u32 func_idx, __u32 nr_skip);
+LIBBPF_API const struct bpf_line_info *
+bpf_prog_linfo__lfind(const struct bpf_prog_linfo *prog_linfo,
+		      __u32 insn_off, __u32 nr_skip);
+
 #ifdef __cplusplus
 } /* extern "C" */
 #endif
diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map
index 8deff22d61bb..cd02cd4e2cc3 100644
--- a/tools/lib/bpf/libbpf.map
+++ b/tools/lib/bpf/libbpf.map
@@ -99,6 +99,10 @@ LIBBPF_0.0.1 {
 		bpf_program__unload;
 		bpf_program__unpin;
 		bpf_program__unpin_instance;
+		bpf_prog_linfo__free;
+		bpf_prog_linfo__new;
+		bpf_prog_linfo__lfind_addr_func;
+		bpf_prog_linfo__lfind;
 		bpf_raw_tracepoint_open;
 		bpf_set_link_xdp_fd;
 		bpf_task_fd_query;
-- 
2.17.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ