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