xref: /openbsd-src/gnu/usr.bin/binutils/gdb/alpha-linux-tdep.c (revision 11efff7f3ac2b3cfeff0c0cddc14294d9b3aca4f)
1b725ae77Skettenis /* Target-dependent code for GNU/Linux on Alpha.
2b725ae77Skettenis    Copyright 2002, 2003 Free Software Foundation, Inc.
3b725ae77Skettenis 
4b725ae77Skettenis    This file is part of GDB.
5b725ae77Skettenis 
6b725ae77Skettenis    This program is free software; you can redistribute it and/or modify
7b725ae77Skettenis    it under the terms of the GNU General Public License as published by
8b725ae77Skettenis    the Free Software Foundation; either version 2 of the License, or
9b725ae77Skettenis    (at your option) any later version.
10b725ae77Skettenis 
11b725ae77Skettenis    This program is distributed in the hope that it will be useful,
12b725ae77Skettenis    but WITHOUT ANY WARRANTY; without even the implied warranty of
13b725ae77Skettenis    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14b725ae77Skettenis    GNU General Public License for more details.
15b725ae77Skettenis 
16b725ae77Skettenis    You should have received a copy of the GNU General Public License
17b725ae77Skettenis    along with this program; if not, write to the Free Software
18b725ae77Skettenis    Foundation, Inc., 59 Temple Place - Suite 330,
19b725ae77Skettenis    Boston, MA 02111-1307, USA.  */
20b725ae77Skettenis 
21b725ae77Skettenis #include "defs.h"
22b725ae77Skettenis #include "frame.h"
23b725ae77Skettenis #include "gdb_assert.h"
24b725ae77Skettenis #include "osabi.h"
25b725ae77Skettenis 
26b725ae77Skettenis #include "alpha-tdep.h"
27b725ae77Skettenis 
28b725ae77Skettenis /* Under GNU/Linux, signal handler invocations can be identified by
29b725ae77Skettenis    the designated code sequence that is used to return from a signal
30b725ae77Skettenis    handler.  In particular, the return address of a signal handler
31b725ae77Skettenis    points to a sequence that copies $sp to $16, loads $0 with the
32b725ae77Skettenis    appropriate syscall number, and finally enters the kernel.
33b725ae77Skettenis 
34b725ae77Skettenis    This is somewhat complicated in that:
35b725ae77Skettenis      (1) the expansion of the "mov" assembler macro has changed over
36b725ae77Skettenis          time, from "bis src,src,dst" to "bis zero,src,dst",
37b725ae77Skettenis      (2) the kernel has changed from using "addq" to "lda" to load the
38b725ae77Skettenis          syscall number,
39b725ae77Skettenis      (3) there is a "normal" sigreturn and an "rt" sigreturn which
40b725ae77Skettenis          has a different stack layout.
41b725ae77Skettenis */
42b725ae77Skettenis 
43b725ae77Skettenis static long
alpha_linux_sigtramp_offset_1(CORE_ADDR pc)44b725ae77Skettenis alpha_linux_sigtramp_offset_1 (CORE_ADDR pc)
45b725ae77Skettenis {
46b725ae77Skettenis   switch (alpha_read_insn (pc))
47b725ae77Skettenis     {
48b725ae77Skettenis     case 0x47de0410:		/* bis $30,$30,$16 */
49b725ae77Skettenis     case 0x47fe0410:		/* bis $31,$30,$16 */
50b725ae77Skettenis       return 0;
51b725ae77Skettenis 
52b725ae77Skettenis     case 0x43ecf400:		/* addq $31,103,$0 */
53b725ae77Skettenis     case 0x201f0067:		/* lda $0,103($31) */
54b725ae77Skettenis     case 0x201f015f:		/* lda $0,351($31) */
55b725ae77Skettenis       return 4;
56b725ae77Skettenis 
57b725ae77Skettenis     case 0x00000083:		/* call_pal callsys */
58b725ae77Skettenis       return 8;
59b725ae77Skettenis 
60b725ae77Skettenis     default:
61b725ae77Skettenis       return -1;
62b725ae77Skettenis     }
63b725ae77Skettenis }
64b725ae77Skettenis 
65b725ae77Skettenis static LONGEST
alpha_linux_sigtramp_offset(CORE_ADDR pc)66b725ae77Skettenis alpha_linux_sigtramp_offset (CORE_ADDR pc)
67b725ae77Skettenis {
68b725ae77Skettenis   long i, off;
69b725ae77Skettenis 
70b725ae77Skettenis   if (pc & 3)
71b725ae77Skettenis     return -1;
72b725ae77Skettenis 
73b725ae77Skettenis   /* Guess where we might be in the sequence.  */
74b725ae77Skettenis   off = alpha_linux_sigtramp_offset_1 (pc);
75b725ae77Skettenis   if (off < 0)
76b725ae77Skettenis     return -1;
77b725ae77Skettenis 
78b725ae77Skettenis   /* Verify that the other two insns of the sequence are as we expect.  */
79b725ae77Skettenis   pc -= off;
80b725ae77Skettenis   for (i = 0; i < 12; i += 4)
81b725ae77Skettenis     {
82b725ae77Skettenis       if (i == off)
83b725ae77Skettenis 	continue;
84b725ae77Skettenis       if (alpha_linux_sigtramp_offset_1 (pc + i) != i)
85b725ae77Skettenis 	return -1;
86b725ae77Skettenis     }
87b725ae77Skettenis 
88b725ae77Skettenis   return off;
89b725ae77Skettenis }
90b725ae77Skettenis 
91b725ae77Skettenis static int
alpha_linux_pc_in_sigtramp(CORE_ADDR pc,char * func_name)92b725ae77Skettenis alpha_linux_pc_in_sigtramp (CORE_ADDR pc, char *func_name)
93b725ae77Skettenis {
94b725ae77Skettenis   return alpha_linux_sigtramp_offset (pc) >= 0;
95b725ae77Skettenis }
96b725ae77Skettenis 
97b725ae77Skettenis static CORE_ADDR
alpha_linux_sigcontext_addr(struct frame_info * next_frame)98b725ae77Skettenis alpha_linux_sigcontext_addr (struct frame_info *next_frame)
99b725ae77Skettenis {
100b725ae77Skettenis   CORE_ADDR pc;
101b725ae77Skettenis   ULONGEST sp;
102b725ae77Skettenis   long off;
103b725ae77Skettenis 
104b725ae77Skettenis   pc = frame_pc_unwind (next_frame);
105b725ae77Skettenis   frame_unwind_unsigned_register (next_frame, ALPHA_SP_REGNUM, &sp);
106b725ae77Skettenis 
107b725ae77Skettenis   off = alpha_linux_sigtramp_offset (pc);
108b725ae77Skettenis   gdb_assert (off >= 0);
109b725ae77Skettenis 
110b725ae77Skettenis   /* __NR_rt_sigreturn has a couple of structures on the stack.  This is:
111b725ae77Skettenis 
112b725ae77Skettenis 	struct rt_sigframe {
113b725ae77Skettenis 	  struct siginfo info;
114b725ae77Skettenis 	  struct ucontext uc;
115b725ae77Skettenis         };
116b725ae77Skettenis 
117b725ae77Skettenis 	offsetof (struct rt_sigframe, uc.uc_mcontext);
118b725ae77Skettenis   */
119b725ae77Skettenis   if (alpha_read_insn (pc - off + 4) == 0x201f015f)
120b725ae77Skettenis     return sp + 176;
121b725ae77Skettenis 
122b725ae77Skettenis   /* __NR_sigreturn has the sigcontext structure at the top of the stack.  */
123b725ae77Skettenis   return sp;
124b725ae77Skettenis }
125b725ae77Skettenis 
126b725ae77Skettenis static void
alpha_linux_init_abi(struct gdbarch_info info,struct gdbarch * gdbarch)127b725ae77Skettenis alpha_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
128b725ae77Skettenis {
129b725ae77Skettenis   struct gdbarch_tdep *tdep;
130b725ae77Skettenis 
131b725ae77Skettenis   /* Hook into the DWARF CFI frame unwinder.  */
132b725ae77Skettenis   alpha_dwarf2_init_abi (info, gdbarch);
133b725ae77Skettenis 
134b725ae77Skettenis   /* Hook into the MDEBUG frame unwinder.  */
135b725ae77Skettenis   alpha_mdebug_init_abi (info, gdbarch);
136b725ae77Skettenis 
137b725ae77Skettenis   tdep = gdbarch_tdep (gdbarch);
138b725ae77Skettenis   tdep->dynamic_sigtramp_offset = alpha_linux_sigtramp_offset;
139b725ae77Skettenis   tdep->sigcontext_addr = alpha_linux_sigcontext_addr;
140*11efff7fSkettenis   tdep->pc_in_sigtramp = alpha_linux_pc_in_sigtramp;
141b725ae77Skettenis   tdep->jb_pc = 2;
142b725ae77Skettenis   tdep->jb_elt_size = 8;
143b725ae77Skettenis }
144b725ae77Skettenis 
145b725ae77Skettenis void
_initialize_alpha_linux_tdep(void)146b725ae77Skettenis _initialize_alpha_linux_tdep (void)
147b725ae77Skettenis {
148b725ae77Skettenis   gdbarch_register_osabi (bfd_arch_alpha, 0, GDB_OSABI_LINUX,
149b725ae77Skettenis                           alpha_linux_init_abi);
150b725ae77Skettenis }
151