2008-02-26 Greg Law <glaw@undo-software.com>
[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,
9b254dd1 3 2006, 2007, 2008 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
27#ifndef PTRACE_GET_THREAD_AREA
28#define PTRACE_GET_THREAD_AREA 22
29#endif
30
fb1e4ffc
DJ
31#ifndef PTRACE_GETWMMXREGS
32# define PTRACE_GETWMMXREGS 18
33# define PTRACE_SETWMMXREGS 19
34#endif
35
0a30fbc4
DJ
36#ifdef HAVE_SYS_REG_H
37#include <sys/reg.h>
38#endif
39
23ce3b1c 40#define arm_num_regs 26
0a30fbc4 41
2ec06d2e 42static int arm_regmap[] = {
0a30fbc4
DJ
43 0, 4, 8, 12, 16, 20, 24, 28,
44 32, 36, 40, 44, 48, 52, 56, 60,
23ce3b1c
DJ
45 -1, -1, -1, -1, -1, -1, -1, -1, -1,
46 64
0a30fbc4
DJ
47};
48
2ec06d2e
DJ
49static int
50arm_cannot_store_register (int regno)
0a30fbc4 51{
2ec06d2e 52 return (regno >= arm_num_regs);
0a30fbc4
DJ
53}
54
2ec06d2e
DJ
55static int
56arm_cannot_fetch_register (int regno)
0a30fbc4 57{
2ec06d2e 58 return (regno >= arm_num_regs);
0a30fbc4
DJ
59}
60
fb1e4ffc
DJ
61static void
62arm_fill_gregset (void *buf)
63{
64 int i;
65
66 for (i = 0; i < arm_num_regs; i++)
67 if (arm_regmap[i] != -1)
68 collect_register (i, ((char *) buf) + arm_regmap[i]);
69}
70
71static void
72arm_store_gregset (const void *buf)
73{
74 int i;
75 char zerobuf[8];
76
77 memset (zerobuf, 0, 8);
78 for (i = 0; i < arm_num_regs; i++)
79 if (arm_regmap[i] != -1)
80 supply_register (i, ((char *) buf) + arm_regmap[i]);
81 else
82 supply_register (i, zerobuf);
83}
84
85#ifdef __IWMMXT__
86
87static void
88arm_fill_wmmxregset (void *buf)
89{
90 int i;
91
92 for (i = 0; i < 16; i++)
93 collect_register (arm_num_regs + i, (char *) buf + i * 8);
94
95 /* We only have access to wcssf, wcasf, and wcgr0-wcgr3. */
96 for (i = 0; i < 6; i++)
97 collect_register (arm_num_regs + i + 16, (char *) buf + 16 * 8 + i * 4);
98}
99
100static void
101arm_store_wmmxregset (const void *buf)
102{
103 int i;
104
105 for (i = 0; i < 16; i++)
106 supply_register (arm_num_regs + i, (char *) buf + i * 8);
107
108 /* We only have access to wcssf, wcasf, and wcgr0-wcgr3. */
109 for (i = 0; i < 6; i++)
110 supply_register (arm_num_regs + i + 16, (char *) buf + 16 * 8 + i * 4);
111}
112
113#endif /* __IWMMXT__ */
114
d677d77d
DJ
115extern int debug_threads;
116
0d62e5e8
DJ
117static CORE_ADDR
118arm_get_pc ()
119{
120 unsigned long pc;
121 collect_register_by_name ("pc", &pc);
d677d77d
DJ
122 if (debug_threads)
123 fprintf (stderr, "stop pc is %08lx\n", pc);
0d62e5e8
DJ
124 return pc;
125}
126
127static void
128arm_set_pc (CORE_ADDR pc)
129{
130 unsigned long newpc = pc;
131 supply_register_by_name ("pc", &newpc);
132}
133
134/* Correct in either endianness. We do not support Thumb yet. */
135static const unsigned long arm_breakpoint = 0xef9f0001;
136#define arm_breakpoint_len 4
137
9d1fb177
DJ
138/* For new EABI binaries. We recognize it regardless of which ABI
139 is used for gdbserver, so single threaded debugging should work
140 OK, but for multi-threaded debugging we only insert the current
141 ABI's breakpoint instruction. For now at least. */
142static const unsigned long arm_eabi_breakpoint = 0xe7f001f0;
143
0d62e5e8
DJ
144static int
145arm_breakpoint_at (CORE_ADDR where)
146{
147 unsigned long insn;
148
f450004a 149 (*the_target->read_memory) (where, (unsigned char *) &insn, 4);
0d62e5e8
DJ
150 if (insn == arm_breakpoint)
151 return 1;
152
9d1fb177
DJ
153 if (insn == arm_eabi_breakpoint)
154 return 1;
155
0d62e5e8 156 /* If necessary, recognize more trap instructions here. GDB only uses the
9d1fb177
DJ
157 two. */
158
0d62e5e8
DJ
159 return 0;
160}
161
3b2fc2ea
DJ
162/* We only place breakpoints in empty marker functions, and thread locking
163 is outside of the function. So rather than importing software single-step,
164 we can just run until exit. */
165static CORE_ADDR
166arm_reinsert_addr ()
167{
168 unsigned long pc;
169 collect_register_by_name ("lr", &pc);
170 return pc;
171}
172
9308fc88
DJ
173/* Fetch the thread-local storage pointer for libthread_db. */
174
175ps_err_e
176ps_get_thread_area (const struct ps_prochandle *ph,
177 lwpid_t lwpid, int idx, void **base)
178{
179 if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0)
180 return PS_ERR;
181
182 /* IDX is the bias from the thread pointer to the beginning of the
183 thread descriptor. It has to be subtracted due to implementation
184 quirks in libthread_db. */
185 *base = (void *) ((char *)*base - idx);
186
187 return PS_OK;
188}
189
fb1e4ffc
DJ
190struct regset_info target_regsets[] = {
191 { PTRACE_GETREGS, PTRACE_SETREGS, 18 * 4,
192 GENERAL_REGS,
193 arm_fill_gregset, arm_store_gregset },
194#ifdef __IWMMXT__
195 { PTRACE_GETWMMXREGS, PTRACE_SETWMMXREGS, 16 * 8 + 6 * 4,
196 EXTENDED_REGS,
197 arm_fill_wmmxregset, arm_store_wmmxregset },
198#endif
199 { 0, 0, -1, -1, NULL, NULL }
200};
201
2ec06d2e
DJ
202struct linux_target_ops the_low_target = {
203 arm_num_regs,
204 arm_regmap,
205 arm_cannot_fetch_register,
206 arm_cannot_store_register,
0d62e5e8
DJ
207 arm_get_pc,
208 arm_set_pc,
9d1fb177 209#ifndef __ARM_EABI__
f450004a 210 (const unsigned char *) &arm_breakpoint,
9d1fb177
DJ
211#else
212 (const unsigned char *) &arm_eabi_breakpoint,
213#endif
0d62e5e8 214 arm_breakpoint_len,
3b2fc2ea 215 arm_reinsert_addr,
0d62e5e8
DJ
216 0,
217 arm_breakpoint_at,
2ec06d2e 218};
This page took 0.487202 seconds and 4 git commands to generate.