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"
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"
31 /* Unpack an elf_gregset_t into GDB's register cache. */
34 loongarch_supply_gregset (const struct regset
*r
,
35 struct regcache
*regcache
, int regno
,
36 const void *gprs
, size_t len
)
38 loongarch_gdbarch_tdep
*tdep
39 = (loongarch_gdbarch_tdep
*) gdbarch_tdep (regcache
->arch ());
40 auto regs
= tdep
->regs
;
42 int regsize
= register_size (regcache
->arch (), regs
.r
);
43 const gdb_byte
*buf
= nullptr;
48 regcache
->raw_supply_zeroed (regs
.r
);
50 for (int i
= 1; i
< 32; i
++)
52 buf
= (const gdb_byte
*) gprs
+ regsize
* i
;
53 regcache
->raw_supply (regs
.r
+ i
, (const void *) buf
);
56 /* Size base (pc) = regsize * regs.pc. */
57 buf
= (const gdb_byte
*) gprs
+ regsize
* regs
.pc
;
58 regcache
->raw_supply (regs
.pc
, (const void *) buf
);
60 /* Size base (badv) = regsize * regs.badv. */
61 buf
= (const gdb_byte
*) gprs
+ regsize
* regs
.badv
;
62 regcache
->raw_supply (regs
.badv
, (const void *) buf
);
64 else if (regs
.r
== regno
)
65 regcache
->raw_supply_zeroed (regno
);
66 else if ((regs
.r
< regno
&& regno
< regs
.r
+ 32)
67 || regs
.pc
== regno
|| regs
.badv
== regno
)
69 /* Offset offset (regno) = regsize * (regno - regs.r). */
70 buf
= (const gdb_byte
*) gprs
+ regsize
* (regno
- regs
.r
);
71 regcache
->raw_supply (regno
, (const void *) buf
);
75 /* Pack the GDB's register cache value into an elf_gregset_t. */
78 loongarch_fill_gregset (const struct regset
*r
,
79 const struct regcache
*regcache
, int regno
,
80 void *gprs
, size_t len
)
82 loongarch_gdbarch_tdep
*tdep
83 = (loongarch_gdbarch_tdep
*) gdbarch_tdep (regcache
->arch ());
84 auto regs
= tdep
->regs
;
85 int regsize
= register_size (regcache
->arch (), regs
.r
);
86 gdb_byte
*buf
= nullptr;
90 for (int i
= 0; i
< 32; i
++)
92 buf
= (gdb_byte
*) gprs
+ regsize
* i
;
93 regcache
->raw_collect (regs
.r
+ i
, (void *) buf
);
96 /* Size base (pc) = regsize * regs.pc. */
97 buf
= (gdb_byte
*) gprs
+ regsize
* regs
.pc
;
98 regcache
->raw_collect (regs
.pc
, (void *) buf
);
100 /* Size base (badv) = regsize * regs.badv. */
101 buf
= (gdb_byte
*) gprs
+ regsize
* regs
.badv
;
102 regcache
->raw_collect (regs
.badv
, (void *) buf
);
104 else if ((regs
.r
<= regno
&& regno
< regs
.r
+ 32)
105 || regs
.pc
== regno
|| regs
.badv
== regno
)
107 /* Offset offset (regno) = regsize * (regno - regs.r). */
108 buf
= (gdb_byte
*) gprs
+ regsize
* (regno
- regs
.r
);
109 regcache
->raw_collect (regno
, (void *) buf
);
113 /* Register set definitions. */
115 const struct regset loongarch_gregset
=
118 loongarch_supply_gregset
,
119 loongarch_fill_gregset
,
122 /* Implement the "init" method of struct tramp_frame. */
124 #define LOONGARCH_RT_SIGFRAME_UCONTEXT_OFFSET 128
125 #define LOONGARCH_UCONTEXT_SIGCONTEXT_OFFSET 176
128 loongarch_linux_rt_sigframe_init (const struct tramp_frame
*self
,
129 struct frame_info
*this_frame
,
130 struct trad_frame_cache
*this_cache
,
133 struct gdbarch
*gdbarch
= get_frame_arch (this_frame
);
134 loongarch_gdbarch_tdep
*tdep
= (loongarch_gdbarch_tdep
*) gdbarch_tdep (gdbarch
);
135 auto regs
= tdep
->regs
;
137 CORE_ADDR frame_sp
= get_frame_sp (this_frame
);
138 CORE_ADDR sigcontext_base
= (frame_sp
+ LOONGARCH_RT_SIGFRAME_UCONTEXT_OFFSET
139 + LOONGARCH_UCONTEXT_SIGCONTEXT_OFFSET
);
141 trad_frame_set_reg_addr (this_cache
, regs
.pc
, sigcontext_base
);
142 for (int i
= 0; i
< 32; i
++)
143 trad_frame_set_reg_addr (this_cache
, regs
.r
+ i
, sigcontext_base
+ 8 + i
* 8);
145 trad_frame_set_id (this_cache
, frame_id_build (frame_sp
, func
));
148 /* li.w a7, __NR_rt_sigreturn */
149 #define LOONGARCH_INST_LIW_A7_RT_SIGRETURN 0x03822c0b
151 #define LOONGARCH_INST_SYSCALL 0x002b0000
153 static const struct tramp_frame loongarch_linux_rt_sigframe
=
158 { LOONGARCH_INST_LIW_A7_RT_SIGRETURN
, ULONGEST_MAX
},
159 { LOONGARCH_INST_SYSCALL
, ULONGEST_MAX
},
160 { TRAMP_SENTINEL_INSN
, ULONGEST_MAX
}
162 loongarch_linux_rt_sigframe_init
,
166 /* Initialize LoongArch Linux ABI info. */
169 loongarch_linux_init_abi (struct gdbarch_info info
, struct gdbarch
*gdbarch
)
171 linux_init_abi (info
, gdbarch
, 0);
173 set_solib_svr4_fetch_link_map_offsets (gdbarch
,
174 info
.bfd_arch_info
->bits_per_address
== 32
175 ? linux_ilp32_fetch_link_map_offsets
176 : linux_lp64_fetch_link_map_offsets
);
178 /* GNU/Linux uses SVR4-style shared libraries. */
179 set_gdbarch_skip_trampoline_code (gdbarch
, find_solib_trampoline_target
);
181 /* GNU/Linux uses the dynamic linker included in the GNU C Library. */
182 set_gdbarch_skip_solib_resolver (gdbarch
, glibc_skip_solib_resolver
);
184 /* Enable TLS support. */
185 set_gdbarch_fetch_tls_load_module_address (gdbarch
, svr4_fetch_objfile_link_map
);
187 /* Prepend tramp frame unwinder for signal. */
188 tramp_frame_prepend_unwinder (gdbarch
, &loongarch_linux_rt_sigframe
);
191 /* Initialize LoongArch Linux target support. */
193 void _initialize_loongarch_linux_tdep ();
195 _initialize_loongarch_linux_tdep ()
197 gdbarch_register_osabi (bfd_arch_loongarch
, bfd_mach_loongarch32
,
198 GDB_OSABI_LINUX
, loongarch_linux_init_abi
);
199 gdbarch_register_osabi (bfd_arch_loongarch
, bfd_mach_loongarch64
,
200 GDB_OSABI_LINUX
, loongarch_linux_init_abi
);