Commit b053b439 authored by Martin KaFai Lau's avatar Martin KaFai Lau Committed by Alexei Starovoitov

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@arch-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@arch-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: default avatarMartin KaFai Lau <kafai@fb.com>
Acked-by: default avatarYonghong Song <yhs@fb.com>
Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parent 3d650141
...@@ -22,8 +22,8 @@ MAP COMMANDS ...@@ -22,8 +22,8 @@ MAP COMMANDS
============= =============
| **bpftool** **prog { show | list }** [*PROG*] | **bpftool** **prog { show | list }** [*PROG*]
| **bpftool** **prog dump xlated** *PROG* [{**file** *FILE* | **opcodes** | **visual**}] | **bpftool** **prog dump xlated** *PROG* [{**file** *FILE* | **opcodes** | **visual** | **linum**}]
| **bpftool** **prog dump jited** *PROG* [{**file** *FILE* | **opcodes**}] | **bpftool** **prog dump jited** *PROG* [{**file** *FILE* | **opcodes** | **linum**}]
| **bpftool** **prog pin** *PROG* *FILE* | **bpftool** **prog pin** *PROG* *FILE*
| **bpftool** **prog { load | loadall }** *OBJ* *PATH* [**type** *TYPE*] [**map** {**idx** *IDX* | **name** *NAME*} *MAP*] [**dev** *NAME*] | **bpftool** **prog { load | loadall }** *OBJ* *PATH* [**type** *TYPE*] [**map** {**idx** *IDX* | **name** *NAME*} *MAP*] [**dev** *NAME*]
| **bpftool** **prog attach** *PROG* *ATTACH_TYPE* [*MAP*] | **bpftool** **prog attach** *PROG* *ATTACH_TYPE* [*MAP*]
...@@ -56,7 +56,7 @@ DESCRIPTION ...@@ -56,7 +56,7 @@ DESCRIPTION
Output will start with program ID followed by program type and Output will start with program ID followed by program type and
zero or more named attributes (depending on kernel version). 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 Dump eBPF instructions of the program from the kernel. By
default, eBPF will be disassembled and printed to standard default, eBPF will be disassembled and printed to standard
output in human-readable format. In this case, **opcodes** output in human-readable format. In this case, **opcodes**
...@@ -69,13 +69,21 @@ DESCRIPTION ...@@ -69,13 +69,21 @@ DESCRIPTION
built instead, and eBPF instructions will be presented with built instead, and eBPF instructions will be presented with
CFG in DOT format, on standard output. 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. Dump jited image (host machine code) of the program.
If *FILE* is specified image will be written to a file, If *FILE* is specified image will be written to a file,
otherwise it will be disassembled and printed to stdout. otherwise it will be disassembled and printed to stdout.
**opcodes** controls if raw opcodes will be printed. **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* **bpftool prog pin** *PROG* *FILE*
Pin program *PROG* as *FILE*. Pin program *PROG* as *FILE*.
......
...@@ -191,7 +191,7 @@ _bpftool() ...@@ -191,7 +191,7 @@ _bpftool()
# Deal with simplest keywords # Deal with simplest keywords
case $prev in case $prev in
help|hex|opcodes|visual) help|hex|opcodes|visual|linum)
return 0 return 0
;; ;;
tag) tag)
...@@ -278,10 +278,10 @@ _bpftool() ...@@ -278,10 +278,10 @@ _bpftool()
*) *)
_bpftool_once_attr 'file' _bpftool_once_attr 'file'
if _bpftool_search_list 'xlated'; then if _bpftool_search_list 'xlated'; then
COMPREPLY+=( $( compgen -W 'opcodes visual' -- \ COMPREPLY+=( $( compgen -W 'opcodes visual linum' -- \
"$cur" ) ) "$cur" ) )
else else
COMPREPLY+=( $( compgen -W 'opcodes' -- \ COMPREPLY+=( $( compgen -W 'opcodes linum' -- \
"$cur" ) ) "$cur" ) )
fi fi
return 0 return 0
......
...@@ -385,3 +385,67 @@ void btf_dumper_type_only(const struct btf *btf, __u32 type_id, char *func_sig, ...@@ -385,3 +385,67 @@ void btf_dumper_type_only(const struct btf *btf, __u32 type_id, char *func_sig,
if (err < 0) if (err < 0)
func_sig[0] = '\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));
}
}
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <dis-asm.h> #include <dis-asm.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <limits.h> #include <limits.h>
#include <libbpf.h>
#include "json_writer.h" #include "json_writer.h"
#include "main.h" #include "main.h"
...@@ -68,10 +69,16 @@ static int fprintf_json(void *out, const char *fmt, ...) ...@@ -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, 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; disassembler_ftype disassemble;
struct disassemble_info info; struct disassemble_info info;
unsigned int nr_skip = 0;
int count, i, pc = 0; int count, i, pc = 0;
char tpath[PATH_MAX]; char tpath[PATH_MAX];
bfd *bfdf; bfd *bfdf;
...@@ -127,12 +134,26 @@ void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes, ...@@ -127,12 +134,26 @@ void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes,
if (json_output) if (json_output)
jsonw_start_array(json_wtr); jsonw_start_array(json_wtr);
do { 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) { if (json_output) {
jsonw_start_object(json_wtr); jsonw_start_object(json_wtr);
oper_count = 0; oper_count = 0;
if (linfo)
btf_dump_linfo_json(btf, linfo, linum);
jsonw_name(json_wtr, "pc"); jsonw_name(json_wtr, "pc");
jsonw_printf(json_wtr, "\"0x%x\"", pc); jsonw_printf(json_wtr, "\"0x%x\"", pc);
} else { } else {
if (linfo)
btf_dump_linfo_plain(btf, linfo, "; ",
linum);
printf("%4x:\t", pc); printf("%4x:\t", pc);
} }
......
...@@ -138,6 +138,9 @@ struct pinned_obj { ...@@ -138,6 +138,9 @@ struct pinned_obj {
struct hlist_node hash; struct hlist_node hash;
}; };
struct btf;
struct bpf_line_info;
int build_pinned_obj_table(struct pinned_obj_table *table, int build_pinned_obj_table(struct pinned_obj_table *table,
enum bpf_obj_type type); enum bpf_obj_type type);
void delete_pinned_obj_table(struct pinned_obj_table *tab); void delete_pinned_obj_table(struct pinned_obj_table *tab);
...@@ -175,13 +178,23 @@ int map_parse_fd(int *argc, char ***argv); ...@@ -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); int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len);
#ifdef HAVE_LIBBFD_SUPPORT #ifdef HAVE_LIBBFD_SUPPORT
struct bpf_prog_linfo;
void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes, 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); int disasm_init(void);
#else #else
static inline static inline
void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes, 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) static inline int disasm_init(void)
...@@ -217,6 +230,12 @@ int btf_dumper_type(const struct btf_dumper *d, __u32 type_id, ...@@ -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, void btf_dumper_type_only(const struct btf *btf, __u32 func_type_id,
char *func_only, int size); 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 nlattr;
struct ifinfomsg; struct ifinfomsg;
struct tcmsg; struct tcmsg;
......
...@@ -423,24 +423,26 @@ static int do_show(int argc, char **argv) ...@@ -423,24 +423,26 @@ static int do_show(int argc, char **argv)
static int do_dump(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; unsigned long *func_ksyms = NULL;
struct bpf_prog_info info = {}; struct bpf_prog_info info = {};
unsigned int *func_lens = NULL; unsigned int *func_lens = NULL;
const char *disasm_opt = NULL; const char *disasm_opt = NULL;
unsigned int finfo_rec_size;
unsigned int nr_func_ksyms; unsigned int nr_func_ksyms;
unsigned int nr_func_lens; unsigned int nr_func_lens;
struct dump_data dd = {}; struct dump_data dd = {};
__u32 len = sizeof(info); __u32 len = sizeof(info);
struct btf *btf = NULL; struct btf *btf = NULL;
void *func_info = NULL;
unsigned int finfo_cnt;
unsigned int buf_size; unsigned int buf_size;
char *filepath = NULL; char *filepath = NULL;
bool opcodes = false; bool opcodes = false;
bool visual = false; bool visual = false;
char func_sig[1024]; char func_sig[1024];
unsigned char *buf; unsigned char *buf;
bool linum = false;
__u32 *member_len; __u32 *member_len;
__u64 *member_ptr; __u64 *member_ptr;
ssize_t n; ssize_t n;
...@@ -484,6 +486,9 @@ static int do_dump(int argc, char **argv) ...@@ -484,6 +486,9 @@ static int do_dump(int argc, char **argv)
} else if (is_prefix(*argv, "visual")) { } else if (is_prefix(*argv, "visual")) {
visual = true; visual = true;
NEXT_ARG(); NEXT_ARG();
} else if (is_prefix(*argv, "linum")) {
linum = true;
NEXT_ARG();
} }
if (argc) { if (argc) {
...@@ -543,6 +548,32 @@ static int do_dump(int argc, char **argv) ...@@ -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)); memset(&info, 0, sizeof(info));
*member_ptr = ptr_to_u64(buf); *member_ptr = ptr_to_u64(buf);
...@@ -554,6 +585,13 @@ static int do_dump(int argc, char **argv) ...@@ -554,6 +585,13 @@ static int do_dump(int argc, char **argv)
info.func_info_cnt = finfo_cnt; info.func_info_cnt = finfo_cnt;
info.func_info_rec_size = finfo_rec_size; info.func_info_rec_size = finfo_rec_size;
info.func_info = ptr_to_u64(func_info); 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); err = bpf_obj_get_info_by_fd(fd, &info, &len);
close(fd); close(fd);
...@@ -596,6 +634,30 @@ static int do_dump(int argc, char **argv) ...@@ -596,6 +634,30 @@ static int do_dump(int argc, char **argv)
finfo_cnt = 0; 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 && if ((member_len == &info.jited_prog_len &&
info.jited_prog_insns == 0) || info.jited_prog_insns == 0) ||
(member_len == &info.xlated_prog_len && (member_len == &info.xlated_prog_len &&
...@@ -609,6 +671,12 @@ static int do_dump(int argc, char **argv) ...@@ -609,6 +671,12 @@ static int do_dump(int argc, char **argv)
goto err_free; 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) { if (filepath) {
fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0600); fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0600);
if (fd < 0) { if (fd < 0) {
...@@ -690,8 +758,11 @@ static int do_dump(int argc, char **argv) ...@@ -690,8 +758,11 @@ static int do_dump(int argc, char **argv)
printf("%s:\n", sym_name); printf("%s:\n", sym_name);
} }
disasm_print_insn(img, lens[i], opcodes, name, disasm_print_insn(img, lens[i], opcodes,
disasm_opt); name, disasm_opt, btf,
prog_linfo, ksyms[i], i,
linum);
img += lens[i]; img += lens[i];
if (json_output) if (json_output)
...@@ -704,7 +775,7 @@ static int do_dump(int argc, char **argv) ...@@ -704,7 +775,7 @@ static int do_dump(int argc, char **argv)
jsonw_end_array(json_wtr); jsonw_end_array(json_wtr);
} else { } else {
disasm_print_insn(buf, *member_len, opcodes, name, disasm_print_insn(buf, *member_len, opcodes, name,
disasm_opt); disasm_opt, btf, NULL, 0, 0, false);
} }
} else if (visual) { } else if (visual) {
if (json_output) if (json_output)
...@@ -718,11 +789,14 @@ static int do_dump(int argc, char **argv) ...@@ -718,11 +789,14 @@ static int do_dump(int argc, char **argv)
dd.btf = btf; dd.btf = btf;
dd.func_info = func_info; dd.func_info = func_info;
dd.finfo_rec_size = finfo_rec_size; dd.finfo_rec_size = finfo_rec_size;
dd.prog_linfo = prog_linfo;
if (json_output) if (json_output)
dump_xlated_json(&dd, buf, *member_len, opcodes); dump_xlated_json(&dd, buf, *member_len, opcodes,
linum);
else else
dump_xlated_plain(&dd, buf, *member_len, opcodes); dump_xlated_plain(&dd, buf, *member_len, opcodes,
linum);
kernel_syms_destroy(&dd); kernel_syms_destroy(&dd);
} }
...@@ -730,6 +804,9 @@ static int do_dump(int argc, char **argv) ...@@ -730,6 +804,9 @@ static int do_dump(int argc, char **argv)
free(func_ksyms); free(func_ksyms);
free(func_lens); free(func_lens);
free(func_info); free(func_info);
free(linfo);
free(jited_linfo);
bpf_prog_linfo__free(prog_linfo);
return 0; return 0;
err_free: err_free:
...@@ -737,6 +814,9 @@ static int do_dump(int argc, char **argv) ...@@ -737,6 +814,9 @@ static int do_dump(int argc, char **argv)
free(func_ksyms); free(func_ksyms);
free(func_lens); free(func_lens);
free(func_info); free(func_info);
free(linfo);
free(jited_linfo);
bpf_prog_linfo__free(prog_linfo);
return -1; return -1;
} }
...@@ -1138,8 +1218,8 @@ static int do_help(int argc, char **argv) ...@@ -1138,8 +1218,8 @@ static int do_help(int argc, char **argv)
fprintf(stderr, fprintf(stderr,
"Usage: %s %s { show | list } [PROG]\n" "Usage: %s %s { show | list } [PROG]\n"
" %s %s dump xlated PROG [{ file FILE | opcodes | visual }]\n" " %s %s dump xlated PROG [{ file FILE | opcodes | visual | linum }]\n"
" %s %s dump jited PROG [{ file FILE | opcodes }]\n" " %s %s dump jited PROG [{ file FILE | opcodes | linum }]\n"
" %s %s pin PROG FILE\n" " %s %s pin PROG FILE\n"
" %s %s { load | loadall } OBJ PATH \\\n" " %s %s { load | loadall } OBJ PATH \\\n"
" [type TYPE] [dev NAME] \\\n" " [type TYPE] [dev NAME] \\\n"
......
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/types.h> #include <sys/types.h>
#include <libbpf.h>
#include "disasm.h" #include "disasm.h"
#include "json_writer.h" #include "json_writer.h"
...@@ -234,8 +235,9 @@ static const char *print_imm(void *private_data, ...@@ -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, 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 = { const struct bpf_insn_cbs cbs = {
.cb_print = print_insn_json, .cb_print = print_insn_json,
.cb_call = print_call, .cb_call = print_call,
...@@ -246,6 +248,7 @@ void dump_xlated_json(struct dump_data *dd, void *buf, unsigned int len, ...@@ -246,6 +248,7 @@ void dump_xlated_json(struct dump_data *dd, void *buf, unsigned int len,
struct bpf_insn *insn = buf; struct bpf_insn *insn = buf;
struct btf *btf = dd->btf; struct btf *btf = dd->btf;
bool double_insn = false; bool double_insn = false;
unsigned int nr_skip = 0;
char func_sig[1024]; char func_sig[1024];
unsigned int i; unsigned int i;
...@@ -273,6 +276,16 @@ void dump_xlated_json(struct dump_data *dd, void *buf, unsigned int len, ...@@ -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"); jsonw_name(json_wtr, "disasm");
print_bpf_insn(&cbs, insn + i, true); print_bpf_insn(&cbs, insn + i, true);
...@@ -307,8 +320,9 @@ void dump_xlated_json(struct dump_data *dd, void *buf, unsigned int len, ...@@ -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, 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 = { const struct bpf_insn_cbs cbs = {
.cb_print = print_insn, .cb_print = print_insn,
.cb_call = print_call, .cb_call = print_call,
...@@ -318,6 +332,7 @@ void dump_xlated_plain(struct dump_data *dd, void *buf, unsigned int len, ...@@ -318,6 +332,7 @@ void dump_xlated_plain(struct dump_data *dd, void *buf, unsigned int len,
struct bpf_func_info *record; struct bpf_func_info *record;
struct bpf_insn *insn = buf; struct bpf_insn *insn = buf;
struct btf *btf = dd->btf; struct btf *btf = dd->btf;
unsigned int nr_skip = 0;
bool double_insn = false; bool double_insn = false;
char func_sig[1024]; char func_sig[1024];
unsigned int i; unsigned int i;
...@@ -340,6 +355,17 @@ void dump_xlated_plain(struct dump_data *dd, void *buf, unsigned int len, ...@@ -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); double_insn = insn[i].code == (BPF_LD | BPF_IMM | BPF_DW);
printf("% 4d: ", i); printf("% 4d: ", i);
......
...@@ -40,6 +40,8 @@ ...@@ -40,6 +40,8 @@
#define SYM_MAX_NAME 256 #define SYM_MAX_NAME 256
struct bpf_prog_linfo;
struct kernel_sym { struct kernel_sym {
unsigned long address; unsigned long address;
char name[SYM_MAX_NAME]; char name[SYM_MAX_NAME];
...@@ -54,6 +56,7 @@ struct dump_data { ...@@ -54,6 +56,7 @@ struct dump_data {
struct btf *btf; struct btf *btf;
void *func_info; void *func_info;
__u32 finfo_rec_size; __u32 finfo_rec_size;
const struct bpf_prog_linfo *prog_linfo;
char scratch_buff[SYM_MAX_NAME + 8]; char scratch_buff[SYM_MAX_NAME + 8];
}; };
...@@ -61,9 +64,9 @@ void kernel_syms_load(struct dump_data *dd); ...@@ -61,9 +64,9 @@ void kernel_syms_load(struct dump_data *dd);
void kernel_syms_destroy(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); 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, 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, 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, void dump_xlated_for_graph(struct dump_data *dd, void *buf, void *buf_end,
unsigned int start_index); unsigned int start_index);
......
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
// 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;
}
...@@ -342,6 +342,19 @@ int libbpf_nl_get_qdisc(int sock, unsigned int nl_pid, int ifindex, ...@@ -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, int libbpf_nl_get_filter(int sock, unsigned int nl_pid, int ifindex, int handle,
libbpf_dump_nlmsg_t dump_filter_nlmsg, void *cookie); 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 #ifdef __cplusplus
} /* extern "C" */ } /* extern "C" */
#endif #endif
......
...@@ -99,6 +99,10 @@ LIBBPF_0.0.1 { ...@@ -99,6 +99,10 @@ LIBBPF_0.0.1 {
bpf_program__unload; bpf_program__unload;
bpf_program__unpin; bpf_program__unpin;
bpf_program__unpin_instance; 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_raw_tracepoint_open;
bpf_set_link_xdp_fd; bpf_set_link_xdp_fd;
bpf_task_fd_query; bpf_task_fd_query;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment