* utils.c (fputs_maybe_filtered): Check if there's already a top
[deliverable/binutils-gdb.git] / gdb / arm-linux-nat.c
CommitLineData
ed9a39eb 1/* GNU/Linux on ARM native support.
4c38e0a4
JB
2 Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2008, 2009,
3 2010 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,
17c12639 249 (char *) &regs[ARM_CPSR_GREGNUM]);
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,
17c12639 289 (char *) &regs[ARM_CPSR_GREGNUM]);
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,
17c12639 327 (char *) &regs[ARM_CPSR_GREGNUM]);
adb8a87c 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,
17c12639 365 (char *) &regs[ARM_CPSR_GREGNUM]);
adb8a87c 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
28439f5e
PA
455arm_linux_fetch_inferior_registers (struct target_ops *ops,
456 struct regcache *regcache, int regno)
ed9a39eb 457{
41c49b06
SB
458 if (-1 == regno)
459 {
56be3814
UW
460 fetch_regs (regcache);
461 fetch_fpregs (regcache);
05a4558a 462 if (arm_linux_has_wmmx_registers)
56be3814 463 fetch_wmmx_regs (regcache);
41c49b06
SB
464 }
465 else
466 {
05a4558a 467 if (regno < ARM_F0_REGNUM || regno == ARM_PS_REGNUM)
56be3814 468 fetch_register (regcache, regno);
05a4558a 469 else if (regno >= ARM_F0_REGNUM && regno <= ARM_FPS_REGNUM)
56be3814 470 fetch_fpregister (regcache, regno);
05a4558a
DJ
471 else if (arm_linux_has_wmmx_registers
472 && regno >= ARM_WR0_REGNUM && regno <= ARM_WCGR7_REGNUM)
56be3814 473 fetch_wmmx_regs (regcache);
41c49b06 474 }
ed9a39eb
JM
475}
476
477/* Store registers back into the inferior. Store all registers if
478 regno == -1, otherwise store all general registers or all floating
479 point registers depending upon the value of regno. */
480
10d6c8cd 481static void
28439f5e
PA
482arm_linux_store_inferior_registers (struct target_ops *ops,
483 struct regcache *regcache, int regno)
ed9a39eb 484{
41c49b06
SB
485 if (-1 == regno)
486 {
56be3814
UW
487 store_regs (regcache);
488 store_fpregs (regcache);
05a4558a 489 if (arm_linux_has_wmmx_registers)
56be3814 490 store_wmmx_regs (regcache);
41c49b06
SB
491 }
492 else
493 {
05a4558a 494 if (regno < ARM_F0_REGNUM || regno == ARM_PS_REGNUM)
56be3814 495 store_register (regcache, regno);
05a4558a 496 else if ((regno >= ARM_F0_REGNUM) && (regno <= ARM_FPS_REGNUM))
56be3814 497 store_fpregister (regcache, regno);
05a4558a
DJ
498 else if (arm_linux_has_wmmx_registers
499 && regno >= ARM_WR0_REGNUM && regno <= ARM_WCGR7_REGNUM)
56be3814 500 store_wmmx_regs (regcache);
41c49b06 501 }
ed9a39eb
JM
502}
503
cb587d83
DJ
504/* Wrapper functions for the standard regset handling, used by
505 thread debugging. */
41c49b06
SB
506
507void
7f7fe91e
UW
508fill_gregset (const struct regcache *regcache,
509 gdb_gregset_t *gregsetp, int regno)
41c49b06 510{
7f7fe91e 511 arm_linux_collect_gregset (NULL, regcache, regno, gregsetp, 0);
41c49b06
SB
512}
513
41c49b06 514void
7f7fe91e 515supply_gregset (struct regcache *regcache, const gdb_gregset_t *gregsetp)
41c49b06 516{
7f7fe91e 517 arm_linux_supply_gregset (NULL, regcache, -1, gregsetp, 0);
41c49b06
SB
518}
519
41c49b06 520void
7f7fe91e
UW
521fill_fpregset (const struct regcache *regcache,
522 gdb_fpregset_t *fpregsetp, int regno)
41c49b06 523{
7f7fe91e 524 arm_linux_collect_nwfpe (NULL, regcache, regno, fpregsetp, 0);
41c49b06
SB
525}
526
527/* Fill GDB's register array with the floating-point register values
528 in *fpregsetp. */
529
530void
7f7fe91e 531supply_fpregset (struct regcache *regcache, const gdb_fpregset_t *fpregsetp)
ed9a39eb 532{
7f7fe91e 533 arm_linux_supply_nwfpe (NULL, regcache, -1, fpregsetp, 0);
ed9a39eb
JM
534}
535
9308fc88
DJ
536/* Fetch the thread-local storage pointer for libthread_db. */
537
538ps_err_e
539ps_get_thread_area (const struct ps_prochandle *ph,
540 lwpid_t lwpid, int idx, void **base)
541{
542 if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0)
543 return PS_ERR;
544
545 /* IDX is the bias from the thread pointer to the beginning of the
546 thread descriptor. It has to be subtracted due to implementation
547 quirks in libthread_db. */
548 *base = (void *) ((char *)*base - idx);
549
550 return PS_OK;
551}
552
ed9a39eb
JM
553static unsigned int
554get_linux_version (unsigned int *vmajor,
555 unsigned int *vminor,
556 unsigned int *vrelease)
557{
558 struct utsname info;
559 char *pmajor, *pminor, *prelease, *tail;
560
561 if (-1 == uname (&info))
562 {
edefbb7c 563 warning (_("Unable to determine GNU/Linux version."));
ed9a39eb
JM
564 return -1;
565 }
566
567 pmajor = strtok (info.release, ".");
568 pminor = strtok (NULL, ".");
569 prelease = strtok (NULL, ".");
570
571 *vmajor = (unsigned int) strtoul (pmajor, &tail, 0);
572 *vminor = (unsigned int) strtoul (pminor, &tail, 0);
573 *vrelease = (unsigned int) strtoul (prelease, &tail, 0);
574
575 return ((*vmajor << 16) | (*vminor << 8) | *vrelease);
576}
577
81adfced
DJ
578static const struct target_desc *
579arm_linux_read_description (struct target_ops *ops)
05a4558a 580{
81adfced
DJ
581 int ret;
582 char regbuf[IWMMXT_REGS_SIZE];
05a4558a 583
81adfced
DJ
584 ret = ptrace (PTRACE_GETWMMXREGS, GET_THREAD_ID (inferior_ptid),
585 0, regbuf);
586 if (ret < 0)
587 arm_linux_has_wmmx_registers = 0;
588 else
589 arm_linux_has_wmmx_registers = 1;
590
591 if (arm_linux_has_wmmx_registers)
592 return tdesc_arm_with_iwmmxt;
593 else
594 return NULL;
05a4558a
DJ
595}
596
10d6c8cd
DJ
597void _initialize_arm_linux_nat (void);
598
ed9a39eb
JM
599void
600_initialize_arm_linux_nat (void)
601{
10d6c8cd
DJ
602 struct target_ops *t;
603
ed9a39eb 604 os_version = get_linux_version (&os_major, &os_minor, &os_release);
10d6c8cd
DJ
605
606 /* Fill in the generic GNU/Linux methods. */
607 t = linux_target ();
608
609 /* Add our register access methods. */
610 t->to_fetch_registers = arm_linux_fetch_inferior_registers;
611 t->to_store_registers = arm_linux_store_inferior_registers;
612
81adfced 613 t->to_read_description = arm_linux_read_description;
05a4558a 614
10d6c8cd 615 /* Register the target. */
f973ed9c 616 linux_nat_add_target (t);
81adfced
DJ
617
618 /* Initialize the standard target descriptions. */
619 initialize_tdesc_arm_with_iwmmxt ();
ed9a39eb 620}
This page took 0.587061 seconds and 4 git commands to generate.