sim: eBPF simulator

This patch introduces the basics of an instruction-simulator for eBPF.
The simulator is based on CGEN.

gdb/ChangeLog:

2020-08-04  Jose E. Marchesi  <jose.marchesi@oracle.com>

	* configure.tgt: Set gdb_sim for bpf-*-* targets.

sim/ChangeLog:

2020-08-04  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.
	* 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-04  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.
This commit is contained in:
Jose E. Marchesi 2020-08-04 18:09:16 +02:00
parent 39791af2a2
commit b26e2ae7d3
36 changed files with 18708 additions and 0 deletions

View file

@ -1,3 +1,7 @@
2020-08-04 Jose E. Marchesi <jose.marchesi@oracle.com>
* configure.tgt: Set gdb_sim for bpf-*-* targets.
2020-08-04 Weimin Pan <weimin.pan@oracle.com>
Jose E. Marchesi <jose.marchesi@oracle.com>

View file

@ -208,6 +208,7 @@ bfin-*-*)
bpf-*-*)
# Target: eBPF
gdb_target_obs="bpf-tdep.o"
gdb_sim=../sim/bpf/libsim.a
;;
cris*)

View file

@ -1,3 +1,26 @@
2020-08-04 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.
* 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.
2019-12-19 Tom Tromey <tromey@adacore.com>
PR build/24572:

View file

@ -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>

203
sim/bpf/Makefile.in Normal file
View file

@ -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 -outfile-suffix -le
$(SHELL) $(srcroot)/move-if-change eng-le.hin eng-le.h
$(SHELL) $(srcroot)/move-if-change mloop-le.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 -outfile-suffix -be
$(SHELL) $(srcroot)/move-if-change eng-be.hin eng-be.h
$(SHELL) $(srcroot)/move-if-change mloop-be.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

119
sim/bpf/aclocal.m4 vendored Normal file
View file

@ -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($@)])

175
sim/bpf/bpf-helpers.c Normal file
View file

@ -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;
}

194
sim/bpf/bpf-helpers.def Normal file
View file

@ -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:
*/

31
sim/bpf/bpf-helpers.h Normal file
View file

@ -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 */

31
sim/bpf/bpf-sim.h Normal file
View file

@ -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 */

327
sim/bpf/bpf.c Normal file
View file

@ -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 */
}
/***** 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
};

248
sim/bpf/config.in Normal file
View file

@ -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

15942
sim/bpf/configure vendored Executable file

File diff suppressed because it is too large Load diff

13
sim/bpf/configure.ac Normal file
View file

@ -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

37
sim/bpf/decode.h Normal file
View file

@ -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 */

23
sim/bpf/eng.h Normal file
View file

@ -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"

165
sim/bpf/mloop.in Normal file
View file

@ -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

214
sim/bpf/sim-if.c Normal file
View file

@ -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;
/* 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;
}

51
sim/bpf/sim-main.h Normal file
View file

@ -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
};
struct sim_state
{
sim_cpu *cpu[MAX_NR_PROCESSORS];
CGEN_STATE cgen_state;
sim_state_base base;
};
#endif /* ! SIM_MAIN_H */

33
sim/bpf/traps.c Normal file
View file

@ -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();
}

8
sim/configure vendored
View file

@ -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*-*-*)

View file

@ -26,6 +26,9 @@ case "${target}" in
bfin-*-*)
SIM_ARCH(bfin)
;;
bpf-*-*)
SIM_ARCH(bpf)
;;
cr16*-*-*)
SIM_ARCH(cr16)
;;

View file

@ -1,3 +1,20 @@
2020-08-04 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.
2020-07-29 Simon Marchi <simon.marchi@efficios.com>
* configure: Re-generate.

View file

@ -1875,6 +1875,9 @@ case "${target}" in
bfin-*-*)
sim_arch=bfin
;;
bpf-*-*)
sim_arch=bpf
;;
cr16*-*-*)
sim_arch=cr16
;;

View file

@ -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
}
}

109
sim/testsuite/sim/bpf/alu.s Normal file
View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

120
sim/testsuite/sim/bpf/jmp.s Normal file
View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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