1/* Target-dependent code for GNU/Linux on CSKY.
2
3   Copyright (C) 2012-2023 Free Software Foundation, Inc.
4
5   Contributed by C-SKY Microsystems and Mentor Graphics.
6
7   This file is part of GDB.
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; either version 3 of the License, or
12   (at your option) any later version.
13
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19   You should have received a copy of the GNU General Public License
20   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
21
22#include "defs.h"
23#include "osabi.h"
24#include "glibc-tdep.h"
25#include "linux-tdep.h"
26#include "gdbarch.h"
27#include "solib-svr4.h"
28#include "regset.h"
29#include "trad-frame.h"
30#include "tramp-frame.h"
31#include "csky-tdep.h"
32
33/* Functions, definitions, and data structures for C-Sky core file debug.  */
34
35/* General regset pc, r1, r0, psr, r2-r31 for CK810.  */
36#define SIZEOF_CSKY_GREGSET 34*4
37/* Float regset fesr fsr fr0-fr31 for CK810.  */
38#define SIZEOF_CSKY_FREGSET 34*4
39/* Float regset vr0~vr15 fr15~fr31, reserved for CK810 when kernel 4.x.  */
40#define SIZEOF_CSKY_FREGSET_K4X  400
41
42/* Offset mapping table from core_section to regcache of general
43   registers for ck810.  */
44static const int csky_gregset_offset[] =
45{
46  72,  1,  0, 89,  2,  /* pc, r1, r0, psr, r2.  */
47   3,  4,  5,  6,  7,  /* r3 ~ r32.  */
48   8,  9, 10, 11, 12,
49  13, 14, 15, 16, 17,
50  18, 19, 20, 21, 22,
51  23, 24, 25, 26, 27,
52  28, 29, 30, 31
53};
54
55/* Offset mapping table from core_section to regcache of float
56   registers for ck810.  */
57
58static const int csky_fregset_offset[] =
59{
60  122, 123, 40, 41, 42,     /* fcr, fesr, fr0 ~ fr2.  */
61   43,  44, 45, 46, 47,     /* fr3 ~ fr15.  */
62   48,  49, 50, 51, 52,
63   53,  54, 55
64};
65
66/* Implement the supply_regset hook for GP registers in core files.  */
67
68static void
69csky_supply_gregset (const struct regset *regset,
70		     struct regcache *regcache, int regnum,
71		     const void *regs, size_t len)
72{
73  int i, gregset_num;
74  const gdb_byte *gregs = (const gdb_byte *) regs ;
75
76  gdb_assert (len >= SIZEOF_CSKY_GREGSET);
77  gregset_num = ARRAY_SIZE (csky_gregset_offset);
78
79  for (i = 0; i < gregset_num; i++)
80    {
81      if ((regnum == csky_gregset_offset[i] || regnum == -1)
82	  && csky_gregset_offset[i] != -1)
83	regcache->raw_supply (csky_gregset_offset[i], gregs + 4 * i);
84    }
85}
86
87/* Implement the collect_regset hook for GP registers in core files.  */
88
89static void
90csky_collect_gregset (const struct regset *regset,
91		      const struct regcache *regcache,
92		      int regnum, void *gregs_buf, size_t len)
93{
94  int regno, gregset_num;
95  gdb_byte *gregs = (gdb_byte *) gregs_buf ;
96
97  gdb_assert (len >= SIZEOF_CSKY_GREGSET);
98  gregset_num = ARRAY_SIZE (csky_gregset_offset);
99
100  for (regno = 0; regno < gregset_num; regno++)
101    {
102      if ((regnum == csky_gregset_offset[regno] || regnum == -1)
103	  && csky_gregset_offset[regno] != -1)
104	regcache->raw_collect (regno,
105			       gregs + 4 + csky_gregset_offset[regno]);
106    }
107}
108
109/* Implement the supply_regset hook for FP registers in core files.  */
110
111static void
112csky_supply_fregset (const struct regset *regset,
113		     struct regcache *regcache, int regnum,
114		     const void *regs, size_t len)
115{
116  int i;
117  int offset = 0;
118  struct gdbarch *gdbarch = regcache->arch ();
119  const gdb_byte *fregs = (const gdb_byte *) regs;
120  int fregset_num = ARRAY_SIZE (csky_fregset_offset);
121
122  gdb_assert (len >= SIZEOF_CSKY_FREGSET);
123  if (len == SIZEOF_CSKY_FREGSET)
124    {
125      for (i = 0; i < fregset_num; i++)
126	{
127	  if ((regnum == csky_fregset_offset[i] || regnum == -1)
128	      && csky_fregset_offset[i] != -1)
129	    {
130	      int num = csky_fregset_offset[i];
131	      offset += register_size (gdbarch, num);
132	      regcache->raw_supply (csky_fregset_offset[i], fregs + offset);
133	    }
134	}
135    }
136  else if (len == SIZEOF_CSKY_FREGSET_K4X)
137    {
138      /* When kernel version >= 4.x, .reg2 size will be 400.
139	 Contents is {
140	  unsigned long vr[96];
141	  unsigned long fcr;
142	  unsigned long fesr;
143	  unsigned long fid;
144	  unsigned long reserved;
145	 }
146	 VR[96] means: (vr0~vr15) + (fr16~fr31), each Vector register is
147	 128-bits, each Float register is 64 bits, the total size is
148	 (4*96).
149
150	 In addition, for fr0~fr15, each FRx is the lower 64 bits of the
151	 corresponding VRx. So fr0~fr15 and vr0~vr15 regisetrs use the same
152	 offset.  */
153      int fcr_regno[] = {122, 123, 121}; /* fcr, fesr, fid.  */
154
155      /* Supply vr0~vr15.  */
156      for (i = 0; i < 16; i ++)
157	{
158	  if (*gdbarch_register_name (gdbarch, (CSKY_VR0_REGNUM + i)) != '\0')
159	    {
160	      offset = 16 * i;
161	      regcache->raw_supply (CSKY_VR0_REGNUM + i, fregs + offset);
162	    }
163	}
164      /* Supply fr0~fr15.  */
165      for (i = 0; i < 16; i ++)
166	{
167	  if (*gdbarch_register_name (gdbarch, (CSKY_FR0_REGNUM + i)) != '\0')
168	    {
169	      offset = 16 * i;
170	      regcache->raw_supply (CSKY_FR0_REGNUM + i, fregs + offset);
171	    }
172	}
173      /* Supply fr16~fr31.  */
174      for (i = 0; i < 16; i ++)
175	{
176	  if (*gdbarch_register_name (gdbarch, (CSKY_FR16_REGNUM + i)) != '\0')
177	    {
178	      offset = (16 * 16) + (8 * i);
179	      regcache->raw_supply (CSKY_FR16_REGNUM + i, fregs + offset);
180	    }
181	}
182     /* Supply fcr, fesr, fid.  */
183      for (i = 0; i < 3; i ++)
184	{
185	  if (*gdbarch_register_name (gdbarch, fcr_regno[i]) != '\0')
186	    {
187	      offset = (16 * 16) + (16 * 8) + (4 * i);
188	      regcache->raw_supply (fcr_regno[i], fregs + offset);
189	    }
190	}
191    }
192  else
193    {
194      warning (_("Unknow size %s of section .reg2, can not get value"
195		 " of float registers."), pulongest (len));
196    }
197}
198
199/* Implement the collect_regset hook for FP registers in core files.  */
200
201static void
202csky_collect_fregset (const struct regset *regset,
203		      const struct regcache *regcache,
204		      int regnum, void *fregs_buf, size_t len)
205{
206  int regno;
207  struct gdbarch *gdbarch = regcache->arch ();
208  gdb_byte *fregs = (gdb_byte *) fregs_buf ;
209  int fregset_num = ARRAY_SIZE (csky_fregset_offset);
210  int offset = 0;
211
212  gdb_assert (len >= SIZEOF_CSKY_FREGSET);
213  if (len == SIZEOF_CSKY_FREGSET)
214    {
215      for (regno = 0; regno < fregset_num; regno++)
216	{
217	  if ((regnum == csky_fregset_offset[regno] || regnum == -1)
218	       && csky_fregset_offset[regno] != -1)
219	    {
220	      offset += register_size (gdbarch, csky_fregset_offset[regno]);
221	      regcache->raw_collect (regno, fregs + offset);
222	    }
223	}
224    }
225  else if (len == SIZEOF_CSKY_FREGSET_K4X)
226    {
227      /* When kernel version >= 4.x, .reg2 size will be 400.
228	 Contents is {
229	   unsigned long vr[96];
230	   unsigned long fcr;
231	   unsigned long fesr;
232	   unsigned long fid;
233	   unsigned long reserved;
234	 }
235	 VR[96] means: (vr0~vr15) + (fr16~fr31), each Vector register is$
236	 128-bits, each Float register is 64 bits, the total size is$
237	 (4*96).$
238
239	 In addition, for fr0~fr15, each FRx is the lower 64 bits of the$
240	 corresponding VRx. So fr0~fr15 and vr0~vr15 regisetrs use the same$
241	 offset.  */
242      int i = 0;
243      int fcr_regno[] = {122, 123, 121}; /* fcr, fesr, fid.  */
244
245      /* Supply vr0~vr15.  */
246      for (i = 0; i < 16; i ++)
247	{
248	  if (*gdbarch_register_name (gdbarch, (CSKY_VR0_REGNUM + i)) != '\0')
249	    {
250	      offset = 16 * i;
251	      regcache ->raw_collect (CSKY_VR0_REGNUM + i, fregs + offset);
252	    }
253	}
254      /* Supply fr16~fr31.  */
255      for (i = 0; i < 16; i ++)
256	{
257	  if (*gdbarch_register_name (gdbarch, (CSKY_FR16_REGNUM + i)) != '\0')
258	    {
259	      offset = (16 * 16) + (8 * i);
260	      regcache ->raw_collect (CSKY_FR16_REGNUM + i, fregs + offset);
261	    }
262	}
263      /* Supply fcr, fesr, fid.  */
264      for (i = 0; i < 3; i ++)
265	{
266	  if (*gdbarch_register_name (gdbarch, fcr_regno[i]) != '\0')
267	    {
268	      offset = (16 * 16) + (16 * 8) + (4 * i);
269	      regcache ->raw_collect (fcr_regno[i], fregs + offset);
270	    }
271	}
272    }
273  else
274    {
275      warning (_("Unknow size %s of section .reg2, will not set value"
276		 " of float registers."), pulongest (len));
277    }
278}
279
280static const struct regset csky_regset_general =
281{
282  NULL,
283  csky_supply_gregset,
284  csky_collect_gregset
285};
286
287static const struct regset csky_regset_float =
288{
289  NULL,
290  csky_supply_fregset,
291  csky_collect_fregset,
292  /* Allow .reg2 to have a different size, and the size of .reg2 should
293     always be bigger than SIZEOF_CSKY_FREGSET.  */
294  1
295};
296
297/* Iterate over core file register note sections.  */
298
299static void
300csky_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
301					 iterate_over_regset_sections_cb *cb,
302					 void *cb_data,
303					 const struct regcache *regcache)
304{
305  cb (".reg", sizeof (csky_gregset_offset), sizeof (csky_gregset_offset),
306      &csky_regset_general, NULL, cb_data);
307  cb (".reg2", sizeof (csky_fregset_offset), sizeof (csky_fregset_offset),
308      &csky_regset_float, NULL, cb_data);
309}
310
311static void
312csky_linux_rt_sigreturn_init (const struct tramp_frame *self,
313			      frame_info_ptr this_frame,
314			      struct trad_frame_cache *this_cache,
315			      CORE_ADDR func)
316{
317  int i;
318  CORE_ADDR sp = get_frame_register_unsigned (this_frame, 14);
319
320  CORE_ADDR base = sp + CSKY_SIGINFO_OFFSET + CSKY_SIGINFO_SIZE
321		   + CSKY_UCONTEXT_SIGCONTEXT
322		   + CSKY_SIGCONTEXT_SC_USP
323		   + CSKY_SIGCONTEXT_SC_A0;
324
325  /* Set addrs of R0 ~ R13.  */
326  for (i = 0; i < 14; i++)
327   trad_frame_set_reg_addr (this_cache, i, base + i * 4);
328
329  /* Set addrs of SP(R14) and R15.  */
330  trad_frame_set_reg_addr (this_cache, 14, base - 4);
331  trad_frame_set_reg_addr (this_cache, 15, base + 4 * 14);
332
333  /* Set addrs of R16 ~ R31.  */
334  for (i = 15; i < 31; i++)
335   trad_frame_set_reg_addr (this_cache, i, base + i * 4);
336
337  /* Set addrs of PSR and PC.  */
338  trad_frame_set_reg_addr (this_cache, 89, base + 4 * 33);
339  trad_frame_set_reg_addr (this_cache, 72, base + 4 * 34);
340
341  trad_frame_set_id (this_cache, frame_id_build (sp, func));
342}
343
344static struct tramp_frame
345csky_linux_rt_sigreturn_tramp_frame = {
346  SIGTRAMP_FRAME,
347  4,
348  {
349    { CSKY_MOVI_R7_173, ULONGEST_MAX },
350    { CSKY_TRAP_0, ULONGEST_MAX },
351    { TRAMP_SENTINEL_INSN }
352  },
353  csky_linux_rt_sigreturn_init
354};
355
356static void
357csky_linux_rt_sigreturn_init_pt_regs (const struct tramp_frame *self,
358				      frame_info_ptr this_frame,
359				      struct trad_frame_cache *this_cache,
360				      CORE_ADDR func)
361{
362  int i;
363  CORE_ADDR sp = get_frame_register_unsigned (this_frame, CSKY_SP_REGNUM);
364
365  CORE_ADDR base = sp + CSKY_SIGINFO_OFFSET + CSKY_SIGINFO_SIZE
366		   + CSKY_UCONTEXT_SIGCONTEXT
367		   + CSKY_SIGCONTEXT_PT_REGS_TLS;
368
369  /* LR */
370  trad_frame_set_reg_addr (this_cache, CSKY_R15_REGNUM, base);
371
372  /* PC */
373  trad_frame_set_reg_addr (this_cache, CSKY_PC_REGNUM, base + 4);
374
375  /* PSR */
376  trad_frame_set_reg_addr (this_cache, CSKY_CR0_REGNUM, base + 8);
377
378  /* SP */
379  trad_frame_set_reg_addr (this_cache, CSKY_SP_REGNUM, base + 12);
380
381  /* Set addrs of R0 ~ R13.  */
382  for (i = 0; i < 14; i++)
383    trad_frame_set_reg_addr (this_cache, i, base + i * 4 + 20);
384
385  trad_frame_set_id (this_cache, frame_id_build (sp, func));
386}
387
388
389static struct tramp_frame
390csky_linux_rt_sigreturn_tramp_frame_kernel_4x = {
391  SIGTRAMP_FRAME,
392  4,
393  {
394    { CSKY_MOVI_R7_139, ULONGEST_MAX },
395    { CSKY_TRAP_0, ULONGEST_MAX },
396    { TRAMP_SENTINEL_INSN }
397  },
398  csky_linux_rt_sigreturn_init_pt_regs
399};
400
401/* Hook function for gdbarch_register_osabi.  */
402
403static void
404csky_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
405{
406  linux_init_abi (info, gdbarch, 0);
407
408  /* Shared library handling.  */
409  set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
410  set_gdbarch_skip_solib_resolver (gdbarch, glibc_skip_solib_resolver);
411  set_solib_svr4_fetch_link_map_offsets (gdbarch,
412					 linux_ilp32_fetch_link_map_offsets);
413
414  /* Enable TLS support.  */
415  set_gdbarch_fetch_tls_load_module_address (gdbarch,
416					     svr4_fetch_objfile_link_map);
417
418  /* Core file support.  */
419  set_gdbarch_iterate_over_regset_sections (
420    gdbarch, csky_linux_iterate_over_regset_sections);
421
422  /* Append tramp frame unwinder for SIGNAL.  */
423
424  tramp_frame_prepend_unwinder (gdbarch,
425				&csky_linux_rt_sigreturn_tramp_frame);
426  tramp_frame_prepend_unwinder (gdbarch,
427				&csky_linux_rt_sigreturn_tramp_frame_kernel_4x);
428}
429
430void _initialize_csky_linux_tdep ();
431void
432_initialize_csky_linux_tdep ()
433{
434  gdbarch_register_osabi (bfd_arch_csky, 0, GDB_OSABI_LINUX,
435			  csky_linux_init_abi);
436}
437