Switch the license of all .exp files to GPLv3.
[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
DJ
27#include "target-descriptions.h"
28#include "xml-support.h"
ed9a39eb 29
aeb98c60 30#include "arm-tdep.h"
cb587d83 31#include "arm-linux-tdep.h"
aeb98c60 32
ed9a39eb
JM
33#include <sys/user.h>
34#include <sys/ptrace.h>
35#include <sys/utsname.h>
41c49b06 36#include <sys/procfs.h>
ed9a39eb 37
c60c0f5f
MS
38/* Prototypes for supply_gregset etc. */
39#include "gregset.h"
40
9308fc88
DJ
41/* Defines ps_err_e, struct ps_prochandle. */
42#include "gdb_proc_service.h"
43
44#ifndef PTRACE_GET_THREAD_AREA
45#define PTRACE_GET_THREAD_AREA 22
46#endif
47
05a4558a
DJ
48#ifndef PTRACE_GETWMMXREGS
49#define PTRACE_GETWMMXREGS 18
50#define PTRACE_SETWMMXREGS 19
51#endif
52
53/* A flag for whether the WMMX registers are available. */
54static int arm_linux_has_wmmx_registers;
55
ed9a39eb
JM
56extern int arm_apcs_32;
57
ed9a39eb 58/* The following variables are used to determine the version of the
fdf39c9a 59 underlying GNU/Linux operating system. Examples:
ed9a39eb 60
fdf39c9a 61 GNU/Linux 2.0.35 GNU/Linux 2.2.12
ed9a39eb
JM
62 os_version = 0x00020023 os_version = 0x0002020c
63 os_major = 2 os_major = 2
64 os_minor = 0 os_minor = 2
65 os_release = 35 os_release = 12
66
67 Note: os_version = (os_major << 16) | (os_minor << 8) | os_release
68
69 These are initialized using get_linux_version() from
70 _initialize_arm_linux_nat(). */
71
72static unsigned int os_version, os_major, os_minor, os_release;
73
fdf39c9a 74/* On GNU/Linux, threads are implemented as pseudo-processes, in which
41c49b06 75 case we may be tracing more than one process at a time. In that
39f77062 76 case, inferior_ptid will contain the main process ID and the
fdf39c9a
RE
77 individual thread (process) ID. get_thread_id () is used to get
78 the thread id if it's available, and the process id otherwise. */
41c49b06
SB
79
80int
39f77062 81get_thread_id (ptid_t ptid)
41c49b06 82{
39f77062
KB
83 int tid = TIDGET (ptid);
84 if (0 == tid)
85 tid = PIDGET (ptid);
41c49b06
SB
86 return tid;
87}
05a4558a 88#define GET_THREAD_ID(PTID) get_thread_id (PTID)
41c49b06 89
41c49b06 90/* Get the value of a particular register from the floating point
c6b92abd 91 state of the process and store it into regcache. */
41c49b06
SB
92
93static void
56be3814 94fetch_fpregister (struct regcache *regcache, int regno)
41c49b06
SB
95{
96 int ret, tid;
cb587d83 97 gdb_byte fp[ARM_LINUX_SIZEOF_NWFPE];
41c49b06
SB
98
99 /* Get the thread id for the ptrace call. */
39f77062 100 tid = GET_THREAD_ID (inferior_ptid);
41c49b06
SB
101
102 /* Read the floating point state. */
cb587d83 103 ret = ptrace (PT_GETFPREGS, tid, 0, fp);
41c49b06
SB
104 if (ret < 0)
105 {
edefbb7c 106 warning (_("Unable to fetch floating point register."));
41c49b06
SB
107 return;
108 }
109
110 /* Fetch fpsr. */
34e8f22d 111 if (ARM_FPS_REGNUM == regno)
56be3814 112 regcache_raw_supply (regcache, ARM_FPS_REGNUM,
cb587d83 113 fp + NWFPE_FPSR_OFFSET);
41c49b06
SB
114
115 /* Fetch the floating point register. */
34e8f22d 116 if (regno >= ARM_F0_REGNUM && regno <= ARM_F7_REGNUM)
56be3814 117 supply_nwfpe_register (regcache, regno, fp);
41c49b06
SB
118}
119
120/* Get the whole floating point state of the process and store it
c6b92abd 121 into regcache. */
ed9a39eb
JM
122
123static void
56be3814 124fetch_fpregs (struct regcache *regcache)
ed9a39eb 125{
41c49b06 126 int ret, regno, tid;
cb587d83 127 gdb_byte fp[ARM_LINUX_SIZEOF_NWFPE];
ed9a39eb 128
41c49b06 129 /* Get the thread id for the ptrace call. */
39f77062 130 tid = GET_THREAD_ID (inferior_ptid);
41c49b06 131
ed9a39eb 132 /* Read the floating point state. */
cb587d83 133 ret = ptrace (PT_GETFPREGS, tid, 0, fp);
ed9a39eb
JM
134 if (ret < 0)
135 {
edefbb7c 136 warning (_("Unable to fetch the floating point registers."));
ed9a39eb
JM
137 return;
138 }
139
140 /* Fetch fpsr. */
56be3814 141 regcache_raw_supply (regcache, ARM_FPS_REGNUM,
cb587d83 142 fp + NWFPE_FPSR_OFFSET);
ed9a39eb
JM
143
144 /* Fetch the floating point registers. */
34e8f22d 145 for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++)
56be3814 146 supply_nwfpe_register (regcache, regno, fp);
ed9a39eb
JM
147}
148
41c49b06 149/* Save a particular register into the floating point state of the
c6b92abd 150 process using the contents from regcache. */
41c49b06
SB
151
152static void
56be3814 153store_fpregister (const struct regcache *regcache, int regno)
41c49b06
SB
154{
155 int ret, tid;
cb587d83 156 gdb_byte fp[ARM_LINUX_SIZEOF_NWFPE];
41c49b06
SB
157
158 /* Get the thread id for the ptrace call. */
39f77062 159 tid = GET_THREAD_ID (inferior_ptid);
41c49b06
SB
160
161 /* Read the floating point state. */
cb587d83 162 ret = ptrace (PT_GETFPREGS, tid, 0, fp);
41c49b06
SB
163 if (ret < 0)
164 {
edefbb7c 165 warning (_("Unable to fetch the floating point registers."));
41c49b06
SB
166 return;
167 }
168
169 /* Store fpsr. */
56be3814
UW
170 if (ARM_FPS_REGNUM == regno && regcache_valid_p (regcache, ARM_FPS_REGNUM))
171 regcache_raw_collect (regcache, ARM_FPS_REGNUM, fp + NWFPE_FPSR_OFFSET);
41c49b06
SB
172
173 /* Store the floating point register. */
34e8f22d 174 if (regno >= ARM_F0_REGNUM && regno <= ARM_F7_REGNUM)
56be3814 175 collect_nwfpe_register (regcache, regno, fp);
41c49b06 176
cb587d83 177 ret = ptrace (PTRACE_SETFPREGS, tid, 0, fp);
41c49b06
SB
178 if (ret < 0)
179 {
edefbb7c 180 warning (_("Unable to store floating point register."));
41c49b06
SB
181 return;
182 }
183}
184
ed9a39eb 185/* Save the whole floating point state of the process using
c6b92abd 186 the contents from regcache. */
ed9a39eb
JM
187
188static void
56be3814 189store_fpregs (const struct regcache *regcache)
ed9a39eb 190{
41c49b06 191 int ret, regno, tid;
cb587d83 192 gdb_byte fp[ARM_LINUX_SIZEOF_NWFPE];
ed9a39eb 193
41c49b06 194 /* Get the thread id for the ptrace call. */
39f77062 195 tid = GET_THREAD_ID (inferior_ptid);
41c49b06
SB
196
197 /* Read the floating point state. */
cb587d83 198 ret = ptrace (PT_GETFPREGS, tid, 0, fp);
41c49b06
SB
199 if (ret < 0)
200 {
edefbb7c 201 warning (_("Unable to fetch the floating point registers."));
41c49b06
SB
202 return;
203 }
204
ed9a39eb 205 /* Store fpsr. */
56be3814
UW
206 if (regcache_valid_p (regcache, ARM_FPS_REGNUM))
207 regcache_raw_collect (regcache, ARM_FPS_REGNUM, fp + NWFPE_FPSR_OFFSET);
ed9a39eb
JM
208
209 /* Store the floating point registers. */
34e8f22d 210 for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++)
56be3814
UW
211 if (regcache_valid_p (regcache, regno))
212 collect_nwfpe_register (regcache, regno, fp);
ed9a39eb 213
cb587d83 214 ret = ptrace (PTRACE_SETFPREGS, tid, 0, fp);
ed9a39eb
JM
215 if (ret < 0)
216 {
edefbb7c 217 warning (_("Unable to store floating point registers."));
ed9a39eb
JM
218 return;
219 }
220}
221
41c49b06 222/* Fetch a general register of the process and store into
c6b92abd 223 regcache. */
41c49b06
SB
224
225static void
56be3814 226fetch_register (struct regcache *regcache, int regno)
41c49b06
SB
227{
228 int ret, tid;
c2152441 229 elf_gregset_t regs;
41c49b06
SB
230
231 /* Get the thread id for the ptrace call. */
39f77062 232 tid = GET_THREAD_ID (inferior_ptid);
41c49b06
SB
233
234 ret = ptrace (PTRACE_GETREGS, tid, 0, &regs);
235 if (ret < 0)
236 {
edefbb7c 237 warning (_("Unable to fetch general register."));
41c49b06
SB
238 return;
239 }
240
34e8f22d 241 if (regno >= ARM_A1_REGNUM && regno < ARM_PC_REGNUM)
56be3814 242 regcache_raw_supply (regcache, regno, (char *) &regs[regno]);
41c49b06 243
34e8f22d 244 if (ARM_PS_REGNUM == regno)
41c49b06
SB
245 {
246 if (arm_apcs_32)
56be3814 247 regcache_raw_supply (regcache, ARM_PS_REGNUM,
23a6d369 248 (char *) &regs[ARM_CPSR_REGNUM]);
41c49b06 249 else
56be3814 250 regcache_raw_supply (regcache, ARM_PS_REGNUM,
23a6d369 251 (char *) &regs[ARM_PC_REGNUM]);
41c49b06
SB
252 }
253
34e8f22d 254 if (ARM_PC_REGNUM == regno)
41c49b06 255 {
bf6ae464
UW
256 regs[ARM_PC_REGNUM] = gdbarch_addr_bits_remove
257 (current_gdbarch, regs[ARM_PC_REGNUM]);
56be3814 258 regcache_raw_supply (regcache, ARM_PC_REGNUM,
23a6d369 259 (char *) &regs[ARM_PC_REGNUM]);
41c49b06
SB
260 }
261}
262
ed9a39eb 263/* Fetch all general registers of the process and store into
c6b92abd 264 regcache. */
ed9a39eb
JM
265
266static void
56be3814 267fetch_regs (struct regcache *regcache)
ed9a39eb 268{
41c49b06 269 int ret, regno, tid;
c2152441 270 elf_gregset_t regs;
ed9a39eb 271
41c49b06 272 /* Get the thread id for the ptrace call. */
39f77062 273 tid = GET_THREAD_ID (inferior_ptid);
41c49b06
SB
274
275 ret = ptrace (PTRACE_GETREGS, tid, 0, &regs);
ed9a39eb
JM
276 if (ret < 0)
277 {
edefbb7c 278 warning (_("Unable to fetch general registers."));
ed9a39eb
JM
279 return;
280 }
281
34e8f22d 282 for (regno = ARM_A1_REGNUM; regno < ARM_PC_REGNUM; regno++)
56be3814 283 regcache_raw_supply (regcache, regno, (char *) &regs[regno]);
ed9a39eb
JM
284
285 if (arm_apcs_32)
56be3814 286 regcache_raw_supply (regcache, ARM_PS_REGNUM,
23a6d369 287 (char *) &regs[ARM_CPSR_REGNUM]);
ed9a39eb 288 else
56be3814 289 regcache_raw_supply (regcache, ARM_PS_REGNUM,
23a6d369 290 (char *) &regs[ARM_PC_REGNUM]);
ed9a39eb 291
bf6ae464
UW
292 regs[ARM_PC_REGNUM] = gdbarch_addr_bits_remove
293 (current_gdbarch, 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.47121 seconds and 4 git commands to generate.