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
37 extern 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
46 typedef union tagFPREG
47 {
48 unsigned int fSingle;
49 unsigned int fDouble[2];
50 unsigned int fExtended[3];
51 }
52 FPREG;
53
54 typedef 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 }
63 FPA11;
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
79 static 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
87 int
get_thread_id(ptid_t ptid)88 get_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
97 static void
fetch_nwfpe_single(unsigned int fn,FPA11 * fpa11)98 fetch_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
108 static void
fetch_nwfpe_double(unsigned int fn,FPA11 * fpa11)109 fetch_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
119 static void
fetch_nwfpe_none(unsigned int fn)120 fetch_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
128 static void
fetch_nwfpe_extended(unsigned int fn,FPA11 * fpa11)129 fetch_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
139 static void
fetch_nwfpe_register(int regno,FPA11 * fpa11)140 fetch_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
163 static void
store_nwfpe_single(unsigned int fn,FPA11 * fpa11)164 store_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
173 static void
store_nwfpe_double(unsigned int fn,FPA11 * fpa11)174 store_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
184 void
store_nwfpe_extended(unsigned int fn,FPA11 * fpa11)185 store_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
196 void
store_nwfpe_register(int regno,FPA11 * fpa11)197 store_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
223 static void
fetch_fpregister(int regno)224 fetch_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
272 static void
fetch_fpregs(void)273 fetch_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
320 static void
store_fpregister(int regno)321 store_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
358 static void
store_fpregs(void)359 store_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
396 static void
fetch_register(int regno)397 fetch_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, ®s);
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 *) ®s[regno]);
414
415 if (ARM_PS_REGNUM == regno)
416 {
417 if (arm_apcs_32)
418 supply_register (ARM_PS_REGNUM, (char *) ®s[ARM_CPSR_REGNUM]);
419 else
420 supply_register (ARM_PS_REGNUM, (char *) ®s[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 *) ®s[ARM_PC_REGNUM]);
427 }
428 }
429
430 /* Fetch all general registers of the process and store into
431 regcache. */
432
433 static void
fetch_regs(void)434 fetch_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, ®s);
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 *) ®s[regno]);
451
452 if (arm_apcs_32)
453 supply_register (ARM_PS_REGNUM, (char *) ®s[ARM_CPSR_REGNUM]);
454 else
455 supply_register (ARM_PS_REGNUM, (char *) ®s[ARM_PC_REGNUM]);
456
457 regs[ARM_PC_REGNUM] = ADDR_BITS_REMOVE (regs[ARM_PC_REGNUM]);
458 supply_register (ARM_PC_REGNUM, (char *) ®s[ARM_PC_REGNUM]);
459 }
460
461 /* Store all general registers of the process from the values in
462 regcache. */
463
464 static void
store_register(int regno)465 store_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, ®s);
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 *) ®s[regno]);
486
487 ret = ptrace (PTRACE_SETREGS, tid, 0, ®s);
488 if (ret < 0)
489 {
490 warning ("Unable to store general register.");
491 return;
492 }
493 }
494
495 static void
store_regs(void)496 store_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, ®s);
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 *) ®s[regno]);
516 }
517
518 ret = ptrace (PTRACE_SETREGS, tid, 0, ®s);
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
531 void
fetch_inferior_registers(int regno)532 fetch_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
553 void
store_inferior_registers(int regno)554 store_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
575 void
fill_gregset(gdb_gregset_t * gregsetp,int regno)576 fill_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
601 void
supply_gregset(gdb_gregset_t * gregsetp)602 supply_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 *) ®_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
622 void
fill_fpregset(gdb_fpregset_t * fpregsetp,int regno)623 fill_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
647 void
supply_fpregset(gdb_fpregset_t * fpregsetp)648 supply_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
663 int
arm_linux_kernel_u_size(void)664 arm_linux_kernel_u_size (void)
665 {
666 return (sizeof (struct user));
667 }
668
669 static unsigned int
get_linux_version(unsigned int * vmajor,unsigned int * vminor,unsigned int * vrelease)670 get_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
694 void
_initialize_arm_linux_nat(void)695 _initialize_arm_linux_nat (void)
696 {
697 os_version = get_linux_version (&os_major, &os_minor, &os_release);
698 }
699