* regcache.h (struct thread_info): Forward declare.
[deliverable/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.
9b254dd1 2 Copyright (C) 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2005, 2006, 2007,
4c38e0a4 3 2008, 2009, 2010 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
21b0f40c 23#include <sys/ptrace.h>
186947f7 24#include <endian.h>
21b0f40c
DJ
25
26#include "gdb_proc_service.h"
27
d05b4ac3
UW
28/* Defined in auto-generated file mips-linux.c. */
29void init_registers_mips_linux (void);
30/* Defined in auto-generated file mips64-linux.c. */
31void init_registers_mips64_linux (void);
32
21b0f40c
DJ
33#ifndef PTRACE_GET_THREAD_AREA
34#define PTRACE_GET_THREAD_AREA 25
35#endif
36
0a30fbc4
DJ
37#ifdef HAVE_SYS_REG_H
38#include <sys/reg.h>
39#endif
40
117ce543 41#define mips_num_regs 73
0a30fbc4
DJ
42
43#include <asm/ptrace.h>
44
186947f7
DJ
45union mips_register
46{
47 unsigned char buf[8];
48
49 /* Deliberately signed, for proper sign extension. */
50 int reg32;
51 long long reg64;
52};
53
0a30fbc4
DJ
54/* Return the ptrace ``address'' of register REGNO. */
55
2ec06d2e 56static int mips_regmap[] = {
117ce543 57 -1, 1, 2, 3, 4, 5, 6, 7,
0a30fbc4
DJ
58 8, 9, 10, 11, 12, 13, 14, 15,
59 16, 17, 18, 19, 20, 21, 22, 23,
60 24, 25, 26, 27, 28, 29, 30, 31,
61
62 -1, MMLO, MMHI, BADVADDR, CAUSE, PC,
63
64 FPR_BASE, FPR_BASE + 1, FPR_BASE + 2, FPR_BASE + 3,
65 FPR_BASE + 4, FPR_BASE + 5, FPR_BASE + 6, FPR_BASE + 7,
66 FPR_BASE + 8, FPR_BASE + 8, FPR_BASE + 10, FPR_BASE + 11,
67 FPR_BASE + 12, FPR_BASE + 13, FPR_BASE + 14, FPR_BASE + 15,
68 FPR_BASE + 16, FPR_BASE + 17, FPR_BASE + 18, FPR_BASE + 19,
69 FPR_BASE + 20, FPR_BASE + 21, FPR_BASE + 22, FPR_BASE + 23,
70 FPR_BASE + 24, FPR_BASE + 25, FPR_BASE + 26, FPR_BASE + 27,
71 FPR_BASE + 28, FPR_BASE + 29, FPR_BASE + 30, FPR_BASE + 31,
72 FPC_CSR, FPC_EIR,
73
117ce543 74 0
0a30fbc4
DJ
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
117ce543 90 if (find_regno ("r0") == 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
117ce543 102 if (find_regno ("r0") == regno)
0a30fbc4
DJ
103 return 1;
104
1d33e73a 105 if (find_regno ("cause") == regno)
0a30fbc4
DJ
106 return 1;
107
117ce543 108 if (find_regno ("badvaddr") == 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 117static CORE_ADDR
442ea881 118mips_get_pc (struct regcache *regcache)
0d62e5e8 119{
186947f7 120 union mips_register pc;
442ea881 121 collect_register_by_name (regcache, "pc", pc.buf);
186947f7 122 return register_size (0) == 4 ? pc.reg32 : pc.reg64;
0d62e5e8
DJ
123}
124
125static void
442ea881 126mips_set_pc (struct regcache *regcache, CORE_ADDR pc)
0d62e5e8 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
442ea881 134 supply_register_by_name (regcache, "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
442ea881 145mips_reinsert_addr (void)
0d62e5e8 146{
442ea881 147 struct regcache *regcache = get_thread_regcache (current_inferior, 1);
186947f7 148 union mips_register ra;
442ea881 149 collect_register_by_name (regcache, "r31", ra.buf);
186947f7 150 return register_size (0) == 4 ? ra.reg32 : ra.reg64;
0d62e5e8
DJ
151}
152
153static int
154mips_breakpoint_at (CORE_ADDR where)
155{
186947f7 156 unsigned int insn;
0d62e5e8 157
f450004a 158 (*the_target->read_memory) (where, (unsigned char *) &insn, 4);
0d62e5e8
DJ
159 if (insn == mips_breakpoint)
160 return 1;
161
162 /* If necessary, recognize more trap instructions here. GDB only uses the
163 one. */
164 return 0;
165}
166
21b0f40c
DJ
167/* Fetch the thread-local storage pointer for libthread_db. */
168
169ps_err_e
170ps_get_thread_area (const struct ps_prochandle *ph,
1b3f6016 171 lwpid_t lwpid, int idx, void **base)
21b0f40c
DJ
172{
173 if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0)
174 return PS_ERR;
175
176 /* IDX is the bias from the thread pointer to the beginning of the
177 thread descriptor. It has to be subtracted due to implementation
178 quirks in libthread_db. */
179 *base = (void *) ((char *)*base - idx);
180
181 return PS_OK;
182}
183
186947f7
DJ
184#ifdef HAVE_PTRACE_GETREGS
185
186static void
442ea881
PA
187mips_collect_register (struct regcache *regcache,
188 int use_64bit, int regno, union mips_register *reg)
186947f7
DJ
189{
190 union mips_register tmp_reg;
191
192 if (use_64bit)
193 {
442ea881 194 collect_register (regcache, regno, &tmp_reg.reg64);
186947f7
DJ
195 *reg = tmp_reg;
196 }
197 else
198 {
442ea881 199 collect_register (regcache, regno, &tmp_reg.reg32);
186947f7
DJ
200 reg->reg64 = tmp_reg.reg32;
201 }
202}
203
204static void
442ea881
PA
205mips_supply_register (struct regcache *regcache,
206 int use_64bit, int regno, const union mips_register *reg)
186947f7
DJ
207{
208 int offset = 0;
209
210 /* For big-endian 32-bit targets, ignore the high four bytes of each
211 eight-byte slot. */
212 if (__BYTE_ORDER == __BIG_ENDIAN && !use_64bit)
213 offset = 4;
214
442ea881 215 supply_register (regcache, regno, reg->buf + offset);
186947f7
DJ
216}
217
218static void
442ea881
PA
219mips_collect_register_32bit (struct regcache *regcache,
220 int use_64bit, int regno, unsigned char *buf)
186947f7
DJ
221{
222 union mips_register tmp_reg;
223 int reg32;
224
442ea881 225 mips_collect_register (regcache, use_64bit, regno, &tmp_reg);
186947f7
DJ
226 reg32 = tmp_reg.reg64;
227 memcpy (buf, &reg32, 4);
228}
229
230static void
442ea881
PA
231mips_supply_register_32bit (struct regcache *regcache,
232 int use_64bit, int regno, const unsigned char *buf)
186947f7
DJ
233{
234 union mips_register tmp_reg;
235 int reg32;
236
237 memcpy (&reg32, buf, 4);
238 tmp_reg.reg64 = reg32;
442ea881 239 mips_supply_register (regcache, use_64bit, regno, &tmp_reg);
186947f7
DJ
240}
241
242static void
442ea881 243mips_fill_gregset (struct regcache *regcache, void *buf)
186947f7
DJ
244{
245 union mips_register *regset = buf;
246 int i, use_64bit;
247
248 use_64bit = (register_size (0) == 8);
249
117ce543 250 for (i = 1; i < 32; i++)
442ea881
PA
251 mips_collect_register (regcache, use_64bit, i, regset + i);
252
253 mips_collect_register (regcache, use_64bit,
254 find_regno ("lo"), regset + 32);
255 mips_collect_register (regcache, use_64bit,
256 find_regno ("hi"), regset + 33);
257 mips_collect_register (regcache, use_64bit,
258 find_regno ("pc"), regset + 34);
259 mips_collect_register (regcache, use_64bit,
260 find_regno ("badvaddr"), regset + 35);
261 mips_collect_register (regcache, use_64bit,
262 find_regno ("status"), regset + 36);
263 mips_collect_register (regcache, use_64bit,
264 find_regno ("cause"), regset + 37);
265
266 mips_collect_register (regcache, use_64bit,
267 find_regno ("restart"), regset + 0);
186947f7
DJ
268}
269
270static void
442ea881 271mips_store_gregset (struct regcache *regcache, const void *buf)
186947f7
DJ
272{
273 const union mips_register *regset = buf;
274 int i, use_64bit;
275
276 use_64bit = (register_size (0) == 8);
277
278 for (i = 0; i < 32; i++)
442ea881
PA
279 mips_supply_register (regcache, use_64bit, i, regset + i);
280
281 mips_supply_register (regcache, use_64bit, find_regno ("lo"), regset + 32);
282 mips_supply_register (regcache, use_64bit, find_regno ("hi"), regset + 33);
283 mips_supply_register (regcache, use_64bit, find_regno ("pc"), regset + 34);
284 mips_supply_register (regcache, use_64bit,
285 find_regno ("badvaddr"), regset + 35);
286 mips_supply_register (regcache, use_64bit,
287 find_regno ("status"), regset + 36);
288 mips_supply_register (regcache, use_64bit,
289 find_regno ("cause"), regset + 37);
290
291 mips_supply_register (regcache, use_64bit,
292 find_regno ("restart"), regset + 0);
186947f7
DJ
293}
294
295static void
442ea881 296mips_fill_fpregset (struct regcache *regcache, void *buf)
186947f7
DJ
297{
298 union mips_register *regset = buf;
299 int i, use_64bit, first_fp, big_endian;
300
301 use_64bit = (register_size (0) == 8);
302 first_fp = find_regno ("f0");
303 big_endian = (__BYTE_ORDER == __BIG_ENDIAN);
304
305 /* See GDB for a discussion of this peculiar layout. */
306 for (i = 0; i < 32; i++)
307 if (use_64bit)
442ea881 308 collect_register (regcache, first_fp + i, regset[i].buf);
186947f7 309 else
442ea881 310 collect_register (regcache, first_fp + i,
186947f7
DJ
311 regset[i & ~1].buf + 4 * (big_endian != (i & 1)));
312
442ea881
PA
313 mips_collect_register_32bit (regcache, use_64bit,
314 find_regno ("fcsr"), regset[32].buf);
315 mips_collect_register_32bit (regcache, use_64bit, find_regno ("fir"),
186947f7
DJ
316 regset[32].buf + 4);
317}
318
319static void
442ea881 320mips_store_fpregset (struct regcache *regcache, const void *buf)
186947f7
DJ
321{
322 const union mips_register *regset = buf;
323 int i, use_64bit, first_fp, big_endian;
324
325 use_64bit = (register_size (0) == 8);
326 first_fp = find_regno ("f0");
327 big_endian = (__BYTE_ORDER == __BIG_ENDIAN);
328
329 /* See GDB for a discussion of this peculiar layout. */
330 for (i = 0; i < 32; i++)
331 if (use_64bit)
442ea881 332 supply_register (regcache, first_fp + i, regset[i].buf);
186947f7 333 else
442ea881 334 supply_register (regcache, first_fp + i,
186947f7
DJ
335 regset[i & ~1].buf + 4 * (big_endian != (i & 1)));
336
442ea881
PA
337 mips_supply_register_32bit (regcache, use_64bit,
338 find_regno ("fcsr"), regset[32].buf);
339 mips_supply_register_32bit (regcache, use_64bit, find_regno ("fir"),
186947f7
DJ
340 regset[32].buf + 4);
341}
342#endif /* HAVE_PTRACE_GETREGS */
343
344struct regset_info target_regsets[] = {
345#ifdef HAVE_PTRACE_GETREGS
346 { PTRACE_GETREGS, PTRACE_SETREGS, 38 * 8, GENERAL_REGS,
347 mips_fill_gregset, mips_store_gregset },
348 { PTRACE_GETFPREGS, PTRACE_SETFPREGS, 33 * 8, FP_REGS,
349 mips_fill_fpregset, mips_store_fpregset },
350#endif /* HAVE_PTRACE_GETREGS */
351 { 0, 0, -1, -1, NULL, NULL }
352};
353
2ec06d2e 354struct linux_target_ops the_low_target = {
d05b4ac3
UW
355#ifdef __mips64
356 init_registers_mips64_linux,
357#else
358 init_registers_mips_linux,
359#endif
2ec06d2e
DJ
360 mips_num_regs,
361 mips_regmap,
362 mips_cannot_fetch_register,
363 mips_cannot_store_register,
0d62e5e8
DJ
364 mips_get_pc,
365 mips_set_pc,
f450004a 366 (const unsigned char *) &mips_breakpoint,
0d62e5e8
DJ
367 mips_breakpoint_len,
368 mips_reinsert_addr,
369 0,
370 mips_breakpoint_at,
2ec06d2e 371};
This page took 0.58362 seconds and 4 git commands to generate.