public inbox for elfutils@sourceware.org
 help / color / mirror / Atom feed
* Re: [PATCH] Add support for BPF
@ 2016-06-08 16:11 Richard Henderson
  0 siblings, 0 replies; 3+ messages in thread
From: Richard Henderson @ 2016-06-08 16:11 UTC (permalink / raw)
  To: elfutils-devel

[-- Attachment #1: Type: text/plain, Size: 3114 bytes --]

On 06/07/2016 06:19 AM, Mark Wielaard wrote:
> Hi Richard,
> 
> On Fri, 2016-06-03 at 13:48 -0700, Richard Henderson wrote:
>> I'm using the following to aid in debugging objects similar to what's
>> produced by the llvm-bpf backend.
> 
> Thanks. Is there a document/URL on BPF data structures and how it gets
> embedded into ELF files to include in the source comments for reference?

No.  The best I could do is point you at

http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/samples/bpf/bpf_load.c

and then you can read the code.  ;-)

> Also can I trick you into submitting a GNU-style ChangeLog for it too?
> Personally I like those because they review by listing what to expect.
> Although there seem to be more and more abolitionists out there these
> days.

Heh.  And I'm one of them.  But yes, I can write such a thing.

> Nice :) Normally we just take the latest elf.h from glibc.
> Would you mind submitting that part to libc-alpha@sourceware.org for
> inclusion? That would also make sure that other projects pick up the
> same EM constant as standard for BPF ELF files.

Yeah, I'll submit it for binutils and llvm too.

>> What's lacking so far are test cases.  Although there needn't be too
>> many of those, considering the simplicity of the target.
> 
> A simple testcase would be great. If only for those of us who have never
> actually seen an BPF ELF file. Note that we do allow binary files in the
> testsuite for tests that only read data. But please add a note in the
> test harness how to regenerate them.
> 
> I think we need a configure check to see if we have <linux/bpf.h>. Or we
> could create our own constants file and struct bpf_insn to be
> independent from the specific kernel headers installed.
> 
>> +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",
>> +  [BPF_ALU64] = "alu64",
>> +};
> 
> Why is RET 6?

The "old" bpf format, from *bsd, used opcode 6 for return.  In the new ebpf
format, it's completely unused.

>> +      /* ??? We really should pass in CTX, so that we can detect
>> +	 wrong endianness and do some swapping.  */
> 
> Note that the disasm EBL hook is an internal API, so you should feel
> free to just pass in the ctx, ebl or elf to the function if you need it
> to determine whether the ELF was big or little endian. All users are
> internal.

Ok.

>> +      code = i.code;
>> +      class = BPF_CLASS(code);
>> +      op = BPF_OP(code) | BPF_SRC(code);
> 
> Do the various BPF_XXX macros clamp the values so that the fmt array
> accesses below don't overflow? We don't want crashes even if someone
> feeds bogus code (struct bpf_insn) values.

Yes, they do mask values.

> Of course if we have a small BPF testcase ELF file we can always just
> run a fuzzer on it to make sure.

Fair enough.  It would be small enough to just add all 256 values that fill the
opcode byte.


r~

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] Add support for BPF
@ 2016-06-07 13:19 Mark Wielaard
  0 siblings, 0 replies; 3+ messages in thread
From: Mark Wielaard @ 2016-06-07 13:19 UTC (permalink / raw)
  To: elfutils-devel

[-- Attachment #1: Type: text/plain, Size: 4163 bytes --]

Hi Richard,

On Fri, 2016-06-03 at 13:48 -0700, Richard Henderson wrote:
> I'm using the following to aid in debugging objects similar to what's
> produced by the llvm-bpf backend.

Thanks. Is there a document/URL on BPF data structures and how it gets
embedded into ELF files to include in the source comments for reference?

Also can I trick you into submitting a GNU-style ChangeLog for it too?
Personally I like those because they review by listing what to expect.
Although there seem to be more and more abolitionists out there these
days.

> (Really, the only change I've made so far is to give the objects a
> proper e_machine value.  The stock llvm compiler produces e_machine = 0.
> I chose EM_BPF = 0xeb9f, as a sort-of leet-speak spelling of "ebpf".)

Nice :) Normally we just take the latest elf.h from glibc.
Would you mind submitting that part to libc-alpha@sourceware.org for
inclusion? That would also make sure that other projects pick up the
same EM constant as standard for BPF ELF files.

