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 2BEFE3858D34 for ; Fri, 3 Jul 2020 10:37:26 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 2BEFE3858D34 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 063ASISO189271 for ; Fri, 3 Jul 2020 10:37:25 GMT Received: from userp3020.oracle.com (userp3020.oracle.com [156.151.31.79]) by userp2120.oracle.com with ESMTP id 31wxrnn6fh-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL) for ; Fri, 03 Jul 2020 10:37:25 +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 063ASoiM100181 for ; Fri, 3 Jul 2020 10:37:25 GMT Received: from aserv0121.oracle.com (aserv0121.oracle.com [141.146.126.235]) by userp3020.oracle.com with ESMTP id 31xfvx5acd-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK) for ; Fri, 03 Jul 2020 10:37:24 +0000 Received: from abhmp0007.oracle.com (abhmp0007.oracle.com [141.146.116.13]) by aserv0121.oracle.com (8.14.4/8.13.8) with ESMTP id 063AbMmE001289 for ; Fri, 3 Jul 2020 10:37:23 GMT Received: from termi.localdomain (/10.175.63.130) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Fri, 03 Jul 2020 10:37:22 +0000 From: "Jose E. Marchesi" To: gdb-patches@sourceware.org Subject: [PATCH 1/2] gdb: support for eBPF Date: Fri, 3 Jul 2020 12:37:12 +0200 Message-Id: <20200703103713.7676-2-jose.marchesi@oracle.com> X-Mailer: git-send-email 2.25.0.2.g232378479e In-Reply-To: <20200703103713.7676-1-jose.marchesi@oracle.com> References: <20200703103713.7676-1-jose.marchesi@oracle.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Proofpoint-Virus-Version: vendor=nai engine=6000 definitions=9670 signatures=668680 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 suspectscore=43 adultscore=0 spamscore=0 phishscore=0 malwarescore=0 mlxlogscore=999 bulkscore=0 mlxscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2004280000 definitions=main-2007030073 X-Proofpoint-Virus-Version: vendor=nai engine=6000 definitions=9670 signatures=668680 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 mlxscore=0 mlxlogscore=999 priorityscore=1501 impostorscore=0 bulkscore=0 clxscore=1015 malwarescore=0 phishscore=0 adultscore=0 cotscore=-2147483648 lowpriorityscore=0 suspectscore=43 spamscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2004280000 definitions=main-2007030073 X-Spam-Status: No, score=-11.5 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_MSPIKE_H2, 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: Fri, 03 Jul 2020 10:37:28 -0000 This patch adds basic support for the eBPF target: tdep and build machinery. The accompanying simulator is introduced in subsequent patches. gdb/ChangeLog: 2020-07-03 Weimin Pan Jose E. Marchesi * configure.tgt: Add entry for bpf-*-*. * Makefile.in (ALL_TARGET_OBS): Add bpf-tdep.o (HFILES_NO_SRCDIR): Add bpf-tdep.h. (ALLDEPFILES): Add bpf-tdep.c. * bpf-tdep.h: New file. * bpf-tdep.c: Likewise. gdb/doc/ChangeLog: 2020-07-03 Jose E. Marchesi * gdb.texinfo (Contributors): Add information for the eBPF support. (BPF): New section. --- gdb/ChangeLog | 10 ++ gdb/Makefile.in | 3 + gdb/bpf-tdep.c | 331 ++++++++++++++++++++++++++++++++++++++++++++ gdb/bpf-tdep.h | 46 ++++++ gdb/configure.tgt | 6 + gdb/doc/ChangeLog | 6 + gdb/doc/gdb.texinfo | 21 +++ 7 files changed, 423 insertions(+) create mode 100644 gdb/bpf-tdep.c create mode 100644 gdb/bpf-tdep.h diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 9ae9fe2d1e..bce77b693d 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -717,6 +717,7 @@ ALL_TARGET_OBS = \ avr-tdep.o \ bfin-linux-tdep.o \ bfin-tdep.o \ + bpf-tdep.o \ bsd-uthread.o \ cris-linux-tdep.o \ cris-tdep.o \ @@ -1221,6 +1222,7 @@ HFILES_NO_SRCDIR = \ bcache.h \ bfd-target.h \ bfin-tdep.h \ + bpf-tdep.h \ block.h \ breakpoint.h \ bsd-kvm.h \ @@ -2145,6 +2147,7 @@ ALLDEPFILES = \ avr-tdep.c \ bfin-linux-tdep.c \ bfin-tdep.c \ + bpf-tdep.c \ bsd-kvm.c \ bsd-uthread.c \ csky-linux-tdep.c \ diff --git a/gdb/bpf-tdep.c b/gdb/bpf-tdep.c new file mode 100644 index 0000000000..ebaf8f8cf3 --- /dev/null +++ b/gdb/bpf-tdep.c @@ -0,0 +1,331 @@ +/* Target-dependent code for eBPF. + + Copyright (C) 2020 Free Software Foundation, Inc. + + This file is part of GDB. + + 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 "defs.h" +#include "arch-utils.h" +#include "dis-asm.h" +#include "frame.h" +#include "frame-unwind.h" +#include "trad-frame.h" +#include "symtab.h" +#include "value.h" +#include "gdbcmd.h" +#include "breakpoint.h" +#include "inferior.h" +#include "regcache.h" +#include "target.h" +#include "dwarf2/frame.h" +#include "osabi.h" +#include "target-descriptions.h" +#include "bpf-tdep.h" +#include "remote.h" + + +static unsigned int ebpf_debug_flag = 0; + +static void ATTRIBUTE_PRINTF (1, 2) +ebpf_debug (const char *fmt, ...) +{ + if (ebpf_debug_flag) + { + va_list args; + + va_start (args, fmt); + printf_unfiltered ("eBPF: "); + vprintf_unfiltered (fmt, args); + va_end (args); + } +} + + +/* eBPF registers */ + +static const char *ebpf_register_names[] = +{ + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "pc" +}; + +/* Return the name of register REGNUM. */ + +static const char * +ebpf_register_name (struct gdbarch *gdbarch, int reg) +{ + if (reg >= 0 && reg < EBPF_NUM_REGS) + return ebpf_register_names[reg]; + return NULL; +} + +/* Return the GDB type of register REGNUM. */ + +static struct type * +ebpf_register_type (struct gdbarch *gdbarch, int reg) +{ + if (reg == EBPF_R10_REGNUM) + return builtin_type (gdbarch)->builtin_data_ptr; + else if (reg == EBPF_PC_REGNUM) + return builtin_type (gdbarch)->builtin_func_ptr; + return builtin_type (gdbarch)->builtin_int64; +} + +/* Return the GDB register number corresponding to DWARF's REG. */ + +static int +ebpf_dwarf2_reg_to_regnum (struct gdbarch *gdbarch, int reg) +{ + if (reg >= 0 && reg < EBPF_NUM_REGS) + return reg; + return -1; +} + +/* Implement the "print_insn" gdbarch method. */ + +static int +bpf_gdb_print_insn (bfd_vma memaddr, disassemble_info *info) +{ + info->symbols = NULL; + return default_print_insn (memaddr, info); +} + + +/* Implement the "unwind_pc" gdbarch method. */ + +static CORE_ADDR +ebpf_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame) +{ + return frame_unwind_register_unsigned (next_frame, + gdbarch_pc_regnum (gdbarch)); +} + +/* Return PC of first real instruction of the function starting at + START_PC. */ + +static CORE_ADDR +ebpf_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR start_pc) +{ + ebpf_debug ("Skipping prologue: start_pc=%s\n", + paddress (gdbarch, start_pc)); + /* XXX */ + return start_pc+0; +} + + +/* Frame unwinder. */ + +static void +bpf_frame_this_id (struct frame_info *this_frame, + void **this_prologue_cache, + struct frame_id *this_id) +{ + /* XXX */ +} + +static enum unwind_stop_reason +bpf_frame_unwind_stop_reason (struct frame_info *this_frame, + void **this_cache) +{ + return UNWIND_OUTERMOST; /* XXX */ +} + +static struct value * +bpf_frame_prev_register (struct frame_info *this_frame, + void **this_prologue_cache, int regnum) +{ + return frame_unwind_got_register (this_frame, regnum, regnum); /* XXX */ +} + +static const struct frame_unwind bpf_frame_unwind = +{ + NORMAL_FRAME, + bpf_frame_unwind_stop_reason, + bpf_frame_this_id, + bpf_frame_prev_register, + NULL, + default_frame_sniffer +}; + + +/* Breakpoints. */ + +/* Implement the breakpoint_kind_from_pc gdbarch method. */ + +static int +ebpf_breakpoint_kind_from_pc (struct gdbarch *gdbarch, CORE_ADDR *start_pc) +{ + /* We support just one kind of breakpoint. */ + return 8; +} + +/* Implement the sw_breakpoint_from_kind gdbarch method. */ + +static const gdb_byte * +ebpf_sw_breakpoint_from_kind (struct gdbarch *gdbarch, int kind, int *size) +{ + static unsigned char ebpf_breakpoint[] + = {0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + *size = kind; + return ebpf_breakpoint; +} + + +/* Assuming THIS_FRAME is a dummy frame, return its frame ID. */ + +static struct frame_id +ebpf_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame) +{ + CORE_ADDR sp = get_frame_register_unsigned (this_frame, + gdbarch_sp_regnum (gdbarch)); + return frame_id_build (sp, get_frame_pc (this_frame)); +} + +static CORE_ADDR +ebpf_push_dummy_call (struct gdbarch *gdbarch, struct value *function, + struct regcache *regcache, CORE_ADDR bp_addr, + int nargs, struct value **args, CORE_ADDR sp, + function_call_return_method return_method, + CORE_ADDR struct_addr) +{ + ebpf_debug ("Pushing dummy call: sp=%s\n", paddress (gdbarch, sp)); + /* XXX */ + return sp; +} + +/* Extract a function return value of TYPE from REGCACHE, + and copy it into VALBUF. */ + +static void +ebpf_extract_return_value (struct type *type, struct regcache *regcache, + gdb_byte *valbuf) +{ + int len = TYPE_LENGTH (type); + gdb_byte vbuf[8]; + + gdb_assert (len <= 8); + regcache->cooked_read (EBPF_R0_REGNUM, vbuf); + memcpy (valbuf, vbuf + 8 - len, len); +} + +/* Store the function return value of type TYPE from VALBUF into REGNAME. */ + +static void +ebpf_store_return_value (struct type *type, struct regcache *regcache, + const gdb_byte *valbuf) +{ + int len = TYPE_LENGTH (type); + gdb_byte vbuf[8]; + + gdb_assert (len <= 8); + memset (vbuf, 0, sizeof(vbuf)); + memcpy (vbuf + 8 - len, valbuf, len); + regcache->cooked_write (EBPF_R0_REGNUM, vbuf); +} + +/* Handle function's return value. */ + +static enum return_value_convention +ebpf_return_value (struct gdbarch *gdbarch, struct value *function, + struct type *type, struct regcache *regcache, + gdb_byte *readbuf, const gdb_byte *writebuf) +{ + int len = TYPE_LENGTH (type); + + if (len > 8) + return RETURN_VALUE_STRUCT_CONVENTION; + + if (readbuf) + ebpf_extract_return_value (type, regcache, readbuf); + if (writebuf) + ebpf_store_return_value (type, regcache, writebuf); + + return RETURN_VALUE_REGISTER_CONVENTION; +} + + +/* Initialize the current architecture based on INFO. If possible, re-use an + architecture from ARCHES, which is a list of architectures already created + during this debugging session. */ + +static struct gdbarch * +ebpf_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) +{ + struct gdbarch_tdep *tdep; + struct gdbarch *gdbarch; + + /* If there is already a candidate, use it. */ + arches = gdbarch_list_lookup_by_info (arches, &info); + if (arches != NULL) + return arches->gdbarch; + + /* Allocate space for the new architecture. */ + tdep = XCNEW (struct gdbarch_tdep); + gdbarch = gdbarch_alloc (&info, tdep); + + /* Information about registers, etc. */ + set_gdbarch_num_regs (gdbarch, EBPF_NUM_REGS); + set_gdbarch_register_name (gdbarch, ebpf_register_name); + set_gdbarch_register_type (gdbarch, ebpf_register_type); + + /* Register numbers of various important registers. */ + set_gdbarch_sp_regnum (gdbarch, EBPF_R10_REGNUM); + set_gdbarch_pc_regnum (gdbarch, EBPF_PC_REGNUM); + + /* Map DWARF2 registers to GDB registers. */ + set_gdbarch_dwarf2_reg_to_regnum (gdbarch, ebpf_dwarf2_reg_to_regnum); + + /* Call dummy code. */ + set_gdbarch_call_dummy_location (gdbarch, ON_STACK); + set_gdbarch_dummy_id (gdbarch, ebpf_dummy_id); + set_gdbarch_push_dummy_call (gdbarch, ebpf_push_dummy_call); + + /* Returning results. */ + set_gdbarch_return_value (gdbarch, ebpf_return_value); + + /* Advance PC across function entry code. */ + set_gdbarch_skip_prologue (gdbarch, ebpf_skip_prologue); + + /* Stack grows downward. */ + set_gdbarch_inner_than (gdbarch, core_addr_lessthan); + + /* Breakpoint manipulation. */ + set_gdbarch_breakpoint_kind_from_pc (gdbarch, ebpf_breakpoint_kind_from_pc); + set_gdbarch_sw_breakpoint_from_kind (gdbarch, ebpf_sw_breakpoint_from_kind); + + /* Frame handling. */ + set_gdbarch_frame_args_skip (gdbarch, 8); + set_gdbarch_unwind_pc (gdbarch, ebpf_unwind_pc); + + /* Disassembly. */ + set_gdbarch_print_insn (gdbarch, bpf_gdb_print_insn); + + /* Hook in ABI-specific overrides, if they have been registered. */ + gdbarch_init_osabi (info, gdbarch); + + /* Install unwinders. */ + frame_unwind_append_unwinder (gdbarch, &bpf_frame_unwind); + + return gdbarch; +} + +void _initialize_ebpf_tdep (); +void +_initialize_ebpf_tdep (void) +{ + register_gdbarch_init (bfd_arch_bpf, ebpf_gdbarch_init); +} diff --git a/gdb/bpf-tdep.h b/gdb/bpf-tdep.h new file mode 100644 index 0000000000..3cfab9cd43 --- /dev/null +++ b/gdb/bpf-tdep.h @@ -0,0 +1,46 @@ +/* Target-dependent code for eBPF, for GDB. + + Copyright (C) 2020 Free Software Foundation, Inc. + + This file is part of GDB. + + 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_TDEP_H +#define BPF_TDEP_H + +enum ebpf_regnum { + EBPF_R0_REGNUM, /* return value */ + EBPF_R1_REGNUM, + EBPF_R2_REGNUM, + EBPF_R3_REGNUM, + EBPF_R4_REGNUM, + EBPF_R5_REGNUM, + EBPF_R6_REGNUM, + EBPF_R7_REGNUM, + EBPF_R8_REGNUM, + EBPF_R9_REGNUM, + EBPF_R10_REGNUM, /* sp */ + EBPF_PC_REGNUM, +}; + +#define EBPF_NUM_REGS (EBPF_PC_REGNUM + 1) + +/* Target-dependent structure in gdbarch. */ +struct gdbarch_tdep +{ + /* XXX */ +}; + +#endif /* BPF_TDEP_H */ diff --git a/gdb/configure.tgt b/gdb/configure.tgt index d66f01bb9f..8a26bdeb87 100644 --- a/gdb/configure.tgt +++ b/gdb/configure.tgt @@ -205,6 +205,12 @@ bfin-*-*) gdb_sim=../sim/bfin/libsim.a ;; +bpf-*-*) + # Target: eBPF + gdb_target_obs="bpf-tdep.o" + gdb_sim=../sim/bpf/libsim.a + ;; + cris*) # Target: CRIS gdb_target_obs="cris-tdep.o cris-linux-tdep.o linux-tdep.o solib-svr4.o" diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index fbe9f850af..b9df9cdf95 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -557,6 +557,10 @@ Alessandro Forin and Per Bothner. More recent ports have been the work of Jeremy Bennett, Franck Jullien, Stefan Wallentowitz and Stafford Horne. +Weimin Pan, David Faust and Jose E. Marchesi contributed support for +the Linux kernel BPF virtual architecture. This work was sponsored by +Oracle. + @node Sample Session @chapter A Sample @value{GDBN} Session @@ -24379,6 +24383,7 @@ acceptable commands. @menu * ARC:: Synopsys ARC * ARM:: ARM +* BPF:: eBPF * M68K:: Motorola M68K * MicroBlaze:: Xilinx MicroBlaze * MIPS Embedded:: MIPS Embedded @@ -24513,6 +24518,22 @@ The default value is @code{all}. @end table @end table +@node BPF +@subsection BPF + +@table @code +@item target sim @r{[}@var{simargs}@r{]} @dots{} +The @value{GDBN} BPF simulator accepts the following optional arguments. + +@table @code +@item --skb-data-offset=@var{offset} +Tell the simulator the offset, measured in bytes, of the +@code{skb_data} field in the kernel @code{struct sk_buff} structure. +This offset is used by some BPF specific-purpose load/store +instructions. Defaults to 0. +@end table +@end table + @node M68K @subsection M68k -- 2.25.0.2.g232378479e