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