> The most important part of the patch, for me, is the disassembler,
> since there isn't any published tool for that at the moment, much less
> one that could take its data out of the object file.  I followed the
> dumping code in linux/kernel/bpf/verifier.c in producing C-like output.
> (Though the kernel's output for 32-bit ALU ops is ugly so I cleaned
> that up, as well as tweaking the signed shift and compare ops.)

I do have to admit that our disassembler isn't very actively maintained.
This might be the first addition in the last 5 years.

> What's lacking so far are test cases.  Although there needn't be too
> many of those, considering the simplicity of the target.

A simple testcase would be great. If only for those of us who have never
actually seen an BPF ELF file. Note that we do allow binary files in the
testsuite for tests that only read data. But please add a note in the
test harness how to regenerate them.

I think we need a configure check to see if we have <linux/bpf.h>. Or we
could create our own constants file and struct bpf_insn to be
independent from the specific kernel headers installed.

> +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",
> +  [BPF_ALU64] = "alu64",
> +};

Why is RET 6?

> +int
> +bpf_disasm (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 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, op;
> +      const char *op_str;
> +
> +      memcpy(&i, start, sizeof(struct bpf_insn));
> +      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.  */

Note that the disasm EBL hook is an internal API, so you should feel
free to just pass in the ctx, ebl or elf to the function if you need it
to determine whether the ELF was big or little endian. All users are
internal.

(And libasm.h itself isn't really a public interface itself. You aren't
actually able to initialize an DisasmCtx_t because that needs an Ebl
handle, which is only accessible through internal non-public functions.
Oops.)

> +      code = i.code;
> +      class = BPF_CLASS(code);
> +      op = BPF_OP(code) | BPF_SRC(code);

Do the various BPF_XXX macros clamp the values so that the fmt array
accesses below don't overflow? We don't want crashes even if someone
feeds bogus code (struct bpf_insn) values.

Of course if we have a small BPF testcase ELF file we can always just
run a fuzzer on it to make sure.

Looks good.

Mark

^ permalink raw reply	[flat|nested] 3+ messages in thread

* [PATCH] Add support for BPF
@ 2016-06-03 20:48 Richard Henderson
  0 siblings, 0 replies; 3+ messages in thread
From: Richard Henderson @ 2016-06-03 20:48 UTC (permalink / raw)
  To: elfutils-devel

[-- Attachment #1: Type: text/plain, Size: 21230 bytes --]

I'm using the following to aid in debugging objects similar to what's
produced by the llvm-bpf backend.

(Really, the only change I've made so far is to give the objects a
proper e_machine value.  The stock llvm compiler produces e_machine = 0.
I chose EM_BPF = 0xeb9f, as a sort-of leet-speak spelling of "ebpf".)

The most important part of the patch, for me, is the disassembler,
since there isn't any published tool for that at the moment, much less
one that could take its data out of the object file.  I followed the
dumping code in linux/kernel/bpf/verifier.c in producing C-like output.
(Though the kernel's output for 32-bit ALU ops is ugly so I cleaned
that up, as well as tweaking the signed shift and compare ops.)

What's lacking so far are test cases.  Although there needn't be too
many of those, considering the simplicity of the target.

Signed-off-by: Richard Henderson <rth@redhat.com>
---
 backends/Makefile.am    |  10 +-
 backends/bpf_init.c     |  58 ++++++++++
 backends/bpf_regs.c     |  59 ++++++++++
 backends/bpf_reloc.def  |  31 +++++
 backends/common-reloc.c |   7 +-
 libcpu/Makefile.am      |   5 +-
 libcpu/bpf_disasm.c     | 301 ++++++++++++++++++++++++++++++++++++++++++++++++
 libebl/eblopenbackend.c |   1 +
 libelf/elf.h            |   5 +
 9 files changed, 472 insertions(+), 5 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

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..8ea1bc1
--- /dev/null
+++ b/backends/bpf_init.c
@@ -0,0 +1,58 @@
+/* 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);
+  HOOK (eh, disasm);
+
+  return MODVERSION;
+}
diff --git a/backends/bpf_regs.c b/backends/bpf_regs.c
new file mode 100644
index 0000000..49313ba
--- /dev/null
+++ b/backends/bpf_regs.c
@@ -0,0 +1,59 @@
+/* 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>
+#include <linux/bpf.h>
+
+#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..baceaab
--- /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)
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/libcpu/Makefile.am b/libcpu/Makefile.am
index f0caaea..84050b8 100644
--- a/libcpu/Makefile.am
+++ b/libcpu/Makefile.am
@@ -35,10 +35,13 @@ LEXCOMPILE = $(LEX) $(LFLAGS) $(AM_LFLAGS) -P$(<F:lex.l=)
 LEX_OUTPUT_ROOT = lex.$(<F:lex.l=)
 AM_YFLAGS = -p$(<F:parse.y=)
 
-noinst_LIBRARIES = libcpu_i386.a libcpu_x86_64.a
+noinst_LIBRARIES = libcpu_i386.a libcpu_x86_64.a libcpu_bpf.a
 
 libcpu_i386_a_SOURCES = i386_disasm.c i386_dis.h
 libcpu_x86_64_a_SOURCES = x86_64_disasm.c x86_64_dis.h
+libcpu_bpf_a_SOURCES = bpf_disasm.c
+
+libcpu_bpf_a_CFLAGS = $(AM_CFLAGS) -Wno-format-nonliteral
 
 i386_gendis_SOURCES = i386_gendis.c i386_lex.l i386_parse.y
 
diff --git a/libcpu/bpf_disasm.c b/libcpu/bpf_disasm.c
new file mode 100644
index 0000000..d1b4584
--- /dev/null
+++ b/libcpu/bpf_disasm.c
@@ -0,0 +1,301 @@
+/* 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 "../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",
+  [BPF_ALU64] = "alu64",
+};
+
+static const char size_string[][4] = {
+  [BPF_W >> 3]  = "u32",
+  [BPF_H >> 3]  = "u16",
+  [BPF_B >> 3]  = "u8",
+  [BPF_DW >> 3] = "u64",
+};
+
+/* Dest = 1$, Src = 2$, Imm = 3$.  */
+static const char * const fmt_alu[32] = {
+  [(BPF_ADD  | BPF_K) >> 3] = "r%1$d = (u32)r%1$d + %3$u",
+  [(BPF_SUB  | BPF_K) >> 3] = "r%1$d = (u32)r%1$d - %3$u",
+  [(BPF_MUL  | BPF_K) >> 3] = "r%1$d = (u32)r%1$d * %3$u",
+  [(BPF_DIV  | BPF_K) >> 3] = "r%1$d = (u32)r%1$d / %3$u",
+  [(BPF_OR   | BPF_K) >> 3] = "r%1$d = (u32)r%1$d | %3$u",
+  [(BPF_AND  | BPF_K) >> 3] = "r%1$d = (u32)r%1$d & %3$u",
+  [(BPF_LSH  | BPF_K) >> 3] = "r%1$d = (u32)r%1$d << %3$u",
+  [(BPF_RSH  | BPF_K) >> 3] = "r%1$d = (u32)r%1$d >> %3$u",
+  /* (BPF_NEG  | BPF_K) invalid */
+  [(BPF_MOD  | BPF_K) >> 3] = "r%1$d = (u32)r%1$d % %3$u",
+  [(BPF_XOR  | BPF_K) >> 3] = "r%1$d = (u32)r%1$d ^ %3$u",
+  [(BPF_MOV  | BPF_K) >> 3] = "r%1$d = %3$u",
+  [(BPF_ARSH | BPF_K) >> 3] = "r%1$d = (u32)((s32)r%1$d >> %3$u)",
+  [(BPF_END  | BPF_TO_LE) >> 3] = "r%1$d = le32(r%2$d)",
+
+  [(BPF_ADD  | BPF_X) >> 3] = "r%1$d = (u32)r%1$d + (u32)r%2$d",
+  [(BPF_SUB  | BPF_X) >> 3] = "r%1$d = (u32)r%1$d - (u32)r%2$d",
+  [(BPF_MUL  | BPF_X) >> 3] = "r%1$d = (u32)r%1$d * (u32)r%2$d",
+  [(BPF_DIV  | BPF_X) >> 3] = "r%1$d = (u32)r%1$d / (u32)r%2$d",
+  [(BPF_OR   | BPF_X) >> 3] = "r%1$d = (u32)r%1$d | (u32)r%2$d",
+  [(BPF_AND  | BPF_X) >> 3] = "r%1$d = (u32)r%1$d & (u32)r%2$d",
+  [(BPF_LSH  | BPF_X) >> 3] = "r%1$d = (u32)r%1$d << r%2$d",
+  [(BPF_RSH  | BPF_X) >> 3] = "r%1$d = (u32)r%1$d >> r%2$d",
+  [(BPF_NEG  | BPF_X) >> 3] = "r%1$d = (u32)-r%2$d",
+  [(BPF_MOD  | BPF_X) >> 3] = "r%1$d = (u32)r%1$d % (u32)r%2$d",
+  [(BPF_XOR  | BPF_X) >> 3] = "r%1$d = (u32)r%1$d ^ (u32)r%2$d",
+  [(BPF_MOV  | BPF_X) >> 3] = "r%1$d = (u32)r%2$d",
+  [(BPF_ARSH | BPF_X) >> 3] = "r%1$d = (u32)((s32)r%1$d >> r%2$d)",
+  [(BPF_END  | BPF_TO_BE) >> 3] = "r%1$d = be32(r%2$d)",
+};
+
+static const char * const fmt_alu64[32] = {
+  [(BPF_ADD  | BPF_K) >> 3] = "r%1$d = r%1$d + %3$d",
+  [(BPF_SUB  | BPF_K) >> 3] = "r%1$d = r%1$d - %3$d",
+  [(BPF_MUL  | BPF_K) >> 3] = "r%1$d = r%1$d * %3$d",
+  [(BPF_DIV  | BPF_K) >> 3] = "r%1$d = r%1$d / %3$d",
+  [(BPF_OR   | BPF_K) >> 3] = "r%1$d = r%1$d | %3$d",
+  [(BPF_AND  | BPF_K) >> 3] = "r%1$d = r%1$d & %3$d",
+  [(BPF_LSH  | BPF_K) >> 3] = "r%1$d = r%1$d << %3$d",
+  [(BPF_RSH  | BPF_K) >> 3] = "r%1$d = r%1$d >> %3$d",
+  /* (BPF_NEG  | BPF_K) invalid */
+  [(BPF_MOD  | BPF_K) >> 3] = "r%1$d = r%1$d % %3$d",
+  [(BPF_XOR  | BPF_K) >> 3] = "r%1$d = r%1$d ^ %3$d",
+  [(BPF_MOV  | BPF_K) >> 3] = "r%1$d = %3$d",
+  [(BPF_ARSH | BPF_K) >> 3] = "r%1$d = (s64)r%1$d >> %3$d",
+  [(BPF_END  | BPF_TO_LE) >> 3] = "r%1$d = le64(r%2$d)",
+
+  [(BPF_ADD  | BPF_X) >> 3] = "r%1$d = r%1$d + r%2$d",
+  [(BPF_SUB  | BPF_X) >> 3] = "r%1$d = r%1$d - r%2$d",
+  [(BPF_MUL  | BPF_X) >> 3] = "r%1$d = r%1$d * r%2$d",
+  [(BPF_DIV  | BPF_X) >> 3] = "r%1$d = r%1$d / r%2$d",
+  [(BPF_OR   | BPF_X) >> 3] = "r%1$d = r%1$d | r%2$d",
+  [(BPF_AND  | BPF_X) >> 3] = "r%1$d = r%1$d & r%2$d",
+  [(BPF_LSH  | BPF_X) >> 3] = "r%1$d = r%1$d << r%2$d",
+  [(BPF_RSH  | BPF_X) >> 3] = "r%1$d = r%1$d >> r%2$d",
+  [(BPF_NEG  | BPF_X) >> 3] = "r%1$d = -r%2$d",
+  [(BPF_MOD  | BPF_X) >> 3] = "r%1$d = r%1$d % r%2$d",
+  [(BPF_XOR  | BPF_X) >> 3] = "r%1$d = r%1$d ^ r%2$d",
+  [(BPF_MOV  | BPF_X) >> 3] = "r%1$d = r%2$d",
+  [(BPF_ARSH | BPF_X) >> 3] = "r%1$d = (s64)r%1$d >> r%2$d",
+  [(BPF_END  | BPF_TO_BE) >> 3] = "r%1$d = be64(r%2$d)",
+};
+
+/* Dest = 1$, Src = 2$, Imm = 3$, Jmp = 4$.  */
+static const char * const fmt_jmp[32] = {
+  [(BPF_JA   | BPF_K) >> 3] = "goto %4$x",
+  [(BPF_JEQ  | BPF_K) >> 3] = "if r%1$d == %3$d goto %4$x",
+  [(BPF_JGT  | BPF_K) >> 3] = "if r%1$d > %3$d goto %4$x",
+  [(BPF_JGE  | BPF_K) >> 3] = "if r%1$d >= %3$d goto %4$x",
+  [(BPF_JSET | BPF_K) >> 3] = "if r%1$d & %3$d goto %4$x",
+  [(BPF_JNE  | BPF_K) >> 3] = "if r%1$d != %3$d goto %4$x",
+  [(BPF_JSGT | BPF_K) >> 3] = "if (s64)r%1$d > %3$d goto %4$x",
+  [(BPF_JSGE | BPF_K) >> 3] = "if (s64)r%1$d >= %3$d goto %4$x",
+  [(BPF_CALL | BPF_K) >> 3] = "call %3$d",
+  [(BPF_EXIT | BPF_K) >> 3] = "exit",
+
+  [(BPF_JEQ  | BPF_X) >> 3] = "if r%1$d == r%2$d goto %4$x",
+  [(BPF_JGT  | BPF_X) >> 3] = "if r%1$d > r%2$d goto %4$x",
+  [(BPF_JGE  | BPF_X) >> 3] = "if r%1$d >= r%2$d goto %4$x",
+  [(BPF_JSET | BPF_X) >> 3] = "if r%1$d & r%2$d goto %4$x",
+  [(BPF_JNE  | BPF_X) >> 3] = "if r%1$d != r%2$d goto %4$x",
+  [(BPF_JSGT | BPF_X) >> 3] = "if (s64)r%1$d > (s64)r%2$d goto %4$x",
+  [(BPF_JSGE | BPF_X) >> 3] = "if (s64)r%1$d >= (s64)r%2$d goto %4$x",
+};
+
+int
+bpf_disasm (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 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, op;
+      const char *op_str;
+
+      memcpy(&i, start, sizeof(struct bpf_insn));
+      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;
+      class = BPF_CLASS(code);
+      op = BPF_OP(code) | BPF_SRC(code);
+      len = -1;
+
+      switch (class)
+	{
+	case BPF_ALU:
+	  op_str = fmt_alu[op >> 3];
+	  goto do_alu;
+	case BPF_ALU64:
+	  op_str = fmt_alu64[op >> 3];
+	do_alu:
+	  if (op_str)
+	    len = snprintf(buf, sizeof(buf), op_str,
+			   i.dst_reg, i.src_reg, i.imm);
+	  break;
+
+	case BPF_STX:
+	  op_str = size_string[BPF_SIZE(code) >> 3];
+	  switch (BPF_MODE(code))
+	    {
+	    case BPF_MEM:
+	      len = snprintf(buf, sizeof(buf),
+			     "*(%s *)(r%d%+d) = r%d",
+			     op_str, i.dst_reg, i.off, i.src_reg);
+	      break;
+
+	    case BPF_XADD:
+	      len = snprintf(buf, sizeof(buf),
+			     "lock *(%s *)(r%d%+d) += r%d",
+			     op_str, i.dst_reg, i.off, i.src_reg);
+	      break;
+	    }
+	  break;
+
+	case BPF_ST:
+	  if (BPF_MODE(code) == BPF_MEM)
+	    {
+	      op_str = size_string[BPF_SIZE(code) >> 3];
+	      len = snprintf(buf, sizeof(buf),
+			     "*(%s *)(r%d%+d) = %d",
+			     op_str, i.dst_reg, i.off, i.imm);
+	    }
+	  break;
+
+	case BPF_LDX:
+	  if (BPF_MODE(code) == BPF_MEM)
+	    {
+	      op_str = size_string[BPF_SIZE(code) >> 3];
+	      len = snprintf(buf, sizeof(buf),
+			     "r%d = *(%s *)(r%d%+d)",
+			     i.dst_reg, op_str, i.src_reg, i.off);
+	    }
+	  break;
+
+	case BPF_LD:
+	  op_str = size_string[BPF_SIZE(code) >> 3];
+	  switch (BPF_MODE(code))
+	    {
+	    case BPF_ABS:
+	      len = snprintf(buf, sizeof(buf),
+			     "r0 = *(%s *)skb[%d]",
+			     op_str, i.imm);
+	      break;
+
+	    case BPF_IND:
+	      len = snprintf(buf, sizeof(buf),
+			     "r0 = *(%s *)skb[r%d%+d]",
+			     op_str, i.src_reg, i.imm);
+	      break;
+
+	    case BPF_IMM:
+	      if (BPF_SIZE(code) == 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));
+		  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:
+		      len = snprintf(buf, sizeof(buf),
+				     "r%d = %#" PRIx64, i.dst_reg, imm64);
+		      break;
+		    case BPF_PSEUDO_MAP_FD:
+		      len = snprintf(buf, sizeof(buf),
+				     "r%d = map_fd", i.dst_reg);
+		      break;
+		    }
+                }
+	      break;
+	    }
+	  break;
+
+	case BPF_JMP:
+	  op_str = fmt_jmp[op >> 3];
+	  if (op_str)
+	    {
+	      unsigned jmp = addr + i.off * sizeof(struct bpf_insn);
+	      len = snprintf(buf, sizeof(buf), op_str,
+			     i.dst_reg, i.src_reg, i.imm, jmp);
+	    }
+	  break;
+	}
+      if (len < 0)
+	{
+	  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/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/libelf/elf.h b/libelf/elf.h
index ce96bd5..2db03c3 100644
--- a/libelf/elf.h
+++ b/libelf/elf.h
@@ -261,6 +261,7 @@ typedef struct
    chances of collision with official or non-GNU unofficial values.  */
 
 #define EM_ALPHA	0x9026
+#define EM_BPF		0xeb9f
 
 /* Legal values for e_version (version).  */
 
@@ -3566,6 +3567,10 @@ enum
 
 #define R_TILEGX_NUM		130
 
+/* BPF specific declarations.  */
+
+#define R_BPF_NONE		0	/* No reloc */
+#define R_BPF_MAP_FD		1	/* Map fd to pointer */
 
 __END_DECLS
 
-- 
2.5.5

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2016-06-08 16:11 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-06-08 16:11 [PATCH] Add support for BPF Richard Henderson
  -- strict thread matches above, loose matches on Subject: below --
2016-06-07 13:19 Mark Wielaard
2016-06-03 20:48 Richard Henderson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).