]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/gdbserver/linux-mips-low.c
Copyright updates for 2007.
[thirdparty/binutils-gdb.git] / gdb / gdbserver / linux-mips-low.c
CommitLineData
0a30fbc4 1/* GNU/Linux/MIPS specific low level interface, for the remote server for GDB.
6aba47ca 2 Copyright (C) 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2005, 2006, 2007
0a30fbc4
DJ
3 Free Software Foundation, Inc.
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
6f0f660e
EZ
19 Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA. */
0a30fbc4
DJ
21
22#include "server.h"
58caa3dc 23#include "linux-low.h"
0a30fbc4 24
21b0f40c 25#include <sys/ptrace.h>
186947f7 26#include <endian.h>
21b0f40c
DJ
27
28#include "gdb_proc_service.h"
29
30#ifndef PTRACE_GET_THREAD_AREA
31#define PTRACE_GET_THREAD_AREA 25
32#endif
33
0a30fbc4
DJ
34#ifdef HAVE_SYS_REG_H
35#include <sys/reg.h>
36#endif
37
2ec06d2e 38#define mips_num_regs 90
0a30fbc4
DJ
39
40#include <asm/ptrace.h>
41
186947f7
DJ
42union mips_register
43{
44 unsigned char buf[8];
45
46 /* Deliberately signed, for proper sign extension. */
47 int reg32;
48 long long reg64;
49};
50
0a30fbc4
DJ
51/* Return the ptrace ``address'' of register REGNO. */
52
53/* Matches mips_generic32_regs */
2ec06d2e 54static int mips_regmap[] = {
0a30fbc4
DJ
55 0, 1, 2, 3, 4, 5, 6, 7,
56 8, 9, 10, 11, 12, 13, 14, 15,
57 16, 17, 18, 19, 20, 21, 22, 23,
58 24, 25, 26, 27, 28, 29, 30, 31,
59
60 -1, MMLO, MMHI, BADVADDR, CAUSE, PC,
61
62 FPR_BASE, FPR_BASE + 1, FPR_BASE + 2, FPR_BASE + 3,
63 FPR_BASE + 4, FPR_BASE + 5, FPR_BASE + 6, FPR_BASE + 7,
64 FPR_BASE + 8, FPR_BASE + 8, FPR_BASE + 10, FPR_BASE + 11,
65 FPR_BASE + 12, FPR_BASE + 13, FPR_BASE + 14, FPR_BASE + 15,
66 FPR_BASE + 16, FPR_BASE + 17, FPR_BASE + 18, FPR_BASE + 19,
67 FPR_BASE + 20, FPR_BASE + 21, FPR_BASE + 22, FPR_BASE + 23,
68 FPR_BASE + 24, FPR_BASE + 25, FPR_BASE + 26, FPR_BASE + 27,
69 FPR_BASE + 28, FPR_BASE + 29, FPR_BASE + 30, FPR_BASE + 31,
70 FPC_CSR, FPC_EIR,
71
72 -1, -1,
73 -1, -1, -1, -1, -1, -1, -1, -1,
74 -1, -1, -1, -1, -1, -1, -1, -1,
75};
76
77/* From mips-linux-nat.c. */
78
79/* Pseudo registers can not be read. ptrace does not provide a way to
80 read (or set) PS_REGNUM, and there's no point in reading or setting
81 ZERO_REGNUM. We also can not set BADVADDR, CAUSE, or FCRIR via
82 ptrace(). */
83
2ec06d2e
DJ
84static int
85mips_cannot_fetch_register (int regno)
0a30fbc4 86{
2ec06d2e 87 if (mips_regmap[regno] == -1)
0a30fbc4
DJ
88 return 1;
89
aa32f823 90 if (find_regno ("zero") == regno)
0a30fbc4
DJ
91 return 1;
92
93 return 0;
94}
95
2ec06d2e
DJ
96static int
97mips_cannot_store_register (int regno)
0a30fbc4 98{
2ec06d2e 99 if (mips_regmap[regno] == -1)
0a30fbc4
DJ
100 return 1;
101
1d33e73a 102 if (find_regno ("zero") == regno)
0a30fbc4
DJ
103 return 1;
104
1d33e73a 105 if (find_regno ("cause") == regno)
0a30fbc4
DJ
106 return 1;
107
1d33e73a 108 if (find_regno ("bad") == regno)
0a30fbc4
DJ
109 return 1;
110
1d33e73a 111 if (find_regno ("fir") == regno)
0a30fbc4
DJ
112 return 1;
113
114 return 0;
115}
2ec06d2e 116
0d62e5e8
DJ
117static CORE_ADDR
118mips_get_pc ()
119{
186947f7
DJ
120 union mips_register pc;
121 collect_register_by_name ("pc", pc.buf);
122 return register_size (0) == 4 ? pc.reg32 : pc.reg64;
0d62e5e8
DJ
123}
124
125static void
126mips_set_pc (CORE_ADDR pc)
127{
186947f7
DJ
128 union mips_register newpc;
129 if (register_size (0) == 4)
130 newpc.reg32 = pc;
131 else
132 newpc.reg64 = pc;
133
134 supply_register_by_name ("pc", newpc.buf);
0d62e5e8
DJ
135}
136
137/* Correct in either endianness. */
186947f7 138static const unsigned int mips_breakpoint = 0x0005000d;
0d62e5e8
DJ
139#define mips_breakpoint_len 4
140
141/* We only place breakpoints in empty marker functions, and thread locking
142 is outside of the function. So rather than importing software single-step,
143 we can just run until exit. */
144static CORE_ADDR
145mips_reinsert_addr ()
146{
186947f7
DJ
147 union mips_register ra;
148 collect_register_by_name ("ra", ra.buf);
149 return register_size (0) == 4 ? ra.reg32 : ra.reg64;
0d62e5e8
DJ
150}
151
152static int
153mips_breakpoint_at (CORE_ADDR where)
154{
186947f7 155 unsigned int insn;
0d62e5e8 156
f450004a 157 (*the_target->read_memory) (where, (unsigned char *) &insn, 4);
0d62e5e8
DJ
158 if (insn == mips_breakpoint)
159 return 1;
160
161 /* If necessary, recognize more trap instructions here. GDB only uses the
162 one. */
163 return 0;
164}
165
21b0f40c
DJ
166/* Fetch the thread-local storage pointer for libthread_db. */
167
168ps_err_e
169ps_get_thread_area (const struct ps_prochandle *ph,
170 lwpid_t lwpid, int idx, void **base)
171{
172 if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0)
173 return PS_ERR;
174
175 /* IDX is the bias from the thread pointer to the beginning of the
176 thread descriptor. It has to be subtracted due to implementation
177 quirks in libthread_db. */
178 *base = (void *) ((char *)*base - idx);
179
180 return PS_OK;
181}
182
186947f7
DJ
183#ifdef HAVE_PTRACE_GETREGS
184
185static void
186mips_collect_register (int use_64bit, int regno, union mips_register *reg)
187{
188 union mips_register tmp_reg;
189
190 if (use_64bit)
191 {
192 collect_register (regno, &tmp_reg.reg64);
193 *reg = tmp_reg;
194 }
195 else
196 {
197 collect_register (regno, &tmp_reg.reg32);
198 reg->reg64 = tmp_reg.reg32;
199 }
200}
201
202static void
203mips_supply_register (int use_64bit, int regno, const union mips_register *reg)
204{
205 int offset = 0;
206
207 /* For big-endian 32-bit targets, ignore the high four bytes of each
208 eight-byte slot. */
209 if (__BYTE_ORDER == __BIG_ENDIAN && !use_64bit)
210 offset = 4;
211
212 supply_register (regno, reg->buf + offset);
213}
214
215static void
216mips_collect_register_32bit (int use_64bit, int regno, unsigned char *buf)
217{
218 union mips_register tmp_reg;
219 int reg32;
220
221 mips_collect_register (use_64bit, regno, &tmp_reg);
222 reg32 = tmp_reg.reg64;
223 memcpy (buf, &reg32, 4);
224}
225
226static void
227mips_supply_register_32bit (int use_64bit, int regno, const unsigned char *buf)
228{
229 union mips_register tmp_reg;
230 int reg32;
231
232 memcpy (&reg32, buf, 4);
233 tmp_reg.reg64 = reg32;
234 mips_supply_register (use_64bit, regno, &tmp_reg);
235}
236
237static void
238mips_fill_gregset (void *buf)
239{
240 union mips_register *regset = buf;
241 int i, use_64bit;
242
243 use_64bit = (register_size (0) == 8);
244
245 for (i = 0; i < 32; i++)
246 mips_collect_register (use_64bit, i, regset + i);
247
248 mips_collect_register (use_64bit, find_regno ("lo"), regset + 32);
249 mips_collect_register (use_64bit, find_regno ("hi"), regset + 33);
250 mips_collect_register (use_64bit, find_regno ("pc"), regset + 34);
251 mips_collect_register (use_64bit, find_regno ("bad"), regset + 35);
252 mips_collect_register (use_64bit, find_regno ("sr"), regset + 36);
253 mips_collect_register (use_64bit, find_regno ("cause"), regset + 37);
254}
255
256static void
257mips_store_gregset (const void *buf)
258{
259 const union mips_register *regset = buf;
260 int i, use_64bit;
261
262 use_64bit = (register_size (0) == 8);
263
264 for (i = 0; i < 32; i++)
265 mips_supply_register (use_64bit, i, regset + i);
266
267 mips_supply_register (use_64bit, find_regno ("lo"), regset + 32);
268 mips_supply_register (use_64bit, find_regno ("hi"), regset + 33);
269 mips_supply_register (use_64bit, find_regno ("pc"), regset + 34);
270 mips_supply_register (use_64bit, find_regno ("bad"), regset + 35);
271 mips_supply_register (use_64bit, find_regno ("sr"), regset + 36);
272 mips_supply_register (use_64bit, find_regno ("cause"), regset + 37);
273}
274
275static void
276mips_fill_fpregset (void *buf)
277{
278 union mips_register *regset = buf;
279 int i, use_64bit, first_fp, big_endian;
280
281 use_64bit = (register_size (0) == 8);
282 first_fp = find_regno ("f0");
283 big_endian = (__BYTE_ORDER == __BIG_ENDIAN);
284
285 /* See GDB for a discussion of this peculiar layout. */
286 for (i = 0; i < 32; i++)
287 if (use_64bit)
288 collect_register (first_fp + i, regset[i].buf);
289 else
290 collect_register (first_fp + i,
291 regset[i & ~1].buf + 4 * (big_endian != (i & 1)));
292
293 mips_collect_register_32bit (use_64bit, find_regno ("fsr"), regset[32].buf);
294 mips_collect_register_32bit (use_64bit, find_regno ("fir"),
295 regset[32].buf + 4);
296}
297
298static void
299mips_store_fpregset (const void *buf)
300{
301 const union mips_register *regset = buf;
302 int i, use_64bit, first_fp, big_endian;
303
304 use_64bit = (register_size (0) == 8);
305 first_fp = find_regno ("f0");
306 big_endian = (__BYTE_ORDER == __BIG_ENDIAN);
307
308 /* See GDB for a discussion of this peculiar layout. */
309 for (i = 0; i < 32; i++)
310 if (use_64bit)
311 supply_register (first_fp + i, regset[i].buf);
312 else
313 supply_register (first_fp + i,
314 regset[i & ~1].buf + 4 * (big_endian != (i & 1)));
315
316 mips_supply_register_32bit (use_64bit, find_regno ("fsr"), regset[32].buf);
317 mips_supply_register_32bit (use_64bit, find_regno ("fir"),
318 regset[32].buf + 4);
319}
320#endif /* HAVE_PTRACE_GETREGS */
321
322struct regset_info target_regsets[] = {
323#ifdef HAVE_PTRACE_GETREGS
324 { PTRACE_GETREGS, PTRACE_SETREGS, 38 * 8, GENERAL_REGS,
325 mips_fill_gregset, mips_store_gregset },
326 { PTRACE_GETFPREGS, PTRACE_SETFPREGS, 33 * 8, FP_REGS,
327 mips_fill_fpregset, mips_store_fpregset },
328#endif /* HAVE_PTRACE_GETREGS */
329 { 0, 0, -1, -1, NULL, NULL }
330};
331
2ec06d2e
DJ
332struct linux_target_ops the_low_target = {
333 mips_num_regs,
334 mips_regmap,
335 mips_cannot_fetch_register,
336 mips_cannot_store_register,
0d62e5e8
DJ
337 mips_get_pc,
338 mips_set_pc,
f450004a 339 (const unsigned char *) &mips_breakpoint,
0d62e5e8
DJ
340 mips_breakpoint_len,
341 mips_reinsert_addr,
342 0,
343 mips_breakpoint_at,
2ec06d2e 344};