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