]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdbserver/linux-loongarch-low.cc
7b81e4b786aebf69a156a5e9453e2d6363023f3a
[thirdparty/binutils-gdb.git] / gdbserver / linux-loongarch-low.cc
1 /* GNU/Linux/LoongArch specific low level interface, for the remote server
2 for GDB.
3 Copyright (C) 2022 Free Software Foundation, Inc.
4
5 This file is part of GDB.
6
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.
11
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.
16
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/>. */
19
20 #include "server.h"
21 #include "linux-low.h"
22 #include "tdesc.h"
23 #include "elf/common.h"
24 #include "arch/loongarch.h"
25
26 /* Linux target ops definitions for the LoongArch architecture. */
27
28 class loongarch_target : public linux_process_target
29 {
30 public:
31
32 const regs_info *get_regs_info () override;
33
34 int breakpoint_kind_from_pc (CORE_ADDR *pcptr) override;
35
36 const gdb_byte *sw_breakpoint_from_kind (int kind, int *size) override;
37
38 protected:
39
40 void low_arch_setup () override;
41
42 bool low_cannot_fetch_register (int regno) override;
43
44 bool low_cannot_store_register (int regno) override;
45
46 bool low_fetch_register (regcache *regcache, int regno) override;
47
48 bool low_supports_breakpoints () override;
49
50 CORE_ADDR low_get_pc (regcache *regcache) override;
51
52 void low_set_pc (regcache *regcache, CORE_ADDR newpc) override;
53
54 bool low_breakpoint_at (CORE_ADDR pc) override;
55 };
56
57 /* The singleton target ops object. */
58
59 static loongarch_target the_loongarch_target;
60
61 bool
62 loongarch_target::low_cannot_fetch_register (int regno)
63 {
64 gdb_assert_not_reached ("linux target op low_cannot_fetch_register "
65 "is not implemented by the target");
66 }
67
68 bool
69 loongarch_target::low_cannot_store_register (int regno)
70 {
71 gdb_assert_not_reached ("linux target op low_cannot_store_register "
72 "is not implemented by the target");
73 }
74
75 /* Implementation of linux target ops method "low_arch_setup". */
76
77 void
78 loongarch_target::low_arch_setup ()
79 {
80 static const char *expedite_regs[] = { "r3", "pc", NULL };
81 loongarch_gdbarch_features features;
82 target_desc_up tdesc;
83
84 features.xlen = sizeof (elf_greg_t);
85 tdesc = loongarch_create_target_description (features);
86
87 if (!tdesc->expedite_regs)
88 init_target_desc (tdesc.get (), expedite_regs);
89 current_process ()->tdesc = tdesc.release ();
90 }
91
92 /* Collect GPRs from REGCACHE into BUF. */
93
94 static void
95 loongarch_fill_gregset (struct regcache *regcache, void *buf)
96 {
97 elf_gregset_t *regset = (elf_gregset_t *) buf;
98 int i;
99
100 for (i = 1; i < 32; i++)
101 collect_register (regcache, i, *regset + i);
102 collect_register (regcache, LOONGARCH_PC_REGNUM, *regset + LOONGARCH_PC_REGNUM);
103 collect_register (regcache, LOONGARCH_BADV_REGNUM, *regset + LOONGARCH_BADV_REGNUM);
104 }
105
106 /* Supply GPRs from BUF into REGCACHE. */
107
108 static void
109 loongarch_store_gregset (struct regcache *regcache, const void *buf)
110 {
111 const elf_gregset_t *regset = (const elf_gregset_t *) buf;
112 int i;
113
114 supply_register_zeroed (regcache, 0);
115 for (i = 1; i < 32; i++)
116 supply_register (regcache, i, *regset + i);
117 supply_register (regcache, LOONGARCH_PC_REGNUM, *regset + LOONGARCH_PC_REGNUM);
118 supply_register (regcache, LOONGARCH_BADV_REGNUM, *regset + LOONGARCH_BADV_REGNUM);
119 }
120
121 /* LoongArch/Linux regsets. */
122 static struct regset_info loongarch_regsets[] = {
123 { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PRSTATUS, sizeof (elf_gregset_t),
124 GENERAL_REGS, loongarch_fill_gregset, loongarch_store_gregset },
125 NULL_REGSET
126 };
127
128 /* LoongArch/Linux regset information. */
129 static struct regsets_info loongarch_regsets_info =
130 {
131 loongarch_regsets, /* regsets */
132 0, /* num_regsets */
133 NULL, /* disabled_regsets */
134 };
135
136 /* Definition of linux_target_ops data member "regs_info". */
137 static struct regs_info loongarch_regs =
138 {
139 NULL, /* regset_bitmap */
140 NULL, /* usrregs */
141 &loongarch_regsets_info,
142 };
143
144 /* Implementation of linux target ops method "get_regs_info". */
145
146 const regs_info *
147 loongarch_target::get_regs_info ()
148 {
149 return &loongarch_regs;
150 }
151
152 /* Implementation of linux target ops method "low_fetch_register". */
153
154 bool
155 loongarch_target::low_fetch_register (regcache *regcache, int regno)
156 {
157 if (regno != 0)
158 return false;
159 supply_register_zeroed (regcache, 0);
160 return true;
161 }
162
163 bool
164 loongarch_target::low_supports_breakpoints ()
165 {
166 return true;
167 }
168
169 /* Implementation of linux target ops method "low_get_pc". */
170
171 CORE_ADDR
172 loongarch_target::low_get_pc (regcache *regcache)
173 {
174 if (register_size (regcache->tdesc, 0) == 8)
175 return linux_get_pc_64bit (regcache);
176 else
177 return linux_get_pc_32bit (regcache);
178 }
179
180 /* Implementation of linux target ops method "low_set_pc". */
181
182 void
183 loongarch_target::low_set_pc (regcache *regcache, CORE_ADDR newpc)
184 {
185 if (register_size (regcache->tdesc, 0) == 8)
186 linux_set_pc_64bit (regcache, newpc);
187 else
188 linux_set_pc_32bit (regcache, newpc);
189 }
190
191 #define loongarch_breakpoint_len 4
192
193 /* LoongArch BRK software debug mode instruction.
194 This instruction needs to match gdb/loongarch-tdep.c
195 (loongarch_default_breakpoint). */
196 static const gdb_byte loongarch_breakpoint[] = {0x05, 0x00, 0x2a, 0x00};
197
198 /* Implementation of target ops method "breakpoint_kind_from_pc". */
199
200 int
201 loongarch_target::breakpoint_kind_from_pc (CORE_ADDR *pcptr)
202 {
203 return loongarch_breakpoint_len;
204 }
205
206 /* Implementation of target ops method "sw_breakpoint_from_kind". */
207
208 const gdb_byte *
209 loongarch_target::sw_breakpoint_from_kind (int kind, int *size)
210 {
211 *size = loongarch_breakpoint_len;
212 return (const gdb_byte *) &loongarch_breakpoint;
213 }
214
215 /* Implementation of linux target ops method "low_breakpoint_at". */
216
217 bool
218 loongarch_target::low_breakpoint_at (CORE_ADDR pc)
219 {
220 gdb_byte insn[loongarch_breakpoint_len];
221
222 read_memory (pc, (unsigned char *) &insn, loongarch_breakpoint_len);
223 if (memcmp (insn, loongarch_breakpoint, loongarch_breakpoint_len) == 0)
224 return true;
225
226 return false;
227 }
228
229 /* The linux target ops object. */
230
231 linux_process_target *the_linux_target = &the_loongarch_target;
232
233 /* Initialize the LoongArch/Linux target. */
234
235 void
236 initialize_low_arch ()
237 {
238 initialize_regsets_info (&loongarch_regsets_info);
239 }