From patchwork Wed Jan 15 03:17:59 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: jiangshuai_li@c-sky.com X-Patchwork-Id: 37388 Received: (qmail 129325 invoked by alias); 15 Jan 2020 03:18:07 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 129317 invoked by uid 89); 15 Jan 2020 03:18:07 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-11.9 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, SCC_10_SHORT_WORD_LINES, SCC_20_SHORT_WORD_LINES, SCC_5_SHORT_WORD_LINES, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 spammy=Supply, expedite, H*UA:16.0, H*x:16.0 X-HELO: smtp2200-217.mail.aliyun.com Received: from smtp2200-217.mail.aliyun.com (HELO smtp2200-217.mail.aliyun.com) (121.197.200.217) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 15 Jan 2020 03:18:04 +0000 X-Alimail-AntiSpam: AC=AD; BC=0.7025211|0.04917457; BR=01201311R161b1; CH=blue; DM=CONTINUE|AD|true|0.639763-0.00690342-0.353334; DS=CONTINUE|ham_system_inform|0.00699254-0.000226332-0.992781; FP=0|0|0|0|0|-1|-1|-1; HT=e02c03296; MF=jiangshuai_li@c-sky.com; NM=1; PH=DS; RN=6; RT=6; SR=0; TI=SMTPD_---.GcIBSjk_1579058279; Received: from LPF1D4R0J1252(mailfrom:jiangshuai_li@c-sky.com fp:SMTPD_---.GcIBSjk_1579058279) by smtp.aliyun-inc.com(10.147.41.121); Wed, 15 Jan 2020 11:17:59 +0800 From: To: "'Jim Wilson'" , , Cc: , =?gb2312?B?J8/EwaK3vSc=?= , "'yunhai_shang'" Subject: [PATCH] riscv: add gdbserver support Date: Wed, 15 Jan 2020 11:17:59 +0800 Message-ID: <00e401d5cb52$63a4d000$2aee7000$@c-sky.com> MIME-Version: 1.0 This patch is a base support for Riscv32 and Riscv64 arch. It implemented how to r/w gprs and fprs, identify the software bkpt insns and the *.dat files for regs_info. I have tested it on kernel 5.1.15, and it works normally. Some requirements may be implemented later: 1. if fpu has 64bits in riscv32 2. hardware bkpt/watchpoint support 3. vector regitsers r/w Add riscv base linux32 add linux64 gdbserver support. gdb/gdbserver/Changlog: 2020-0113 Jiangshuai Li * Makefile.in (SFILES): Add '$(srcdir)/linux-riscv-low.c'. * configure.srv: Target support riscv*-*linux* * linux-riscv-low.c: New file: Riscv low target supporting code (init_registers_riscv32_linux): Defined in auto-generated file riscv32-linux-generated.c for RV32 linux. (init_registers_riscv64_linux): Defined in auto-generated file riscv64-linux-generated.c for RV64 linux. (riscv_cannot_fetch_register): Implement linux_target_ops.cannot_fetch_register. (riscv_cannot_store_register,): Implement linux_target_ops.cannot_store_register. (riscv_fill_gregset): Fill *BUF according to elf_greg_t. (riscv_store_gregset): Supply *BUF according to elf_greg_t. (riscv_fill_fpregset): Fill *BUF according to prfpregset_t. (riscv_store_fpregset): Supply *BUF according to prfpregset_t. (riscv_arch_setup): Init current_process ()->tdesc with RV32 or RV64. (regs_info): Implement linux_target_ops.riscv_regs_info. (riscv_sw_breakpoint_from_kind): Implement linux_target_ops.sw_breakpoint_from_kind, 32bits ebreak or 16bits c. ebreak. (riscv_breakpoint_at): Implement linux_target_ops.breakpoint_at, check if mem at pc is bkpt-insn. 2020-0113 Jiangshuai Li * regformats/riscv32-linux.dat: New file. * regformats/riscv64-linux.dat: New file. Change-Id: Ie94277dd709b853912afe3a146be0ac2e636d5a1 --- gdb/ChangeLog | 5 + gdb/gdbserver/ChangeLog | 24 ++++ gdb/gdbserver/Makefile.in | 1 + gdb/gdbserver/configure.srv | 5 + gdb/gdbserver/linux-riscv-low.c | 229 +++++++++++++++++++++++++++++++++++++++ gdb/regformats/riscv32-linux.dat | 71 ++++++++++++ gdb/regformats/riscv64-linux.dat | 71 ++++++++++++ 7 files changed, 406 insertions(+) create mode 100644 gdb/gdbserver/linux-riscv-low.c create mode 100644 gdb/regformats/riscv32-linux.dat create mode 100644 gdb/regformats/riscv64-linux.dat diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 39fcac7..f5cf6c7 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,8 @@ +2020-0113 Jiangshuai Li + + * regformats/riscv32-linux.dat: New file. + * regformats/riscv64-linux.dat: New file. + 2019-09-18 Christian Biesinger * dwarf2loc.c: Change extern declaration of dwarf_always_disassemble diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog index faafdfd..be2b8f0 100644 --- a/gdb/gdbserver/ChangeLog +++ b/gdb/gdbserver/ChangeLog @@ -1,3 +1,27 @@ +2020-0113 Jiangshuai Li + + * Makefile.in (SFILES): Add '$(srcdir)/linux-riscv-low.c'. + * configure.srv: Target support riscv*-*linux* + * linux-riscv-low.c: New file: Riscv low target supporting code + (init_registers_riscv32_linux): Defined in auto-generated file + riscv32-linux-generated.c for RV32 linux. + (init_registers_riscv64_linux): Defined in auto-generated file + riscv64-linux-generated.c for RV64 linux. + (riscv_cannot_fetch_register): Implement + linux_target_ops.cannot_fetch_register. + (riscv_cannot_store_register,): Implement + linux_target_ops.cannot_store_register. + (riscv_fill_gregset): Fill *BUF according to elf_greg_t. + (riscv_store_gregset): Supply *BUF according to elf_greg_t. + (riscv_fill_fpregset): Fill *BUF according to prfpregset_t. + (riscv_store_fpregset): Supply *BUF according to prfpregset_t. + (riscv_arch_setup): Init current_process ()->tdesc with RV32 or RV64. + (regs_info): Implement linux_target_ops.riscv_regs_info. + (riscv_sw_breakpoint_from_kind): Implement + linux_target_ops.sw_breakpoint_from_kind, 32bits ebreak or 16bits c. ebreak. + (riscv_breakpoint_at): Implement + linux_target_ops.breakpoint_at, check if mem at pc is bkpt-insn. + 2019-08-23 Sergio Durigan Junior * Makefile.in (SFILES): Add 'gdbsupport/gdb-dlfcn.c'. diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in index ca0a4cb..ada3494 100644 --- a/gdb/gdbserver/Makefile.in +++ b/gdb/gdbserver/Makefile.in @@ -172,6 +172,7 @@ SFILES = \ $(srcdir)/linux-mips-low.c \ $(srcdir)/linux-nios2-low.c \ $(srcdir)/linux-ppc-low.c \ + $(srcdir)/linux-riscv-low.c \ $(srcdir)/linux-s390-low.c \ $(srcdir)/linux-sh-low.c \ $(srcdir)/linux-sparc-low.c \ diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv index 66d3d42..b1dc77d 100644 --- a/gdb/gdbserver/configure.srv +++ b/gdb/gdbserver/configure.srv @@ -391,6 +391,11 @@ case "${target}" in srv_linux_regsets=yes srv_linux_thread_db=yes ;; + riscv*-*linux*) srv_regobj="riscv32-linux.o riscv64-linux.o" + srv_tgtobj="$srv_linux_obj linux-riscv-low.o" + srv_linux_regsets=yes + srv_linux_thread_db=yes + ;; *) echo "Error: target not supported by gdbserver." exit 1 ;; diff --git a/gdb/gdbserver/linux-riscv-low.c b/gdb/gdbserver/linux-riscv-low.c new file mode 100644 index 0000000..efd156e --- /dev/null +++ b/gdb/gdbserver/linux-riscv-low.c @@ -0,0 +1,229 @@ +/* GNU/Linux/RISCV specific low level interface, for the remote server 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 . */ + +#include "server.h" +#include "linux-low.h" +#include +#include "elf.h" +#include "riscv-tdep.h" + + +/* Defined in auto-generated file riscv32-linux-generated.c. */ +void init_registers_riscv32_linux (void); +extern const struct target_desc *tdesc_riscv32_linux; + +/* Defined in auto-generated file riscv64-linux-generated.c. */ +void init_registers_riscv64_linux (void); +extern const struct target_desc *tdesc_riscv64_linux; + +static int +riscv_cannot_fetch_register (int regno) +{ + if (regno >=0 && regno <= 63) + return 0; + else + return 1; +} + +static int +riscv_cannot_store_register (int regno) +{ + if (regno >=0 && regno <= 63) + return 0; + else + return 1; +} + +static void +riscv_fill_gregset (struct regcache *regcache, void *buf) +{ + elf_greg_t *regp = (elf_greg_t *)buf; + + /* We only support the integer registers and PC here. */ + for (int i = RISCV_ZERO_REGNUM + 1; i < RISCV_PC_REGNUM; i++) + collect_register (regcache, i, regp + i); + + collect_register (regcache, 32, regp + 0); +} + +static void +riscv_store_gregset (struct regcache *regcache, const void *buf) +{ + const elf_greg_t *regp = (const elf_greg_t *)buf; + + /* We only support the integer registers and PC here. */ + for (int i = RISCV_ZERO_REGNUM + 1; i < RISCV_PC_REGNUM; i++) + supply_register (regcache, i, regp + i); + + /* GDB stores PC in reg 32. Linux kernel stores it in reg 0. */ + supply_register (regcache, 32, regp + 0); + + /* Fill the inaccessible zero register with zero. */ + supply_register_zeroed (regcache, 0); +} + +static void +riscv_fill_fpregset (struct regcache *regcache, void *buf) +{ + prfpregset_t *fpregs = (prfpregset_t *)buf; + + /* We only support the FP registers and FCSR here. */ + for (int i = RISCV_FIRST_FP_REGNUM; i <= RISCV_LAST_FP_REGNUM; i++) + collect_register (regcache, i, &fpregs->__d.__f[i - RISCV_FIRST_FP_REGNUM]); + + collect_register (regcache, RISCV_CSR_FCSR_REGNUM, &fpregs->__d.__fcsr); +} + +static void +riscv_store_fpregset (struct regcache *regcache, const void *buf) +{ + const prfpregset_t *fpregs = (const prfpregset_t *)buf; + + /* We only support the FP registers and FCSR here. */ + for (int i = RISCV_FIRST_FP_REGNUM; i <= RISCV_LAST_FP_REGNUM; i++) + supply_register (regcache, i, &fpregs->__d.__f[i - RISCV_FIRST_FP_REGNUM]); + + supply_register (regcache, RISCV_CSR_FCSR_REGNUM, &fpregs->__d.__fcsr); +} + +static struct regset_info riscv_regsets[] = { + { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PRSTATUS, sizeof (elf_gregset_t), + GENERAL_REGS, + riscv_fill_gregset, riscv_store_gregset }, + { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_FPREGSET, sizeof (elf_fpregset_t), + FP_REGS, + riscv_fill_fpregset, riscv_store_fpregset }, + NULL_REGSET +}; + + +static void +riscv_arch_setup (void) +{ + int size = sizeof (elf_greg_t); + + if (size == 4) + current_process ()->tdesc = tdesc_riscv32_linux; + else + current_process ()->tdesc = tdesc_riscv64_linux; +} + +static struct regsets_info riscv_regsets_info = + { + riscv_regsets, /* regsets */ + 0, /* num_regsets */ + NULL, /* disabled_regsets */ + }; + +static struct regs_info regs_info = + { + NULL, /* regset_bitmap */ + NULL, /* usrregs */ + &riscv_regsets_info + }; + +static const struct regs_info * +riscv_regs_info (void) +{ + return ®s_info; +} + +/* Implementation of linux_target_ops method "sw_breakpoint_from_kind". */ +static const gdb_byte ebreak[] = {0x73, 0x00, 0x10, 0x00}; +static const gdb_byte c_ebreak[] = {0x02, 0x90}; + +static const gdb_byte * +riscv_sw_breakpoint_from_kind (int kind, int *size) +{ + *size = kind; + + switch (kind) + { + case 2: + return c_ebreak; + case 4: + return ebreak; + default: + gdb_assert (0); + } +} + +static int +riscv_breakpoint_at (CORE_ADDR where) +{ + unsigned char insn[4]; + + (*the_target->read_memory) (where, (unsigned char *) insn, 4); + + if (insn[0] == ebreak[0] && insn[1] == ebreak[1] + && insn[2] == ebreak[2] && insn[3] == ebreak[3]) + return 1; + else if (insn[0] == ebreak[0] && insn[1] == ebreak[1]) + return 1; + else + return 0; +} + + +struct linux_target_ops the_low_target = { + riscv_arch_setup, /* arch_setup */ + riscv_regs_info, /* regs_info */ + riscv_cannot_fetch_register, /* cannot_fetch_register */ + riscv_cannot_store_register, /* cannot_store_register */ + NULL, /* fetch_register */ + linux_get_pc_64bit, /* get_pc */ + linux_set_pc_64bit, /* set_pc */ + NULL, /* breakpoint_kind_from_pc */ + riscv_sw_breakpoint_from_kind, /* sw_breakpoint_from_kind */ + NULL, /* get_next_pcs */ + 0, /* decr_pc_after_break */ + riscv_breakpoint_at, /* breakpoint_at */ + NULL, /* supports_z_point_type */ + NULL, /* insert_point */ + NULL, /* remove_point */ + NULL, /* stopped_by_watchpoint */ + NULL, /* stopped_data_address */ + NULL, /* collect_ptrace_register */ + NULL, /* supply_ptrace_register */ + NULL, /* siginfo_fixup */ + NULL, /* new_process */ + NULL, /* delete_process */ + NULL, /* new_thread */ + NULL, /* delete_thread */ + NULL, /* new_fork */ + NULL, /* prepare_to_resume */ + NULL, /* process_qsupported */ + NULL, /* supports_tracepoints */ + NULL, /* get_thread_area */ + NULL, /* install_fast_tracepoint_jump_pad */ + NULL, /* emit_ops */ + NULL, /* get_min_fast_tracepoint_insn_len */ + NULL, /* supports_range_stepping */ + NULL, /* breakpoint_kind_from_current_state */ + NULL, /* supports_hardware_single_step */ +}; + + +void +initialize_low_arch (void) +{ + init_registers_riscv32_linux (); + init_registers_riscv64_linux (); + initialize_regsets_info (&riscv_regsets_info); +} diff --git a/gdb/regformats/riscv32-linux.dat b/gdb/regformats/riscv32-linux.dat new file mode 100644 index 0000000..d7dae52 --- /dev/null +++ b/gdb/regformats/riscv32-linux.dat @@ -0,0 +1,71 @@ +name:riscv32_linux +xmltarget:riscv32-linux.xml +expedite:sp,fp,pc +32:zero +32:ra +32:sp +32:gp +32:tp +32:t0 +32:t1 +32:t2 +32:fp +32:s1 +32:a0 +32:a1 +32:a2 +32:a3 +32:a4 +32:a5 +32:a6 +32:a7 +32:s2 +32:s3 +32:s4 +32:s5 +32:s6 +32:s7 +32:s8 +32:s9 +32:s10 +32:s11 +32:t3 +32:t4 +32:t5 +32:t6 +32:pc +32:ft0 +32:ft1 +32:ft2 +32:ft3 +32:ft4 +32:ft5 +32:ft6 +32:ft7 +32:fs0 +32:fs1 +32:fa0 +32:fa1 +32:fa2 +32:fa3 +32:fa4 +32:fa5 +32:fa6 +32:fa7 +32:fs2 +32:fs3 +32:fs4 +32:fs5 +32:fs6 +32:fs7 +32:fs8 +32:fs9 +32:fs10 +32:fs11 +32:ft8 +32:ft9 +32:ft10 +32:ft11 +32:fflags +32:frm +32:fcsr diff --git a/gdb/regformats/riscv64-linux.dat b/gdb/regformats/riscv64-linux.dat new file mode 100644 index 0000000..1b88f6c --- /dev/null +++ b/gdb/regformats/riscv64-linux.dat @@ -0,0 +1,71 @@ +name:riscv64_linux +xmltarget:riscv64-linux.xml +expedite:sp,fp,pc +64:zero +64:ra +64:sp +64:gp +64:tp +64:t0 +64:t1 +64:t2 +64:fp +64:s1 +64:a0 +64:a1 +64:a2 +64:a3 +64:a4 +64:a5 +64:a6 +64:a7 +64:s2 +64:s3 +64:s4 +64:s5 +64:s6 +64:s7 +64:s8 +64:s9 +64:s10 +64:s11 +64:t3 +64:t4 +64:t5 +64:t6 +64:pc +64:ft0 +64:ft1 +64:ft2 +64:ft3 +64:ft4 +64:ft5 +64:ft6 +64:ft7 +64:fs0 +64:fs1 +64:fa0 +64:fa1 +64:fa2 +64:fa3 +64:fa4 +64:fa5 +64:fa6 +64:fa7 +64:fs2 +64:fs3 +64:fs4 +64:fs5 +64:fs6 +64:fs7 +64:fs8 +64:fs9 +64:fs10 +64:fs11 +64:ft8 +64:ft9 +64:ft10 +64:ft11 +32:fflags +32:frm +32:fcsr