1 /* Target-dependent code for GNU/Linux on LoongArch processors.
3 Copyright (C) 2022 Free Software Foundation, Inc.
4 Contributed by Loongson Ltd.
6 This file is part of GDB.
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.
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.
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/>. */
22 #include "glibc-tdep.h"
25 #include "linux-tdep.h"
26 #include "loongarch-tdep.h"
27 #include "solib-svr4.h"
28 #include "target-descriptions.h"
29 #include "trad-frame.h"
30 #include "tramp-frame.h"
32 /* The general-purpose regset consists of 32 R registers, plus PC,
33 and BADV registers. In addition, reserved 11 for extension in glibc. */
35 #define LOONGARCH_LINUX_NUM_GREGSET (45)
37 /* Unpack an elf_gregset_t into GDB's register cache. */
40 loongarch_supply_gregset (const struct regset
*r
,
41 struct regcache
*regcache
, int regno
,
42 const void *gprs
, size_t len
)
44 loongarch_gdbarch_tdep
*tdep
45 = (loongarch_gdbarch_tdep
*) gdbarch_tdep (regcache
->arch ());
46 auto regs
= tdep
->regs
;
48 int regsize
= register_size (regcache
->arch (), regs
.r
);
49 const gdb_byte
*buf
= nullptr;
54 regcache
->raw_supply_zeroed (regs
.r
);
56 for (int i
= 1; i
< 32; i
++)
58 buf
= (const gdb_byte
*) gprs
+ regsize
* i
;
59 regcache
->raw_supply (regs
.r
+ i
, (const void *) buf
);
62 /* Size base (pc) = regsize * regs.pc. */
63 buf
= (const gdb_byte
*) gprs
+ regsize
* regs
.pc
;
64 regcache
->raw_supply (regs
.pc
, (const void *) buf
);
66 /* Size base (badv) = regsize * regs.badv. */
67 buf
= (const gdb_byte
*) gprs
+ regsize
* regs
.badv
;
68 regcache
->raw_supply (regs
.badv
, (const void *) buf
);
70 else if (regs
.r
== regno
)
71 regcache
->raw_supply_zeroed (regno
);
72 else if ((regs
.r
< regno
&& regno
< regs
.r
+ 32)
73 || regs
.pc
== regno
|| regs
.badv
== regno
)
75 /* Offset offset (regno) = regsize * (regno - regs.r). */
76 buf
= (const gdb_byte
*) gprs
+ regsize
* (regno
- regs
.r
);
77 regcache
->raw_supply (regno
, (const void *) buf
);
81 /* Pack the GDB's register cache value into an elf_gregset_t. */
84 loongarch_fill_gregset (const struct regset
*r
,
85 const struct regcache
*regcache
, int regno
,
86 void *gprs
, size_t len
)
88 loongarch_gdbarch_tdep
*tdep
89 = (loongarch_gdbarch_tdep
*) gdbarch_tdep (regcache
->arch ());
90 auto regs
= tdep
->regs
;
91 int regsize
= register_size (regcache
->arch (), regs
.r
);
92 gdb_byte
*buf
= nullptr;
96 for (int i
= 0; i
< 32; i
++)
98 buf
= (gdb_byte
*) gprs
+ regsize
* i
;
99 regcache
->raw_collect (regs
.r
+ i
, (void *) buf
);
102 /* Size base (pc) = regsize * regs.pc. */
103 buf
= (gdb_byte
*) gprs
+ regsize
* regs
.pc
;
104 regcache
->raw_collect (regs
.pc
, (void *) buf
);
106 /* Size base (badv) = regsize * regs.badv. */
107 buf
= (gdb_byte
*) gprs
+ regsize
* regs
.badv
;
108 regcache
->raw_collect (regs
.badv
, (void *) buf
);
110 else if ((regs
.r
<= regno
&& regno
< regs
.r
+ 32)
111 || regs
.pc
== regno
|| regs
.badv
== regno
)
113 /* Offset offset (regno) = regsize * (regno - regs.r). */
114 buf
= (gdb_byte
*) gprs
+ regsize
* (regno
- regs
.r
);
115 regcache
->raw_collect (regno
, (void *) buf
);
119 /* Register set definitions. */
121 const struct regset loongarch_gregset
=
124 loongarch_supply_gregset
,
125 loongarch_fill_gregset
,
128 /* Implement the "init" method of struct tramp_frame. */
130 #define LOONGARCH_RT_SIGFRAME_UCONTEXT_OFFSET 128
131 #define LOONGARCH_UCONTEXT_SIGCONTEXT_OFFSET 176
134 loongarch_linux_rt_sigframe_init (const struct tramp_frame
*self
,
135 struct frame_info
*this_frame
,
136 struct trad_frame_cache
*this_cache
,
139 struct gdbarch
*gdbarch
= get_frame_arch (this_frame
);
140 loongarch_gdbarch_tdep
*tdep
= (loongarch_gdbarch_tdep
*) gdbarch_tdep (gdbarch
);
141 auto regs
= tdep
->regs
;
143 CORE_ADDR frame_sp
= get_frame_sp (this_frame
);
144 CORE_ADDR sigcontext_base
= (frame_sp
+ LOONGARCH_RT_SIGFRAME_UCONTEXT_OFFSET
145 + LOONGARCH_UCONTEXT_SIGCONTEXT_OFFSET
);
147 trad_frame_set_reg_addr (this_cache
, regs
.pc
, sigcontext_base
);
148 for (int i
= 0; i
< 32; i
++)
149 trad_frame_set_reg_addr (this_cache
, regs
.r
+ i
, sigcontext_base
+ 8 + i
* 8);
151 trad_frame_set_id (this_cache
, frame_id_build (frame_sp
, func
));
154 /* li.w a7, __NR_rt_sigreturn */
155 #define LOONGARCH_INST_LIW_A7_RT_SIGRETURN 0x03822c0b
157 #define LOONGARCH_INST_SYSCALL 0x002b0000
159 static const struct tramp_frame loongarch_linux_rt_sigframe
=
164 { LOONGARCH_INST_LIW_A7_RT_SIGRETURN
, ULONGEST_MAX
},
165 { LOONGARCH_INST_SYSCALL
, ULONGEST_MAX
},
166 { TRAMP_SENTINEL_INSN
, ULONGEST_MAX
}
168 loongarch_linux_rt_sigframe_init
,
172 /* Implement the "iterate_over_regset_sections" gdbarch method. */
175 loongarch_iterate_over_regset_sections (struct gdbarch
*gdbarch
,
176 iterate_over_regset_sections_cb
*cb
,
178 const struct regcache
*regcache
)
180 loongarch_gdbarch_tdep
*tdep
181 = (loongarch_gdbarch_tdep
*) gdbarch_tdep (gdbarch
);
182 auto regs
= tdep
->regs
;
183 int regsize
= register_size (gdbarch
, regs
.r
);
185 cb (".reg", LOONGARCH_LINUX_NUM_GREGSET
* regsize
,
186 LOONGARCH_LINUX_NUM_GREGSET
* regsize
, &loongarch_gregset
, NULL
, cb_data
);
189 /* Initialize LoongArch Linux ABI info. */
192 loongarch_linux_init_abi (struct gdbarch_info info
, struct gdbarch
*gdbarch
)
194 linux_init_abi (info
, gdbarch
, 0);
196 set_solib_svr4_fetch_link_map_offsets (gdbarch
,
197 info
.bfd_arch_info
->bits_per_address
== 32
198 ? linux_ilp32_fetch_link_map_offsets
199 : linux_lp64_fetch_link_map_offsets
);
201 /* GNU/Linux uses SVR4-style shared libraries. */
202 set_gdbarch_skip_trampoline_code (gdbarch
, find_solib_trampoline_target
);
204 /* GNU/Linux uses the dynamic linker included in the GNU C Library. */
205 set_gdbarch_skip_solib_resolver (gdbarch
, glibc_skip_solib_resolver
);
207 /* Enable TLS support. */
208 set_gdbarch_fetch_tls_load_module_address (gdbarch
, svr4_fetch_objfile_link_map
);
210 /* Prepend tramp frame unwinder for signal. */
211 tramp_frame_prepend_unwinder (gdbarch
, &loongarch_linux_rt_sigframe
);
213 /* Core file support. */
214 set_gdbarch_iterate_over_regset_sections (gdbarch
, loongarch_iterate_over_regset_sections
);
217 /* Initialize LoongArch Linux target support. */
219 void _initialize_loongarch_linux_tdep ();
221 _initialize_loongarch_linux_tdep ()
223 gdbarch_register_osabi (bfd_arch_loongarch
, bfd_mach_loongarch32
,
224 GDB_OSABI_LINUX
, loongarch_linux_init_abi
);
225 gdbarch_register_osabi (bfd_arch_loongarch
, bfd_mach_loongarch64
,
226 GDB_OSABI_LINUX
, loongarch_linux_init_abi
);