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