xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/sparc-obsd-tdep.c (revision 6881a4007f077b54e5f51159c52b9b25f57deb0d)
1 /* Target-dependent code for OpenBSD/sparc.
2 
3    Copyright (C) 2004-2023 Free Software Foundation, Inc.
4 
5    This file is part of GDB.
6 
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11 
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16 
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
19 
20 #include "defs.h"
21 #include "frame.h"
22 #include "frame-unwind.h"
23 #include "gdbcore.h"
24 #include "osabi.h"
25 #include "regcache.h"
26 #include "symtab.h"
27 #include "trad-frame.h"
28 #include "inferior.h"
29 
30 #include "obsd-tdep.h"
31 #include "sparc-tdep.h"
32 #include "solib-svr4.h"
33 #include "bsd-uthread.h"
34 #include "gdbarch.h"
35 
36 /* Signal trampolines.  */
37 
38 /* The OpenBSD kernel maps the signal trampoline at some random
39    location in user space, which means that the traditional BSD way of
40    detecting it won't work.
41 
42    The signal trampoline will be mapped at an address that is page
43    aligned.  We recognize the signal trampoline by looking for the
44    sigreturn system call.  */
45 
46 static const int sparc32obsd_page_size = 4096;
47 
48 static int
49 sparc32obsd_pc_in_sigtramp (CORE_ADDR pc, const char *name)
50 {
51   CORE_ADDR start_pc = (pc & ~(sparc32obsd_page_size - 1));
52   unsigned long insn;
53 
54   if (name)
55     return 0;
56 
57   /* Check for "restore %g0, SYS_sigreturn, %g1".  */
58   insn = sparc_fetch_instruction (start_pc + 0xec);
59   if (insn != 0x83e82067)
60     return 0;
61 
62   /* Check for "t ST_SYSCALL".  */
63   insn = sparc_fetch_instruction (start_pc + 0xf4);
64   if (insn != 0x91d02000)
65     return 0;
66 
67   return 1;
68 }
69 
70 static struct sparc_frame_cache *
71 sparc32obsd_sigtramp_frame_cache (frame_info_ptr this_frame,
72 				  void **this_cache)
73 {
74   struct sparc_frame_cache *cache;
75   CORE_ADDR addr;
76 
77   if (*this_cache)
78     return (struct sparc_frame_cache *) *this_cache;
79 
80   cache = sparc_frame_cache (this_frame, this_cache);
81   gdb_assert (cache == *this_cache);
82 
83   /* If we couldn't find the frame's function, we're probably dealing
84      with an on-stack signal trampoline.  */
85   if (cache->pc == 0)
86     {
87       cache->pc = get_frame_pc (this_frame);
88       cache->pc &= ~(sparc32obsd_page_size - 1);
89 
90       /* Since we couldn't find the frame's function, the cache was
91 	 initialized under the assumption that we're frameless.  */
92       sparc_record_save_insn (cache);
93       addr = get_frame_register_unsigned (this_frame, SPARC_FP_REGNUM);
94       cache->base = addr;
95     }
96 
97   cache->saved_regs = sparc32nbsd_sigcontext_saved_regs (this_frame);
98 
99   return cache;
100 }
101 
102 static void
103 sparc32obsd_sigtramp_frame_this_id (frame_info_ptr this_frame,
104 				    void **this_cache,
105 				    struct frame_id *this_id)
106 {
107   struct sparc_frame_cache *cache =
108     sparc32obsd_sigtramp_frame_cache (this_frame, this_cache);
109 
110   (*this_id) = frame_id_build (cache->base, cache->pc);
111 }
112 
113 static struct value *
114 sparc32obsd_sigtramp_frame_prev_register (frame_info_ptr this_frame,
115 					  void **this_cache, int regnum)
116 {
117   struct sparc_frame_cache *cache =
118     sparc32obsd_sigtramp_frame_cache (this_frame, this_cache);
119 
120   return trad_frame_get_prev_register (this_frame, cache->saved_regs, regnum);
121 }
122 
123 static int
124 sparc32obsd_sigtramp_frame_sniffer (const struct frame_unwind *self,
125 				    frame_info_ptr this_frame,
126 				    void **this_cache)
127 {
128   CORE_ADDR pc = get_frame_pc (this_frame);
129   const char *name;
130 
131   find_pc_partial_function (pc, &name, NULL, NULL);
132   if (sparc32obsd_pc_in_sigtramp (pc, name))
133     return 1;
134 
135   return 0;
136 }
137 static const struct frame_unwind sparc32obsd_sigtramp_frame_unwind =
138 {
139   "sparc32 openbsd sigtramp",
140   SIGTRAMP_FRAME,
141   default_frame_unwind_stop_reason,
142   sparc32obsd_sigtramp_frame_this_id,
143   sparc32obsd_sigtramp_frame_prev_register,
144   NULL,
145   sparc32obsd_sigtramp_frame_sniffer
146 };
147 
148 
149 
150 /* Offset wthin the thread structure where we can find %fp and %i7.  */
151 #define SPARC32OBSD_UTHREAD_FP_OFFSET	128
152 #define SPARC32OBSD_UTHREAD_PC_OFFSET	132
153 
154 static void
155 sparc32obsd_supply_uthread (struct regcache *regcache,
156 			    int regnum, CORE_ADDR addr)
157 {
158   struct gdbarch *gdbarch = regcache->arch ();
159   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
160   CORE_ADDR fp, fp_addr = addr + SPARC32OBSD_UTHREAD_FP_OFFSET;
161   gdb_byte buf[4];
162 
163   /* This function calls functions that depend on the global current thread.  */
164   gdb_assert (regcache->ptid () == inferior_ptid);
165 
166   gdb_assert (regnum >= -1);
167 
168   fp = read_memory_unsigned_integer (fp_addr, 4, byte_order);
169   if (regnum == SPARC_SP_REGNUM || regnum == -1)
170     {
171       store_unsigned_integer (buf, 4, byte_order, fp);
172       regcache->raw_supply (SPARC_SP_REGNUM, buf);
173 
174       if (regnum == SPARC_SP_REGNUM)
175 	return;
176     }
177 
178   if (regnum == SPARC32_PC_REGNUM || regnum == SPARC32_NPC_REGNUM
179       || regnum == -1)
180     {
181       CORE_ADDR i7, i7_addr = addr + SPARC32OBSD_UTHREAD_PC_OFFSET;
182 
183       i7 = read_memory_unsigned_integer (i7_addr, 4, byte_order);
184       if (regnum == SPARC32_PC_REGNUM || regnum == -1)
185 	{
186 	  store_unsigned_integer (buf, 4, byte_order, i7 + 8);
187 	  regcache->raw_supply (SPARC32_PC_REGNUM, buf);
188 	}
189       if (regnum == SPARC32_NPC_REGNUM || regnum == -1)
190 	{
191 	  store_unsigned_integer (buf, 4, byte_order, i7 + 12);
192 	  regcache->raw_supply (SPARC32_NPC_REGNUM, buf);
193 	}
194 
195       if (regnum == SPARC32_PC_REGNUM || regnum == SPARC32_NPC_REGNUM)
196 	return;
197     }
198 
199   sparc_supply_rwindow (regcache, fp, regnum);
200 }
201 
202 static void
203 sparc32obsd_collect_uthread(const struct regcache *regcache,
204 			    int regnum, CORE_ADDR addr)
205 {
206   struct gdbarch *gdbarch = regcache->arch ();
207   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
208   CORE_ADDR sp;
209   gdb_byte buf[4];
210 
211   /* This function calls functions that depend on the global current thread.  */
212   gdb_assert (regcache->ptid () == inferior_ptid);
213 
214   gdb_assert (regnum >= -1);
215 
216   if (regnum == SPARC_SP_REGNUM || regnum == -1)
217     {
218       CORE_ADDR fp_addr = addr + SPARC32OBSD_UTHREAD_FP_OFFSET;
219 
220       regcache->raw_collect (SPARC_SP_REGNUM, buf);
221       write_memory (fp_addr,buf, 4);
222     }
223 
224   if (regnum == SPARC32_PC_REGNUM || regnum == -1)
225     {
226       CORE_ADDR i7, i7_addr = addr + SPARC32OBSD_UTHREAD_PC_OFFSET;
227 
228       regcache->raw_collect (SPARC32_PC_REGNUM, buf);
229       i7 = extract_unsigned_integer (buf, 4, byte_order) - 8;
230       write_memory_unsigned_integer (i7_addr, 4, byte_order, i7);
231 
232       if (regnum == SPARC32_PC_REGNUM)
233 	return;
234     }
235 
236   regcache->raw_collect (SPARC_SP_REGNUM, buf);
237   sp = extract_unsigned_integer (buf, 4, byte_order);
238   sparc_collect_rwindow (regcache, sp, regnum);
239 }
240 
241 
242 static void
243 sparc32obsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
244 {
245   /* OpenBSD/sparc is very similar to NetBSD/sparc ELF.  */
246   sparc32nbsd_init_abi (info, gdbarch);
247 
248   set_gdbarch_skip_solib_resolver (gdbarch, obsd_skip_solib_resolver);
249 
250   frame_unwind_append_unwinder (gdbarch, &sparc32obsd_sigtramp_frame_unwind);
251 
252   /* OpenBSD provides a user-level threads implementation.  */
253   bsd_uthread_set_supply_uthread (gdbarch, sparc32obsd_supply_uthread);
254   bsd_uthread_set_collect_uthread (gdbarch, sparc32obsd_collect_uthread);
255 }
256 
257 void _initialize_sparc32obsd_tdep ();
258 void
259 _initialize_sparc32obsd_tdep ()
260 {
261   gdbarch_register_osabi (bfd_arch_sparc, 0, GDB_OSABI_OPENBSD,
262 			  sparc32obsd_init_abi);
263 }
264