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
)
136 init_target_desc (tdesc
.get (), expedite_regs
);
138 current_process ()->tdesc
= tdesc
.release ();
143 /* Fetch the thread-local storage pointer for libthread_db. */
146 ps_get_thread_area (struct ps_prochandle
*ph
,
147 lwpid_t lwpid
, int idx
, void **base
)
149 struct pt_regs regset
;
150 if (ptrace (PTRACE_GETREGSET
, lwpid
,
151 (PTRACE_TYPE_ARG3
) (long) NT_PRSTATUS
, ®set
) != 0)
154 *base
= (void *) regset
.tls
;
156 /* IDX is the bias from the thread pointer to the beginning of the
157 thread descriptor. It has to be subtracted due to implementation
158 quirks in libthread_db. */
159 *base
= (void *) ((char *)*base
- idx
);
164 /* Gdbserver uses PTRACE_GET/SET_RGESET. */
167 csky_fill_pt_gregset (struct regcache
*regcache
, void *buf
)
170 struct pt_regs
*regset
= (struct pt_regs
*)buf
;
172 collect_register_by_name (regcache
, "r15", ®set
->lr
);
173 collect_register_by_name (regcache
, "pc", ®set
->pc
);
174 collect_register_by_name (regcache
, "psr", ®set
->sr
);
175 collect_register_by_name (regcache
, "r14", ®set
->usp
);
177 collect_register_by_name (regcache
, "r0", ®set
->a0
);
178 collect_register_by_name (regcache
, "r1", ®set
->a1
);
179 collect_register_by_name (regcache
, "r2", ®set
->a2
);
180 collect_register_by_name (regcache
, "r3", ®set
->a3
);
182 base
= find_regno (regcache
->tdesc
, "r4");
184 for (i
= 0; i
< 10; i
++)
185 collect_register (regcache
, base
+ i
, ®set
->regs
[i
]);
187 base
= find_regno (regcache
->tdesc
, "r16");
188 for (i
= 0; i
< 16; i
++)
189 collect_register (regcache
, base
+ i
, ®set
->exregs
[i
]);
191 collect_register_by_name (regcache
, "hi", ®set
->rhi
);
192 collect_register_by_name (regcache
, "lo", ®set
->rlo
);
196 csky_store_pt_gregset (struct regcache
*regcache
, const void *buf
)
199 const struct pt_regs
*regset
= (const struct pt_regs
*) buf
;
201 supply_register_by_name (regcache
, "r15", ®set
->lr
);
202 supply_register_by_name (regcache
, "pc", ®set
->pc
);
203 supply_register_by_name (regcache
, "psr", ®set
->sr
);
204 supply_register_by_name (regcache
, "r14", ®set
->usp
);
206 supply_register_by_name (regcache
, "r0", ®set
->a0
);
207 supply_register_by_name (regcache
, "r1", ®set
->a1
);
208 supply_register_by_name (regcache
, "r2", ®set
->a2
);
209 supply_register_by_name (regcache
, "r3", ®set
->a3
);
211 base
= find_regno (regcache
->tdesc
, "r4");
213 for (i
= 0; i
< 10; i
++)
214 supply_register (regcache
, base
+ i
, ®set
->regs
[i
]);
216 base
= find_regno (regcache
->tdesc
, "r16");
217 for (i
= 0; i
< 16; i
++)
218 supply_register (regcache
, base
+ i
, ®set
->exregs
[i
]);
220 supply_register_by_name (regcache
, "hi", ®set
->rhi
);
221 supply_register_by_name (regcache
, "lo", ®set
->rlo
);
225 csky_fill_pt_vrregset (struct regcache
*regcache
, void *buf
)
228 struct user_fp
*regset
= (struct user_fp
*)buf
;
230 base
= find_regno (regcache
->tdesc
, "vr0");
232 for (i
= 0; i
< 16; i
++)
233 collect_register (regcache
, base
+ i
, ®set
->vr
[i
* 4]);
234 collect_register_by_name (regcache
, "fcr", ®set
->fcr
);
235 collect_register_by_name (regcache
, "fesr", ®set
->fesr
);
236 collect_register_by_name (regcache
, "fid", ®set
->fid
);
241 csky_store_pt_vrregset (struct regcache
*regcache
, const void *buf
)
244 const struct user_fp
*regset
= (const struct user_fp
*)buf
;
246 base
= find_regno (regcache
->tdesc
, "vr0");
248 for (i
= 0; i
< 16; i
++)
249 supply_register (regcache
, base
+ i
, ®set
->vr
[i
* 4]);
251 base
= find_regno (regcache
->tdesc
, "fr0");
253 for (i
= 0; i
< 16; i
++)
254 supply_register (regcache
, base
+ i
, ®set
->vr
[i
* 4]);
255 supply_register_by_name (regcache
, "fcr", ®set
->fcr
);
256 supply_register_by_name (regcache
, "fesr", ®set
->fesr
);
257 supply_register_by_name (regcache
, "fid", ®set
->fid
);
260 struct regset_info csky_regsets
[] = {
261 { PTRACE_GETREGSET
, PTRACE_SETREGSET
, NT_PRSTATUS
, sizeof(struct pt_regs
),
262 GENERAL_REGS
, csky_fill_pt_gregset
, csky_store_pt_gregset
},
264 { PTRACE_GETREGSET
, PTRACE_SETREGSET
, NT_FPREGSET
, sizeof(struct user_fp
),
265 FP_REGS
, csky_fill_pt_vrregset
, csky_store_pt_vrregset
},
270 static struct regsets_info csky_regsets_info
=
272 csky_regsets
, /* Regsets */
274 NULL
, /* Disabled_regsets */
278 static struct regs_info csky_regs_info
=
280 NULL
, /* FIXME: what's this */
281 NULL
, /* PEEKUSER/PORKUSR isn't supported by kernel > 4.x */
287 csky_target::get_regs_info ()
289 return &csky_regs_info
;
292 /* Implementation of linux_target_ops method "sw_breakpoint_from_kind". */
295 csky_target::sw_breakpoint_from_kind (int kind
, int *size
)
300 return (const gdb_byte
*) &csky_breakpoint_illegal_4_v2
;
305 return (const gdb_byte
*) &csky_breakpoint_illegal_2_v2
;
310 csky_target::supports_z_point_type (char z_type
)
312 /* FIXME: hardware breakpoint support ?? */
313 if (z_type
== Z_PACKET_SW_BP
)
320 csky_target::low_breakpoint_at (CORE_ADDR where
)
324 /* Here just read 2 bytes, as csky_breakpoint_illegal_4_v2
325 is double of csky_breakpoint_illegal_2_v2, csky_breakpoint_bkpt_4
326 is double of csky_breakpoint_bkpt_2. Others are 2 bytes bkpt. */
327 read_memory (where
, (unsigned char *) &insn
, 2);
329 if (insn
== csky_breakpoint_illegal_2_v2
)
335 /* Support for hardware single step. */
338 csky_target::supports_hardware_single_step ()
343 /* The linux target ops object. */
345 linux_process_target
*the_linux_target
= &the_csky_target
;
348 initialize_low_arch (void)
350 initialize_regsets_info (&csky_regsets_info
);