2007-10-10 Markus Deuling <deuling@de.ibm.com>
[deliverable/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
2eb4d78b 63 if (regno < 0 || regno >= gdbarch_num_regs (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
2eb4d78b 98 if (regno < 0 || regno >= gdbarch_num_regs (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))
2eb4d78b 105 regaddr = MIPS64_FPR_BASE + (regno - gdbarch_fp0_regnum (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 149{
2eb4d78b 150 if (mips_isa_regsize (get_regcache_arch (regcache)) == 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 159{
2eb4d78b 160 if (mips_isa_regsize (get_regcache_arch (regcache)) == 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 168{
2eb4d78b 169 if (mips_isa_regsize (get_regcache_arch (regcache)) == 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 178{
2eb4d78b 179 if (mips_isa_regsize (get_regcache_arch (regcache)) == 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 191{
2eb4d78b 192 struct gdbarch *gdbarch = get_regcache_arch (regcache);
d37eb719
DJ
193 int is_fp;
194 int tid;
195
2eb4d78b
UW
196 if (regno >= mips_regnum (gdbarch)->fp0
197 && regno <= mips_regnum (gdbarch)->fp0 + 32)
d37eb719 198 is_fp = 1;
2eb4d78b 199 else if (regno == mips_regnum (gdbarch)->fp_control_status)
d37eb719 200 is_fp = 1;
2eb4d78b 201 else if (regno == mips_regnum (gdbarch)->fp_implementation_revision)
d37eb719
DJ
202 is_fp = 1;
203 else
204 is_fp = 0;
205
206 tid = ptid_get_lwp (inferior_ptid);
207 if (tid == 0)
208 tid = ptid_get_pid (inferior_ptid);
209
210 if (regno == -1 || !is_fp)
211 {
212 mips64_elf_gregset_t regs;
213
214 if (ptrace (PTRACE_GETREGS, tid, 0L, (PTRACE_TYPE_ARG3) &regs) == -1)
215 {
216 if (errno == EIO)
217 {
218 have_ptrace_regsets = 0;
219 return;
220 }
221 perror_with_name (_("Couldn't get registers"));
222 }
223
56be3814 224 mips64_supply_gregset (regcache,
28f5035f 225 (const mips64_elf_gregset_t *) &regs);
d37eb719
DJ
226 }
227
228 if (regno == -1 || is_fp)
229 {
230 mips64_elf_fpregset_t fp_regs;
231
232 if (ptrace (PTRACE_GETFPREGS, tid, 0L,
233 (PTRACE_TYPE_ARG3) &fp_regs) == -1)
234 {
235 if (errno == EIO)
236 {
237 have_ptrace_regsets = 0;
238 return;
239 }
240 perror_with_name (_("Couldn't get FP registers"));
241 }
242
56be3814 243 mips64_supply_fpregset (regcache,
28f5035f 244 (const mips64_elf_fpregset_t *) &fp_regs);
d37eb719
DJ
245 }
246}
247
248/* Store REGNO (or all registers if REGNO == -1) to the target
249 using PTRACE_SETREGS et al. */
250
251static void
56be3814 252mips64_linux_regsets_store_registers (const struct regcache *regcache, int regno)
d37eb719 253{
2eb4d78b 254 struct gdbarch *gdbarch = get_regcache_arch (regcache);
d37eb719
DJ
255 int is_fp;
256 int tid;
257
2eb4d78b
UW
258 if (regno >= mips_regnum (gdbarch)->fp0
259 && regno <= mips_regnum (gdbarch)->fp0 + 32)
d37eb719 260 is_fp = 1;
2eb4d78b 261 else if (regno == mips_regnum (gdbarch)->fp_control_status)
d37eb719 262 is_fp = 1;
2eb4d78b 263 else if (regno == mips_regnum (gdbarch)->fp_implementation_revision)
d37eb719
DJ
264 is_fp = 1;
265 else
266 is_fp = 0;
267
268 tid = ptid_get_lwp (inferior_ptid);
269 if (tid == 0)
270 tid = ptid_get_pid (inferior_ptid);
271
272 if (regno == -1 || !is_fp)
273 {
274 mips64_elf_gregset_t regs;
275
276 if (ptrace (PTRACE_GETREGS, tid, 0L, (PTRACE_TYPE_ARG3) &regs) == -1)
277 perror_with_name (_("Couldn't get registers"));
278
56be3814 279 mips64_fill_gregset (regcache, &regs, regno);
d37eb719
DJ
280
281 if (ptrace (PTRACE_SETREGS, tid, 0L, (PTRACE_TYPE_ARG3) &regs) == -1)
282 perror_with_name (_("Couldn't set registers"));
283 }
284
285 if (regno == -1 || is_fp)
286 {
287 mips64_elf_fpregset_t fp_regs;
288
289 if (ptrace (PTRACE_GETFPREGS, tid, 0L,
290 (PTRACE_TYPE_ARG3) &fp_regs) == -1)
291 perror_with_name (_("Couldn't get FP registers"));
292
56be3814 293 mips64_fill_fpregset (regcache, &fp_regs, regno);
d37eb719
DJ
294
295 if (ptrace (PTRACE_SETFPREGS, tid, 0L,
296 (PTRACE_TYPE_ARG3) &fp_regs) == -1)
297 perror_with_name (_("Couldn't set FP registers"));
298 }
299}
300
301/* Fetch REGNO (or all registers if REGNO == -1) from the target
302 using any working method. */
303
304static void
56be3814 305mips64_linux_fetch_registers (struct regcache *regcache, int regnum)
d37eb719
DJ
306{
307 /* Unless we already know that PTRACE_GETREGS does not work, try it. */
308 if (have_ptrace_regsets)
56be3814 309 mips64_linux_regsets_fetch_registers (regcache, regnum);
d37eb719
DJ
310
311 /* If we know, or just found out, that PTRACE_GETREGS does not work, fall
312 back to PTRACE_PEEKUSER. */
313 if (!have_ptrace_regsets)
56be3814 314 super_fetch_registers (regcache, regnum);
d37eb719
DJ
315}
316
317/* Store REGNO (or all registers if REGNO == -1) to the target
318 using any working method. */
319
320static void
56be3814 321mips64_linux_store_registers (struct regcache *regcache, int regnum)
d37eb719
DJ
322{
323 /* Unless we already know that PTRACE_GETREGS does not work, try it. */
324 if (have_ptrace_regsets)
56be3814 325 mips64_linux_regsets_store_registers (regcache, regnum);
d37eb719
DJ
326
327 /* If we know, or just found out, that PTRACE_GETREGS does not work, fall
328 back to PTRACE_PEEKUSER. */
329 if (!have_ptrace_regsets)
56be3814 330 super_store_registers (regcache, regnum);
d37eb719
DJ
331}
332
910122bf
UW
333/* Return the address in the core dump or inferior of register
334 REGNO. */
335
336static CORE_ADDR
7714d83a 337mips_linux_register_u_offset (struct gdbarch *gdbarch, int regno, int store_p)
910122bf 338{
7714d83a
UW
339 if (mips_abi_regsize (gdbarch) == 8)
340 return mips64_linux_register_addr (gdbarch, regno, store_p);
dda0c97e 341 else
7714d83a 342 return mips_linux_register_addr (gdbarch, regno, store_p);
910122bf
UW
343}
344
822b6570
DJ
345static LONGEST (*super_xfer_partial) (struct target_ops *, enum target_object,
346 const char *, gdb_byte *, const gdb_byte *,
347 ULONGEST, LONGEST);
348
349static LONGEST
350mips_linux_xfer_partial (struct target_ops *ops,
351 enum target_object object,
352 const char *annex,
353 gdb_byte *readbuf, const gdb_byte *writebuf,
354 ULONGEST offset, LONGEST len)
355{
356 if (object == TARGET_OBJECT_AVAILABLE_FEATURES)
357 {
358 if (annex != NULL && strcmp (annex, "target.xml") == 0)
359 {
360 /* Report that target registers are a size we know for sure
361 that we can get from ptrace. */
362 if (_MIPS_SIM == _ABIO32)
363 annex = "mips-linux.xml";
364 else
365 annex = "mips64-linux.xml";
366 }
367
368 return xml_builtin_xfer_partial (annex, readbuf, writebuf, offset, len);
369 }
370
371 return super_xfer_partial (ops, object, annex, readbuf, writebuf,
372 offset, len);
373}
374
10d6c8cd
DJ
375void _initialize_mips_linux_nat (void);
376
377void
378_initialize_mips_linux_nat (void)
379{
910122bf 380 struct target_ops *t = linux_trad_target (mips_linux_register_u_offset);
d37eb719
DJ
381
382 super_fetch_registers = t->to_fetch_registers;
383 super_store_registers = t->to_store_registers;
384
385 t->to_fetch_registers = mips64_linux_fetch_registers;
386 t->to_store_registers = mips64_linux_store_registers;
387
822b6570
DJ
388 /* Override the default to_xfer_partial. */
389 super_xfer_partial = t->to_xfer_partial;
390 t->to_xfer_partial = mips_linux_xfer_partial;
391
f973ed9c 392 linux_nat_add_target (t);
10d6c8cd 393}
This page took 0.568426 seconds and 4 git commands to generate.