This is the mail archive of the elfutils-devel@sourceware.org mailing list for the elfutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH v2 2/2] Add support for BPF


Signed-off-by: Richard Henderson <rth@redhat.com>
---
 ChangeLog                          |   4 +
 backends/ChangeLog                 |   9 ++
 backends/Makefile.am               |  10 +-
 backends/bpf_init.c                |  60 ++++++++
 backends/bpf_regs.c                |  64 +++++++++
 backends/bpf_reloc.def             |  31 ++++
 backends/common-reloc.c            |   7 +-
 configure.ac                       |   4 +
 libasm/ChangeLog                   |   4 +
 libasm/disasm_cb.c                 |   4 +-
 libcpu/ChangeLog                   |   7 +
 libcpu/Makefile.am                 |   6 +
 libcpu/bpf_disasm.c                | 288 +++++++++++++++++++++++++++++++++++++
 libcpu/i386_disasm.c               |   3 +-
 libebl/ChangeLog                   |   5 +
 libebl/ebl-hooks.h                 |   2 +-
 libebl/eblopenbackend.c            |   1 +
 src/ChangeLog                      |   4 +
 src/elflint.c                      |   2 +-
 tests/ChangeLog                    |   9 ++
 tests/Makefile.am                  |   7 +-
 tests/run-disasm-bpf.sh            |  63 ++++++++
 tests/testfile-bpf-dis1.expect.bz2 | Bin 0 -> 1497 bytes
 tests/testfile-bpf-dis1.o.bz2      | Bin 0 -> 737 bytes
 24 files changed, 584 insertions(+), 10 deletions(-)
 create mode 100644 backends/bpf_init.c
 create mode 100644 backends/bpf_regs.c
 create mode 100644 backends/bpf_reloc.def
 create mode 100644 libcpu/bpf_disasm.c
 create mode 100755 tests/run-disasm-bpf.sh
 create mode 100644 tests/testfile-bpf-dis1.expect.bz2
 create mode 100644 tests/testfile-bpf-dis1.o.bz2
---

/
	* configure.ac (HAVE_LINUX_BPF_H): New test and conditional.
 
backends/
	* Makefile.am (modules): Add bpf.
	(libebl_pic): Add libebl_bpf_pic.a.
	(am_libebl_bpf_pic_a_OBJECTS): New.
	* bpf_init.c, bpf_regs.c, bpf_reloc.def: New files.
	* common-reloc.c (copy_reloc_p): Honor NO_COPY_RELOC.
	(init_reloc): Likewise.
 
libasm/
	* disasm_cb.c (disasm_cb): Pass ebl to disasm hook.

libcpu/
	* Makefile.am (noinst_LIBRARIES): Add libcpu_bpf.a.
	(libcpu_bpf_a_SOURCES, libcpu_bpf_a_CFLAGS): New.
	* bpf_disasm.c: New file.
	* i386_disasm.c (i386_disasm): Add ebl parameter.

libebl/
	* ebl-hooks.h (EBLHOOK(disasm)): Add ebl parameter.
	* eblopenbackend.c (machines): Add EM_BPF entry.

src/
	* elflint.c (valid_e_machine): Add EM_BPF.

tests/
	* Makefile.am (TESTS): Add run-disasm-bpf.sh, conditionally.
	(EXTRA_DIST): Add run-disasm-bpf.sh, testfile-bpf-dis1.expect.bz2,
	testfile-bpf-dis1.o.bz2
	(run-disasm-bpf.sh): New file.
	(testfile-bpf-dis1.expect.bz2): New file.
	(testfile-bpf-dis1.o.bz2): New file.


diff --git a/backends/Makefile.am b/backends/Makefile.am
index bf52391..02f1fa6 100644
--- a/backends/Makefile.am
+++ b/backends/Makefile.am
@@ -33,12 +33,12 @@ AM_CPPFLAGS += -I$(top_srcdir)/libebl -I$(top_srcdir)/libasm \
 
 
 modules = i386 sh x86_64 ia64 alpha arm aarch64 sparc ppc ppc64 s390 \
-	  tilegx m68k
+	  tilegx m68k bpf
 libebl_pic = libebl_i386_pic.a libebl_sh_pic.a libebl_x86_64_pic.a    \
 	     libebl_ia64_pic.a libebl_alpha_pic.a libebl_arm_pic.a    \
 	     libebl_aarch64_pic.a libebl_sparc_pic.a libebl_ppc_pic.a \
 	     libebl_ppc64_pic.a libebl_s390_pic.a libebl_tilegx_pic.a \
-	     libebl_m68k_pic.a
+	     libebl_m68k_pic.a libebl_bpf_pic.a
 noinst_LIBRARIES = $(libebl_pic)
 noinst_DATA = $(libebl_pic:_pic.a=.so)
 
@@ -118,6 +118,11 @@ m68k_SRCS = m68k_init.c m68k_symbol.c m68k_regs.c \
 libebl_m68k_pic_a_SOURCES = $(m68k_SRCS)
 am_libebl_m68k_pic_a_OBJECTS = $(m68k_SRCS:.c=.os)
 
