GDB (xrefs)
Loading...
Searching...
No Matches
loongarch-linux-tdep.c
Go to the documentation of this file.
1/* Target-dependent code for GNU/Linux on LoongArch processors.
2
3 Copyright (C) 2022-2023 Free Software Foundation, Inc.
4 Contributed by Loongson Ltd.
5
6 This file is part of GDB.
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>. */
20
21#include "defs.h"
22#include "glibc-tdep.h"
23#include "inferior.h"
24#include "linux-tdep.h"
25#include "loongarch-tdep.h"
26#include "solib-svr4.h"
27#include "target-descriptions.h"
28#include "trad-frame.h"
29#include "tramp-frame.h"
30
31/* Unpack an elf_gregset_t into GDB's register cache. */
32
33static void
35 struct regcache *regcache, int regnum,
36 const void *gprs, size_t len)
37{
38 int regsize = register_size (regcache->arch (), 0);
39 const gdb_byte *buf = nullptr;
40
41 if (regnum == -1)
42 {
44
45 for (int i = 1; i < 32; i++)
46 {
47 buf = (const gdb_byte*) gprs + regsize * i;
48 regcache->raw_supply (i, (const void *) buf);
49 }
50
51 buf = (const gdb_byte*) gprs + regsize * LOONGARCH_ORIG_A0_REGNUM;
52 regcache->raw_supply (LOONGARCH_ORIG_A0_REGNUM, (const void *) buf);
53
54 buf = (const gdb_byte*) gprs + regsize * LOONGARCH_PC_REGNUM;
55 regcache->raw_supply (LOONGARCH_PC_REGNUM, (const void *) buf);
56
57 buf = (const gdb_byte*) gprs + regsize * LOONGARCH_BADV_REGNUM;
58 regcache->raw_supply (LOONGARCH_BADV_REGNUM, (const void *) buf);
59 }
60 else if (regnum == 0)
62 else if ((regnum > 0 && regnum < 32)
66 {
67 buf = (const gdb_byte*) gprs + regsize * regnum;
68 regcache->raw_supply (regnum, (const void *) buf);
69 }
70}
71
72/* Pack the GDB's register cache value into an elf_gregset_t. */
73
74static void
76 const struct regcache *regcache, int regnum,
77 void *gprs, size_t len)
78{
79 int regsize = register_size (regcache->arch (), 0);
80 gdb_byte *buf = nullptr;
81
82 if (regnum == -1)
83 {
84 for (int i = 0; i < 32; i++)
85 {
86 buf = (gdb_byte *) gprs + regsize * i;
87 regcache->raw_collect (i, (void *) buf);
88 }
89
90 buf = (gdb_byte *) gprs + regsize * LOONGARCH_ORIG_A0_REGNUM;
92
93 buf = (gdb_byte *) gprs + regsize * LOONGARCH_PC_REGNUM;
95
96 buf = (gdb_byte *) gprs + regsize * LOONGARCH_BADV_REGNUM;
98 }
99 else if ((regnum >= 0 && regnum < 32)
103 {
104 buf = (gdb_byte *) gprs + regsize * regnum;
105 regcache->raw_collect (regnum, (void *) buf);
106 }
107}
108
109/* Define the general register regset. */
110
112{
113 nullptr,
116};
117
118/* Unpack an elf_fpregset_t into GDB's register cache. */
119static void
121 struct regcache *regcache, int regnum,
122 const void *fprs, size_t len)
123{
124 const gdb_byte *buf = nullptr;
127
128 if (regnum == -1)
129 {
130 for (int i = 0; i < LOONGARCH_LINUX_NUM_FPREGSET; i++)
131 {
132 buf = (const gdb_byte *)fprs + fprsize * i;
133 regcache->raw_supply (LOONGARCH_FIRST_FP_REGNUM + i, (const void *)buf);
134 }
135 for (int i = 0; i < LOONGARCH_LINUX_NUM_FCC; i++)
136 {
137 buf = (const gdb_byte *)fprs + fprsize * LOONGARCH_LINUX_NUM_FPREGSET +
138 fccsize * i;
139 regcache->raw_supply (LOONGARCH_FIRST_FCC_REGNUM + i, (const void *)buf);
140 }
141 buf = (const gdb_byte *)fprs + fprsize * LOONGARCH_LINUX_NUM_FPREGSET +
142 fccsize * LOONGARCH_LINUX_NUM_FCC;
143 regcache->raw_supply (LOONGARCH_FCSR_REGNUM, (const void *)buf);
144 }
146 {
147 buf = (const gdb_byte *)fprs + fprsize * (regnum - LOONGARCH_FIRST_FP_REGNUM);
148 regcache->raw_supply (regnum, (const void *)buf);
149 }
151 {
152 buf = (const gdb_byte *)fprs + fprsize * LOONGARCH_LINUX_NUM_FPREGSET +
154 regcache->raw_supply (regnum, (const void *)buf);
155 }
156 else if (regnum == LOONGARCH_FCSR_REGNUM)
157 {
158 buf = (const gdb_byte *)fprs + fprsize * LOONGARCH_LINUX_NUM_FPREGSET +
159 fccsize * LOONGARCH_LINUX_NUM_FCC;
160 regcache->raw_supply (regnum, (const void *)buf);
161 }
162}
163
164/* Pack the GDB's register cache value into an elf_fpregset_t. */
165static void
167 const struct regcache *regcache, int regnum,
168 void *fprs, size_t len)
169{
170 gdb_byte *buf = nullptr;
173
174 if (regnum == -1)
175 {
176 for (int i = 0; i < LOONGARCH_LINUX_NUM_FPREGSET; i++)
177 {
178 buf = (gdb_byte *)fprs + fprsize * i;
180 }
181 for (int i = 0; i < LOONGARCH_LINUX_NUM_FCC; i++)
182 {
183 buf = (gdb_byte *)fprs + fprsize * LOONGARCH_LINUX_NUM_FPREGSET +
184 fccsize * i;
186 }
187 buf = (gdb_byte *)fprs + fprsize * LOONGARCH_LINUX_NUM_FPREGSET +
188 fccsize * LOONGARCH_LINUX_NUM_FCC;
190 }
192 {
193 buf = (gdb_byte *)fprs + fprsize * (regnum - LOONGARCH_FIRST_FP_REGNUM);
194 regcache->raw_collect (regnum, (void *)buf);
195 }
197 {
198 buf = (gdb_byte *)fprs + fprsize * LOONGARCH_LINUX_NUM_FPREGSET +
200 regcache->raw_collect (regnum, (void *)buf);
201 }
202 else if (regnum == LOONGARCH_FCSR_REGNUM)
203 {
204 buf = (gdb_byte *)fprs + fprsize * LOONGARCH_LINUX_NUM_FPREGSET +
205 fccsize * LOONGARCH_LINUX_NUM_FCC;
206 regcache->raw_collect (regnum, (void *)buf);
207 }
208}
209
210/* Define the FP register regset. */
212{
213 nullptr,
216};
217
218/* Implement the "init" method of struct tramp_frame. */
219
220#define LOONGARCH_RT_SIGFRAME_UCONTEXT_OFFSET 128
221#define LOONGARCH_UCONTEXT_SIGCONTEXT_OFFSET 176
222
223static void
225 frame_info_ptr this_frame,
226 struct trad_frame_cache *this_cache,
227 CORE_ADDR func)
228{
229 CORE_ADDR frame_sp = get_frame_sp (this_frame);
230 CORE_ADDR sigcontext_base = (frame_sp + LOONGARCH_RT_SIGFRAME_UCONTEXT_OFFSET
232
233 trad_frame_set_reg_addr (this_cache, LOONGARCH_PC_REGNUM, sigcontext_base);
234 for (int i = 0; i < 32; i++)
235 trad_frame_set_reg_addr (this_cache, i, sigcontext_base + 8 + i * 8);
236
237 trad_frame_set_id (this_cache, frame_id_build (frame_sp, func));
238}
239
240/* li.w a7, __NR_rt_sigreturn */
241#define LOONGARCH_INST_LIW_A7_RT_SIGRETURN 0x03822c0b
242/* syscall 0 */
243#define LOONGARCH_INST_SYSCALL 0x002b0000
244
246{
248 4,
249 {
250 { LOONGARCH_INST_LIW_A7_RT_SIGRETURN, ULONGEST_MAX },
251 { LOONGARCH_INST_SYSCALL, ULONGEST_MAX },
252 { TRAMP_SENTINEL_INSN, ULONGEST_MAX }
253 },
255 nullptr
256};
257
258/* Implement the "iterate_over_regset_sections" gdbarch method. */
259
260static void
263 void *cb_data,
264 const struct regcache *regcache)
265{
266 int gprsize = register_size (gdbarch, 0);
270 int fpsize = fprsize * LOONGARCH_LINUX_NUM_FPREGSET +
271 fccsize * LOONGARCH_LINUX_NUM_FCC + fcsrsize;
272
273 cb (".reg", LOONGARCH_LINUX_NUM_GREGSET * gprsize,
274 LOONGARCH_LINUX_NUM_GREGSET * gprsize, &loongarch_gregset, nullptr, cb_data);
275 cb (".reg2", fpsize, fpsize, &loongarch_fpregset, nullptr, cb_data);
276}
277
278/* The following value is derived from __NR_rt_sigreturn in
279 <include/uapi/asm-generic/unistd.h> from the Linux source tree. */
280
281#define LOONGARCH_NR_rt_sigreturn 139
282
283/* When FRAME is at a syscall instruction, return the PC of the next
284 instruction to be executed. */
285
286static CORE_ADDR
288{
289 const CORE_ADDR pc = get_frame_pc (frame);
291
292 /* If we are about to make a sigreturn syscall, use the unwinder to
293 decode the signal frame. */
295 return frame_unwind_caller_pc (frame);
296
297 return pc + 4;
298}
299
300/* Initialize LoongArch Linux ABI info. */
301
302static void
304{
305 loongarch_gdbarch_tdep *tdep = gdbarch_tdep<loongarch_gdbarch_tdep> (gdbarch);
306
307 linux_init_abi (info, gdbarch, 0);
308
310 info.bfd_arch_info->bits_per_address == 32
313
314 /* GNU/Linux uses SVR4-style shared libraries. */
316
317 /* GNU/Linux uses the dynamic linker included in the GNU C Library. */
319
320 /* Enable TLS support. */
322
323 /* Prepend tramp frame unwinder for signal. */
325
326 /* Core file support. */
328
330}
331
332/* Initialize LoongArch Linux target support. */
333
335void
337{
338 gdbarch_register_osabi (bfd_arch_loongarch, bfd_mach_loongarch32,
340 gdbarch_register_osabi (bfd_arch_loongarch, bfd_mach_loongarch64,
342}
int regnum
gdbarch * arch() const
Definition regcache.c:231
void raw_collect(int regnum, void *buf) const override
Definition regcache.c:1127
void raw_supply(int regnum, const void *buf) override
Definition regcache.c:1062
void raw_supply_zeroed(int regnum)
Definition regcache.c:1110
ULONGEST get_frame_register_unsigned(frame_info_ptr frame, int regnum)
Definition frame.c:1399
CORE_ADDR frame_unwind_caller_pc(frame_info_ptr this_frame)
Definition frame.c:1042
CORE_ADDR get_frame_pc(frame_info_ptr frame)
Definition frame.c:2712
CORE_ADDR get_frame_sp(frame_info_ptr this_frame)
Definition frame.c:3115
struct frame_id frame_id_build(CORE_ADDR stack_addr, CORE_ADDR code_addr)
Definition frame.c:736
@ SIGTRAMP_FRAME
Definition frame.h:198
void set_gdbarch_skip_trampoline_code(struct gdbarch *gdbarch, gdbarch_skip_trampoline_code_ftype *skip_trampoline_code)
void set_gdbarch_fetch_tls_load_module_address(struct gdbarch *gdbarch, gdbarch_fetch_tls_load_module_address_ftype *fetch_tls_load_module_address)
void set_gdbarch_skip_solib_resolver(struct gdbarch *gdbarch, gdbarch_skip_solib_resolver_ftype *skip_solib_resolver)
void set_gdbarch_iterate_over_regset_sections(struct gdbarch *gdbarch, gdbarch_iterate_over_regset_sections_ftype *iterate_over_regset_sections)
void iterate_over_regset_sections_cb(const char *sect_name, int supply_size, int collect_size, const struct regset *regset, const char *human_name, void *cb_data)
Definition gdbarch.h:104
CORE_ADDR glibc_skip_solib_resolver(struct gdbarch *gdbarch, CORE_ADDR pc)
Definition glibc-tdep.c:38
link_map_offsets * linux_lp64_fetch_link_map_offsets()
link_map_offsets * linux_ilp32_fetch_link_map_offsets()
void linux_init_abi(struct gdbarch_info info, struct gdbarch *gdbarch, int num_disp_step_buffers)
static CORE_ADDR loongarch_linux_syscall_next_pc(frame_info_ptr frame)
static void loongarch_supply_gregset(const struct regset *regset, struct regcache *regcache, int regnum, const void *gprs, size_t len)
static void loongarch_fill_gregset(const struct regset *regset, const struct regcache *regcache, int regnum, void *gprs, size_t len)
void _initialize_loongarch_linux_tdep()
#define LOONGARCH_RT_SIGFRAME_UCONTEXT_OFFSET
#define LOONGARCH_INST_SYSCALL
const struct regset loongarch_gregset
#define LOONGARCH_INST_LIW_A7_RT_SIGRETURN
static void loongarch_linux_init_abi(struct gdbarch_info info, struct gdbarch *gdbarch)
#define LOONGARCH_UCONTEXT_SIGCONTEXT_OFFSET
static const struct tramp_frame loongarch_linux_rt_sigframe
const struct regset loongarch_fpregset
#define LOONGARCH_NR_rt_sigreturn
static void loongarch_iterate_over_regset_sections(struct gdbarch *gdbarch, iterate_over_regset_sections_cb *cb, void *cb_data, const struct regcache *regcache)
static void loongarch_fill_fpregset(const struct regset *r, const struct regcache *regcache, int regnum, void *fprs, size_t len)
static void loongarch_supply_fpregset(const struct regset *r, struct regcache *regcache, int regnum, const void *fprs, size_t len)
static void loongarch_linux_rt_sigframe_init(const struct tramp_frame *self, frame_info_ptr this_frame, struct trad_frame_cache *this_cache, CORE_ADDR func)
@ LOONGARCH_A7_REGNUM
Definition loongarch.h:31
@ LOONGARCH_LINUX_NUM_FPREGSET
Definition loongarch.h:40
@ LOONGARCH_LINUX_NUM_FCC
Definition loongarch.h:42
@ LOONGARCH_FIRST_FCC_REGNUM
Definition loongarch.h:41
@ LOONGARCH_FIRST_FP_REGNUM
Definition loongarch.h:39
@ LOONGARCH_PC_REGNUM
Definition loongarch.h:34
@ LOONGARCH_FCSR_REGNUM
Definition loongarch.h:43
@ LOONGARCH_LINUX_NUM_GREGSET
Definition loongarch.h:36
@ LOONGARCH_ORIG_A0_REGNUM
Definition loongarch.h:33
@ LOONGARCH_BADV_REGNUM
Definition loongarch.h:35
CORE_ADDR find_solib_trampoline_target(frame_info_ptr frame, CORE_ADDR pc)
Definition minsyms.c:1554
void gdbarch_register_osabi(enum bfd_architecture arch, unsigned long machine, enum gdb_osabi osabi, void(*init_osabi)(struct gdbarch_info, struct gdbarch *))
Definition osabi.c:146
@ GDB_OSABI_LINUX
Definition osabi.h:32
int register_size(struct gdbarch *gdbarch, int regnum)
Definition regcache.c:170
void(* func)(remote_target *remote, char *)
void set_solib_svr4_fetch_link_map_offsets(struct gdbarch *gdbarch, struct link_map_offsets *(*flmo)(void))
CORE_ADDR svr4_fetch_objfile_link_map(struct objfile *objfile)
CORE_ADDR(* syscall_next_pc)(frame_info_ptr frame)
void trad_frame_set_reg_addr(struct trad_frame_cache *this_trad_cache, int regnum, CORE_ADDR addr)
Definition trad-frame.c:110
void trad_frame_set_id(struct trad_frame_cache *this_trad_cache, struct frame_id this_id)
Definition trad-frame.c:220
void tramp_frame_prepend_unwinder(struct gdbarch *gdbarch, const struct tramp_frame *tramp_frame)
#define TRAMP_SENTINEL_INSN
Definition tramp-frame.h:44