aboutsummaryrefslogtreecommitdiff
path: root/sim/bpf/bpf-helpers.c
diff options
context:
space:
mode:
authorJose E. Marchesi <jose.marchesi@oracle.com>2020-08-04 18:09:16 +0200
committerJose E. Marchesi <jose.marchesi@oracle.com>2020-08-04 18:09:16 +0200
commitb26e2ae7d333d84a85daaa9ca699c8bae2bd05bc (patch)
tree73db093a038074bb84b9104e5bd1182e062e9546 /sim/bpf/bpf-helpers.c
parent39791af2a2191a2f7765d7809ecedcd0442138bf (diff)
downloadgdb-b26e2ae7d333d84a85daaa9ca699c8bae2bd05bc.zip
gdb-b26e2ae7d333d84a85daaa9ca699c8bae2bd05bc.tar.gz
gdb-b26e2ae7d333d84a85daaa9ca699c8bae2bd05bc.tar.bz2
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.
Diffstat (limited to 'sim/bpf/bpf-helpers.c')
-rw-r--r--sim/bpf/bpf-helpers.c175
1 files changed, 175 insertions, 0 deletions
diff --git a/sim/bpf/bpf-helpers.c b/sim/bpf/bpf-helpers.c
new file mode 100644
index 0000000..cec5645
--- /dev/null
+++ b/sim/bpf/bpf-helpers.c
@@ -0,0 +1,175 @@
+/* Emulation of eBPF helpers.
+ Copyright (C) 2020 Free Software Foundation, Inc.
+
+ This file is part of GDB, the GNU debugger.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* BPF programs rely on the existence of several helper functions,
+ which are provided by the kernel. This simulator provides an
+ implementation of the helpers, which can be customized by the
+ user. */
+
+#define WANT_CPU_BPFBF
+#define WANT_CPU bpfbf
+
+#include "sim-main.h"
+#include "cgen-mem.h"
+#include "cgen-ops.h"
+#include "cpu.h"
+
+/* bpf_trace_printk is a printk-like facility for debugging.
+
+ In the kernel, it appends a line to the Linux's tracing debugging
+ interface.
+
+ In this simulator, it uses the simulator's tracing interface
+ instead.
+
+ The format tags recognized by this helper are:
+ %d, %i, %u, %x, %ld, %li, %lu, %lx, %lld, %lli, %llu, %llx,
+ %p, %s
+
+ A maximum of three tags are supported.
+
+ This helper returns the number of bytes written, or a negative
+ value in case of failure. */
+
+int
+bpf_trace_printk (SIM_CPU *current_cpu)
+{
+ va_list ap;
+ SIM_DESC sd = CPU_STATE (current_cpu);
+
+ DI fmt_address;
+ uint32_t size, tags_processed;
+ size_t i, bytes_written = 0;
+
+ /* The first argument is the format string, which is passed as a
+ pointer in %r1. */
+ fmt_address = GET_H_GPR (1);
+
+ /* The second argument is the length of the format string, as an
+ unsigned 32-bit number in %r2. */
+ size = GET_H_GPR (2);
+
+ /* Read the format string from the memory pointed by %r2, printing
+ out the stuff as we go. There is a maximum of three format tags
+ supported, which are read from %r3, %r4 and %r5 respectively. */
+ for (i = 0, tags_processed = 0; i < size;)
+ {
+ QI c = GETMEMUQI (current_cpu, CPU_PC_GET (current_cpu),
+ fmt_address + i);
+
+ switch (c)
+ {
+ case '%':
+ /* Check we are not exceeding the limit of three format
+ tags. */
+ if (tags_processed > 2)
+ return -1; /* XXX look for kernel error code. */
+
+ /* Depending on the kind of tag, extract the value from the
+ proper argument. */
+ if (i++ >= size)
+ return -1; /* XXX look for kernel error code. */
+
+ UDI value = GET_H_GPR (3 + tags_processed);
+
+ switch ((GETMEMUQI (current_cpu, CPU_PC_GET (current_cpu),
+ fmt_address + i)))
+ {
+ case 'd':
+ trace_printf (sd, current_cpu, "%d", value);
+ break;
+ case 'i':
+ trace_printf (sd, current_cpu, "%i", value);
+ break;
+ case 'u':
+ trace_printf (sd, current_cpu, "%u", value);
+ break;
+ case 'x':
+ trace_printf (sd, current_cpu, "%x", value);
+ break;
+ case 'l':
+ {
+ if (i++ >= size)
+ return -1;
+ switch (GETMEMUQI (current_cpu, CPU_PC_GET (current_cpu),
+ fmt_address + i))
+ {
+ case 'd':
+ trace_printf (sd, current_cpu, "%ld", value);
+ break;
+ case 'i':
+ trace_printf (sd, current_cpu, "%li", value);
+ break;
+ case 'u':
+ trace_printf (sd, current_cpu, "%lu", value);
+ break;
+ case 'x':
+ trace_printf (sd, current_cpu, "%lx", value);
+ break;
+ case 'l':
+ {
+ if (i++ >= size)
+ return -1;
+ switch (GETMEMUQI (current_cpu, CPU_PC_GET (current_cpu),
+ fmt_address + i)) {
+ case 'd':
+ trace_printf (sd, current_cpu, "%lld", value);
+ break;
+ case 'i':
+ trace_printf (sd, current_cpu, "%lli", value);
+ break;
+ case 'u':
+ trace_printf (sd, current_cpu, "%llu", value);
+ break;
+ case 'x':
+ trace_printf (sd, current_cpu, "%llx", value);
+ break;
+ default:
+ assert (0);
+ break;
+ }
+ break;
+ }
+ default:
+ assert (0);
+ break;
+ }
+ break;
+ }
+ default:
+ /* XXX completeme */
+ assert (0);
+ break;
+ }
+
+ tags_processed++;
+ i++;
+ break;
+ case '\0':
+ i = size;
+ break;
+ default:
+ trace_printf (sd, current_cpu, "%c", c);
+ bytes_written++;
+ i++;
+ break;
+ }
+ }
+
+ return bytes_written;
+}