+bpf_SRCS = bpf_init.c bpf_regs.c
+cpu_bpf = ../libcpu/libcpu_bpf.a
+libebl_bpf_pic_a_SOURCES = $(bpf_SRCS)
+am_libebl_bpf_pic_a_OBJECTS = $(bpf_SRCS:.c=.os)
+
 
 libebl_%.so libebl_%.map: libebl_%_pic.a $(libelf) $(libdw)
 	@rm -f $(@:.so=.map)
@@ -131,6 +136,7 @@ libebl_%.so libebl_%.map: libebl_%_pic.a $(libelf) $(libdw)
 
 libebl_i386.so: $(cpu_i386)
 libebl_x86_64.so: $(cpu_x86_64)
+libebl_bpf.so: $(cpu_bpf)
 
 install: install-am install-ebl-modules
 install-ebl-modules:
diff --git a/backends/bpf_init.c b/backends/bpf_init.c
new file mode 100644
index 0000000..22842e2
--- /dev/null
+++ b/backends/bpf_init.c
@@ -0,0 +1,60 @@
+/* Initialization of BPF specific backend library.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#define BACKEND		bpf_
+#define RELOC_PREFIX	R_BPF_
+#include "libebl_CPU.h"
+
+/* This defines the common reloc hooks based on bpf_reloc.def.  */
+#define NO_RELATIVE_RELOC
+#define NO_COPY_RELOC
+#include "common-reloc.c"
+
+
+const char *
+bpf_init (Elf *elf __attribute__ ((unused)),
+	  GElf_Half machine __attribute__ ((unused)),
+	  Ebl *eh, size_t ehlen)
+{
+  /* Check whether the Elf_BH object has a sufficent size.  */
+  if (ehlen < sizeof (Ebl))
+    return NULL;
+
+  /* We handle it.  */
+  eh->name = "BPF";
+  bpf_init_reloc (eh);
+  HOOK (eh, register_info);
+#ifdef HAVE_LINUX_BPF_H
+  HOOK (eh, disasm);
+#endif
+
+  return MODVERSION;
+}
diff --git a/backends/bpf_regs.c b/backends/bpf_regs.c
new file mode 100644
index 0000000..180af83
--- /dev/null
+++ b/backends/bpf_regs.c
@@ -0,0 +1,64 @@
+/* Register names and numbers for BPF DWARF.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#ifdef HAVE_LINUX_BPF_H
+#include <linux/bpf.h>
+#else
+#define MAX_BPF_REG 10
+#endif
+
+#define BACKEND bpf_
+#include "libebl_CPU.h"
+
+ssize_t
+bpf_register_info (Ebl *ebl __attribute__ ((unused)),
+		   int regno, char *name, size_t namelen,
+		   const char **prefix, const char **setname,
+		   int *bits, int *type)
+{
+  ssize_t len;
+
+  if (name == NULL)
+    return MAX_BPF_REG;
+  if (regno < 0 || regno >= MAX_BPF_REG)
+    return -1;
+
+  *prefix = "";
+  *setname = "integer";
+  *bits = 64;
+  *type = DW_ATE_signed;
+
+  len = snprintf(name, namelen, "r%d", regno);
+  return ((size_t)len < namelen ? len : -1);
+}
diff --git a/backends/bpf_reloc.def b/backends/bpf_reloc.def
new file mode 100644
index 0000000..a410da9
--- /dev/null
+++ b/backends/bpf_reloc.def
@@ -0,0 +1,31 @@
+/* List the relocation types for BPF.  -*- C -*-
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+/*	    NAME,		REL|EXEC|DYN	*/
+
+RELOC_TYPE (NONE,		EXEC|DYN)
+RELOC_TYPE (MAP_FD,		REL|EXEC|DYN)
diff --git a/backends/common-reloc.c b/backends/common-reloc.c
index 3317b6c..096ed1c 100644
--- a/backends/common-reloc.c
+++ b/backends/common-reloc.c
@@ -124,12 +124,13 @@ EBLHOOK(reloc_valid_use) (Elf *elf, int reloc)
   return type > ET_NONE && type < ET_CORE && (uses & (1 << (type - 1)));
 }
 
-
+#ifndef NO_COPY_RELOC
 bool
 EBLHOOK(copy_reloc_p) (int reloc)
 {
   return reloc == R_TYPE (COPY);
 }
+#endif
 
 bool
 EBLHOOK(none_reloc_p) (int reloc)
@@ -151,8 +152,10 @@ EBLHOOK(init_reloc) (Ebl *ebl)
   ebl->reloc_type_name = EBLHOOK(reloc_type_name);
   ebl->reloc_type_check = EBLHOOK(reloc_type_check);
   ebl->reloc_valid_use = EBLHOOK(reloc_valid_use);
-  ebl->copy_reloc_p = EBLHOOK(copy_reloc_p);
   ebl->none_reloc_p = EBLHOOK(none_reloc_p);
+#ifndef NO_COPY_RELOC
+  ebl->copy_reloc_p = EBLHOOK(copy_reloc_p);
+#endif
 #ifndef NO_RELATIVE_RELOC
   ebl->relative_reloc_p = EBLHOOK(relative_reloc_p);
 #endif
diff --git a/configure.ac b/configure.ac
index 07c0463..926715c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -361,6 +361,10 @@ else
 fi
 AC_SUBST([argp_LDADD])
 
