tools: bpftool: use the kernel's instruction printer

Compile the instruction printer from kernel/bpf and use it
for disassembling "translated" eBPF code.

Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: Simon Horman <simon.horman@netronome.com>
Acked-by: Alexei Starovoitov <ast@kernel.org>
Acked-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Jakub Kicinski 2017-10-09 10:30:13 -07:00 committed by David S. Miller
parent f4ac7e0b5c
commit c9c35995bc
4 changed files with 51 additions and 21 deletions

View File

@ -11,7 +11,7 @@ SYNOPSIS
======== ========
| **bpftool** prog show [*PROG*] | **bpftool** prog show [*PROG*]
| **bpftool** prog dump xlated *PROG* file *FILE* | **bpftool** prog dump xlated *PROG* [file *FILE*] [opcodes]
| **bpftool** prog dump jited *PROG* [file *FILE*] [opcodes] | **bpftool** prog dump jited *PROG* [file *FILE*] [opcodes]
| **bpftool** prog pin *PROG* *FILE* | **bpftool** prog pin *PROG* *FILE*
| **bpftool** prog help | **bpftool** prog help
@ -28,9 +28,12 @@ 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* **bpftool prog dump xlated** *PROG* [**file** *FILE*] [**opcodes**]
Dump eBPF instructions of the program from the kernel to a Dump eBPF instructions of the program from the kernel.
file. 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.
**bpftool prog dump jited** *PROG* [**file** *FILE*] [**opcodes**] **bpftool prog dump jited** *PROG* [**file** *FILE*] [**opcodes**]
Dump jited image (host machine code) of the program. Dump jited image (host machine code) of the program.

View File

@ -51,7 +51,7 @@ CC = gcc
CFLAGS += -O2 CFLAGS += -O2
CFLAGS += -W -Wall -Wextra -Wno-unused-parameter -Wshadow CFLAGS += -W -Wall -Wextra -Wno-unused-parameter -Wshadow
CFLAGS += -D__EXPORTED_HEADERS__ -I$(srctree)/tools/include/uapi -I$(srctree)/tools/include -I$(srctree)/tools/lib/bpf CFLAGS += -D__EXPORTED_HEADERS__ -I$(srctree)/tools/include/uapi -I$(srctree)/tools/include -I$(srctree)/tools/lib/bpf -I$(srctree)/kernel/bpf/
LIBS = -lelf -lbfd -lopcodes $(LIBBPF) LIBS = -lelf -lbfd -lopcodes $(LIBBPF)
include $(wildcard *.d) include $(wildcard *.d)
@ -59,7 +59,10 @@ include $(wildcard *.d)
all: $(OUTPUT)bpftool all: $(OUTPUT)bpftool
SRCS=$(wildcard *.c) SRCS=$(wildcard *.c)
OBJS=$(patsubst %.c,$(OUTPUT)%.o,$(SRCS)) OBJS=$(patsubst %.c,$(OUTPUT)%.o,$(SRCS)) $(OUTPUT)disasm.o
$(OUTPUT)disasm.o: $(srctree)/kernel/bpf/disasm.c
$(QUIET_CC)$(COMPILE.c) -MMD -o $@ $<
$(OUTPUT)bpftool: $(OBJS) $(LIBBPF) $(OUTPUT)bpftool: $(OBJS) $(LIBBPF)
$(QUIET_LINK)$(CC) $(CFLAGS) -o $@ $^ $(LIBS) $(QUIET_LINK)$(CC) $(CFLAGS) -o $@ $^ $(LIBS)

View File

