1 /* GNU/Linux/LoongArch specific low level interface, for the remote server
3 Copyright (C) 2022-2023 Free Software Foundation, Inc.
5 This file is part of GDB.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
21 #include "linux-low.h"
23 #include "elf/common.h"
24 #include "arch/loongarch.h"
26 /* Linux target ops definitions for the LoongArch architecture. */
28 class loongarch_target
: public linux_process_target
32 const regs_info
*get_regs_info () override
;
34 int breakpoint_kind_from_pc (CORE_ADDR
*pcptr
) override
;
36 const gdb_byte
*sw_breakpoint_from_kind (int kind
, int *size
) override
;
40 void low_arch_setup () override
;
42 bool low_cannot_fetch_register (int regno
) override
;
44 bool low_cannot_store_register (int regno
) override
;
46 bool low_fetch_register (regcache
*regcache
, int regno
) override
;
48 bool low_supports_breakpoints () override
;
50 CORE_ADDR
low_get_pc (regcache
*regcache
) override
;
52 void low_set_pc (regcache
*regcache
, CORE_ADDR newpc
) override
;
54 bool low_breakpoint_at (CORE_ADDR pc
) override
;
57 /* The singleton target ops object. */
59 static loongarch_target the_loongarch_target
;
62 loongarch_target::low_cannot_fetch_register (int regno
)
64 gdb_assert_not_reached ("linux target op low_cannot_fetch_register "
65 "is not implemented by the target");
69 loongarch_target::low_cannot_store_register (int regno
)
71 gdb_assert_not_reached ("linux target op low_cannot_store_register "
72 "is not implemented by the target");
75 /* Implementation of linux target ops method "low_arch_setup". */
78 loongarch_target::low_arch_setup ()
80 static const char *expedite_regs
[] = { "r3", "pc", NULL
};
81 loongarch_gdbarch_features features
;
84 features
.xlen
= sizeof (elf_greg_t
);
85 tdesc
= loongarch_create_target_description (features
);
87 if (tdesc
->expedite_regs
.empty ())
89 init_target_desc (tdesc
.get (), expedite_regs
);
90 gdb_assert (!tdesc
->expedite_regs
.empty ());
92 current_process ()->tdesc
= tdesc
.release ();
95 /* Collect GPRs from REGCACHE into BUF. */
98 loongarch_fill_gregset (struct regcache
*regcache
, void *buf
)
100 elf_gregset_t
*regset
= (elf_gregset_t
*) buf
;
103 for (i
= 1; i
< 32; i
++)
104 collect_register (regcache
, i
, *regset
+ i
);
105 collect_register (regcache
, LOONGARCH_ORIG_A0_REGNUM
, *regset
+ LOONGARCH_ORIG_A0_REGNUM
);
106 collect_register (regcache
, LOONGARCH_PC_REGNUM
, *regset
+ LOONGARCH_PC_REGNUM
);
107 collect_register (regcache
, LOONGARCH_BADV_REGNUM
, *regset
+ LOONGARCH_BADV_REGNUM
);
110 /* Supply GPRs from BUF into REGCACHE. */
113 loongarch_store_gregset (struct regcache
*regcache
, const void *buf
)
115 const elf_gregset_t
*regset
= (const elf_gregset_t
*) buf
;
118 supply_register_zeroed (regcache
, 0);
119 for (i
= 1; i
< 32; i
++)
120 supply_register (regcache
, i
, *regset
+ i
);
121 supply_register (regcache
, LOONGARCH_ORIG_A0_REGNUM
, *regset
+ LOONGARCH_ORIG_A0_REGNUM
);
122 supply_register (regcache
, LOONGARCH_PC_REGNUM
, *regset
+ LOONGARCH_PC_REGNUM
);
123 supply_register (regcache
, LOONGARCH_BADV_REGNUM
, *regset
+ LOONGARCH_BADV_REGNUM
);
126 /* Collect FPRs from REGCACHE into BUF. */
129 loongarch_fill_fpregset (struct regcache
*regcache
, void *buf
)
131 gdb_byte
*regbuf
= nullptr;
132 int fprsize
= register_size (regcache
->tdesc
, LOONGARCH_FIRST_FP_REGNUM
);
133 int fccsize
= register_size (regcache
->tdesc
, LOONGARCH_FIRST_FCC_REGNUM
);
135 for (int i
= 0; i
< LOONGARCH_LINUX_NUM_FPREGSET
; i
++)
137 regbuf
= (gdb_byte
*)buf
+ fprsize
* i
;
138 collect_register (regcache
, LOONGARCH_FIRST_FP_REGNUM
+ i
, regbuf
);
141 for (int i
= 0; i
< LOONGARCH_LINUX_NUM_FCC
; i
++)
143 regbuf
= (gdb_byte
*)buf
+ fprsize
* LOONGARCH_LINUX_NUM_FPREGSET
+
145 collect_register (regcache
, LOONGARCH_FIRST_FCC_REGNUM
+ i
, regbuf
);
148 regbuf
= (gdb_byte
*)buf
+ fprsize
* LOONGARCH_LINUX_NUM_FPREGSET
+
149 fccsize
* LOONGARCH_LINUX_NUM_FCC
;
150 collect_register (regcache
, LOONGARCH_FCSR_REGNUM
, regbuf
);
153 /* Supply FPRs from BUF into REGCACHE. */
156 loongarch_store_fpregset (struct regcache
*regcache
, const void *buf
)
158 const gdb_byte
*regbuf
= nullptr;
159 int fprsize
= register_size (regcache
->tdesc
, LOONGARCH_FIRST_FP_REGNUM
);
160 int fccsize
= register_size (regcache
->tdesc
, LOONGARCH_FIRST_FCC_REGNUM
);
162 for (int i
= 0; i
< LOONGARCH_LINUX_NUM_FPREGSET
; i
++)
164 regbuf
= (const gdb_byte
*)buf
+ fprsize
* i
;
165 supply_register (regcache
, LOONGARCH_FIRST_FP_REGNUM
+ i
, regbuf
);
168 for (int i
= 0; i
< LOONGARCH_LINUX_NUM_FCC
; i
++)
170 regbuf
= (const gdb_byte
*)buf
+ fprsize
* LOONGARCH_LINUX_NUM_FPREGSET
+
172 supply_register (regcache
, LOONGARCH_FIRST_FCC_REGNUM
+ i
, regbuf
);
175 regbuf
= (const gdb_byte
*)buf
+ fprsize
* LOONGARCH_LINUX_NUM_FPREGSET
+
176 fccsize
* LOONGARCH_LINUX_NUM_FCC
;
177 supply_register (regcache
, LOONGARCH_FCSR_REGNUM
, regbuf
);
180 /* LoongArch/Linux regsets. */
181 static struct regset_info loongarch_regsets
[] = {
182 { PTRACE_GETREGSET
, PTRACE_SETREGSET
, NT_PRSTATUS
, sizeof (elf_gregset_t
),
183 GENERAL_REGS
, loongarch_fill_gregset
, loongarch_store_gregset
},
184 { PTRACE_GETREGSET
, PTRACE_SETREGSET
, NT_FPREGSET
, sizeof (elf_fpregset_t
),
185 FP_REGS
, loongarch_fill_fpregset
, loongarch_store_fpregset
},
189 /* LoongArch/Linux regset information. */
190 static struct regsets_info loongarch_regsets_info
=
192 loongarch_regsets
, /* regsets */
194 NULL
, /* disabled_regsets */
197 /* Definition of linux_target_ops data member "regs_info". */
198 static struct regs_info loongarch_regs
=
200 NULL
, /* regset_bitmap */
202 &loongarch_regsets_info
,
205 /* Implementation of linux target ops method "get_regs_info". */
208 loongarch_target::get_regs_info ()
210 return &loongarch_regs
;
213 /* Implementation of linux target ops method "low_fetch_register". */
216 loongarch_target::low_fetch_register (regcache
*regcache
, int regno
)
220 supply_register_zeroed (regcache
, 0);
225 loongarch_target::low_supports_breakpoints ()
230 /* Implementation of linux target ops method "low_get_pc". */
233 loongarch_target::low_get_pc (regcache
*regcache
)
235 if (register_size (regcache
->tdesc
, 0) == 8)
236 return linux_get_pc_64bit (regcache
);
238 return linux_get_pc_32bit (regcache
);
241 /* Implementation of linux target ops method "low_set_pc". */
244 loongarch_target::low_set_pc (regcache
*regcache
, CORE_ADDR newpc
)
246 if (register_size (regcache
->tdesc
, 0) == 8)
247 linux_set_pc_64bit (regcache
, newpc
);
249 linux_set_pc_32bit (regcache
, newpc
);
252 #define loongarch_breakpoint_len 4
254 /* LoongArch BRK software debug mode instruction.
255 This instruction needs to match gdb/loongarch-tdep.c
256 (loongarch_default_breakpoint). */
257 static const gdb_byte loongarch_breakpoint
[] = {0x05, 0x00, 0x2a, 0x00};
259 /* Implementation of target ops method "breakpoint_kind_from_pc". */
262 loongarch_target::breakpoint_kind_from_pc (CORE_ADDR
*pcptr
)
264 return loongarch_breakpoint_len
;
267 /* Implementation of target ops method "sw_breakpoint_from_kind". */
270 loongarch_target::sw_breakpoint_from_kind (int kind
, int *size
)
272 *size
= loongarch_breakpoint_len
;
273 return (const gdb_byte
*) &loongarch_breakpoint
;
276 /* Implementation of linux target ops method "low_breakpoint_at". */
279 loongarch_target::low_breakpoint_at (CORE_ADDR pc
)
281 gdb_byte insn
[loongarch_breakpoint_len
];
283 read_memory (pc
, (unsigned char *) &insn
, loongarch_breakpoint_len
);
284 if (memcmp (insn
, loongarch_breakpoint
, loongarch_breakpoint_len
) == 0)
290 /* The linux target ops object. */
292 linux_process_target
*the_linux_target
= &the_loongarch_target
;
294 /* Initialize the LoongArch/Linux target. */
297 initialize_low_arch ()
299 initialize_regsets_info (&loongarch_regsets_info
);