1 /* GNU/Linux/MIPS specific low level interface, for the remote server for GDB.
2 Copyright (C) 2022-2023 Free Software Foundation, Inc.
4 This file is part of GDB.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>. */
21 #include "linux-low.h"
22 #include <sys/ptrace.h>
23 #include "gdb_proc_service.h"
24 #include <asm/ptrace.h>
26 #include "arch/csky.h"
28 /* Linux target op definitions for the CSKY architecture. */
30 class csky_target
: public linux_process_target
34 const regs_info
*get_regs_info () override
;
36 const gdb_byte
*sw_breakpoint_from_kind (int kind
, int *size
) override
;
38 bool supports_z_point_type (char z_type
) override
;
40 bool supports_hardware_single_step () override
;
44 void low_arch_setup () override
;
46 bool low_cannot_fetch_register (int regno
) override
;
48 bool low_cannot_store_register (int regno
) 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 csky_target the_csky_target
;
61 /* Return the ptrace "address" of register REGNO. */
62 static int csky_regmap
[] = {
63 0*4, 1*4, 2*4, 3*4, 4*4, 5*4, 6*4, 7*4,
64 8*4, 9*4, 10*4, 11*4, 12*4, 13*4, 14*4, 15*4,
65 16*4, 17*4, 18*4, 19*4, 20*4, 21*4, 22*4, 23*4,
66 24*4, 25*4, 26*4, 27*4, 28*4, 29*4, 30*4, 31*4,
67 -1, -1, -1, -1, 34*4, 35*4, -1, -1,
68 40*4, 42*4, 44*4, 46*4, 48*4, 50*4, 52*4, 54*4, /* fr0 ~ fr15, 64bit */
69 56*4, 58*4, 60*4, 62*4, 64*4, 66*4, 68*4, 70*4,
70 72*4, 76*4, 80*4, 84*4, 88*4, 92*4, 96*4,100*4, /* vr0 ~ vr15, 128bit */
71 104*4,108*4,112*4,116*4,120*4,124*4,128*4,132*4,
73 -1, -1, -1, -1, -1, -1, -1, -1,
74 -1, -1, -1, -1, -1, -1, -1, -1,
75 32*4, -1, -1, -1, -1, -1, -1, -1, /* psr */
76 -1, -1, -1, -1, -1, -1, -1, -1,
77 -1, -1, -1, -1, -1, -1, -1, -1,
78 -1, -1, -1, -1, -1, -1, -1, -1,
79 73*4, 72*4, 74*4, -1, -1, -1, 14*4, /* fcr, fid, fesr, usp */
82 /* CSKY software breakpoint instruction code. */
84 /* When the kernel code version is behind v4.x,
85 illegal insn 0x1464 will be a software bkpt trigger.
86 When an illegal insn exception happens, the case
87 that insn at EPC is 0x1464 will be recognized as SIGTRAP. */
88 static unsigned short csky_breakpoint_illegal_2_v2
= 0x1464;
89 static unsigned int csky_breakpoint_illegal_4_v2
= 0x14641464;
92 csky_target::low_cannot_fetch_register (int regno
)
94 if (csky_regmap
[regno
] == -1)
101 csky_target::low_cannot_store_register (int regno
)
103 if (csky_regmap
[regno
] == -1)
109 /* Get the value of pc register. */
112 csky_target::low_get_pc (struct regcache
*regcache
)
115 collect_register_by_name (regcache
, "pc", &pc
);
119 /* Set pc register. */
122 csky_target::low_set_pc (struct regcache
*regcache
, CORE_ADDR pc
)
124 unsigned long new_pc
= pc
;
125 supply_register_by_name (regcache
, "pc", &new_pc
);
130 csky_target::low_arch_setup ()
132 static const char *expedite_regs
[] = { "r14", "pc", NULL
};
133 target_desc_up tdesc
= csky_create_target_description ();
135 if (tdesc
->expedite_regs
.empty ())
137 init_target_desc (tdesc
.get (), expedite_regs
);
138 gdb_assert (!tdesc
->expedite_regs
.empty ());
141 current_process ()->tdesc
= tdesc
.release ();
146 /* Fetch the thread-local storage pointer for libthread_db. */
149 ps_get_thread_area (struct ps_prochandle
*ph
,
150 lwpid_t lwpid
, int idx
, void **base
)
152 struct pt_regs regset
;
153 if (ptrace (PTRACE_GETREGSET
, lwpid
,
154 (PTRACE_TYPE_ARG3
) (long) NT_PRSTATUS
, ®set
) != 0)
157 *base
= (void *) regset
.tls
;
159 /* IDX is the bias from the thread pointer to the beginning of the
160 thread descriptor. It has to be subtracted due to implementation
161 quirks in libthread_db. */
162 *base
= (void *) ((char *)*base
- idx
);
167 /* Gdbserver uses PTRACE_GET/SET_RGESET. */
170 csky_fill_pt_gregset (struct regcache
*regcache
, void *buf
)
173 struct pt_regs
*regset
= (struct pt_regs
*)buf
;
175 collect_register_by_name (regcache
, "r15", ®set
->lr
);
176 collect_register_by_name (regcache
, "pc", ®set
->pc
);
177 collect_register_by_name (regcache
, "psr", ®set
->sr
);
178 collect_register_by_name (regcache
, "r14", ®set
->usp
);
180 collect_register_by_name (regcache
, "r0", ®set
->a0
);
181 collect_register_by_name (regcache
, "r1", ®set
->a1
);
182 collect_register_by_name (regcache
, "r2", ®set
->a2
);
183 collect_register_by_name (regcache
, "r3", ®set
->a3
);
185 base
= find_regno (regcache
->tdesc
, "r4");
187 for (i
= 0; i
< 10; i
++)
188 collect_register (regcache
, base
+ i
, ®set
->regs
[i
]);
190 base
= find_regno (regcache
->tdesc
, "r16");
191 for (i
= 0; i
< 16; i
++)
192 collect_register (regcache
, base
+ i
, ®set
->exregs
[i
]);
194 collect_register_by_name (regcache
, "hi", ®set
->rhi
);
195 collect_register_by_name (regcache
, "lo", ®set
->rlo
);
199 csky_store_pt_gregset (struct regcache
*regcache
, const void *buf
)
202 const struct pt_regs
*regset
= (const struct pt_regs
*) buf
;
204 supply_register_by_name (regcache
, "r15", ®set
->lr
);
205 supply_register_by_name (regcache
, "pc", ®set
->pc
);
206 supply_register_by_name (regcache
, "psr", ®set
->sr
);
207 supply_register_by_name (regcache
, "r14", ®set
->usp
);
209 supply_register_by_name (regcache
, "r0", ®set
->a0
);
210 supply_register_by_name (regcache
, "r1", ®set
->a1
);
211 supply_register_by_name (regcache
, "r2", ®set
->a2
);
212 supply_register_by_name (regcache
, "r3", ®set
->a3
);
214 base
= find_regno (regcache
->tdesc
, "r4");
216 for (i
= 0; i
< 10; i
++)
217 supply_register (regcache
, base
+ i
, ®set
->regs
[i
]);
219 base
= find_regno (regcache
->tdesc
, "r16");
220 for (i
= 0; i
< 16; i
++)
221 supply_register (regcache
, base
+ i
, ®set
->exregs
[i
]);
223 supply_register_by_name (regcache
, "hi", ®set
->rhi
);
224 supply_register_by_name (regcache
, "lo", ®set
->rlo
);
228 csky_fill_pt_vrregset (struct regcache
*regcache
, void *buf
)
231 struct user_fp
*regset
= (struct user_fp
*)buf
;
233 base
= find_regno (regcache
->tdesc
, "vr0");
235 for (i
= 0; i
< 16; i
++)
236 collect_register (regcache
, base
+ i
, ®set
->vr
[i
* 4]);
237 collect_register_by_name (regcache
, "fcr", ®set
->fcr
);
238 collect_register_by_name (regcache
, "fesr", ®set
->fesr
);
239 collect_register_by_name (regcache
, "fid", ®set
->fid
);
244 csky_store_pt_vrregset (struct regcache
*regcache
, const void *buf
)
247 const struct user_fp
*regset
= (const struct user_fp
*)buf
;
249 base
= find_regno (regcache
->tdesc
, "vr0");
251 for (i
= 0; i
< 16; i
++)
252 supply_register (regcache
, base
+ i
, ®set
->vr
[i
* 4]);
254 base
= find_regno (regcache
->tdesc
, "fr0");
256 for (i
= 0; i
< 16; i
++)
257 supply_register (regcache
, base
+ i
, ®set
->vr
[i
* 4]);
258 supply_register_by_name (regcache
, "fcr", ®set
->fcr
);
259 supply_register_by_name (regcache
, "fesr", ®set
->fesr
);
260 supply_register_by_name (regcache
, "fid", ®set
->fid
);
263 struct regset_info csky_regsets
[] = {
264 { PTRACE_GETREGSET
, PTRACE_SETREGSET
, NT_PRSTATUS
, sizeof(struct pt_regs
),
265 GENERAL_REGS
, csky_fill_pt_gregset
, csky_store_pt_gregset
},
267 { PTRACE_GETREGSET
, PTRACE_SETREGSET
, NT_FPREGSET
, sizeof(struct user_fp
),
268 FP_REGS
, csky_fill_pt_vrregset
, csky_store_pt_vrregset
},
273 static struct regsets_info csky_regsets_info
=
275 csky_regsets
, /* Regsets */
277 NULL
, /* Disabled_regsets */
281 static struct regs_info csky_regs_info
=
283 NULL
, /* FIXME: what's this */
284 NULL
, /* PEEKUSER/POKEUSR isn't supported by kernel > 4.x */
290 csky_target::get_regs_info ()
292 return &csky_regs_info
;
295 /* Implementation of linux_target_ops method "sw_breakpoint_from_kind". */
298 csky_target::sw_breakpoint_from_kind (int kind
, int *size
)
303 return (const gdb_byte
*) &csky_breakpoint_illegal_4_v2
;
308 return (const gdb_byte
*) &csky_breakpoint_illegal_2_v2
;
313 csky_target::supports_z_point_type (char z_type
)
315 /* FIXME: hardware breakpoint support ?? */
316 if (z_type
== Z_PACKET_SW_BP
)
323 csky_target::low_breakpoint_at (CORE_ADDR where
)
327 /* Here just read 2 bytes, as csky_breakpoint_illegal_4_v2
328 is double of csky_breakpoint_illegal_2_v2, csky_breakpoint_bkpt_4
329 is double of csky_breakpoint_bkpt_2. Others are 2 bytes bkpt. */
330 read_memory (where
, (unsigned char *) &insn
, 2);
332 if (insn
== csky_breakpoint_illegal_2_v2
)
338 /* Support for hardware single step. */
341 csky_target::supports_hardware_single_step ()
346 /* The linux target ops object. */
348 linux_process_target
*the_linux_target
= &the_csky_target
;
351 initialize_low_arch (void)
353 initialize_regsets_info (&csky_regsets_info
);