xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/csky-linux-tdep.c (revision f8cf1a9151c7af1cb0bd8b09c13c66bca599c027)
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.  */
44 static 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 
58 static 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 
68 static void
69 csky_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 
89 static void
90 csky_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 
111 static void
112 csky_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 
201 static void
202 csky_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 
280 static const struct regset csky_regset_general =
281 {
282   NULL,
283   csky_supply_gregset,
284   csky_collect_gregset
285 };
286 
287 static 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 
299 static void
300 csky_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 
311 static void
312 csky_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 
344 static struct tramp_frame
345 csky_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 
356 static void
357 csky_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 
389 static struct tramp_frame
390 csky_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 
403 static void
404 csky_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 
430 void _initialize_csky_linux_tdep ();
431 void
432 _initialize_csky_linux_tdep ()
433 {
434   gdbarch_register_osabi (bfd_arch_csky, 0, GDB_OSABI_LINUX,
435 			  csky_linux_init_abi);
436 }
437