+dnl Check if we have <linux/bpf.h> for EM_BPF disassembly.
+AC_CHECK_HEADERS(linux/bpf.h)
+AM_CONDITIONAL(HAVE_LINUX_BPF_H, [test "x$ac_cv_header_linux_bpf_h" = "xyes"])
+
 dnl The directories with content.
 
 dnl Documentation.
diff --git a/libasm/disasm_cb.c b/libasm/disasm_cb.c
index eb3689c..cf278c7 100644
--- a/libasm/disasm_cb.c
+++ b/libasm/disasm_cb.c
@@ -173,7 +173,7 @@ disasm_cb (DisasmCtx_t *ctx, const uint8_t **startp, const uint8_t *end,
       getsym = default_elf_getsym;
     }
 
-  return ctx->ebl->disasm (startp, end, addr, fmt, outcb, getsym, outcbarg,
-			   symcbarg);
+  return ctx->ebl->disasm (ctx->ebl, startp, end, addr, fmt, outcb,
+			   getsym, outcbarg, symcbarg);
 }
 INTDEF (disasm_cb)
diff --git a/libcpu/Makefile.am b/libcpu/Makefile.am
index f0caaea..b98b583 100644
--- a/libcpu/Makefile.am
+++ b/libcpu/Makefile.am
@@ -45,6 +45,12 @@ i386_gendis_SOURCES = i386_gendis.c i386_lex.l i386_parse.y
 i386_disasm.o: i386.mnemonics $(srcdir)/i386_dis.h
 x86_64_disasm.o: x86_64.mnemonics $(srcdir)/x86_64_dis.h
 
+if HAVE_LINUX_BPF_H
+noinst_LIBRARIES += libcpu_bpf.a
+libcpu_bpf_a_SOURCES = bpf_disasm.c
+libcpu_bpf_a_CFLAGS = $(AM_CFLAGS) -Wno-format-nonliteral
+endif
+
 %_defs: $(srcdir)/defs/i386
 	$(AM_V_GEN)m4 -D$* -DDISASSEMBLER $< > $@T
 	$(AM_V_at)mv -f $@T $@
