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