[PATCH] Add support for m68k
by Andreas Schwab
Signed-off-by: Andreas Schwab <schwab(a)linux-m68k.org>
---
backends/ChangeLog | 14 +++++
backends/Makefile.am | 10 ++-
backends/linux-core-note.c | 4 +-
backends/m68k_corenote.c | 71 +++++++++++++++++++++
backends/m68k_init.c | 60 ++++++++++++++++++
backends/m68k_regs.c | 96 ++++++++++++++++++++++++++++
backends/m68k_reloc.def | 70 +++++++++++++++++++++
backends/m68k_retval.c | 153 +++++++++++++++++++++++++++++++++++++++++++++
backends/m68k_symbol.c | 70 +++++++++++++++++++++
libebl/ChangeLog | 4 ++
libebl/eblopenbackend.c | 2 +-
11 files changed, 550 insertions(+), 4 deletions(-)
create mode 100644 backends/m68k_corenote.c
create mode 100644 backends/m68k_init.c
create mode 100644 backends/m68k_regs.c
create mode 100644 backends/m68k_reloc.def
create mode 100644 backends/m68k_retval.c
create mode 100644 backends/m68k_symbol.c
diff --git a/backends/ChangeLog b/backends/ChangeLog
index cf70a52..afda37a 100644
--- a/backends/ChangeLog
+++ b/backends/ChangeLog
@@ -1,3 +1,17 @@
+2016-05-20 Andreas Schwab <schwab(a)linux-m68k.org>
+
+ * Makefile.am (modules): Add m68k.
+ (libebl_pic): Add libebl_m68k_pic.a.
+ (m68k_SRCS, libebl_m68k_pic_a_SOURCES)
+ (am_libebl_m68k_pic_a_OBJECTS): Define.
+ * m68k_init.c: New file.
+ * m68k_symbol.c: New file.
+ * m68k_regs.c: New file.
+ * m68k_retval.c: New file.
+ * m68k_corenote.c: New file.
+ * m68k_reloc.def: New file.
+ * linux-core-note.c (ALIGN_INT): Only define if not defined.
+
2016-02-26 Jose E. Marchesi <jose.marchesi(a)oracle.com>
* sparc_initreg.c (EBLHOOK): Provide a dummy
diff --git a/backends/Makefile.am b/backends/Makefile.am
index b16f948..bf52391 100644
--- a/backends/Makefile.am
+++ b/backends/Makefile.am
@@ -33,11 +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
+ tilegx m68k
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_ppc64_pic.a libebl_s390_pic.a libebl_tilegx_pic.a \
+ libebl_m68k_pic.a
noinst_LIBRARIES = $(libebl_pic)
noinst_DATA = $(libebl_pic:_pic.a=.so)
@@ -112,6 +113,11 @@ tilegx_SRCS = tilegx_init.c tilegx_symbol.c tilegx_regs.c \
libebl_tilegx_pic_a_SOURCES = $(tilegx_SRCS)
am_libebl_tilegx_pic_a_OBJECTS = $(tilegx_SRCS:.c=.os)
+m68k_SRCS = m68k_init.c m68k_symbol.c m68k_regs.c \
+ m68k_retval.c m68k_corenote.c
+libebl_m68k_pic_a_SOURCES = $(m68k_SRCS)
+am_libebl_m68k_pic_a_OBJECTS = $(m68k_SRCS:.c=.os)
+
libebl_%.so libebl_%.map: libebl_%_pic.a $(libelf) $(libdw)
@rm -f $(@:.so=.map)
diff --git a/backends/linux-core-note.c b/backends/linux-core-note.c
index ff2b226..c00c0b1 100644
--- a/backends/linux-core-note.c
+++ b/backends/linux-core-note.c
@@ -41,7 +41,9 @@
#define ALIGN_SHORT 2
#define TYPE_SHORT ELF_T_HALF
#define INT int32_t
-#define ALIGN_INT 4
+#ifndef ALIGN_INT
+# define ALIGN_INT 4
+#endif
#define TYPE_INT ELF_T_SWORD
#ifndef PR_REG
# define PR_REG ULONG
diff --git a/backends/m68k_corenote.c b/backends/m68k_corenote.c
new file mode 100644
index 0000000..e839edf
--- /dev/null
+++ b/backends/m68k_corenote.c
@@ -0,0 +1,71 @@
+/* M68K specific core note handling.
+ 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 <elf.h>
+#include <inttypes.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <sys/time.h>
+
+#define BACKEND m68k_
+#include "libebl_CPU.h"
+
+static const Ebl_Register_Location prstatus_regs[] =
+ {
+ { .offset = 0, .regno = 1, .count = 14, .bits = 32 }, /* d1-d7, a0-a6 */
+ { .offset = 14 * 4, .regno = 0, .count = 1, .bits = 32 }, /* d0 */
+ { .offset = 15 * 4, .regno = 15, .count = 1, .bits = 32 }, /* a7 */
+ { .offset = 18 * 4, .regno = 24, .count = 1, .bits = 32 } /* pc */
+ };
+#define PRSTATUS_REGS_SIZE (20 * 4)
+
+#define ULONG uint32_t
+#define PID_T int32_t
+#define UID_T uint16_t
+#define GID_T uint16_t
+#define ALIGN_INT 2
+#define ALIGN_ULONG 2
+#define ALIGN_PID_T 2
+#define ALIGN_UID_T 2
+#define ALIGN_GID_T 2
+#define TYPE_ULONG ELF_T_WORD
+#define TYPE_PID_T ELF_T_SWORD
+#define TYPE_UID_T ELF_T_HALF
+#define TYPE_GID_T ELF_T_HALF
+
+static const Ebl_Register_Location fpregset_regs[] =
+ {
+ { .offset = 0, .regno = 16, .count = 8, .bits = 96 }, /* fp0-fp7 */
+ };
+#define FPREGSET_SIZE (27 * 4)
+
+#include "linux-core-note.c"
diff --git a/backends/m68k_init.c b/backends/m68k_init.c
new file mode 100644
index 0000000..943478f
--- /dev/null
+++ b/backends/m68k_init.c
@@ -0,0 +1,60 @@
+/* Initialization of M68K 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 m68k_
+#define RELOC_PREFIX R_68K_
+#include "libebl_CPU.h"
+
+/* This defines the common reloc hooks based on m68k_reloc.def. */
+#include "common-reloc.c"
+
+
+const char *
+m68k_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 = "M68K";
+ m68k_init_reloc (eh);
+ HOOK (eh, gotpc_reloc_check);
+ HOOK (eh, reloc_simple_type);
+ HOOK (eh, return_value_location);
+ HOOK (eh, register_info);
+ HOOK (eh, core_note);
+
+ return MODVERSION;
+}
diff --git a/backends/m68k_regs.c b/backends/m68k_regs.c
new file mode 100644
index 0000000..cb99f55
--- /dev/null
+++ b/backends/m68k_regs.c
@@ -0,0 +1,96 @@
+/* Register names and numbers for M68K 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 <dwarf.h>
+
+#define BACKEND m68k_
+#include "libebl_CPU.h"
+
+ssize_t
+m68k_register_info (Ebl *ebl __attribute__ ((unused)),
+ int regno, char *name, size_t namelen,
+ const char **prefix, const char **setname,
+ int *bits, int *type)
+{
+ if (name == NULL)
+ return 25;
+
+ if (regno < 0 || regno > 24 || namelen < 5)
+ return -1;
+
+ *prefix = "%";
+ *setname = "integer";
+ *bits = 32;
+
+ switch (regno)
+ {
+ case 0 ... 7:
+ *type = DW_ATE_signed;
+ name[0] = 'd';
+ name[1] = regno + '0';
+ namelen = 2;
+ break;
+
+ case 8 ... 15:
+ *type = DW_ATE_address;
+ name[0] = 'a';
+ name[1] = regno - 8 + '0';
+ namelen = 2;
+ break;
+
+ case 16 ... 23:
+ *type = DW_ATE_float;
+ *setname = "FPU";
+ *bits = 96;
+ name[0] = 'f';
+ name[1] = 'p';
+ name[2] = regno - 16 + '0';
+ namelen = 3;
+ break;
+
+ case 24:
+ *type = DW_ATE_address;
+ name[0] = 'p';
+ name[1] = 'c';
+ namelen = 2;
+ break;
+
+ /* Can't happen. */
+ default:
+ *setname = NULL;
+ return 0;
+ }
+
+ name[namelen++] = '\0';
+ return namelen;
+}
diff --git a/backends/m68k_reloc.def b/backends/m68k_reloc.def
new file mode 100644
index 0000000..b7cc4df
--- /dev/null
+++ b/backends/m68k_reloc.def
@@ -0,0 +1,70 @@
+/* List the relocation types for m68k. -*- 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 (32, REL|EXEC|DYN)
+RELOC_TYPE (16, REL|EXEC|DYN)
+RELOC_TYPE (8, REL|EXEC|DYN)
+RELOC_TYPE (PC32, REL|EXEC|DYN)
+RELOC_TYPE (PC16, REL|EXEC|DYN)
+RELOC_TYPE (PC8, REL|EXEC|DYN)
+RELOC_TYPE (GOT32, REL)
+RELOC_TYPE (GOT16, REL)
+RELOC_TYPE (GOT8, REL)
+RELOC_TYPE (GOT32O, REL)
+RELOC_TYPE (GOT16O, REL)
+RELOC_TYPE (GOT8O, REL)
+RELOC_TYPE (PLT32, REL)
+RELOC_TYPE (PLT16, REL)
+RELOC_TYPE (PLT8, REL)
+RELOC_TYPE (PLT32O, REL)
+RELOC_TYPE (PLT16O, REL)
+RELOC_TYPE (PLT8O, REL)
+RELOC_TYPE (COPY, EXEC|DYN)
+RELOC_TYPE (GLOB_DAT, EXEC|DYN)
+RELOC_TYPE (JMP_SLOT, EXEC|DYN)
+RELOC_TYPE (RELATIVE, EXEC|DYN)
+RELOC_TYPE (TLS_GD32, REL)
+RELOC_TYPE (TLS_GD16, REL)
+RELOC_TYPE (TLS_GD8, REL)
+RELOC_TYPE (TLS_LDM32, REL)
+RELOC_TYPE (TLS_LDM16, REL)
+RELOC_TYPE (TLS_LDM8, REL)
+RELOC_TYPE (TLS_LDO32, REL)
+RELOC_TYPE (TLS_LDO16, REL)
+RELOC_TYPE (TLS_LDO8, REL)
+RELOC_TYPE (TLS_IE32, REL)
+RELOC_TYPE (TLS_IE16, REL)
+RELOC_TYPE (TLS_IE8, REL)
+RELOC_TYPE (TLS_LE32, REL)
+RELOC_TYPE (TLS_LE16, REL)
+RELOC_TYPE (TLS_LE8, REL)
+RELOC_TYPE (TLS_DTPMOD32, EXEC|DYN)
+RELOC_TYPE (TLS_DTPREL32, EXEC|DYN)
+RELOC_TYPE (TLS_TPREL32, EXEC|DYN)
diff --git a/backends/m68k_retval.c b/backends/m68k_retval.c
new file mode 100644
index 0000000..2dd285a
--- /dev/null
+++ b/backends/m68k_retval.c
@@ -0,0 +1,153 @@
+/* Function return value location for Linux/m68k ABI.
+ 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 <dwarf.h>
+
+#define BACKEND m68k_
+#include "libebl_CPU.h"
+
+
+/* %d0, or pair %d0, %d1. */
+static const Dwarf_Op loc_intreg[] =
+ {
+ { .atom = DW_OP_reg0 }, { .atom = DW_OP_piece, .number = 4 },
+ { .atom = DW_OP_reg1 }, { .atom = DW_OP_piece, .number = 4 },
+ };
+#define nloc_intreg 1
+#define nloc_intregpair 4
+
+/* %a0. */
+static const Dwarf_Op loc_ptrreg[] =
+ {
+ { .atom = DW_OP_reg8 }
+ };
+#define nloc_ptrreg 1
+
+/* %fp0. */
+static const Dwarf_Op loc_fpreg[] =
+ {
+ { .atom = DW_OP_reg16 }
+ };
+#define nloc_fpreg 1
+
+/* The return value is a structure and is actually stored in stack space
+ passed in a hidden argument by the caller. But, the compiler
+ helpfully returns the address of that space in %a0. */
+static const Dwarf_Op loc_aggregate[] =
+ {
+ { .atom = DW_OP_reg8 }
+ };
+#define nloc_aggregate 1
+
+int
+m68k_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp)
+{
+ /* Start with the function's type, and get the DW_AT_type attribute,
+ which is the type of the return value. */
+ Dwarf_Die die_mem, *typedie = &die_mem;
+ int tag = dwarf_peeled_die_type (functypedie, typedie);
+ if (tag <= 0)
+ return tag;
+
+ switch (tag)
+ {
+ case -1:
+ return -1;
+
+ case DW_TAG_subrange_type:
+ if (! dwarf_hasattr_integrate (typedie, DW_AT_byte_size))
+ {
+ Dwarf_Attribute attr_mem, *attr;
+ attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem);
+ typedie = dwarf_formref_die (attr, &die_mem);
+ tag = DWARF_TAG_OR_RETURN (typedie);
+ }
+ /* Fall through. */
+
+ case DW_TAG_base_type:
+ case DW_TAG_enumeration_type:
+ case DW_TAG_pointer_type:
+ case DW_TAG_ptr_to_member_type:
+ {
+ Dwarf_Word size;
+ Dwarf_Attribute attr_mem;
+ if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size,
+ &attr_mem), &size) != 0)
+ {
+ if (tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type)
+ size = 4;
+ else
+ return -1;
+ }
+ if (tag == DW_TAG_base_type)
+ {
+ Dwarf_Word encoding;
+ if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding,
+ &attr_mem),
+ &encoding) != 0)
+ return -1;
+ if (encoding == DW_ATE_float)
+ {
+ if (size > 12)
+ return -2;
+ *locp = loc_fpreg;
+ return nloc_fpreg;
+ }
+ }
+ if (tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type)
+ {
+ *locp = loc_ptrreg;
+ return nloc_ptrreg;
+ }
+ *locp = loc_intreg;
+ if (size <= 4)
+ return nloc_intreg;
+ if (size <= 8)
+ return nloc_intregpair;
+
+ /* Else fall through. */
+ }
+
+ case DW_TAG_structure_type:
+ case DW_TAG_class_type:
+ case DW_TAG_union_type:
+ case DW_TAG_array_type:
+ *locp = loc_aggregate;
+ return nloc_aggregate;
+ }
+
+ /* XXX We don't have a good way to return specific errors from ebl calls.
+ This value means we do not understand the type, but it is well-formed
+ DWARF and might be valid. */
+ return -2;
+}
diff --git a/backends/m68k_symbol.c b/backends/m68k_symbol.c
new file mode 100644
index 0000000..269d12e
--- /dev/null
+++ b/backends/m68k_symbol.c
@@ -0,0 +1,70 @@
+/* m68k specific symbolic name handling.
+ 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 <elf.h>
+#include <stddef.h>
+#include <string.h>
+
+#define BACKEND m68k_
+#include "libebl_CPU.h"
+
+
+/* Return true if the symbol type is that referencing the GOT. */
+bool
+m68k_gotpc_reloc_check (Elf *elf __attribute__ ((unused)), int type)
+{
+ switch (type)
+ {
+ case R_68K_GOT32:
+ case R_68K_GOT16:
+ case R_68K_GOT8:
+ return true;
+ }
+ return false;
+}
+
+/* Check for the simple reloc types. */
+Elf_Type
+m68k_reloc_simple_type (Ebl *ebl __attribute__ ((unused)), int type)
+{
+ switch (type)
+ {
+ case R_68K_32:
+ return ELF_T_SWORD;
+ case R_68K_16:
+ return ELF_T_HALF;
+ case R_68K_8:
+ return ELF_T_BYTE;
+ default:
+ return ELF_T_NUM;
+ }
+}
diff --git a/libebl/ChangeLog b/libebl/ChangeLog
index 26a4f94..97a9b89 100644
--- a/libebl/ChangeLog
+++ b/libebl/ChangeLog
@@ -1,3 +1,7 @@
+2016-05-20 Andreas Schwab <schwab(a)linux-m68k.org>
+
+ * eblopenbackend.c (machines) [EM_68K]: Set class and data.
+
2016-02-12 Mark Wielaard <mjw(a)redhat.com>
* eblobjnotetypename.c (ebl_object_note_type_name): Check name is
diff --git a/libebl/eblopenbackend.c b/libebl/eblopenbackend.c
index 372ef2a..2b92254 100644
--- a/libebl/eblopenbackend.c
+++ b/libebl/eblopenbackend.c
@@ -73,7 +73,7 @@ static const struct
{ "s390", "ebl_s390", "s390", 4, EM_S390, 0, 0 },
{ "m32", "elf_m32", "m32", 3, EM_M32, 0, 0 },
- { "m68k", "elf_m68k", "m68k", 4, EM_68K, 0, 0 },
+ { "m68k", "elf_m68k", "m68k", 4, EM_68K, ELFCLASS32, ELFDATA2MSB },
{ "m88k", "elf_m88k", "m88k", 4, EM_88K, 0, 0 },
{ "i860", "elf_i860", "i860", 4, EM_860, 0, 0 },
{ "s370", "ebl_s370", "s370", 4, EM_S370, 0, 0 },
--
2.8.3
--
Andreas Schwab, schwab(a)linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756 01D3 44D5 214B 8276 4ED5
"And now for something completely different."
7 years, 4 months
[PATCH] libelf: find 1st section instead of assuming
by John Ogness
When getting section headers it is assumed that the first section
is on the first section list. However, it is possible that the
first section list only contains the zeroth section, in which
case either illegal memory access occurs or elf_nextscn()
erroneously returns NULL.
With this patch, checks are added to avoid the illegal memory
access and (if available) the second section list is looked at
to find the first section.
Signed-off-by: John Ogness <john.ogness(a)linutronix.de>
---
libelf/elf32_updatenull.c | 11 +++++++++--
libelf/elf_nextscn.c | 38 +++++++++++++++++---------------------
2 files changed, 26 insertions(+), 23 deletions(-)
diff --git a/libelf/elf32_updatenull.c b/libelf/elf32_updatenull.c
index 03de032..7507062 100644
--- a/libelf/elf32_updatenull.c
+++ b/libelf/elf32_updatenull.c
@@ -180,6 +180,7 @@ __elfw2(LIBELFBITS,updatenull_wrlock) (Elf *elf, int *change_bop, size_t shnum)
if (shnum > 0)
{
+ struct Elf_Scn *scn1 = NULL;
Elf_ScnList *list;
bool first = true;
@@ -198,10 +199,16 @@ __elfw2(LIBELFBITS,updatenull_wrlock) (Elf *elf, int *change_bop, size_t shnum)
/* Go over all sections and find out how large they are. */
list = &elf->state.ELFW(elf,LIBELFBITS).scns;
+ /* Find the first section. */
+ if (list->cnt > 1)
+ scn1 = &list->data[1];
+ else if (list->next != NULL)
+ scn1 = &list->next->data[0];
+
/* Load the section headers if necessary. This loads the
headers for all sections. */
- if (list->data[1].shdr.ELFW(e,LIBELFBITS) == NULL)
- (void) __elfw2(LIBELFBITS,getshdr_wrlock) (&list->data[1]);
+ if (scn1 != NULL && scn1->shdr.ELFW(e,LIBELFBITS) == NULL)
+ (void) __elfw2(LIBELFBITS,getshdr_wrlock) (scn1);
do
{
diff --git a/libelf/elf_nextscn.c b/libelf/elf_nextscn.c
index 62cb891..d2f3e7c 100644
--- a/libelf/elf_nextscn.c
+++ b/libelf/elf_nextscn.c
@@ -41,6 +41,7 @@
Elf_Scn *
elf_nextscn (Elf *elf, Elf_Scn *scn)
{
+ Elf_ScnList *list;
Elf_Scn *result = NULL;
if (elf == NULL)
@@ -50,34 +51,29 @@ elf_nextscn (Elf *elf, Elf_Scn *scn)
if (scn == NULL)
{
- /* If no section handle is given return the first (not 0th) section. */
+ /* If no section handle is given return the first (not 0th) section.
+ Set scn to the 0th section and perform nextscn. */
if (elf->class == ELFCLASS32
|| (offsetof (Elf, state.elf32.scns)
== offsetof (Elf, state.elf64.scns)))
- {
- if (elf->state.elf32.scns.cnt > 1)
- result = &elf->state.elf32.scns.data[1];
- }
+ list = &elf->state.elf32.scns;
else
- {
- if (elf->state.elf64.scns.cnt > 1)
- result = &elf->state.elf64.scns.data[1];
- }
+ list = &elf->state.elf64.scns;
+
+ scn = &list->data[0];
}
else
+ list = scn->list;
+
+ if (scn + 1 < &list->data[list->cnt])
+ result = scn + 1;
+ else if (scn + 1 == &list->data[list->max]
+ && (list = list->next) != NULL)
{
- Elf_ScnList *list = scn->list;
-
- if (scn + 1 < &list->data[list->cnt])
- result = scn + 1;
- else if (scn + 1 == &list->data[list->max]
- && (list = list->next) != NULL)
- {
- /* If there is another element in the section list it must
- have at least one entry. */
- assert (list->cnt > 0);
- result = &list->data[0];
- }
+ /* If there is another element in the section list it must
+ have at least one entry. */
+ assert (list->cnt > 0);
+ result = &list->data[0];
}
rwlock_unlock (elf->lock);
--
2.8.1
7 years, 5 months
[PATCH v2 0/2] Add support for BPF
by Richard Henderson
Changes since v2:
(1) We've got an official number for EM_BPF,
(2) A disassembly test case,
(3) Added a configure test for <linux/bpf.h>,
(4) Byte swapping of bpf_insns during disassembly,
(5) ChangeLog entries.
I've tested 2-4 with a ppc64 Fedora 20 host, which doesn't natively
have <linux/bpf.h>. I then forced configure to find the header I
copied over to the machine and re-tested to see that the little-endian
disassembly test case works properly with the big-endian host.
r~
Richard Henderson (2):
Sync elf.h from glibc
Add support for BPF
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 +
libelf/ChangeLog | 4 +
libelf/elf.h | 281 +++++++++++++++++++++++++-----------
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
26 files changed, 786 insertions(+), 93 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
--
2.5.5
7 years, 5 months
[PATCH][SPARC] Fix GNU_Sparc_HWCAPS and GNU_Sparc_HWCAPS2 tag values
by Jose E. Marchesi
Hi people! Just a little patch to make readelf -A to print a nice list
of comma-separated hwcap names, instead of rubbish :)
2016-06-08 Jose E. Marchesi <jose.marchesi(a)oracle.com>
* sparc_attrs.c (sparc_check_object_attribute): Fix the
calculation of GNU_Sparc_HWCAPS and GNU_Sparc_HWCAPS2 tags values.
diff --git a/backends/sparc_attrs.c b/backends/sparc_attrs.c
index e95b577..505a01d 100644
--- a/backends/sparc_attrs.c
+++ b/backends/sparc_attrs.c
@@ -41,33 +41,60 @@ sparc_check_object_attribute (Ebl *ebl __attribute__ ((unused)),
const char *vendor, int tag, uint64_t value,
const char **tag_name, const char **value_name)
{
+ static const char *hwcaps[30] =
+ {
+ "mul32", "div32", "fsmuld", "v8plus", "popc", "vis", "vis2",
+ "asi_blk_init", "fmaf", NULL, "vis3", "hpc", "random", "trans", "fjfmau",
+ "ima", "asi_cache_sparing", "aes", "des", "kasumi", "camellia",
+ "md5", "sha1", "sha256", "sha512", "mpmul", "mont", "pause",
+ "cbcond", "crc32c"
+ };
+
+ static const char *hwcaps2[11] =
+ {
+ "fjathplus", "vis3b", "adp", "sparc5", "mwait", "xmpmul",
+ "xmont", "nsec", "fjathhpc", "fjdes", "fjaes"
+ };
+
+ /* NAME must be large enough to contain up to N comma-separated list
+ of atributes in the arrays defined above. */
+ static char name [30 * 16 + 30];
+ name[0] = '\0';
+
if (!strcmp (vendor, "gnu"))
switch (tag)
{
case 4:
- *tag_name = "GNU_Sparc_HWCAPS";
- static const char *hwcaps[30] =
- {
- "mul32", "div32", "fsmuld", "v8plus", "popc", "vis", "vis2",
- "asi_blk_init", "fmaf", NULL, "vis3", "hpc", "random", "trans", "fjfmau",
- "ima", "asi_cache_sparing", "aes", "des", "kasumi", "camellia",
- "md5", "sha1", "sha256", "sha512", "mpmul", "mont", "pause",
- "cbcond", "crc32c"
- };
- if (value < 30 && hwcaps[value] != NULL)
- *value_name = hwcaps[value];
- return true;
-
case 8:
- *tag_name = "GNU_Sparc_HWCAPS2";
- static const char *hwcaps2[11] =
- {
- "fjathplus", "vis3b", "adp", "sparc5", "mwait", "xmpmul",
- "xmont", "nsec", "fjathhpc", "fjdes", "fjaes"
- };
- if (value < 11)
- *value_name = hwcaps2[value];
- return true;
+ {
+ const char **caps;
+ int cap;
+
+ if (tag == 4)
+ {
+ *tag_name = "GNU_Sparc_HWCAPS";
+ caps = hwcaps;
+ cap = sizeof (hwcaps) / sizeof (hwcaps[0]);
+ }
+ else
+ {
+ *tag_name = "GNU_Sparc_HWCAPS2";
+ caps = hwcaps2;
+ cap = sizeof (hwcaps2) / sizeof (hwcaps2[0]);
+ }
+
+ char *s = name;
+ for (cap--; cap >= 0; cap--)
+ if (value & (1 << cap))
+ {
+ if (*s != '\0')
+ s = strcat (s, ",");
+ s = strcat (s, caps[cap]);
+ }
+
+ *value_name = s;
+ return true;
+ }
}
return false;
7 years, 5 months
example for using libdw(fl) for in-process stack unwinding?
by Milian Wolff
Hey all,
from [1] I got that libdw(fl) can be used for unwinding as an alternative to
libunwind, i.e. `dwfl_getthread_frames()`. Apparently, it is even considerably
faster in the context of Linux perf. I'd like to try that out and compare it
to libunwind in the context of my heaptrack tracer.
[1]: https://lwn.net/Articles/579508/
But, so far, I could not find an example for using libdw(fl) for in-process
stack unwinding. All examples I can find out there use libunwind for the
unwinding and libdw only for the DWARF debug information interpretation.
I've tried my shot at implementing a trivial example around
`dwfl_getthread_frames` but struggle with the API a lot. It is quite involved,
contrary to a simple `unw_backtrace`, or even to the manual stepping with
libunwind over the `unw_local_addr_space`. The documentation of libdw(fl)
often refers to terms that I have no clue about as I'm not deeply acquainted
with the DWARF and ELF specs. Problems I'm facing are:
- Am I correct in assuming that in-process is the opposite of "offline use"
referred to in the libdwfl API documentation?
* If so, what should I set `Dwfl_Callbacks::section_address` to?
- How do I attach state in-process? `dwfl_attach_state` sounds like the
correct choice, as `dwfl_linux_proc_attach` mentions ptrace which I don't
want/need. So, assuming it's `dwfl_attach_state`:
What is the correct way to get an `Elf *` for my current executable? Do I
really `open("/proc/self/exe")` and pass that to `elf_begin`? What Elf_Cmd
should I use? ELF_C_READ?
How should the obligatory callbacks of Dwfl_Thread_Callbacks be implemented?
* next_thread: I'm only interested in the current thread, so doing something
similar to perf should be possible here
* memory_read: just cast the address to a pointer and dereference it?
* set_initial_registers: no clue, really
Is there an easy-to-grasp example out there somewhere for me to follow on how
to use libdw(fl) for in-process stack unwinding? For reference, here's my
current non-functional attempt, which you can compile with
g++ -ldw -lelf -std=c++11 -g -O0 backtrace.cpp -o backtrace
~~~~~~~~~~~~~~~~~~~~~~~
#define PACKAGE
#define PACKAGE_VERSION
#include <elfutils/libdw.h>
#include <elfutils/libdwfl.h>
#include <unistd.h>
#include <cassert>
#include <fcntl.h>
namespace dw {
static const Dwfl_Callbacks offline_callbacks = {
dwfl_build_id_find_elf,
dwfl_standard_find_debuginfo,
// TODO: we are in-process, not offline, or?
dwfl_offline_section_address,
nullptr,
};
bool set_initial_registers(Dwfl_Thread *thread, void *arg)
{
// TODO: what to do here?
return true;
}
static pid_t next_thread(Dwfl *dwfl, void *arg, void **thread_argp)
{
// TODO: what to do here? Code below is copied from perf, probably
wrong here
/* We want only single thread to be processed. */
if (*thread_argp != NULL)
return 0;
*thread_argp = arg;
return dwfl_pid(dwfl);
}
static bool memory_read(Dwfl *dwfl, Dwarf_Addr addr, Dwarf_Word *result,
void *arg)
{
// TODO: what to do here? We are in-process, so can we just do the
following?
*result = *reinterpret_cast<Dwarf_Word*>(addr);
return true;
}
static const Dwfl_Thread_Callbacks callbacks = {
next_thread,
nullptr,
memory_read,
set_initial_registers,
nullptr,
nullptr
};
int frame_callback(Dwfl_Frame* frame, void* data)
{
return DWARF_CB_OK;
}
void backtrace()
{
auto dwfl = dwfl_begin(&offline_callbacks);
fprintf(stderr, "%d: %d = %s\n", __LINE__, dwfl_errno(),
dwfl_errmsg(dwfl_errno()));
assert(dwfl);
// TODO: thread specific pid?
auto pid = getpid();
// TODO: is this the correct way to get the Elf*?
auto fd = open("/proc/self/exe", O_RDONLY);
auto elf = elf_begin(fd, ELF_C_READ_MMAP, nullptr);
bool attached = dwfl_attach_state(dwfl, elf, pid, &callbacks,
nullptr);
fprintf(stderr, "%d: %d = %s\n", __LINE__, dwfl_errno(),
dwfl_errmsg(dwfl_errno()));
assert(attached);
auto ret = dwfl_getthread_frames(dwfl, pid, &frame_callback, nullptr);
fprintf(stderr, "%d: %d = %s\n", __LINE__, dwfl_errno(),
dwfl_errmsg(dwfl_errno()));
assert(ret == 0);
dwfl_end(dwfl);
}
}
void a()
{
dw::backtrace();
}
void b()
{
a();
}
void c()
{
b();
}
int main()
{
c();
return 0;
}
~~~~~~~~~~~~~~~~~~~~
The output I get is:
62: 0 = (null)
73: 0 = (null)
77: 0 = No DWARF information found
backtrace: backtrace.cpp:78: void dw::backtrace(): Assertion `ret == 0'
failed.
Any help appreciated, thanks.
--
Milian Wolff
mail(a)milianw.de
http://milianw.de
7 years, 5 months
[PATCH] Add support for BPF
by Richard Henderson
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(a)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
7 years, 6 months