From: Tiezhu Yang Date: Fri, 11 Feb 2022 12:15:06 +0000 (+0800) Subject: gdb: LoongArch: Add initial Linux target support X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=24e58d7c9b85782f8f57bdf4c53acbd19e1fb260;p=binutils-gdb.git gdb: LoongArch: Add initial Linux target support This commit adds initial Linux target support for LoongArch. Signed-off-by: Zhensong Liu Signed-off-by: Qing zhang Signed-off-by: Youling Tang Signed-off-by: Tiezhu Yang --- diff --git a/gdb/loongarch-linux-tdep.c b/gdb/loongarch-linux-tdep.c new file mode 100644 index 00000000000..6c040c3c385 --- /dev/null +++ b/gdb/loongarch-linux-tdep.c @@ -0,0 +1,151 @@ +/* Target-dependent code for GNU/Linux on LoongArch processors. + + Copyright (C) 2022 Free Software Foundation, Inc. + Contributed by Loongson Ltd. + + 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 "glibc-tdep.h" +#include "inferior.h" +#include "linux-tdep.h" +#include "loongarch-tdep.h" +#include "solib-svr4.h" +#include "target-descriptions.h" + +/* Unpack an elf_gregset_t into GDB's register cache. */ + +static void +loongarch_supply_gregset (const struct regset *r, + struct regcache *regcache, int regno, + const void *gprs, size_t len) +{ + loongarch_gdbarch_tdep *tdep + = (loongarch_gdbarch_tdep *) gdbarch_tdep (regcache->arch ()); + auto regs = tdep->regs; + + int regsize = register_size (regcache->arch (), regs.r); + const gdb_byte *buf = nullptr; + + if (regno == -1) + { + /* Set $r0 = 0. */ + regcache->raw_supply_zeroed (regs.r); + + for (int i = 1; i < 32; i++) + { + buf = (const gdb_byte*) gprs + regsize * i; + regcache->raw_supply (regs.r + i, (const void *) buf); + } + + /* Size base (pc) = regsize * regs.pc. */ + buf = (const gdb_byte*) gprs + regsize * regs.pc; + regcache->raw_supply (regs.pc, (const void *) buf); + + /* Size base (badv) = regsize * regs.badv. */ + buf = (const gdb_byte*) gprs + regsize * regs.badv; + regcache->raw_supply (regs.badv, (const void *) buf); + } + else if (regs.r == regno) + regcache->raw_supply_zeroed (regno); + else if ((regs.r < regno && regno < regs.r + 32) + || regs.pc == regno || regs.badv == regno) + { + /* Offset offset (regno) = regsize * (regno - regs.r). */ + buf = (const gdb_byte*) gprs + regsize * (regno - regs.r); + regcache->raw_supply (regno, (const void *) buf); + } +} + +/* Pack the GDB's register cache value into an elf_gregset_t. */ + +static void +loongarch_fill_gregset (const struct regset *r, + const struct regcache *regcache, int regno, + void *gprs, size_t len) +{ + loongarch_gdbarch_tdep *tdep + = (loongarch_gdbarch_tdep *) gdbarch_tdep (regcache->arch ()); + auto regs = tdep->regs; + int regsize = register_size (regcache->arch (), regs.r); + gdb_byte *buf = nullptr; + + if (regno == -1) + { + for (int i = 0; i < 32; i++) + { + buf = (gdb_byte *) gprs + regsize * i; + regcache->raw_collect (regs.r + i, (void *) buf); + } + + /* Size base (pc) = regsize * regs.pc. */ + buf = (gdb_byte *) gprs + regsize * regs.pc; + regcache->raw_collect (regs.pc, (void *) buf); + + /* Size base (badv) = regsize * regs.badv. */ + buf = (gdb_byte *) gprs + regsize * regs.badv; + regcache->raw_collect (regs.badv, (void *) buf); + } + else if ((regs.r <= regno && regno < regs.r + 32) + || regs.pc == regno || regs.badv == regno) + { + /* Offset offset (regno) = regsize * (regno - regs.r). */ + buf = (gdb_byte *) gprs + regsize * (regno - regs.r); + regcache->raw_collect (regno, (void *) buf); + } +} + +/* Register set definitions. */ + +const struct regset loongarch_gregset = +{ + nullptr, + loongarch_supply_gregset, + loongarch_fill_gregset, +}; + +/* Initialize LoongArch Linux ABI info. */ + +static void +loongarch_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) +{ + linux_init_abi (info, gdbarch, 0); + + set_solib_svr4_fetch_link_map_offsets (gdbarch, + info.bfd_arch_info->bits_per_address == 32 + ? linux_ilp32_fetch_link_map_offsets + : linux_lp64_fetch_link_map_offsets); + + /* GNU/Linux uses SVR4-style shared libraries. */ + set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target); + + /* GNU/Linux uses the dynamic linker included in the GNU C Library. */ + set_gdbarch_skip_solib_resolver (gdbarch, glibc_skip_solib_resolver); + /* Enable TLS support. */ + set_gdbarch_fetch_tls_load_module_address (gdbarch, svr4_fetch_objfile_link_map); +} + +/* Initialize LoongArch Linux target support. */ + +void _initialize_loongarch_linux_tdep (); +void +_initialize_loongarch_linux_tdep () +{ + gdbarch_register_osabi (bfd_arch_loongarch, bfd_mach_loongarch32, + GDB_OSABI_LINUX, loongarch_linux_init_abi); + gdbarch_register_osabi (bfd_arch_loongarch, bfd_mach_loongarch64, + GDB_OSABI_LINUX, loongarch_linux_init_abi); +}