* inferiors.c (find_inferior): Make it safe for the callback
[deliverable/binutils-gdb.git] / gdb / gdbserver / linux-arm-low.c
CommitLineData
0a30fbc4 1/* GNU/Linux/ARM specific low level interface, for the remote server for GDB.
9308fc88 2 Copyright (C) 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
0fb0cc75 3 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
0a30fbc4
DJ
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
a9762ec7 9 the Free Software Foundation; either version 3 of the License, or
0a30fbc4
DJ
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
a9762ec7 18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
0a30fbc4
DJ
19
20#include "server.h"
58caa3dc 21#include "linux-low.h"
0a30fbc4 22
9308fc88
DJ
23#include <sys/ptrace.h>
24
25#include "gdb_proc_service.h"
26
d05b4ac3
UW
27/* Defined in auto-generated file reg-arm.c. */
28void init_registers_arm (void);
29/* Defined in auto-generated file arm-with-iwmmxt.c. */
30void init_registers_arm_with_iwmmxt (void);
31
9308fc88
DJ
32#ifndef PTRACE_GET_THREAD_AREA
33#define PTRACE_GET_THREAD_AREA 22
34#endif
35
fb1e4ffc
DJ
36#ifndef PTRACE_GETWMMXREGS
37# define PTRACE_GETWMMXREGS 18
38# define PTRACE_SETWMMXREGS 19
39#endif
40
0a30fbc4
DJ
41#ifdef HAVE_SYS_REG_H
42#include <sys/reg.h>
43#endif
44
23ce3b1c 45#define arm_num_regs 26
0a30fbc4 46
2ec06d2e 47static int arm_regmap[] = {
0a30fbc4
DJ
48 0, 4, 8, 12, 16, 20, 24, 28,
49 32, 36, 40, 44, 48, 52, 56, 60,
23ce3b1c
DJ
50 -1, -1, -1, -1, -1, -1, -1, -1, -1,
51 64
0a30fbc4
DJ
52};
53
2ec06d2e
DJ
54static int
55arm_cannot_store_register (int regno)
0a30fbc4 56{
2ec06d2e 57 return (regno >= arm_num_regs);
0a30fbc4
DJ
58}
59
2ec06d2e
DJ
60static int
61arm_cannot_fetch_register (int regno)
0a30fbc4 62{
2ec06d2e 63 return (regno >= arm_num_regs);
0a30fbc4
DJ
64}
65
fb1e4ffc
DJ
66static void
67arm_fill_gregset (void *buf)
68{
69 int i;
70
71 for (i = 0; i < arm_num_regs; i++)
72 if (arm_regmap[i] != -1)
73 collect_register (i, ((char *) buf) + arm_regmap[i]);
74}
75
76static void
77arm_store_gregset (const void *buf)
78{
79 int i;
80 char zerobuf[8];
81
82 memset (zerobuf, 0, 8);
83 for (i = 0; i < arm_num_regs; i++)
84 if (arm_regmap[i] != -1)
85 supply_register (i, ((char *) buf) + arm_regmap[i]);
86 else
87 supply_register (i, zerobuf);
88}
89
90#ifdef __IWMMXT__
91
92static void
93arm_fill_wmmxregset (void *buf)
94{
95 int i;
96
97 for (i = 0; i < 16; i++)
98 collect_register (arm_num_regs + i, (char *) buf + i * 8);
99
100 /* We only have access to wcssf, wcasf, and wcgr0-wcgr3. */
101 for (i = 0; i < 6; i++)
102 collect_register (arm_num_regs + i + 16, (char *) buf + 16 * 8 + i * 4);
103}
104
105static void
106arm_store_wmmxregset (const void *buf)
107{
108 int i;
109
110 for (i = 0; i < 16; i++)
111 supply_register (arm_num_regs + i, (char *) buf + i * 8);
112
113 /* We only have access to wcssf, wcasf, and wcgr0-wcgr3. */
114 for (i = 0; i < 6; i++)
115 supply_register (arm_num_regs + i + 16, (char *) buf + 16 * 8 + i * 4);
116}
117
118#endif /* __IWMMXT__ */
119
d677d77d
DJ
120extern int debug_threads;
121
0d62e5e8
DJ
122static CORE_ADDR
123arm_get_pc ()
124{
125 unsigned long pc;
126 collect_register_by_name ("pc", &pc);
d677d77d
DJ
127 if (debug_threads)
128 fprintf (stderr, "stop pc is %08lx\n", pc);
0d62e5e8
DJ
129 return pc;
130}
131
132static void
133arm_set_pc (CORE_ADDR pc)
134{
135 unsigned long newpc = pc;
136 supply_register_by_name ("pc", &newpc);
137}
138
aeb75bf5 139/* Correct in either endianness. */
0d62e5e8
DJ
140static const unsigned long arm_breakpoint = 0xef9f0001;
141#define arm_breakpoint_len 4
aeb75bf5
DJ
142static const unsigned short thumb_breakpoint = 0xde01;
143#define thumb_breakpoint_len 2
0d62e5e8 144
9d1fb177
DJ
145/* For new EABI binaries. We recognize it regardless of which ABI
146 is used for gdbserver, so single threaded debugging should work
147 OK, but for multi-threaded debugging we only insert the current
148 ABI's breakpoint instruction. For now at least. */
149static const unsigned long arm_eabi_breakpoint = 0xe7f001f0;
150
0d62e5e8
DJ
151static int
152arm_breakpoint_at (CORE_ADDR where)
153{
aeb75bf5 154 unsigned long cpsr;
0d62e5e8 155
aeb75bf5 156 collect_register_by_name ("cpsr", &cpsr);
0d62e5e8 157
aeb75bf5
DJ
158 if (cpsr & 0x20)
159 {
160 /* Thumb mode. */
161 unsigned short insn;
9d1fb177 162
aeb75bf5
DJ
163 (*the_target->read_memory) (where, (unsigned char *) &insn, 2);
164 if (insn == thumb_breakpoint)
165 return 1;
166 }
167 else
168 {
169 /* ARM mode. */
170 unsigned long insn;
171
172 (*the_target->read_memory) (where, (unsigned char *) &insn, 4);
173 if (insn == arm_breakpoint)
174 return 1;
175
176 if (insn == arm_eabi_breakpoint)
177 return 1;
178 }
9d1fb177 179
0d62e5e8
DJ
180 return 0;
181}
182
3b2fc2ea
DJ
183/* We only place breakpoints in empty marker functions, and thread locking
184 is outside of the function. So rather than importing software single-step,
185 we can just run until exit. */
186static CORE_ADDR
187arm_reinsert_addr ()
188{
189 unsigned long pc;
190 collect_register_by_name ("lr", &pc);
191 return pc;
192}
193
9308fc88
DJ
194/* Fetch the thread-local storage pointer for libthread_db. */
195
196ps_err_e
197ps_get_thread_area (const struct ps_prochandle *ph,
198 lwpid_t lwpid, int idx, void **base)
199{
200 if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0)
201 return PS_ERR;
202
203 /* IDX is the bias from the thread pointer to the beginning of the
204 thread descriptor. It has to be subtracted due to implementation
205 quirks in libthread_db. */
206 *base = (void *) ((char *)*base - idx);
207
208 return PS_OK;
209}
210
fb1e4ffc
DJ
211struct regset_info target_regsets[] = {
212 { PTRACE_GETREGS, PTRACE_SETREGS, 18 * 4,
213 GENERAL_REGS,
214 arm_fill_gregset, arm_store_gregset },
215#ifdef __IWMMXT__
216 { PTRACE_GETWMMXREGS, PTRACE_SETWMMXREGS, 16 * 8 + 6 * 4,
217 EXTENDED_REGS,
218 arm_fill_wmmxregset, arm_store_wmmxregset },
219#endif
220 { 0, 0, -1, -1, NULL, NULL }
221};
222
2ec06d2e 223struct linux_target_ops the_low_target = {
d05b4ac3
UW
224#ifdef __IWMMXT__
225 init_registers_arm_with_iwmmxt,
226#else
227 init_registers_arm,
228#endif
2ec06d2e
DJ
229 arm_num_regs,
230 arm_regmap,
231 arm_cannot_fetch_register,
232 arm_cannot_store_register,
0d62e5e8
DJ
233 arm_get_pc,
234 arm_set_pc,
aeb75bf5
DJ
235
236 /* Define an ARM-mode breakpoint; we only set breakpoints in the C
237 library, which is most likely to be ARM. If the kernel supports
238 clone events, we will never insert a breakpoint, so even a Thumb
239 C library will work; so will mixing EABI/non-EABI gdbserver and
240 application. */
9d1fb177 241#ifndef __ARM_EABI__
f450004a 242 (const unsigned char *) &arm_breakpoint,
9d1fb177
DJ
243#else
244 (const unsigned char *) &arm_eabi_breakpoint,
245#endif
0d62e5e8 246 arm_breakpoint_len,
3b2fc2ea 247 arm_reinsert_addr,
0d62e5e8
DJ
248 0,
249 arm_breakpoint_at,
2ec06d2e 250};
This page took 0.569008 seconds and 4 git commands to generate.