Add tests for PR ld/16452 and PR ld/16457
[platform/upstream/binutils.git] / gdb / sparcobsd-tdep.c
1 /* Target-dependent code for OpenBSD/sparc.
2
3    Copyright (C) 2004-2014 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 "floatformat.h"
22 #include "frame.h"
23 #include "frame-unwind.h"
24 #include "gdbcore.h"
25 #include "osabi.h"
26 #include "regcache.h"
27 #include "symtab.h"
28 #include "trad-frame.h"
29
30 #include "obsd-tdep.h"
31 #include "sparc-tdep.h"
32 #include "solib-svr4.h"
33 #include "bsd-uthread.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 *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 \f
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 = get_regcache_arch (regcache);
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 (regcache, 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 (regcache, 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 (regcache, 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 = get_regcache_arch (regcache);
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 (regcache, 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 (regcache, 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 (regcache, SPARC_SP_REGNUM, buf);
229   sp = extract_unsigned_integer (buf, 4, byte_order);
230   sparc_collect_rwindow (regcache, sp, regnum);
231 }
232 \f
233
234 static void
235 sparc32obsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
236 {
237   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
238
239   /* OpenBSD/sparc is very similar to NetBSD/sparc ELF.  */
240   sparc32nbsd_elf_init_abi (info, gdbarch);
241
242   set_gdbarch_skip_solib_resolver (gdbarch, obsd_skip_solib_resolver);
243
244   frame_unwind_append_unwinder (gdbarch, &sparc32obsd_sigtramp_frame_unwind);
245
246   /* OpenBSD provides a user-level threads implementation.  */
247   bsd_uthread_set_supply_uthread (gdbarch, sparc32obsd_supply_uthread);
248   bsd_uthread_set_collect_uthread (gdbarch, sparc32obsd_collect_uthread);
249 }
250
251 \f
252 /* Provide a prototype to silence -Wmissing-prototypes.  */
253 void _initialize_sparc32obsd_tdep (void);
254
255 void
256 _initialize_sparc32obsd_tdep (void)
257 {
258   gdbarch_register_osabi (bfd_arch_sparc, 0, GDB_OSABI_OPENBSD_ELF,
259                           sparc32obsd_init_abi);
260 }