1 /* GNU/Linux/MIPS specific low level interface, for the remote server for GDB.
2 Copyright (C) 2022-2024 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/>. */
20 #include "linux-low.h"
21 #include <sys/ptrace.h>
22 #include "gdb_proc_service.h"
23 #include <asm/ptrace.h>
25 #include "arch/csky.h"
27 /* Linux target op definitions for the CSKY architecture. */
29 class csky_target
: public linux_process_target
33 const regs_info
*get_regs_info () override
;
35 const gdb_byte
*sw_breakpoint_from_kind (int kind
, int *size
) override
;
37 bool supports_z_point_type (char z_type
) override
;
39 bool supports_hardware_single_step () override
;
43 void low_arch_setup () override
;
45 bool low_cannot_fetch_register (int regno
) override
;
47 bool low_cannot_store_register (int regno
) override
;
49 CORE_ADDR
low_get_pc (regcache
*regcache
) override
;
51 void low_set_pc (regcache
*regcache
, CORE_ADDR newpc
) override
;
53 bool low_breakpoint_at (CORE_ADDR pc
) override
;
56 /* The singleton target ops object. */
58 static csky_target the_csky_target
;
60 /* Return the ptrace "address" of register REGNO. */
61 static int csky_regmap
[] = {
62 0*4, 1*4, 2*4, 3*4, 4*4, 5*4, 6*4, 7*4,
63 8*4, 9*4, 10*4, 11*4, 12*4, 13*4, 14*4, 15*4,
64 16*4, 17*4, 18*4, 19*4, 20*4, 21*4, 22*4, 23*4,
65 24*4, 25*4, 26*4, 27*4, 28*4, 29*4, 30*4, 31*4,
66 -1, -1, -1, -1, 34*4, 35*4, -1, -1,
67 40*4, 42*4, 44*4, 46*4, 48*4, 50*4, 52*4, 54*4, /* fr0 ~ fr15, 64bit */
68 56*4, 58*4, 60*4, 62*4, 64*4, 66*4, 68*4, 70*4,
69 72*4, 76*4, 80*4, 84*4, 88*4, 92*4, 96*4,100*4, /* vr0 ~ vr15, 128bit */
70 104*4,108*4,112*4,116*4,120*4,124*4,128*4,132*4,
72 -1, -1, -1, -1, -1, -1, -1, -1,
73 -1, -1, -1, -1, -1, -1, -1, -1,
74 32*4, -1, -1, -1, -1, -1, -1, -1, /* psr */
75 -1, -1, -1, -1, -1, -1, -1, -1,
76 -1, -1, -1, -1, -1, -1, -1, -1,
77 -1, -1, -1, -1, -1, -1, -1, -1,
78 73*4, 72*4, 74*4, -1, -1, -1, 14*4, /* fcr, fid, fesr, usp */
81 /* CSKY software breakpoint instruction code. */
83 /* When the kernel code version is behind v4.x,
84 illegal insn 0x1464 will be a software bkpt trigger.
85 When an illegal insn exception happens, the case
86 that insn at EPC is 0x1464 will be recognized as SIGTRAP. */
87 static unsigned short csky_breakpoint_illegal_2_v2
= 0x1464;
88 static unsigned int csky_breakpoint_illegal_4_v2
= 0x14641464;
91 csky_target::low_cannot_fetch_register (int regno
)
93 if (csky_regmap
[regno
] == -1)
100 csky_target::low_cannot_store_register (int regno
)
102 if (csky_regmap
[regno
] == -1)
108 /* Get the value of pc register. */
111 csky_target::low_get_pc (struct regcache
*regcache
)
114 collect_register_by_name (regcache
, "pc", &pc
);
118 /* Set pc register. */
121 csky_target::low_set_pc (struct regcache
*regcache
, CORE_ADDR pc
)
123 unsigned long new_pc
= pc
;
124 supply_register_by_name (regcache
, "pc", &new_pc
);
129 csky_target::low_arch_setup ()
131 static const char *expedite_regs
[] = { "r14", "pc", NULL
};
132 target_desc_up tdesc
= csky_create_target_description ();
134 if (tdesc
->expedite_regs
.empty ())
136 init_target_desc (tdesc
.get (), expedite_regs
);
137 gdb_assert (!tdesc
->expedite_regs
.empty ());
140 current_process ()->tdesc
= tdesc
.release ();
145 /* Fetch the thread-local storage pointer for libthread_db. */
148 ps_get_thread_area (struct ps_prochandle
*ph
,
149 lwpid_t lwpid
, int idx
, void **base
)
151 struct pt_regs regset
;
152 if (ptrace (PTRACE_GETREGSET
, lwpid
,
153 (PTRACE_TYPE_ARG3
) (long) NT_PRSTATUS
, ®set
) != 0)
156 *base
= (void *) regset
.tls
;
158 /* IDX is the bias from the thread pointer to the beginning of the
159 thread descriptor. It has to be subtracted due to implementation
160 quirks in libthread_db. */
161 *base
= (void *) ((char *)*base
- idx
);
166 /* Gdbserver uses PTRACE_GET/SET_RGESET. */
169 csky_fill_pt_gregset (struct regcache
*regcache
, void *buf
)
172 struct pt_regs
*regset
= (struct pt_regs
*)buf
;
174 collect_register_by_name (regcache
, "r15", ®set
->lr
);
175 collect_register_by_name (regcache
, "pc", ®set
->pc
);
176 collect_register_by_name (regcache
, "psr", ®set
->sr
);
177 collect_register_by_name (regcache
, "r14", ®set
->usp
);
179 collect_register_by_name (regcache
, "r0", ®set
->a0
);
180 collect_register_by_name (regcache
, "r1", ®set
->a1
);
181 collect_register_by_name (regcache
, "r2", ®set
->a2
);
182 collect_register_by_name (regcache
, "r3", ®set
->a3
);
184 base
= find_regno (regcache
->tdesc
, "r4");
186 for (i
= 0; i
< 10; i
++)
187 collect_register (regcache
, base
+ i
, ®set
->regs
[i
]);
189 base
= find_regno (regcache
->tdesc
, "r16");
190 for (i
= 0; i
< 16; i
++)
191 collect_register (regcache
, base
+ i
, ®set
->exregs
[i
]);
193 collect_register_by_name (regcache
, "hi", ®set
->rhi
);
194 collect_register_by_name (regcache
, "lo", ®set
->rlo
);
198 csky_store_pt_gregset (struct regcache
*regcache
, const void *buf
)
201 const struct pt_regs
*regset
= (const struct pt_regs
*) buf
;
203 supply_register_by_name (regcache
, "r15", ®set
->lr
);
204 supply_register_by_name (regcache
, "pc", ®set
->pc
);
205 supply_register_by_name (regcache
, "psr", ®set
->sr
);
206 supply_register_by_name (regcache
, "r14", ®set
->usp
);
208 supply_register_by_name (regcache
, "r0", ®set
->a0
);
209 supply_register_by_name (regcache
, "r1", ®set
->a1
);
210 supply_register_by_name (regcache
, "r2", ®set
->a2
);
211 supply_register_by_name (regcache
, "r3", ®set
->a3
);
213 base
= find_regno (regcache
->tdesc
, "r4");
215 for (i
= 0; i
< 10; i
++)
216 supply_register (regcache
, base
+ i
, ®set
->regs
[i
]);
218 base
= find_regno (regcache
->tdesc
, "r16");
219 for (i
= 0; i
< 16; i
++)
220 supply_register (regcache
, base
+ i
, ®set
->exregs
[i
]);
222 supply_register_by_name (regcache
, "hi", ®set
->rhi
);
223 supply_register_by_name (regcache
, "lo", ®set
->rlo
);
227 csky_fill_pt_vrregset (struct regcache
*regcache
, void *buf
)
230 struct user_fp
*regset
= (struct user_fp
*)buf
;
232 base
= find_regno (regcache
->tdesc
, "vr0");
234 for (i
= 0; i
< 16; i
++)
235 collect_register (regcache
, base
+ i
, ®set
->vr
[i
* 4]);
236 collect_register_by_name (regcache
, "fcr", ®set
->fcr
);
237 collect_register_by_name (regcache
, "fesr", ®set
->fesr
);
238 collect_register_by_name (regcache
, "fid", ®set
->fid
);
243 csky_store_pt_vrregset (struct regcache
*regcache
, const void *buf
)
246 const struct user_fp
*regset
= (const struct user_fp
*)buf
;
248 base
= find_regno (regcache
->tdesc
, "vr0");
250 for (i
= 0; i
< 16; i
++)
251 supply_register (regcache
, base
+ i
, ®set
->vr
[i
* 4]);
253 base
= find_regno (regcache
->tdesc
, "fr0");
255 for (i
= 0; i
< 16; i
++)
256 supply_register (regcache
, base
+ i
, ®set
->vr
[i
* 4]);
257 supply_register_by_name (regcache
, "fcr", ®set
->fcr
);
258 supply_register_by_name (regcache
, "fesr", ®set
->fesr
);
259 supply_register_by_name (regcache
, "fid", ®set
->fid
);
262 struct regset_info csky_regsets
[] = {
263 { PTRACE_GETREGSET
, PTRACE_SETREGSET
, NT_PRSTATUS
, sizeof(struct pt_regs
),
264 GENERAL_REGS
, csky_fill_pt_gregset
, csky_store_pt_gregset
},
266 { PTRACE_GETREGSET
, PTRACE_SETREGSET
, NT_FPREGSET
, sizeof(struct user_fp
),
267 FP_REGS
, csky_fill_pt_vrregset
, csky_store_pt_vrregset
},
272 static struct regsets_info csky_regsets_info
=
274 csky_regsets
, /* Regsets */
276 NULL
, /* Disabled_regsets */
280 static struct regs_info csky_regs_info
=
282 NULL
, /* FIXME: what's this */
283 NULL
, /* PEEKUSER/POKEUSR isn't supported by kernel > 4.x */
289 csky_target::get_regs_info ()
291 return &csky_regs_info
;
294 /* Implementation of linux_target_ops method "sw_breakpoint_from_kind". */
297 csky_target::sw_breakpoint_from_kind (int kind
, int *size
)
302 return (const gdb_byte
*) &csky_breakpoint_illegal_4_v2
;
307 return (const gdb_byte
*) &csky_breakpoint_illegal_2_v2
;
312 csky_target::supports_z_point_type (char z_type
)
314 /* FIXME: hardware breakpoint support ?? */
315 if (z_type
== Z_PACKET_SW_BP
)
322 csky_target::low_breakpoint_at (CORE_ADDR where
)
326 /* Here just read 2 bytes, as csky_breakpoint_illegal_4_v2
327 is double of csky_breakpoint_illegal_2_v2, csky_breakpoint_bkpt_4
328 is double of csky_breakpoint_bkpt_2. Others are 2 bytes bkpt. */
329 read_memory (where
, (unsigned char *) &insn
, 2);
331 if (insn
== csky_breakpoint_illegal_2_v2
)
337 /* Support for hardware single step. */
340 csky_target::supports_hardware_single_step ()
345 /* The linux target ops object. */
347 linux_process_target
*the_linux_target
= &the_csky_target
;
350 initialize_low_arch (void)
352 initialize_regsets_info (&csky_regsets_info
);