Mention bug #.
[external/binutils.git] / gdb / arm-linux-nat.c
1 /* GNU/Linux on ARM native support.
2    Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007
3    Free Software Foundation, Inc.
4
5    This file is part of GDB.
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin Street, Fifth Floor,
20    Boston, MA 02110-1301, USA.  */
21
22 #include "defs.h"
23 #include "inferior.h"
24 #include "gdbcore.h"
25 #include "gdb_string.h"
26 #include "regcache.h"
27 #include "target.h"
28 #include "linux-nat.h"
29
30 #include "arm-tdep.h"
31 #include "arm-linux-tdep.h"
32
33 #include <sys/user.h>
34 #include <sys/ptrace.h>
35 #include <sys/utsname.h>
36 #include <sys/procfs.h>
37
38 /* Prototypes for supply_gregset etc. */
39 #include "gregset.h"
40
41 /* Defines ps_err_e, struct ps_prochandle.  */
42 #include "gdb_proc_service.h"
43
44 #ifndef PTRACE_GET_THREAD_AREA
45 #define PTRACE_GET_THREAD_AREA 22
46 #endif
47
48 extern int arm_apcs_32;
49
50 /* The following variables are used to determine the version of the
51    underlying GNU/Linux operating system.  Examples:
52
53    GNU/Linux 2.0.35             GNU/Linux 2.2.12
54    os_version = 0x00020023      os_version = 0x0002020c
55    os_major = 2                 os_major = 2
56    os_minor = 0                 os_minor = 2
57    os_release = 35              os_release = 12
58
59    Note: os_version = (os_major << 16) | (os_minor << 8) | os_release
60
61    These are initialized using get_linux_version() from
62    _initialize_arm_linux_nat().  */
63
64 static unsigned int os_version, os_major, os_minor, os_release;
65
66 /* On GNU/Linux, threads are implemented as pseudo-processes, in which
67    case we may be tracing more than one process at a time.  In that
68    case, inferior_ptid will contain the main process ID and the
69    individual thread (process) ID.  get_thread_id () is used to get
70    the thread id if it's available, and the process id otherwise.  */
71
72 int
73 get_thread_id (ptid_t ptid)
74 {
75   int tid = TIDGET (ptid);
76   if (0 == tid)
77     tid = PIDGET (ptid);
78   return tid;
79 }
80 #define GET_THREAD_ID(PTID)     get_thread_id ((PTID));
81
82 /* Get the value of a particular register from the floating point
83    state of the process and store it into regcache.  */
84
85 static void
86 fetch_fpregister (int regno)
87 {
88   int ret, tid;
89   gdb_byte fp[ARM_LINUX_SIZEOF_NWFPE];
90   
91   /* Get the thread id for the ptrace call.  */
92   tid = GET_THREAD_ID (inferior_ptid);
93
94   /* Read the floating point state.  */
95   ret = ptrace (PT_GETFPREGS, tid, 0, fp);
96   if (ret < 0)
97     {
98       warning (_("Unable to fetch floating point register."));
99       return;
100     }
101
102   /* Fetch fpsr.  */
103   if (ARM_FPS_REGNUM == regno)
104     regcache_raw_supply (current_regcache, ARM_FPS_REGNUM,
105                          fp + NWFPE_FPSR_OFFSET);
106
107   /* Fetch the floating point register.  */
108   if (regno >= ARM_F0_REGNUM && regno <= ARM_F7_REGNUM)
109     supply_nwfpe_register (current_regcache, regno, fp);
110 }
111
112 /* Get the whole floating point state of the process and store it
113    into regcache.  */
114
115 static void
116 fetch_fpregs (void)
117 {
118   int ret, regno, tid;
119   gdb_byte fp[ARM_LINUX_SIZEOF_NWFPE];
120
121   /* Get the thread id for the ptrace call.  */
122   tid = GET_THREAD_ID (inferior_ptid);
123   
124   /* Read the floating point state.  */
125   ret = ptrace (PT_GETFPREGS, tid, 0, fp);
126   if (ret < 0)
127     {
128       warning (_("Unable to fetch the floating point registers."));
129       return;
130     }
131
132   /* Fetch fpsr.  */
133   regcache_raw_supply (current_regcache, ARM_FPS_REGNUM,
134                        fp + NWFPE_FPSR_OFFSET);
135
136   /* Fetch the floating point registers.  */
137   for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++)
138     supply_nwfpe_register (current_regcache, regno, fp);
139 }
140
141 /* Save a particular register into the floating point state of the
142    process using the contents from regcache.  */
143
144 static void
145 store_fpregister (int regno)
146 {
147   int ret, tid;
148   gdb_byte fp[ARM_LINUX_SIZEOF_NWFPE];
149
150   /* Get the thread id for the ptrace call.  */
151   tid = GET_THREAD_ID (inferior_ptid);
152   
153   /* Read the floating point state.  */
154   ret = ptrace (PT_GETFPREGS, tid, 0, fp);
155   if (ret < 0)
156     {
157       warning (_("Unable to fetch the floating point registers."));
158       return;
159     }
160
161   /* Store fpsr.  */
162   if (ARM_FPS_REGNUM == regno && register_cached (ARM_FPS_REGNUM))
163     regcache_raw_collect (current_regcache, ARM_FPS_REGNUM,
164                           fp + NWFPE_FPSR_OFFSET);
165
166   /* Store the floating point register.  */
167   if (regno >= ARM_F0_REGNUM && regno <= ARM_F7_REGNUM)
168     collect_nwfpe_register (current_regcache, regno, fp);
169
170   ret = ptrace (PTRACE_SETFPREGS, tid, 0, fp);
171   if (ret < 0)
172     {
173       warning (_("Unable to store floating point register."));
174       return;
175     }
176 }
177
178 /* Save the whole floating point state of the process using
179    the contents from regcache.  */
180
181 static void
182 store_fpregs (void)
183 {
184   int ret, regno, tid;
185   gdb_byte fp[ARM_LINUX_SIZEOF_NWFPE];
186
187   /* Get the thread id for the ptrace call.  */
188   tid = GET_THREAD_ID (inferior_ptid);
189   
190   /* Read the floating point state.  */
191   ret = ptrace (PT_GETFPREGS, tid, 0, fp);
192   if (ret < 0)
193     {
194       warning (_("Unable to fetch the floating point registers."));
195       return;
196     }
197
198   /* Store fpsr.  */
199   if (register_cached (ARM_FPS_REGNUM))
200     regcache_raw_collect (current_regcache, ARM_FPS_REGNUM,
201                           fp + NWFPE_FPSR_OFFSET);
202
203   /* Store the floating point registers.  */
204   for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++)
205     if (register_cached (regno))
206       collect_nwfpe_register (current_regcache, regno, fp);
207
208   ret = ptrace (PTRACE_SETFPREGS, tid, 0, fp);
209   if (ret < 0)
210     {
211       warning (_("Unable to store floating point registers."));
212       return;
213     }
214 }
215
216 /* Fetch a general register of the process and store into
217    regcache.  */
218
219 static void
220 fetch_register (int regno)
221 {
222   int ret, tid;
223   elf_gregset_t regs;
224
225   /* Get the thread id for the ptrace call.  */
226   tid = GET_THREAD_ID (inferior_ptid);
227   
228   ret = ptrace (PTRACE_GETREGS, tid, 0, &regs);
229   if (ret < 0)
230     {
231       warning (_("Unable to fetch general register."));
232       return;
233     }
234
235   if (regno >= ARM_A1_REGNUM && regno < ARM_PC_REGNUM)
236     regcache_raw_supply (current_regcache, regno, (char *) &regs[regno]);
237
238   if (ARM_PS_REGNUM == regno)
239     {
240       if (arm_apcs_32)
241         regcache_raw_supply (current_regcache, ARM_PS_REGNUM,
242                              (char *) &regs[ARM_CPSR_REGNUM]);
243       else
244         regcache_raw_supply (current_regcache, ARM_PS_REGNUM,
245                              (char *) &regs[ARM_PC_REGNUM]);
246     }
247     
248   if (ARM_PC_REGNUM == regno)
249     { 
250       regs[ARM_PC_REGNUM] = ADDR_BITS_REMOVE (regs[ARM_PC_REGNUM]);
251       regcache_raw_supply (current_regcache, ARM_PC_REGNUM,
252                            (char *) &regs[ARM_PC_REGNUM]);
253     }
254 }
255
256 /* Fetch all general registers of the process and store into
257    regcache.  */
258
259 static void
260 fetch_regs (void)
261 {
262   int ret, regno, tid;
263   elf_gregset_t regs;
264
265   /* Get the thread id for the ptrace call.  */
266   tid = GET_THREAD_ID (inferior_ptid);
267   
268   ret = ptrace (PTRACE_GETREGS, tid, 0, &regs);
269   if (ret < 0)
270     {
271       warning (_("Unable to fetch general registers."));
272       return;
273     }
274
275   for (regno = ARM_A1_REGNUM; regno < ARM_PC_REGNUM; regno++)
276     regcache_raw_supply (current_regcache, regno, (char *) &regs[regno]);
277
278   if (arm_apcs_32)
279     regcache_raw_supply (current_regcache, ARM_PS_REGNUM,
280                          (char *) &regs[ARM_CPSR_REGNUM]);
281   else
282     regcache_raw_supply (current_regcache, ARM_PS_REGNUM,
283                          (char *) &regs[ARM_PC_REGNUM]);
284
285   regs[ARM_PC_REGNUM] = ADDR_BITS_REMOVE (regs[ARM_PC_REGNUM]);
286   regcache_raw_supply (current_regcache, ARM_PC_REGNUM,
287                        (char *) &regs[ARM_PC_REGNUM]);
288 }
289
290 /* Store all general registers of the process from the values in
291    regcache.  */
292
293 static void
294 store_register (int regno)
295 {
296   int ret, tid;
297   elf_gregset_t regs;
298   
299   if (!register_cached (regno))
300     return;
301
302   /* Get the thread id for the ptrace call.  */
303   tid = GET_THREAD_ID (inferior_ptid);
304   
305   /* Get the general registers from the process.  */
306   ret = ptrace (PTRACE_GETREGS, tid, 0, &regs);
307   if (ret < 0)
308     {
309       warning (_("Unable to fetch general registers."));
310       return;
311     }
312
313   if (regno >= ARM_A1_REGNUM && regno <= ARM_PC_REGNUM)
314     regcache_raw_collect (current_regcache, regno, (char *) &regs[regno]);
315   else if (arm_apcs_32 && regno == ARM_PS_REGNUM)
316     regcache_raw_collect (current_regcache, regno,
317                          (char *) &regs[ARM_CPSR_REGNUM]);
318   else if (!arm_apcs_32 && regno == ARM_PS_REGNUM)
319     regcache_raw_collect (current_regcache, ARM_PC_REGNUM,
320                          (char *) &regs[ARM_PC_REGNUM]);
321
322   ret = ptrace (PTRACE_SETREGS, tid, 0, &regs);
323   if (ret < 0)
324     {
325       warning (_("Unable to store general register."));
326       return;
327     }
328 }
329
330 static void
331 store_regs (void)
332 {
333   int ret, regno, tid;
334   elf_gregset_t regs;
335
336   /* Get the thread id for the ptrace call.  */
337   tid = GET_THREAD_ID (inferior_ptid);
338   
339   /* Fetch the general registers.  */
340   ret = ptrace (PTRACE_GETREGS, tid, 0, &regs);
341   if (ret < 0)
342     {
343       warning (_("Unable to fetch general registers."));
344       return;
345     }
346
347   for (regno = ARM_A1_REGNUM; regno <= ARM_PC_REGNUM; regno++)
348     {
349       if (register_cached (regno))
350         regcache_raw_collect (current_regcache, regno, (char *) &regs[regno]);
351     }
352
353   if (arm_apcs_32 && register_cached (ARM_PS_REGNUM))
354     regcache_raw_collect (current_regcache, ARM_PS_REGNUM,
355                          (char *) &regs[ARM_CPSR_REGNUM]);
356
357   ret = ptrace (PTRACE_SETREGS, tid, 0, &regs);
358
359   if (ret < 0)
360     {
361       warning (_("Unable to store general registers."));
362       return;
363     }
364 }
365
366 /* Fetch registers from the child process.  Fetch all registers if
367    regno == -1, otherwise fetch all general registers or all floating
368    point registers depending upon the value of regno.  */
369
370 static void
371 arm_linux_fetch_inferior_registers (int regno)
372 {
373   if (-1 == regno)
374     {
375       fetch_regs ();
376       fetch_fpregs ();
377     }
378   else 
379     {
380       if (regno < ARM_F0_REGNUM || regno > ARM_FPS_REGNUM)
381         fetch_register (regno);
382
383       if (regno >= ARM_F0_REGNUM && regno <= ARM_FPS_REGNUM)
384         fetch_fpregister (regno);
385     }
386 }
387
388 /* Store registers back into the inferior.  Store all registers if
389    regno == -1, otherwise store all general registers or all floating
390    point registers depending upon the value of regno.  */
391
392 static void
393 arm_linux_store_inferior_registers (int regno)
394 {
395   if (-1 == regno)
396     {
397       store_regs ();
398       store_fpregs ();
399     }
400   else
401     {
402       if ((regno < ARM_F0_REGNUM) || (regno > ARM_FPS_REGNUM))
403         store_register (regno);
404
405       if ((regno >= ARM_F0_REGNUM) && (regno <= ARM_FPS_REGNUM))
406         store_fpregister (regno);
407     }
408 }
409
410 /* Wrapper functions for the standard regset handling, used by
411    thread debugging.  */
412
413 void
414 fill_gregset (gdb_gregset_t *gregsetp, int regno)
415 {
416   arm_linux_collect_gregset (NULL, current_regcache, regno, gregsetp, 0);
417 }
418
419 void
420 supply_gregset (gdb_gregset_t *gregsetp)
421 {
422   arm_linux_supply_gregset (NULL, current_regcache, -1, gregsetp, 0);
423 }
424
425 void
426 fill_fpregset (gdb_fpregset_t *fpregsetp, int regno)
427 {
428   arm_linux_collect_nwfpe (NULL, current_regcache, regno, fpregsetp, 0);
429 }
430
431 /* Fill GDB's register array with the floating-point register values
432    in *fpregsetp.  */
433
434 void
435 supply_fpregset (gdb_fpregset_t *fpregsetp)
436 {
437   arm_linux_supply_nwfpe (NULL, current_regcache, -1, fpregsetp, 0);
438 }
439
440 int
441 arm_linux_kernel_u_size (void)
442 {
443   return (sizeof (struct user));
444 }
445
446 /* Fetch the thread-local storage pointer for libthread_db.  */
447
448 ps_err_e
449 ps_get_thread_area (const struct ps_prochandle *ph,
450                     lwpid_t lwpid, int idx, void **base)
451 {
452   if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0)
453     return PS_ERR;
454
455   /* IDX is the bias from the thread pointer to the beginning of the
456      thread descriptor.  It has to be subtracted due to implementation
457      quirks in libthread_db.  */
458   *base = (void *) ((char *)*base - idx);
459
460   return PS_OK;
461 }
462
463 static unsigned int
464 get_linux_version (unsigned int *vmajor,
465                    unsigned int *vminor,
466                    unsigned int *vrelease)
467 {
468   struct utsname info;
469   char *pmajor, *pminor, *prelease, *tail;
470
471   if (-1 == uname (&info))
472     {
473       warning (_("Unable to determine GNU/Linux version."));
474       return -1;
475     }
476
477   pmajor = strtok (info.release, ".");
478   pminor = strtok (NULL, ".");
479   prelease = strtok (NULL, ".");
480
481   *vmajor = (unsigned int) strtoul (pmajor, &tail, 0);
482   *vminor = (unsigned int) strtoul (pminor, &tail, 0);
483   *vrelease = (unsigned int) strtoul (prelease, &tail, 0);
484
485   return ((*vmajor << 16) | (*vminor << 8) | *vrelease);
486 }
487
488 void _initialize_arm_linux_nat (void);
489
490 void
491 _initialize_arm_linux_nat (void)
492 {
493   struct target_ops *t;
494
495   os_version = get_linux_version (&os_major, &os_minor, &os_release);
496
497   /* Fill in the generic GNU/Linux methods.  */
498   t = linux_target ();
499
500   /* Add our register access methods.  */
501   t->to_fetch_registers = arm_linux_fetch_inferior_registers;
502   t->to_store_registers = arm_linux_store_inferior_registers;
503
504   /* Register the target.  */
505   linux_nat_add_target (t);
506 }