Browse Source
This commit adds initial Linux target support for LoongArch. Signed-off-by: Zhensong Liu <liuzhensong@loongson.cn> Signed-off-by: Qing zhang <zhangqing@loongson.cn> Signed-off-by: Youling Tang <tangyouling@loongson.cn> Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>gdb-12-branch
1 changed files with 151 additions and 0 deletions
@ -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 <http://www.gnu.org/licenses/>. */
|
|||
|
|||
#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); |
|||
} |
|||
Loading…
Reference in new issue