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