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