* ppc-tdep.h (struct gdbarch_tdep): Remove ppc_ev31_regnum member.
[deliverable/binutils-gdb.git] / gdb / arm-linux-nat.c
CommitLineData
ed9a39eb 1/* GNU/Linux on ARM native support.
9b254dd1 2 Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2008
10d6c8cd 3 Free Software Foundation, Inc.
ed9a39eb
JM
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
ed9a39eb
JM
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/>. */
ed9a39eb
JM
19
20#include "defs.h"
21#include "inferior.h"
22#include "gdbcore.h"
23#include "gdb_string.h"
4e052eda 24#include "regcache.h"
10d6c8cd
DJ
25#include "target.h"
26#include "linux-nat.h"
05a4558a 27#include "target-descriptions.h"
ed9a39eb 28
aeb98c60 29#include "arm-tdep.h"
cb587d83 30#include "arm-linux-tdep.h"
aeb98c60 31
ed9a39eb
JM
32#include <sys/user.h>
33#include <sys/ptrace.h>
34#include <sys/utsname.h>
41c49b06 35#include <sys/procfs.h>
ed9a39eb 36
c60c0f5f
MS
37/* Prototypes for supply_gregset etc. */
38#include "gregset.h"
39
9308fc88
DJ
40/* Defines ps_err_e, struct ps_prochandle. */
41#include "gdb_proc_service.h"
42
81adfced
DJ
43#include "features/arm-with-iwmmxt.c"
44
9308fc88
DJ
45#ifndef PTRACE_GET_THREAD_AREA
46#define PTRACE_GET_THREAD_AREA 22
47#endif
48
05a4558a
DJ
49#ifndef PTRACE_GETWMMXREGS
50#define PTRACE_GETWMMXREGS 18
51#define PTRACE_SETWMMXREGS 19
52#endif
53
54/* A flag for whether the WMMX registers are available. */
55static int arm_linux_has_wmmx_registers;
56
ed9a39eb
JM
57extern int arm_apcs_32;
58
ed9a39eb 59/* The following variables are used to determine the version of the
fdf39c9a 60 underlying GNU/Linux operating system. Examples:
ed9a39eb 61
fdf39c9a 62 GNU/Linux 2.0.35 GNU/Linux 2.2.12
ed9a39eb
JM
63 os_version = 0x00020023 os_version = 0x0002020c
64 os_major = 2 os_major = 2
65 os_minor = 0 os_minor = 2
66 os_release = 35 os_release = 12
67
68 Note: os_version = (os_major << 16) | (os_minor << 8) | os_release
69
70 These are initialized using get_linux_version() from
71 _initialize_arm_linux_nat(). */
72
73static unsigned int os_version, os_major, os_minor, os_release;
74
fdf39c9a 75/* On GNU/Linux, threads are implemented as pseudo-processes, in which
41c49b06 76 case we may be tracing more than one process at a time. In that
39f77062 77 case, inferior_ptid will contain the main process ID and the
fdf39c9a
RE
78 individual thread (process) ID. get_thread_id () is used to get
79 the thread id if it's available, and the process id otherwise. */
41c49b06
SB
80
81int
39f77062 82get_thread_id (ptid_t ptid)
41c49b06 83{
39f77062
KB
84 int tid = TIDGET (ptid);
85 if (0 == tid)
86 tid = PIDGET (ptid);
41c49b06
SB
87 return tid;
88}
05a4558a 89#define GET_THREAD_ID(PTID) get_thread_id (PTID)
41c49b06 90
41c49b06 91/* Get the value of a particular register from the floating point
c6b92abd 92 state of the process and store it into regcache. */
41c49b06
SB
93
94static void
56be3814 95fetch_fpregister (struct regcache *regcache, int regno)
41c49b06
SB
96{
97 int ret, tid;
cb587d83 98 gdb_byte fp[ARM_LINUX_SIZEOF_NWFPE];
41c49b06
SB
99
100 /* Get the thread id for the ptrace call. */
39f77062 101 tid = GET_THREAD_ID (inferior_ptid);
41c49b06
SB
102
103 /* Read the floating point state. */
cb587d83 104 ret = ptrace (PT_GETFPREGS, tid, 0, fp);
41c49b06
SB
105 if (ret < 0)
106 {
edefbb7c 107 warning (_("Unable to fetch floating point register."));
41c49b06
SB
108 return;
109 }
110
111 /* Fetch fpsr. */
34e8f22d 112 if (ARM_FPS_REGNUM == regno)
56be3814 113 regcache_raw_supply (regcache, ARM_FPS_REGNUM,
cb587d83 114 fp + NWFPE_FPSR_OFFSET);
41c49b06
SB
115
116 /* Fetch the floating point register. */
34e8f22d 117 if (regno >= ARM_F0_REGNUM && regno <= ARM_F7_REGNUM)
56be3814 118 supply_nwfpe_register (regcache, regno, fp);
41c49b06
SB
119}
120
121/* Get the whole floating point state of the process and store it
c6b92abd 122 into regcache. */
ed9a39eb
JM
123
124static void
56be3814 125fetch_fpregs (struct regcache *regcache)
ed9a39eb 126{
41c49b06 127 int ret, regno, tid;
cb587d83 128 gdb_byte fp[ARM_LINUX_SIZEOF_NWFPE];
ed9a39eb 129
41c49b06 130 /* Get the thread id for the ptrace call. */
39f77062 131 tid = GET_THREAD_ID (inferior_ptid);
41c49b06 132
ed9a39eb 133 /* Read the floating point state. */
cb587d83 134 ret = ptrace (PT_GETFPREGS, tid, 0, fp);
ed9a39eb
JM
135 if (ret < 0)
136 {
edefbb7c 137 warning (_("Unable to fetch the floating point registers."));
ed9a39eb
JM
138 return;
139 }
140
141 /* Fetch fpsr. */
56be3814 142 regcache_raw_supply (regcache, ARM_FPS_REGNUM,
cb587d83 143 fp + NWFPE_FPSR_OFFSET);
ed9a39eb
JM
144
145 /* Fetch the floating point registers. */
34e8f22d 146 for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++)
56be3814 147 supply_nwfpe_register (regcache, regno, fp);
ed9a39eb
JM
148}
149
41c49b06 150/* Save a particular register into the floating point state of the
c6b92abd 151 process using the contents from regcache. */
41c49b06
SB
152
153static void
56be3814 154store_fpregister (const struct regcache *regcache, int regno)
41c49b06
SB
155{
156 int ret, tid;
cb587d83 157 gdb_byte fp[ARM_LINUX_SIZEOF_NWFPE];
41c49b06
SB
158
159 /* Get the thread id for the ptrace call. */
39f77062 160 tid = GET_THREAD_ID (inferior_ptid);
41c49b06
SB
161
162 /* Read the floating point state. */
cb587d83 163 ret = ptrace (PT_GETFPREGS, tid, 0, fp);
41c49b06
SB
164 if (ret < 0)
165 {
edefbb7c 166 warning (_("Unable to fetch the floating point registers."));
41c49b06
SB
167 return;
168 }
169
170 /* Store fpsr. */
56be3814
UW
171 if (ARM_FPS_REGNUM == regno && regcache_valid_p (regcache, ARM_FPS_REGNUM))
172 regcache_raw_collect (regcache, ARM_FPS_REGNUM, fp + NWFPE_FPSR_OFFSET);
41c49b06
SB
173
174 /* Store the floating point register. */
34e8f22d 175 if (regno >= ARM_F0_REGNUM && regno <= ARM_F7_REGNUM)
56be3814 176 collect_nwfpe_register (regcache, regno, fp);
41c49b06 177
cb587d83 178 ret = ptrace (PTRACE_SETFPREGS, tid, 0, fp);
41c49b06
SB
179 if (ret < 0)
180 {
edefbb7c 181 warning (_("Unable to store floating point register."));
41c49b06
SB
182 return;
183 }
184}
185
ed9a39eb 186/* Save the whole floating point state of the process using
c6b92abd 187 the contents from regcache. */
ed9a39eb
JM
188
189static void
56be3814 190store_fpregs (const struct regcache *regcache)
ed9a39eb 191{
41c49b06 192 int ret, regno, tid;
cb587d83 193 gdb_byte fp[ARM_LINUX_SIZEOF_NWFPE];
ed9a39eb 194
41c49b06 195 /* Get the thread id for the ptrace call. */
39f77062 196 tid = GET_THREAD_ID (inferior_ptid);
41c49b06
SB
197
198 /* Read the floating point state. */
cb587d83 199 ret = ptrace (PT_GETFPREGS, tid, 0, fp);
41c49b06
SB
200 if (ret < 0)
201 {
edefbb7c 202 warning (_("Unable to fetch the floating point registers."));
41c49b06
SB
203 return;
204 }
205
ed9a39eb 206 /* Store fpsr. */
56be3814
UW
207 if (regcache_valid_p (regcache, ARM_FPS_REGNUM))
208 regcache_raw_collect (regcache, ARM_FPS_REGNUM, fp + NWFPE_FPSR_OFFSET);
ed9a39eb
JM
209
210 /* Store the floating point registers. */
34e8f22d 211 for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++)
56be3814
UW
212 if (regcache_valid_p (regcache, regno))
213 collect_nwfpe_register (regcache, regno, fp);
ed9a39eb 214
cb587d83 215 ret = ptrace (PTRACE_SETFPREGS, tid, 0, fp);
ed9a39eb
JM
216 if (ret < 0)
217 {
edefbb7c 218 warning (_("Unable to store floating point registers."));
ed9a39eb
JM
219 return;
220 }
221}
222
41c49b06 223/* Fetch a general register of the process and store into
c6b92abd 224 regcache. */
41c49b06
SB
225
226static void
56be3814 227fetch_register (struct regcache *regcache, int regno)
41c49b06
SB
228{
229 int ret, tid;
c2152441 230 elf_gregset_t regs;
41c49b06
SB
231
232 /* Get the thread id for the ptrace call. */
39f77062 233 tid = GET_THREAD_ID (inferior_ptid);
41c49b06
SB
234
235 ret = ptrace (PTRACE_GETREGS, tid, 0, &regs);
236 if (ret < 0)
237 {
edefbb7c 238 warning (_("Unable to fetch general register."));
41c49b06
SB
239 return;
240 }
241
34e8f22d 242 if (regno >= ARM_A1_REGNUM && regno < ARM_PC_REGNUM)
56be3814 243 regcache_raw_supply (regcache, regno, (char *) &regs[regno]);
41c49b06 244
34e8f22d 245 if (ARM_PS_REGNUM == regno)
41c49b06
SB
246 {
247 if (arm_apcs_32)
56be3814 248 regcache_raw_supply (regcache, ARM_PS_REGNUM,
23a6d369 249 (char *) &regs[ARM_CPSR_REGNUM]);
41c49b06 250 else
56be3814 251 regcache_raw_supply (regcache, ARM_PS_REGNUM,
23a6d369 252 (char *) &regs[ARM_PC_REGNUM]);
41c49b06
SB
253 }
254
34e8f22d 255 if (ARM_PC_REGNUM == regno)
41c49b06 256 {
bf6ae464 257 regs[ARM_PC_REGNUM] = gdbarch_addr_bits_remove
08790784
UW
258 (get_regcache_arch (regcache),
259 regs[ARM_PC_REGNUM]);
56be3814 260 regcache_raw_supply (regcache, ARM_PC_REGNUM,
23a6d369 261 (char *) &regs[ARM_PC_REGNUM]);
41c49b06
SB
262 }
263}
264
ed9a39eb 265/* Fetch all general registers of the process and store into
c6b92abd 266 regcache. */
ed9a39eb
JM
267
268static void
56be3814 269fetch_regs (struct regcache *regcache)
ed9a39eb 270{
41c49b06 271 int ret, regno, tid;
c2152441 272 elf_gregset_t regs;
ed9a39eb 273
41c49b06 274 /* Get the thread id for the ptrace call. */
39f77062 275 tid = GET_THREAD_ID (inferior_ptid);
41c49b06
SB
276
277 ret = ptrace (PTRACE_GETREGS, tid, 0, &regs);
ed9a39eb
JM
278 if (ret < 0)
279 {
edefbb7c 280 warning (_("Unable to fetch general registers."));
ed9a39eb
JM
281 return;
282 }
283
34e8f22d 284 for (regno = ARM_A1_REGNUM; regno < ARM_PC_REGNUM; regno++)
56be3814 285 regcache_raw_supply (regcache, regno, (char *) &regs[regno]);
ed9a39eb
JM
286
287 if (arm_apcs_32)
56be3814 288 regcache_raw_supply (regcache, ARM_PS_REGNUM,
23a6d369 289 (char *) &regs[ARM_CPSR_REGNUM]);
ed9a39eb 290 else
56be3814 291 regcache_raw_supply (regcache, ARM_PS_REGNUM,
23a6d369 292 (char *) &regs[ARM_PC_REGNUM]);
ed9a39eb 293
bf6ae464 294 regs[ARM_PC_REGNUM] = gdbarch_addr_bits_remove
08790784 295 (get_regcache_arch (regcache), regs[ARM_PC_REGNUM]);
56be3814 296 regcache_raw_supply (regcache, ARM_PC_REGNUM,
23a6d369 297 (char *) &regs[ARM_PC_REGNUM]);
ed9a39eb
JM
298}
299
300/* Store all general registers of the process from the values in
c6b92abd 301 regcache. */
ed9a39eb 302
41c49b06 303static void
56be3814 304store_register (const struct regcache *regcache, int regno)
41c49b06
SB
305{
306 int ret, tid;
c2152441 307 elf_gregset_t regs;
41c49b06 308
56be3814 309 if (!regcache_valid_p (regcache, regno))
41c49b06
SB
310 return;
311
312 /* Get the thread id for the ptrace call. */
39f77062 313 tid = GET_THREAD_ID (inferior_ptid);
41c49b06
SB
314
315 /* Get the general registers from the process. */
316 ret = ptrace (PTRACE_GETREGS, tid, 0, &regs);
317 if (ret < 0)
318 {
edefbb7c 319 warning (_("Unable to fetch general registers."));
41c49b06
SB
320 return;
321 }
322
34e8f22d 323 if (regno >= ARM_A1_REGNUM && regno <= ARM_PC_REGNUM)
56be3814 324 regcache_raw_collect (regcache, regno, (char *) &regs[regno]);
adb8a87c 325 else if (arm_apcs_32 && regno == ARM_PS_REGNUM)
56be3814 326 regcache_raw_collect (regcache, regno,
adb8a87c
DJ
327 (char *) &regs[ARM_CPSR_REGNUM]);
328 else if (!arm_apcs_32 && regno == ARM_PS_REGNUM)
56be3814 329 regcache_raw_collect (regcache, ARM_PC_REGNUM,
adb8a87c 330 (char *) &regs[ARM_PC_REGNUM]);
41c49b06
SB
331
332 ret = ptrace (PTRACE_SETREGS, tid, 0, &regs);
333 if (ret < 0)
334 {
edefbb7c 335 warning (_("Unable to store general register."));
41c49b06
SB
336 return;
337 }
338}
339
ed9a39eb 340static void
56be3814 341store_regs (const struct regcache *regcache)
ed9a39eb 342{
41c49b06 343 int ret, regno, tid;
c2152441 344 elf_gregset_t regs;
ed9a39eb 345
41c49b06 346 /* Get the thread id for the ptrace call. */
39f77062 347 tid = GET_THREAD_ID (inferior_ptid);
41c49b06
SB
348
349 /* Fetch the general registers. */
350 ret = ptrace (PTRACE_GETREGS, tid, 0, &regs);
ed9a39eb
JM
351 if (ret < 0)
352 {
edefbb7c 353 warning (_("Unable to fetch general registers."));
ed9a39eb
JM
354 return;
355 }
356
34e8f22d 357 for (regno = ARM_A1_REGNUM; regno <= ARM_PC_REGNUM; regno++)
ed9a39eb 358 {
56be3814
UW
359 if (regcache_valid_p (regcache, regno))
360 regcache_raw_collect (regcache, regno, (char *) &regs[regno]);
ed9a39eb
JM
361 }
362
56be3814
UW
363 if (arm_apcs_32 && regcache_valid_p (regcache, ARM_PS_REGNUM))
364 regcache_raw_collect (regcache, ARM_PS_REGNUM,
adb8a87c
DJ
365 (char *) &regs[ARM_CPSR_REGNUM]);
366
41c49b06 367 ret = ptrace (PTRACE_SETREGS, tid, 0, &regs);
ed9a39eb
JM
368
369 if (ret < 0)
370 {
edefbb7c 371 warning (_("Unable to store general registers."));
ed9a39eb
JM
372 return;
373 }
374}
375
05a4558a
DJ
376/* Fetch all WMMX registers of the process and store into
377 regcache. */
378
379#define IWMMXT_REGS_SIZE (16 * 8 + 6 * 4)
380
381static void
56be3814 382fetch_wmmx_regs (struct regcache *regcache)
05a4558a
DJ
383{
384 char regbuf[IWMMXT_REGS_SIZE];
385 int ret, regno, tid;
386
387 /* Get the thread id for the ptrace call. */
388 tid = GET_THREAD_ID (inferior_ptid);
389
390 ret = ptrace (PTRACE_GETWMMXREGS, tid, 0, regbuf);
391 if (ret < 0)
392 {
393 warning (_("Unable to fetch WMMX registers."));
394 return;
395 }
396
397 for (regno = 0; regno < 16; regno++)
56be3814 398 regcache_raw_supply (regcache, regno + ARM_WR0_REGNUM,
05a4558a
DJ
399 &regbuf[regno * 8]);
400
401 for (regno = 0; regno < 2; regno++)
56be3814 402 regcache_raw_supply (regcache, regno + ARM_WCSSF_REGNUM,
05a4558a
DJ
403 &regbuf[16 * 8 + regno * 4]);
404
405 for (regno = 0; regno < 4; regno++)
56be3814 406 regcache_raw_supply (regcache, regno + ARM_WCGR0_REGNUM,
05a4558a
DJ
407 &regbuf[16 * 8 + 2 * 4 + regno * 4]);
408}
409
410static void
56be3814 411store_wmmx_regs (const struct regcache *regcache)
05a4558a
DJ
412{
413 char regbuf[IWMMXT_REGS_SIZE];
414 int ret, regno, tid;
415
416 /* Get the thread id for the ptrace call. */
417 tid = GET_THREAD_ID (inferior_ptid);
418
419 ret = ptrace (PTRACE_GETWMMXREGS, tid, 0, regbuf);
420 if (ret < 0)
421 {
422 warning (_("Unable to fetch WMMX registers."));
423 return;
424 }
425
426 for (regno = 0; regno < 16; regno++)
56be3814
UW
427 if (regcache_valid_p (regcache, regno + ARM_WR0_REGNUM))
428 regcache_raw_collect (regcache, regno + ARM_WR0_REGNUM,
05a4558a
DJ
429 &regbuf[regno * 8]);
430
431 for (regno = 0; regno < 2; regno++)
56be3814
UW
432 if (regcache_valid_p (regcache, regno + ARM_WCSSF_REGNUM))
433 regcache_raw_collect (regcache, regno + ARM_WCSSF_REGNUM,
05a4558a
DJ
434 &regbuf[16 * 8 + regno * 4]);
435
436 for (regno = 0; regno < 4; regno++)
56be3814
UW
437 if (regcache_valid_p (regcache, regno + ARM_WCGR0_REGNUM))
438 regcache_raw_collect (regcache, regno + ARM_WCGR0_REGNUM,
05a4558a
DJ
439 &regbuf[16 * 8 + 2 * 4 + regno * 4]);
440
441 ret = ptrace (PTRACE_SETWMMXREGS, tid, 0, regbuf);
442
443 if (ret < 0)
444 {
445 warning (_("Unable to store WMMX registers."));
446 return;
447 }
448}
449
ed9a39eb
JM
450/* Fetch registers from the child process. Fetch all registers if
451 regno == -1, otherwise fetch all general registers or all floating
452 point registers depending upon the value of regno. */
453
10d6c8cd 454static void
56be3814 455arm_linux_fetch_inferior_registers (struct regcache *regcache, int regno)
ed9a39eb 456{
41c49b06
SB
457 if (-1 == regno)
458 {
56be3814
UW
459 fetch_regs (regcache);
460 fetch_fpregs (regcache);
05a4558a 461 if (arm_linux_has_wmmx_registers)
56be3814 462 fetch_wmmx_regs (regcache);
41c49b06
SB
463 }
464 else
465 {
05a4558a 466 if (regno < ARM_F0_REGNUM || regno == ARM_PS_REGNUM)
56be3814 467 fetch_register (regcache, regno);
05a4558a 468 else if (regno >= ARM_F0_REGNUM && regno <= ARM_FPS_REGNUM)
56be3814 469 fetch_fpregister (regcache, regno);
05a4558a
DJ
470 else if (arm_linux_has_wmmx_registers
471 && regno >= ARM_WR0_REGNUM && regno <= ARM_WCGR7_REGNUM)
56be3814 472 fetch_wmmx_regs (regcache);
41c49b06 473 }
ed9a39eb
JM
474}
475
476/* Store registers back into the inferior. Store all registers if
477 regno == -1, otherwise store all general registers or all floating
478 point registers depending upon the value of regno. */
479
10d6c8cd 480static void
56be3814 481arm_linux_store_inferior_registers (struct regcache *regcache, int regno)
ed9a39eb 482{
41c49b06
SB
483 if (-1 == regno)
484 {
56be3814
UW
485 store_regs (regcache);
486 store_fpregs (regcache);
05a4558a 487 if (arm_linux_has_wmmx_registers)
56be3814 488 store_wmmx_regs (regcache);
41c49b06
SB
489 }
490 else
491 {
05a4558a 492 if (regno < ARM_F0_REGNUM || regno == ARM_PS_REGNUM)
56be3814 493 store_register (regcache, regno);
05a4558a 494 else if ((regno >= ARM_F0_REGNUM) && (regno <= ARM_FPS_REGNUM))
56be3814 495 store_fpregister (regcache, regno);
05a4558a
DJ
496 else if (arm_linux_has_wmmx_registers
497 && regno >= ARM_WR0_REGNUM && regno <= ARM_WCGR7_REGNUM)
56be3814 498 store_wmmx_regs (regcache);
41c49b06 499 }
ed9a39eb
JM
500}
501
cb587d83
DJ
502/* Wrapper functions for the standard regset handling, used by
503 thread debugging. */
41c49b06
SB
504
505void
7f7fe91e
UW
506fill_gregset (const struct regcache *regcache,
507 gdb_gregset_t *gregsetp, int regno)
41c49b06 508{
7f7fe91e 509 arm_linux_collect_gregset (NULL, regcache, regno, gregsetp, 0);
41c49b06
SB
510}
511
41c49b06 512void
7f7fe91e 513supply_gregset (struct regcache *regcache, const gdb_gregset_t *gregsetp)
41c49b06 514{
7f7fe91e 515 arm_linux_supply_gregset (NULL, regcache, -1, gregsetp, 0);
41c49b06
SB
516}
517
41c49b06 518void
7f7fe91e
UW
519fill_fpregset (const struct regcache *regcache,
520 gdb_fpregset_t *fpregsetp, int regno)
41c49b06 521{
7f7fe91e 522 arm_linux_collect_nwfpe (NULL, regcache, regno, fpregsetp, 0);
41c49b06
SB
523}
524
525/* Fill GDB's register array with the floating-point register values
526 in *fpregsetp. */
527
528void
7f7fe91e 529supply_fpregset (struct regcache *regcache, const gdb_fpregset_t *fpregsetp)
ed9a39eb 530{
7f7fe91e 531 arm_linux_supply_nwfpe (NULL, regcache, -1, fpregsetp, 0);
ed9a39eb
JM
532}
533
9308fc88
DJ
534/* Fetch the thread-local storage pointer for libthread_db. */
535
536ps_err_e
537ps_get_thread_area (const struct ps_prochandle *ph,
538 lwpid_t lwpid, int idx, void **base)
539{
540 if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0)
541 return PS_ERR;
542
543 /* IDX is the bias from the thread pointer to the beginning of the
544 thread descriptor. It has to be subtracted due to implementation
545 quirks in libthread_db. */
546 *base = (void *) ((char *)*base - idx);
547
548 return PS_OK;
549}
550
ed9a39eb
JM
551static unsigned int
552get_linux_version (unsigned int *vmajor,
553 unsigned int *vminor,
554 unsigned int *vrelease)
555{
556 struct utsname info;
557 char *pmajor, *pminor, *prelease, *tail;
558
559 if (-1 == uname (&info))
560 {
edefbb7c 561 warning (_("Unable to determine GNU/Linux version."));
ed9a39eb
JM
562 return -1;
563 }
564
565 pmajor = strtok (info.release, ".");
566 pminor = strtok (NULL, ".");
567 prelease = strtok (NULL, ".");
568
569 *vmajor = (unsigned int) strtoul (pmajor, &tail, 0);
570 *vminor = (unsigned int) strtoul (pminor, &tail, 0);
571 *vrelease = (unsigned int) strtoul (prelease, &tail, 0);
572
573 return ((*vmajor << 16) | (*vminor << 8) | *vrelease);
574}
575
81adfced
DJ
576static const struct target_desc *
577arm_linux_read_description (struct target_ops *ops)
05a4558a 578{
81adfced
DJ
579 int ret;
580 char regbuf[IWMMXT_REGS_SIZE];
05a4558a 581
81adfced
DJ
582 ret = ptrace (PTRACE_GETWMMXREGS, GET_THREAD_ID (inferior_ptid),
583 0, regbuf);
584 if (ret < 0)
585 arm_linux_has_wmmx_registers = 0;
586 else
587 arm_linux_has_wmmx_registers = 1;
588
589 if (arm_linux_has_wmmx_registers)
590 return tdesc_arm_with_iwmmxt;
591 else
592 return NULL;
05a4558a
DJ
593}
594
10d6c8cd
DJ
595void _initialize_arm_linux_nat (void);
596
ed9a39eb
JM
597void
598_initialize_arm_linux_nat (void)
599{
10d6c8cd
DJ
600 struct target_ops *t;
601
ed9a39eb 602 os_version = get_linux_version (&os_major, &os_minor, &os_release);
10d6c8cd
DJ
603
604 /* Fill in the generic GNU/Linux methods. */
605 t = linux_target ();
606
607 /* Add our register access methods. */
608 t->to_fetch_registers = arm_linux_fetch_inferior_registers;
609 t->to_store_registers = arm_linux_store_inferior_registers;
610
81adfced 611 t->to_read_description = arm_linux_read_description;
05a4558a 612
10d6c8cd 613 /* Register the target. */
f973ed9c 614 linux_nat_add_target (t);
81adfced
DJ
615
616 /* Initialize the standard target descriptions. */
617 initialize_tdesc_arm_with_iwmmxt ();
ed9a39eb 618}
This page took 0.63422 seconds and 4 git commands to generate.