*** empty log message ***
[deliverable/binutils-gdb.git] / gdb / arm-linux-nat.c
CommitLineData
ed9a39eb 1/* GNU/Linux on ARM native support.
4e052eda 2 Copyright 1999, 2000, 2001 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
JM
26
27#include <sys/user.h>
28#include <sys/ptrace.h>
29#include <sys/utsname.h>
41c49b06 30#include <sys/procfs.h>
ed9a39eb 31
433144fb
DJ
32#include <asm/ptrace.h>
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
44#define 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 Linux operating system. Examples:
67
68 Linux 2.0.35 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
41c49b06
SB
81/* On Linux, threads are implemented as pseudo-processes, in which
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
ca6724c1
KB
84 individual thread (process) ID. get_thread_id () is used to
85 get 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;
105 supply_register (F0_REGNUM + fn, (char *) &mem[0]);
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;
116 supply_register (F0_REGNUM + fn, (char *) &mem[0]);
117}
118
119static void
56624b0a 120fetch_nwfpe_none (unsigned int fn)
ed9a39eb
JM
121{
122 unsigned int mem[3] =
123 {0, 0, 0};
124
125 supply_register (F0_REGNUM + fn, (char *) &mem[0]);
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 */
136 supply_register (F0_REGNUM + fn, (char *) &mem[0]);
137}
138
41c49b06
SB
139static void
140fetch_nwfpe_register (int regno, FPA11 * fpa11)
141{
142 int fn = regno - 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
ed9a39eb 163static void
56624b0a 164store_nwfpe_single (unsigned int fn, FPA11 * fpa11)
ed9a39eb
JM
165{
166 unsigned int mem[3];
167
168 read_register_gen (F0_REGNUM + fn, (char *) &mem[0]);
169 fpa11->fpreg[fn].fSingle = mem[0];
170 fpa11->fType[fn] = typeSingle;
171}
172
173static void
56624b0a 174store_nwfpe_double (unsigned int fn, FPA11 * fpa11)
ed9a39eb
JM
175{
176 unsigned int mem[3];
177
178 read_register_gen (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
56624b0a 185store_nwfpe_extended (unsigned int fn, FPA11 * fpa11)
ed9a39eb
JM
186{
187 unsigned int mem[3];
188
189 read_register_gen (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
41c49b06
SB
196void
197store_nwfpe_register (int regno, FPA11 * fpa11)
198{
199 if (register_valid[regno])
200 {
201 unsigned int fn = regno - 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 registers[]. */
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. */
241 if (FPS_REGNUM == regno)
242 supply_register (FPS_REGNUM, (char *) &fp.fpsr);
243
244 /* Fetch the floating point register. */
245 if (regno >= F0_REGNUM && regno <= F7_REGNUM)
246 {
247 int fn = regno - 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 registers[]. */
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. */
290 supply_register (FPS_REGNUM, (char *) &fp.fpsr);
291
292 /* Fetch the floating point registers. */
293 for (regno = F0_REGNUM; regno <= F7_REGNUM; regno++)
294 {
295 int fn = regno - 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
SB
317/* Save a particular register into the floating point state of the
318 process using the contents from registers[]. */
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. */
338 if (FPS_REGNUM == regno && register_valid[FPS_REGNUM])
339 read_register_gen (FPS_REGNUM, (char *) &fp.fpsr);
340
341 /* Store the floating point register. */
342 if (regno >= F0_REGNUM && regno <= 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
ed9a39eb
JM
355/* Save the whole floating point state of the process using
356 the contents from registers[]. */
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
JM
375 /* Store fpsr. */
376 if (register_valid[FPS_REGNUM])
377 read_register_gen (FPS_REGNUM, (char *) &fp.fpsr);
378
379 /* Store the floating point registers. */
380 for (regno = F0_REGNUM; regno <= F7_REGNUM; regno++)
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
SB
393/* Fetch a general register of the process and store into
394 registers[]. */
395
396static void
397fetch_register (int regno)
398{
399 int ret, tid;
400 struct pt_regs regs;
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
412 if (regno >= A1_REGNUM && regno < PC_REGNUM)
413 supply_register (regno, (char *) &regs.uregs[regno]);
414
415 if (PS_REGNUM == regno)
416 {
417 if (arm_apcs_32)
418 supply_register (PS_REGNUM, (char *) &regs.uregs[CPSR_REGNUM]);
419 else
420 supply_register (PS_REGNUM, (char *) &regs.uregs[PC_REGNUM]);
421 }
422
423 if (PC_REGNUM == regno)
424 {
425 regs.uregs[PC_REGNUM] = ADDR_BITS_REMOVE (regs.uregs[PC_REGNUM]);
426 supply_register (PC_REGNUM, (char *) &regs.uregs[PC_REGNUM]);
427 }
428}
429
ed9a39eb
JM
430/* Fetch all general registers of the process and store into
431 registers[]. */
432
433static void
434fetch_regs (void)
435{
41c49b06 436 int ret, regno, tid;
ed9a39eb
JM
437 struct pt_regs regs;
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
449 for (regno = A1_REGNUM; regno < PC_REGNUM; regno++)
450 supply_register (regno, (char *) &regs.uregs[regno]);
451
452 if (arm_apcs_32)
453 supply_register (PS_REGNUM, (char *) &regs.uregs[CPSR_REGNUM]);
454 else
455 supply_register (PS_REGNUM, (char *) &regs.uregs[PC_REGNUM]);
456
457 regs.uregs[PC_REGNUM] = ADDR_BITS_REMOVE (regs.uregs[PC_REGNUM]);
458 supply_register (PC_REGNUM, (char *) &regs.uregs[PC_REGNUM]);
459}
460
461/* Store all general registers of the process from the values in
462 registers[]. */
463
41c49b06
SB
464static void
465store_register (int regno)
466{
467 int ret, tid;
468 struct pt_regs regs;
469
470 if (!register_valid[regno])
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
484 if (regno >= A1_REGNUM && regno <= PC_REGNUM)
485 read_register_gen (regno, (char *) &regs.uregs[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
ed9a39eb
JM
495static void
496store_regs (void)
497{
41c49b06 498 int ret, regno, tid;
ed9a39eb
JM
499 struct pt_regs regs;
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
512 for (regno = A1_REGNUM; regno <= PC_REGNUM; regno++)
513 {
514 if (register_valid[regno])
515 read_register_gen (regno, (char *) &regs.uregs[regno]);
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 {
541 if (regno < F0_REGNUM || regno > FPS_REGNUM)
542 fetch_register (regno);
ed9a39eb 543
41c49b06
SB
544 if (regno >= F0_REGNUM && regno <= FPS_REGNUM)
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 {
563 if ((regno < F0_REGNUM) || (regno > FPS_REGNUM))
564 store_register (regno);
ed9a39eb 565
41c49b06
SB
566 if ((regno >= F0_REGNUM) && (regno <= FPS_REGNUM))
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;
581 for (regnum = A1_REGNUM; regnum <= PC_REGNUM; regnum++)
17fd1ad9 582 read_register_gen (regnum, (char *) &(*gregsetp)[regnum]);
41c49b06
SB
583 }
584 else if (regno >= A1_REGNUM && regno <= PC_REGNUM)
17fd1ad9 585 read_register_gen (regno, (char *) &(*gregsetp)[regno]);
41c49b06
SB
586
587 if (PS_REGNUM == regno || -1 == regno)
588 {
17fd1ad9
DJ
589 if (arm_apcs_32)
590 read_register_gen (PS_REGNUM, (char *) &(*gregsetp)[CPSR_REGNUM]);
591 else
592 read_register_gen (PC_REGNUM, (char *) &(*gregsetp)[PC_REGNUM]);
41c49b06 593 }
41c49b06
SB
594}
595
596/* Fill GDB's register array with the general-purpose register values
597 in *gregsetp. */
598
599void
713f0374 600supply_gregset (gdb_gregset_t *gregsetp)
41c49b06
SB
601{
602 int regno, reg_pc;
603
604 for (regno = A1_REGNUM; regno < PC_REGNUM; regno++)
605 supply_register (regno, (char *) &(*gregsetp)[regno]);
606
607 if (arm_apcs_32)
608 supply_register (PS_REGNUM, (char *) &(*gregsetp)[CPSR_REGNUM]);
609 else
610 supply_register (PS_REGNUM, (char *) &(*gregsetp)[PC_REGNUM]);
611
612 reg_pc = ADDR_BITS_REMOVE ((CORE_ADDR)(*gregsetp)[PC_REGNUM]);
613 supply_register (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
620void
713f0374 621fill_fpregset (gdb_fpregset_t *fpregsetp, int regno)
41c49b06
SB
622{
623 FPA11 *fp = (FPA11 *) fpregsetp;
624
625 if (-1 == regno)
626 {
627 int regnum;
628 for (regnum = F0_REGNUM; regnum <= F7_REGNUM; regnum++)
629 store_nwfpe_register (regnum, fp);
630 }
631 else if (regno >= F0_REGNUM && regno <= F7_REGNUM)
632 {
633 store_nwfpe_register (regno, fp);
634 return;
635 }
636
637 /* Store fpsr. */
17fd1ad9
DJ
638 if (FPS_REGNUM == regno || -1 == regno)
639 read_register_gen (FPS_REGNUM, (char *) &fp->fpsr);
41c49b06
SB
640}
641
642/* Fill GDB's register array with the floating-point register values
643 in *fpregsetp. */
644
645void
713f0374 646supply_fpregset (gdb_fpregset_t *fpregsetp)
ed9a39eb 647{
41c49b06
SB
648 int regno;
649 FPA11 *fp = (FPA11 *) fpregsetp;
650
651 /* Fetch fpsr. */
652 supply_register (FPS_REGNUM, (char *) &fp->fpsr);
653
654 /* Fetch the floating point registers. */
655 for (regno = F0_REGNUM; regno <= F7_REGNUM; regno++)
656 {
657 fetch_nwfpe_register (regno, fp);
658 }
ed9a39eb
JM
659}
660
661int
662arm_linux_kernel_u_size (void)
663{
664 return (sizeof (struct user));
665}
666
ed9a39eb
JM
667static unsigned int
668get_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
692void
693_initialize_arm_linux_nat (void)
694{
695 os_version = get_linux_version (&os_major, &os_minor, &os_release);
696}
This page took 0.118871 seconds and 4 git commands to generate.