2004-03-23 Andrew Cagney <cagney@redhat.com>
[external/binutils.git] / gdb / frv-linux-tdep.c
1 /* Target-dependent code for GNU/Linux running on the Fujitsu FR-V,
2    for GDB.
3    Copyright 2004 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 2 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, write to the Free Software
19    Foundation, Inc., 59 Temple Place - Suite 330,
20    Boston, MA 02111-1307, USA.  */
21
22 #include "defs.h"
23 #include "target.h"
24 #include "frame.h"
25 #include "osabi.h"
26 #include "elf-bfd.h"
27 #include "elf/frv.h"
28 #include "frv-tdep.h"
29
30 /* Define the size (in bytes) of an FR-V instruction.  */
31 static const int frv_instr_size = 4;
32
33 enum {
34   NORMAL_SIGTRAMP = 1,
35   RT_SIGTRAMP = 2
36 };
37
38 static int
39 frv_linux_pc_in_sigtramp (CORE_ADDR pc, char *name)
40 {
41   char buf[frv_instr_size];
42   LONGEST instr;
43   int retval = 0;
44
45   if (target_read_memory (pc, buf, sizeof buf) != 0)
46     return 0;
47
48   instr = extract_unsigned_integer (buf, sizeof buf);
49
50   if (instr == 0x8efc0077)      /* setlos #__NR_sigreturn, gr7 */
51     retval = NORMAL_SIGTRAMP;
52   else if (instr -= 0x8efc00ad) /* setlos #__NR_rt_sigreturn, gr7 */
53     retval = RT_SIGTRAMP;
54   else
55     return 0;
56
57   if (target_read_memory (pc + frv_instr_size, buf, sizeof buf) != 0)
58     return 0;
59   instr = extract_unsigned_integer (buf, sizeof buf);
60   if (instr != 0xc0700000)      /* tira gr0, 0 */
61     return 0;
62
63   /* If we get this far, we'll return a non-zero value, either
64      NORMAL_SIGTRAMP (1) or RT_SIGTRAMP (2).  */
65   return retval;
66 }
67
68 /* Given NEXT_FRAME, "callee" frame of the sigtramp frame that we
69    wish to decode, and REGNO, one of the frv register numbers defined
70    in frv-tdep.h, return the address of the saved register (corresponding
71    to REGNO) in the sigtramp frame.  Return -1 if the register is not
72    found in the sigtramp frame.  The magic numbers in the code below
73    were computed by examining the following kernel structs:
74
75    From arch/frvnommu/signal.c:
76
77       struct sigframe
78       {
79               void (*pretcode)(void);
80               int sig;
81               struct sigcontext sc;
82               unsigned long extramask[_NSIG_WORDS-1];
83               uint32_t retcode[2];
84       };
85
86       struct rt_sigframe
87       {
88               void (*pretcode)(void);
89               int sig;
90               struct siginfo *pinfo;
91               void *puc;
92               struct siginfo info;
93               struct ucontext uc;
94               uint32_t retcode[2];
95       };
96
97    From include/asm-frvnommu/ucontext.h:
98
99       struct ucontext {
100               unsigned long             uc_flags;
101               struct ucontext           *uc_link;
102               stack_t                   uc_stack;
103               struct sigcontext uc_mcontext;
104               sigset_t          uc_sigmask;
105       };
106
107    From include/asm-frvnommu/sigcontext.h:
108
109       struct sigcontext {
110               struct user_context       sc_context;
111               unsigned long             sc_oldmask;
112       } __attribute__((aligned(8)));
113
114    From include/asm-frvnommu/registers.h:
115       struct user_int_regs
116       {
117               unsigned long             psr;
118               unsigned long             isr;
119               unsigned long             ccr;
120               unsigned long             cccr;
121               unsigned long             lr;
122               unsigned long             lcr;
123               unsigned long             pc;
124               unsigned long             __status;
125               unsigned long             syscallno;
126               unsigned long             orig_gr8;
127               unsigned long             gner[2];
128               unsigned long long        iacc[1];
129
130               union {
131                       unsigned long     tbr;
132                       unsigned long     gr[64];
133               };
134       };
135
136       struct user_fpmedia_regs
137       {
138               unsigned long     fr[64];
139               unsigned long     fner[2];
140               unsigned long     msr[2];
141               unsigned long     acc[8];
142               unsigned char     accg[8];
143               unsigned long     fsr[1];
144       };
145
146       struct user_context
147       {
148               struct user_int_regs              i;
149               struct user_fpmedia_regs  f;
150
151               void *extension;
152       } __attribute__((aligned(8)));  */
153
154 static CORE_ADDR
155 frv_linux_sigcontext_reg_addr (struct frame_info *next_frame, int regno,
156                                CORE_ADDR *sc_addr_cache_ptr)
157 {
158   CORE_ADDR sc_addr;
159
160   if (sc_addr_cache_ptr && *sc_addr_cache_ptr)
161     {
162       sc_addr = *sc_addr_cache_ptr;
163     }
164   else
165     {
166       CORE_ADDR pc, sp;
167       char buf[4];
168       int tramp_type;
169
170       pc = frame_pc_unwind (next_frame);
171       tramp_type = frv_linux_pc_in_sigtramp (pc, 0);
172
173       frame_unwind_register (next_frame, sp_regnum, buf);
174       sp = extract_unsigned_integer (buf, sizeof buf);
175
176       if (tramp_type == NORMAL_SIGTRAMP)
177         {
178           /* For a normal sigtramp frame, the sigcontext struct starts
179              at SP + 8.  */
180           sc_addr = sp + 8;
181         }
182       else if (tramp_type == RT_SIGTRAMP)
183         {
184           /* For a realtime sigtramp frame, SP + 12 contains a pointer
185              to the a ucontext struct.  The ucontext struct contains
186              a sigcontext struct starting 12 bytes in.  */
187           if (target_read_memory (sp + 12, buf, sizeof buf) != 0)
188             {
189               warning ("Can't read realtime sigtramp frame.");
190               return 0;
191             }
192           sc_addr = extract_unsigned_integer (buf, sizeof buf);
193           sc_addr += 12;
194         }
195       else
196         internal_error (__FILE__, __LINE__, "not a signal trampoline");
197
198       if (sc_addr_cache_ptr)
199         *sc_addr_cache_ptr = sc_addr;
200     }
201
202   switch (regno)
203     {
204     case psr_regnum :
205       return sc_addr + 0;
206     /* sc_addr + 4 has "isr", the Integer Status Register.  */
207     case ccr_regnum :
208       return sc_addr + 8;
209     case cccr_regnum :
210       return sc_addr + 12;
211     case lr_regnum :
212       return sc_addr + 16;
213     case lcr_regnum :
214       return sc_addr + 20;
215     case pc_regnum :
216       return sc_addr + 24;
217     /* sc_addr + 28 is __status, the exception status.
218        sc_addr + 32 is syscallno, the syscall number or -1.
219        sc_addr + 36 is orig_gr8, the original syscall arg #1.
220        sc_addr + 40 is gner[0].
221        sc_addr + 44 is gner[1]. */
222     case iacc0h_regnum :
223       return sc_addr + 48;
224     case iacc0l_regnum :
225       return sc_addr + 52;
226     default : 
227       if (first_gpr_regnum <= regno && regno <= last_gpr_regnum)
228         return sc_addr + 56 + 4 * (regno - first_gpr_regnum);
229       else if (first_fpr_regnum <= regno && regno <= last_fpr_regnum)
230         return sc_addr + 312 + 4 * (regno - first_fpr_regnum);
231       else
232         return -1;  /* not saved. */
233     }
234 }
235
236 static void
237 frv_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
238 {
239   /* When the FR-V Linux kernel calls a signal handler, the return
240      address points to a bit of code on the stack.  This function is
241      used to identify this bit of code as a signal trampoline in order
242      to support backtracing through calls to signal handlers.  */
243   set_gdbarch_deprecated_pc_in_sigtramp (gdbarch, frv_linux_pc_in_sigtramp);
244   frv_set_sigcontext_reg_addr (gdbarch, frv_linux_sigcontext_reg_addr);
245 }
246
247 static enum gdb_osabi
248 frv_linux_elf_osabi_sniffer (bfd *abfd)
249 {
250   int elf_flags;
251
252   elf_flags = elf_elfheader (abfd)->e_flags;
253
254   /* Assume GNU/Linux if using the FDPIC ABI.  If/when another OS shows
255      up that uses this ABI, we'll need to start using .note sections
256      or some such.  */
257   if (elf_flags & EF_FRV_FDPIC)
258     return GDB_OSABI_LINUX;
259   else
260     return GDB_OSABI_UNKNOWN;
261 }
262
263 /* Provide a prototype to silence -Wmissing-prototypes.  */
264 void _initialize_frv_linux_tdep (void);
265
266 void
267 _initialize_frv_linux_tdep (void)
268 {
269   gdbarch_register_osabi (bfd_arch_frv, 0, GDB_OSABI_LINUX, frv_linux_init_abi);
270   gdbarch_register_osabi_sniffer (bfd_arch_frv,
271                                   bfd_target_elf_flavour,
272                                   frv_linux_elf_osabi_sniffer);
273 }