]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/sparc64-linux-tdep.c
* ser-base.c: Include "gdb_string.h".
[thirdparty/binutils-gdb.git] / gdb / sparc64-linux-tdep.c
CommitLineData
386c036b
MK
1/* Target-dependent code for GNU/Linux UltraSPARC.
2
cc9784b6 3 Copyright 2003, 2004 Free Software Foundation, Inc.
386c036b
MK
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"
78a0fd57
DM
23#include "frame.h"
24#include "frame-unwind.h"
386c036b
MK
25#include "gdbarch.h"
26#include "osabi.h"
b2756930 27#include "solib-svr4.h"
78a0fd57
DM
28#include "symtab.h"
29#include "trad-frame.h"
30
31#include "gdb_assert.h"
32#include "gdb_string.h"
386c036b
MK
33
34#include "sparc64-tdep.h"
35
78a0fd57
DM
36/* The instruction sequence for RT signals is
37 mov __NR_rt_sigreturn, %g1 ! hex: 0x82102065
38 ta 0x6d ! hex: 0x91d0206d
39
40 The effect is to call the system call rt_sigreturn.
41 Note that 64-bit binaries only use this RT signal return method. */
42
43#define LINUX64_RT_SIGTRAMP_INSN0 0x82102065
44#define LINUX64_RT_SIGTRAMP_INSN1 0x91d0206d
45
46/* If PC is in a sigtramp routine consisting of the instructions
47 LINUX64_RT_SIGTRAMP_INSN0 and LINUX64_RT_SIGTRAMP_INSN1, return
48 the address of the start of the routine. Otherwise, return 0. */
49
50static CORE_ADDR
51sparc64_linux_sigtramp_start (struct frame_info *next_frame)
52{
53 CORE_ADDR pc = frame_pc_unwind (next_frame);
54 ULONGEST word0, word1;
55 unsigned char buf[8]; /* Two instructions. */
56
57 /* We only recognize a signal trampoline if PC is at the start of
58 one of the instructions. We optimize for finding the PC at the
59 start of the instruction sequence, as will be the case when the
60 trampoline is not the first frame on the stack. We assume that
61 in the case where the PC is not at the start of the instruction
62 sequence, there will be a few trailing readable bytes on the
63 stack. */
64
65 if (!safe_frame_unwind_memory (next_frame, pc, buf, sizeof buf))
66 return 0;
67
68 word0 = extract_unsigned_integer (buf, 4);
69 if (word0 != LINUX64_RT_SIGTRAMP_INSN0)
70 {
71 if (word0 != LINUX64_RT_SIGTRAMP_INSN1)
72 return 0;
73
74 pc -= 4;
75 if (!safe_frame_unwind_memory (next_frame, pc, buf, sizeof buf))
76 return 0;
77
78 word0 = extract_unsigned_integer (buf, 4);
79 }
80
81 word1 = extract_unsigned_integer (buf + 4, 4);
82 if (word0 != LINUX64_RT_SIGTRAMP_INSN0
83 || word1 != LINUX64_RT_SIGTRAMP_INSN1)
84 return 0;
85
86 return pc;
87}
88
89static int
90sparc64_linux_sigtramp_p (struct frame_info *next_frame)
91{
92 CORE_ADDR pc = frame_pc_unwind (next_frame);
93 char *name;
94
95 find_pc_partial_function (pc, &name, NULL, NULL);
96
97 /* If we have NAME, we can optimize the search. The trampolines is
98 named __rt_sigreturn_stub. However, is isn't dynamically exported
99 from the shared C library, so the trampoline may appear to be part
100 of the preceding function. This should always be sigaction,
101 __sigaction, or __libc_sigaction (all aliases to the same function). */
102 if (name == NULL || strstr (name, "sigaction") != NULL)
103 return (sparc64_linux_sigtramp_start (next_frame) != 0);
104
105 return (strcmp ("__rt_sigreturn_stub", name) == 0);
106}
107
108static struct sparc_frame_cache *
109sparc64_linux_sigtramp_frame_cache (struct frame_info *next_frame,
110 void **this_cache)
111{
112 struct sparc_frame_cache *cache;
113 CORE_ADDR sigcontext_addr, addr;
114 int regnum;
115
116 if (*this_cache)
117 return *this_cache;
118
119 cache = sparc_frame_cache (next_frame, this_cache);
120 gdb_assert (cache == *this_cache);
121
122 regnum = SPARC_SP_REGNUM;
123 cache->base = frame_unwind_register_unsigned (next_frame, regnum);
124 if (cache->base & 1)
125 cache->base += BIAS;
126
127 regnum = SPARC_O1_REGNUM;
128 sigcontext_addr = frame_unwind_register_unsigned (next_frame, regnum);
129
130 /* If this is a RT signal trampoline, adjust SIGCONTEXT_ADDR
131 accordingly. */
132 addr = sparc64_linux_sigtramp_start (next_frame);
133 if (addr)
134 sigcontext_addr += 128;
135 else
136 addr = frame_func_unwind (next_frame);
137
138 cache->pc = addr;
139
140 cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
141
142 /* Offsets from <bits/sigcontext.h> */
143
144 /* Since %g0 is always zero, keep the identity encoding. */
145 for (addr = sigcontext_addr + 8, regnum = SPARC_G1_REGNUM;
146 regnum <= SPARC_O7_REGNUM; regnum++, addr += 8)
147 cache->saved_regs[regnum].addr = addr;
148
149 cache->saved_regs[SPARC64_STATE_REGNUM].addr = addr + 0;
150 cache->saved_regs[SPARC64_PC_REGNUM].addr = addr + 8;
151 cache->saved_regs[SPARC64_NPC_REGNUM].addr = addr + 16;
152 cache->saved_regs[SPARC64_Y_REGNUM].addr = addr + 24;
153 cache->saved_regs[SPARC64_FPRS_REGNUM].addr = addr + 28;
154
155 for (regnum = SPARC_L0_REGNUM, addr = cache->base;
156 regnum <= SPARC_I7_REGNUM; regnum++, addr += 8)
157 cache->saved_regs[regnum].addr = addr;
158
159 return cache;
160}
161
162static void
163sparc64_linux_sigtramp_frame_this_id (struct frame_info *next_frame,
164 void **this_cache,
165 struct frame_id *this_id)
166{
167 struct sparc_frame_cache *cache =
168 sparc64_linux_sigtramp_frame_cache (next_frame, this_cache);
169
170 (*this_id) = frame_id_build (cache->base, cache->pc);
171}
172
173static void
174sparc64_linux_sigtramp_frame_prev_register (struct frame_info *next_frame,
175 void **this_cache,
176 int regnum, int *optimizedp,
177 enum lval_type *lvalp,
178 CORE_ADDR *addrp,
179 int *realnump, void *valuep)
180{
181 struct sparc_frame_cache *cache =
182 sparc64_linux_sigtramp_frame_cache (next_frame, this_cache);
183
184 trad_frame_get_prev_register (next_frame, cache->saved_regs, regnum,
185 optimizedp, lvalp, addrp, realnump, valuep);
186}
187
188static const struct frame_unwind sparc64_linux_sigtramp_frame_unwind =
189{
190 SIGTRAMP_FRAME,
191 sparc64_linux_sigtramp_frame_this_id,
192 sparc64_linux_sigtramp_frame_prev_register
193};
194
195static const struct frame_unwind *
196sparc64_linux_sigtramp_frame_sniffer (struct frame_info *next_frame)
197{
198 if (sparc64_linux_sigtramp_p (next_frame))
199 return &sparc64_linux_sigtramp_frame_unwind;
200
201 return NULL;
202}
203\f
386c036b
MK
204static void
205sparc64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
206{
207 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
208
78a0fd57
DM
209 frame_unwind_append_sniffer (gdbarch, sparc64_linux_sigtramp_frame_sniffer);
210
386c036b
MK
211 /* GNU/Linux is very similar to Solaris ... */
212 sparc64_sol2_init_abi (info, gdbarch);
213
214 /* ... but doesn't have kernel-assisted single-stepping support. */
215 set_gdbarch_software_single_step (gdbarch, sparc_software_single_step);
b2756930
KB
216
217 /* Enable TLS support. */
218 set_gdbarch_fetch_tls_load_module_address (gdbarch,
219 svr4_fetch_objfile_link_map);
386c036b
MK
220}
221
222/* Provide a prototype to silence -Wmissing-prototypes. */
223extern void _initialize_sparc64_linux_tdep (void);
224
225void
226_initialize_sparc64_linux_tdep (void)
227{
228 gdbarch_register_osabi (bfd_arch_sparc, bfd_mach_sparc_v9,
229 GDB_OSABI_LINUX, sparc64_linux_init_abi);
230}