diff --git a/libcpu/bpf_disasm.c b/libcpu/bpf_disasm.c
new file mode 100644
index 0000000..6301dcc
--- /dev/null
+++ b/libcpu/bpf_disasm.c
@@ -0,0 +1,288 @@
+/* Disassembler for BPF.
+   Copyright (C) 2016 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <gelf.h>
+#include <inttypes.h>
+#include <linux/bpf.h>
+
+#include "../libelf/common.h"
+#include "../libebl/libeblP.h"
+
+
+static const char class_string[8][8] = {
+  [BPF_LD]    = "ld",
+  [BPF_LDX]   = "ldx",
+  [BPF_ST]    = "st",
+  [BPF_STX]   = "stx",
+  [BPF_ALU]   = "alu",
+  [BPF_JMP]   = "jmp",
+  [BPF_RET]   = "6",		/* completely unused in ebpf */
+  [BPF_ALU64] = "alu64",
+};
+
+/* Dest = 1$, Src = 2$, Imm = 3$, Off = 4$, Branch = 5$.  */
+
+#define DST		"r%1$d"
+#define DSTU		"(u32)" DST
+#define DSTS		"(s64)" DST
+
+#define SRC		"r%2$d"
+#define SRCU		"(u32)" SRC
+#define SRCS		"(s64)" SRC
+
+#define IMMS		"%3$d"
+#define IMMX		"%3$#x"
+#define OFF		"%4$+d"
+#define JMP		"%5$#x"
+
+#define A32(O, S)	DST " = " DSTU " " #O " " S
+#define A64(O, S)	DST " " #O "= " S
+#define J64(D, O, S)	"if " D " " #O " " S " goto " JMP
+#define LOAD(T)		DST " = *(" #T " *)(" SRC OFF ")"
+#define STORE(T, S)	"*(" #T " *)(" DST OFF ") = " S
+#define XADD(T, S)	"lock *(" #T " *)(" DST OFF ") += " S
+#define LDSKB(T, S)	"r0 = *(" #T " *)skb[" S "]"
+
+/* 8 character field between opcode and arguments.  */
+static const char * const code_fmts[256] = {
+  [BPF_ALU | BPF_ADD  | BPF_K]    = A32(+, IMMS),
+  [BPF_ALU | BPF_SUB  | BPF_K]    = A32(-, IMMS),
+  [BPF_ALU | BPF_MUL  | BPF_K]    = A32(*, IMMS),
+  [BPF_ALU | BPF_DIV  | BPF_K]    = A32(/, IMMS),
+  [BPF_ALU | BPF_OR   | BPF_K]    = A32(|, IMMX),
+  [BPF_ALU | BPF_AND  | BPF_K]    = A32(&, IMMX),
+  [BPF_ALU | BPF_LSH  | BPF_K]    = A32(<<, IMMS),
+  [BPF_ALU | BPF_RSH  | BPF_K]    = A32(>>, IMMS),
+  [BPF_ALU | BPF_MOD  | BPF_K]    = A32(%, IMMS),
+  [BPF_ALU | BPF_XOR  | BPF_K]    = A32(^, IMMX),
+  [BPF_ALU | BPF_MOV  | BPF_K]    = DST " = " IMMX,
+  [BPF_ALU | BPF_ARSH | BPF_K]    = DST " = (u32)((s32)" DST " >> " IMMS ")",
+
+  [BPF_ALU | BPF_ADD  | BPF_X]    = A32(+, SRCU),
+  [BPF_ALU | BPF_SUB  | BPF_X]    = A32(-, SRCU),
+  [BPF_ALU | BPF_MUL  | BPF_X]    = A32(*, SRCU),
+  [BPF_ALU | BPF_DIV  | BPF_X]    = A32(/, SRCU),
+  [BPF_ALU | BPF_OR   | BPF_X]    = A32(|, SRCU),
+  [BPF_ALU | BPF_AND  | BPF_X]    = A32(&, SRCU),
+  [BPF_ALU | BPF_LSH  | BPF_X]    = A32(<<, SRCU),
+  [BPF_ALU | BPF_RSH  | BPF_X]    = A32(>>, SRCU),
+  [BPF_ALU | BPF_MOD  | BPF_X]    = A32(%, SRCU),
+  [BPF_ALU | BPF_XOR  | BPF_X]    = A32(^, SRCU),
+  [BPF_ALU | BPF_MOV  | BPF_X]    = DST " = " SRCU,
+  [BPF_ALU | BPF_ARSH | BPF_X]    = DST " = (u32)((s32)" DST " >> " SRC ")",
+
+  [BPF_ALU64 | BPF_ADD  | BPF_K]  = A64(+, IMMS),
+  [BPF_ALU64 | BPF_SUB  | BPF_K]  = A64(-, IMMS),
+  [BPF_ALU64 | BPF_MUL  | BPF_K]  = A64(*, IMMS),
+  [BPF_ALU64 | BPF_DIV  | BPF_K]  = A64(/, IMMS),
+  [BPF_ALU64 | BPF_OR   | BPF_K]  = A64(|, IMMS),
+  [BPF_ALU64 | BPF_AND  | BPF_K]  = A64(&, IMMS),
+  [BPF_ALU64 | BPF_LSH  | BPF_K]  = A64(<<, IMMS),
+  [BPF_ALU64 | BPF_RSH  | BPF_K]  = A64(>>, IMMS),
+  [BPF_ALU64 | BPF_MOD  | BPF_K]  = A64(%, IMMS),
+  [BPF_ALU64 | BPF_XOR  | BPF_K]  = A64(^, IMMS),
+  [BPF_ALU64 | BPF_MOV  | BPF_K]  = DST " = " IMMS,
+  [BPF_ALU64 | BPF_ARSH | BPF_K]  = DST " = (s64)" DST " >> " IMMS,
+
+  [BPF_ALU64 | BPF_ADD  | BPF_X]  = A64(+, SRC),
+  [BPF_ALU64 | BPF_SUB  | BPF_X]  = A64(-, SRC),
+  [BPF_ALU64 | BPF_MUL  | BPF_X]  = A64(*, SRC),
+  [BPF_ALU64 | BPF_DIV  | BPF_X]  = A64(/, SRC),
+  [BPF_ALU64 | BPF_OR   | BPF_X]  = A64(|, SRC),
+  [BPF_ALU64 | BPF_AND  | BPF_X]  = A64(&, SRC),
+  [BPF_ALU64 | BPF_LSH  | BPF_X]  = A64(<<, SRC),
+  [BPF_ALU64 | BPF_RSH  | BPF_X]  = A64(>>, SRC),
+  [BPF_ALU64 | BPF_MOD  | BPF_X]  = A64(%, SRC),
+  [BPF_ALU64 | BPF_XOR  | BPF_X]  = A64(^, SRC),
+  [BPF_ALU64 | BPF_MOV  | BPF_X]  = DST " = " SRC,
+  [BPF_ALU64 | BPF_ARSH | BPF_X]  = DST " = (s64)" DST " >> " SRC,
+
+  [BPF_ALU | BPF_NEG]		  = DST " = (u32)-" DST,
+  [BPF_ALU64 | BPF_NEG]		  = DST " = -" DST,
+
+  /* The imm field contains {16,32,64}.  */
+  [BPF_ALU | BPF_END | BPF_TO_LE] = DST " = le%3$-6d(" DST ")",
+  [BPF_ALU | BPF_END | BPF_TO_BE] = DST " = be%3$-6d(" DST ")",
+
+  [BPF_JMP | BPF_JEQ  | BPF_K]    = J64(DST, ==, IMMS),
+  [BPF_JMP | BPF_JGT  | BPF_K]    = J64(DST, >, IMMS),
+  [BPF_JMP | BPF_JGE  | BPF_K]    = J64(DST, >=, IMMS),
+  [BPF_JMP | BPF_JSET | BPF_K]    = J64(DST, &, IMMS),
+  [BPF_JMP | BPF_JNE  | BPF_K]    = J64(DST, !=, IMMS),
+  [BPF_JMP | BPF_JSGT | BPF_K]    = J64(DSTS, >, IMMS),
+  [BPF_JMP | BPF_JSGE | BPF_K]    = J64(DSTS, >=, IMMS),
+
+  [BPF_JMP | BPF_JEQ  | BPF_X]    = J64(DST, ==, SRC),
+  [BPF_JMP | BPF_JGT  | BPF_X]    = J64(DST, >, SRC),
+  [BPF_JMP | BPF_JGE  | BPF_X]    = J64(DST, >=, SRC),
+  [BPF_JMP | BPF_JSET | BPF_X]    = J64(DST, &, SRC),
+  [BPF_JMP | BPF_JNE  | BPF_X]    = J64(DST, !=, SRC),
+  [BPF_JMP | BPF_JSGT | BPF_X]    = J64(DSTS, >, SRCS),
+  [BPF_JMP | BPF_JSGE | BPF_X]    = J64(DSTS, >=, SRCS),
+
+  [BPF_JMP | BPF_JA]              = "goto " JMP,
+  [BPF_JMP | BPF_CALL]            = "call " IMMS,
+  [BPF_JMP | BPF_EXIT]            = "exit",
+
+  [BPF_LDX | BPF_MEM | BPF_B]     = LOAD(u8),
+  [BPF_LDX | BPF_MEM | BPF_H]     = LOAD(u16),
+  [BPF_LDX | BPF_MEM | BPF_W]     = LOAD(u32),
+  [BPF_LDX | BPF_MEM | BPF_DW]    = LOAD(u64),
+
+  [BPF_STX | BPF_MEM | BPF_B]     = STORE(u8, SRC),
+  [BPF_STX | BPF_MEM | BPF_H]     = STORE(u16, SRC),
+  [BPF_STX | BPF_MEM | BPF_W]     = STORE(u32, SRC),
+  [BPF_STX | BPF_MEM | BPF_DW]    = STORE(u64, SRC),
+
+  [BPF_STX | BPF_XADD | BPF_W]    = XADD(u32, SRC),
+  [BPF_STX | BPF_XADD | BPF_DW]   = XADD(u64, SRC),
+
+  [BPF_ST | BPF_MEM | BPF_B]      = STORE(u8, IMMS),
+  [BPF_ST | BPF_MEM | BPF_H]      = STORE(u16, IMMS),
+  [BPF_ST | BPF_MEM | BPF_W]      = STORE(u32, IMMS),
+  [BPF_ST | BPF_MEM | BPF_DW]     = STORE(u64, IMMS),
+
+  [BPF_LD | BPF_ABS | BPF_B]      = LDSKB(u8, IMMS),
+  [BPF_LD | BPF_ABS | BPF_H]      = LDSKB(u16, IMMS),
+  [BPF_LD | BPF_ABS | BPF_W]      = LDSKB(u32, IMMS),
+
+  [BPF_LD | BPF_IND | BPF_B]      = LDSKB(u8, SRC "+" IMMS),
+  [BPF_LD | BPF_IND | BPF_H]      = LDSKB(u16, SRC "+" IMMS),
+  [BPF_LD | BPF_IND | BPF_W]      = LDSKB(u32, SRC "+" IMMS),
+};
+
+static void
+bswap_bpf_insn (struct bpf_insn *p)
+{
+  /* Note that the dst_reg and src_reg fields are 4-bit bitfields.
+     That means these two nibbles are (typically) layed out in the
+     opposite order between big- and little-endian hosts.  This is
+     not required by any standard, but does happen to be true for
+     at least ppc, s390, arm and mips as big-endian hosts.  */
+  int t = p->dst_reg;
+  p->dst_reg = p->src_reg;
+  p->src_reg = t;
+
+  /* The other 2 and 4 byte fields are trivially converted.  */
+  CONVERT (p->off);
+  CONVERT (p->imm);
+}
+
+int
+bpf_disasm (Ebl *ebl, const uint8_t **startp, const uint8_t *end,
+	    GElf_Addr addr, const char *fmt __attribute__((unused)),
+	    DisasmOutputCB_t outcb,
+	    DisasmGetSymCB_t symcb __attribute__((unused)),
+	    void *outcbarg,
+	    void *symcbarg __attribute__((unused)))
+{
+  const bool need_bswap = MY_ELFDATA != ebl->data;
+  const uint8_t *start = *startp;
+  char buf[128];
+  int len, retval = 0;
+
+  while (start + sizeof(struct bpf_insn) <= end)
+    {
+      struct bpf_insn i;
+      unsigned code, class, jmp;
+      const char *code_fmt;
+
+      memcpy(&i, start, sizeof(struct bpf_insn));
+      if (need_bswap)
+	bswap_bpf_insn (&i);
+      start += sizeof(struct bpf_insn);
+      addr += sizeof(struct bpf_insn);
+
+      /* ??? We really should pass in CTX, so that we can detect
+	 wrong endianness and do some swapping.  */
+
+      code = i.code;
+      code_fmt = code_fmts[code];
+
+      if (code == (BPF_LD | BPF_IMM | BPF_DW))
+	{
+	  struct bpf_insn i2;
+	  uint64_t imm64;
+
+	  if (start + sizeof(struct bpf_insn) > end)
+	    {
+	      start -= sizeof(struct bpf_insn);
+	      *startp = start;
+	      goto done;
+	    }
+	  memcpy(&i2, start, sizeof(struct bpf_insn));
+	  if (need_bswap)
+	    bswap_bpf_insn (&i2);
+	  start += sizeof(struct bpf_insn);
+	  addr += sizeof(struct bpf_insn);
+
+	  imm64 = (uint32_t)i.imm | ((uint64_t)i2.imm << 32);
+	  switch (i.src_reg)
+	    {
+	    case 0:
+	      code_fmt = DST " = %2$#" PRIx64;
+	      break;
+	    case BPF_PSEUDO_MAP_FD:
+	      code_fmt = DST " = map_fd(%2$#" PRIx64 ")";
+	      break;
+	    default:
+	      code_fmt = DST " = ld_pseudo(%3$d, %2$#" PRIx64 ")";
+	      break;
+	    }
+	  len = snprintf(buf, sizeof(buf), code_fmt,
+			 i.dst_reg, imm64, i.src_reg);
+	}
+      else if (code_fmt != NULL)
+	{
+	  jmp = addr + i.off * sizeof(struct bpf_insn);
+	  len = snprintf(buf, sizeof(buf), code_fmt, i.dst_reg, i.src_reg,
+			 i.imm, i.off, jmp);
+	}
+      else
+	{
+	  class = BPF_CLASS(code);
+	  len = snprintf(buf, sizeof(buf), "invalid class %s",
+			 class_string[class]);
+        }
+
+      *startp = start;
+      retval = outcb (buf, len, outcbarg);
+      if (retval != 0)
+	goto done;
+    }
+
+ done:
+  return retval;
+}
diff --git a/libcpu/i386_disasm.c b/libcpu/i386_disasm.c
index 832241f..ceb5164 100644
--- a/libcpu/i386_disasm.c
+++ b/libcpu/i386_disasm.c
@@ -313,7 +313,8 @@ struct output_data
 
 
 int
