]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/arm-linux-nat.c
*** empty log message ***
[thirdparty/binutils-gdb.git] / gdb / arm-linux-nat.c
CommitLineData
ed9a39eb 1/* GNU/Linux on ARM native support.
34e8f22d 2 Copyright 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
ed9a39eb
JM
3
4 This file is part of GDB.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
20
21#include "defs.h"
22#include "inferior.h"
23#include "gdbcore.h"
24#include "gdb_string.h"
4e052eda 25#include "regcache.h"
ed9a39eb 26
aeb98c60
RE
27#include "arm-tdep.h"
28
ed9a39eb
JM
29#include <sys/user.h>
30#include <sys/ptrace.h>
31#include <sys/utsname.h>
41c49b06 32#include <sys/procfs.h>
ed9a39eb 33
c60c0f5f
MS
34/* Prototypes for supply_gregset etc. */
35#include "gregset.h"
36
ed9a39eb
JM
37extern int arm_apcs_32;
38
39#define typeNone 0x00
40#define typeSingle 0x01
41#define typeDouble 0x02
42#define typeExtended 0x03
43#define FPWORDS 28
34e8f22d 44#define ARM_CPSR_REGNUM 16
ed9a39eb
JM
45
46typedef union tagFPREG
47 {
48 unsigned int fSingle;
49 unsigned int fDouble[2];
50 unsigned int fExtended[3];
51 }
52FPREG;
53
54typedef struct tagFPA11
55 {
56 FPREG fpreg[8]; /* 8 floating point registers */
57 unsigned int fpsr; /* floating point status register */
58 unsigned int fpcr; /* floating point control register */
59 unsigned char fType[8]; /* type of floating point value held in
60 floating point registers. */
61 int initflag; /* NWFPE initialization flag. */
62 }
63FPA11;
64
65/* The following variables are used to determine the version of the
fdf39c9a 66 underlying GNU/Linux operating system. Examples:
ed9a39eb 67
fdf39c9a 68 GNU/Linux 2.0.35 GNU/Linux 2.2.12
ed9a39eb
JM
69 os_version = 0x00020023 os_version = 0x0002020c
70 os_major = 2 os_major = 2
71 os_minor = 0 os_minor = 2
72 os_release = 35 os_release = 12
73
74 Note: os_version = (os_major << 16) | (os_minor << 8) | os_release
75
76 These are initialized using get_linux_version() from
77 _initialize_arm_linux_nat(). */
78
79static unsigned int os_version, os_major, os_minor, os_release;
80
fdf39c9a 81/* On GNU/Linux, threads are implemented as pseudo-processes, in which
41c49b06 82 case we may be tracing more than one process at a time. In that
39f77062 83 case, inferior_ptid will contain the main process ID and the
fdf39c9a
RE
84 individual thread (process) ID. get_thread_id () is used to get
85 the thread id if it's available, and the process id otherwise. */
41c49b06
SB
86
87int
39f77062 88get_thread_id (ptid_t ptid)
41c49b06 89{
39f77062
KB
90 int tid = TIDGET (ptid);
91 if (0 == tid)
92 tid = PIDGET (ptid);
41c49b06
SB
93 return tid;
94}
39f77062 95#define GET_THREAD_ID(PTID) get_thread_id ((PTID));
41c49b06 96
ed9a39eb 97static void
56624b0a 98fetch_nwfpe_single (unsigned int fn, FPA11 * fpa11)
ed9a39eb
JM
99{
100 unsigned int mem[3];
101
102 mem[0] = fpa11->fpreg[fn].fSingle;
103 mem[1] = 0;
104 mem[2] = 0;
34e8f22d 105 supply_register (ARM_F0_REGNUM + fn, (char *) &mem[0]);
ed9a39eb
JM
106}
107
108static void
56624b0a 109fetch_nwfpe_double (unsigned int fn, FPA11 * fpa11)
ed9a39eb
JM
110{
111 unsigned int mem[3];
112
113 mem[0] = fpa11->fpreg[fn].fDouble[1];
114 mem[1] = fpa11->fpreg[fn].fDouble[0];
115 mem[2] = 0;
34e8f22d 116 supply_register (ARM_F0_REGNUM + fn, (char *) &mem[0]);
ed9a39eb
JM
117}
118
119static void
56624b0a 120fetch_nwfpe_none (unsigned int fn)
ed9a39eb
JM
121{
122 unsigned int mem[3] =
123 {0, 0, 0};
124
34e8f22d 125 supply_register (ARM_F0_REGNUM + fn, (char *) &mem[0]);
ed9a39eb
JM
126}
127
128static void
56624b0a 129fetch_nwfpe_extended (unsigned int fn, FPA11 * fpa11)
ed9a39eb
JM
130{
131 unsigned int mem[3];
132
133 mem[0] = fpa11->fpreg[fn].fExtended[0]; /* sign & exponent */
134 mem[1] = fpa11->fpreg[fn].fExtended[2]; /* ls bits */
135 mem[2] = fpa11->fpreg[fn].fExtended[1]; /* ms bits */
34e8f22d 136 supply_register (ARM_F0_REGNUM + fn, (char *) &mem[0]);
ed9a39eb
JM
137}
138
41c49b06
SB
139static void
140fetch_nwfpe_register (int regno, FPA11 * fpa11)
141{
34e8f22d 142 int fn = regno - ARM_F0_REGNUM;
41c49b06
SB
143
144 switch (fpa11->fType[fn])
145 {
146 case typeSingle:
147 fetch_nwfpe_single (fn, fpa11);
148 break;
149
150 case typeDouble:
151 fetch_nwfpe_double (fn, fpa11);
152 break;
153
154 case typeExtended:
155 fetch_nwfpe_extended (fn, fpa11);
156 break;
157
158 default:
159 fetch_nwfpe_none (fn);
160 }
161}
162
ed9a39eb 163static void
85ae890c 164store_nwfpe_single (unsigned int fn, FPA11 *fpa11)
ed9a39eb
JM
165{
166 unsigned int mem[3];
167
85ae890c 168 regcache_collect (ARM_F0_REGNUM + fn, (char *) &mem[0]);
ed9a39eb
JM
169 fpa11->fpreg[fn].fSingle = mem[0];
170 fpa11->fType[fn] = typeSingle;
171}
172
173static void
85ae890c 174store_nwfpe_double (unsigned int fn, FPA11 *fpa11)
ed9a39eb
JM
175{
176 unsigned int mem[3];
177
85ae890c 178 regcache_collect (ARM_F0_REGNUM + fn, (char *) &mem[0]);
ed9a39eb
JM
179 fpa11->fpreg[fn].fDouble[1] = mem[0];
180 fpa11->fpreg[fn].fDouble[0] = mem[1];
181 fpa11->fType[fn] = typeDouble;
182}
183
184void
85ae890c 185store_nwfpe_extended (unsigned int fn, FPA11 *fpa11)
ed9a39eb
JM
186{
187 unsigned int mem[3];
188
85ae890c 189 regcache_collect (ARM_F0_REGNUM + fn, (char *) &mem[0]);
ed9a39eb
JM
190 fpa11->fpreg[fn].fExtended[0] = mem[0]; /* sign & exponent */
191 fpa11->fpreg[fn].fExtended[2] = mem[1]; /* ls bits */
192 fpa11->fpreg[fn].fExtended[1] = mem[2]; /* ms bits */
193 fpa11->fType[fn] = typeDouble;
194}
195
41c49b06
SB
196void
197store_nwfpe_register (int regno, FPA11 * fpa11)
198{
c6b92abd 199 if (register_cached (regno))
41c49b06 200 {
34e8f22d 201 unsigned int fn = regno - ARM_F0_REGNUM;
41c49b06
SB
202 switch (fpa11->fType[fn])
203 {
204 case typeSingle:
205 store_nwfpe_single (fn, fpa11);
206 break;
207
208 case typeDouble:
209 store_nwfpe_double (fn, fpa11);
210 break;
211
212 case typeExtended:
213 store_nwfpe_extended (fn, fpa11);
214 break;
215 }
216 }
217}
218
219
220/* Get the value of a particular register from the floating point
c6b92abd 221 state of the process and store it into regcache. */
41c49b06
SB
222
223static void
224fetch_fpregister (int regno)
225{
226 int ret, tid;
227 FPA11 fp;
228
229 /* Get the thread id for the ptrace call. */
39f77062 230 tid = GET_THREAD_ID (inferior_ptid);
41c49b06
SB
231
232 /* Read the floating point state. */
233 ret = ptrace (PT_GETFPREGS, tid, 0, &fp);
234 if (ret < 0)
235 {
236 warning ("Unable to fetch floating point register.");
237 return;
238 }
239
240 /* Fetch fpsr. */
34e8f22d
RE
241 if (ARM_FPS_REGNUM == regno)
242 supply_register (ARM_FPS_REGNUM, (char *) &fp.fpsr);
41c49b06
SB
243
244 /* Fetch the floating point register. */
34e8f22d 245 if (regno >= ARM_F0_REGNUM && regno <= ARM_F7_REGNUM)
41c49b06 246 {
34e8f22d 247 int fn = regno - ARM_F0_REGNUM;
41c49b06
SB
248
249 switch (fp.fType[fn])
250 {
251 case typeSingle:
252 fetch_nwfpe_single (fn, &fp);
253 break;
254
255 case typeDouble:
256 fetch_nwfpe_double (fn, &fp);
257 break;
258
259 case typeExtended:
260 fetch_nwfpe_extended (fn, &fp);
261 break;
262
263 default:
264 fetch_nwfpe_none (fn);
265 }
266 }
267}
268
269/* Get the whole floating point state of the process and store it
c6b92abd 270 into regcache. */
ed9a39eb
JM
271
272static void
273fetch_fpregs (void)
274{
41c49b06 275 int ret, regno, tid;
ed9a39eb
JM
276 FPA11 fp;
277
41c49b06 278 /* Get the thread id for the ptrace call. */
39f77062 279 tid = GET_THREAD_ID (inferior_ptid);
41c49b06 280
ed9a39eb 281 /* Read the floating point state. */
41c49b06 282 ret = ptrace (PT_GETFPREGS, tid, 0, &fp);
ed9a39eb
JM
283 if (ret < 0)
284 {
41c49b06 285 warning ("Unable to fetch the floating point registers.");
ed9a39eb
JM
286 return;
287 }
288
289 /* Fetch fpsr. */
34e8f22d 290 supply_register (ARM_FPS_REGNUM, (char *) &fp.fpsr);
ed9a39eb
JM
291
292 /* Fetch the floating point registers. */
34e8f22d 293 for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++)
ed9a39eb 294 {
34e8f22d 295 int fn = regno - ARM_F0_REGNUM;
ed9a39eb
JM
296
297 switch (fp.fType[fn])
298 {
299 case typeSingle:
56624b0a 300 fetch_nwfpe_single (fn, &fp);
ed9a39eb
JM
301 break;
302
303 case typeDouble:
56624b0a 304 fetch_nwfpe_double (fn, &fp);
ed9a39eb
JM
305 break;
306
307 case typeExtended:
56624b0a 308 fetch_nwfpe_extended (fn, &fp);
ed9a39eb
JM
309 break;
310
311 default:
56624b0a 312 fetch_nwfpe_none (fn);
ed9a39eb
JM
313 }
314 }
315}
316
41c49b06 317/* Save a particular register into the floating point state of the
c6b92abd 318 process using the contents from regcache. */
41c49b06
SB
319
320static void
321store_fpregister (int regno)
322{
323 int ret, tid;
324 FPA11 fp;
325
326 /* Get the thread id for the ptrace call. */
39f77062 327 tid = GET_THREAD_ID (inferior_ptid);
41c49b06
SB
328
329 /* Read the floating point state. */
330 ret = ptrace (PT_GETFPREGS, tid, 0, &fp);
331 if (ret < 0)
332 {
333 warning ("Unable to fetch the floating point registers.");
334 return;
335 }
336
337 /* Store fpsr. */
34e8f22d 338 if (ARM_FPS_REGNUM == regno && register_cached (ARM_FPS_REGNUM))
85ae890c 339 regcache_collect (ARM_FPS_REGNUM, (char *) &fp.fpsr);
41c49b06
SB
340
341 /* Store the floating point register. */
34e8f22d 342 if (regno >= ARM_F0_REGNUM && regno <= ARM_F7_REGNUM)
41c49b06
SB
343 {
344 store_nwfpe_register (regno, &fp);
345 }
346
347 ret = ptrace (PTRACE_SETFPREGS, tid, 0, &fp);
348 if (ret < 0)
349 {
350 warning ("Unable to store floating point register.");
351 return;
352 }
353}
354
ed9a39eb 355/* Save the whole floating point state of the process using
c6b92abd 356 the contents from regcache. */
ed9a39eb
JM
357
358static void
359store_fpregs (void)
360{
41c49b06 361 int ret, regno, tid;
ed9a39eb
JM
362 FPA11 fp;
363
41c49b06 364 /* Get the thread id for the ptrace call. */
39f77062 365 tid = GET_THREAD_ID (inferior_ptid);
41c49b06
SB
366
367 /* Read the floating point state. */
368 ret = ptrace (PT_GETFPREGS, tid, 0, &fp);
369 if (ret < 0)
370 {
371 warning ("Unable to fetch the floating point registers.");
372 return;
373 }
374
ed9a39eb 375 /* Store fpsr. */
34e8f22d 376 if (register_cached (ARM_FPS_REGNUM))
85ae890c 377 regcache_collect (ARM_FPS_REGNUM, (char *) &fp.fpsr);
ed9a39eb
JM
378
379 /* Store the floating point registers. */
34e8f22d 380 for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++)
ed9a39eb 381 {
41c49b06 382 fetch_nwfpe_register (regno, &fp);
ed9a39eb
JM
383 }
384
41c49b06 385 ret = ptrace (PTRACE_SETFPREGS, tid, 0, &fp);
ed9a39eb
JM
386 if (ret < 0)
387 {
41c49b06 388 warning ("Unable to store floating point registers.");
ed9a39eb
JM
389 return;
390 }
391}
392
41c49b06 393/* Fetch a general register of the process and store into
c6b92abd 394 regcache. */
41c49b06
SB
395
396static void
397fetch_register (int regno)
398{
399 int ret, tid;
c2152441 400 elf_gregset_t regs;
41c49b06
SB
401
402 /* Get the thread id for the ptrace call. */
39f77062 403 tid = GET_THREAD_ID (inferior_ptid);
41c49b06
SB
404
405 ret = ptrace (PTRACE_GETREGS, tid, 0, &regs);
406 if (ret < 0)
407 {
408 warning ("Unable to fetch general register.");
409 return;
410 }
411
34e8f22d 412 if (regno >= ARM_A1_REGNUM && regno < ARM_PC_REGNUM)
c2152441 413 supply_register (regno, (char *) &regs[regno]);
41c49b06 414
34e8f22d 415 if (ARM_PS_REGNUM == regno)
41c49b06
SB
416 {
417 if (arm_apcs_32)
34e8f22d 418 supply_register (ARM_PS_REGNUM, (char *) &regs[ARM_CPSR_REGNUM]);
41c49b06 419 else
34e8f22d 420 supply_register (ARM_PS_REGNUM, (char *) &regs[ARM_PC_REGNUM]);
41c49b06
SB
421 }
422
34e8f22d 423 if (ARM_PC_REGNUM == regno)
41c49b06 424 {
34e8f22d
RE
425 regs[ARM_PC_REGNUM] = ADDR_BITS_REMOVE (regs[ARM_PC_REGNUM]);
426 supply_register (ARM_PC_REGNUM, (char *) &regs[ARM_PC_REGNUM]);
41c49b06
SB
427 }
428}
429
ed9a39eb 430/* Fetch all general registers of the process and store into
c6b92abd 431 regcache. */
ed9a39eb
JM
432
433static void
434fetch_regs (void)
435{
41c49b06 436 int ret, regno, tid;
c2152441 437 elf_gregset_t regs;
ed9a39eb 438
41c49b06 439 /* Get the thread id for the ptrace call. */
39f77062 440 tid = GET_THREAD_ID (inferior_ptid);
41c49b06
SB
441
442 ret = ptrace (PTRACE_GETREGS, tid, 0, &regs);
ed9a39eb
JM
443 if (ret < 0)
444 {
445 warning ("Unable to fetch general registers.");
446 return;
447 }
448
34e8f22d 449 for (regno = ARM_A1_REGNUM; regno < ARM_PC_REGNUM; regno++)
c2152441 450 supply_register (regno, (char *) &regs[regno]);
ed9a39eb
JM
451
452 if (arm_apcs_32)
34e8f22d 453 supply_register (ARM_PS_REGNUM, (char *) &regs[ARM_CPSR_REGNUM]);
ed9a39eb 454 else
34e8f22d 455 supply_register (ARM_PS_REGNUM, (char *) &regs[ARM_PC_REGNUM]);
ed9a39eb 456
34e8f22d
RE
457 regs[ARM_PC_REGNUM] = ADDR_BITS_REMOVE (regs[ARM_PC_REGNUM]);
458 supply_register (ARM_PC_REGNUM, (char *) &regs[ARM_PC_REGNUM]);
ed9a39eb
JM
459}
460
461/* Store all general registers of the process from the values in
c6b92abd 462 regcache. */
ed9a39eb 463
41c49b06
SB
464static void
465store_register (int regno)
466{
467 int ret, tid;
c2152441 468 elf_gregset_t regs;
41c49b06 469
c6b92abd 470 if (!register_cached (regno))
41c49b06
SB
471 return;
472
473 /* Get the thread id for the ptrace call. */
39f77062 474 tid = GET_THREAD_ID (inferior_ptid);
41c49b06
SB
475
476 /* Get the general registers from the process. */
477 ret = ptrace (PTRACE_GETREGS, tid, 0, &regs);
478 if (ret < 0)
479 {
480 warning ("Unable to fetch general registers.");
481 return;
482 }
483
34e8f22d 484 if (regno >= ARM_A1_REGNUM && regno <= ARM_PC_REGNUM)
85ae890c 485 regcache_collect (regno, (char *) &regs[regno]);
41c49b06
SB
486
487 ret = ptrace (PTRACE_SETREGS, tid, 0, &regs);
488 if (ret < 0)
489 {
490 warning ("Unable to store general register.");
491 return;
492 }
493}
494
ed9a39eb
JM
495static void
496store_regs (void)
497{
41c49b06 498 int ret, regno, tid;
c2152441 499 elf_gregset_t regs;
ed9a39eb 500
41c49b06 501 /* Get the thread id for the ptrace call. */
39f77062 502 tid = GET_THREAD_ID (inferior_ptid);
41c49b06
SB
503
504 /* Fetch the general registers. */
505 ret = ptrace (PTRACE_GETREGS, tid, 0, &regs);
ed9a39eb
JM
506 if (ret < 0)
507 {
508 warning ("Unable to fetch general registers.");
509 return;
510 }
511
34e8f22d 512 for (regno = ARM_A1_REGNUM; regno <= ARM_PC_REGNUM; regno++)
ed9a39eb 513 {
c6b92abd 514 if (register_cached (regno))
85ae890c 515 regcache_collect (regno, (char *) &regs[regno]);
ed9a39eb
JM
516 }
517
41c49b06 518 ret = ptrace (PTRACE_SETREGS, tid, 0, &regs);
ed9a39eb
JM
519
520 if (ret < 0)
521 {
522 warning ("Unable to store general registers.");
523 return;
524 }
525}
526
527/* Fetch registers from the child process. Fetch all registers if
528 regno == -1, otherwise fetch all general registers or all floating
529 point registers depending upon the value of regno. */
530
531void
532fetch_inferior_registers (int regno)
533{
41c49b06
SB
534 if (-1 == regno)
535 {
536 fetch_regs ();
537 fetch_fpregs ();
538 }
539 else
540 {
34e8f22d 541 if (regno < ARM_F0_REGNUM || regno > ARM_FPS_REGNUM)
41c49b06 542 fetch_register (regno);
ed9a39eb 543
34e8f22d 544 if (regno >= ARM_F0_REGNUM && regno <= ARM_FPS_REGNUM)
41c49b06
SB
545 fetch_fpregister (regno);
546 }
ed9a39eb
JM
547}
548
549/* Store registers back into the inferior. Store all registers if
550 regno == -1, otherwise store all general registers or all floating
551 point registers depending upon the value of regno. */
552
553void
554store_inferior_registers (int regno)
555{
41c49b06
SB
556 if (-1 == regno)
557 {
558 store_regs ();
559 store_fpregs ();
560 }
561 else
562 {
34e8f22d 563 if ((regno < ARM_F0_REGNUM) || (regno > ARM_FPS_REGNUM))
41c49b06 564 store_register (regno);
ed9a39eb 565
34e8f22d 566 if ((regno >= ARM_F0_REGNUM) && (regno <= ARM_FPS_REGNUM))
41c49b06
SB
567 store_fpregister (regno);
568 }
ed9a39eb
JM
569}
570
41c49b06
SB
571/* Fill register regno (if it is a general-purpose register) in
572 *gregsetp with the appropriate value from GDB's register array.
573 If regno is -1, do this for all registers. */
574
575void
713f0374 576fill_gregset (gdb_gregset_t *gregsetp, int regno)
41c49b06
SB
577{
578 if (-1 == regno)
579 {
580 int regnum;
34e8f22d 581 for (regnum = ARM_A1_REGNUM; regnum <= ARM_PC_REGNUM; regnum++)
85ae890c 582 regcache_collect (regnum, (char *) &(*gregsetp)[regnum]);
41c49b06 583 }
34e8f22d 584 else if (regno >= ARM_A1_REGNUM && regno <= ARM_PC_REGNUM)
85ae890c 585 regcache_collect (regno, (char *) &(*gregsetp)[regno]);
41c49b06 586
34e8f22d 587 if (ARM_PS_REGNUM == regno || -1 == regno)
41c49b06 588 {
17fd1ad9 589 if (arm_apcs_32)
85ae890c
RE
590 regcache_collect (ARM_PS_REGNUM,
591 (char *) &(*gregsetp)[ARM_CPSR_REGNUM]);
17fd1ad9 592 else
85ae890c
RE
593 regcache_collect (ARM_PC_REGNUM,
594 (char *) &(*gregsetp)[ARM_PC_REGNUM]);
41c49b06 595 }
41c49b06
SB
596}
597
598/* Fill GDB's register array with the general-purpose register values
599 in *gregsetp. */
600
601void
713f0374 602supply_gregset (gdb_gregset_t *gregsetp)
41c49b06
SB
603{
604 int regno, reg_pc;
605
34e8f22d 606 for (regno = ARM_A1_REGNUM; regno < ARM_PC_REGNUM; regno++)
41c49b06
SB
607 supply_register (regno, (char *) &(*gregsetp)[regno]);
608
609 if (arm_apcs_32)
34e8f22d 610 supply_register (ARM_PS_REGNUM, (char *) &(*gregsetp)[ARM_CPSR_REGNUM]);
41c49b06 611 else
34e8f22d 612 supply_register (ARM_PS_REGNUM, (char *) &(*gregsetp)[ARM_PC_REGNUM]);
41c49b06 613
34e8f22d
RE
614 reg_pc = ADDR_BITS_REMOVE ((CORE_ADDR)(*gregsetp)[ARM_PC_REGNUM]);
615 supply_register (ARM_PC_REGNUM, (char *) &reg_pc);
41c49b06
SB
616}
617
618/* Fill register regno (if it is a floating-point register) in
619 *fpregsetp with the appropriate value from GDB's register array.
620 If regno is -1, do this for all registers. */
621
622void
713f0374 623fill_fpregset (gdb_fpregset_t *fpregsetp, int regno)
41c49b06
SB
624{
625 FPA11 *fp = (FPA11 *) fpregsetp;
626
627 if (-1 == regno)
628 {
629 int regnum;
34e8f22d 630 for (regnum = ARM_F0_REGNUM; regnum <= ARM_F7_REGNUM; regnum++)
41c49b06
SB
631 store_nwfpe_register (regnum, fp);
632 }
34e8f22d 633 else if (regno >= ARM_F0_REGNUM && regno <= ARM_F7_REGNUM)
41c49b06
SB
634 {
635 store_nwfpe_register (regno, fp);
636 return;
637 }
638
639 /* Store fpsr. */
34e8f22d 640 if (ARM_FPS_REGNUM == regno || -1 == regno)
85ae890c 641 regcache_collect (ARM_FPS_REGNUM, (char *) &fp->fpsr);
41c49b06
SB
642}
643
644/* Fill GDB's register array with the floating-point register values
645 in *fpregsetp. */
646
647void
713f0374 648supply_fpregset (gdb_fpregset_t *fpregsetp)
ed9a39eb 649{
41c49b06
SB
650 int regno;
651 FPA11 *fp = (FPA11 *) fpregsetp;
652
653 /* Fetch fpsr. */
34e8f22d 654 supply_register (ARM_FPS_REGNUM, (char *) &fp->fpsr);
41c49b06
SB
655
656 /* Fetch the floating point registers. */
34e8f22d 657 for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++)
41c49b06
SB
658 {
659 fetch_nwfpe_register (regno, fp);
660 }
ed9a39eb
JM
661}
662
663int
664arm_linux_kernel_u_size (void)
665{
666 return (sizeof (struct user));
667}
668
ed9a39eb
JM
669static unsigned int
670get_linux_version (unsigned int *vmajor,
671 unsigned int *vminor,
672 unsigned int *vrelease)
673{
674 struct utsname info;
675 char *pmajor, *pminor, *prelease, *tail;
676
677 if (-1 == uname (&info))
678 {
fdf39c9a 679 warning ("Unable to determine GNU/Linux version.");
ed9a39eb
JM
680 return -1;
681 }
682
683 pmajor = strtok (info.release, ".");
684 pminor = strtok (NULL, ".");
685 prelease = strtok (NULL, ".");
686
687 *vmajor = (unsigned int) strtoul (pmajor, &tail, 0);
688 *vminor = (unsigned int) strtoul (pminor, &tail, 0);
689 *vrelease = (unsigned int) strtoul (prelease, &tail, 0);
690
691 return ((*vmajor << 16) | (*vminor << 8) | *vrelease);
692}
693
694void
695_initialize_arm_linux_nat (void)
696{
697 os_version = get_linux_version (&os_major, &os_minor, &os_release);
698}