2003-01-08 Andrew Cagney <cagney@redhat.com>
[external/binutils.git] / gdb / alpha-linux-tdep.c
1 /* Target-dependent code for GNU/Linux on Alpha.
2    Copyright 2002, 2003 Free Software Foundation, Inc.
3
4    This file is part of GDB.
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 59 Temple Place - Suite 330,
19    Boston, MA 02111-1307, USA.  */
20
21 #include "defs.h"
22 #include "frame.h"
23 #include "gdbcore.h"
24 #include "value.h"
25 #include "osabi.h"
26
27 #include "alpha-tdep.h"
28
29 /* Under GNU/Linux, signal handler invocations can be identified by the
30    designated code sequence that is used to return from a signal
31    handler.  In particular, the return address of a signal handler
32    points to the following sequence (the first instruction is quadword
33    aligned):
34   
35    bis $30,$30,$16
36    addq $31,0x67,$0
37    call_pal callsys 
38       
39    Each instruction has a unique encoding, so we simply attempt to
40    match the instruction the pc is pointing to with any of the above
41    instructions.  If there is a hit, we know the offset to the start
42    of the designated sequence and can then check whether we really are
43    executing in a designated sequence.  If not, -1 is returned,
44    otherwise the offset from the start of the desingated sequence is
45    returned.
46    
47    There is a slight chance of false hits: code could jump into the
48    middle of the designated sequence, in which case there is no
49    guarantee that we are in the middle of a sigreturn syscall.  Don't
50    think this will be a problem in praxis, though.  */
51 LONGEST
52 alpha_linux_sigtramp_offset (CORE_ADDR pc)
53 {
54   unsigned int i[3], w;
55   long off;
56
57   if (read_memory_nobpt (pc, (char *) &w, 4) != 0)
58     return -1;
59
60   off = -1;
61   switch (w)
62     {
63     case 0x47de0410:
64       off = 0;
65       break;                    /* bis $30,$30,$16 */
66     case 0x43ecf400:
67       off = 4;
68       break;                    /* addq $31,0x67,$0 */
69     case 0x00000083:
70       off = 8;
71       break;                    /* call_pal callsys */
72     default:
73       return -1;
74     }
75   pc -= off;
76   if (pc & 0x7)
77     {
78       /* designated sequence is not quadword aligned */
79       return -1;
80     }
81   if (read_memory_nobpt (pc, (char *) i, sizeof (i)) != 0)
82     return -1;
83
84   if (i[0] == 0x47de0410 && i[1] == 0x43ecf400 && i[2] == 0x00000083)
85     return off;
86
87   return -1;
88 }
89
90 static int
91 alpha_linux_pc_in_sigtramp (CORE_ADDR pc, char *func_name)
92 {
93   return (alpha_linux_sigtramp_offset (pc) >= 0);
94 }
95
96 static CORE_ADDR
97 alpha_linux_sigcontext_addr (struct frame_info *frame)
98 {
99   return (get_frame_base (frame) - 0x298); /* sizeof(struct sigcontext) */
100 }
101
102 static void
103 alpha_linux_init_abi (struct gdbarch_info info,
104                       struct gdbarch *gdbarch)
105 {
106   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
107
108   set_gdbarch_pc_in_sigtramp (gdbarch, alpha_linux_pc_in_sigtramp);
109
110   tdep->dynamic_sigtramp_offset = alpha_linux_sigtramp_offset;
111   tdep->sigcontext_addr = alpha_linux_sigcontext_addr;
112
113   tdep->jb_pc = 2;
114   tdep->jb_elt_size = 8;
115 }
116
117 void
118 _initialize_alpha_linux_tdep (void)
119 {
120   gdbarch_register_osabi (bfd_arch_alpha, 0, GDB_OSABI_LINUX,
121                           alpha_linux_init_abi);
122 }