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