@ -36,11 +36,12 @@
#ifndef __BPF_TOOL_H #ifndef __BPF_TOOL_H
#define __BPF_TOOL_H #define __BPF_TOOL_H
/* BFD and kernel.h both define GCC_VERSION, differently */
#undef GCC_VERSION
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <linux/bpf.h> #include <linux/bpf.h>
#include <linux/kernel.h>
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
#define err(msg...) fprintf(stderr, "Error: " msg) #define err(msg...) fprintf(stderr, "Error: " msg)
#define warn(msg...) fprintf(stderr, "Warning: " msg) #define warn(msg...) fprintf(stderr, "Warning: " msg)
@ -48,11 +49,6 @@
#define ptr_to_u64(ptr) ((__u64)(unsigned long)(ptr)) #define ptr_to_u64(ptr) ((__u64)(unsigned long)(ptr))
#define min(a, b) \
({ typeof(a) _a = (a); typeof(b) _b = (b); _a > _b ? _b : _a; })
#define max(a, b) \
({ typeof(a) _a = (a); typeof(b) _b = (b); _a < _b ? _b : _a; })
#define NEXT_ARG() ({ argc--; argv++; if (argc < 0) usage(); }) #define NEXT_ARG() ({ argc--; argv++; if (argc < 0) usage(); })
#define NEXT_ARGP() ({ (*argc)--; (*argv)++; if (*argc < 0) usage(); }) #define NEXT_ARGP() ({ (*argc)--; (*argv)++; if (*argc < 0) usage(); })
#define BAD_ARG() ({ err("what is '%s'?\n", *argv); -1; }) #define BAD_ARG() ({ err("what is '%s'?\n", *argv); -1; })

View File

@ -35,6 +35,7 @@
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -46,6 +47,7 @@
#include <bpf.h> #include <bpf.h>
#include "main.h" #include "main.h"
#include "disasm.h"
static const char * const prog_type_name[] = { static const char * const prog_type_name[] = {
[BPF_PROG_TYPE_UNSPEC] = "unspec", [BPF_PROG_TYPE_UNSPEC] = "unspec",
@ -297,11 +299,39 @@ static int do_show(int argc, char **argv)
return 0; return 0;
} }
static void print_insn(struct bpf_verifier_env *env, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
}
static void dump_xlated(void *buf, unsigned int len, bool opcodes)
{
struct bpf_insn *insn = buf;
unsigned int i;
for (i = 0; i < len / sizeof(*insn); i++) {
printf("% 4d: ", i);
print_bpf_insn(print_insn, NULL, insn + i, true);
if (opcodes) {
printf(" ");
print_hex(insn + i, 8, " ");
printf("\n");
}
if (insn[i].code == (BPF_LD | BPF_IMM | BPF_DW))
i++;
}
}
static int do_dump(int argc, char **argv) static int do_dump(int argc, char **argv)
{ {
struct bpf_prog_info info = {}; struct bpf_prog_info info = {};
__u32 len = sizeof(info); __u32 len = sizeof(info);
bool can_disasm = false;
unsigned int buf_size; unsigned int buf_size;
char *filepath = NULL; char *filepath = NULL;
bool opcodes = false; bool opcodes = false;
@ -315,7 +345,6 @@ static int do_dump(int argc, char **argv)
if (is_prefix(*argv, "jited")) { if (is_prefix(*argv, "jited")) {
member_len = &info.jited_prog_len; member_len = &info.jited_prog_len;
member_ptr = &info.jited_prog_insns; member_ptr = &info.jited_prog_insns;
can_disasm = true;
} else if (is_prefix(*argv, "xlated")) { } else if (is_prefix(*argv, "xlated")) {
member_len = &info.xlated_prog_len; member_len = &info.xlated_prog_len;
member_ptr = &info.xlated_prog_insns; member_ptr = &info.xlated_prog_insns;
@ -346,10 +375,6 @@ static int do_dump(int argc, char **argv)
NEXT_ARG(); NEXT_ARG();
} }
if (!filepath && !can_disasm) {
err("expected 'file' got %s\n", *argv);
return -1;
}
if (argc) { if (argc) {
usage(); usage();
return -1; return -1;
@ -409,7 +434,10 @@ static int do_dump(int argc, char **argv)
goto err_free; goto err_free;
} }
} else { } else {
disasm_print_insn(buf, *member_len, opcodes); if (member_len == &info.jited_prog_len)
disasm_print_insn(buf, *member_len, opcodes);
else
dump_xlated(buf, *member_len, opcodes);
} }
free(buf); free(buf);
@ -430,7 +458,7 @@ static int do_help(int argc, char **argv)
{ {
fprintf(stderr, fprintf(stderr,
"Usage: %s %s show [PROG]\n" "Usage: %s %s show [PROG]\n"
" %s %s dump xlated PROG file FILE\n" " %s %s dump xlated PROG [file FILE] [opcodes]\n"
" %s %s dump jited PROG [file FILE] [opcodes]\n" " %s %s dump jited PROG [file FILE] [opcodes]\n"
" %s %s pin PROG FILE\n" " %s %s pin PROG FILE\n"
" %s %s help\n" " %s %s help\n"