diff options
author | Jose E. Marchesi <jose.marchesi@oracle.com> | 2020-08-04 18:09:16 +0200 |
---|---|---|
committer | Jose E. Marchesi <jose.marchesi@oracle.com> | 2020-08-04 18:09:16 +0200 |
commit | b26e2ae7d333d84a85daaa9ca699c8bae2bd05bc (patch) | |
tree | 73db093a038074bb84b9104e5bd1182e062e9546 /sim/bpf/bpf-helpers.c | |
parent | 39791af2a2191a2f7765d7809ecedcd0442138bf (diff) | |
download | gdb-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.c | 175 |
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; +} |