]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/mips-linux-nat.c
Switch the license of all .c files to GPLv3.
[thirdparty/binutils-gdb.git] / gdb / mips-linux-nat.c
CommitLineData
75c9abc6 1/* Native-dependent code for GNU/Linux on MIPS processors.
a094c6fb 2
6aba47ca 3 Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007
dc60ece8 4 Free Software Foundation, Inc.
2aa830e4
DJ
5
6 This file is part of GDB.
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
a9762ec7 10 the Free Software Foundation; either version 3 of the License, or
2aa830e4
DJ
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
a9762ec7 19 along with this program. If not, see <http://www.gnu.org/licenses/>. */
2aa830e4
DJ
20
21#include "defs.h"
d37eb719 22#include "inferior.h"
6b753f60 23#include "mips-tdep.h"
10d6c8cd 24#include "target.h"
28f5035f 25#include "regcache.h"
10d6c8cd 26#include "linux-nat.h"
d37eb719 27#include "mips-linux-tdep.h"
822b6570
DJ
28#include "target-descriptions.h"
29#include "xml-support.h"
2aa830e4 30
dc60ece8 31#include "gdb_proc_service.h"
3e00823e 32#include "gregset.h"
dc60ece8 33
822b6570 34#include <sgidefs.h>
d37eb719
DJ
35#include <sys/ptrace.h>
36
dc60ece8
DJ
37#ifndef PTRACE_GET_THREAD_AREA
38#define PTRACE_GET_THREAD_AREA 25
39#endif
40
d37eb719
DJ
41/* Assume that we have PTRACE_GETREGS et al. support. If we do not,
42 we'll clear this and use PTRACE_PEEKUSER instead. */
43static int have_ptrace_regsets = 1;
44
45/* Saved function pointers to fetch and store a single register using
46 PTRACE_PEEKUSER and PTRACE_POKEUSER. */
47
56be3814
UW
48void (*super_fetch_registers) (struct regcache *, int);
49void (*super_store_registers) (struct regcache *, int);
d37eb719 50
dda0c97e 51/* Map gdb internal register number to ptrace ``address''.
7714d83a
UW
52 These ``addresses'' are normally defined in <asm/ptrace.h>.
53
54 ptrace does not provide a way to read (or set) MIPS_PS_REGNUM,
55 and there's no point in reading or setting MIPS_ZERO_REGNUM.
56 We also can not set BADVADDR, CAUSE, or FCRIR via ptrace(). */
dda0c97e
UW
57
58static CORE_ADDR
7714d83a 59mips_linux_register_addr (struct gdbarch *gdbarch, int regno, int store)
dda0c97e 60{
7714d83a 61 CORE_ADDR regaddr;
dda0c97e 62
f57d151a 63 if (regno < 0 || regno >= gdbarch_num_regs (current_gdbarch))
dda0c97e
UW
64 error (_("Bogon register number %d."), regno);
65
7714d83a 66 if (regno > MIPS_ZERO_REGNUM && regno < MIPS_ZERO_REGNUM + 32)
dda0c97e 67 regaddr = regno;
7714d83a
UW
68 else if ((regno >= mips_regnum (gdbarch)->fp0)
69 && (regno < mips_regnum (gdbarch)->fp0 + 32))
70 regaddr = FPR_BASE + (regno - mips_regnum (gdbarch)->fp0);
71 else if (regno == mips_regnum (gdbarch)->pc)
dda0c97e 72 regaddr = PC;
7714d83a
UW
73 else if (regno == mips_regnum (gdbarch)->cause)
74 regaddr = store? (CORE_ADDR) -1 : CAUSE;
75 else if (regno == mips_regnum (gdbarch)->badvaddr)
76 regaddr = store? (CORE_ADDR) -1 : BADVADDR;
77 else if (regno == mips_regnum (gdbarch)->lo)
dda0c97e 78 regaddr = MMLO;
7714d83a 79 else if (regno == mips_regnum (gdbarch)->hi)
dda0c97e 80 regaddr = MMHI;
7714d83a 81 else if (regno == mips_regnum (gdbarch)->fp_control_status)
dda0c97e 82 regaddr = FPC_CSR;
7714d83a
UW
83 else if (regno == mips_regnum (gdbarch)->fp_implementation_revision)
84 regaddr = store? (CORE_ADDR) -1 : FPC_EIR;
822b6570
DJ
85 else if (mips_linux_restart_reg_p (gdbarch) && regno == MIPS_RESTART_REGNUM)
86 regaddr = 0;
dda0c97e 87 else
7714d83a 88 regaddr = (CORE_ADDR) -1;
dda0c97e
UW
89
90 return regaddr;
91}
92
93static CORE_ADDR
7714d83a 94mips64_linux_register_addr (struct gdbarch *gdbarch, int regno, int store)
dda0c97e 95{
7714d83a 96 CORE_ADDR regaddr;
dda0c97e 97
f57d151a 98 if (regno < 0 || regno >= gdbarch_num_regs (current_gdbarch))
dda0c97e
UW
99 error (_("Bogon register number %d."), regno);
100
7714d83a 101 if (regno > MIPS_ZERO_REGNUM && regno < MIPS_ZERO_REGNUM + 32)
dda0c97e 102 regaddr = regno;
7714d83a
UW
103 else if ((regno >= mips_regnum (gdbarch)->fp0)
104 && (regno < mips_regnum (gdbarch)->fp0 + 32))
3e8c568d 105 regaddr = MIPS64_FPR_BASE + (regno - gdbarch_fp0_regnum (current_gdbarch));
7714d83a 106 else if (regno == mips_regnum (gdbarch)->pc)
dda0c97e 107 regaddr = MIPS64_PC;
7714d83a
UW
108 else if (regno == mips_regnum (gdbarch)->cause)
109 regaddr = store? (CORE_ADDR) -1 : MIPS64_CAUSE;
110 else if (regno == mips_regnum (gdbarch)->badvaddr)
111 regaddr = store? (CORE_ADDR) -1 : MIPS64_BADVADDR;
112 else if (regno == mips_regnum (gdbarch)->lo)
dda0c97e 113 regaddr = MIPS64_MMLO;
7714d83a 114 else if (regno == mips_regnum (gdbarch)->hi)
dda0c97e 115 regaddr = MIPS64_MMHI;
7714d83a 116 else if (regno == mips_regnum (gdbarch)->fp_control_status)
dda0c97e 117 regaddr = MIPS64_FPC_CSR;
7714d83a
UW
118 else if (regno == mips_regnum (gdbarch)->fp_implementation_revision)
119 regaddr = store? (CORE_ADDR) -1 : MIPS64_FPC_EIR;
822b6570
DJ
120 else if (mips_linux_restart_reg_p (gdbarch) && regno == MIPS_RESTART_REGNUM)
121 regaddr = 0;
dda0c97e 122 else
7714d83a 123 regaddr = (CORE_ADDR) -1;
dda0c97e
UW
124
125 return regaddr;
126}
127
dc60ece8
DJ
128/* Fetch the thread-local storage pointer for libthread_db. */
129
130ps_err_e
131ps_get_thread_area (const struct ps_prochandle *ph,
132 lwpid_t lwpid, int idx, void **base)
133{
134 if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0)
135 return PS_ERR;
136
137 /* IDX is the bias from the thread pointer to the beginning of the
138 thread descriptor. It has to be subtracted due to implementation
139 quirks in libthread_db. */
140 *base = (void *) ((char *)*base - idx);
141
142 return PS_OK;
143}
144
3e00823e
UW
145/* Wrapper functions. These are only used by libthread_db. */
146
147void
7f7fe91e 148supply_gregset (struct regcache *regcache, const gdb_gregset_t *gregsetp)
3e00823e
UW
149{
150 if (mips_isa_regsize (current_gdbarch) == 4)
7f7fe91e 151 mips_supply_gregset (regcache, (const mips_elf_gregset_t *) gregsetp);
3e00823e 152 else
7f7fe91e 153 mips64_supply_gregset (regcache, (const mips64_elf_gregset_t *) gregsetp);
3e00823e
UW
154}
155
156void
7f7fe91e
UW
157fill_gregset (const struct regcache *regcache,
158 gdb_gregset_t *gregsetp, int regno)
3e00823e
UW
159{
160 if (mips_isa_regsize (current_gdbarch) == 4)
7f7fe91e 161 mips_fill_gregset (regcache, (mips_elf_gregset_t *) gregsetp, regno);
3e00823e 162 else
7f7fe91e 163 mips64_fill_gregset (regcache, (mips64_elf_gregset_t *) gregsetp, regno);
3e00823e
UW
164}
165
166void
7f7fe91e 167supply_fpregset (struct regcache *regcache, const gdb_fpregset_t *fpregsetp)
3e00823e
UW
168{
169 if (mips_isa_regsize (current_gdbarch) == 4)
7f7fe91e 170 mips_supply_fpregset (regcache, (const mips_elf_fpregset_t *) fpregsetp);
3e00823e 171 else
7f7fe91e 172 mips64_supply_fpregset (regcache, (const mips64_elf_fpregset_t *) fpregsetp);
3e00823e
UW
173}
174
175void
7f7fe91e
UW
176fill_fpregset (const struct regcache *regcache,
177 gdb_fpregset_t *fpregsetp, int regno)
3e00823e
UW
178{
179 if (mips_isa_regsize (current_gdbarch) == 4)
7f7fe91e 180 mips_fill_fpregset (regcache, (mips_elf_fpregset_t *) fpregsetp, regno);
3e00823e 181 else
7f7fe91e 182 mips64_fill_fpregset (regcache, (mips64_elf_fpregset_t *) fpregsetp, regno);
3e00823e
UW
183}
184
185
d37eb719
DJ
186/* Fetch REGNO (or all registers if REGNO == -1) from the target
187 using PTRACE_GETREGS et al. */
188
189static void
56be3814 190mips64_linux_regsets_fetch_registers (struct regcache *regcache, int regno)
d37eb719
DJ
191{
192 int is_fp;
193 int tid;
194
195 if (regno >= mips_regnum (current_gdbarch)->fp0
196 && regno <= mips_regnum (current_gdbarch)->fp0 + 32)
197 is_fp = 1;
198 else if (regno == mips_regnum (current_gdbarch)->fp_control_status)
199 is_fp = 1;
200 else if (regno == mips_regnum (current_gdbarch)->fp_implementation_revision)
201 is_fp = 1;
202 else
203 is_fp = 0;
204
205 tid = ptid_get_lwp (inferior_ptid);
206 if (tid == 0)
207 tid = ptid_get_pid (inferior_ptid);
208
209 if (regno == -1 || !is_fp)
210 {
211 mips64_elf_gregset_t regs;
212
213 if (ptrace (PTRACE_GETREGS, tid, 0L, (PTRACE_TYPE_ARG3) &regs) == -1)
214 {
215 if (errno == EIO)
216 {
217 have_ptrace_regsets = 0;
218 return;
219 }
220 perror_with_name (_("Couldn't get registers"));
221 }
222
56be3814 223 mips64_supply_gregset (regcache,
28f5035f 224 (const mips64_elf_gregset_t *) &regs);
d37eb719
DJ
225 }
226
227 if (regno == -1 || is_fp)
228 {
229 mips64_elf_fpregset_t fp_regs;
230
231 if (ptrace (PTRACE_GETFPREGS, tid, 0L,
232 (PTRACE_TYPE_ARG3) &fp_regs) == -1)
233 {
234 if (errno == EIO)
235 {
236 have_ptrace_regsets = 0;
237 return;
238 }
239 perror_with_name (_("Couldn't get FP registers"));
240 }
241
56be3814 242 mips64_supply_fpregset (regcache,
28f5035f 243 (const mips64_elf_fpregset_t *) &fp_regs);
d37eb719
DJ
244 }
245}
246
247/* Store REGNO (or all registers if REGNO == -1) to the target
248 using PTRACE_SETREGS et al. */
249
250static void
56be3814 251mips64_linux_regsets_store_registers (const struct regcache *regcache, int regno)
d37eb719
DJ
252{
253 int is_fp;
254 int tid;
255
256 if (regno >= mips_regnum (current_gdbarch)->fp0
257 && regno <= mips_regnum (current_gdbarch)->fp0 + 32)
258 is_fp = 1;
259 else if (regno == mips_regnum (current_gdbarch)->fp_control_status)
260 is_fp = 1;
261 else if (regno == mips_regnum (current_gdbarch)->fp_implementation_revision)
262 is_fp = 1;
263 else
264 is_fp = 0;
265
266 tid = ptid_get_lwp (inferior_ptid);
267 if (tid == 0)
268 tid = ptid_get_pid (inferior_ptid);
269
270 if (regno == -1 || !is_fp)
271 {
272 mips64_elf_gregset_t regs;
273
274 if (ptrace (PTRACE_GETREGS, tid, 0L, (PTRACE_TYPE_ARG3) &regs) == -1)
275 perror_with_name (_("Couldn't get registers"));
276
56be3814 277 mips64_fill_gregset (regcache, &regs, regno);
d37eb719
DJ
278
279 if (ptrace (PTRACE_SETREGS, tid, 0L, (PTRACE_TYPE_ARG3) &regs) == -1)
280 perror_with_name (_("Couldn't set registers"));
281 }
282
283 if (regno == -1 || is_fp)
284 {
285 mips64_elf_fpregset_t fp_regs;
286
287 if (ptrace (PTRACE_GETFPREGS, tid, 0L,
288 (PTRACE_TYPE_ARG3) &fp_regs) == -1)
289 perror_with_name (_("Couldn't get FP registers"));
290
56be3814 291 mips64_fill_fpregset (regcache, &fp_regs, regno);
d37eb719
DJ
292
293 if (ptrace (PTRACE_SETFPREGS, tid, 0L,
294 (PTRACE_TYPE_ARG3) &fp_regs) == -1)
295 perror_with_name (_("Couldn't set FP registers"));
296 }
297}
298
299/* Fetch REGNO (or all registers if REGNO == -1) from the target
300 using any working method. */
301
302static void
56be3814 303mips64_linux_fetch_registers (struct regcache *regcache, int regnum)
d37eb719
DJ
304{
305 /* Unless we already know that PTRACE_GETREGS does not work, try it. */
306 if (have_ptrace_regsets)
56be3814 307 mips64_linux_regsets_fetch_registers (regcache, regnum);
d37eb719
DJ
308
309 /* If we know, or just found out, that PTRACE_GETREGS does not work, fall
310 back to PTRACE_PEEKUSER. */
311 if (!have_ptrace_regsets)
56be3814 312 super_fetch_registers (regcache, regnum);
d37eb719
DJ
313}
314
315/* Store REGNO (or all registers if REGNO == -1) to the target
316 using any working method. */
317
318static void
56be3814 319mips64_linux_store_registers (struct regcache *regcache, int regnum)
d37eb719
DJ
320{
321 /* Unless we already know that PTRACE_GETREGS does not work, try it. */
322 if (have_ptrace_regsets)
56be3814 323 mips64_linux_regsets_store_registers (regcache, regnum);
d37eb719
DJ
324
325 /* If we know, or just found out, that PTRACE_GETREGS does not work, fall
326 back to PTRACE_PEEKUSER. */
327 if (!have_ptrace_regsets)
56be3814 328 super_store_registers (regcache, regnum);
d37eb719
DJ
329}
330
910122bf
UW
331/* Return the address in the core dump or inferior of register
332 REGNO. */
333
334static CORE_ADDR
7714d83a 335mips_linux_register_u_offset (struct gdbarch *gdbarch, int regno, int store_p)
910122bf 336{
7714d83a
UW
337 if (mips_abi_regsize (gdbarch) == 8)
338 return mips64_linux_register_addr (gdbarch, regno, store_p);
dda0c97e 339 else
7714d83a 340 return mips_linux_register_addr (gdbarch, regno, store_p);
910122bf
UW
341}
342
822b6570
DJ
343static LONGEST (*super_xfer_partial) (struct target_ops *, enum target_object,
344 const char *, gdb_byte *, const gdb_byte *,
345 ULONGEST, LONGEST);
346
347static LONGEST
348mips_linux_xfer_partial (struct target_ops *ops,
349 enum target_object object,
350 const char *annex,
351 gdb_byte *readbuf, const gdb_byte *writebuf,
352 ULONGEST offset, LONGEST len)
353{
354 if (object == TARGET_OBJECT_AVAILABLE_FEATURES)
355 {
356 if (annex != NULL && strcmp (annex, "target.xml") == 0)
357 {
358 /* Report that target registers are a size we know for sure
359 that we can get from ptrace. */
360 if (_MIPS_SIM == _ABIO32)
361 annex = "mips-linux.xml";
362 else
363 annex = "mips64-linux.xml";
364 }
365
366 return xml_builtin_xfer_partial (annex, readbuf, writebuf, offset, len);
367 }
368
369 return super_xfer_partial (ops, object, annex, readbuf, writebuf,
370 offset, len);
371}
372
10d6c8cd
DJ
373void _initialize_mips_linux_nat (void);
374
375void
376_initialize_mips_linux_nat (void)
377{
910122bf 378 struct target_ops *t = linux_trad_target (mips_linux_register_u_offset);
d37eb719
DJ
379
380 super_fetch_registers = t->to_fetch_registers;
381 super_store_registers = t->to_store_registers;
382
383 t->to_fetch_registers = mips64_linux_fetch_registers;
384 t->to_store_registers = mips64_linux_store_registers;
385
822b6570
DJ
386 /* Override the default to_xfer_partial. */
387 super_xfer_partial = t->to_xfer_partial;
388 t->to_xfer_partial = mips_linux_xfer_partial;
389
f973ed9c 390 linux_nat_add_target (t);
10d6c8cd 391}