xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/sparc-obsd-tdep.c (revision d16b7486a53dcb8072b60ec6fcb4373a2d0c27b7)
1 /* Target-dependent code for OpenBSD/sparc.
2 
3    Copyright (C) 2004-2020 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 
29 #include "obsd-tdep.h"
30 #include "sparc-tdep.h"
31 #include "solib-svr4.h"
32 #include "bsd-uthread.h"
33 #include "gdbarch.h"
34 
35 /* Signal trampolines.  */
36 
37 /* The OpenBSD kernel maps the signal trampoline at some random
38    location in user space, which means that the traditional BSD way of
39    detecting it won't work.
40 
41    The signal trampoline will be mapped at an address that is page
42    aligned.  We recognize the signal trampoline by looking for the
43    sigreturn system call.  */
44 
45 static const int sparc32obsd_page_size = 4096;
46 
47 static int
48 sparc32obsd_pc_in_sigtramp (CORE_ADDR pc, const char *name)
49 {
50   CORE_ADDR start_pc = (pc & ~(sparc32obsd_page_size - 1));
51   unsigned long insn;
52 
53   if (name)
54     return 0;
55 
56   /* Check for "restore %g0, SYS_sigreturn, %g1".  */
57   insn = sparc_fetch_instruction (start_pc + 0xec);
58   if (insn != 0x83e82067)
59     return 0;
60 
61   /* Check for "t ST_SYSCALL".  */
62   insn = sparc_fetch_instruction (start_pc + 0xf4);
63   if (insn != 0x91d02000)
64     return 0;
65 
66   return 1;
67 }
68 
69 static struct sparc_frame_cache *
70 sparc32obsd_sigtramp_frame_cache (struct frame_info *this_frame,
71 				  void **this_cache)
72 {
73   struct sparc_frame_cache *cache;
74   CORE_ADDR addr;
75 
76   if (*this_cache)
77     return (struct sparc_frame_cache *) *this_cache;
78 
79   cache = sparc_frame_cache (this_frame, this_cache);
80   gdb_assert (cache == *this_cache);
81 
82   /* If we couldn't find the frame's function, we're probably dealing
83      with an on-stack signal trampoline.  */
84   if (cache->pc == 0)
85     {
86       cache->pc = get_frame_pc (this_frame);
87       cache->pc &= ~(sparc32obsd_page_size - 1);
88 
89       /* Since we couldn't find the frame's function, the cache was
90          initialized under the assumption that we're frameless.  */
91       sparc_record_save_insn (cache);
92       addr = get_frame_register_unsigned (this_frame, SPARC_FP_REGNUM);
93       cache->base = addr;
94     }
95 
96   cache->saved_regs = sparc32nbsd_sigcontext_saved_regs (this_frame);
97 
98   return cache;
99 }
100 
101 static void
102 sparc32obsd_sigtramp_frame_this_id (struct frame_info *this_frame,
103 				    void **this_cache,
104 				    struct frame_id *this_id)
105 {
106   struct sparc_frame_cache *cache =
107     sparc32obsd_sigtramp_frame_cache (this_frame, this_cache);
108 
109   (*this_id) = frame_id_build (cache->base, cache->pc);
110 }
111 
112 static struct value *
113 sparc32obsd_sigtramp_frame_prev_register (struct frame_info *this_frame,
114 					  void **this_cache, int regnum)
115 {
116   struct sparc_frame_cache *cache =
117     sparc32obsd_sigtramp_frame_cache (this_frame, this_cache);
118 
119   return trad_frame_get_prev_register (this_frame, cache->saved_regs, regnum);
120 }
121 
122 static int
123 sparc32obsd_sigtramp_frame_sniffer (const struct frame_unwind *self,
124 				    struct frame_info *this_frame,
125 				    void **this_cache)
126 {
127   CORE_ADDR pc = get_frame_pc (this_frame);
128   const char *name;
129 
130   find_pc_partial_function (pc, &name, NULL, NULL);
131   if (sparc32obsd_pc_in_sigtramp (pc, name))
132     return 1;
133 
134   return 0;
135 }
136 static const struct frame_unwind sparc32obsd_sigtramp_frame_unwind =
137 {
138   SIGTRAMP_FRAME,
139   default_frame_unwind_stop_reason,
140   sparc32obsd_sigtramp_frame_this_id,
141   sparc32obsd_sigtramp_frame_prev_register,
142   NULL,
143   sparc32obsd_sigtramp_frame_sniffer
144 };
145 
146 
147 
148 /* Offset wthin the thread structure where we can find %fp and %i7.  */
149 #define SPARC32OBSD_UTHREAD_FP_OFFSET	128
150 #define SPARC32OBSD_UTHREAD_PC_OFFSET	132
151 
152 static void
153 sparc32obsd_supply_uthread (struct regcache *regcache,
154 			    int regnum, CORE_ADDR addr)
155 {
156   struct gdbarch *gdbarch = regcache->arch ();
157   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
158   CORE_ADDR fp, fp_addr = addr + SPARC32OBSD_UTHREAD_FP_OFFSET;
159   gdb_byte buf[4];
160 
161   gdb_assert (regnum >= -1);
162 
163   fp = read_memory_unsigned_integer (fp_addr, 4, byte_order);
164   if (regnum == SPARC_SP_REGNUM || regnum == -1)
165     {
166       store_unsigned_integer (buf, 4, byte_order, fp);
167       regcache->raw_supply (SPARC_SP_REGNUM, buf);
168 
169       if (regnum == SPARC_SP_REGNUM)
170 	return;
171     }
172 
173   if (regnum == SPARC32_PC_REGNUM || regnum == SPARC32_NPC_REGNUM
174       || regnum == -1)
175     {
176       CORE_ADDR i7, i7_addr = addr + SPARC32OBSD_UTHREAD_PC_OFFSET;
177 
178       i7 = read_memory_unsigned_integer (i7_addr, 4, byte_order);
179       if (regnum == SPARC32_PC_REGNUM || regnum == -1)
180 	{
181 	  store_unsigned_integer (buf, 4, byte_order, i7 + 8);
182 	  regcache->raw_supply (SPARC32_PC_REGNUM, buf);
183 	}
184       if (regnum == SPARC32_NPC_REGNUM || regnum == -1)
185 	{
186 	  store_unsigned_integer (buf, 4, byte_order, i7 + 12);
187 	  regcache->raw_supply (SPARC32_NPC_REGNUM, buf);
188 	}
189 
190       if (regnum == SPARC32_PC_REGNUM || regnum == SPARC32_NPC_REGNUM)
191 	return;
192     }
193 
194   sparc_supply_rwindow (regcache, fp, regnum);
195 }
196 
197 static void
198 sparc32obsd_collect_uthread(const struct regcache *regcache,
199 			    int regnum, CORE_ADDR addr)
200 {
201   struct gdbarch *gdbarch = regcache->arch ();
202   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
203   CORE_ADDR sp;
204   gdb_byte buf[4];
205 
206   gdb_assert (regnum >= -1);
207 
208   if (regnum == SPARC_SP_REGNUM || regnum == -1)
209     {
210       CORE_ADDR fp_addr = addr + SPARC32OBSD_UTHREAD_FP_OFFSET;
211 
212       regcache->raw_collect (SPARC_SP_REGNUM, buf);
213       write_memory (fp_addr,buf, 4);
214     }
215 
216   if (regnum == SPARC32_PC_REGNUM || regnum == -1)
217     {
218       CORE_ADDR i7, i7_addr = addr + SPARC32OBSD_UTHREAD_PC_OFFSET;
219 
220       regcache->raw_collect (SPARC32_PC_REGNUM, buf);
221       i7 = extract_unsigned_integer (buf, 4, byte_order) - 8;
222       write_memory_unsigned_integer (i7_addr, 4, byte_order, i7);
223 
224       if (regnum == SPARC32_PC_REGNUM)
225 	return;
226     }
227 
228   regcache->raw_collect (SPARC_SP_REGNUM, buf);
229   sp = extract_unsigned_integer (buf, 4, byte_order);
230   sparc_collect_rwindow (regcache, sp, regnum);
231 }
232 
233 
234 static void
235 sparc32obsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
236 {
237   /* OpenBSD/sparc is very similar to NetBSD/sparc ELF.  */
238   sparc32nbsd_init_abi (info, gdbarch);
239 
240   set_gdbarch_skip_solib_resolver (gdbarch, obsd_skip_solib_resolver);
241 
242   frame_unwind_append_unwinder (gdbarch, &sparc32obsd_sigtramp_frame_unwind);
243 
244   /* OpenBSD provides a user-level threads implementation.  */
245   bsd_uthread_set_supply_uthread (gdbarch, sparc32obsd_supply_uthread);
246   bsd_uthread_set_collect_uthread (gdbarch, sparc32obsd_collect_uthread);
247 }
248 
249 void _initialize_sparc32obsd_tdep ();
250 void
251 _initialize_sparc32obsd_tdep ()
252 {
253   gdbarch_register_osabi (bfd_arch_sparc, 0, GDB_OSABI_OPENBSD,
254 			  sparc32obsd_init_abi);
255 }
256