OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [tags/] [VER_5_3/] [gdb-5.3/] [gdb/] [arm-linux-nat.c] - Blame information for rev 1778

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.