From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from userp2120.oracle.com (userp2120.oracle.com [156.151.31.85]) by sourceware.org (Postfix) with ESMTPS id 5EB323858D35 for ; Mon, 3 Aug 2020 14:04:50 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 5EB323858D35 Received: from pps.filterd (userp2120.oracle.com [127.0.0.1]) by userp2120.oracle.com (8.16.0.42/8.16.0.42) with SMTP id 073Dvxdu196008 for ; Mon, 3 Aug 2020 14:04:49 GMT Received: from userp3020.oracle.com (userp3020.oracle.com [156.151.31.79]) by userp2120.oracle.com with ESMTP id 32n11mxj40-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL) for ; Mon, 03 Aug 2020 14:04:47 +0000 Received: from pps.filterd (userp3020.oracle.com [127.0.0.1]) by userp3020.oracle.com (8.16.0.42/8.16.0.42) with SMTP id 073DwsqV093589 for ; Mon, 3 Aug 2020 14:02:46 GMT Received: from userv0122.oracle.com (userv0122.oracle.com [156.151.31.75]) by userp3020.oracle.com with ESMTP id 32pdhagarw-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK) for ; Mon, 03 Aug 2020 14:02:46 +0000 Received: from abhmp0018.oracle.com (abhmp0018.oracle.com [141.146.116.24]) by userv0122.oracle.com (8.14.4/8.14.4) with ESMTP id 073E2jiw023077 for ; Mon, 3 Aug 2020 14:02:45 GMT Received: from termi.localdomain (/10.175.1.95) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Mon, 03 Aug 2020 07:02:44 -0700 From: "Jose E. Marchesi" To: gdb-patches@sourceware.org Subject: [PATCH V6 2/3] sim: eBPF simulator Date: Mon, 3 Aug 2020 16:02:36 +0200 Message-Id: <20200803140237.14476-3-jose.marchesi@oracle.com> X-Mailer: git-send-email 2.25.0.2.g232378479e In-Reply-To: <20200803140237.14476-1-jose.marchesi@oracle.com> References: <20200803140237.14476-1-jose.marchesi@oracle.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Proofpoint-Virus-Version: vendor=nai engine=6000 definitions=9701 signatures=668679 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 adultscore=0 phishscore=0 spamscore=0 bulkscore=0 malwarescore=0 mlxscore=0 mlxlogscore=999 suspectscore=43 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2006250000 definitions=main-2008030105 X-Proofpoint-Virus-Version: vendor=nai engine=6000 definitions=9701 signatures=668679 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 clxscore=1015 priorityscore=1501 impostorscore=0 lowpriorityscore=0 malwarescore=0 spamscore=0 mlxscore=0 suspectscore=43 mlxlogscore=999 phishscore=0 adultscore=0 bulkscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2006250000 definitions=main-2008030105 X-Spam-Status: No, score=-7.7 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_ASCII_DIVIDERS, KAM_SHORT, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SCC_10_SHORT_WORD_LINES, SCC_20_SHORT_WORD_LINES, SCC_5_SHORT_WORD_LINES, SPF_HELO_PASS, SPF_PASS, TXREP, UNPARSEABLE_RELAY autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 03 Aug 2020 14:04:58 -0000 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 David Faust * 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. * 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 Jose E. Marchesi * 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 + 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 aarch64 Jim Wilson arm Nick Clifton bfin Mike Frysinger +bpf Jose E. Marchesi cr16 M R Swami Reddy frv Dave Brolley ft32 James Bowman 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 . + +## 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 + +.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 . */ + +/* 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 +. */ + +/* 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 . */ + +#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 . */ + +#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 . */ + +#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 */ +} + + +/***** 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 header file. */ +#undef HAVE_DLFCN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_ERRNO_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_FCNTL_H + +/* Define to 1 if you have the 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 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 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 header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the 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 header file. */ +#undef HAVE_SYS_MMAN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_RESOURCE_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TIMES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TIME_H + +/* Define to 1 if you have the 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 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 header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the 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 . */ + +/* 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 . */ + +/* 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 . + +# 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 <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 <> 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 <&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 . */ + +#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; + + +/* 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; +} + + +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 . */ + +#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 +}; + + + +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 . */ + +#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