gdb/testsuite/
[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
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 147 union mips_register ra;
117ce543 148 collect_register_by_name ("r31", ra.buf);
186947f7 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,
1b3f6016 170 lwpid_t lwpid, int idx, void **base)
21b0f40c
DJ
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
117ce543 245 for (i = 1; i < 32; i++)
186947f7
DJ
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);
117ce543
DJ
251 mips_collect_register (use_64bit, find_regno ("badvaddr"), regset + 35);
252 mips_collect_register (use_64bit, find_regno ("status"), regset + 36);
186947f7 253 mips_collect_register (use_64bit, find_regno ("cause"), regset + 37);
117ce543
DJ
254
255 mips_collect_register (use_64bit, find_regno ("restart"), regset + 0);
186947f7
DJ
256}
257
258static void
259mips_store_gregset (const void *buf)
260{
261 const union mips_register *regset = buf;
262 int i, use_64bit;
263
264 use_64bit = (register_size (0) == 8);
265
266 for (i = 0; i < 32; i++)
267 mips_supply_register (use_64bit, i, regset + i);
268
269 mips_supply_register (use_64bit, find_regno ("lo"), regset + 32);
270 mips_supply_register (use_64bit, find_regno ("hi"), regset + 33);
271 mips_supply_register (use_64bit, find_regno ("pc"), regset + 34);
117ce543
DJ
272 mips_supply_register (use_64bit, find_regno ("badvaddr"), regset + 35);
273 mips_supply_register (use_64bit, find_regno ("status"), regset + 36);
186947f7 274 mips_supply_register (use_64bit, find_regno ("cause"), regset + 37);
117ce543
DJ
275
276 mips_supply_register (use_64bit, find_regno ("restart"), regset + 0);
186947f7
DJ
277}
278
279static void
280mips_fill_fpregset (void *buf)
281{
282 union mips_register *regset = buf;
283 int i, use_64bit, first_fp, big_endian;
284
285 use_64bit = (register_size (0) == 8);
286 first_fp = find_regno ("f0");
287 big_endian = (__BYTE_ORDER == __BIG_ENDIAN);
288
289 /* See GDB for a discussion of this peculiar layout. */
290 for (i = 0; i < 32; i++)
291 if (use_64bit)
292 collect_register (first_fp + i, regset[i].buf);
293 else
294 collect_register (first_fp + i,
295 regset[i & ~1].buf + 4 * (big_endian != (i & 1)));
296
117ce543 297 mips_collect_register_32bit (use_64bit, find_regno ("fcsr"), regset[32].buf);
186947f7
DJ
298 mips_collect_register_32bit (use_64bit, find_regno ("fir"),
299 regset[32].buf + 4);
300}
301
302static void
303mips_store_fpregset (const void *buf)
304{
305 const union mips_register *regset = buf;
306 int i, use_64bit, first_fp, big_endian;
307
308 use_64bit = (register_size (0) == 8);
309 first_fp = find_regno ("f0");
310 big_endian = (__BYTE_ORDER == __BIG_ENDIAN);
311
312 /* See GDB for a discussion of this peculiar layout. */
313 for (i = 0; i < 32; i++)
314 if (use_64bit)
315 supply_register (first_fp + i, regset[i].buf);
316 else
317 supply_register (first_fp + i,
318 regset[i & ~1].buf + 4 * (big_endian != (i & 1)));
319
117ce543 320 mips_supply_register_32bit (use_64bit, find_regno ("fcsr"), regset[32].buf);
186947f7
DJ
321 mips_supply_register_32bit (use_64bit, find_regno ("fir"),
322 regset[32].buf + 4);
323}
324#endif /* HAVE_PTRACE_GETREGS */
325
326struct regset_info target_regsets[] = {
327#ifdef HAVE_PTRACE_GETREGS
328 { PTRACE_GETREGS, PTRACE_SETREGS, 38 * 8, GENERAL_REGS,
329 mips_fill_gregset, mips_store_gregset },
330 { PTRACE_GETFPREGS, PTRACE_SETFPREGS, 33 * 8, FP_REGS,
331 mips_fill_fpregset, mips_store_fpregset },
332#endif /* HAVE_PTRACE_GETREGS */
333 { 0, 0, -1, -1, NULL, NULL }
334};
335
2ec06d2e 336struct linux_target_ops the_low_target = {
d05b4ac3
UW
337#ifdef __mips64
338 init_registers_mips64_linux,
339#else
340 init_registers_mips_linux,
341#endif
2ec06d2e
DJ
342 mips_num_regs,
343 mips_regmap,
344 mips_cannot_fetch_register,
345 mips_cannot_store_register,
0d62e5e8
DJ
346 mips_get_pc,
347 mips_set_pc,
f450004a 348 (const unsigned char *) &mips_breakpoint,
0d62e5e8
DJ
349 mips_breakpoint_len,
350 mips_reinsert_addr,
351 0,
352 mips_breakpoint_at,
2ec06d2e 353};
This page took 0.679012 seconds and 4 git commands to generate.