xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/ppc-fbsd-tdep.c (revision 6881a4007f077b54e5f51159c52b9b25f57deb0d)
1699b0f92Schristos /* Target-dependent code for PowerPC systems running FreeBSD.
2699b0f92Schristos 
3*6881a400Schristos    Copyright (C) 2013-2023 Free Software Foundation, Inc.
4699b0f92Schristos 
5699b0f92Schristos    This file is part of GDB.
6699b0f92Schristos 
7699b0f92Schristos    This program is free software; you can redistribute it and/or modify
8699b0f92Schristos    it under the terms of the GNU General Public License as published by
9699b0f92Schristos    the Free Software Foundation; either version 3 of the License, or
10699b0f92Schristos    (at your option) any later version.
11699b0f92Schristos 
12699b0f92Schristos    This program is distributed in the hope that it will be useful,
13699b0f92Schristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
14699b0f92Schristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15699b0f92Schristos    GNU General Public License for more details.
16699b0f92Schristos 
17699b0f92Schristos    You should have received a copy of the GNU General Public License
18699b0f92Schristos    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
19699b0f92Schristos 
20699b0f92Schristos #include "defs.h"
21699b0f92Schristos #include "arch-utils.h"
22699b0f92Schristos #include "frame.h"
23699b0f92Schristos #include "gdbcore.h"
24699b0f92Schristos #include "frame-unwind.h"
25699b0f92Schristos #include "gdbtypes.h"
26699b0f92Schristos #include "osabi.h"
27699b0f92Schristos #include "regcache.h"
28699b0f92Schristos #include "regset.h"
29699b0f92Schristos #include "symtab.h"
30699b0f92Schristos #include "target.h"
31699b0f92Schristos #include "trad-frame.h"
32699b0f92Schristos 
33699b0f92Schristos #include "ppc-tdep.h"
34699b0f92Schristos #include "ppc64-tdep.h"
35699b0f92Schristos #include "ppc-fbsd-tdep.h"
36699b0f92Schristos #include "fbsd-tdep.h"
37699b0f92Schristos #include "solib-svr4.h"
387d62b00eSchristos #include "inferior.h"
39699b0f92Schristos 
40699b0f92Schristos 
41699b0f92Schristos /* 32-bit regset descriptions.  */
42699b0f92Schristos 
43699b0f92Schristos static const struct ppc_reg_offsets ppc32_fbsd_reg_offsets =
44699b0f92Schristos   {
45699b0f92Schristos 	/* General-purpose registers.  */
46699b0f92Schristos 	/* .r0_offset = */     0,
47699b0f92Schristos 	/* .gpr_size = */      4,
48699b0f92Schristos 	/* .xr_size = */       4,
49699b0f92Schristos 	/* .pc_offset = */     144,
50699b0f92Schristos 	/* .ps_offset = */     -1,
51699b0f92Schristos 	/* .cr_offset = */     132,
52699b0f92Schristos 	/* .lr_offset = */     128,
53699b0f92Schristos 	/* .ctr_offset = */    140,
54699b0f92Schristos 	/* .xer_offset = */    136,
55699b0f92Schristos 	/* .mq_offset = */     -1,
56699b0f92Schristos 
57699b0f92Schristos 	/* Floating-point registers.  */
58699b0f92Schristos 	/* .f0_offset = */     0,
59699b0f92Schristos 	/* .fpscr_offset = */  256,
607f2ac410Schristos 	/* .fpscr_size = */    8
61699b0f92Schristos   };
62699b0f92Schristos 
63699b0f92Schristos /* 64-bit regset descriptions.  */
64699b0f92Schristos 
65699b0f92Schristos static const struct ppc_reg_offsets ppc64_fbsd_reg_offsets =
66699b0f92Schristos   {
67699b0f92Schristos 	/* General-purpose registers.  */
68699b0f92Schristos 	/* .r0_offset = */     0,
69699b0f92Schristos 	/* .gpr_size = */      8,
70699b0f92Schristos 	/* .xr_size = */       8,
71699b0f92Schristos 	/* .pc_offset = */     288,
72699b0f92Schristos 	/* .ps_offset = */     -1,
73699b0f92Schristos 	/* .cr_offset = */     264,
74699b0f92Schristos 	/* .lr_offset = */     256,
75699b0f92Schristos 	/* .ctr_offset = */    280,
76699b0f92Schristos 	/* .xer_offset = */    272,
77699b0f92Schristos 	/* .mq_offset = */     -1,
78699b0f92Schristos 
79699b0f92Schristos 	/* Floating-point registers.  */
80699b0f92Schristos 	/* .f0_offset = */     0,
81699b0f92Schristos 	/* .fpscr_offset = */  256,
827f2ac410Schristos 	/* .fpscr_size = */    8
83699b0f92Schristos   };
84699b0f92Schristos 
85699b0f92Schristos /* 32-bit general-purpose register set.  */
86699b0f92Schristos 
87699b0f92Schristos static const struct regset ppc32_fbsd_gregset = {
88699b0f92Schristos   &ppc32_fbsd_reg_offsets,
89699b0f92Schristos   ppc_supply_gregset,
90699b0f92Schristos   ppc_collect_gregset
91699b0f92Schristos };
92699b0f92Schristos 
93699b0f92Schristos /* 64-bit general-purpose register set.  */
94699b0f92Schristos 
95699b0f92Schristos static const struct regset ppc64_fbsd_gregset = {
96699b0f92Schristos   &ppc64_fbsd_reg_offsets,
97699b0f92Schristos   ppc_supply_gregset,
98699b0f92Schristos   ppc_collect_gregset
99699b0f92Schristos };
100699b0f92Schristos 
101699b0f92Schristos /* 32-/64-bit floating-point register set.  */
102699b0f92Schristos 
103699b0f92Schristos static const struct regset ppc32_fbsd_fpregset = {
104699b0f92Schristos   &ppc32_fbsd_reg_offsets,
105699b0f92Schristos   ppc_supply_fpregset,
106699b0f92Schristos   ppc_collect_fpregset
107699b0f92Schristos };
108699b0f92Schristos 
109699b0f92Schristos const struct regset *
110699b0f92Schristos ppc_fbsd_gregset (int wordsize)
111699b0f92Schristos {
112699b0f92Schristos   return wordsize == 8 ? &ppc64_fbsd_gregset : &ppc32_fbsd_gregset;
113699b0f92Schristos }
114699b0f92Schristos 
115699b0f92Schristos const struct regset *
116699b0f92Schristos ppc_fbsd_fpregset (void)
117699b0f92Schristos {
118699b0f92Schristos   return &ppc32_fbsd_fpregset;
119699b0f92Schristos }
120699b0f92Schristos 
121699b0f92Schristos /* Iterate over core file register note sections.  */
122699b0f92Schristos 
123699b0f92Schristos static void
124699b0f92Schristos ppcfbsd_iterate_over_regset_sections (struct gdbarch *gdbarch,
125699b0f92Schristos 				      iterate_over_regset_sections_cb *cb,
126699b0f92Schristos 				      void *cb_data,
127699b0f92Schristos 				      const struct regcache *regcache)
128699b0f92Schristos {
129*6881a400Schristos   ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
130699b0f92Schristos 
131699b0f92Schristos   if (tdep->wordsize == 4)
1327f2ac410Schristos     cb (".reg", 148, 148, &ppc32_fbsd_gregset, NULL, cb_data);
133699b0f92Schristos   else
1347f2ac410Schristos     cb (".reg", 296, 296, &ppc64_fbsd_gregset, NULL, cb_data);
1357f2ac410Schristos   cb (".reg2", 264, 264, &ppc32_fbsd_fpregset, NULL, cb_data);
136699b0f92Schristos }
137699b0f92Schristos 
138699b0f92Schristos /* Default page size.  */
139699b0f92Schristos 
140699b0f92Schristos static const int ppcfbsd_page_size = 4096;
141699b0f92Schristos 
142699b0f92Schristos /* Offset for sigreturn(2).  */
143699b0f92Schristos 
144699b0f92Schristos static const int ppcfbsd_sigreturn_offset[] = {
145699b0f92Schristos   0xc,				/* FreeBSD 32-bit  */
146699b0f92Schristos   -1
147699b0f92Schristos };
148699b0f92Schristos 
149699b0f92Schristos /* Signal trampolines.  */
150699b0f92Schristos 
151699b0f92Schristos static int
152699b0f92Schristos ppcfbsd_sigtramp_frame_sniffer (const struct frame_unwind *self,
153*6881a400Schristos 				frame_info_ptr this_frame,
154699b0f92Schristos 				void **this_cache)
155699b0f92Schristos {
156699b0f92Schristos   struct gdbarch *gdbarch = get_frame_arch (this_frame);
157699b0f92Schristos   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
158699b0f92Schristos   CORE_ADDR pc = get_frame_pc (this_frame);
159699b0f92Schristos   CORE_ADDR start_pc = (pc & ~(ppcfbsd_page_size - 1));
160699b0f92Schristos   const int *offset;
161699b0f92Schristos   const char *name;
162699b0f92Schristos 
163699b0f92Schristos   /* A stack trampoline is detected if no name is associated
164699b0f92Schristos    to the current pc and if it points inside a trampoline
165699b0f92Schristos    sequence.  */
166699b0f92Schristos 
167699b0f92Schristos   find_pc_partial_function (pc, &name, NULL, NULL);
168699b0f92Schristos 
169699b0f92Schristos   /* If we have a name, we have no trampoline, return.  */
170699b0f92Schristos   if (name)
171699b0f92Schristos     return 0;
172699b0f92Schristos 
173699b0f92Schristos   for (offset = ppcfbsd_sigreturn_offset; *offset != -1; offset++)
174699b0f92Schristos     {
175699b0f92Schristos       gdb_byte buf[2 * PPC_INSN_SIZE];
176699b0f92Schristos       unsigned long insn;
177699b0f92Schristos 
178699b0f92Schristos       if (!safe_frame_unwind_memory (this_frame, start_pc + *offset,
179*6881a400Schristos 				     {buf, sizeof buf}))
180699b0f92Schristos 	continue;
181699b0f92Schristos 
182699b0f92Schristos       /* Check for "li r0,SYS_sigreturn".  */
183699b0f92Schristos       insn = extract_unsigned_integer (buf, PPC_INSN_SIZE, byte_order);
184699b0f92Schristos       if (insn != 0x380001a1)
185699b0f92Schristos 	continue;
186699b0f92Schristos 
187699b0f92Schristos       /* Check for "sc".  */
188699b0f92Schristos       insn = extract_unsigned_integer (buf + PPC_INSN_SIZE,
189699b0f92Schristos 				       PPC_INSN_SIZE, byte_order);
190699b0f92Schristos       if (insn != 0x44000002)
191699b0f92Schristos 	continue;
192699b0f92Schristos 
193699b0f92Schristos       return 1;
194699b0f92Schristos     }
195699b0f92Schristos 
196699b0f92Schristos   return 0;
197699b0f92Schristos }
198699b0f92Schristos 
199699b0f92Schristos static struct trad_frame_cache *
200*6881a400Schristos ppcfbsd_sigtramp_frame_cache (frame_info_ptr this_frame, void **this_cache)
201699b0f92Schristos {
202699b0f92Schristos   struct gdbarch *gdbarch = get_frame_arch (this_frame);
203*6881a400Schristos   ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
204699b0f92Schristos   struct trad_frame_cache *cache;
205699b0f92Schristos   CORE_ADDR addr, base, func;
206699b0f92Schristos   gdb_byte buf[PPC_INSN_SIZE];
207699b0f92Schristos   int i;
208699b0f92Schristos 
209699b0f92Schristos   if (*this_cache)
210699b0f92Schristos     return (struct trad_frame_cache *) *this_cache;
211699b0f92Schristos 
212699b0f92Schristos   cache = trad_frame_cache_zalloc (this_frame);
213699b0f92Schristos   *this_cache = cache;
214699b0f92Schristos 
215699b0f92Schristos   func = get_frame_pc (this_frame);
216699b0f92Schristos   func &= ~(ppcfbsd_page_size - 1);
217*6881a400Schristos   if (!safe_frame_unwind_memory (this_frame, func, {buf, sizeof buf}))
218699b0f92Schristos     return cache;
219699b0f92Schristos 
220699b0f92Schristos   base = get_frame_register_unsigned (this_frame, gdbarch_sp_regnum (gdbarch));
221699b0f92Schristos   addr = base + 0x10 + 2 * tdep->wordsize;
222699b0f92Schristos   for (i = 0; i < ppc_num_gprs; i++, addr += tdep->wordsize)
223699b0f92Schristos     {
224699b0f92Schristos       int regnum = i + tdep->ppc_gp0_regnum;
225699b0f92Schristos       trad_frame_set_reg_addr (cache, regnum, addr);
226699b0f92Schristos     }
227699b0f92Schristos   trad_frame_set_reg_addr (cache, tdep->ppc_lr_regnum, addr);
228699b0f92Schristos   addr += tdep->wordsize;
229699b0f92Schristos   trad_frame_set_reg_addr (cache, tdep->ppc_cr_regnum, addr);
230699b0f92Schristos   addr += tdep->wordsize;
231699b0f92Schristos   trad_frame_set_reg_addr (cache, tdep->ppc_xer_regnum, addr);
232699b0f92Schristos   addr += tdep->wordsize;
233699b0f92Schristos   trad_frame_set_reg_addr (cache, tdep->ppc_ctr_regnum, addr);
234699b0f92Schristos   addr += tdep->wordsize;
235699b0f92Schristos   trad_frame_set_reg_addr (cache, gdbarch_pc_regnum (gdbarch), addr);
236699b0f92Schristos   /* SRR0?  */
237699b0f92Schristos   addr += tdep->wordsize;
238699b0f92Schristos 
239699b0f92Schristos   /* Construct the frame ID using the function start.  */
240699b0f92Schristos   trad_frame_set_id (cache, frame_id_build (base, func));
241699b0f92Schristos 
242699b0f92Schristos   return cache;
243699b0f92Schristos }
244699b0f92Schristos 
245699b0f92Schristos static void
246*6881a400Schristos ppcfbsd_sigtramp_frame_this_id (frame_info_ptr this_frame,
247699b0f92Schristos 				void **this_cache, struct frame_id *this_id)
248699b0f92Schristos {
249699b0f92Schristos   struct trad_frame_cache *cache =
250699b0f92Schristos     ppcfbsd_sigtramp_frame_cache (this_frame, this_cache);
251699b0f92Schristos 
252699b0f92Schristos   trad_frame_get_id (cache, this_id);
253699b0f92Schristos }
254699b0f92Schristos 
255699b0f92Schristos static struct value *
256*6881a400Schristos ppcfbsd_sigtramp_frame_prev_register (frame_info_ptr this_frame,
257699b0f92Schristos 				      void **this_cache, int regnum)
258699b0f92Schristos {
259699b0f92Schristos   struct trad_frame_cache *cache =
260699b0f92Schristos     ppcfbsd_sigtramp_frame_cache (this_frame, this_cache);
261699b0f92Schristos 
262699b0f92Schristos   return trad_frame_get_register (cache, this_frame, regnum);
263699b0f92Schristos }
264699b0f92Schristos 
265699b0f92Schristos static const struct frame_unwind ppcfbsd_sigtramp_frame_unwind = {
266*6881a400Schristos   "ppc freebsd sigtramp",
267699b0f92Schristos   SIGTRAMP_FRAME,
268699b0f92Schristos   default_frame_unwind_stop_reason,
269699b0f92Schristos   ppcfbsd_sigtramp_frame_this_id,
270699b0f92Schristos   ppcfbsd_sigtramp_frame_prev_register,
271699b0f92Schristos   NULL,
272699b0f92Schristos   ppcfbsd_sigtramp_frame_sniffer
273699b0f92Schristos };
274699b0f92Schristos 
275699b0f92Schristos static enum return_value_convention
276699b0f92Schristos ppcfbsd_return_value (struct gdbarch *gdbarch, struct value *function,
277699b0f92Schristos 		      struct type *valtype, struct regcache *regcache,
278699b0f92Schristos 		      gdb_byte *readbuf, const gdb_byte *writebuf)
279699b0f92Schristos {
280699b0f92Schristos   return ppc_sysv_abi_broken_return_value (gdbarch, function, valtype,
281699b0f92Schristos 					   regcache, readbuf, writebuf);
282699b0f92Schristos }
283699b0f92Schristos 
2847d62b00eSchristos /* Implement the "get_thread_local_address" gdbarch method.  */
2857d62b00eSchristos 
2867d62b00eSchristos static CORE_ADDR
2877d62b00eSchristos ppcfbsd_get_thread_local_address (struct gdbarch *gdbarch, ptid_t ptid,
2887d62b00eSchristos 				  CORE_ADDR lm_addr, CORE_ADDR offset)
2897d62b00eSchristos {
290*6881a400Schristos   ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
2917d62b00eSchristos   struct regcache *regcache;
2927d62b00eSchristos   int tp_offset, tp_regnum;
2937d62b00eSchristos 
2947d62b00eSchristos   regcache = get_thread_arch_regcache (current_inferior ()->process_target (),
2957d62b00eSchristos 				       ptid, gdbarch);
2967d62b00eSchristos 
2977d62b00eSchristos   if (tdep->wordsize == 4)
2987d62b00eSchristos     {
2997d62b00eSchristos       tp_offset = 0x7008;
3007d62b00eSchristos       tp_regnum = PPC_R0_REGNUM + 2;
3017d62b00eSchristos     }
3027d62b00eSchristos   else
3037d62b00eSchristos     {
3047d62b00eSchristos       tp_offset = 0x7010;
3057d62b00eSchristos       tp_regnum = PPC_R0_REGNUM + 13;
3067d62b00eSchristos     }
3077d62b00eSchristos   target_fetch_registers (regcache, tp_regnum);
3087d62b00eSchristos 
3097d62b00eSchristos   ULONGEST tp;
3107d62b00eSchristos   if (regcache->cooked_read (tp_regnum, &tp) != REG_VALID)
3117d62b00eSchristos     error (_("Unable to fetch tcb pointer"));
3127d62b00eSchristos 
3137d62b00eSchristos   /* tp points to the end of the TCB block.  The first member of the
3147d62b00eSchristos      TCB is the pointer to the DTV array.  */
3157d62b00eSchristos   CORE_ADDR dtv_addr = tp - tp_offset;
3167d62b00eSchristos   return fbsd_get_thread_local_address (gdbarch, dtv_addr, lm_addr, offset);
3177d62b00eSchristos }
318699b0f92Schristos 
319699b0f92Schristos static void
320699b0f92Schristos ppcfbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
321699b0f92Schristos {
322*6881a400Schristos   ppc_gdbarch_tdep *tdep = gdbarch_tdep<ppc_gdbarch_tdep> (gdbarch);
323699b0f92Schristos 
324699b0f92Schristos   /* Generic FreeBSD support. */
325699b0f92Schristos   fbsd_init_abi (info, gdbarch);
326699b0f92Schristos 
327699b0f92Schristos   /* FreeBSD doesn't support the 128-bit `long double' from the psABI.  */
328699b0f92Schristos   set_gdbarch_long_double_bit (gdbarch, 64);
329699b0f92Schristos   set_gdbarch_long_double_format (gdbarch, floatformats_ieee_double);
330699b0f92Schristos 
331699b0f92Schristos   if (tdep->wordsize == 4)
332699b0f92Schristos     {
333699b0f92Schristos       set_gdbarch_return_value (gdbarch, ppcfbsd_return_value);
334699b0f92Schristos 
335699b0f92Schristos       set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
336699b0f92Schristos       set_solib_svr4_fetch_link_map_offsets (gdbarch,
337699b0f92Schristos 					     svr4_ilp32_fetch_link_map_offsets);
338699b0f92Schristos 
339699b0f92Schristos       frame_unwind_append_unwinder (gdbarch, &ppcfbsd_sigtramp_frame_unwind);
340699b0f92Schristos       set_gdbarch_gcore_bfd_target (gdbarch, "elf32-powerpc");
341699b0f92Schristos     }
342699b0f92Schristos 
343699b0f92Schristos   if (tdep->wordsize == 8)
344699b0f92Schristos     {
345699b0f92Schristos       set_gdbarch_convert_from_func_ptr_addr
346699b0f92Schristos 	(gdbarch, ppc64_convert_from_func_ptr_addr);
347699b0f92Schristos       set_gdbarch_elf_make_msymbol_special (gdbarch,
348699b0f92Schristos 					    ppc64_elf_make_msymbol_special);
349699b0f92Schristos 
350699b0f92Schristos       set_gdbarch_skip_trampoline_code (gdbarch, ppc64_skip_trampoline_code);
351699b0f92Schristos       set_solib_svr4_fetch_link_map_offsets (gdbarch,
352699b0f92Schristos 					     svr4_lp64_fetch_link_map_offsets);
353699b0f92Schristos       set_gdbarch_gcore_bfd_target (gdbarch, "elf64-powerpc");
354699b0f92Schristos     }
355699b0f92Schristos 
356699b0f92Schristos   set_gdbarch_iterate_over_regset_sections
357699b0f92Schristos     (gdbarch, ppcfbsd_iterate_over_regset_sections);
358699b0f92Schristos 
359699b0f92Schristos   set_gdbarch_fetch_tls_load_module_address (gdbarch,
360699b0f92Schristos 					     svr4_fetch_objfile_link_map);
3617d62b00eSchristos   set_gdbarch_get_thread_local_address (gdbarch,
3627d62b00eSchristos 					ppcfbsd_get_thread_local_address);
363699b0f92Schristos }
364699b0f92Schristos 
3657d62b00eSchristos void _initialize_ppcfbsd_tdep ();
366699b0f92Schristos void
3677d62b00eSchristos _initialize_ppcfbsd_tdep ()
368699b0f92Schristos {
369699b0f92Schristos   gdbarch_register_osabi (bfd_arch_powerpc, bfd_mach_ppc, GDB_OSABI_FREEBSD,
370699b0f92Schristos 			  ppcfbsd_init_abi);
371699b0f92Schristos   gdbarch_register_osabi (bfd_arch_powerpc, bfd_mach_ppc64, GDB_OSABI_FREEBSD,
372699b0f92Schristos 			  ppcfbsd_init_abi);
373699b0f92Schristos   gdbarch_register_osabi (bfd_arch_rs6000, 0, GDB_OSABI_FREEBSD,
374699b0f92Schristos 			  ppcfbsd_init_abi);
375699b0f92Schristos }
376