Re: [PATCH V6 2/3] sim: eBPF simulator

Andrew Burgess
2020-08-04T14:50:34Z

* Jose E. Marchesi via Gdb-patches <gdb-patches@sourceware.org> [2020-08-03 16:02:36 +0200]:

> This patch introduces the basics of an instruction-simulator for eBPF.
> The simulator is based on CGEN.
>
> sim/ChangeLog:
>
> 2020-08-03 Jose E. Marchesi <jose.marchesi@oracle.com>
> David Faust <david.faust@oracle.com>
>
> * configure.tgt (sim_arch): Add entry for bpf-*-*.
> * configure: Regenerate.
> * MAINTAINERS: Add maintainer for the BPF simulator.
> * bpf/Makefile.in: New file.
> * bpf/bpf-helpers.c: Likewise.
> * bpf/bpf-helpers.def: Likewise.
> * bpf/bpf-helpers.h: Likewise.
> * bpf/bpf-sim.h: Likewise.
> * bpf/bpf.c: Likewise.
> * bpf/config.in: Likewise.
> * bpf/configure.ac: Likewise.

You need to regenerate bpf/configure and commit it.

> * bpf/decode.h: Likewise.
> * bpf/eng.h: Likewise.
> * bpf/mloop.in: Likewise.
> * bpf/sim-if.c: Likewise.
> * bpf/sim-main.h: Likewise.
> * bpf/traps.c: Likewise.
> * bpf/configure: Generate.
> * bpf/aclocal.m4: Likewise.
>
> sim/testsuite/ChangeLog:
>
> 2020-08-03 David Faust <david.faust@oracle.com>
> Jose E. Marchesi <jose.marchesi@oracle.com>
>
> * configure: Regenerate.
> * sim/bpf/allinsn.exp: New file.
> * sim/bpf/alu.s: Likewise.
> * sim/bpf/alu32.s: Likewise.
> * sim/bpf/endbe.s: Likewise.
> * sim/bpf/endle.s: Likewise.
> * sim/bpf/jmp.s: Likewise.
> * sim/bpf/jmp32.s: Likewise.
> * sim/bpf/ldabs.s: Likewise.
> * sim/bpf/mem.s: Likewise.
> * sim/bpf/mov.s: Likewise.
> * sim/bpf/testutils.inc: Likewise.
> * sim/bpf/xadd.s: Likewise.
> ---
> gdb/ChangeLog | 4 +
> gdb/configure.tgt | 1 +

Make sure you include the gdb/ChangeLog entry in the commit message.

> sim/ChangeLog | 23 +
> sim/MAINTAINERS | 1 +
> sim/bpf/Makefile.in | 203 +
> sim/bpf/aclocal.m4 | 119 +
> sim/bpf/bpf-helpers.c | 175 +
> sim/bpf/bpf-helpers.def | 194 +
> sim/bpf/bpf-helpers.h | 31 +
> sim/bpf/bpf-sim.h | 31 +
> sim/bpf/bpf.c | 327 +
> sim/bpf/config.in | 248 +
> sim/bpf/configure | 15942 ++++++++++++++++++++++++++
> sim/bpf/configure.ac | 13 +
> sim/bpf/decode.h | 37 +
> sim/bpf/eng.h | 23 +
> sim/bpf/mloop.in | 165 +
> sim/bpf/sim-if.c | 214 +
> sim/bpf/sim-main.h | 51 +
> sim/bpf/traps.c | 33 +
> sim/configure | 8 +
> sim/configure.tgt | 3 +
> sim/testsuite/ChangeLog | 17 +
> sim/testsuite/configure | 3 +
> sim/testsuite/sim/bpf/allinsn.exp | 26 +
> sim/testsuite/sim/bpf/alu.s | 109 +
> sim/testsuite/sim/bpf/alu32.s | 99 +
> sim/testsuite/sim/bpf/endbe.s | 46 +
> sim/testsuite/sim/bpf/endle.s | 43 +
> sim/testsuite/sim/bpf/jmp.s | 120 +
> sim/testsuite/sim/bpf/jmp32.s | 120 +
> sim/testsuite/sim/bpf/ldabs.s | 87 +
> sim/testsuite/sim/bpf/mem.s | 56 +
> sim/testsuite/sim/bpf/mov.s | 54 +
> sim/testsuite/sim/bpf/testutils.inc | 38 +
> sim/testsuite/sim/bpf/xadd.s | 44 +
> 36 files changed, 18708 insertions(+)
> create mode 100644 sim/bpf/Makefile.in
> create mode 100644 sim/bpf/aclocal.m4
> create mode 100644 sim/bpf/bpf-helpers.c
> create mode 100644 sim/bpf/bpf-helpers.def
> create mode 100644 sim/bpf/bpf-helpers.h
> create mode 100644 sim/bpf/bpf-sim.h
> create mode 100644 sim/bpf/bpf.c
> create mode 100644 sim/bpf/config.in
> create mode 100755 sim/bpf/configure
> create mode 100644 sim/bpf/configure.ac
> create mode 100644 sim/bpf/decode.h
> create mode 100644 sim/bpf/eng.h
> create mode 100644 sim/bpf/mloop.in
> create mode 100644 sim/bpf/sim-if.c
> create mode 100644 sim/bpf/sim-main.h
> create mode 100644 sim/bpf/traps.c
> create mode 100644 sim/testsuite/sim/bpf/allinsn.exp
> create mode 100644 sim/testsuite/sim/bpf/alu.s
> create mode 100644 sim/testsuite/sim/bpf/alu32.s
> create mode 100644 sim/testsuite/sim/bpf/endbe.s
> create mode 100644 sim/testsuite/sim/bpf/endle.s
> create mode 100644 sim/testsuite/sim/bpf/jmp.s
> create mode 100644 sim/testsuite/sim/bpf/jmp32.s
> create mode 100644 sim/testsuite/sim/bpf/ldabs.s
> create mode 100644 sim/testsuite/sim/bpf/mem.s
> create mode 100644 sim/testsuite/sim/bpf/mov.s
> create mode 100644 sim/testsuite/sim/bpf/testutils.inc
> create mode 100644 sim/testsuite/sim/bpf/xadd.s
>
> diff --git a/gdb/configure.tgt b/gdb/configure.tgt
> index 7e84eff444..8a26bdeb87 100644
> --- a/gdb/configure.tgt
> +++ b/gdb/configure.tgt
> @@ -208,6 +208,7 @@ bfin-*-*)
> bpf-*-*)
> # Target: eBPF
> gdb_target_obs="bpf-tdep.o"
> + gdb_sim=../sim/bpf/libsim.a
> ;;
>
> cris*)
> diff --git a/sim/MAINTAINERS b/sim/MAINTAINERS
> index 4ca67cfd1d..7dcd88422c 100644
> --- a/sim/MAINTAINERS
> +++ b/sim/MAINTAINERS
> @@ -17,6 +17,7 @@ aarch64 Nick Clifton <nickc@redhat.com>
> aarch64 Jim Wilson <wilson@tuliptree.org>
> arm Nick Clifton <nickc@redhat.com>
> bfin Mike Frysinger <vapier@gentoo.org>
> +bpf Jose E. Marchesi <jose.marchesi@oracle.com>
> cr16 M R Swami Reddy <MR.Swami.Reddy@nsc.com>
> frv Dave Brolley <brolley@redhat.com>
> ft32 James Bowman <james.bowman@ftdichip.com>
> diff --git a/sim/bpf/Makefile.in b/sim/bpf/Makefile.in
> new file mode 100644
> index 0000000000..6110f79750
> --- /dev/null
> +++ b/sim/bpf/Makefile.in
> @@ -0,0 +1,203 @@
> +# Makefile template for configure for the eBPF simulator
> +# Copyright (C) 2020 Free Software Foundation, Inc.
> +#
> +# This file is part of GDB, the GNU debugger.
> +#
> +# This program 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.
> +#
> +# This program 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/>.
> +
> +## COMMON_PRE_CONFIG_FRAG
> +
> +CGEN_STD_OBJS = cgen-run.o cgen-scache.o cgen-trace.o cgen-utils.o
> +BPF_GEN_OBJS = arch.o cpu.o \
> + decode-le.o decode-be.o \
> + sem-le.o sem-be.o \
> + mloop-le.o mloop-be.o
> +BPF_HAND_OBJS = bpf.o sim-if.o traps.o bpf-helpers.o
> +
> +SIM_OBJS = \
> + $(SIM_NEW_COMMON_OBJS) \
> + $(CGEN_STD_OBJS) \
> + $(BPF_GEN_OBJS) \
> + $(BPF_HAND_OBJS)
> +
> +SIM_EXTRA_DEPS = \
> + $(CGEN_INCLUDE_DEPS) \
> + arch.h \
> + bpf-sim.h \
> + $(srcdir)/../../opcodes/bpf-desc.h \
> + $(srcdir)/../../opcodes/bpf-opc.h
> +
> +SIM_EXTRA_CLEAN = bpf-clean
> +
> +## COMMON_POST_CONFIG_FRAG
> +
> +# cgen support, enable with --enable-cgen-maint
> +CGEN_MAINT = ; @true
> +# The following line is commented in or out depending upon --enable-cgen-maint.
> +@CGEN_MAINT@CGEN_MAINT =
> +
> +# BPF headers
> +
> +BPF_INCLUDE_DEPS = \
> + $(CGEN_MAIN_CPU_DEPS) \
> + $(SIM_EXTRA_DEPS) \
> + cpu.h cpuall.h \
> + decode-le.h decode-be.h \
> + defs-le.h defs-be.h \
> + eng-le.h eng-be.h \
> + config.h
> +
> +# Dependencies for binaries from CGEN generated source
> +
> +arch.o: arch.c $(SIM_MAIN_DEPS)
> +cpu.o: cpu.c $(BPF_INCLUDE_DEPS)
> +decode-le.o: decode-le.c $(BPF_INCLUDE_DEPS)
> +decode-be.o: decode-be.c $(BPF_INCLUDE_DEPS)
> +
> +sim-if.o: sim-if.c $(SIM_MAIN_DEPS) $(srcdir)/../common/sim-core.h eng.h
> + $(COMPILE) $<
> + $(POSTCOMPILE)
> +
> +traps.o: traps.c $(SIM_MAIN_DEPS) eng.h
> + $(COMPILE) $<
> + $(POSTCOMPILE)
> +
> +mloop-le.o: mloop-le.c $(BPF_INCLUDE_DEPS)
> + $(CC) -c mloop-le.c $(ALL_CFLAGS) -DWANT_ISA_EBPFLE
> +mloop-be.o: mloop-be.c $(BPF_INCLUDE_DEPS)
> + $(CC) -c mloop-be.c $(ALL_CFLAGS) -DWANT_ISA_EBPFBE
> +
> +decode-le.o: decode-le.c $(BPF_INCLUDE_DEPS)
> + $(CC) -c $(srcdir)/decode-le.c $(ALL_CFLAGS) -DWANT_ISA_EBPFLE
> +decode-be.o: decode-be.c $(BPF_INCLUDE_DEPS)
> + $(CC) -c $(srcdir)/decode-be.c $(ALL_CFLAGS) -DWANT_ISA_EBPFBE
> +
> +sem-le.o: sem-le.c $(BPF_INCLUDE_DEPS)
> + $(CC) -c $(srcdir)/sem-le.c $(ALL_CFLAGS) -DWANT_ISA_EBPFLE
> +sem-be.o: sem-be.c $(BPF_INCLUDE_DEPS)
> + $(CC) -c $(srcdir)/sem-be.c $(ALL_CFLAGS) -DWANT_ISA_EBPFBE
> +
> +arch = bpf
> +
> +CGEN_COMMON_DEPS = \
> + $(CGEN_READ_SCM) \
> + $(srcdir)/../../cpu/bpf.cpu \
> + $(srcdir)/../../cpu/bpf.opc \
> + Makefile
> +
> +stamp-arch: $(CGEN_COMMON_DEPS) $(CGEN_ARCH_SCM)
> + $(MAKE) cgen-arch $(CGEN_FLAGS_TO_PASS) \
> + mach=bpf cpu=bpfbf \
> + archfile=$(srcdir)/../../cpu/bpf.cpu \
> + FLAGS="with-scache"
> + touch $@
> +$(srcdir)/arch.h $(srcdir)/arch.c $(srcdir)/cpuall.h: $(CGEN_MAINT) stamp-arch
> + @true
> +
> +stamp-cpu: $(CGEN_COMMON_DEPS) $(CGEN_CPU_SCM)
> + $(MAKE) cgen-cpu $(CGEN_FLAGS_TO_PASS) \
> + isa=ebpfle,ebpfbe cpu=bpfbf mach=bpf \
> + archfile=$(srcdir)/../../cpu/bpf.cpu \
> + FLAGS="with-multiple-isa with-scache"
> + rm -f $(srcdir)/model.c
> + touch $@
> +$(srcdir)/cpu.h $(srcdir)/cpu.c $(srcdir)/model.c: $(CGEN_MAINT) stamp-cpu
> + @true
> +
> +# We need to generate a group of files per ISA.
> +# For eBPF little-endian:
> +# defs-le.h
> +# sem-le.c, decode-le.c, decode-le.h
> +# $(objdir)/mloop-le.c $(objdir)/eng-le.h
> +# For eBPF big-endian:
> +# defs-be.h
> +# sem-be.c, decode-be.c, decode-be.h
> +# $(objdir)/mloop-be.c $(objdir)/eng-le.h
> +#
> +# The rules below take care of that.
> +
> +stamp-defs-le: $(CGEN_COMMON_DEPS) $(CGEN_CPU_SCM)
> + $(MAKE) cgen-defs $(CGEN_FLAGS_TO_PASS) \
> + isa=ebpfle cpu=bpfbf mach=bpf \
> + archfile=$(srcdir)/../../cpu/bpf.cpu \
> + FLAGS="with-scache" \
> + SUFFIX="-le"
> + touch $@
> +$(srcdir)/defs-le.h: $(CGEN_MAINT) stamp-defs-le
> + @true
> +
> +
> +stamp-defs-be: $(CGEN_COMMON_DEPS) $(CGEN_CPU_SCM)
> + $(MAKE) cgen-defs $(CGEN_FLAGS_TO_PASS) \
> + isa=ebpfbe cpu=bpfbf mach=bpf \
> + archfile=$(srcdir)/../../cpu/bpf.cpu \
> + FLAGS="with-scache" \
> + SUFFIX="-be"
> + touch $@
> +$(srcdir)/defs-be.h: $(CGEN_MAINT) stamp-defs-be
> + @true
> +
> +stamp-decode-le: $(CGEN_COMMON_DEPS) $(CGEN_CPU_SCM) $(GEN_DECODE_SCM)
> + $(MAKE) cgen-decode $(CGEN_FLAGS_TO_PASS) \
> + isa=ebpfle cpu=bpfbf mach=bpf \
> + archfile=$(srcdir)/../../cpu/bpf.cpu \
> + FLAGS="with-scache" \
> + SUFFIX="-le" \
> + EXTRAFILES="$(CGEN_CPU_SEM)"
> + touch $@
> +$(srcdir)/sem-le.c $(srcdir)/decode-le.c $(srcdir)/decode-le.h: \
> + $(CGEN_MAINT) stamp-decode-le
> + @true
> +
> +
> +stamp-decode-be: $(CGEN_COMMON_DEPS) $(CGEN_CPU_SCM) $(GEN_DECODE_SCM)
> + $(MAKE) cgen-decode $(CGEN_FLAGS_TO_PASS) \
> + isa=ebpfbe cpu=bpfbf mach=bpf \
> + archfile=$(srcdir)/../../cpu/bpf.cpu \
> + FLAGS="with-scache" \
> + SUFFIX="-be" \
> + EXTRAFILES="$(CGEN_CPU_SEM)"
> + touch $@
> +$(srcdir)/sem-be.c $(srcdir)/decode-be.c $(srcdir)/decode-be.h: \
> + $(CGEN_MAINT) stamp-decode-be
> + @true
> +
> +# Note the following files are generated in objdir, not srcdir.
> +
> +stamp-mloop: stamp-mloop-le stamp-mloop-be
> +
> +stamp-mloop-le: $(srcdir)/../common/genmloop.sh mloop.in Makefile
> + $(SHELL) $(srccom)/genmloop.sh -shell $(SHELL) \
> + -mono -scache -prefix bpfbf_ebpfle -cpu bpfbf \
> + -infile $(srcdir)/mloop.in
> + $(SHELL) $(srcroot)/move-if-change eng.hin eng-le.h
> + $(SHELL) $(srcroot)/move-if-change mloop.cin mloop-le.c
> + touch $@
> +mloop-le.c eng-le.h: stamp-mloop-le
> + @true
> +
> +stamp-mloop-be: $(srcdir)/../common/genmloop.sh mloop.in Makefile
> + $(SHELL) $(srccom)/genmloop.sh -shell $(SHELL) \
> + -mono -scache -prefix bpfbf_ebpfbe -cpu bpfbf \
> + -infile $(srcdir)/mloop.in
> + $(SHELL) $(srcroot)/move-if-change eng.hin eng-be.h
> + $(SHELL) $(srcroot)/move-if-change mloop.cin mloop-be.c
> + touch $@
> +mloop-be.c eng-be.h: stamp-mloop-be
> + @true

