From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 7873) id 31D493852754; Tue, 14 Jun 2022 14:22:16 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 31D493852754 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable From: Tiezhu Yang To: gdb-cvs@sourceware.org Subject: [binutils-gdb] gdbserver: Add LoongArch/Linux support X-Act-Checkin: binutils-gdb X-Git-Author: Youling Tang X-Git-Refname: refs/heads/master X-Git-Oldrev: 476288fa2bddecf0f0e13dee826a076309bf01fe X-Git-Newrev: e5ab6af52d38ee068c1860ef113b7db4cc985cfb Message-Id: <20220614142216.31D493852754@sourceware.org> Date: Tue, 14 Jun 2022 14:22:16 +0000 (GMT) X-BeenThere: gdb-cvs@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 14 Jun 2022 14:22:16 -0000 https://sourceware.org/git/gitweb.cgi?p=3Dbinutils-gdb.git;h=3De5ab6af52d38= ee068c1860ef113b7db4cc985cfb commit e5ab6af52d38ee068c1860ef113b7db4cc985cfb Author: Youling Tang Date: Mon May 30 20:08:30 2022 +0800 gdbserver: Add LoongArch/Linux support =20 Implement LoongArch/Linux support, including XML target description handling based on features determined, GPR regset support, and software breakpoint handling. =20 In the Linux kernel code of LoongArch, ptrace implements PTRACE_POKEUSR and PTRACE_PEEKUSR in the arch_ptrace function, so srv_linux_usrregs is set to yes. =20 With this patch on LoongArch: =20 $ make check-gdb TESTS=3D"gdb.server/server-connect.exp" [...] # of expected passes 18 [...] =20 Signed-off-by: Youling Tang Signed-off-by: Tiezhu Yang Diff: --- gdb/NEWS | 3 + gdb/arch/loongarch.c | 12 +- gdb/arch/loongarch.h | 13 +++ gdbserver/Makefile.in | 2 + gdbserver/configure.srv | 6 + gdbserver/linux-loongarch-low.cc | 245 +++++++++++++++++++++++++++++++++++= ++++ 6 files changed, 280 insertions(+), 1 deletion(-) diff --git a/gdb/NEWS b/gdb/NEWS index 7164e18bfa5..0efcce7d3ef 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -694,6 +694,8 @@ QMemTags =20 ** GDBserver is now supported on RISC-V GNU/Linux. =20 + ** GDBserver is now supported on LoongArch GNU/Linux. + ** GDBserver no longer supports these host triplets: =20 i[34567]86-*-lynxos* @@ -785,6 +787,7 @@ alias [-a] [--] ALIAS =3D COMMAND [DEFAULT-ARGS...] * New targets =20 GNU/Linux/RISC-V (gdbserver) riscv*-*-linux* +GNU/Linux/LoongArch (gdbserver) loongarch*-*-linux* BPF bpf-unknown-none Z80 z80-unknown-* =20 diff --git a/gdb/arch/loongarch.c b/gdb/arch/loongarch.c index 934f6e489c5..11310c1dd93 100644 --- a/gdb/arch/loongarch.c +++ b/gdb/arch/loongarch.c @@ -25,7 +25,13 @@ #include "../features/loongarch/base32.c" #include "../features/loongarch/base64.c" =20 -static target_desc_up +#ifndef GDBSERVER +#define STATIC_IN_GDB static +#else +#define STATIC_IN_GDB +#endif + +STATIC_IN_GDB target_desc_up loongarch_create_target_description (const struct loongarch_gdbarch_featur= es features) { /* Now we should create a new target description. */ @@ -51,6 +57,8 @@ loongarch_create_target_description (const struct loongar= ch_gdbarch_features fea return tdesc; } =20 +#ifndef GDBSERVER + /* Wrapper used by std::unordered_map to generate hash for feature set. */ struct loongarch_gdbarch_features_hasher { @@ -86,3 +94,5 @@ loongarch_lookup_target_description (const struct loongar= ch_gdbarch_features fea loongarch_tdesc_cache.emplace (features, std::move (tdesc)); return ptr; } + +#endif /* !GDBSERVER */ diff --git a/gdb/arch/loongarch.h b/gdb/arch/loongarch.h index 9e10df967d1..8194ea66c0a 100644 --- a/gdb/arch/loongarch.h +++ b/gdb/arch/loongarch.h @@ -60,6 +60,17 @@ struct loongarch_gdbarch_features } }; =20 +#ifdef GDBSERVER + +/* Create and return a target description that is compatible with FEATURES. + This is only used directly from the gdbserver where the created target + description is modified after it is return. */ + +target_desc_up loongarch_create_target_description + (const struct loongarch_gdbarch_features features); + +#else + /* Lookup an already existing target description matching FEATURES, or create a new target description if this is the first time we have seen FEATURES. For the same FEATURES the same target_desc is always @@ -70,4 +81,6 @@ struct loongarch_gdbarch_features const target_desc *loongarch_lookup_target_description (const struct loongarch_gdbarch_features features); =20 +#endif /* GDBSERVER */ + #endif /* ARCH_LOONGARCH_H */ diff --git a/gdbserver/Makefile.in b/gdbserver/Makefile.in index 6e14278cd4b..75e497753e8 100644 --- a/gdbserver/Makefile.in +++ b/gdbserver/Makefile.in @@ -176,6 +176,7 @@ SFILES =3D \ $(srcdir)/linux-arc-low.cc \ $(srcdir)/linux-arm-low.cc \ $(srcdir)/linux-ia64-low.cc \ + $(srcdir)/linux-loongarch-low.cc \ $(srcdir)/linux-low.cc \ $(srcdir)/linux-m68k-low.cc \ $(srcdir)/linux-mips-low.cc \ @@ -211,6 +212,7 @@ SFILES =3D \ $(srcdir)/../gdb/arch/arm.c \ $(srcdir)/../gdb/arch/arm-get-next-pcs.c \ $(srcdir)/../gdb/arch/arm-linux.c \ + $(srcdir)/../gdb/arch/loongarch.c \ $(srcdir)/../gdb/arch/ppc-linux-common.c \ $(srcdir)/../gdb/arch/riscv.c \ $(srcdir)/../gdb/nat/aarch64-mte-linux-ptrace.c \ diff --git a/gdbserver/configure.srv b/gdbserver/configure.srv index d37053628fc..ebb6b32a6c4 100644 --- a/gdbserver/configure.srv +++ b/gdbserver/configure.srv @@ -126,6 +126,12 @@ case "${gdbserver_host}" in srv_tgtobj=3D"$srv_linux_obj linux-ia64-low.o" srv_linux_usrregs=3Dyes ;; + loongarch*-*-linux*) srv_tgtobj=3D"arch/loongarch.o linux-loongarch-low.= o" + srv_tgtobj=3D"${srv_tgtobj} ${srv_linux_obj}" + srv_linux_regsets=3Dyes + srv_linux_usrregs=3Dyes + srv_linux_thread_db=3Dyes + ;; m68*-*-linux*) if test "$gdb_cv_m68k_is_coldfire" =3D yes; then srv_regobj=3Dreg-cf.o else diff --git a/gdbserver/linux-loongarch-low.cc b/gdbserver/linux-loongarch-l= ow.cc new file mode 100644 index 00000000000..5d3739354e6 --- /dev/null +++ b/gdbserver/linux-loongarch-low.cc @@ -0,0 +1,245 @@ +/* GNU/Linux/LoongArch specific low level interface, for the remote server + for GDB. + Copyright (C) 2022 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 "tdesc.h" +#include "elf/common.h" +#include "arch/loongarch.h" + +/* Linux target ops definitions for the LoongArch architecture. */ + +class loongarch_target : public linux_process_target +{ +public: + + const regs_info *get_regs_info () override; + + int breakpoint_kind_from_pc (CORE_ADDR *pcptr) override; + + const gdb_byte *sw_breakpoint_from_kind (int kind, int *size) override; + +protected: + + void low_arch_setup () override; + + bool low_cannot_fetch_register (int regno) override; + + bool low_cannot_store_register (int regno) override; + + bool low_fetch_register (regcache *regcache, int regno) override; + + bool low_supports_breakpoints () override; + + CORE_ADDR low_get_pc (regcache *regcache) override; + + void low_set_pc (regcache *regcache, CORE_ADDR newpc) override; + + bool low_breakpoint_at (CORE_ADDR pc) override; +}; + +/* The singleton target ops object. */ + +static loongarch_target the_loongarch_target; + +bool +loongarch_target::low_cannot_fetch_register (int regno) +{ + gdb_assert_not_reached ("linux target op low_cannot_fetch_register " + "is not implemented by the target"); +} + +bool +loongarch_target::low_cannot_store_register (int regno) +{ + gdb_assert_not_reached ("linux target op low_cannot_store_register " + "is not implemented by the target"); +} + +/* Implementation of linux target ops method "low_arch_setup". */ + +void +loongarch_target::low_arch_setup () +{ + static const char *expedite_regs[] =3D { "r3", "pc", NULL }; + loongarch_gdbarch_features features; + target_desc_up tdesc; + + features.xlen =3D sizeof (elf_greg_t); + tdesc =3D loongarch_create_target_description (features); + + if (!tdesc->expedite_regs) + init_target_desc (tdesc.get (), expedite_regs); + current_process ()->tdesc =3D tdesc.release (); +} + +/* Collect GPRs from REGCACHE into BUF. */ + +static void +loongarch_fill_gregset (struct regcache *regcache, void *buf) +{ + const struct target_desc *tdesc =3D regcache->tdesc; + elf_gregset_t *regset =3D (elf_gregset_t *) buf; + int regno =3D find_regno (tdesc, "r0"); + int i; + + for (i =3D 1; i < 32; i++) + collect_register (regcache, regno + i, *regset + i); + collect_register_by_name (regcache, "pc", *regset + 32); + collect_register_by_name (regcache, "badv", *regset + 33); +} + +/* Supply GPRs from BUF into REGCACHE. */ + +static void +loongarch_store_gregset (struct regcache *regcache, const void *buf) +{ + const struct target_desc *tdesc =3D regcache->tdesc; + const elf_gregset_t *regset =3D (const elf_gregset_t *) buf; + int regno =3D find_regno (tdesc, "r0"); + int i; + + supply_register_zeroed (regcache, regno); + for (i =3D 1; i < 32; i++) + supply_register (regcache, regno + i, *regset + i); + supply_register_by_name (regcache, "pc", *regset + 32); + supply_register_by_name (regcache, "badv", *regset + 33); +} + +/* LoongArch/Linux regsets. */ +static struct regset_info loongarch_regsets[] =3D { + { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PRSTATUS, sizeof (elf_gregset_t= ), + GENERAL_REGS, loongarch_fill_gregset, loongarch_store_gregset }, + NULL_REGSET +}; + +/* LoongArch/Linux regset information. */ +static struct regsets_info loongarch_regsets_info =3D + { + loongarch_regsets, /* regsets */ + 0, /* num_regsets */ + NULL, /* disabled_regsets */ + }; + +/* Definition of linux_target_ops data member "regs_info". */ +static struct regs_info loongarch_regs =3D + { + NULL, /* regset_bitmap */ + NULL, /* usrregs */ + &loongarch_regsets_info, + }; + +/* Implementation of linux target ops method "get_regs_info". */ + +const regs_info * +loongarch_target::get_regs_info () +{ + return &loongarch_regs; +} + +/* Implementation of linux target ops method "low_fetch_register". */ + +bool +loongarch_target::low_fetch_register (regcache *regcache, int regno) +{ + const struct target_desc *tdesc =3D regcache->tdesc; + + if (regno !=3D find_regno (tdesc, "r0")) + return false; + supply_register_zeroed (regcache, regno); + return true; +} + +bool +loongarch_target::low_supports_breakpoints () +{ + return true; +} + +/* Implementation of linux target ops method "low_get_pc". */ + +CORE_ADDR +loongarch_target::low_get_pc (regcache *regcache) +{ + if (register_size (regcache->tdesc, 0) =3D=3D 8) + return linux_get_pc_64bit (regcache); + else + return linux_get_pc_32bit (regcache); +} + +/* Implementation of linux target ops method "low_set_pc". */ + +void +loongarch_target::low_set_pc (regcache *regcache, CORE_ADDR newpc) +{ + if (register_size (regcache->tdesc, 0) =3D=3D 8) + linux_set_pc_64bit (regcache, newpc); + else + linux_set_pc_32bit (regcache, newpc); +} + +#define loongarch_breakpoint_len 4 + +/* LoongArch BRK software debug mode instruction. + This instruction needs to match gdb/loongarch-tdep.c + (loongarch_default_breakpoint). */ +static const gdb_byte loongarch_breakpoint[] =3D {0x05, 0x00, 0x2a, 0x00}; + +/* Implementation of target ops method "breakpoint_kind_from_pc". */ + +int +loongarch_target::breakpoint_kind_from_pc (CORE_ADDR *pcptr) +{ + return loongarch_breakpoint_len; +} + +/* Implementation of target ops method "sw_breakpoint_from_kind". */ + +const gdb_byte * +loongarch_target::sw_breakpoint_from_kind (int kind, int *size) +{ + *size =3D loongarch_breakpoint_len; + return (const gdb_byte *) &loongarch_breakpoint; +} + +/* Implementation of linux target ops method "low_breakpoint_at". */ + +bool +loongarch_target::low_breakpoint_at (CORE_ADDR pc) +{ + gdb_byte insn[loongarch_breakpoint_len]; + + read_memory (pc, (unsigned char *) &insn, loongarch_breakpoint_len); + if (memcmp (insn, loongarch_breakpoint, loongarch_breakpoint_len) =3D=3D= 0) + return true; + + return false; +} + +/* The linux target ops object. */ + +linux_process_target *the_linux_target =3D &the_loongarch_target; + +/* Initialize the LoongArch/Linux target. */ + +void +initialize_low_arch () +{ + initialize_regsets_info (&loongarch_regsets_info); +}