gdb/gdbserver:
[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.
0b302171
JB
2 Copyright (C) 1995-1996, 1998-2002, 2005-2012 Free Software
3 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);
1faeff08
MR
30/* Defined in auto-generated file mips-dsp-linux.c. */
31void init_registers_mips_dsp_linux (void);
d05b4ac3
UW
32/* Defined in auto-generated file mips64-linux.c. */
33void init_registers_mips64_linux (void);
1faeff08
MR
34/* Defined in auto-generated file mips64-dsp-linux.c. */
35void init_registers_mips64_dsp_linux (void);
36
37#ifdef __mips64
38#define init_registers_mips_linux init_registers_mips64_linux
39#define init_registers_mips_dsp_linux init_registers_mips64_dsp_linux
40#endif
d05b4ac3 41
21b0f40c
DJ
42#ifndef PTRACE_GET_THREAD_AREA
43#define PTRACE_GET_THREAD_AREA 25
44#endif
45
0a30fbc4
DJ
46#ifdef HAVE_SYS_REG_H
47#include <sys/reg.h>
48#endif
49
117ce543 50#define mips_num_regs 73
1faeff08 51#define mips_dsp_num_regs 80
0a30fbc4
DJ
52
53#include <asm/ptrace.h>
54
1faeff08
MR
55#ifndef DSP_BASE
56#define DSP_BASE 71
57#define DSP_CONTROL 77
58#endif
59
186947f7
DJ
60union mips_register
61{
62 unsigned char buf[8];
63
64 /* Deliberately signed, for proper sign extension. */
65 int reg32;
66 long long reg64;
67};
68
0a30fbc4
DJ
69/* Return the ptrace ``address'' of register REGNO. */
70
1faeff08
MR
71#define mips_base_regs \
72 -1, 1, 2, 3, 4, 5, 6, 7, \
73 8, 9, 10, 11, 12, 13, 14, 15, \
74 16, 17, 18, 19, 20, 21, 22, 23, \
75 24, 25, 26, 27, 28, 29, 30, 31, \
76 \
77 -1, MMLO, MMHI, BADVADDR, CAUSE, PC, \
78 \
79 FPR_BASE, FPR_BASE + 1, FPR_BASE + 2, FPR_BASE + 3, \
80 FPR_BASE + 4, FPR_BASE + 5, FPR_BASE + 6, FPR_BASE + 7, \
81 FPR_BASE + 8, FPR_BASE + 9, FPR_BASE + 10, FPR_BASE + 11, \
82 FPR_BASE + 12, FPR_BASE + 13, FPR_BASE + 14, FPR_BASE + 15, \
83 FPR_BASE + 16, FPR_BASE + 17, FPR_BASE + 18, FPR_BASE + 19, \
84 FPR_BASE + 20, FPR_BASE + 21, FPR_BASE + 22, FPR_BASE + 23, \
85 FPR_BASE + 24, FPR_BASE + 25, FPR_BASE + 26, FPR_BASE + 27, \
86 FPR_BASE + 28, FPR_BASE + 29, FPR_BASE + 30, FPR_BASE + 31, \
87 FPC_CSR, FPC_EIR
88
89#define mips_dsp_regs \
90 DSP_BASE, DSP_BASE + 1, DSP_BASE + 2, DSP_BASE + 3, \
91 DSP_BASE + 4, DSP_BASE + 5, \
92 DSP_CONTROL
93
94static int mips_regmap[mips_num_regs] = {
95 mips_base_regs,
96 0
97};
0a30fbc4 98
1faeff08
MR
99static int mips_dsp_regmap[mips_dsp_num_regs] = {
100 mips_base_regs,
101 mips_dsp_regs,
102 0
103};
0a30fbc4 104
1faeff08
MR
105/* DSP registers are not in any regset and can only be accessed
106 individually. */
0a30fbc4 107
1faeff08
MR
108static unsigned char mips_dsp_regset_bitmap[(mips_dsp_num_regs + 7) / 8] = {
109 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x80
0a30fbc4
DJ
110};
111
1faeff08
MR
112/* Try peeking at an arbitrarily chosen DSP register and pick the available
113 user register set accordingly. */
114
115static void
116mips_arch_setup (void)
117{
118 static void (*init_registers) (void);
119
120 gdb_assert (current_inferior);
121
122 if (init_registers == NULL)
123 {
124 int pid = lwpid_of (get_thread_lwp (current_inferior));
125
126 ptrace (PTRACE_PEEKUSER, pid, DSP_CONTROL, 0);
127 switch (errno)
128 {
129 case 0:
130 the_low_target.num_regs = mips_dsp_num_regs;
131 the_low_target.regmap = mips_dsp_regmap;
132 the_low_target.regset_bitmap = mips_dsp_regset_bitmap;
133 init_registers = init_registers_mips_dsp_linux;
134 break;
135 case EIO:
136 the_low_target.num_regs = mips_num_regs;
137 the_low_target.regmap = mips_regmap;
138 the_low_target.regset_bitmap = NULL;
139 init_registers = init_registers_mips_linux;
140 break;
141 default:
142 perror_with_name ("ptrace");
143 break;
144 }
145 }
146 init_registers ();
147}
148
0a30fbc4
DJ
149/* From mips-linux-nat.c. */
150
151/* Pseudo registers can not be read. ptrace does not provide a way to
152 read (or set) PS_REGNUM, and there's no point in reading or setting
153 ZERO_REGNUM. We also can not set BADVADDR, CAUSE, or FCRIR via
154 ptrace(). */
155
2ec06d2e
DJ
156static int
157mips_cannot_fetch_register (int regno)
0a30fbc4 158{
1faeff08 159 if (the_low_target.regmap[regno] == -1)
0a30fbc4
DJ
160 return 1;
161
117ce543 162 if (find_regno ("r0") == regno)
0a30fbc4
DJ
163 return 1;
164
165 return 0;
166}
167
2ec06d2e
DJ
168static int
169mips_cannot_store_register (int regno)
0a30fbc4 170{
1faeff08 171 if (the_low_target.regmap[regno] == -1)
0a30fbc4
DJ
172 return 1;
173
117ce543 174 if (find_regno ("r0") == regno)
0a30fbc4
DJ
175 return 1;
176
1d33e73a 177 if (find_regno ("cause") == regno)
0a30fbc4
DJ
178 return 1;
179
117ce543 180 if (find_regno ("badvaddr") == regno)
0a30fbc4
DJ
181 return 1;
182
1d33e73a 183 if (find_regno ("fir") == regno)
0a30fbc4
DJ
184 return 1;
185
186 return 0;
187}
2ec06d2e 188
0d62e5e8 189static CORE_ADDR
442ea881 190mips_get_pc (struct regcache *regcache)
0d62e5e8 191{
186947f7 192 union mips_register pc;
442ea881 193 collect_register_by_name (regcache, "pc", pc.buf);
186947f7 194 return register_size (0) == 4 ? pc.reg32 : pc.reg64;
0d62e5e8
DJ
195}
196
197static void
442ea881 198mips_set_pc (struct regcache *regcache, CORE_ADDR pc)
0d62e5e8 199{
186947f7
DJ
200 union mips_register newpc;
201 if (register_size (0) == 4)
202 newpc.reg32 = pc;
203 else
204 newpc.reg64 = pc;
205
442ea881 206 supply_register_by_name (regcache, "pc", newpc.buf);
0d62e5e8
DJ
207}
208
209/* Correct in either endianness. */
186947f7 210static const unsigned int mips_breakpoint = 0x0005000d;
0d62e5e8
DJ
211#define mips_breakpoint_len 4
212
213/* We only place breakpoints in empty marker functions, and thread locking
214 is outside of the function. So rather than importing software single-step,
215 we can just run until exit. */
216static CORE_ADDR
442ea881 217mips_reinsert_addr (void)
0d62e5e8 218{
442ea881 219 struct regcache *regcache = get_thread_regcache (current_inferior, 1);
186947f7 220 union mips_register ra;
442ea881 221 collect_register_by_name (regcache, "r31", ra.buf);
186947f7 222 return register_size (0) == 4 ? ra.reg32 : ra.reg64;
0d62e5e8
DJ
223}
224
225static int
226mips_breakpoint_at (CORE_ADDR where)
227{
186947f7 228 unsigned int insn;
0d62e5e8 229
f450004a 230 (*the_target->read_memory) (where, (unsigned char *) &insn, 4);
0d62e5e8
DJ
231 if (insn == mips_breakpoint)
232 return 1;
233
234 /* If necessary, recognize more trap instructions here. GDB only uses the
235 one. */
236 return 0;
237}
238
21b0f40c
DJ
239/* Fetch the thread-local storage pointer for libthread_db. */
240
241ps_err_e
242ps_get_thread_area (const struct ps_prochandle *ph,
1b3f6016 243 lwpid_t lwpid, int idx, void **base)
21b0f40c
DJ
244{
245 if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0)
246 return PS_ERR;
247
248 /* IDX is the bias from the thread pointer to the beginning of the
249 thread descriptor. It has to be subtracted due to implementation
250 quirks in libthread_db. */
251 *base = (void *) ((char *)*base - idx);
252
253 return PS_OK;
254}
255
186947f7
DJ
256#ifdef HAVE_PTRACE_GETREGS
257
258static void
442ea881
PA
259mips_collect_register (struct regcache *regcache,
260 int use_64bit, int regno, union mips_register *reg)
186947f7
DJ
261{
262 union mips_register tmp_reg;
263
264 if (use_64bit)
265 {
442ea881 266 collect_register (regcache, regno, &tmp_reg.reg64);
186947f7
DJ
267 *reg = tmp_reg;
268 }
269 else
270 {
442ea881 271 collect_register (regcache, regno, &tmp_reg.reg32);
186947f7
DJ
272 reg->reg64 = tmp_reg.reg32;
273 }
274}
275
276static void
442ea881
PA
277mips_supply_register (struct regcache *regcache,
278 int use_64bit, int regno, const union mips_register *reg)
186947f7
DJ
279{
280 int offset = 0;
281
282 /* For big-endian 32-bit targets, ignore the high four bytes of each
283 eight-byte slot. */
284 if (__BYTE_ORDER == __BIG_ENDIAN && !use_64bit)
285 offset = 4;
286
442ea881 287 supply_register (regcache, regno, reg->buf + offset);
186947f7
DJ
288}
289
290static void
442ea881
PA
291mips_collect_register_32bit (struct regcache *regcache,
292 int use_64bit, int regno, unsigned char *buf)
186947f7
DJ
293{
294 union mips_register tmp_reg;
295 int reg32;
296
442ea881 297 mips_collect_register (regcache, use_64bit, regno, &tmp_reg);
186947f7
DJ
298 reg32 = tmp_reg.reg64;
299 memcpy (buf, &reg32, 4);
300}
301
302static void
442ea881
PA
303mips_supply_register_32bit (struct regcache *regcache,
304 int use_64bit, int regno, const unsigned char *buf)
186947f7
DJ
305{
306 union mips_register tmp_reg;
307 int reg32;
308
309 memcpy (&reg32, buf, 4);
310 tmp_reg.reg64 = reg32;
442ea881 311 mips_supply_register (regcache, use_64bit, regno, &tmp_reg);
186947f7
DJ
312}
313
314static void
442ea881 315mips_fill_gregset (struct regcache *regcache, void *buf)
186947f7
DJ
316{
317 union mips_register *regset = buf;
318 int i, use_64bit;
319
320 use_64bit = (register_size (0) == 8);
321
117ce543 322 for (i = 1; i < 32; i++)
442ea881
PA
323 mips_collect_register (regcache, use_64bit, i, regset + i);
324
325 mips_collect_register (regcache, use_64bit,
326 find_regno ("lo"), regset + 32);
327 mips_collect_register (regcache, use_64bit,
328 find_regno ("hi"), regset + 33);
329 mips_collect_register (regcache, use_64bit,
330 find_regno ("pc"), regset + 34);
331 mips_collect_register (regcache, use_64bit,
332 find_regno ("badvaddr"), regset + 35);
333 mips_collect_register (regcache, use_64bit,
334 find_regno ("status"), regset + 36);
335 mips_collect_register (regcache, use_64bit,
336 find_regno ("cause"), regset + 37);
337
338 mips_collect_register (regcache, use_64bit,
339 find_regno ("restart"), regset + 0);
186947f7
DJ
340}
341
342static void
442ea881 343mips_store_gregset (struct regcache *regcache, const void *buf)
186947f7
DJ
344{
345 const union mips_register *regset = buf;
346 int i, use_64bit;
347
348 use_64bit = (register_size (0) == 8);
349
350 for (i = 0; i < 32; i++)
442ea881
PA
351 mips_supply_register (regcache, use_64bit, i, regset + i);
352
353 mips_supply_register (regcache, use_64bit, find_regno ("lo"), regset + 32);
354 mips_supply_register (regcache, use_64bit, find_regno ("hi"), regset + 33);
355 mips_supply_register (regcache, use_64bit, find_regno ("pc"), regset + 34);
356 mips_supply_register (regcache, use_64bit,
357 find_regno ("badvaddr"), regset + 35);
358 mips_supply_register (regcache, use_64bit,
359 find_regno ("status"), regset + 36);
360 mips_supply_register (regcache, use_64bit,
361 find_regno ("cause"), regset + 37);
362
363 mips_supply_register (regcache, use_64bit,
364 find_regno ("restart"), regset + 0);
186947f7
DJ
365}
366
367static void
442ea881 368mips_fill_fpregset (struct regcache *regcache, void *buf)
186947f7
DJ
369{
370 union mips_register *regset = buf;
371 int i, use_64bit, first_fp, big_endian;
372
373 use_64bit = (register_size (0) == 8);
374 first_fp = find_regno ("f0");
375 big_endian = (__BYTE_ORDER == __BIG_ENDIAN);
376
377 /* See GDB for a discussion of this peculiar layout. */
378 for (i = 0; i < 32; i++)
379 if (use_64bit)
442ea881 380 collect_register (regcache, first_fp + i, regset[i].buf);
186947f7 381 else
442ea881 382 collect_register (regcache, first_fp + i,
186947f7
DJ
383 regset[i & ~1].buf + 4 * (big_endian != (i & 1)));
384
442ea881
PA
385 mips_collect_register_32bit (regcache, use_64bit,
386 find_regno ("fcsr"), regset[32].buf);
387 mips_collect_register_32bit (regcache, use_64bit, find_regno ("fir"),
186947f7
DJ
388 regset[32].buf + 4);
389}
390
391static void
442ea881 392mips_store_fpregset (struct regcache *regcache, const void *buf)
186947f7
DJ
393{
394 const union mips_register *regset = buf;
395 int i, use_64bit, first_fp, big_endian;
396
397 use_64bit = (register_size (0) == 8);
398 first_fp = find_regno ("f0");
399 big_endian = (__BYTE_ORDER == __BIG_ENDIAN);
400
401 /* See GDB for a discussion of this peculiar layout. */
402 for (i = 0; i < 32; i++)
403 if (use_64bit)
442ea881 404 supply_register (regcache, first_fp + i, regset[i].buf);
186947f7 405 else
442ea881 406 supply_register (regcache, first_fp + i,
186947f7
DJ
407 regset[i & ~1].buf + 4 * (big_endian != (i & 1)));
408
442ea881
PA
409 mips_supply_register_32bit (regcache, use_64bit,
410 find_regno ("fcsr"), regset[32].buf);
411 mips_supply_register_32bit (regcache, use_64bit, find_regno ("fir"),
186947f7
DJ
412 regset[32].buf + 4);
413}
414#endif /* HAVE_PTRACE_GETREGS */
415
416struct regset_info target_regsets[] = {
417#ifdef HAVE_PTRACE_GETREGS
1570b33e 418 { PTRACE_GETREGS, PTRACE_SETREGS, 0, 38 * 8, GENERAL_REGS,
186947f7 419 mips_fill_gregset, mips_store_gregset },
1570b33e 420 { PTRACE_GETFPREGS, PTRACE_SETFPREGS, 0, 33 * 8, FP_REGS,
186947f7
DJ
421 mips_fill_fpregset, mips_store_fpregset },
422#endif /* HAVE_PTRACE_GETREGS */
1570b33e 423 { 0, 0, 0, -1, -1, NULL, NULL }
186947f7
DJ
424};
425
2ec06d2e 426struct linux_target_ops the_low_target = {
1faeff08
MR
427 mips_arch_setup,
428 -1,
429 NULL,
430 NULL,
2ec06d2e
DJ
431 mips_cannot_fetch_register,
432 mips_cannot_store_register,
c14dfd32 433 NULL, /* fetch_register */
0d62e5e8
DJ
434 mips_get_pc,
435 mips_set_pc,
f450004a 436 (const unsigned char *) &mips_breakpoint,
0d62e5e8
DJ
437 mips_breakpoint_len,
438 mips_reinsert_addr,
439 0,
440 mips_breakpoint_at,
2ec06d2e 441};
This page took 0.806898 seconds and 4 git commands to generate.