]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - gnu/usr.bin/gdb/arch/arm/armfbsd-nat.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / gnu / usr.bin / gdb / arch / arm / armfbsd-nat.c
1 /* $FreeBSD$ */
2
3  /* Native-dependent code for BSD Unix running on ARM's, for GDB.
4    Copyright 1988, 1989, 1991, 1992, 1994, 1996, 1999, 2002
5    Free Software Foundation, Inc.
6
7    This file is part of GDB.
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 59 Temple Place - Suite 330,
22    Boston, MA 02111-1307, USA.  */
23
24 #include "defs.h"
25
26 #ifndef FETCH_INFERIOR_REGISTERS
27 #ifndef CROSS_DEBUGGER
28 #error Not FETCH_INFERIOR_REGISTERS 
29 #endif
30 #endif /* !FETCH_INFERIOR_REGISTERS */
31
32 #include "arm-tdep.h"
33
34 #include <sys/types.h>
35 #ifndef CROSS_DEBUGGER
36 #include <sys/ptrace.h>
37 #include <machine/reg.h>
38 #include <machine/frame.h>
39 #endif
40 #include "inferior.h"
41 #include "regcache.h"
42 #include "gdbcore.h"
43
44 extern int arm_apcs_32;
45
46 #ifdef CROSS_DEBUGGER
47 struct reg {
48         unsigned int r[13];
49         unsigned int r_sp;
50         unsigned int r_lr;
51         unsigned int r_pc;
52         unsigned int r_cpsr;
53 };
54
55 typedef struct fp_extended_precision {
56         u_int32_t fp_exponent;
57         u_int32_t fp_mantissa_hi;
58         u_int32_t fp_mantissa_lo;
59 } fp_extended_precision_t;
60
61 typedef struct fp_extended_precision fp_reg_t;
62
63 struct fpreg {
64         unsigned int fpr_fpsr;
65         fp_reg_t fpr[8];
66 };
67 #endif
68
69 void
70 supply_gregset (struct reg *gregset)
71 {
72   int regno;
73   CORE_ADDR r_pc;
74
75   /* Integer registers.  */
76   for (regno = ARM_A1_REGNUM; regno < ARM_SP_REGNUM; regno++)
77     supply_register (regno, (char *) &gregset->r[regno]);
78
79   supply_register (ARM_SP_REGNUM, (char *) &gregset->r_sp);
80   supply_register (ARM_LR_REGNUM, (char *) &gregset->r_lr);
81   supply_register (ARM_PC_REGNUM, (char *) &gregset->r_pc);
82
83   if (arm_apcs_32)
84     supply_register (ARM_PS_REGNUM, (char *) &gregset->r_cpsr);
85   else
86     supply_register (ARM_PS_REGNUM, (char *) &gregset->r_pc);
87 }
88
89 /* Fill register REGNO (if it is a general-purpose register) in
90    *GREGSETPS with the value in GDB's register array.  If REGNO is -1,
91    do this for all registers.  */
92
93 void
94 fill_gregset (struct reg *gregset, int regno)
95 {
96   int i;
97
98   for (i = ARM_A1_REGNUM; i < ARM_SP_REGNUM; i++)
99     if ((regno == -1 || regno == i))
100       regcache_collect (i, &gregset->r[i]);
101   if (regno == -1 || regno == ARM_SP_REGNUM)
102       regcache_collect (ARM_SP_REGNUM, &gregset->r_sp);
103   if (regno == -1 || regno == ARM_LR_REGNUM)
104       regcache_collect (ARM_LR_REGNUM, &gregset->r_lr);
105   if (regno == -1 || regno == ARM_PC_REGNUM)
106       regcache_collect (ARM_PC_REGNUM, &gregset->r_pc);
107   if (regno == -1 || regno == ARM_PS_REGNUM)
108       regcache_collect (ARM_PS_REGNUM, &gregset->r_cpsr);
109 }
110
111 void
112 supply_fpregset (struct fpreg *fparegset)
113 {
114   int regno;
115
116   for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++)
117     supply_register
118       (regno, (char *) &fparegset->fpr[regno - ARM_F0_REGNUM]);
119
120   supply_register (ARM_FPS_REGNUM, (char *) &fparegset->fpr_fpsr);
121 }
122
123 void
124 fill_fpregset (struct fpreg *fparegset, int regno)
125 {
126   int i;
127
128   for (i = ARM_F0_REGNUM; i <= ARM_F7_REGNUM; i++)
129     if (regno == -1 || regno == i)
130       regcache_raw_supply(current_regcache, i,
131           &fparegset->fpr[i - ARM_F0_REGNUM]);
132   if (regno == -1 || regno == ARM_FPS_REGNUM)
133     regcache_raw_supply(current_regcache, ARM_FPS_REGNUM, 
134         &fparegset->fpr_fpsr);
135 }
136
137 static void
138 fetch_register (int regno)
139 {
140   struct reg inferior_registers;
141 #ifndef CROSS_DEBUGGER
142   int ret;
143
144   ret = ptrace (PT_GETREGS, PIDGET (inferior_ptid),
145                 (PTRACE_ARG3_TYPE) &inferior_registers, 0);
146
147   if (ret < 0)
148     {
149       warning ("unable to fetch general register");
150       return;
151     }
152 #endif
153
154   switch (regno)
155     {
156     case ARM_SP_REGNUM:
157       supply_register (ARM_SP_REGNUM, (char *) &inferior_registers.r_sp);
158       break;
159
160     case ARM_LR_REGNUM:
161       supply_register (ARM_LR_REGNUM, (char *) &inferior_registers.r_lr);
162       break;
163
164     case ARM_PC_REGNUM:
165       /* This is ok: we're running native... */
166       inferior_registers.r_pc = ADDR_BITS_REMOVE (inferior_registers.r_pc);
167       supply_register (ARM_PC_REGNUM, (char *) &inferior_registers.r_pc);
168       break;
169
170     case ARM_PS_REGNUM:
171       if (arm_apcs_32)
172         supply_register (ARM_PS_REGNUM, (char *) &inferior_registers.r_cpsr);
173       else
174         supply_register (ARM_PS_REGNUM, (char *) &inferior_registers.r_pc);
175       break;
176
177     default:
178       supply_register (regno, (char *) &inferior_registers.r[regno]);
179       break;
180     }
181 }
182
183 static void
184 fetch_regs (void)
185 {
186   struct reg inferior_registers;
187 #ifndef CROSS_DEBUGGER
188   int ret;
189 #endif
190   int regno;
191
192 #ifndef CROSS_DEBUGGER
193   ret = ptrace (PT_GETREGS, PIDGET (inferior_ptid),
194                 (PTRACE_ARG3_TYPE) &inferior_registers, 0);
195
196   if (ret < 0)
197     {
198       warning ("unable to fetch general registers");
199       return;
200     }
201 #endif
202
203   supply_gregset (&inferior_registers);
204 }
205
206 static void
207 fetch_fp_register (int regno)
208 {
209   struct fpreg inferior_fp_registers;
210 #ifndef CROSS_DEBUGGER
211   int ret;
212
213   ret = ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
214                 (PTRACE_ARG3_TYPE) &inferior_fp_registers, 0);
215
216   if (ret < 0)
217     {
218       warning ("unable to fetch floating-point register");
219       return;
220     }
221 #endif
222
223   switch (regno)
224     {
225     case ARM_FPS_REGNUM:
226       supply_register (ARM_FPS_REGNUM,
227                        (char *) &inferior_fp_registers.fpr_fpsr);
228       break;
229
230     default:
231       supply_register
232         (regno, (char *) &inferior_fp_registers.fpr[regno - ARM_F0_REGNUM]);
233       break;
234     }
235 }
236
237 static void
238 fetch_fp_regs (void)
239 {
240   struct fpreg inferior_fp_registers;
241 #ifndef CROSS_DEBUGGER
242   int ret;
243 #endif
244   int regno;
245
246 #ifndef CROSS_DEBUGGER
247   ret = ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
248                 (PTRACE_ARG3_TYPE) &inferior_fp_registers, 0);
249
250   if (ret < 0)
251     {
252       warning ("unable to fetch general registers");
253       return;
254     }
255 #endif
256
257   supply_fpregset (&inferior_fp_registers);
258 }
259
260 void
261 fetch_inferior_registers (int regno)
262 {
263   if (regno >= 0)
264     {
265       if (regno < ARM_F0_REGNUM || regno > ARM_FPS_REGNUM)
266         fetch_register (regno);
267       else
268         fetch_fp_register (regno);
269     }
270   else
271     {
272       fetch_regs ();
273       fetch_fp_regs ();
274     }
275 }
276
277
278 static void
279 store_register (int regno)
280 {
281   struct reg inferior_registers;
282 #ifndef CROSS_DEBUGGER
283   int ret;
284
285   ret = ptrace (PT_GETREGS, PIDGET (inferior_ptid),
286                 (PTRACE_ARG3_TYPE) &inferior_registers, 0);
287
288   if (ret < 0)
289     {
290       warning ("unable to fetch general registers");
291       return;
292     }
293 #endif
294
295   switch (regno)
296     {
297     case ARM_SP_REGNUM:
298       regcache_collect (ARM_SP_REGNUM, (char *) &inferior_registers.r_sp);
299       break;
300
301     case ARM_LR_REGNUM:
302       regcache_collect (ARM_LR_REGNUM, (char *) &inferior_registers.r_lr);
303       break;
304
305     case ARM_PC_REGNUM:
306       if (arm_apcs_32)
307         regcache_collect (ARM_PC_REGNUM, (char *) &inferior_registers.r_pc);
308       else
309         {
310           unsigned pc_val;
311
312           regcache_collect (ARM_PC_REGNUM, (char *) &pc_val);
313           
314           pc_val = ADDR_BITS_REMOVE (pc_val);
315           inferior_registers.r_pc
316             ^= ADDR_BITS_REMOVE (inferior_registers.r_pc);
317           inferior_registers.r_pc |= pc_val;
318         }
319       break;
320
321     case ARM_PS_REGNUM:
322       if (arm_apcs_32)
323         regcache_collect (ARM_PS_REGNUM, (char *) &inferior_registers.r_cpsr);
324       else
325         {
326           unsigned psr_val;
327
328           regcache_collect (ARM_PS_REGNUM, (char *) &psr_val);
329
330           psr_val ^= ADDR_BITS_REMOVE (psr_val);
331           inferior_registers.r_pc = ADDR_BITS_REMOVE (inferior_registers.r_pc);
332           inferior_registers.r_pc |= psr_val;
333         }
334       break;
335
336     default:
337       regcache_collect (regno, (char *) &inferior_registers.r[regno]);
338       break;
339     }
340
341 #ifndef CROSS_DEBUGGER
342   ret = ptrace (PT_SETREGS, PIDGET (inferior_ptid),
343                 (PTRACE_ARG3_TYPE) &inferior_registers, 0);
344
345   if (ret < 0)
346     warning ("unable to write register %d to inferior", regno);
347 #endif
348 }
349
350 static void
351 store_regs (void)
352 {
353   struct reg inferior_registers;
354   int ret;
355   int regno;
356
357
358   for (regno = ARM_A1_REGNUM; regno < ARM_SP_REGNUM; regno++)
359     regcache_collect (regno, (char *) &inferior_registers.r[regno]);
360
361   regcache_collect (ARM_SP_REGNUM, (char *) &inferior_registers.r_sp);
362   regcache_collect (ARM_LR_REGNUM, (char *) &inferior_registers.r_lr);
363
364   if (arm_apcs_32)
365     {
366       regcache_collect (ARM_PC_REGNUM, (char *) &inferior_registers.r_pc);
367       regcache_collect (ARM_PS_REGNUM, (char *) &inferior_registers.r_cpsr);
368     }
369   else
370     {
371       unsigned pc_val;
372       unsigned psr_val;
373
374       regcache_collect (ARM_PC_REGNUM, (char *) &pc_val);
375       regcache_collect (ARM_PS_REGNUM, (char *) &psr_val);
376           
377       pc_val = ADDR_BITS_REMOVE (pc_val);
378       psr_val ^= ADDR_BITS_REMOVE (psr_val);
379
380       inferior_registers.r_pc = pc_val | psr_val;
381     }
382
383 #ifndef CROSS_DEBUGGER
384   ret = ptrace (PT_SETREGS, PIDGET (inferior_ptid),
385                 (PTRACE_ARG3_TYPE) &inferior_registers, 0);
386
387   if (ret < 0)
388     warning ("unable to store general registers");
389 #endif
390 }
391
392 static void
393 store_fp_register (int regno)
394 {
395   struct fpreg inferior_fp_registers;
396 #ifndef CROSS_DEBUGGER
397   int ret;
398
399   ret = ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
400                 (PTRACE_ARG3_TYPE) &inferior_fp_registers, 0);
401
402   if (ret < 0)
403     {
404       warning ("unable to fetch floating-point registers");
405       return;
406     }
407 #endif
408
409   switch (regno)
410     {
411     case ARM_FPS_REGNUM:
412       regcache_collect (ARM_FPS_REGNUM,
413                         (char *) &inferior_fp_registers.fpr_fpsr);
414       break;
415
416     default:
417       regcache_collect
418         (regno, (char *) &inferior_fp_registers.fpr[regno - ARM_F0_REGNUM]);
419       break;
420     }
421
422 #ifndef CROSS_DEBUGGER
423   ret = ptrace (PT_SETFPREGS, PIDGET (inferior_ptid),
424                 (PTRACE_ARG3_TYPE) &inferior_fp_registers, 0);
425
426   if (ret < 0)
427     warning ("unable to write register %d to inferior", regno);
428 #endif
429 }
430
431 static void
432 store_fp_regs (void)
433 {
434   struct fpreg inferior_fp_registers;
435   int ret;
436   int regno;
437
438
439   for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++)
440     regcache_collect
441       (regno, (char *) &inferior_fp_registers.fpr[regno - ARM_F0_REGNUM]);
442
443   regcache_collect (ARM_FPS_REGNUM, (char *) &inferior_fp_registers.fpr_fpsr);
444
445 #ifndef CROSS_DEBUGGER
446   ret = ptrace (PT_SETFPREGS, PIDGET (inferior_ptid),
447                 (PTRACE_ARG3_TYPE) &inferior_fp_registers, 0);
448
449   if (ret < 0)
450     warning ("unable to store floating-point registers");
451 #endif
452 }
453
454 void
455 store_inferior_registers (int regno)
456 {
457   if (regno >= 0)
458     {
459       if (regno < ARM_F0_REGNUM || regno > ARM_FPS_REGNUM)
460         store_register (regno);
461       else
462         store_fp_register (regno);
463     }
464   else
465     {
466       store_regs ();
467       store_fp_regs ();
468     }
469 }
470
471
472 struct md_core
473 {
474   struct reg intreg;
475   struct fpreg freg;
476 };
477
478 static void
479 fetch_core_registers (char *core_reg_sect, unsigned core_reg_size,
480                       int which, CORE_ADDR ignore)
481 {
482   struct md_core *core_reg = (struct md_core *) core_reg_sect;
483   int regno;
484   CORE_ADDR r_pc;
485
486   supply_gregset (&core_reg->intreg);
487   supply_fpregset (&core_reg->freg);
488 }
489
490 static void
491 fetch_elfcore_registers (char *core_reg_sect, unsigned core_reg_size,
492                          int which, CORE_ADDR ignore)
493 {
494   struct reg gregset;
495   struct fpreg fparegset;
496
497   switch (which)
498     {
499     case 0:     /* Integer registers.  */
500       if (core_reg_size != sizeof (struct reg))
501         warning ("wrong size of register set in core file");
502       else
503         {
504           /* The memcpy may be unnecessary, but we can't really be sure
505              of the alignment of the data in the core file.  */
506           memcpy (&gregset, core_reg_sect, sizeof (gregset));
507           supply_gregset (&gregset);
508         }
509       break;
510
511     case 2:
512       if (core_reg_size != sizeof (struct fpreg))
513         warning ("wrong size of FPA register set in core file");
514       else
515         {
516           /* The memcpy may be unnecessary, but we can't really be sure
517              of the alignment of the data in the core file.  */
518           memcpy (&fparegset, core_reg_sect, sizeof (fparegset));
519           supply_fpregset (&fparegset);
520         }
521       break;
522
523     default:
524       /* Don't know what kind of register request this is; just ignore it.  */
525       break;
526     }
527 }
528
529 static struct core_fns arm_freebsd_core_fns =
530 {
531   bfd_target_unknown_flavour,           /* core_flovour.  */
532   default_check_format,                 /* check_format.  */
533   default_core_sniffer,                 /* core_sniffer.  */
534   fetch_core_registers,                 /* core_read_registers.  */
535   NULL
536 };
537
538 static struct core_fns arm_freebsd_elfcore_fns =
539 {
540   bfd_target_elf_flavour,               /* core_flovour.  */
541   default_check_format,                 /* check_format.  */
542   default_core_sniffer,                 /* core_sniffer.  */
543   fetch_elfcore_registers,              /* core_read_registers.  */
544   NULL
545 };
546
547 void
548 _initialize_arm_fbsdnat (void)
549 {
550   add_core_fns (&arm_freebsd_core_fns);
551   add_core_fns (&arm_freebsd_elfcore_fns);
552 }