-i386_disasm (const uint8_t **startp, const uint8_t *end, GElf_Addr addr,
+i386_disasm (Ebl *ebl __attribute__((unused)),
+	     const uint8_t **startp, const uint8_t *end, GElf_Addr addr,
 	     const char *fmt, DisasmOutputCB_t outcb, DisasmGetSymCB_t symcb,
 	     void *outcbarg, void *symcbarg)
 {
diff --git a/libebl/ebl-hooks.h b/libebl/ebl-hooks.h
index 2e31446..a7f4755 100644
--- a/libebl/ebl-hooks.h
+++ b/libebl/ebl-hooks.h
@@ -150,7 +150,7 @@ int EBLHOOK(syscall_abi) (Ebl *ebl, int *sp, int *pc,
 			  int *callno, int args[6]);
 
 /* Disassembler function.  */
-int EBLHOOK(disasm) (const uint8_t **startp, const uint8_t *end,
+int EBLHOOK(disasm) (Ebl *ebl, const uint8_t **startp, const uint8_t *end,
 		     GElf_Addr addr, const char *fmt, DisasmOutputCB_t outcb,
 		     DisasmGetSymCB_t symcb, void *outcbarg, void *symcbarg);
 
diff --git a/libebl/eblopenbackend.c b/libebl/eblopenbackend.c
index 2b92254..16ec1c4 100644
--- a/libebl/eblopenbackend.c
+++ b/libebl/eblopenbackend.c
@@ -132,6 +132,7 @@ static const struct
   { "arc", "elf_arc_a5", "arc_a5", 6, EM_ARC_A5, 0, 0 },
   { "xtensa", "elf_xtensa", "xtensa", 6, EM_XTENSA, 0, 0 },
   { "aarch64", "elf_aarch64", "aarch64", 7, EM_AARCH64, ELFCLASS64, 0 },
+  { "bpf", "elf_bpf", "bpf", 3, EM_BPF, 0, 0 },
 };
 #define nmachines (sizeof (machines) / sizeof (machines[0]))
 
diff --git a/src/elflint.c b/src/elflint.c
index 15b12f6..8c298c9 100644
--- a/src/elflint.c
+++ b/src/elflint.c
@@ -344,7 +344,7 @@ static const int valid_e_machine[] =
     EM_CRIS, EM_JAVELIN, EM_FIREPATH, EM_ZSP, EM_MMIX, EM_HUANY, EM_PRISM,
     EM_AVR, EM_FR30, EM_D10V, EM_D30V, EM_V850, EM_M32R, EM_MN10300,
     EM_MN10200, EM_PJ, EM_OPENRISC, EM_ARC_A5, EM_XTENSA, EM_ALPHA,
-    EM_TILEGX, EM_TILEPRO, EM_AARCH64
+    EM_TILEGX, EM_TILEPRO, EM_AARCH64, EM_BPF
   };
 #define nvalid_e_machine \
   (sizeof (valid_e_machine) / sizeof (valid_e_machine[0]))
diff --git a/tests/Makefile.am b/tests/Makefile.am
index fedcb39..274356f 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -148,6 +148,9 @@ endif
 if HAVE_LIBASM
 check_PROGRAMS += $(asm_TESTS)
 TESTS += $(asm_TESTS)
+if HAVE_LINUX_BPF_H
+TESTS += run-disasm-bpf.sh
+endif
 endif
 
 EXTRA_DIST = run-arextract.sh run-arsymtest.sh \
@@ -322,7 +325,9 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh \
 	     testfile-zgabi32.bz2 testfile-zgabi64.bz2 \
 	     testfile-zgabi32be.bz2 testfile-zgabi64be.bz2 \
 	     run-elfgetchdr.sh run-elfgetzdata.sh run-elfputzdata.sh \
-	     run-zstrptr.sh run-compress-test.sh
+	     run-zstrptr.sh run-compress-test.sh \
+	     run-disasm-bpf.sh \
+	     testfile-bpf-dis1.expect.bz2 testfile-bpf-dis1.o.bz2
 
 if USE_VALGRIND
 valgrind_cmd='valgrind -q --leak-check=full --error-exitcode=1'
diff --git a/tests/run-disasm-bpf.sh b/tests/run-disasm-bpf.sh
new file mode 100755
index 0000000..8ca89d5
--- /dev/null
+++ b/tests/run-disasm-bpf.sh
@@ -0,0 +1,63 @@
+#! /bin/sh
+# Copyright (C) 2016 Red Hat, Inc.
+# This file is part of elfutils.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# elfutils is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+. $srcdir/test-subr.sh
+
+# This test file is created with
+#
+# #include <linux/bpf.h>
+# #include <stdio.h>
+#
+# int main()
+# {
+#   int i;
+#
+#   printf("\t.text\n");
+#
+#   for (i = 0; i < 256; ++i)
+#     if (i == (BPF_LD | BPF_IMM | BPF_DW))
+#       printf("\t.byte\t%d, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n", i);
+#     else
+#       {
+#         int regs = 0;
+#         switch (BPF_CLASS(i))
+#           {
+#           case BPF_ALU:
+#           case BPF_ALU64:
+#             if (BPF_SRC(i) == BPF_X
+#                 && BPF_OP(i) != BPF_NEG
+#                 && BPF_OP(i) != BPF_END)
+#               regs = 0x21;
+#             break;
+#           case BPF_LDX:
+#           case BPF_STX:
+#             regs = 0x21;
+#             break;
+#           }
+#         printf("\t.byte\t%d, %d, 0, 0, 0, 0, 0, 0\n", i, regs);
+#       }
+#
+#   return 0;
+# }
+#
+# $ ./a.out | as -o z1.o
+# $ objcopy -j .text z1.o z2.o
+#
+# Then emacs hexl edit e_machine to 0xf7.
+
+testfiles testfile-bpf-dis1.o testfile-bpf-dis1.expect
+testrun_compare ${abs_top_builddir}/src/objdump -d testfile-bpf-dis1.o < testfile-bpf-dis1.expect
diff --git a/tests/testfile-bpf-dis1.expect.bz2 b/tests/testfile-bpf-dis1.expect.bz2
new file mode 100644
index 0000000000000000000000000000000000000000..b4a778e03882796d5c0682e2ac46daf8ecf4f53c
GIT binary patch
literal 1497
zcmZ`(X;70_6n#lpLclaZP-JmP$`T^bri2}wBm$KstU(NvXaRvF4V!{&vZ!EW&=E{z
zX+}ZT#0gq7NLf^tA|n_;F_BHQ6c9p7kx~R)`l0>nnfK$)n|t29_nbSA79Q_RqB1Q)
zn0pw%{0WT8j^w3d;<7%js{x>W|NeB$QKZ5Cty9DP!j*N2%)Z6IZF0{t*^rnSGBjF4
zcj)#E2n2`&)T&`lriAYBPCV<rDLzl906+$CVs5pJNEj)p^ef-_HB3XRM&p{Kh~p?;
z(a)Q8nZkX;4h4dcl$-TH!n(Y1gzuP0tTj5YTF_5m*r02r}fv0$Wnk-Ua51wdmo*$|J%
zJGrc{XWXBD*4gLVl2^uqxnEJJ&C2p^$KjE8wu5h2!3hy%I|dRir%bjcF!_Z|(##Ce
z8NJ7|ky5A6l+U^CsekDV_G;)**n27}D#~Sm1av3}j6RnUOjOh)*bTU{MKi~)elU{0
zds&5$=fT9KKn(+Ckdz9|+Y^}dl#iKN%QLSEMJi><@%>L8qZp0h_R9&XTFEx*<H+3?
zk>%ygd3)`Ybt4D5usJ7!xD^r8ej$b%8thHvz^D>bm9BdJQ6?onu^}xr>|h>Ro&*4J
zb+c=j^S9~)mLB~8obQ2V*VMb5Ev$XwJC)5^n+QFUE3Q?Xba?>4j&T6Pz}mcPh3&LA
zxn`vi-=Z2zitw4VgQR?`BK-5OvTn2zEE|j{)%kjZ7`v{45G=80uTE=U?_nv<rX%Pf
zoW(iKcumbI0CTk%Ge=7Ug9o=vU_rWiwwkyQn7Ewk3RYGVls3(lk-m>juuZi9mZTPh
z^*36bdc8R0ma_Clr7Y7C&{Mq4Bn`EsGjQJmEOw)Ep`GrO^s35`U0>;uw9)I~;jw&g
z3p#nwcwa(}m6A?O^a+s?Ip?v6_Hl(w$_>ZcBf;YP(a)6&>?#=jn_W)T0qsjj9Hb7?Az
z<Dz+IISHA>MAGCw{IeEL3ZZm4>&1HKH0!7-3UTY=Ks48N364j*;n1m<&RRFeIm?fW
zW-#Z}FBPCVcI#+a#Kz+BPsioIlVW4}Qm-y2qUjWkR>z8z^wW05IX^w2q?47AseL%K
zHhG-qIK0XBEanYe+Z&E{oWHyORGYcTCRr9I2tS57i$nTF8}yNiqqalMurQ>QW5g59
zXxmG9{T3nYJL5cupXp*~%PIt)!g^)0nP9|ka8SjRGb=XjG;8ea>^b_hMgg_^B|05N
z2t`#h;<(`oS^fWPD$g@*_R;fcueW`>xC1O(mcKzS4oTaY^M32DAG^LBDo(>d`V<6R
zaOV013+f0s4YirNwy?157mC=phUjR~TyPK;Lay2%R2O<$%3AN-7VP<#4ACJ%8IT8x
zmI+?V*g_wP&-aF$^zgJAtK7Z<(C_eNASRx<;I!m$!xIbByua_ItlV0AJ9bi$9(a)s2s
zkx7&Gp(P4oG*=5}7K4~yG%n2Vi5*-Wavx_$lAqoTvt=dZ=|t&%YS<@NND%7(BXrd#
z2zTE;hf;LZ$7b{%80t<eY*XDJc??)LCiTF*-MjSFl|36v6JhBSzP{}aBey44n%r7f
zOyS;UrRITI4*?&pol0>X1>f~6-Bz#2u4ejuJZ*}!*km`*nS4;{ZFZdp(a)Q0wSJIseL
z8YPE>>ID#+@`lJGZv<tnBQh$ceIut(a)IucLO(9)KTg~7$8Cd9oT3ypbws-}m=$vp<H
zC-+gQrk%rqKD-Yc8Eb~r-9;tvH|AEOs;*#6?)-7n<ofBfP}K`=nR)i&vP<#M6g`wt
z+6bdvM~_9yvhvg!Me4KG(a)FH-@#*!>4t+ycv>S{`>1nQ5F<8>p5yHk>@3D17Q&WWWy
mjS|MSu~72>jR%kmrWCMOBAFHa(470*WQo6?nMSB}7Ue&skb?gJ

literal 0
HcmV?d00001

diff --git a/tests/testfile-bpf-dis1.o.bz2 b/tests/testfile-bpf-dis1.o.bz2
new file mode 100644
index 0000000000000000000000000000000000000000..94bb612bcbfb191519c42b7b8c45981df0566f9b
GIT binary patch
literal 737
zcmZ>Y%CIzaj8qGb++%U#9|Lp5e}dou<K4S=avPpaG)hV`m}wx)a^z$KgRhC9kpYvD
z0iyu}gPKoUkD4;aK?5~L10OX8!DS2?SI+br`1<(Tnxsf^FfcF(GfFUUPWE9CNC0wt
z7)=r-7-j&CSvG@#S*=ZRvD>UfH8mf>iHjK+W-u_SF>p2jX*|H>tHzR#f{UHx7GF6i
zm6UOEv9F;m!%Tx2YCbbEd}atUD6=H+x(TbPsrAfoGnG(W#+2EVpyoC!<FXpdi34g3
zObextc{WZ^^O;gUTg;@UCDP-PQE=t?X7z_ZCZ?(f-~8ThzaStZ&X(a)o6XZ6(mpP7}7
zor9B`Hy>jDBBEmA5>m2c%ayO9s-~`?rAxP7{U)Yn<`!1AY}>W(;_Bw^;pHoK-1sS}
zY2UJB%aJoz?jI|EYVY`Y;i4r=m#<vCX6?H58yQ$cHyAYL={d9S6;KJ-*j!K_DQQ``
z^OuxjNpn_KyWkp-pgaHVJ9ib_>l-H8Db3mP<#NN`r4BD%GKGjS2%fm`Jl^W%%$e!W
zWGAJZ64ID#l(J;8)eK2BPyHI7sV_Ua)UO&iHK{1?n6l%{nbUe|sd7f1lUgrtP`)~S
z_d(t~KekS;bm8TGlTSE2Fe*QI;Dw8k3hR(a)yurvpT*-=c^Teodz6VN?+_CogV1K+nF
z(m(QmOUxjT|28+j(a)cZuGAIDFeJazg{>!r)Qf395RQ;v(a)DJFqaBt?#D%-&?ou{LlM;
zB46<S0~P=F?*0kO_04B)0Y;*P0;5<8^8&^R9O0H3Iv;k(6^4jx<S1}=V3hDY$f4Ks
zRjly(a)+f)Tst(T8>A6I|6{!Dx7wmSmHS9I1jA1UO(a)d&h8saRRe~Kqq^FP~kxi21$k%
g2A&2d1~vzt1`wN9Nu5RS$L>j*hgw=69&`Ty0IB~rGynhq

literal 0
HcmV?d00001

-- 
2.5.5

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]