* target-descriptions.c (tdesc_predefined_types): New.
[deliverable/binutils-gdb.git] / gdb / arm-linux-nat.c
CommitLineData
ed9a39eb 1/* GNU/Linux on ARM native support.
6aba47ca 2 Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007
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
UW
257 regs[ARM_PC_REGNUM] = gdbarch_addr_bits_remove
258 (current_gdbarch, regs[ARM_PC_REGNUM]);
56be3814 259 regcache_raw_supply (regcache, ARM_PC_REGNUM,
23a6d369 260 (char *) &regs[ARM_PC_REGNUM]);
41c49b06
SB
261 }
262}
263
ed9a39eb 264/* Fetch all general registers of the process and store into
c6b92abd 265 regcache. */
ed9a39eb
JM
266
267static void
56be3814 268fetch_regs (struct regcache *regcache)
ed9a39eb 269{
41c49b06 270 int ret, regno, tid;
c2152441 271 elf_gregset_t regs;
ed9a39eb 272
41c49b06 273 /* Get the thread id for the ptrace call. */
39f77062 274 tid = GET_THREAD_ID (inferior_ptid);
41c49b06
SB
275
276 ret = ptrace (PTRACE_GETREGS, tid, 0, &regs);
ed9a39eb
JM
277 if (ret < 0)
278 {
edefbb7c 279 warning (_("Unable to fetch general registers."));
ed9a39eb
JM
280 return;
281 }
282
34e8f22d 283 for (regno = ARM_A1_REGNUM; regno < ARM_PC_REGNUM; regno++)
56be3814 284 regcache_raw_supply (regcache, regno, (char *) &regs[regno]);
ed9a39eb
JM
285
286 if (arm_apcs_32)
56be3814 287 regcache_raw_supply (regcache, ARM_PS_REGNUM,
23a6d369 288 (char *) &regs[ARM_CPSR_REGNUM]);
ed9a39eb 289 else
56be3814 290 regcache_raw_supply (regcache, ARM_PS_REGNUM,
23a6d369 291 (char *) &regs[ARM_PC_REGNUM]);
ed9a39eb 292
bf6ae464
UW
293 regs[ARM_PC_REGNUM] = gdbarch_addr_bits_remove
294 (current_gdbarch, regs[ARM_PC_REGNUM]);
56be3814 295 regcache_raw_supply (regcache, ARM_PC_REGNUM,
23a6d369 296 (char *) &regs[ARM_PC_REGNUM]);
ed9a39eb
JM
297}
298
299/* Store all general registers of the process from the values in
c6b92abd 300 regcache. */
ed9a39eb 301
41c49b06 302static void
56be3814 303store_register (const struct regcache *regcache, int regno)
41c49b06
SB
304{
305 int ret, tid;
c2152441 306 elf_gregset_t regs;
41c49b06 307
56be3814 308 if (!regcache_valid_p (regcache, regno))
41c49b06
SB
309 return;
310
311 /* Get the thread id for the ptrace call. */
39f77062 312 tid = GET_THREAD_ID (inferior_ptid);
41c49b06
SB
313
314 /* Get the general registers from the process. */
315 ret = ptrace (PTRACE_GETREGS, tid, 0, &regs);
316 if (ret < 0)
317 {
edefbb7c 318 warning (_("Unable to fetch general registers."));
41c49b06
SB
319 return;
320 }
321
34e8f22d 322 if (regno >= ARM_A1_REGNUM && regno <= ARM_PC_REGNUM)
56be3814 323 regcache_raw_collect (regcache, regno, (char *) &regs[regno]);
adb8a87c 324 else if (arm_apcs_32 && regno == ARM_PS_REGNUM)
56be3814 325 regcache_raw_collect (regcache, regno,
adb8a87c
DJ
326 (char *) &regs[ARM_CPSR_REGNUM]);
327 else if (!arm_apcs_32 && regno == ARM_PS_REGNUM)
56be3814 328 regcache_raw_collect (regcache, ARM_PC_REGNUM,
adb8a87c 329 (char *) &regs[ARM_PC_REGNUM]);
41c49b06
SB
330
331 ret = ptrace (PTRACE_SETREGS, tid, 0, &regs);
332 if (ret < 0)
333 {
edefbb7c 334 warning (_("Unable to store general register."));
41c49b06
SB
335 return;
336 }
337}
338
ed9a39eb 339static void
56be3814 340store_regs (const struct regcache *regcache)
ed9a39eb 341{
41c49b06 342 int ret, regno, tid;
c2152441 343 elf_gregset_t regs;
ed9a39eb 344
41c49b06 345 /* Get the thread id for the ptrace call. */
39f77062 346 tid = GET_THREAD_ID (inferior_ptid);
41c49b06
SB
347
348 /* Fetch the general registers. */
349 ret = ptrace (PTRACE_GETREGS, tid, 0, &regs);
ed9a39eb
JM
350 if (ret < 0)
351 {
edefbb7c 352 warning (_("Unable to fetch general registers."));
ed9a39eb
JM
353 return;
354 }
355
34e8f22d 356 for (regno = ARM_A1_REGNUM; regno <= ARM_PC_REGNUM; regno++)
ed9a39eb 357 {
56be3814
UW
358 if (regcache_valid_p (regcache, regno))
359 regcache_raw_collect (regcache, regno, (char *) &regs[regno]);
ed9a39eb
JM
360 }
361
56be3814
UW
362 if (arm_apcs_32 && regcache_valid_p (regcache, ARM_PS_REGNUM))
363 regcache_raw_collect (regcache, ARM_PS_REGNUM,
adb8a87c
DJ
364 (char *) &regs[ARM_CPSR_REGNUM]);
365
41c49b06 366 ret = ptrace (PTRACE_SETREGS, tid, 0, &regs);
ed9a39eb
JM
367
368 if (ret < 0)
369 {
edefbb7c 370 warning (_("Unable to store general registers."));
ed9a39eb
JM
371 return;
372 }
373}
374
05a4558a
DJ
375/* Fetch all WMMX registers of the process and store into
376 regcache. */
377
378#define IWMMXT_REGS_SIZE (16 * 8 + 6 * 4)
379
380static void
56be3814 381fetch_wmmx_regs (struct regcache *regcache)
05a4558a
DJ
382{
383 char regbuf[IWMMXT_REGS_SIZE];
384 int ret, regno, tid;
385
386 /* Get the thread id for the ptrace call. */
387 tid = GET_THREAD_ID (inferior_ptid);
388
389 ret = ptrace (PTRACE_GETWMMXREGS, tid, 0, regbuf);
390 if (ret < 0)
391 {
392 warning (_("Unable to fetch WMMX registers."));
393 return;
394 }
395
396 for (regno = 0; regno < 16; regno++)
56be3814 397 regcache_raw_supply (regcache, regno + ARM_WR0_REGNUM,
05a4558a
DJ
398 &regbuf[regno * 8]);
399
400 for (regno = 0; regno < 2; regno++)
56be3814 401 regcache_raw_supply (regcache, regno + ARM_WCSSF_REGNUM,
05a4558a
DJ
402 &regbuf[16 * 8 + regno * 4]);
403
404 for (regno = 0; regno < 4; regno++)
56be3814 405 regcache_raw_supply (regcache, regno + ARM_WCGR0_REGNUM,
05a4558a
DJ
406 &regbuf[16 * 8 + 2 * 4 + regno * 4]);
407}
408
409static void
56be3814 410store_wmmx_regs (const struct regcache *regcache)
05a4558a
DJ
411{
412 char regbuf[IWMMXT_REGS_SIZE];
413 int ret, regno, tid;
414
415 /* Get the thread id for the ptrace call. */
416 tid = GET_THREAD_ID (inferior_ptid);
417
418 ret = ptrace (PTRACE_GETWMMXREGS, tid, 0, regbuf);
419 if (ret < 0)
420 {
421 warning (_("Unable to fetch WMMX registers."));
422 return;
423 }
424
425 for (regno = 0; regno < 16; regno++)
56be3814
UW
426 if (regcache_valid_p (regcache, regno + ARM_WR0_REGNUM))
427 regcache_raw_collect (regcache, regno + ARM_WR0_REGNUM,
05a4558a
DJ
428 &regbuf[regno * 8]);
429
430 for (regno = 0; regno < 2; regno++)
56be3814
UW
431 if (regcache_valid_p (regcache, regno + ARM_WCSSF_REGNUM))
432 regcache_raw_collect (regcache, regno + ARM_WCSSF_REGNUM,
05a4558a
DJ
433 &regbuf[16 * 8 + regno * 4]);
434
435 for (regno = 0; regno < 4; regno++)
56be3814
UW
436 if (regcache_valid_p (regcache, regno + ARM_WCGR0_REGNUM))
437 regcache_raw_collect (regcache, regno + ARM_WCGR0_REGNUM,
05a4558a
DJ
438 &regbuf[16 * 8 + 2 * 4 + regno * 4]);
439
440 ret = ptrace (PTRACE_SETWMMXREGS, tid, 0, regbuf);
441
442 if (ret < 0)
443 {
444 warning (_("Unable to store WMMX registers."));
445 return;
446 }
447}
448
ed9a39eb
JM
449/* Fetch registers from the child process. Fetch all registers if
450 regno == -1, otherwise fetch all general registers or all floating
451 point registers depending upon the value of regno. */
452
10d6c8cd 453static void
56be3814 454arm_linux_fetch_inferior_registers (struct regcache *regcache, int regno)
ed9a39eb 455{
41c49b06
SB
456 if (-1 == regno)
457 {
56be3814
UW
458 fetch_regs (regcache);
459 fetch_fpregs (regcache);
05a4558a 460 if (arm_linux_has_wmmx_registers)
56be3814 461 fetch_wmmx_regs (regcache);
41c49b06
SB
462 }
463 else
464 {
05a4558a 465 if (regno < ARM_F0_REGNUM || regno == ARM_PS_REGNUM)
56be3814 466 fetch_register (regcache, regno);
05a4558a 467 else if (regno >= ARM_F0_REGNUM && regno <= ARM_FPS_REGNUM)
56be3814 468 fetch_fpregister (regcache, regno);
05a4558a
DJ
469 else if (arm_linux_has_wmmx_registers
470 && regno >= ARM_WR0_REGNUM && regno <= ARM_WCGR7_REGNUM)
56be3814 471 fetch_wmmx_regs (regcache);
41c49b06 472 }
ed9a39eb
JM
473}
474
475/* Store registers back into the inferior. Store all registers if
476 regno == -1, otherwise store all general registers or all floating
477 point registers depending upon the value of regno. */
478
10d6c8cd 479static void
56be3814 480arm_linux_store_inferior_registers (struct regcache *regcache, int regno)
ed9a39eb 481{
41c49b06
SB
482 if (-1 == regno)
483 {
56be3814
UW
484 store_regs (regcache);
485 store_fpregs (regcache);
05a4558a 486 if (arm_linux_has_wmmx_registers)
56be3814 487 store_wmmx_regs (regcache);
41c49b06
SB
488 }
489 else
490 {
05a4558a 491 if (regno < ARM_F0_REGNUM || regno == ARM_PS_REGNUM)
56be3814 492 store_register (regcache, regno);
05a4558a 493 else if ((regno >= ARM_F0_REGNUM) && (regno <= ARM_FPS_REGNUM))
56be3814 494 store_fpregister (regcache, regno);
05a4558a
DJ
495 else if (arm_linux_has_wmmx_registers
496 && regno >= ARM_WR0_REGNUM && regno <= ARM_WCGR7_REGNUM)
56be3814 497 store_wmmx_regs (regcache);
41c49b06 498 }
ed9a39eb
JM
499}
500
cb587d83
DJ
501/* Wrapper functions for the standard regset handling, used by
502 thread debugging. */
41c49b06
SB
503
504void
7f7fe91e
UW
505fill_gregset (const struct regcache *regcache,
506 gdb_gregset_t *gregsetp, int regno)
41c49b06 507{
7f7fe91e 508 arm_linux_collect_gregset (NULL, regcache, regno, gregsetp, 0);
41c49b06
SB
509}
510
41c49b06 511void
7f7fe91e 512supply_gregset (struct regcache *regcache, const gdb_gregset_t *gregsetp)
41c49b06 513{
7f7fe91e 514 arm_linux_supply_gregset (NULL, regcache, -1, gregsetp, 0);
41c49b06
SB
515}
516
41c49b06 517void
7f7fe91e
UW
518fill_fpregset (const struct regcache *regcache,
519 gdb_fpregset_t *fpregsetp, int regno)
41c49b06 520{
7f7fe91e 521 arm_linux_collect_nwfpe (NULL, regcache, regno, fpregsetp, 0);
41c49b06
SB
522}
523
524/* Fill GDB's register array with the floating-point register values
525 in *fpregsetp. */
526
527void
7f7fe91e 528supply_fpregset (struct regcache *regcache, const gdb_fpregset_t *fpregsetp)
ed9a39eb 529{
7f7fe91e 530 arm_linux_supply_nwfpe (NULL, regcache, -1, fpregsetp, 0);
ed9a39eb
JM
531}
532
9308fc88
DJ
533/* Fetch the thread-local storage pointer for libthread_db. */
534
535ps_err_e
536ps_get_thread_area (const struct ps_prochandle *ph,
537 lwpid_t lwpid, int idx, void **base)
538{
539 if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0)
540 return PS_ERR;
541
542 /* IDX is the bias from the thread pointer to the beginning of the
543 thread descriptor. It has to be subtracted due to implementation
544 quirks in libthread_db. */
545 *base = (void *) ((char *)*base - idx);
546
547 return PS_OK;
548}
549
ed9a39eb
JM
550static unsigned int
551get_linux_version (unsigned int *vmajor,
552 unsigned int *vminor,
553 unsigned int *vrelease)
554{
555 struct utsname info;
556 char *pmajor, *pminor, *prelease, *tail;
557
558 if (-1 == uname (&info))
559 {
edefbb7c 560 warning (_("Unable to determine GNU/Linux version."));
ed9a39eb
JM
561 return -1;
562 }
563
564 pmajor = strtok (info.release, ".");
565 pminor = strtok (NULL, ".");
566 prelease = strtok (NULL, ".");
567
568 *vmajor = (unsigned int) strtoul (pmajor, &tail, 0);
569 *vminor = (unsigned int) strtoul (pminor, &tail, 0);
570 *vrelease = (unsigned int) strtoul (prelease, &tail, 0);
571
572 return ((*vmajor << 16) | (*vminor << 8) | *vrelease);
573}
574
81adfced
DJ
575static const struct target_desc *
576arm_linux_read_description (struct target_ops *ops)
05a4558a 577{
81adfced
DJ
578 int ret;
579 char regbuf[IWMMXT_REGS_SIZE];
05a4558a 580
81adfced
DJ
581 ret = ptrace (PTRACE_GETWMMXREGS, GET_THREAD_ID (inferior_ptid),
582 0, regbuf);
583 if (ret < 0)
584 arm_linux_has_wmmx_registers = 0;
585 else
586 arm_linux_has_wmmx_registers = 1;
587
588 if (arm_linux_has_wmmx_registers)
589 return tdesc_arm_with_iwmmxt;
590 else
591 return NULL;
05a4558a
DJ
592}
593
10d6c8cd
DJ
594void _initialize_arm_linux_nat (void);
595
ed9a39eb
JM
596void
597_initialize_arm_linux_nat (void)
598{
10d6c8cd
DJ
599 struct target_ops *t;
600
ed9a39eb 601 os_version = get_linux_version (&os_major, &os_minor, &os_release);
10d6c8cd
DJ
602
603 /* Fill in the generic GNU/Linux methods. */
604 t = linux_target ();
605
606 /* Add our register access methods. */
607 t->to_fetch_registers = arm_linux_fetch_inferior_registers;
608 t->to_store_registers = arm_linux_store_inferior_registers;
609
81adfced 610 t->to_read_description = arm_linux_read_description;
05a4558a 611
10d6c8cd 612 /* Register the target. */
f973ed9c 613 linux_nat_add_target (t);
81adfced
DJ
614
615 /* Initialize the standard target descriptions. */
616 initialize_tdesc_arm_with_iwmmxt ();
ed9a39eb 617}
This page took 0.647267 seconds and 4 git commands to generate.