Reviewed and approved by Alan Modra <amodra@bigpond.net.au>
[deliverable/binutils-gdb.git] / gdb / arm-linux-nat.c
... / ...
CommitLineData
1/* GNU/Linux on ARM native support.
2 Copyright 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
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"
25#include "regcache.h"
26
27#include "arm-tdep.h"
28
29#include <sys/user.h>
30#include <sys/ptrace.h>
31#include <sys/utsname.h>
32#include <sys/procfs.h>
33
34/* Prototypes for supply_gregset etc. */
35#include "gregset.h"
36
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
44#define ARM_CPSR_REGNUM 16
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
66 underlying GNU/Linux operating system. Examples:
67
68 GNU/Linux 2.0.35 GNU/Linux 2.2.12
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
81/* On GNU/Linux, threads are implemented as pseudo-processes, in which
82 case we may be tracing more than one process at a time. In that
83 case, inferior_ptid will contain the main process ID and the
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. */
86
87int
88get_thread_id (ptid_t ptid)
89{
90 int tid = TIDGET (ptid);
91 if (0 == tid)
92 tid = PIDGET (ptid);
93 return tid;
94}
95#define GET_THREAD_ID(PTID) get_thread_id ((PTID));
96
97static void
98fetch_nwfpe_single (unsigned int fn, FPA11 * fpa11)
99{
100 unsigned int mem[3];
101
102 mem[0] = fpa11->fpreg[fn].fSingle;
103 mem[1] = 0;
104 mem[2] = 0;
105 supply_register (ARM_F0_REGNUM + fn, (char *) &mem[0]);
106}
107
108static void
109fetch_nwfpe_double (unsigned int fn, FPA11 * fpa11)
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;
116 supply_register (ARM_F0_REGNUM + fn, (char *) &mem[0]);
117}
118
119static void
120fetch_nwfpe_none (unsigned int fn)
121{
122 unsigned int mem[3] =
123 {0, 0, 0};
124
125 supply_register (ARM_F0_REGNUM + fn, (char *) &mem[0]);
126}
127
128static void
129fetch_nwfpe_extended (unsigned int fn, FPA11 * fpa11)
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 */
136 supply_register (ARM_F0_REGNUM + fn, (char *) &mem[0]);
137}
138
139static void
140fetch_nwfpe_register (int regno, FPA11 * fpa11)
141{
142 int fn = regno - ARM_F0_REGNUM;
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
163static void
164store_nwfpe_single (unsigned int fn, FPA11 *fpa11)
165{
166 unsigned int mem[3];
167
168 regcache_collect (ARM_F0_REGNUM + fn, (char *) &mem[0]);
169 fpa11->fpreg[fn].fSingle = mem[0];
170 fpa11->fType[fn] = typeSingle;
171}
172
173static void
174store_nwfpe_double (unsigned int fn, FPA11 *fpa11)
175{
176 unsigned int mem[3];
177
178 regcache_collect (ARM_F0_REGNUM + fn, (char *) &mem[0]);
179 fpa11->fpreg[fn].fDouble[1] = mem[0];
180 fpa11->fpreg[fn].fDouble[0] = mem[1];
181 fpa11->fType[fn] = typeDouble;
182}
183
184void
185store_nwfpe_extended (unsigned int fn, FPA11 *fpa11)
186{
187 unsigned int mem[3];
188
189 regcache_collect (ARM_F0_REGNUM + fn, (char *) &mem[0]);
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
196void
197store_nwfpe_register (int regno, FPA11 * fpa11)
198{
199 if (register_cached (regno))
200 {
201 unsigned int fn = regno - ARM_F0_REGNUM;
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
221 state of the process and store it into regcache. */
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. */
230 tid = GET_THREAD_ID (inferior_ptid);
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. */
241 if (ARM_FPS_REGNUM == regno)
242 supply_register (ARM_FPS_REGNUM, (char *) &fp.fpsr);
243
244 /* Fetch the floating point register. */
245 if (regno >= ARM_F0_REGNUM && regno <= ARM_F7_REGNUM)
246 {
247 int fn = regno - ARM_F0_REGNUM;
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
270 into regcache. */
271
272static void
273fetch_fpregs (void)
274{
275 int ret, regno, tid;
276 FPA11 fp;
277
278 /* Get the thread id for the ptrace call. */
279 tid = GET_THREAD_ID (inferior_ptid);
280
281 /* Read the floating point state. */
282 ret = ptrace (PT_GETFPREGS, tid, 0, &fp);
283 if (ret < 0)
284 {
285 warning ("Unable to fetch the floating point registers.");
286 return;
287 }
288
289 /* Fetch fpsr. */
290 supply_register (ARM_FPS_REGNUM, (char *) &fp.fpsr);
291
292 /* Fetch the floating point registers. */
293 for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++)
294 {
295 int fn = regno - ARM_F0_REGNUM;
296
297 switch (fp.fType[fn])
298 {
299 case typeSingle:
300 fetch_nwfpe_single (fn, &fp);
301 break;
302
303 case typeDouble:
304 fetch_nwfpe_double (fn, &fp);
305 break;
306
307 case typeExtended:
308 fetch_nwfpe_extended (fn, &fp);
309 break;
310
311 default:
312 fetch_nwfpe_none (fn);
313 }
314 }
315}
316
317/* Save a particular register into the floating point state of the
318 process using the contents from regcache. */
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. */
327 tid = GET_THREAD_ID (inferior_ptid);
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. */
338 if (ARM_FPS_REGNUM == regno && register_cached (ARM_FPS_REGNUM))
339 regcache_collect (ARM_FPS_REGNUM, (char *) &fp.fpsr);
340
341 /* Store the floating point register. */
342 if (regno >= ARM_F0_REGNUM && regno <= ARM_F7_REGNUM)
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
355/* Save the whole floating point state of the process using
356 the contents from regcache. */
357
358static void
359store_fpregs (void)
360{
361 int ret, regno, tid;
362 FPA11 fp;
363
364 /* Get the thread id for the ptrace call. */
365 tid = GET_THREAD_ID (inferior_ptid);
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
375 /* Store fpsr. */
376 if (register_cached (ARM_FPS_REGNUM))
377 regcache_collect (ARM_FPS_REGNUM, (char *) &fp.fpsr);
378
379 /* Store the floating point registers. */
380 for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++)
381 {
382 fetch_nwfpe_register (regno, &fp);
383 }
384
385 ret = ptrace (PTRACE_SETFPREGS, tid, 0, &fp);
386 if (ret < 0)
387 {
388 warning ("Unable to store floating point registers.");
389 return;
390 }
391}
392
393/* Fetch a general register of the process and store into
394 regcache. */
395
396static void
397fetch_register (int regno)
398{
399 int ret, tid;
400 elf_gregset_t regs;
401
402 /* Get the thread id for the ptrace call. */
403 tid = GET_THREAD_ID (inferior_ptid);
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
412 if (regno >= ARM_A1_REGNUM && regno < ARM_PC_REGNUM)
413 supply_register (regno, (char *) &regs[regno]);
414
415 if (ARM_PS_REGNUM == regno)
416 {
417 if (arm_apcs_32)
418 supply_register (ARM_PS_REGNUM, (char *) &regs[ARM_CPSR_REGNUM]);
419 else
420 supply_register (ARM_PS_REGNUM, (char *) &regs[ARM_PC_REGNUM]);
421 }
422
423 if (ARM_PC_REGNUM == regno)
424 {
425 regs[ARM_PC_REGNUM] = ADDR_BITS_REMOVE (regs[ARM_PC_REGNUM]);
426 supply_register (ARM_PC_REGNUM, (char *) &regs[ARM_PC_REGNUM]);
427 }
428}
429
430/* Fetch all general registers of the process and store into
431 regcache. */
432
433static void
434fetch_regs (void)
435{
436 int ret, regno, tid;
437 elf_gregset_t regs;
438
439 /* Get the thread id for the ptrace call. */
440 tid = GET_THREAD_ID (inferior_ptid);
441
442 ret = ptrace (PTRACE_GETREGS, tid, 0, &regs);
443 if (ret < 0)
444 {
445 warning ("Unable to fetch general registers.");
446 return;
447 }
448
449 for (regno = ARM_A1_REGNUM; regno < ARM_PC_REGNUM; regno++)
450 supply_register (regno, (char *) &regs[regno]);
451
452 if (arm_apcs_32)
453 supply_register (ARM_PS_REGNUM, (char *) &regs[ARM_CPSR_REGNUM]);
454 else
455 supply_register (ARM_PS_REGNUM, (char *) &regs[ARM_PC_REGNUM]);
456
457 regs[ARM_PC_REGNUM] = ADDR_BITS_REMOVE (regs[ARM_PC_REGNUM]);
458 supply_register (ARM_PC_REGNUM, (char *) &regs[ARM_PC_REGNUM]);
459}
460
461/* Store all general registers of the process from the values in
462 regcache. */
463
464static void
465store_register (int regno)
466{
467 int ret, tid;
468 elf_gregset_t regs;
469
470 if (!register_cached (regno))
471 return;
472
473 /* Get the thread id for the ptrace call. */
474 tid = GET_THREAD_ID (inferior_ptid);
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
484 if (regno >= ARM_A1_REGNUM && regno <= ARM_PC_REGNUM)
485 regcache_collect (regno, (char *) &regs[regno]);
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
495static void
496store_regs (void)
497{
498 int ret, regno, tid;
499 elf_gregset_t regs;
500
501 /* Get the thread id for the ptrace call. */
502 tid = GET_THREAD_ID (inferior_ptid);
503
504 /* Fetch the general registers. */
505 ret = ptrace (PTRACE_GETREGS, tid, 0, &regs);
506 if (ret < 0)
507 {
508 warning ("Unable to fetch general registers.");
509 return;
510 }
511
512 for (regno = ARM_A1_REGNUM; regno <= ARM_PC_REGNUM; regno++)
513 {
514 if (register_cached (regno))
515 regcache_collect (regno, (char *) &regs[regno]);
516 }
517
518 ret = ptrace (PTRACE_SETREGS, tid, 0, &regs);
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{
534 if (-1 == regno)
535 {
536 fetch_regs ();
537 fetch_fpregs ();
538 }
539 else
540 {
541 if (regno < ARM_F0_REGNUM || regno > ARM_FPS_REGNUM)
542 fetch_register (regno);
543
544 if (regno >= ARM_F0_REGNUM && regno <= ARM_FPS_REGNUM)
545 fetch_fpregister (regno);
546 }
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{
556 if (-1 == regno)
557 {
558 store_regs ();
559 store_fpregs ();
560 }
561 else
562 {
563 if ((regno < ARM_F0_REGNUM) || (regno > ARM_FPS_REGNUM))
564 store_register (regno);
565
566 if ((regno >= ARM_F0_REGNUM) && (regno <= ARM_FPS_REGNUM))
567 store_fpregister (regno);
568 }
569}
570
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
576fill_gregset (gdb_gregset_t *gregsetp, int regno)
577{
578 if (-1 == regno)
579 {
580 int regnum;
581 for (regnum = ARM_A1_REGNUM; regnum <= ARM_PC_REGNUM; regnum++)
582 regcache_collect (regnum, (char *) &(*gregsetp)[regnum]);
583 }
584 else if (regno >= ARM_A1_REGNUM && regno <= ARM_PC_REGNUM)
585 regcache_collect (regno, (char *) &(*gregsetp)[regno]);
586
587 if (ARM_PS_REGNUM == regno || -1 == regno)
588 {
589 if (arm_apcs_32)
590 regcache_collect (ARM_PS_REGNUM,
591 (char *) &(*gregsetp)[ARM_CPSR_REGNUM]);
592 else
593 regcache_collect (ARM_PC_REGNUM,
594 (char *) &(*gregsetp)[ARM_PC_REGNUM]);
595 }
596}
597
598/* Fill GDB's register array with the general-purpose register values
599 in *gregsetp. */
600
601void
602supply_gregset (gdb_gregset_t *gregsetp)
603{
604 int regno, reg_pc;
605
606 for (regno = ARM_A1_REGNUM; regno < ARM_PC_REGNUM; regno++)
607 supply_register (regno, (char *) &(*gregsetp)[regno]);
608
609 if (arm_apcs_32)
610 supply_register (ARM_PS_REGNUM, (char *) &(*gregsetp)[ARM_CPSR_REGNUM]);
611 else
612 supply_register (ARM_PS_REGNUM, (char *) &(*gregsetp)[ARM_PC_REGNUM]);
613
614 reg_pc = ADDR_BITS_REMOVE ((CORE_ADDR)(*gregsetp)[ARM_PC_REGNUM]);
615 supply_register (ARM_PC_REGNUM, (char *) &reg_pc);
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
623fill_fpregset (gdb_fpregset_t *fpregsetp, int regno)
624{
625 FPA11 *fp = (FPA11 *) fpregsetp;
626
627 if (-1 == regno)
628 {
629 int regnum;
630 for (regnum = ARM_F0_REGNUM; regnum <= ARM_F7_REGNUM; regnum++)
631 store_nwfpe_register (regnum, fp);
632 }
633 else if (regno >= ARM_F0_REGNUM && regno <= ARM_F7_REGNUM)
634 {
635 store_nwfpe_register (regno, fp);
636 return;
637 }
638
639 /* Store fpsr. */
640 if (ARM_FPS_REGNUM == regno || -1 == regno)
641 regcache_collect (ARM_FPS_REGNUM, (char *) &fp->fpsr);
642}
643
644/* Fill GDB's register array with the floating-point register values
645 in *fpregsetp. */
646
647void
648supply_fpregset (gdb_fpregset_t *fpregsetp)
649{
650 int regno;
651 FPA11 *fp = (FPA11 *) fpregsetp;
652
653 /* Fetch fpsr. */
654 supply_register (ARM_FPS_REGNUM, (char *) &fp->fpsr);
655
656 /* Fetch the floating point registers. */
657 for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++)
658 {
659 fetch_nwfpe_register (regno, fp);
660 }
661}
662
663int
664arm_linux_kernel_u_size (void)
665{
666 return (sizeof (struct user));
667}
668
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 {
679 warning ("Unable to determine GNU/Linux version.");
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}
This page took 0.027329 seconds and 4 git commands to generate.