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