When testing the build I ran into issues here while trying to perform
a parallel build as both these rules generate the files eng.hin and
mloop.cin.

I know this problem is not unique to this target, but it would be nice
if we didn't introduce more places where the parallel build is broken.

The _correct_ solution would be to update genmloop.sh so that the
output files can be named. However, I'm aware that this is an
unreasonable expectation, so could you at least combine the be and le
generation into a single rule 'stamp-all-mloop' please, and add a
comment explaining why. This at least will work around the problem
for now.

With these issues resolved I'm happy for this to go in.

Thanks,
Andrew

> +
> +.PHONY = bpf-clean
> +
> +bpf-clean:
> + rm -f stamp-arch stamp-cpu stamp-decode stamp-defs stamp-mloop
> diff --git a/sim/bpf/aclocal.m4 b/sim/bpf/aclocal.m4
> new file mode 100644
> index 0000000000..e9f11c775c
> --- /dev/null
> +++ b/sim/bpf/aclocal.m4
> @@ -0,0 +1,119 @@
> +# generated automatically by aclocal 1.15.1 -*- Autoconf -*-
> +
> +# Copyright (C) 1996-2017 Free Software Foundation, Inc.
> +
> +# This file is free software; the Free Software Foundation
> +# gives unlimited permission to copy and/or distribute it,
> +# with or without modifications, as long as this notice is preserved.
> +
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
> +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
> +# PARTICULAR PURPOSE.
> +
> +m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
> +# AM_CONDITIONAL -*- Autoconf -*-
> +
> +# Copyright (C) 1997-2017 Free Software Foundation, Inc.
> +#
> +# This file is free software; the Free Software Foundation
> +# gives unlimited permission to copy and/or distribute it,
> +# with or without modifications, as long as this notice is preserved.
> +
> +# AM_CONDITIONAL(NAME, SHELL-CONDITION)
> +# -------------------------------------
> +# Define a conditional.
> +AC_DEFUN([AM_CONDITIONAL],
> +[AC_PREREQ([2.52])dnl
> + m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])],
> + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
> +AC_SUBST([$1_TRUE])dnl
> +AC_SUBST([$1_FALSE])dnl
> +_AM_SUBST_NOTMAKE([$1_TRUE])dnl
> +_AM_SUBST_NOTMAKE([$1_FALSE])dnl
> +m4_define([_AM_COND_VALUE_$1], [$2])dnl
> +if $2; then
> + $1_TRUE=
> + $1_FALSE='#'
> +else
> + $1_TRUE='#'
> + $1_FALSE=
> +fi
> +AC_CONFIG_COMMANDS_PRE(
> +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then
> + AC_MSG_ERROR([[conditional "$1" was never defined.
> +Usually this means the macro was only invoked conditionally.]])
> +fi])])
> +
> +# Copyright (C) 2003-2017 Free Software Foundation, Inc.
> +#
> +# This file is free software; the Free Software Foundation
> +# gives unlimited permission to copy and/or distribute it,
> +# with or without modifications, as long as this notice is preserved.
> +
> +# Check whether the underlying file-system supports filenames
> +# with a leading dot. For instance MS-DOS doesn't.
> +AC_DEFUN([AM_SET_LEADING_DOT],
> +[rm -rf .tst 2>/dev/null
> +mkdir .tst 2>/dev/null
> +if test -d .tst; then
> + am__leading_dot=.
> +else
> + am__leading_dot=_
> +fi
> +rmdir .tst 2>/dev/null
> +AC_SUBST([am__leading_dot])])
> +
> +# Add --enable-maintainer-mode option to configure. -*- Autoconf -*-
> +# From Jim Meyering
> +
> +# Copyright (C) 1996-2017 Free Software Foundation, Inc.
> +#
> +# This file is free software; the Free Software Foundation
> +# gives unlimited permission to copy and/or distribute it,
> +# with or without modifications, as long as this notice is preserved.
> +
> +# AM_MAINTAINER_MODE([DEFAULT-MODE])
> +# ----------------------------------
> +# Control maintainer-specific portions of Makefiles.
> +# Default is to disable them, unless 'enable' is passed literally.
> +# For symmetry, 'disable' may be passed as well. Anyway, the user
> +# can override the default with the --enable/--disable switch.
> +AC_DEFUN([AM_MAINTAINER_MODE],
> +[m4_case(m4_default([$1], [disable]),
> + [enable], [m4_define([am_maintainer_other], [disable])],
> + [disable], [m4_define([am_maintainer_other], [enable])],
> + [m4_define([am_maintainer_other], [enable])
> + m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])])
> +AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles])
> + dnl maintainer-mode's default is 'disable' unless 'enable' is passed
> + AC_ARG_ENABLE([maintainer-mode],
> + [AS_HELP_STRING([--]am_maintainer_other[-maintainer-mode],
> + am_maintainer_other[ make rules and dependencies not useful
> + (and sometimes confusing) to the casual installer])],
> + [USE_MAINTAINER_MODE=$enableval],
> + [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes]))
> + AC_MSG_RESULT([$USE_MAINTAINER_MODE])
> + AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes])
> + MAINT=$MAINTAINER_MODE_TRUE
> + AC_SUBST([MAINT])dnl
> +]
> +)
> +
> +# Copyright (C) 2006-2017 Free Software Foundation, Inc.
> +#
> +# This file is free software; the Free Software Foundation
> +# gives unlimited permission to copy and/or distribute it,
> +# with or without modifications, as long as this notice is preserved.
> +
> +# _AM_SUBST_NOTMAKE(VARIABLE)
> +# ---------------------------
> +# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in.
> +# This macro is traced by Automake.
> +AC_DEFUN([_AM_SUBST_NOTMAKE])
> +
> +# AM_SUBST_NOTMAKE(VARIABLE)
> +# --------------------------
> +# Public sister of _AM_SUBST_NOTMAKE.
> +AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
> +
> diff --git a/sim/bpf/bpf-helpers.c b/sim/bpf/bpf-helpers.c
> new file mode 100644
> index 0000000000..cec56459aa
> --- /dev/null
> +++ b/sim/bpf/bpf-helpers.c
> @@ -0,0 +1,175 @@
> +/* Emulation of eBPF helpers.
> + Copyright (C) 2020 Free Software Foundation, Inc.
> +
> + This file is part of GDB, the GNU debugger.
> +
> + This program 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.
> +
> + This program 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/>. */
> +
> +/* BPF programs rely on the existence of several helper functions,
> + which are provided by the kernel. This simulator provides an
> + implementation of the helpers, which can be customized by the
> + user. */
> +
> +#define WANT_CPU_BPFBF
> +#define WANT_CPU bpfbf
> +
> +#include "sim-main.h"
> +#include "cgen-mem.h"
> +#include "cgen-ops.h"
> +#include "cpu.h"
> +
> +/* bpf_trace_printk is a printk-like facility for debugging.
> +
> + In the kernel, it appends a line to the Linux's tracing debugging
> + interface.
> +
> + In this simulator, it uses the simulator's tracing interface
> + instead.
> +
> + The format tags recognized by this helper are:
> + %d, %i, %u, %x, %ld, %li, %lu, %lx, %lld, %lli, %llu, %llx,
> + %p, %s
> +
> + A maximum of three tags are supported.
> +
> + This helper returns the number of bytes written, or a negative
> + value in case of failure. */
> +
> +int
> +bpf_trace_printk (SIM_CPU *current_cpu)
> +{
> + va_list ap;
> + SIM_DESC sd = CPU_STATE (current_cpu);
> +
> + DI fmt_address;
> + uint32_t size, tags_processed;
> + size_t i, bytes_written = 0;
> +
> + /* The first argument is the format string, which is passed as a
> + pointer in %r1. */
> + fmt_address = GET_H_GPR (1);
> +
> + /* The second argument is the length of the format string, as an
> + unsigned 32-bit number in %r2. */
> + size = GET_H_GPR (2);
> +
> + /* Read the format string from the memory pointed by %r2, printing
> + out the stuff as we go. There is a maximum of three format tags
> + supported, which are read from %r3, %r4 and %r5 respectively. */
> + for (i = 0, tags_processed = 0; i < size;)
> + {
> + QI c = GETMEMUQI (current_cpu, CPU_PC_GET (current_cpu),
> + fmt_address + i);
> +
> + switch (c)
> + {
> + case '%':
> + /* Check we are not exceeding the limit of three format
> + tags. */
> + if (tags_processed > 2)
> + return -1; /* XXX look for kernel error code. */
> +
> + /* Depending on the kind of tag, extract the value from the
> + proper argument. */
> + if (i++ >= size)
> + return -1; /* XXX look for kernel error code. */
> +
> + UDI value = GET_H_GPR (3 + tags_processed);
> +
> + switch ((GETMEMUQI (current_cpu, CPU_PC_GET (current_cpu),
> + fmt_address + i)))
> + {
> + case 'd':
> + trace_printf (sd, current_cpu, "%d", value);
> + break;
> + case 'i':
> + trace_printf (sd, current_cpu, "%i", value);
> + break;
> + case 'u':
> + trace_printf (sd, current_cpu, "%u", value);
> + break;
> + case 'x':
> + trace_printf (sd, current_cpu, "%x", value);
> + break;
> + case 'l':
> + {
> + if (i++ >= size)
> + return -1;
> + switch (GETMEMUQI (current_cpu, CPU_PC_GET (current_cpu),
> + fmt_address + i))
> + {
> + case 'd':
> + trace_printf (sd, current_cpu, "%ld", value);
> + break;
> + case 'i':
> + trace_printf (sd, current_cpu, "%li", value);
> + break;
> + case 'u':
> + trace_printf (sd, current_cpu, "%lu", value);
> + break;
> + case 'x':
> + trace_printf (sd, current_cpu, "%lx", value);
> + break;
> + case 'l':
> + {
> + if (i++ >= size)
> + return -1;
> + switch (GETMEMUQI (current_cpu, CPU_PC_GET (current_cpu),
> + fmt_address + i)) {
> + case 'd':
> + trace_printf (sd, current_cpu, "%lld", value);
> + break;
> + case 'i':
> + trace_printf (sd, current_cpu, "%lli", value);
> + break;
> + case 'u':
> + trace_printf (sd, current_cpu, "%llu", value);
> + break;
> + case 'x':
> + trace_printf (sd, current_cpu, "%llx", value);
> + break;
> + default:
> + assert (0);
> + break;
> + }
> + break;
> + }
> + default:
> + assert (0);
> + break;
> + }
> + break;
> + }
> + default:
> + /* XXX completeme */
> + assert (0);
> + break;
> + }
> +
> + tags_processed++;
> + i++;
> + break;
> + case '\0':
> + i = size;
> + break;
> + default:
> + trace_printf (sd, current_cpu, "%c", c);
> + bytes_written++;
> + i++;
> + break;
> + }
> + }
> +
> + return bytes_written;
> +}
> diff --git a/sim/bpf/bpf-helpers.def b/sim/bpf/bpf-helpers.def
> new file mode 100644
> index 0000000000..c8b66dc3d9
> --- /dev/null
> +++ b/sim/bpf/bpf-helpers.def
> @@ -0,0 +1,194 @@
> +/* BPF helpers database.
> + Copyright (C) 2019-2020 Free Software Foundation, Inc.
> +
> +This file is part of the GNU simulator.
> +
> +GCC 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, or (at your option)
> +any later version.
> +
> +GCC 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 GCC; see the file COPYING3. If not see
> +<http://www.gnu.org/licenses/>. */
> +
> +/* This file contains the definition of the helpers that are available
> + to BPF programs.
> +
> + The primary source for information on kernel helpers is the
> + linux/include/uapi/linux/bpf.h file in the Linux source tree.
> + Please keep this database in sync.
> +
> + The first column is the first kernel version featuring the helper
> + function. This should be an enumerate from bpf_kernel_version,
> + defined in bpf-opts.h. Note that the backend assumes that helpers
> + never get deprecated in the kernel. If that eventually happens,
> + then we will need to use a bitmask here instead of an enumerate.
> +
> + The second column is the constant-name for the helper.
> + The third column is the program-name of the helper.
> +
> + The fourth column is a list of names describing the types of the
> + values returned and accepted by the helper, in one of these forms:
> +
> + TYPES (type1, type2, ..., 0)
> + VTYPES (type1, type2, ..., 0)
> +
> + VTYPES should be used should the helper accept a variable number of
> + arguments, TYPES otherwise. The valid type names are:
> +
> + `vt' for void.
> + `it' for signed int.
> + `ut' for unsigned int.
> + `pt' for void*.
> + `cpt' for const void*.
> + `st' for short int.
> + `ust' for unsigned short int.
> + `cst' for const char *.
> + `ullt' for unsigned long long.
> + `llt' for long long.
> + `u32t' for uint32.
> + `u64t' for uint64.
> +
> + In types descriptions, the firt entry corresponds to the value
> + returned by the helper. Subsequent names correspond to the helper
> + arguments. Finally, a 0 should close the list.
> +
> + VERY IMPORTANT: the helper entries should be listed in the same
> + order than in the definition of __BPF_FUNC_MAPPER in
> + linux/include/uapi/linux/bpf.h! */
> +
> +DEF_HELPER (LINUX_V4_0, MAP_LOOKUP_ELEM, map_lookup_elem, TYPES (pt, pt, pt, 0))
> +DEF_HELPER (LINUX_V4_0, MAP_UPDATE_ELEM, map_update_elem, TYPES (it, pt, pt, pt, ullt, 0))
> +DEF_HELPER (LINUX_V4_0, MAP_DELETE_ELEM, map_delete_elem, TYPES (it, pt, pt, 0))
> +DEF_HELPER (LINUX_V4_1, PROBE_READ, probe_read, TYPES (it, pt, ut, cpt, 0))
> +DEF_HELPER (LINUX_V4_1, KTIME_GET_NS, ktime_get_ns, TYPES (ullt, 0))
> +DEF_HELPER (LINUX_V4_1, TRACE_PRINTK, trace_printk, VTYPES (it, cst, it, 0))
> +DEF_HELPER (LINUX_V4_1, GET_PRANDOM_U32, get_prandom_u32, TYPES (ullt, 0))
> +DEF_HELPER (LINUX_V4_1, GET_SMP_PROCESSOR_ID, get_smp_processor_id, TYPES (ullt, 0))
> +DEF_HELPER (LINUX_V4_1, SKB_STORE_BYTES, skb_store_bytes, TYPES (it, pt, it, pt, it, it, 0))
> +DEF_HELPER (LINUX_V4_1, L3_CSUM_REPLACE, l3_csum_replace, TYPES (it, pt, it, it ,it ,it, 0))
> +DEF_HELPER (LINUX_V4_1, L4_CSUM_REPLACE, l4_csum_replace, TYPES (it, pt, it, it, it, it, 0))
> +DEF_HELPER (LINUX_V4_2, TAIL_CALL, tail_call, TYPES (vt, pt, pt, it, 0))
> +DEF_HELPER (LINUX_V4_2, CLONE_REDIRECT, clone_redirect, TYPES (it, pt, it, it, 0))
> +DEF_HELPER (LINUX_V4_2, GET_CURRENT_PID_TGID, get_current_pid_tgid, TYPES (ullt, 0))
> +DEF_HELPER (LINUX_V4_2, GET_CURRENT_UID_GID, get_current_uid_gid, TYPES (ullt, 0))
> +DEF_HELPER (LINUX_V4_2, GET_CURRENT_COMM, get_current_comm, TYPES (it, pt, it, 0))
> +DEF_HELPER (LINUX_V4_3, GET_CGROUP_CLASSID, get_cgroup_classid, TYPES (it, pt, 0))
> +DEF_HELPER (LINUX_V4_3, SKB_VLAN_PUSH, skb_vlan_push, TYPES (it, pt, st, ust, 0))
> +DEF_HELPER (LINUX_V4_3, SKB_VLAN_POP, skb_vlan_pop, TYPES (it, pt, 0))
> +DEF_HELPER (LINUX_V4_3, SKB_GET_TUNNEL_KEY, skb_get_tunnel_key, TYPES (it, pt, pt, it, it, 0))
> +DEF_HELPER (LINUX_V4_3, SKB_SET_TUNNEL_KEY, skb_set_tunnel_key, TYPES (it, pt, pt, it, it, 0))
> +DEF_HELPER (LINUX_V4_3, PERF_EVENT_READ, perf_event_read, TYPES (ullt, pt, ullt, 0))
> +DEF_HELPER (LINUX_V4_4, REDIRECT, redirect, TYPES (it, it, it, 0))
> +DEF_HELPER (LINUX_V4_4, GET_ROUTE_REALM, get_route_realm, TYPES (ut, pt, 0))
> +DEF_HELPER (LINUX_V4_4, PERF_EVENT_OUTPUT, perf_event_output, \
> + TYPES (it, pt, pt, ullt, pt, it, 0))
> +DEF_HELPER (LINUX_V4_5, SKB_LOAD_BYTES, skb_load_bytes, TYPES (it, pt, it, pt, it, 0))
> +DEF_HELPER (LINUX_V4_6, GET_STACKID, get_stackid, TYPES (it, pt, pt, it, 0))
> +DEF_HELPER (LINUX_V4_6, CSUM_DIFF, csum_diff, TYPES (it, pt, it, pt, it, it, 0))
> +DEF_HELPER (LINUX_V4_6, SKB_GET_TUNNEL_OPT, skb_get_tunnel_opt, TYPES (it, pt, pt, it, 0))
> +DEF_HELPER (LINUX_V4_6, SKB_SET_TUNNEL_OPT, skb_set_tunnel_opt, TYPES (it, pt, pt, it, 0))
> +DEF_HELPER (LINUX_V4_8, SKB_CHANGE_PROTO, skb_change_proto, TYPES (it, pt, st, u64t, 0))
> +DEF_HELPER (LINUX_V4_8, SKB_CHANGE_TYPE, skb_change_type, TYPES (it, pt, u32t, 0))
> +DEF_HELPER (LINUX_V4_8, SKB_UNDER_CGROUP, skb_under_cgroup, TYPES (it, pt, pt, it, 0))
> +DEF_HELPER (LINUX_V4_8, GET_HASH_RECALC, get_hash_recalc, TYPES (ut, pt, 0))
> +DEF_HELPER (LINUX_V4_8, GET_CURRENT_TASK, get_current_task, TYPES (ullt, 0))
> +DEF_HELPER (LINUX_V4_8, PROBE_WRITE_USER, probe_write_user, TYPES (it, pt, cpt, ut, 0))
> +DEF_HELPER (LINUX_V4_9, CURRENT_TASK_UNDER_CGROUP, current_task_under_cgroup, \
> + TYPES (it, pt, it, 0))
> +DEF_HELPER (LINUX_V4_9, SKB_CHANGE_TAIL, skb_change_tail, TYPES (it, pt, ut, u64t, 0))
> +DEF_HELPER (LINUX_V4_9, SKB_PULL_DATA, skb_pull_data, TYPES (it, pt, it, 0))
> +DEF_HELPER (LINUX_V4_9, CSUM_UPDATE, csum_update, TYPES (llt, pt, u32t, 0))
> +DEF_HELPER (LINUX_V4_9, SET_HASH_INVALID, set_hash_invalid, TYPES (vt, pt, 0))
> +DEF_HELPER (LINUX_V4_10, GET_NUMA_NODE_ID, get_numa_node_id, TYPES (it, 0))
> +DEF_HELPER (LINUX_V4_10, SKB_CHANGE_HEAD, skb_change_head, TYPES (it, pt, it, it, 0))
> +DEF_HELPER (LINUX_V4_10, XDP_ADJUST_HEAD, xdp_adjust_head, TYPES (it, pt, it, 0))
> +DEF_HELPER (LINUX_V4_11, PROBE_READ_STR, probe_read_str, TYPES (it, pt, u32t, cpt, 0))
> +DEF_HELPER (LINUX_V4_12, GET_SOCKET_COOKIE, get_socket_cookie, TYPES (it, pt, 0))
> +DEF_HELPER (LINUX_V4_12, GET_SOCKET_UID, get_socket_uid, TYPES (ut, pt, 0))
> +DEF_HELPER (LINUX_V4_13, SET_HASH, set_hash, TYPES (ut, pt, u32t, 0))
> +DEF_HELPER (LINUX_V4_13, SETSOCKOPT, setsockopt, TYPES (it, pt, it, it, pt, it, 0))
> +DEF_HELPER (LINUX_V4_13, SKB_ADJUST_ROOM, skb_adjust_room, TYPES (it, pt, st, u32t, ullt, 0))
> +DEF_HELPER (LINUX_V4_14, REDIRECT_MAP, redirect_map, TYPES (it, pt, it, it, 0))
> +DEF_HELPER (LINUX_V4_14, SK_REDIRECT_MAP, sk_redirect_map, TYPES (it, pt, pt, it, it, 0))
> +DEF_HELPER (LINUX_V4_14, SOCK_MAP_UPDATE, sock_map_update, TYPES (it, pt, pt, pt, ullt, 0))
> +DEF_HELPER (LINUX_V4_15, XDP_ADJUST_META, xdp_adjust_meta, TYPES (it, pt, it, 0))
> +DEF_HELPER (LINUX_V4_15, PERF_EVENT_READ_VALUE, perf_event_read_value,
> + TYPES (it, pt, ullt, pt, ut, 0))
> +DEF_HELPER (LINUX_V4_15, PERF_PROG_READ_VALUE, perf_prog_read_value,
> + TYPES (it, pt, pt, ut, 0))
> +DEF_HELPER (LINUX_V4_15, GETSOCKOPT, getsockopt, TYPES (it, pt, it, it, pt, it, 0))
> +
> +DEF_HELPER (LINUX_V4_16, OVERRIDE_RETURN, override_return, TYPES (it, pt, ult, 0))
> +DEF_HELPER (LINUX_V4_16, SOCK_OPS_CB_FLAGS_SET, sock_ops_cb_flags_set, TYPES (it, pt, it, 0))
> +DEF_HELPER (LINUX_V4_17, MSG_REDIRECT_MAP, msg_redirect_map, TYPES (it, pt, pt, it, it, 0))
> +DEF_HELPER (LINUX_V4_17, MSG_APPLY_BYTES, msg_apply_bytes, TYPES (it, pt, it, 0))
> +DEF_HELPER (LINUX_V4_17, MSG_CORK_BYTES, msg_cork_bytes, TYPES (it, pt, it, 0))
> +DEF_HELPER (LINUX_V4_17, MSG_PULL_DATA, msg_pull_data, TYPES (it, pt, it, it, it, 0))
> +DEF_HELPER (LINUX_V4_17, BIND, bind, TYPES (it, pt, pt, it, 0))
> +DEF_HELPER (LINUX_V4_18, XDP_ADJUST_TAIL, xdp_adjust_tail, TYPES (it, pt, it, 0))
> +DEF_HELPER (LINUX_V4_18, SKB_GET_XFRM_STATE,
> + skb_get_xfrm_state, TYPES (it, pt, it, pt, it, it, 0))
> +DEF_HELPER (LINUX_V4_18, GET_STACK, get_stack, TYPES (it, pt, pt, it, it, 0))
> +DEF_HELPER (LINUX_V4_18, SKB_LOAD_BYTES_RELATIVE, skb_load_bytes_relative,
> + TYPES (it, pt, it, pt, it, ut, 0))
> +DEF_HELPER (LINUX_V4_18, FIB_LOOKUP, fib_lookup, TYPES (it, pt, pt, it, ut, 0))
> +DEF_HELPER (LINUX_V4_18, SOCK_HASH_UPDATE, sock_hash_update, TYPES (it, pt, pt, pt, ullt, 0))
> +DEF_HELPER (LINUX_V4_18, MSG_REDIRECT_HASH, msg_redirect_hash, TYPES (it, pt, pt, pt, it, 0))
> +DEF_HELPER (LINUX_V4_18, SK_REDIRECT_HASH, sk_redirect_hash, TYPES (it, pt, pt, pt, it, 0))
> +DEF_HELPER (LINUX_V4_18, LWT_PUSH_ENCAP, lwt_push_encap, TYPES (it, pt, ut, pt, ut, 0))
> +DEF_HELPER (LINUX_V4_18, LWT_SEG6_STORE_BYTES, lwt_seg6_store_bytes,
> + TYPES (it, pt, ut, pt, ut, 0))
> +DEF_HELPER (LINUX_V4_18, LWT_SEG6_ADJUST_SRH, lwt_seg6_adjust_srh, TYPES (it, pt, ut, ut, 0))
> +DEF_HELPER (LINUX_V4_18, LWT_SEG6_ACTION, lwt_seg6_action, TYPES (it, pt, ut, pt, ut, 0))
> +DEF_HELPER (LINUX_V4_18, RC_REPEAT, rc_repeat, TYPES (it, pt, 0))
> +DEF_HELPER (LINUX_V4_18, RC_KEYDOWN, rc_keydown, TYPES (it, pt, ut, ullt, ut, 0))
> +DEF_HELPER (LINUX_V4_18, SKB_CGROUP_ID, skb_cgroup_id, TYPES (ullt, pt, 0))
> +DEF_HELPER (LINUX_V4_18, GET_CURRENT_CGROUP_ID, get_current_cgroup_id, TYPES (ullt, 0))
> +DEF_HELPER (LINUX_V4_19, GET_LOCAL_STORAGE, get_local_storage, TYPES (pt, pt, ullt, 0))
> +DEF_HELPER (LINUX_V4_19, SK_SELECT_REUSEPORT, sk_select_reuseport,
> + TYPES (it, pt, pt, pt, ut, 0))
> +DEF_HELPER (LINUX_V4_19, SKB_ANCESTOR_CGROUP_ID, skb_ancestor_cgroup_id,
> + TYPES (ullt, pt, it, 0))
> +DEF_HELPER (LINUX_V4_20, SK_LOOKUP_TCP, sk_lookup_tcp, TYPES (pt, pt, pt, it, ullt, ullt, 0))
> +DEF_HELPER (LINUX_V4_20, SK_LOOKUP_UDP, sk_lookup_udp, TYPES (pt, pt, pt, it, ullt, ullt, 0))
> +DEF_HELPER (LINUX_V4_20, SK_RELEASE, sk_release, TYPES (it, pt, 0))
> +DEF_HELPER (LINUX_V4_20, MAP_PUSH_ELEM, map_push_elem, TYPES (it, pt, pt, ullt, 0))
> +DEF_HELPER (LINUX_V4_20, MAP_POP_ELEM, map_pop_elem, TYPES (it, pt, pt, 0))
> +DEF_HELPER (LINUX_V4_20, MAP_PEEK_ELEM, map_peek_elem, TYPES (it, pt, pt, 0))
> +DEF_HELPER (LINUX_V4_20, MSG_PUSH_DATA, msg_push_data, TYPES (it, pt, it, it, it, 0))
> +DEF_HELPER (LINUX_V5_0, MSG_POP_DATA, msg_pop_data, TYPES (it, pt, it, it, it, 0))
> +DEF_HELPER (LINUX_V5_0, RC_POINTER_REL, rc_pointer_rel, TYPES (it, pt, it, it, 0))
> +DEF_HELPER (LINUX_V5_1, SPIN_LOCK, spin_lock, TYPES (vt, pt, 0))
> +DEF_HELPER (LINUX_V5_1, SPIN_UNLOCK, spin_unlock, TYPES (vt, pt, 0))
> +DEF_HELPER (LINUX_V5_1, SK_FULLSOCK, sk_fullsock, TYPES (pt, pt, 0))
> +DEF_HELPER (LINUX_V5_1, TCP_SOCK, tcp_sock, TYPES (pt, pt, 0))
> +DEF_HELPER (LINUX_V5_1, SKB_ECN_SET_CE, skb_ecn_set_ce, TYPES (it, pt, 0))
> +DEF_HELPER (LINUX_V5_1, GET_LISTENER_SOCK, get_listener_sock, TYPES (pt, pt, 0))
> +DEF_HELPER (LINUX_V5_2, SKC_LOOKUP_TCP, skc_lookup_tcp,
> + TYPES (pt, pt, pt, u32t, u64t, u64t, 0))
> +DEF_HELPER (LINUX_V5_2, TCP_CHECK_SYNCOOKIE, tcp_check_syncookie,
> + TYPES (it, pt, pt, u32t, pt, u32t, 0))
> +DEF_HELPER (LINUX_V5_2, SYSCTL_GET_NAME, sysctl_get_name, TYPES (it, pt, pt, ullt, u64t, 0))
> +DEF_HELPER (LINUX_V5_2, SYSCTL_GET_CURRENT_VALUE, sysctl_get_current_value,
> + TYPES (it, pt, pt, ullt, 0))
> +DEF_HELPER (LINUX_V5_2, SYSCTL_GET_NEW_VALUE, sysctl_get_new_value,
> + TYPES (it, pt, pt, ullt, 0))
> +DEF_HELPER (LINUX_V5_2, SYSCTL_SET_NEW_VALUE, sysctl_set_new_value,
> + TYPES (it, pt, pt, ullt, 0))
> +DEF_HELPER (LINUX_V5_2, STRTOL, strtol, TYPES (it, cst, ullt, u64t, pt, 0))
> +DEF_HELPER (LINUX_V5_2, STRTOUL, strtoul, TYPES (it, pt, ullt, u64t, pt, 0))
> +DEF_HELPER (LINUX_V5_2, SK_STORAGE_GET, sk_storage_get, TYPES (pt, pt, pt, pt, u64t, 0))
> +DEF_HELPER (LINUX_V5_2, SK_STORAGE_DELETE, sk_storage_delete, TYPES (it, pt, pt, 0))
> +
> +/*
> +Local variables:
> +mode:c
> +End:
> +*/
> diff --git a/sim/bpf/bpf-helpers.h b/sim/bpf/bpf-helpers.h
> new file mode 100644
> index 0000000000..fe9413f266
> --- /dev/null
> +++ b/sim/bpf/bpf-helpers.h
> @@ -0,0 +1,31 @@
> +/* Emulation of eBPF helpers. Interface.
> + Copyright (C) 2020 Free Software Foundation, Inc.
> +
> + This file is part of GDB, the GNU debugger.
> +
> + This program 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.
> +
> + This program 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/>. */
> +
> +#ifndef BPF_HELPERS_H
> +#define BPF_HELPERS_H
> +
> +enum bpf_kernel_helper
> + {
> +#define DEF_HELPER(kver, name, fn, types) name,
> +#include "bpf-helpers.def"
> +#undef DEF_HELPER
> + };
> +
> +/* void bpf_trace_printk (const char *fmt); */
> +
> +#endif /* ! BPF_HELPERS_H */
> diff --git a/sim/bpf/bpf-sim.h b/sim/bpf/bpf-sim.h
> new file mode 100644
> index 0000000000..6b5c275cd5
> --- /dev/null
> +++ b/sim/bpf/bpf-sim.h
> @@ -0,0 +1,31 @@
> +/* eBPF simulator support code header
> + Copyright (C) 2020 Free Software Foundation, Inc.
> +
> + This file is part of GDB, the GNU debugger.
> +
> + This program 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.
> +
> + This program 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/>. */
> +
> +#ifndef BPF_SIM_H
> +#define BPF_SIM_H
> +
> +void bpfbf_insn_before (sim_cpu* current_cpu, SEM_PC vpc, const IDESC *idesc);
> +void bpfbf_insn_after (sim_cpu* current_cpu, SEM_PC vpc, const IDESC *idesc);
> +
> +DI bpfbf_endbe (SIM_CPU *, DI, UINT);
> +DI bpfbf_endle (SIM_CPU *, DI, UINT);
> +DI bpfbf_skb_data_offset (SIM_CPU *);
> +VOID bpfbf_call (SIM_CPU *, INT, UINT);
> +VOID bpfbf_exit (SIM_CPU *);
> +
> +#endif /* ! BPF_SIM_H */
> diff --git a/sim/bpf/bpf.c b/sim/bpf/bpf.c
> new file mode 100644
> index 0000000000..0fb8d81c46
> --- /dev/null
> +++ b/sim/bpf/bpf.c
> @@ -0,0 +1,327 @@
> +/* eBPF simulator support code
> + Copyright (C) 2020 Free Software Foundation, Inc.
> +
> + This file is part of GDB, the GNU debugger.
> +
> + This program 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.
> +
> + This program 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/>. */
> +
> +#define WANT_CPU_BPFBF
> +#define WANT_CPU bpfbf
> +
> +#include "sim-main.h"
> +#include "sim-fpu.h"
> +#include "cgen-mem.h"
> +#include "cgen-ops.h"
> +#include "cpuall.h"
> +#include "decode.h"
> +
> +#include "defs-le.h" /* For SCACHE */
> +
> +/* It is not possible to include both defs-le.h and defs-be.h due to
> + duplicated definitions, so we need a bunch of forward declarations
> + here. */
> +extern void bpfbf_ebpfle_init_idesc_table (SIM_CPU *);
> +extern void bpfbf_ebpfbe_init_idesc_table (SIM_CPU *);
> +
> +uint64_t skb_data_offset;
> +
> +IDESC *bpf_idesc_le;
> +IDESC *bpf_idesc_be;
> +
> +
> +int
> +bpfbf_fetch_register (SIM_CPU *current_cpu,
> + int rn,
> + unsigned char *buf,
> + int len)
> +{
> + if (rn == 11)
> + SETTDI (buf, CPU_PC_GET (current_cpu));
> + else if (0 <= rn && rn < 10)
> + SETTDI (buf, GET_H_GPR (rn));
> + else
> + return 0;
> +
> + return len;
> +}
> +
> +int
> +bpfbf_store_register (SIM_CPU *current_cpu,
> + int rn,
> + unsigned char *buf,
> + int len)
> +{
> + if (rn == 11)
> + CPU_PC_SET (current_cpu, GETTDI (buf));
> + else if (0 <= rn && rn < 10)
> + SET_H_GPR (rn, GETTDI (buf));
> + else
> + return 0;
> +
> + return len;
> +}
> +
> +void
> +bpfbf_model_insn_before (SIM_CPU *current_cpu, int first_p)
> +{
> + /* XXX */
> +}
> +
> +void
> +bpfbf_model_insn_after (SIM_CPU *current_cpu, int first_p)
> +{
> + /* XXX */
> +}
> +
> +\f
> +/***** Instruction helpers. *****/
> +
> +/* The semantic routines for most instructions are expressed in RTL in
> + the cpu/bpf.cpu file, and automatically translated to C in the
> + sem-*.c files in this directory.
> +
> + However, some of the semantic routines make use of helper C
> + functions. This happens when the semantics of the instructions
> + can't be expressed in RTL alone in a satisfactory way, or not at
> + all.
> +
> + The following functions implement these C helpers. */
> +
> +DI
> +bpfbf_endle (SIM_CPU *current_cpu, DI value, UINT bitsize)
> +{
> + switch (bitsize)
> + {
> + case 16: return endian_h2le_2(endian_t2h_2(value));
> + case 32: return endian_h2le_4(endian_t2h_4(value));
> + case 64: return endian_h2le_8(endian_t2h_8(value));
> + default: assert(0);
> + }
> + return value;
> +}
> +
> +DI
> +bpfbf_endbe (SIM_CPU *current_cpu, DI value, UINT bitsize)
> +{
> + switch (bitsize)
> + {
> + case 16: return endian_h2be_2(endian_t2h_2(value));
> + case 32: return endian_h2be_4(endian_t2h_4(value));
> + case 64: return endian_h2be_8(endian_t2h_8(value));
> + default: assert(0);
> + }
> + return value;
> +}
> +
> +DI
> +bpfbf_skb_data_offset (SIM_CPU *current_cpu)
> +{
> + /* Simply return the user-configured value.
> + This will be 0 if it has not been set. */
> + return skb_data_offset;
> +}
> +
> +
> +VOID
> +bpfbf_call (SIM_CPU *current_cpu, INT disp32, UINT src)
> +{
> + /* eBPF supports two kind of CALL instructions: the so called pseudo
> + calls ("bpf to bpf") and external calls ("bpf to helper").
> +
> + Both kind of calls use the same instruction (CALL). However,
> + external calls are constructed by passing a constant argument to
> + the instruction, that identifies the helper, whereas pseudo calls
> + result from expressions involving symbols.
> +
> + We distinguish calls from pseudo-calls with the later having a 1
> + stored in the SRC field of the instruction. */
> +
> + if (src == 1)
> + {
> + /* This is a pseudo-call. */
> +
> + /* XXX allocate a new stack frame and transfer control. For
> + that we need to analyze the target function, like the kernel
> + verifier does. We better populate a cache
> + (function_start_address -> frame_size) so we avoid
> + calculating this more than once. */
> + /* XXX note that disp32 is PC-relative in number of 64-bit
> + words, _minus one_. */
> + }
> + else
> + {
> + /* This is a call to a helper.
> +
> + DISP32 contains the helper number. Dispatch to the
> + corresponding helper emulator in bpf-helpers.c. */
> +
> + switch (disp32) {
> + /* case TRACE_PRINTK: */
> + case 7:
> + bpf_trace_printk (current_cpu);
> + break;
> + default:;
> + }
> + }
> +}
> +
> +VOID
> +bpfbf_exit (SIM_CPU *current_cpu)
> +{
> + SIM_DESC sd = CPU_STATE (current_cpu);
> +
> + /* r0 holds "return code" */
> + DI r0 = GET_H_GPR (0);
> +
> + printf ("exit %ld (0x%lx)\n", r0, r0);
> +
> + sim_engine_halt (sd, current_cpu, NULL, CPU_PC_GET (current_cpu),
> + sim_exited, 0 /* sigrc */);
> +}
> +
> +VOID
> +bpfbf_breakpoint (SIM_CPU *current_cpu)
> +{
> + SIM_DESC sd = CPU_STATE (current_cpu);
> +
> + sim_engine_halt (sd, current_cpu, NULL, CPU_PC_GET (current_cpu),
> + sim_stopped, SIM_SIGTRAP);
> +}
> +
> +/* We use the definitions below instead of the cgen-generated model.c,
> + because the later is not really able to work with cpus featuring
> + several ISAs. This should be fixed in CGEN. */
> +
> +static void
> +bpf_def_model_init ()
> +{
> + /* Do nothing. */
> +}
> +
> +static void
> +bpfbf_prepare_run (SIM_CPU *cpu)
> +{
> + /* Nothing. */
> +}
> +
> +void
> +bpf_engine_run_full (SIM_CPU *cpu)
> +{
> + if (current_target_byte_order == BFD_ENDIAN_LITTLE)
> + {
> + if (!bpf_idesc_le)
> + {
> + bpfbf_ebpfle_init_idesc_table (cpu);
> + bpf_idesc_le = CPU_IDESC (cpu);
> + }
> + else
> + CPU_IDESC (cpu) = bpf_idesc_le;
> +
> + bpfbf_ebpfle_engine_run_full (cpu);
> + }
> + else
> + {
> + if (!bpf_idesc_be)
> + {
> + bpfbf_ebpfbe_init_idesc_table (cpu);
> + bpf_idesc_be = CPU_IDESC (cpu);
> + }
> + else
> + CPU_IDESC (cpu) = bpf_idesc_be;
> +
> + bpfbf_ebpfbe_engine_run_full (cpu);
> + }
> +}
> +
> +#if WITH_FAST
> +
> +void
> +bpf_engine_run_fast (SIM_CPU *cpu)
> +{
> + if (current_target_byte_order == BFD_ENDIAN_LITTLE)
> + {
> + if (!bpf_idesc_le)
> + {
> + bpfbf_ebpfle_init_idesc_table (cpu);
> + bpf_idesc_le = CPU_IDESC (cpu);
> + }
> + else
> + CPU_IDESC (cpu) = bpf_idesc_le;
> +
> + bpfbf_ebpfle_engine_run_fast (cpu);
> + }
> + else
> + {
> + if (!bpf_idesc_be)
> + {
> + bpfbf_ebpfbe_init_idesc_table (cpu);
> + bpf_idesc_be = CPU_IDESC (cpu);
> + }
> + else
> + CPU_IDESC (cpu) = bpf_idesc_be;
> +
> + bpfbf_ebpfbe_engine_run_fast (cpu);
> + }
> +}
> +
> +#endif /* WITH_FAST */
> +
> +static const CGEN_INSN *
> +bpfbf_get_idata (SIM_CPU *cpu, int inum)
> +{
> + return CPU_IDESC (cpu) [inum].idata;
> +}
> +
> +static void
> +bpf_init_cpu (SIM_CPU *cpu)
> +{
> + CPU_REG_FETCH (cpu) = bpfbf_fetch_register;
> + CPU_REG_STORE (cpu) = bpfbf_store_register;
> + CPU_PC_FETCH (cpu) = bpfbf_h_pc_get;
> + CPU_PC_STORE (cpu) = bpfbf_h_pc_set;
> + CPU_GET_IDATA (cpu) = bpfbf_get_idata;
> + /* Only used by profiling. 0 disables it. */
> + CPU_MAX_INSNS (cpu) = 0;
> + CPU_INSN_NAME (cpu) = cgen_insn_name;
> + CPU_FULL_ENGINE_FN (cpu) = bpf_engine_run_full;
> +#if WITH_FAST
> + CPU_FAST_ENGINE_FN (cpu) = bpf_engine_run_fast;
> +#else
> + CPU_FAST_ENGINE_FN (cpu) = bpf_engine_run_full;
> +#endif
> +}
> +
> +static const SIM_MODEL bpf_models[] =
> +{
> + { "bpf-def", & bpf_mach, MODEL_BPF_DEF, NULL, bpf_def_model_init },
> + { 0 }
> +};
> +
> +static const SIM_MACH_IMP_PROPERTIES bpfbf_imp_properties =
> +{
> + sizeof (SIM_CPU),
> +#if WITH_SCACHE
> + sizeof (SCACHE)
> +#else
> + 0
> +#endif
> +};
> +
> +const SIM_MACH bpf_mach =
> +{
> + "bpf", "bpf", MACH_BPF,
> + 32, 32, & bpf_models[0], & bpfbf_imp_properties,
> + bpf_init_cpu,
> + bpfbf_prepare_run
> +};
> diff --git a/sim/bpf/config.in b/sim/bpf/config.in
> new file mode 100644
> index 0000000000..7c667a1c0d
> --- /dev/null
> +++ b/sim/bpf/config.in
> @@ -0,0 +1,248 @@
> +/* config.in. Generated from configure.ac by autoheader. */
> +
> +/* Define if building universal (internal helper macro) */
> +#undef AC_APPLE_UNIVERSAL_BUILD
> +
> +/* Sim debug setting */
> +#undef DEBUG
> +
> +/* Define to 1 if translation of program messages to the user's native
> + language is requested. */
> +#undef ENABLE_NLS
> +
> +/* Define to 1 if you have the <dlfcn.h> header file. */
> +#undef HAVE_DLFCN_H
> +
> +/* Define to 1 if you have the <errno.h> header file. */
> +#undef HAVE_ERRNO_H
> +
> +/* Define to 1 if you have the <fcntl.h> header file. */
> +#undef HAVE_FCNTL_H
> +
> +/* Define to 1 if you have the <fpu_control.h> header file. */
> +#undef HAVE_FPU_CONTROL_H
> +
> +/* Define to 1 if you have the `ftruncate' function. */
> +#undef HAVE_FTRUNCATE
> +
> +/* Define to 1 if you have the `getrusage' function. */
> +#undef HAVE_GETRUSAGE
> +
> +/* Define to 1 if you have the <inttypes.h> header file. */
> +#undef HAVE_INTTYPES_H
> +
> +/* Define to 1 if you have the `nsl' library (-lnsl). */
> +#undef HAVE_LIBNSL
> +
> +/* Define to 1 if you have the `socket' library (-lsocket). */
> +#undef HAVE_LIBSOCKET
> +
> +/* Define to 1 if you have the `lstat' function. */
> +#undef HAVE_LSTAT
> +
> +/* Define to 1 if you have the <memory.h> header file. */
> +#undef HAVE_MEMORY_H
> +
> +/* Define to 1 if you have the `mmap' function. */
> +#undef HAVE_MMAP
> +
> +/* Define to 1 if you have the `munmap' function. */
> +#undef HAVE_MUNMAP
> +
> +/* Define to 1 if you have the `posix_fallocate' function. */
> +#undef HAVE_POSIX_FALLOCATE
> +
> +/* Define to 1 if you have the `sigaction' function. */
> +#undef HAVE_SIGACTION
> +
> +/* Define to 1 if the system has the type `socklen_t'. */
> +#undef HAVE_SOCKLEN_T
> +
> +/* Define to 1 if you have the <stdint.h> header file. */
> +#undef HAVE_STDINT_H
> +
> +/* Define to 1 if you have the <stdlib.h> header file. */
> +#undef HAVE_STDLIB_H
> +
> +/* Define to 1 if you have the <strings.h> header file. */
> +#undef HAVE_STRINGS_H
> +
> +/* Define to 1 if you have the <string.h> header file. */
> +#undef HAVE_STRING_H
> +
> +/* Define to 1 if `st_atime' is a member of `struct stat'. */
> +#undef HAVE_STRUCT_STAT_ST_ATIME
> +
> +/* Define to 1 if `st_blksize' is a member of `struct stat'. */
> +#undef HAVE_STRUCT_STAT_ST_BLKSIZE
> +
> +/* Define to 1 if `st_blocks' is a member of `struct stat'. */
> +#undef HAVE_STRUCT_STAT_ST_BLOCKS
> +
> +/* Define to 1 if `st_ctime' is a member of `struct stat'. */
> +#undef HAVE_STRUCT_STAT_ST_CTIME
> +
> +/* Define to 1 if `st_dev' is a member of `struct stat'. */
> +#undef HAVE_STRUCT_STAT_ST_DEV
> +
> +/* Define to 1 if `st_gid' is a member of `struct stat'. */
> +#undef HAVE_STRUCT_STAT_ST_GID
> +
> +/* Define to 1 if `st_ino' is a member of `struct stat'. */
> +#undef HAVE_STRUCT_STAT_ST_INO
> +
> +/* Define to 1 if `st_mode' is a member of `struct stat'. */
> +#undef HAVE_STRUCT_STAT_ST_MODE
> +
> +/* Define to 1 if `st_mtime' is a member of `struct stat'. */
> +#undef HAVE_STRUCT_STAT_ST_MTIME
> +
> +/* Define to 1 if `st_nlink' is a member of `struct stat'. */
> +#undef HAVE_STRUCT_STAT_ST_NLINK
> +
> +/* Define to 1 if `st_rdev' is a member of `struct stat'. */
> +#undef HAVE_STRUCT_STAT_ST_RDEV
> +
> +/* Define to 1 if `st_size' is a member of `struct stat'. */
> +#undef HAVE_STRUCT_STAT_ST_SIZE
> +
> +/* Define to 1 if `st_uid' is a member of `struct stat'. */
> +#undef HAVE_STRUCT_STAT_ST_UID
> +
> +/* Define to 1 if you have the <sys/mman.h> header file. */
> +#undef HAVE_SYS_MMAN_H
> +
> +/* Define to 1 if you have the <sys/resource.h> header file. */
> +#undef HAVE_SYS_RESOURCE_H
> +
> +/* Define to 1 if you have the <sys/stat.h> header file. */
> +#undef HAVE_SYS_STAT_H
> +
> +/* Define to 1 if you have the <sys/times.h> header file. */
> +#undef HAVE_SYS_TIMES_H
> +
> +/* Define to 1 if you have the <sys/time.h> header file. */
> +#undef HAVE_SYS_TIME_H
> +
> +/* Define to 1 if you have the <sys/types.h> header file. */
> +#undef HAVE_SYS_TYPES_H
> +
> +/* Define to 1 if you have the `time' function. */
> +#undef HAVE_TIME
> +
> +/* Define to 1 if you have the <time.h> header file. */
> +#undef HAVE_TIME_H
> +
> +/* Define to 1 if you have the `truncate' function. */
> +#undef HAVE_TRUNCATE
> +
> +/* Define to 1 if you have the <unistd.h> header file. */
> +#undef HAVE_UNISTD_H
> +
> +/* Define to 1 if you have the <windows.h> header file. */
> +#undef HAVE_WINDOWS_H
> +
> +/* Define to 1 if you have the `__setfpucw' function. */
> +#undef HAVE___SETFPUCW
> +
> +/* Define to the sub-directory in which libtool stores uninstalled libraries.
> + */
> +#undef LT_OBJDIR
> +
> +/* Name of this package. */
> +#undef PACKAGE
> +
> +/* Define to the address where bug reports for this package should be sent. */
> +#undef PACKAGE_BUGREPORT
> +
> +/* Define to the full name of this package. */
> +#undef PACKAGE_NAME
> +
> +/* Define to the full name and version of this package. */
> +#undef PACKAGE_STRING
> +
> +/* Define to the one symbol short name of this package. */
> +#undef PACKAGE_TARNAME
> +
> +/* Define to the home page for this package. */
> +#undef PACKAGE_URL
> +
> +/* Define to the version of this package. */
> +#undef PACKAGE_VERSION
> +
> +/* Additional package description */
> +#undef PKGVERSION
> +
> +/* Sim profile settings */
> +#undef PROFILE
> +
> +/* Bug reporting address */
> +#undef REPORT_BUGS_TO
> +
> +/* Define as the return type of signal handlers (`int' or `void'). */
> +#undef RETSIGTYPE
> +
> +/* Define to 1 if you have the ANSI C header files. */
> +#undef STDC_HEADERS
> +
> +/* Enable extensions on AIX 3, Interix. */
> +#ifndef _ALL_SOURCE
> +# undef _ALL_SOURCE
> +#endif
> +/* Enable GNU extensions on systems that have them. */
> +#ifndef _GNU_SOURCE
> +# undef _GNU_SOURCE
> +#endif
> +/* Enable threading extensions on Solaris. */
> +#ifndef _POSIX_PTHREAD_SEMANTICS
> +# undef _POSIX_PTHREAD_SEMANTICS
> +#endif
> +/* Enable extensions on HP NonStop. */
> +#ifndef _TANDEM_SOURCE
> +# undef _TANDEM_SOURCE
> +#endif
> +/* Enable general extensions on Solaris. */
> +#ifndef __EXTENSIONS__
> +# undef __EXTENSIONS__
> +#endif
> +
> +
> +/* Sim assert settings */
> +#undef WITH_ASSERT
> +
> +/* Sim debug setting */
> +#undef WITH_DEBUG
> +
> +/* Sim default environment */
> +#undef WITH_ENVIRONMENT
> +
> +/* Sim profile settings */
> +#undef WITH_PROFILE
> +
> +/* How to route I/O */
> +#undef WITH_STDIO
> +
> +/* Sim trace settings */
> +#undef WITH_TRACE
> +
> +/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
> + significant byte first (like Motorola and SPARC, unlike Intel). */
> +#if defined AC_APPLE_UNIVERSAL_BUILD
> +# if defined __BIG_ENDIAN__
> +# define WORDS_BIGENDIAN 1
> +# endif
> +#else
> +# ifndef WORDS_BIGENDIAN
> +# undef WORDS_BIGENDIAN
> +# endif
> +#endif
> +
> +/* Define to 1 if on MINIX. */
> +#undef _MINIX
> +
> +/* Define to 2 if the system does not provide POSIX.1 features except with
> + this defined. */
> +#undef _POSIX_1_SOURCE
> +
> +/* Define to 1 if you need to in order for `stat' and other things to work. */
> +#undef _POSIX_SOURCE
> diff --git a/sim/bpf/configure.ac b/sim/bpf/configure.ac
> new file mode 100644
> index 0000000000..16ca54e86c
> --- /dev/null
> +++ b/sim/bpf/configure.ac
> @@ -0,0 +1,13 @@
> +dnl Process this file with autoconf to produce a configure script.
> +AC_INIT(Makefile.in)
> +sinclude(../common/acinclude.m4)
> +
> +SIM_AC_COMMON
> +
> +SIM_AC_OPTION_ENDIAN([], [LITTLE])
> +SIM_AC_OPTION_ALIGNMENT(NONSTRICT_ALIGNMENT)
> +SIM_AC_OPTION_SCACHE(16384)
> +SIM_AC_OPTION_DEFAULT_MODEL([bpf-def])
> +SIM_AC_OPTION_CGEN_MAINT
> +
> +SIM_AC_OUTPUT
> diff --git a/sim/bpf/decode.h b/sim/bpf/decode.h
> new file mode 100644
> index 0000000000..74d31cbdfe
> --- /dev/null
> +++ b/sim/bpf/decode.h
> @@ -0,0 +1,37 @@
> +/* Decode declarations.
> + Copyright (C) 2020 Free Software Foundation, Inc.
> + Contributed by Oracle, Inc.
> +
> +This file is part of the GNU simulators.
> +
> +This program 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.
> +
> +This program 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/>. */
> +
> +/* Include declarations for eBPF LE and eBPF BE ISAs. */
> +
> +#ifndef DECODE_H
> +#define DECODE_H
> +
> +#undef WITH_PROFILE_MODEL_P
> +
> +#ifdef WANT_ISA_EBPFLE
> +#include "decode-le.h"
> +#include "defs-le.h"
> +#endif /* WANT_ISA_EBPFLE */
> +
> +#ifdef WANT_ISA_EBPFBE
> +#include "decode-be.h"
> +#include "defs-be.h"
> +#endif /* WANT_ISA_EBPFBE */
> +
> +#endif /* DECODE_H */
> diff --git a/sim/bpf/eng.h b/sim/bpf/eng.h
> new file mode 100644
> index 0000000000..9277be0489
> --- /dev/null
> +++ b/sim/bpf/eng.h
> @@ -0,0 +1,23 @@
> +/* Engine declarations.
> + Copyright (C) 2020 Free Software Foundation, Inc.
> + Contributed by Oracle, Inc.
> +
> +This file is part of the GNU simulators.
> +
> +This program 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.
> +
> +This program 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/>. */
> +
> +/* Include declarations for eBPF LE and eBPF BE ISAs. */
> +
> +#include "eng-le.h"
> +#include "eng-be.h"
> diff --git a/sim/bpf/mloop.in b/sim/bpf/mloop.in
> new file mode 100644
> index 0000000000..921c591caa
> --- /dev/null
> +++ b/sim/bpf/mloop.in
> @@ -0,0 +1,165 @@
> +# Simulator main loop for eBPF. -*- C -*-
> +#
> +# Copyright (C) 2020 Free Software Foundation, Inc.
> +#
> +# This file is part of the GNU Simulators.
> +#
> +# This program 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.
> +#
> +# This program 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/>.
> +
> +# Syntax:
> +# /bin/sh mloop.in command
> +#
> +# Command is one of:
> +#
> +# init
> +# support
> +# extract-{simple,scache,pbb}
> +# {full,fast}-exec-{simple,scache,pbb}
> +#
> +# A target need only provide a "full" version of one of simple,scache,pbb.
> +# If the target wants it can also provide a fast version of same, or if
> +# the slow (full featured) version is `simple', then the fast version can be
> +# one of scache/pbb.
> +# A target can't provide more than this.
> +# However for illustration's sake this file provides examples of all.
> +
> +# ??? After a few more ports are done, revisit.
> +# Will eventually need to machine generate a lot of this.
> +
> +case "x$1" in
> +
> +xsupport)
> +
> +cat <<EOF
> +
> +static INLINE const IDESC *
> +extract (SIM_CPU *current_cpu, PCADDR pc, CGEN_INSN_WORD insn,
> + ARGBUF *abuf, int fast_p)
> +{
> + const IDESC *id = @prefix@_decode (current_cpu, pc, insn, abuf);
> + @prefix@_fill_argbuf (current_cpu, abuf, id, pc, fast_p);
> + if (!fast_p)
> + {
> + int trace_p = PC_IN_TRACE_RANGE_P (current_cpu, pc);
> + int profile_p = PC_IN_PROFILE_RANGE_P (current_cpu, pc);
> + @prefix@_fill_argbuf_tp (current_cpu, abuf, trace_p, profile_p);
> + }
> + return id;
> +}
> +
> +static INLINE SEM_PC
> +execute (SIM_CPU *current_cpu, SCACHE *sc, int fast_p)
> +{
> + SEM_PC vpc;
> +
> + if (fast_p)
> + vpc = (*sc->argbuf.semantic.sem_fast) (current_cpu, sc);
> + else
> + {
> + ARGBUF *abuf = &sc->argbuf;
> + const IDESC *idesc = abuf->idesc;
> + const CGEN_INSN *idata = idesc->idata;
> + int virtual_p = 0;
> +
> + if (! virtual_p)
> + {
> + /* FIXME: call x-before */
> + if (ARGBUF_PROFILE_P (abuf))
> + PROFILE_COUNT_INSN (current_cpu, abuf->addr, idesc->num);
> + /* FIXME: Later make cover macros: PROFILE_INSN_{INIT,FINI}. */
> + if (PROFILE_MODEL_P (current_cpu)
> + && ARGBUF_PROFILE_P (abuf))
> + @cpu@_model_insn_before (current_cpu, 1 /*first_p*/);
> + CGEN_TRACE_INSN_INIT (current_cpu, abuf, 1);
> + CGEN_TRACE_INSN (current_cpu, idata,
> + (const struct argbuf *) abuf, abuf->addr);
> + }
> + vpc = (*sc->argbuf.semantic.sem_full) (current_cpu, sc);
> + if (! virtual_p)
> + {
> + /* FIXME: call x-after */
> + if (PROFILE_MODEL_P (current_cpu)
> + && ARGBUF_PROFILE_P (abuf))
> + {
> + int cycles;
> +
> + cycles = (*idesc->timing->model_fn) (current_cpu, sc);
> + @cpu@_model_insn_after (current_cpu, 1 /*last_p*/, cycles);
> + }
> + CGEN_TRACE_INSN_FINI (current_cpu, abuf, 1);
> + }
> + }
> +
> + return vpc;
> +}
> +
> +EOF
> +
> +;;
> +
> +xinit)
> +
> +# Nothing needed.
> +
> +;;
> +
> +xextract-scache)
> +
> +cat <<EOF
> +{
> +
> + UDI insn = GETIMEMUDI (current_cpu, vpc);
> +
> + if (current_target_byte_order == BFD_ENDIAN_BIG)
> + {
> + /* eBPF instructions are little-endian, but GETIMEMUDI reads according
> + to target byte order. Swap to little-endian. */
> + insn = SWAP_8 (insn);
> +
> + /* But, the imm32 and offset16 fields within instructions follow target
> + byte order. Swap those fields back. */
> + UHI off16 = (UHI) ((insn & 0x00000000ffff0000) >> 16);
> + USI imm32 = (USI) ((insn & 0xffffffff00000000) >> 32);
> + off16 = SWAP_2 (off16);
> + imm32 = SWAP_4 (imm32);
> +
> + insn = (((UDI) imm32) << 32) | (((UDI) off16) << 16) | (insn & 0xffff);
> + }
> +
> + extract (current_cpu, vpc, insn, sc, FAST_P);
> +
> + //XXX SEM_SKIP_COMPILE (current_cpu, sc, 1);
> +}
> +EOF
> +
> +;;
> +
> +xfull-exec-* | xfast-exec-*)
> +
> +# Inputs: current_cpu, vpc, sc, FAST_P
> +# Outputs: vpc
> +# vpc is the virtual program counter.
> +
> +cat <<EOF
> + vpc = execute (current_cpu, sc, FAST_P);
> +EOF
> +
> +;;
> +
> +*)
> + echo "Invalid argument to mainloop.in: $1" >&2
> + exit 1
> + ;;
> +
> +esac
> diff --git a/sim/bpf/sim-if.c b/sim/bpf/sim-if.c
> new file mode 100644
> index 0000000000..fbb122b36e
> --- /dev/null
> +++ b/sim/bpf/sim-if.c
> @@ -0,0 +1,214 @@
> +/* Main simulator entry points specific to the eBPF.
> + Copyright (C) 2020 Free Software Foundation, Inc.
> +
> + This file is part of GDB, the GNU debugger.
> +
> + This program 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.
> +
> + This program 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/>. */
> +
> +#include "sim-main.h"
> +#include "sim-options.h"
> +#include "libiberty.h"
> +#include "bfd.h"
> +
> +/* Globals. */
> +
> +/* String with the name of the section containing the BPF program to
> + run. */
> +static char *bpf_program_section = NULL;
> +
> +extern uint64_t skb_data_offset;
> +
> +\f
> +/* Handle BPF-specific options. */
> +
> +static SIM_RC bpf_option_handler (SIM_DESC, sim_cpu *, int, char *, int);
> +
> +typedef enum
> +{
> + OPTION_BPF_SET_PROGRAM = OPTION_START,
> + OPTION_BPF_LIST_PROGRAMS,
> + OPTION_BPF_VERIFY_PROGRAM,
> + OPTION_BPF_SKB_DATA_OFFSET,
> +} BPF_OPTION;
> +
> +static const OPTION bpf_options[] =
> +{
> + { {"bpf-set-program", required_argument, NULL, OPTION_BPF_SET_PROGRAM},
> + '\0', "SECTION_NAME", "Set the entry point",
> + bpf_option_handler },
> + { {"bpf-list-programs", no_argument, NULL, OPTION_BPF_LIST_PROGRAMS},
> + '\0', "", "List loaded bpf programs",
> + bpf_option_handler },
> + { {"bpf-verify-program", required_argument, NULL, OPTION_BPF_VERIFY_PROGRAM},
> + '\0', "PROGRAM", "Run the verifier on the given BPF program",
> + bpf_option_handler },
> + { {"skb-data-offset", required_argument, NULL, OPTION_BPF_SKB_DATA_OFFSET},
> + '\0', "OFFSET", "Configure offsetof(struct sk_buff, data)",
> + bpf_option_handler },
> +
> + { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL, NULL }
> +};
> +
> +static SIM_RC
> +bpf_option_handler (SIM_DESC sd, sim_cpu *cpu ATTRIBUTE_UNUSED, int opt,
> + char *arg, int is_command ATTRIBUTE_UNUSED)
> +{
> + switch ((BPF_OPTION) opt)
> + {
> + case OPTION_BPF_VERIFY_PROGRAM:
> + /* XXX call the verifier. */
> + sim_io_printf (sd, "Verifying BPF program %s...\n", arg);
> + break;
> +
> + case OPTION_BPF_LIST_PROGRAMS:
> + /* XXX list programs. */
> + sim_io_printf (sd, "BPF programs available:\n");
> + break;
> +
> + case OPTION_BPF_SET_PROGRAM:
> + /* XXX: check that the section exists and tell the user about a
> + new start_address. */
> + bpf_program_section = xstrdup (arg);
> + break;
> +
> + case OPTION_BPF_SKB_DATA_OFFSET:
> + skb_data_offset = strtoul (arg, NULL, 0);
> + break;
> +
> + default:
> + sim_io_eprintf (sd, "Unknown option `%s'\n", arg);
> + return SIM_RC_FAIL;
> + }
> +
> + return SIM_RC_OK;
> +}
> +
> +/* Like sim_state_free, but free the cpu buffers as well. */
> +
> +static void
> +bpf_free_state (SIM_DESC sd)
> +{
> + if (STATE_MODULES (sd) != NULL)
> + sim_module_uninstall (sd);
> +
> + sim_cpu_free_all (sd);
> + sim_state_free (sd);
> +}
> +
> +/* Create an instance of the simulator. */
> +
> +SIM_DESC
> +sim_open (SIM_OPEN_KIND kind,
> + host_callback *callback,
> + struct bfd *abfd,
> + char * const *argv)
> +{
> + /* XXX Analyze the program, and collect per-function information
> + like the kernel verifier does. The implementation of the CALL
> + instruction will need that information, to update %fp. */
> +
> + SIM_DESC sd = sim_state_alloc (kind, callback);
> +
> + if (sim_cpu_alloc_all (sd, 1, cgen_cpu_max_extra_bytes ())
> + != SIM_RC_OK)
> + goto error;
> +
> + if (sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK)
> + goto error;
> +
> + /* Add the BPF-specific option list to the simulator. */
> + if (sim_add_option_table (sd, NULL, bpf_options) != SIM_RC_OK)
> + {
> + bpf_free_state (sd);
> + return 0;
> + }
> +
> + if (sim_parse_args (sd, argv) != SIM_RC_OK)
> + goto error;
> +
> + if (sim_analyze_program (sd,
> + (STATE_PROG_ARGV (sd) != NULL
> + ? *STATE_PROG_ARGV (sd)
> + : NULL), abfd) != SIM_RC_OK)
> + goto error;
> +
> + if (sim_config (sd) != SIM_RC_OK)
> + goto error;
> +
> + if (sim_post_argv_init (sd) != SIM_RC_OK)
> + goto error;
> +
> + /* ... */
> +
> + /* Initialize the CPU descriptors and the disassemble in the cpu
> + descriptor table entries. */
> + {
> + int i;
> + CGEN_CPU_DESC cd = bpf_cgen_cpu_open_1 (STATE_ARCHITECTURE (sd)->printable_name,
> + CGEN_ENDIAN_LITTLE);
> +
> + /* We have one cpu per installed program! MAX_NR_PROCESSORS is an
> + arbitrary upper limit. XXX where is it defined? */
> + for (i = 0; i < MAX_NR_PROCESSORS; ++i)
> + {
> + SIM_CPU *cpu = STATE_CPU (sd, i);
> +
> + CPU_CPU_DESC (cpu) = cd;
> + CPU_DISASSEMBLER (cpu) = sim_cgen_disassemble_insn;
> + }
> +
> + bpf_cgen_init_dis (cd);
> + }
> +
> + /* Initialize various cgen things not done by common framework.
> + Must be done after bpf_cgen_cpu_open. */
> + cgen_init (sd);
> +
> + /* XXX do eBPF sim specific initializations. */
> +
> + return sd;
> +
> + error:
> + bpf_free_state (sd);
> + return NULL;
> +}
> +\f
> +
> +SIM_RC
> +sim_create_inferior (SIM_DESC sd, struct bfd *abfd,
> + char *const *argv, char *const *envp)
> +{
> + SIM_CPU *current_cpu = STATE_CPU (sd, 0);
> + SIM_ADDR addr;
> +
> + /* Determine the start address.
> +
> + XXX acknowledge bpf_program_section. If it is NULL, emit a
> + warning explaining that we are using the ELF file start address,
> + which often is not what is actually wanted. */
> + if (abfd != NULL)
> + addr = bfd_get_start_address (abfd);
> + else
> + addr = 0;
> +
> + sim_pc_set (current_cpu, addr);
> +
> + if (STATE_PROG_ARGV (sd) != argv)
> + {
> + freeargv (STATE_PROG_ARGV (sd));
> + STATE_PROG_ARGV (sd) = dupargv (argv);
> + }
> +
> + return SIM_RC_OK;
> +}
> diff --git a/sim/bpf/sim-main.h b/sim/bpf/sim-main.h
> new file mode 100644
> index 0000000000..fc1e69f6f3
> --- /dev/null
> +++ b/sim/bpf/sim-main.h
> @@ -0,0 +1,51 @@
> +/* eBPF simulator main header
> + Copyright (C) 2020 Free Software Foundation, Inc.
> +
> + This file is part of GDB, the GNU debugger.
> +
> + This program 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.
> +
> + This program 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/>. */
> +
> +#ifndef SIM_MAIN_H
> +#define SIM_MAIN_H
> +
> +#include "sim-basics.h"
> +#include "cgen-types.h"
> +#include "bpf-desc.h"
> +#include "bpf-opc.h"
> +#include "arch.h"
> +#include "sim-base.h"
> +#include "cgen-sim.h"
> +#include "bpf-sim.h"
> +
> +
> +struct _sim_cpu
> +{
> + sim_cpu_base base;
> + CGEN_CPU cgen_cpu;
> +
> +#if defined (WANT_CPU_BPFBF)
> + BPFBF_CPU_DATA cpu_data;
> +#endif
> +};
> +
> +\f
> +
> +struct sim_state
> +{
> + sim_cpu *cpu[MAX_NR_PROCESSORS];
> + CGEN_STATE cgen_state;
> + sim_state_base base;
> +};
> +
> +#endif /* ! SIM_MAIN_H */
> diff --git a/sim/bpf/traps.c b/sim/bpf/traps.c
> new file mode 100644
> index 0000000000..e7ac0c2838
> --- /dev/null
> +++ b/sim/bpf/traps.c
> @@ -0,0 +1,33 @@
> +/* Trap handlers for eBPF.
> + Copyright (C) 2020 Free Software Foundation, Inc.
> +
> + This file is part of GDB, the GNU debugger.
> +
> + This program 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.
> +
> + This program 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/>. */
> +
> +#define WANT_CPU bpfbf
> +#define WANT_CPU_BPFBF
> +
> +#include "sim-main.h"
> +
> +SEM_PC
> +sim_engine_invalid_insn (SIM_CPU *current_cpu ATTRIBUTE_UNUSED,
> + IADDR cia ATTRIBUTE_UNUSED,
> + SEM_PC pc ATTRIBUTE_UNUSED)
> +{
> + /* Can't just return 0 here: the return value is used to set vpc
> + (see decdde-{le,be}.c)
> + Returning 0 will cause an infinite loop! */
> + abort();
> +}
> diff --git a/sim/configure b/sim/configure
> index 72f95cd5c7..37a86f435c 100755
> --- a/sim/configure
> +++ b/sim/configure
> @@ -669,6 +669,7 @@ ac_subdirs_all='aarch64
> arm
> avr
> bfin
> +bpf
> cr16
> cris
> d10v
> @@ -3717,6 +3718,13 @@ subdirs="$subdirs aarch64"
> subdirs="$subdirs bfin"
>
>
> + ;;
> + bpf-*-*)
> +
> + sim_arch=bpf
> + subdirs="$subdirs bpf"
> +
> +
> ;;
> cr16*-*-*)
>
> diff --git a/sim/configure.tgt b/sim/configure.tgt
> index 8a8e03d96f..c115c3c8dd 100644
> --- a/sim/configure.tgt
> +++ b/sim/configure.tgt
> @@ -26,6 +26,9 @@ case "${target}" in
> bfin-*-*)
> SIM_ARCH(bfin)
> ;;
> + bpf-*-*)
> + SIM_ARCH(bpf)
> + ;;
> cr16*-*-*)
> SIM_ARCH(cr16)
> ;;
> diff --git a/sim/testsuite/configure b/sim/testsuite/configure
> index d15fbbab56..c3674c2fa0 100755
> --- a/sim/testsuite/configure
> +++ b/sim/testsuite/configure
> @@ -1875,6 +1875,9 @@ case "${target}" in
> bfin-*-*)
> sim_arch=bfin
> ;;
> + bpf-*-*)
> + sim_arch=bpf
> + ;;
> cr16*-*-*)
> sim_arch=cr16
> ;;
> diff --git a/sim/testsuite/sim/bpf/allinsn.exp b/sim/testsuite/sim/bpf/allinsn.exp
> new file mode 100644
> index 0000000000..2cca77021a
> --- /dev/null
> +++ b/sim/testsuite/sim/bpf/allinsn.exp
> @@ -0,0 +1,26 @@
> +# eBPF simulator testsuite
> +
> +if [istarget bpf-unknown-none] {
> + # all machines
> + set all_machs "bpf"
> +
> + global global_sim_options
> + if ![info exists global_sim_options] {
> + set global_sim_options "--memory-size=4Mb"
> + }
> +
> + global global_ld_options
> + if ![info exists global_ld_options] {
> + set global_ld_options "-Ttext=0x0"
> + }
> +
> + foreach src [lsort [glob -nocomplain $srcdir/$subdir/*.s]] {
> + # If we're only testing specific files and this isn't one of them,
> + # skip it.
> + if ![runtest_file_p $runtests $src] {
> + continue
> + }
> +
> + run_sim_test $src $all_machs
> + }
> +}
> diff --git a/sim/testsuite/sim/bpf/alu.s b/sim/testsuite/sim/bpf/alu.s
> new file mode 100644
> index 0000000000..6013ac7eb9
> --- /dev/null
> +++ b/sim/testsuite/sim/bpf/alu.s
> @@ -0,0 +1,109 @@
> +# mach: bpf
> +# output: pass\nexit 0 (0x0)\n
> +;;; alu.s
> +;;; Tests for ALU64 BPF instructions in simulator
> +
> + .include "testutils.inc"
> +
> + .text
> + .global main
> + .type main, @function
> +main:
> + mov %r1, 0
> + mov %r2, -1
> +
> + ;; add
> + add %r1, 1
> + add %r2, -1
> + add %r1, %r2
> + fail_ne %r1, -1
> +
> + ;; sub
> + sub %r1, %r1
> + fail_ne %r1, 0
> + sub %r1, 10
> + sub %r2, %r1
> + fail_ne %r2, 8
> +
> + ;; mul
> + mul %r2, %r2 ; r2 = 64
> + mul %r2, 3 ; r2 = 192
> + mov %r1, -3
> + mul %r1, %r2 ; r1 = -576
> + mul %r2, 0
> + fail_ne %r1, -576
> + fail_ne %r2, 0
> + mul %r1, %r1
> + mul %r1, %r1
> + fail_ne %r1, 110075314176
> +
> + ;; div
> + div %r2, %r1
> + fail_ne %r2, 0
> + div %r1, -10000
> + fail_ne %r1, -11007531
> + div %r1, %r1
> + fail_ne %r1, 1
> +
> + ;; and
> + lddw %r1, 0xaaaaaaaa55555555
> + and %r1, 0x55aaaaaa ; we still only have 32-bit imm.
> + fail_ne %r1, 0x0000000055000000
> + lddw %r2, 0x5555555a5aaaaaaa
> + and %r2, %r1
> + fail_ne %r2, 0x0000000050000000
> +
> + ;; or
> + or %r2, 0xdeadbeef
> + fail_ne %r2, 0xffffffffdeadbeef ; 0xdeadbeef gets sign extended
> + lddw %r1, 0xdead00000000beef
> + lddw %r2, 0x0000123456780000
> + or %r1, %r2
> + fail_ne %r1, 0xdead12345678beef
> +
> + ;; lsh
> + mov %r1, 0xdeadbeef
> + lsh %r1, 11
> + fail_ne %r1, 0xfffffef56df77800 ; because deadbeef gets sign ext.
> + mov %r2, 21
> + lsh %r1, %r2
> + fail_ne %r1, 0xdeadbeef00000000
> +
> + ;; rsh
> + rsh %r1, 11
> + fail_ne %r1, 0x001bd5b7dde00000 ; 0xdeadbeef 00000000 >> 0xb
> + rsh %r1, %r2
> + fail_ne %r1, 0x00000000deadbeef
> +
> + ;; arsh
> + arsh %r1, 8
> + fail_ne %r1, 0x0000000000deadbe
> + lsh %r1, 40 ; r1 = 0xdead be00 0000 0000
> + arsh %r1, %r2 ; r1 arsh (r2 == 21)
> + fail_ne %r1, 0xfffffef56df00000
> +
> + ;; mod
> + mov %r1, 1025
> + mod %r1, -16
> + fail_ne %r1, 1
> + mov %r1, -25
> + mov %r2, 5
> + mod %r1, %r2
> + fail_ne %r1, 0
> +
> + ;; xor
> + xor %r1, %r2
> + fail_ne %r1, 5
> + xor %r1, 0x7eadbeef
> + fail_ne %r1, 0x7eadbeea
> + xor %r1, %r1
> + fail_ne %r1, 0
> +
> + ;; neg
> + neg %r2
> + fail_ne %r2, -5
> + mov %r1, -1025
> + neg %r1
> + fail_ne %r1, 1025
> +
> + pass
> diff --git a/sim/testsuite/sim/bpf/alu32.s b/sim/testsuite/sim/bpf/alu32.s
> new file mode 100644
> index 0000000000..fcd6699464
> --- /dev/null
> +++ b/sim/testsuite/sim/bpf/alu32.s
> @@ -0,0 +1,99 @@
> +# mach: bpf
> +# output: pass\nexit 0 (0x0)\n
> +;; alu32.s
> +;; Tests for ALU(32) BPF instructions in simulator
> +
> + .include "testutils.inc"
> +
> + .text
> + .global main
> + .type main, @function
> +main:
> + mov32 %r1, 10 ; r1 = 10
> + mov32 %r2, -5 ; r2 = -5
> +
> + ;; add
> + add32 %r1, 1 ; r1 += 1 (r1 = 11)
> + add32 %r2, -1 ; r2 += -1 (r2 = -6)
> + add32 %r1, %r2 ; r1 += r2 (r1 = 11 + -6 = 5)
> + fail_ne32 %r1, 5
> +
> + ;; sub
> + sub32 %r1, 5 ; r1 -= 5 (r1 = 0)
> + sub32 %r1, -5 ; r1 -= -5 (r1 = 5)
> + sub32 %r1, %r2 ; r1 -= r2 (r1 = 5 - -6 = 11)
> + fail_ne32 %r1, 11
> +
> + ;; mul
> + mul32 %r1, 2 ; r1 *= 2 (r1 = 22)
> + mul32 %r1, -2 ; r1 *= -2 (r1 = -44)
> + mul32 %r1, %r2 ; r1 *= r2 (r1 = -44 * -6 = 264)
> + fail_ne32 %r1, 264
> +
> + ;; div
> + div32 %r1, %r2 ; r1 /= r2 (r1 = 264 / -6 = -44)
> + div32 %r1, -2 ; r1 /= -2 (r1 = 22)
> + div32 %r1, 2 ; r1 /= 2 (r1 = 11)
> + fail_ne32 %r1, 11
> +
> + ;; and (bitwise)
> + mov32 %r1, 0xb ; r1 = (0xb = 0b1011)
> + mov32 %r2, 0x5 ; r2 = (0x5 = 0b0101)
> + and32 %r1, 0xa ; r1 &= (0xa = 0b1010) = (0b1010 = 0xa)
> + fail_ne32 %r1, 0xa
> + and32 %r1, %r2 ; r1 &= r2 = 0x0
> + fail_ne32 %r1, 0x0
> +
> + ;; or (bitwise)
> + or32 %r1, 0xb
> + or32 %r1, %r2
> + fail_ne32 %r1, 0xf
> +
> + ;; lsh (left shift)
> + lsh32 %r1, 4 ; r1 <<= 4 (r1 = 0xf0)
> + mov32 %r2, 24 ; r2 = 24
> + lsh32 %r1, %r2
> + fail_ne32 %r1, 0xf0000000
> +
> + ;; rsh (right logical shift)
> + rsh32 %r1, 2
> + rsh32 %r1, %r2
> + fail_ne32 %r1, 0x3c ; (0xf000 0000 >> 26)
> +
> + ;; arsh (right arithmetic shift)
> + arsh32 %r1, 1
> + or32 %r1, 0x80000000
> + mov32 %r2, 3
> + arsh32 %r1, %r2
> + fail_ne %r1, 0x00000000F0000003
> + ; Note: make sure r1 is NOT sign-extended
> + ; i.e. upper-32 bits should be untouched
> +
> + ;; mod
> + mov32 %r1, -25
> + mov32 %r2, 4
> + mod32 %r1, %r2
> + fail_ne32 %r1, -1
> + mov32 %r1, 25
> + mod32 %r1, 5
> + fail_ne32 %r1, 0
> +
> + ;; xor
> + xor32 %r1, %r2
> + fail_ne32 %r1, 4
> + xor32 %r1, 0xF000000F
> + fail_ne %r1, 0xF000000B ; Note: check for (bad) sign-extend
> + xor32 %r1, %r1
> + fail_ne %r1, 0
> +
> + ;; neg
> + mov32 %r1, -1
> + mov32 %r2, 0x7fffffff
> + neg32 %r1
> + neg32 %r2
> + fail_ne32 %r1, 1
> + fail_ne %r2, 0x80000001 ; Note: check for (bad) sign-extend
> + neg32 %r2
> + fail_ne32 %r2, 0x7fffffff
> +
> + pass
> diff --git a/sim/testsuite/sim/bpf/endbe.s b/sim/testsuite/sim/bpf/endbe.s
> new file mode 100644
> index 0000000000..2f662aec02
> --- /dev/null
> +++ b/sim/testsuite/sim/bpf/endbe.s
> @@ -0,0 +1,46 @@
> +# mach: bpf
> +# as: --EB
> +# ld: --EB
> +# sim: -E big
> +# output: pass\nexit 0 (0x0)\n
> +;;; endbe.s
> +;;; Tests for BPF endianness-conversion instructions in simulator
> +;;; running in BIG ENDIAN
> +;;;
> +;;; Both 'be' and 'le' ISAs have both endbe and endle instructions.
> +
> + .include "testutils.inc"
> +
> + .text
> + .global main
> + .type main, @function
> +main:
> + lddw %r1, 0x12345678deadbeef
> + endle %r1, 64
> + fail_ne %r1, 0xefbeadde78563412
> + endle %r1, 64
> + fail_ne %r1, 0x12345678deadbeef
> +
> + ;; `bitsize` < 64 will truncate
> + endle %r1, 32
> + fail_ne %r1, 0xefbeadde
> + endle %r1, 32
> + fail_ne %r1, 0xdeadbeef
> +
> + endle %r1, 16
> + fail_ne %r1, 0xefbe
> + endle %r1, 16
> + fail_ne %r1, 0xbeef
> +
> + ;; endbe on be should be noop (except truncate)
> + lddw %r1, 0x12345678deadbeef
> + endbe %r1, 64
> + fail_ne %r1, 0x12345678deadbeef
> +
> + endbe %r1, 32
> + fail_ne %r1, 0xdeadbeef
> +
> + endbe %r1, 16
> + fail_ne %r1, 0xbeef
> +
> + pass
> diff --git a/sim/testsuite/sim/bpf/endle.s b/sim/testsuite/sim/bpf/endle.s
> new file mode 100644
> index 0000000000..d8f5ceb977
> --- /dev/null
> +++ b/sim/testsuite/sim/bpf/endle.s
> @@ -0,0 +1,43 @@
> +# mach: bpf
> +# output: pass\nexit 0 (0x0)\n
> +;;; endle.s
> +;;; Tests for BPF endianness-conversion instructions in simulator
> +;;; running in LITTLE ENDIAN
> +;;;
> +;;; Both 'be' and 'le' ISAs have both endbe and endle instructions.
> +
> + .include "testutils.inc"
> +
> + .text
> + .global main
> + .type main, @function
> +main:
> + lddw %r1, 0x12345678deadbeef
> + endbe %r1, 64
> + fail_ne %r1, 0xefbeadde78563412
> + endbe %r1, 64
> + fail_ne %r1, 0x12345678deadbeef
> +
> + ;; `bitsize` < 64 will truncate
> + endbe %r1, 32
> + fail_ne %r1, 0xefbeadde
> + endbe %r1, 32
> + fail_ne %r1, 0xdeadbeef
> +
> + endbe %r1, 16
> + fail_ne %r1, 0xefbe
> + endbe %r1, 16
> + fail_ne %r1, 0xbeef
> +
> + ;; endle on le should be noop (except truncate)
> + lddw %r1, 0x12345678deadbeef
> + endle %r1, 64
> + fail_ne %r1, 0x12345678deadbeef
> +
> + endle %r1, 32
> + fail_ne %r1, 0xdeadbeef
> +
> + endle %r1, 16
> + fail_ne %r1, 0xbeef
> +
> + pass
> diff --git a/sim/testsuite/sim/bpf/jmp.s b/sim/testsuite/sim/bpf/jmp.s
> new file mode 100644
> index 0000000000..5ab5de005a
> --- /dev/null
> +++ b/sim/testsuite/sim/bpf/jmp.s
> @@ -0,0 +1,120 @@
> +# mach: bpf
> +# output: pass\nexit 0 (0x0)\n
> +;;; jmp.s
> +;;; Tests for eBPF JMP instructions in simulator
> +
> + .include "testutils.inc"
> +
> + .text
> + .global main
> + .type main, @function
> +main:
> + mov %r1, 5
> + mov %r2, 2
> + mov %r3, 7
> + mov %r4, -1
> +
> + ;; ja - jump absolute (unconditional)
> + ja 2f
> +1: fail
> +
> +2: ;; jeq - jump eq
> + jeq %r1, 4, 1b ; no
> + jeq %r1, %r2, 1b ; no
> + jeq %r1, 5, 2f ; yes
> + fail
> +2: jeq %r1, %r1, 2f ; yes
> + fail
> +
> +2: ;; jgt - jump (unsigned) greater-than
> + jgt %r1, 6, 1b ; no
> + jgt %r1, -5, 1b ; no - unsigned
> + jgt %r1, %r4, 1b ; no - unsigned
> + jgt %r1, 4, 2f ; yes
> + fail
> +2: jgt %r1, %r2, 2f ; yes
> + fail
> +
> +2: ;; jge - jump (unsigned) greater-than-or-equal-to
> + jge %r1, 6, 1b ; no
> + jge %r1, 5, 2f ; yes
> + fail
> +2: jge %r1, %r3, 1b ; no
> + jge %r1, -5, 1b ; no - unsigned
> + jge %r1, %r2, 2f ; yes
> + fail
> +
> +2: ;; jlt - jump (unsigned) less-than
> + jlt %r1, 5, 1b ; no
> + jlt %r1, %r2, 1b ; no
> + jlt %r4, %r1, 1b ; no - unsigned
> + jlt %r1, 6, 2f ; yes
> + fail
> +2:
> + jlt %r1, %r3, 2f ; yes
> + fail
> +
> +2: ;; jle - jump (unsigned) less-than-or-equal-to
> + jle %r1, 4, 1b ; no
> + jle %r1, %r2, 1b ; no
> + jle %r4, %r1, 1b ; no
> + jle %r1, 5, 2f ; yes
> + fail
> +2: jle %r1, %r1, 2f ; yes
> + fail
> +
> +2: ;; jset - jump "test" (AND)
> + jset %r1, 2, 1b ; no (5 & 2 = 0)
> + jset %r1, %r2, 1b ; no (same)
> + jset %r1, 4, 2f ; yes (5 & 4 != 0)
> + fail
> +
> +2: ;; jne - jump not-equal-to
> + jne %r1, 5, 1b ; no
> + jne %r1, %r1, 1b ; no
> + jne %r1, 6, 2f ; yes
> + fail
> +2: jne %r1, %r4, 2f ; yes
> + fail
> +
> +2: ;; jsgt - jump (signed) greater-than
> + jsgt %r1, %r3, 1b ; no
> + jsgt %r1, %r1, 1b ; no
> + jsgt %r1, 5, 1b ; no
> + jsgt %r1, -4, 2f ; yes
> + fail
> +2: jsgt %r1, %r4, 2f ; yes
> + fail
> +
> +2: ;; jsge - jump (signed) greater-than-or-equal-to
> + jsge %r1, %r3, 1b ; no
> + jsge %r1, %r1, 2f ; yes
> + fail
> +2: jsge %r1, 7, 1b ; no
> + jsge %r1, -4, 2f ; yes
> + fail
> +2: jsge %r1, %r4, 2f ; yes
> + fail
> +
> +2: ;; jslt - jump (signed) less-than
> + jslt %r1, 5, 1b ; no
> + jslt %r1, %r2, 1b ; no
> + jslt %r4, %r1, 2f ; yes
> + fail
> +2: jslt %r1, 6, 2f ; yes
> + fail
> +2: jslt %r1, %r3, 2f ; yes
> + fail
> +
> +2: ;; jsle - jump (signed) less-than-or-equal-to
> + jsle %r1, 4, 1b ; no
> + jsle %r1, %r2, 1b ; no
> + jsle %r4, %r1, 2f ; yes
> + fail
> +2: jsle %r1, 5, 2f ; yes
> + fail
> +2: jsle %r1, %r3, 2f ; yes
> + fail
> +
> +2:
> + pass
> diff --git a/sim/testsuite/sim/bpf/jmp32.s b/sim/testsuite/sim/bpf/jmp32.s
> new file mode 100644
> index 0000000000..a6074cd4de
> --- /dev/null
> +++ b/sim/testsuite/sim/bpf/jmp32.s
> @@ -0,0 +1,120 @@
> +# mach: bpf
> +# output: pass\nexit 0 (0x0)\n
> +;;; jmp32.s
> +;;; Tests for eBPF JMP32 instructions in simulator
> +
> + .include "testutils.inc"
> +
> + .text
> + .global main
> + .type main, @function
> +main:
> + mov32 %r1, 5
> + mov32 %r2, 2
> + mov32 %r3, 7
> + mov32 %r4, -1
> +
> + ;; ja - jump absolute (unconditional)
> + ja 2f
> +1: fail
> +
> +2: ;; jeq - jump eq
> + jeq32 %r1, 4, 1b ; no
> + jeq32 %r1, %r2, 1b ; no
> + jeq32 %r1, 5, 2f ; yes
> + fail
> +2: jeq32 %r1, %r1, 2f ; yes
> + fail
> +
> +2: ;; jgt - jump (unsigned) greater-than
> + jgt32 %r1, 6, 1b ; no
> + jgt32 %r1, -5, 1b ; no - unsigned
> + jgt32 %r1, %r4, 1b ; no - unsigned
> + jgt32 %r1, 4, 2f ; yes
> + fail
> +2: jgt32 %r1, %r2, 2f ; yes
> + fail
> +
> +2: ;; jge - jump (unsigned) greater-than-or-equal-to
> + jge32 %r1, 6, 1b ; no
> + jge32 %r1, 5, 2f ; yes
> + fail
> +2: jge32 %r1, %r3, 1b ; no
> + jge32 %r1, -5, 1b ; no - unsigned
> + jge32 %r1, %r2, 2f ; yes
> + fail
> +
> +2: ;; jlt - jump (unsigned) less-than
> + jlt32 %r1, 5, 1b ; no
> + jlt32 %r1, %r2, 1b ; no
> + jlt32 %r4, %r1, 1b ; no - unsigned
> + jlt32 %r1, 6, 2f ; yes
> + fail
> +2:
> + jlt32 %r1, %r3, 2f ; yes
> + fail
> +
> +2: ;; jle - jump (unsigned) less-than-or-equal-to
> + jle32 %r1, 4, 1b ; no
> + jle32 %r1, %r2, 1b ; no
> + jle32 %r4, %r1, 1b ; no
> + jle32 %r1, 5, 2f ; yes
> + fail
> +2: jle32 %r1, %r1, 2f ; yes
> + fail
> +
> +2: ;; jset - jump "test" (AND)
> + jset32 %r1, 2, 1b ; no (5 & 2 = 0)
> + jset32 %r1, %r2, 1b ; no (same)
> + jset32 %r1, 4, 2f ; yes (5 & 4 != 0)
> + fail
> +
> +2: ;; jne - jump not-equal-to
> + jne32 %r1, 5, 1b ; no
> + jne32 %r1, %r1, 1b ; no
> + jne32 %r1, 6, 2f ; yes
> + fail
> +2: jne32 %r1, %r4, 2f ; yes
> + fail
> +
> +2: ;; jsgt - jump (signed) greater-than
> + jsgt32 %r1, %r3, 1b ; no
> + jsgt32 %r1, %r1, 1b ; no
> + jsgt32 %r1, 5, 1b ; no
> + jsgt32 %r1, -4, 2f ; yes
> + fail
> +2: jsgt32 %r1, %r4, 2f ; yes
> + fail
> +
> +2: ;; jsge - jump (signed) greater-than-or-equal-to
> + jsge32 %r1, %r3, 1b ; no
> + jsge32 %r1, %r1, 2f ; yes
> + fail
> +2: jsge32 %r1, 7, 1b ; no
> + jsge32 %r1, -4, 2f ; yes
> + fail
> +2: jsge32 %r1, %r4, 2f ; yes
> + fail
> +
> +2: ;; jslt - jump (signed) less-than
> + jslt32 %r1, 5, 1b ; no
> + jslt32 %r1, %r2, 1b ; no
> + jslt32 %r4, %r1, 2f ; yes
> + fail
> +2: jslt32 %r1, 6, 2f ; yes
> + fail
> +2: jslt32 %r1, %r3, 2f ; yes
> + fail
> +
> +2: ;; jsle - jump (signed) less-than-or-equal-to
> + jsle32 %r1, 4, 1b ; no
> + jsle32 %r1, %r2, 1b ; no
> + jsle32 %r4, %r1, 2f ; yes
> + fail
> +2: jsle32 %r1, 5, 2f ; yes
> + fail
> +2: jsle32 %r1, %r3, 2f ; yes
> + fail
> +
> +2:
> + pass
> diff --git a/sim/testsuite/sim/bpf/ldabs.s b/sim/testsuite/sim/bpf/ldabs.s
> new file mode 100644
> index 0000000000..ae777f1cf5
> --- /dev/null
> +++ b/sim/testsuite/sim/bpf/ldabs.s
> @@ -0,0 +1,87 @@
> +# mach: bpf
> +# sim: --skb-data-offset=0x20
> +# output: pass\nexit 0 (0x0)\n
> +;;; ldabs.s
> +;;; Tests for non-generic BPF load instructions in simulator.
> +;;; These instructions (ld{abs,ind}{b,h,w,dw}) are used to access
> +;;; kernel socket data from BPF programs for high performance filters.
> +;;;
> +;;; Register r6 is an implicit input holding a pointer to a struct sk_buff.
> +;;; Register r0 is an implicit output, holding the fetched data.
> +;;;
> +;;; e.g.
> +;;; ldabsw means:
> +;;; r0 = ntohl (*(u32 *) (((struct sk_buff *)r6)->data + imm32))
> +;;;
> +;;; ldindw means
> +;;; r0 = ntohl (*(u32 *) (((struct sk_buff *)r6)->data + src_reg + imm32))
> +
> + .include "testutils.inc"
> +
> + .text
> + .global main
> + .type main, @function
> +main:
> + ;; R6 holds a pointer to a struct sk_buff, which we pretend
> + ;; exists at 0x1000
> + mov %r6, 0x1000
> +
> + ;; We configure skb-data-offset=0x20
> + ;; This specifies offsetof(struct sk_buff, data), where the field 'data'
> + ;; is a pointer a data buffer, in this case at 0x2000
> + stw [%r6+0x20], 0x2000
> +
> + ;; Write the value 0x7eadbeef into memory at 0x2004
> + ;; i.e. offset 4 within the data buffer pointed to by
> + ;; ((struct sk_buff *)r6)->data
> + stw [%r6+0x1004], 0xdeadbeef
> +
> + ;; Now load data[4] into r0 using the ldabsw instruction
> + ldabsw 0x4
> +
> + ;; ...and compare to what we expect
> + fail_ne32 %r0, 0xdeadbeef
> +
> + ;; Repeat for a half-word (2-bytes)
> + sth [%r6+0x1008], 0x1234
> + ldabsh 0x8
> + fail_ne32 %r0, 0x1234
> +
> + ;; Repeat for a single byte
> + stb [%r6+0x1010], 0x5a
> + ldabsb 0x10
> + fail_ne32 %r0, 0x5a
> +
> + ;; Repeat for a double-word (8-byte)
> + ;; (note: fail_ne macro uses r0, so copy to another r1 to compare)
> + lddw %r2, 0x1234deadbeef5678
> + stxdw [%r6+0x1018], %r2
> + ldabsdw 0x18
> + mov %r1, %r0
> + fail_ne %r1, 0x1234deadbeef5678
> +
> + ;; Now, we do the same for the indirect loads
> + mov %r7, 0x100
> + stw [%r6+0x1100], 0xfeedbeef
> +
> + ldindw %r7, 0x0
> + fail_ne32 %r0, 0xfeedbeef
> +
> + ;; half-word
> + sth [%r6+0x1104], 0x6789
> + ldindh %r7, 0x4
> + fail_ne32 %r0, 0x6789
> +
> + ;; byte
> + stb [%r6+0x1108], 0x5f
> + ldindb %r7, 0x8
> + fail_ne32 %r0, 0x5f
> +
> + ;; double-word
> + lddw %r2, 0xcafe12345678d00d
> + stxdw [%r6+0x1110], %r2
> + ldinddw %r7, 0x10
> + mov %r1, %r0
> + fail_ne %r1, 0xcafe12345678d00d
> +
> + pass
> diff --git a/sim/testsuite/sim/bpf/mem.s b/sim/testsuite/sim/bpf/mem.s
> new file mode 100644
> index 0000000000..f9c6a193ea
> --- /dev/null
> +++ b/sim/testsuite/sim/bpf/mem.s
> @@ -0,0 +1,56 @@
> +# mach: bpf
> +# output: pass\nexit 0 (0x0)\n
> +;;; mem.s
> +;;; Tests for BPF memory (ldx, stx, ..) instructions in simulator
> +
> + .include "testutils.inc"
> +
> + .text
> + .global main
> + .type main, @function
> +main:
> + lddw %r1, 0x1234deadbeef5678
> + mov %r2, 0x1000
> +
> + ;; basic store/load check
> + stxb [%r2+0], %r1
> + stxh [%r2+2], %r1
> + stxw [%r2+4], %r1
> + stxdw [%r2+8], %r1
> +
> + stb [%r2+16], 0x5a
> + sth [%r2+18], 0xcafe
> + stw [%r2+20], 0xbeefface
> + stdw [%r2+24], 0x7eadbeef
> +
> + ldxb %r1, [%r2+16]
> + fail_ne %r1, 0x5a
> + ldxh %r1, [%r2+18]
> + fail_ne %r1, 0xffffffffffffcafe
> + ldxw %r1, [%r2+20]
> + fail_ne %r1, 0xffffffffbeefface
> + ldxdw %r1, [%r2+24]
> + fail_ne %r1, 0x7eadbeef
> +
> + ldxb %r3, [%r2+0]
> + fail_ne %r3, 0x78
> + ldxh %r3, [%r2+2]
> + fail_ne %r3, 0x5678
> + ldxw %r3, [%r2+4]
> + fail_ne %r3, 0xffffffffbeef5678
> + ldxdw %r3, [%r2+8]
> + fail_ne %r3, 0x1234deadbeef5678
> +
> + ldxw %r4, [%r2+10]
> + fail_ne %r4, 0xffffffffdeadbeef
> +
> + ;; negative offsets
> + add %r2, 16
> + ldxh %r5, [%r2+-14]
> + fail_ne %r5, 0x5678
> + ldxw %r5, [%r2+-12]
> + fail_ne %r5, 0xffffffffbeef5678
> + ldxdw %r5, [%r2+-8]
> + fail_ne %r5, 0x1234deadbeef5678
> +
> + pass
> diff --git a/sim/testsuite/sim/bpf/mov.s b/sim/testsuite/sim/bpf/mov.s
> new file mode 100644
> index 0000000000..6665450468
> --- /dev/null
> +++ b/sim/testsuite/sim/bpf/mov.s
> @@ -0,0 +1,54 @@
> +# mach: bpf
> +# output: pass\nexit 0 (0x0)\n
> +;; mov.s
> +;; Tests for mov and mov32 instructions
> +
> + .include "testutils.inc"
> +
> + .text
> + .global main
> + .type main, @function
> +main:
> + ;; some basic sanity checks
> + mov32 %r1, 5
> + fail_ne %r1, 5
> +
> + mov32 %r2, %r1
> + fail_ne %r2, 5
> +
> + mov %r2, %r1
> + fail_ne %r2, 5
> +
> + mov %r1, -666
> + fail_ne %r1, -666
> +
> + ;; should NOT sign extend
> + mov32 %r1, -1
> + fail_ne %r1, 0x00000000ffffffff
> +
> + ;; should sign extend
> + mov %r2, -1
> + fail_ne %r2, 0xffffffffffffffff
> +
> + mov %r3, 0x80000000
> +
> + ;; should NOT sign extend
> + mov32 %r4, %r3
> + fail_ne %r4, 0x0000000080000000
> +
> + ;; should sign extend
> + mov %r5, %r3
> + fail_ne %r5, 0xffffffff80000000
> +
> + mov32 %r1, -2147483648
> + mov32 %r1, %r1
> + fail_ne32 %r1, -2147483648
> +
> + ;; casting shenanigans
> + mov %r1, %r1
> + fail_ne %r1, +2147483648
> + mov32 %r2, -1
> + mov %r2, %r2
> + fail_ne %r2, +4294967295
> +
> + pass
> diff --git a/sim/testsuite/sim/bpf/testutils.inc b/sim/testsuite/sim/bpf/testutils.inc
> new file mode 100644
> index 0000000000..d3d6b17b5b
> --- /dev/null
> +++ b/sim/testsuite/sim/bpf/testutils.inc
> @@ -0,0 +1,38 @@
> +
> + ;; Print "pass\n" and 'exit 0'
> + .macro pass
> + .data
> +mpass:
> + .string "pass\n"
> + .text
> +_pass:
> + mov %r1, mpass ; point to "pass\n" string
> + mov %r2, 5 ; strlen mpass
> + call 7 ; printk
> + mov %r0, 0 ;
> + exit ; exit 0
> + .endm
> +
> +;;; MACRO fail
> +;;; Exit with status 1
> + .macro fail
> + mov %r0, 1
> + exit
> + .endm
> +
> +;;; MACRO fail_ne32
> +;;; Exit with status 1 if \reg32 != \val
> + .macro fail_ne32 reg val
> + jeq32 \reg, \val, 2
> + mov %r0, 1
> + exit
> + .endm
> +
> +;;; MACRO fail_ne
> +;;; Exit with status1 if \reg ne \val
> + .macro fail_ne reg val
> + lddw %r0, \val
> + jeq \reg, %r0, 2
> + mov %r0, 1
> + exit
> + .endm
> diff --git a/sim/testsuite/sim/bpf/xadd.s b/sim/testsuite/sim/bpf/xadd.s
> new file mode 100644
> index 0000000000..be60714242
> --- /dev/null
> +++ b/sim/testsuite/sim/bpf/xadd.s
> @@ -0,0 +1,44 @@
> +# mach: bpf
> +# output: pass\nexit 0 (0x0)\n
> +;;; xadd.s
> +;;; Tests for BPF atomic exchange-and-add instructions in simulator
> +;;;
> +;;; The xadd instructions (XADDW, XADDDW) operate on a memory location
> +;;; specified in $dst + offset16, atomically adding the value in $src.
> +;;;
> +;;; In the simulator, there isn't anything else happening. The atomic
> +;;; instructions are identical to a non-atomic load/add/store.
> +
> + .include "testutils.inc"
> +
> + .text
> + .global main
> + .type main, @function
> +main:
> + mov %r1, 0x1000
> + mov %r2, 5
> +
> + ;; basic xadd w
> + stw [%r1+0], 10
> + xaddw [%r1+0], %r2
> + ldxw %r3, [%r1+0]
> + fail_ne %r3, 15
> +
> + ;; basic xadd dw
> + stdw [%r1+8], 42
> + xadddw [%r1+8], %r2
> + ldxdw %r3, [%r1+8]
> + fail_ne %r3, 47
> +
> + ;; xadd w negative value
> + mov %r4, -1
> + xaddw [%r1+0], %r4
> + ldxw %r3, [%r1+0]
> + fail_ne %r3, 14
> +
> + ;; xadd dw negative val
> + xadddw [%r1+8], %r4
> + ldxdw %r3, [%r1+8]
> + fail_ne %r3, 46
> +
> + pass
> --
> 2.25.0.2.g232378479e
>