summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Henderson <rth@redhat.com>2016-06-21 15:10:10 -0700
committerMark Wielaard <mjw@redhat.com>2016-06-28 20:09:11 +0200
commit9a36c9226c4a237208a7735f0e6a6fd1eefb60ab (patch)
tree22f86eafeea028d09ff8f13ab4b5c3258f3b848f
parent4c746f2501f6062230e2fa609bf4e8499b33caa4 (diff)
downloadelfutils-9a36c9226c4a237208a7735f0e6a6fd1eefb60ab.tar.gz
Add support for BPF
Signed-off-by: Richard Henderson <rth@redhat.com>
-rw-r--r--ChangeLog4
-rw-r--r--backends/ChangeLog10
-rw-r--r--backends/Makefile.am15
-rw-r--r--backends/bpf_init.c60
-rw-r--r--backends/bpf_regs.c64
-rw-r--r--backends/bpf_reloc.def31
-rw-r--r--backends/common-reloc.c7
-rw-r--r--configure.ac4
-rw-r--r--libasm/ChangeLog4
-rw-r--r--libasm/disasm_cb.c4
-rw-r--r--libcpu/ChangeLog7
-rw-r--r--libcpu/Makefile.am6
-rw-r--r--libcpu/bpf_disasm.c288
-rw-r--r--libcpu/i386_disasm.c3
-rw-r--r--libebl/ChangeLog5
-rw-r--r--libebl/ebl-hooks.h2
-rw-r--r--libebl/eblopenbackend.c1
-rw-r--r--src/ChangeLog4
-rw-r--r--src/elflint.c2
-rw-r--r--tests/ChangeLog9
-rw-r--r--tests/Makefile.am7
-rwxr-xr-xtests/run-disasm-bpf.sh63
-rw-r--r--tests/testfile-bpf-dis1.expect.bz2bin0 -> 1497 bytes
-rw-r--r--tests/testfile-bpf-dis1.o.bz2bin0 -> 737 bytes
24 files changed, 590 insertions, 10 deletions
diff --git a/ChangeLog b/ChangeLog
index 1a7d9ccf..5be4c5ec 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2016-06-28 Richard Henderson <rth@redhat.com>
+
+ * configure.ac (HAVE_LINUX_BPF_H): New test and conditional.
+
2016-06-10 Mark Wielaard <mjw@redhat.com>
* CONTRIBUTING: Extend patch, committer and maintainer guidelines.
diff --git a/backends/ChangeLog b/backends/ChangeLog
index afda37a9..7cd19065 100644
--- a/backends/ChangeLog
+++ b/backends/ChangeLog
@@ -1,3 +1,13 @@
+2016-06-28 Richard Henderson <rth@redhat.com>
+
+ * 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.
+
+
2016-05-20 Andreas Schwab <schwab@linux-m68k.org>
* Makefile.am (modules): Add m68k.
diff --git a/backends/Makefile.am b/backends/Makefile.am
index bf523912..b553ec34 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,16 @@ 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
+# The disam hook depends on this if we have linux/bpf.h.
+if HAVE_LINUX_BPF_H
+cpu_bpf = ../libcpu/libcpu_bpf.a
+else
+cpu_bpf =
+endif
+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 +141,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 00000000..22842e26
--- /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 00000000..180af83b
--- /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 00000000..a410da97
--- /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 3317b6c9..096ed1c7 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 07c04637..926715cf 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/ChangeLog b/libasm/ChangeLog
index a8ac2c7c..afc7e8ec 100644
--- a/libasm/ChangeLog
+++ b/libasm/ChangeLog
@@ -1,3 +1,7 @@
+2016-06-28 Richard Henderson <rth@redhat.com>
+
+ * disasm_cb.c (disasm_cb): Pass ebl to disasm hook.
+
2016-02-12 Mark Wielaard <mjw@redhat.com>
* asm_begin.c (prepare_text_output): Only call __fsetlocking when
diff --git a/libasm/disasm_cb.c b/libasm/disasm_cb.c
index eb3689c7..cf278c71 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/ChangeLog b/libcpu/ChangeLog
index c953c7b3..269e777b 100644
--- a/libcpu/ChangeLog
+++ b/libcpu/ChangeLog
@@ -1,3 +1,10 @@
+2016-06-28 Richard Henderson <rth@redhat.com>
+
+ * 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.
+
2015-10-05 Josh Stone <jistone@redhat.com>
* Makefile.am (%_defs): Add AM_V_GEN and AM_V_at silencers.
diff --git a/libcpu/Makefile.am b/libcpu/Makefile.am
index f0caaea6..b98b5838 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 00000000..6301dccc
--- /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 832241f2..ceb5164f 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/ChangeLog b/libebl/ChangeLog
index 97a9b897..8ff40106 100644
--- a/libebl/ChangeLog
+++ b/libebl/ChangeLog
@@ -1,3 +1,8 @@
+2016-06-28 Richard Henderson <rth@redhat.com>
+
+ * ebl-hooks.h (EBLHOOK(disasm)): Add ebl parameter.
+ * eblopenbackend.c (machines): Add EM_BPF entry.
+
2016-05-20 Andreas Schwab <schwab@linux-m68k.org>
* eblopenbackend.c (machines) [EM_68K]: Set class and data.
diff --git a/libebl/ebl-hooks.h b/libebl/ebl-hooks.h
index 2e314464..a7f47554 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 2b922543..16ec1c45 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/ChangeLog b/src/ChangeLog
index bdc9d133..21fc7d51 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,7 @@
+2016-06-28 Richard Henderson <rth@redhat.com>
+
+ * elflint.c (valid_e_machine): Add EM_BPF.
+
2016-04-11 David Abdurachmanov <davidlt@cern.ch>
* elfcmp.c (main): Fix self-comparison error with GCC 6.
diff --git a/src/elflint.c b/src/elflint.c
index 15b12f6f..8c298c93 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/ChangeLog b/tests/ChangeLog
index bcc296f1..1504d487 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,3 +1,12 @@
+2016-06-28 Richard Henderson <rth@redhat.com>
+
+ * 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.
+
2016-02-09 Mark Wielaard <mjw@redhat.com>
* testfile-s390x-hash-both.bz2: New testfile.
diff --git a/tests/Makefile.am b/tests/Makefile.am
index fedcb39d..274356fb 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 00000000..8ca89d53
--- /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 00000000..b4a778e0
--- /dev/null
+++ b/tests/testfile-bpf-dis1.expect.bz2
Binary files differ
diff --git a/tests/testfile-bpf-dis1.o.bz2 b/tests/testfile-bpf-dis1.o.bz2
new file mode 100644
index 00000000..94bb612b
--- /dev/null
+++ b/tests/testfile-bpf-dis1.o.bz2
Binary files differ