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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [gdb-7.1/] [gdb/] [arm-linux-nat.c] - Blame information for rev 227

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

Line No. Rev Author Line
1 227 jeremybenn
/* GNU/Linux on ARM native support.
2
   Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2008, 2009,
3
   2010 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 3 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, see <http://www.gnu.org/licenses/>.  */
19
 
20
#include "defs.h"
21
#include "inferior.h"
22
#include "gdbcore.h"
23
#include "gdb_string.h"
24
#include "regcache.h"
25
#include "target.h"
26
#include "linux-nat.h"
27
#include "target-descriptions.h"
28
 
29
#include "arm-tdep.h"
30
#include "arm-linux-tdep.h"
31
 
32
#include <sys/user.h>
33
#include <sys/ptrace.h>
34
#include <sys/utsname.h>
35
#include <sys/procfs.h>
36
 
37
/* Prototypes for supply_gregset etc. */
38
#include "gregset.h"
39
 
40
/* Defines ps_err_e, struct ps_prochandle.  */
41
#include "gdb_proc_service.h"
42
 
43
#include "features/arm-with-iwmmxt.c"
44
 
45
#ifndef PTRACE_GET_THREAD_AREA
46
#define PTRACE_GET_THREAD_AREA 22
47
#endif
48
 
49
#ifndef PTRACE_GETWMMXREGS
50
#define PTRACE_GETWMMXREGS 18
51
#define PTRACE_SETWMMXREGS 19
52
#endif
53
 
54
/* A flag for whether the WMMX registers are available.  */
55
static int arm_linux_has_wmmx_registers;
56
 
57
extern int arm_apcs_32;
58
 
59
/* The following variables are used to determine the version of the
60
   underlying GNU/Linux operating system.  Examples:
61
 
62
   GNU/Linux 2.0.35             GNU/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
 
73
static unsigned int os_version, os_major, os_minor, os_release;
74
 
75
/* On GNU/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_ptid will contain the main process ID and the
78
   individual thread (process) ID.  get_thread_id () is used to get
79
   the thread id if it's available, and the process id otherwise.  */
80
 
81
int
82
get_thread_id (ptid_t ptid)
83
{
84
  int tid = TIDGET (ptid);
85
  if (0 == tid)
86
    tid = PIDGET (ptid);
87
  return tid;
88
}
89
#define GET_THREAD_ID(PTID)     get_thread_id (PTID)
90
 
91
/* Get the value of a particular register from the floating point
92
   state of the process and store it into regcache.  */
93
 
94
static void
95
fetch_fpregister (struct regcache *regcache, int regno)
96
{
97
  int ret, tid;
98
  gdb_byte fp[ARM_LINUX_SIZEOF_NWFPE];
99
 
100
  /* Get the thread id for the ptrace call.  */
101
  tid = GET_THREAD_ID (inferior_ptid);
102
 
103
  /* Read the floating point state.  */
104
  ret = ptrace (PT_GETFPREGS, tid, 0, fp);
105
  if (ret < 0)
106
    {
107
      warning (_("Unable to fetch floating point register."));
108
      return;
109
    }
110
 
111
  /* Fetch fpsr.  */
112
  if (ARM_FPS_REGNUM == regno)
113
    regcache_raw_supply (regcache, ARM_FPS_REGNUM,
114
                         fp + NWFPE_FPSR_OFFSET);
115
 
116
  /* Fetch the floating point register.  */
117
  if (regno >= ARM_F0_REGNUM && regno <= ARM_F7_REGNUM)
118
    supply_nwfpe_register (regcache, regno, fp);
119
}
120
 
121
/* Get the whole floating point state of the process and store it
122
   into regcache.  */
123
 
124
static void
125
fetch_fpregs (struct regcache *regcache)
126
{
127
  int ret, regno, tid;
128
  gdb_byte fp[ARM_LINUX_SIZEOF_NWFPE];
129
 
130
  /* Get the thread id for the ptrace call.  */
131
  tid = GET_THREAD_ID (inferior_ptid);
132
 
133
  /* Read the floating point state.  */
134
  ret = ptrace (PT_GETFPREGS, tid, 0, fp);
135
  if (ret < 0)
136
    {
137
      warning (_("Unable to fetch the floating point registers."));
138
      return;
139
    }
140
 
141
  /* Fetch fpsr.  */
142
  regcache_raw_supply (regcache, ARM_FPS_REGNUM,
143
                       fp + NWFPE_FPSR_OFFSET);
144
 
145
  /* Fetch the floating point registers.  */
146
  for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++)
147
    supply_nwfpe_register (regcache, regno, fp);
148
}
149
 
150
/* Save a particular register into the floating point state of the
151
   process using the contents from regcache.  */
152
 
153
static void
154
store_fpregister (const struct regcache *regcache, int regno)
155
{
156
  int ret, tid;
157
  gdb_byte fp[ARM_LINUX_SIZEOF_NWFPE];
158
 
159
  /* Get the thread id for the ptrace call.  */
160
  tid = GET_THREAD_ID (inferior_ptid);
161
 
162
  /* Read the floating point state.  */
163
  ret = ptrace (PT_GETFPREGS, tid, 0, fp);
164
  if (ret < 0)
165
    {
166
      warning (_("Unable to fetch the floating point registers."));
167
      return;
168
    }
169
 
170
  /* Store fpsr.  */
171
  if (ARM_FPS_REGNUM == regno && regcache_valid_p (regcache, ARM_FPS_REGNUM))
172
    regcache_raw_collect (regcache, ARM_FPS_REGNUM, fp + NWFPE_FPSR_OFFSET);
173
 
174
  /* Store the floating point register.  */
175
  if (regno >= ARM_F0_REGNUM && regno <= ARM_F7_REGNUM)
176
    collect_nwfpe_register (regcache, regno, fp);
177
 
178
  ret = ptrace (PTRACE_SETFPREGS, tid, 0, fp);
179
  if (ret < 0)
180
    {
181
      warning (_("Unable to store floating point register."));
182
      return;
183
    }
184
}
185
 
186
/* Save the whole floating point state of the process using
187
   the contents from regcache.  */
188
 
189
static void
190
store_fpregs (const struct regcache *regcache)
191
{
192
  int ret, regno, tid;
193
  gdb_byte fp[ARM_LINUX_SIZEOF_NWFPE];
194
 
195
  /* Get the thread id for the ptrace call.  */
196
  tid = GET_THREAD_ID (inferior_ptid);
197
 
198
  /* Read the floating point state.  */
199
  ret = ptrace (PT_GETFPREGS, tid, 0, fp);
200
  if (ret < 0)
201
    {
202
      warning (_("Unable to fetch the floating point registers."));
203
      return;
204
    }
205
 
206
  /* Store fpsr.  */
207
  if (regcache_valid_p (regcache, ARM_FPS_REGNUM))
208
    regcache_raw_collect (regcache, ARM_FPS_REGNUM, fp + NWFPE_FPSR_OFFSET);
209
 
210
  /* Store the floating point registers.  */
211
  for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++)
212
    if (regcache_valid_p (regcache, regno))
213
      collect_nwfpe_register (regcache, regno, fp);
214
 
215
  ret = ptrace (PTRACE_SETFPREGS, tid, 0, fp);
216
  if (ret < 0)
217
    {
218
      warning (_("Unable to store floating point registers."));
219
      return;
220
    }
221
}
222
 
223
/* Fetch a general register of the process and store into
224
   regcache.  */
225
 
226
static void
227
fetch_register (struct regcache *regcache, int regno)
228
{
229
  int ret, tid;
230
  elf_gregset_t regs;
231
 
232
  /* Get the thread id for the ptrace call.  */
233
  tid = GET_THREAD_ID (inferior_ptid);
234
 
235
  ret = ptrace (PTRACE_GETREGS, tid, 0, &regs);
236
  if (ret < 0)
237
    {
238
      warning (_("Unable to fetch general register."));
239
      return;
240
    }
241
 
242
  if (regno >= ARM_A1_REGNUM && regno < ARM_PC_REGNUM)
243
    regcache_raw_supply (regcache, regno, (char *) &regs[regno]);
244
 
245
  if (ARM_PS_REGNUM == regno)
246
    {
247
      if (arm_apcs_32)
248
        regcache_raw_supply (regcache, ARM_PS_REGNUM,
249
                             (char *) &regs[ARM_CPSR_GREGNUM]);
250
      else
251
        regcache_raw_supply (regcache, ARM_PS_REGNUM,
252
                             (char *) &regs[ARM_PC_REGNUM]);
253
    }
254
 
255
  if (ARM_PC_REGNUM == regno)
256
    {
257
      regs[ARM_PC_REGNUM] = gdbarch_addr_bits_remove
258
                              (get_regcache_arch (regcache),
259
                               regs[ARM_PC_REGNUM]);
260
      regcache_raw_supply (regcache, ARM_PC_REGNUM,
261
                           (char *) &regs[ARM_PC_REGNUM]);
262
    }
263
}
264
 
265
/* Fetch all general registers of the process and store into
266
   regcache.  */
267
 
268
static void
269
fetch_regs (struct regcache *regcache)
270
{
271
  int ret, regno, tid;
272
  elf_gregset_t regs;
273
 
274
  /* Get the thread id for the ptrace call.  */
275
  tid = GET_THREAD_ID (inferior_ptid);
276
 
277
  ret = ptrace (PTRACE_GETREGS, tid, 0, &regs);
278
  if (ret < 0)
279
    {
280
      warning (_("Unable to fetch general registers."));
281
      return;
282
    }
283
 
284
  for (regno = ARM_A1_REGNUM; regno < ARM_PC_REGNUM; regno++)
285
    regcache_raw_supply (regcache, regno, (char *) &regs[regno]);
286
 
287
  if (arm_apcs_32)
288
    regcache_raw_supply (regcache, ARM_PS_REGNUM,
289
                         (char *) &regs[ARM_CPSR_GREGNUM]);
290
  else
291
    regcache_raw_supply (regcache, ARM_PS_REGNUM,
292
                         (char *) &regs[ARM_PC_REGNUM]);
293
 
294
  regs[ARM_PC_REGNUM] = gdbarch_addr_bits_remove
295
                          (get_regcache_arch (regcache), regs[ARM_PC_REGNUM]);
296
  regcache_raw_supply (regcache, ARM_PC_REGNUM,
297
                       (char *) &regs[ARM_PC_REGNUM]);
298
}
299
 
300
/* Store all general registers of the process from the values in
301
   regcache.  */
302
 
303
static void
304
store_register (const struct regcache *regcache, int regno)
305
{
306
  int ret, tid;
307
  elf_gregset_t regs;
308
 
309
  if (!regcache_valid_p (regcache, regno))
310
    return;
311
 
312
  /* Get the thread id for the ptrace call.  */
313
  tid = GET_THREAD_ID (inferior_ptid);
314
 
315
  /* Get the general registers from the process.  */
316
  ret = ptrace (PTRACE_GETREGS, tid, 0, &regs);
317
  if (ret < 0)
318
    {
319
      warning (_("Unable to fetch general registers."));
320
      return;
321
    }
322
 
323
  if (regno >= ARM_A1_REGNUM && regno <= ARM_PC_REGNUM)
324
    regcache_raw_collect (regcache, regno, (char *) &regs[regno]);
325
  else if (arm_apcs_32 && regno == ARM_PS_REGNUM)
326
    regcache_raw_collect (regcache, regno,
327
                         (char *) &regs[ARM_CPSR_GREGNUM]);
328
  else if (!arm_apcs_32 && regno == ARM_PS_REGNUM)
329
    regcache_raw_collect (regcache, ARM_PC_REGNUM,
330
                         (char *) &regs[ARM_PC_REGNUM]);
331
 
332
  ret = ptrace (PTRACE_SETREGS, tid, 0, &regs);
333
  if (ret < 0)
334
    {
335
      warning (_("Unable to store general register."));
336
      return;
337
    }
338
}
339
 
340
static void
341
store_regs (const struct regcache *regcache)
342
{
343
  int ret, regno, tid;
344
  elf_gregset_t regs;
345
 
346
  /* Get the thread id for the ptrace call.  */
347
  tid = GET_THREAD_ID (inferior_ptid);
348
 
349
  /* Fetch the general registers.  */
350
  ret = ptrace (PTRACE_GETREGS, tid, 0, &regs);
351
  if (ret < 0)
352
    {
353
      warning (_("Unable to fetch general registers."));
354
      return;
355
    }
356
 
357
  for (regno = ARM_A1_REGNUM; regno <= ARM_PC_REGNUM; regno++)
358
    {
359
      if (regcache_valid_p (regcache, regno))
360
        regcache_raw_collect (regcache, regno, (char *) &regs[regno]);
361
    }
362
 
363
  if (arm_apcs_32 && regcache_valid_p (regcache, ARM_PS_REGNUM))
364
    regcache_raw_collect (regcache, ARM_PS_REGNUM,
365
                         (char *) &regs[ARM_CPSR_GREGNUM]);
366
 
367
  ret = ptrace (PTRACE_SETREGS, tid, 0, &regs);
368
 
369
  if (ret < 0)
370
    {
371
      warning (_("Unable to store general registers."));
372
      return;
373
    }
374
}
375
 
376
/* Fetch all WMMX registers of the process and store into
377
   regcache.  */
378
 
379
#define IWMMXT_REGS_SIZE (16 * 8 + 6 * 4)
380
 
381
static void
382
fetch_wmmx_regs (struct regcache *regcache)
383
{
384
  char regbuf[IWMMXT_REGS_SIZE];
385
  int ret, regno, tid;
386
 
387
  /* Get the thread id for the ptrace call.  */
388
  tid = GET_THREAD_ID (inferior_ptid);
389
 
390
  ret = ptrace (PTRACE_GETWMMXREGS, tid, 0, regbuf);
391
  if (ret < 0)
392
    {
393
      warning (_("Unable to fetch WMMX registers."));
394
      return;
395
    }
396
 
397
  for (regno = 0; regno < 16; regno++)
398
    regcache_raw_supply (regcache, regno + ARM_WR0_REGNUM,
399
                         &regbuf[regno * 8]);
400
 
401
  for (regno = 0; regno < 2; regno++)
402
    regcache_raw_supply (regcache, regno + ARM_WCSSF_REGNUM,
403
                         &regbuf[16 * 8 + regno * 4]);
404
 
405
  for (regno = 0; regno < 4; regno++)
406
    regcache_raw_supply (regcache, regno + ARM_WCGR0_REGNUM,
407
                         &regbuf[16 * 8 + 2 * 4 + regno * 4]);
408
}
409
 
410
static void
411
store_wmmx_regs (const struct regcache *regcache)
412
{
413
  char regbuf[IWMMXT_REGS_SIZE];
414
  int ret, regno, tid;
415
 
416
  /* Get the thread id for the ptrace call.  */
417
  tid = GET_THREAD_ID (inferior_ptid);
418
 
419
  ret = ptrace (PTRACE_GETWMMXREGS, tid, 0, regbuf);
420
  if (ret < 0)
421
    {
422
      warning (_("Unable to fetch WMMX registers."));
423
      return;
424
    }
425
 
426
  for (regno = 0; regno < 16; regno++)
427
    if (regcache_valid_p (regcache, regno + ARM_WR0_REGNUM))
428
      regcache_raw_collect (regcache, regno + ARM_WR0_REGNUM,
429
                            &regbuf[regno * 8]);
430
 
431
  for (regno = 0; regno < 2; regno++)
432
    if (regcache_valid_p (regcache, regno + ARM_WCSSF_REGNUM))
433
      regcache_raw_collect (regcache, regno + ARM_WCSSF_REGNUM,
434
                            &regbuf[16 * 8 + regno * 4]);
435
 
436
  for (regno = 0; regno < 4; regno++)
437
    if (regcache_valid_p (regcache, regno + ARM_WCGR0_REGNUM))
438
      regcache_raw_collect (regcache, regno + ARM_WCGR0_REGNUM,
439
                            &regbuf[16 * 8 + 2 * 4 + regno * 4]);
440
 
441
  ret = ptrace (PTRACE_SETWMMXREGS, tid, 0, regbuf);
442
 
443
  if (ret < 0)
444
    {
445
      warning (_("Unable to store WMMX registers."));
446
      return;
447
    }
448
}
449
 
450
/* Fetch registers from the child process.  Fetch all registers if
451
   regno == -1, otherwise fetch all general registers or all floating
452
   point registers depending upon the value of regno.  */
453
 
454
static void
455
arm_linux_fetch_inferior_registers (struct target_ops *ops,
456
                                    struct regcache *regcache, int regno)
457
{
458
  if (-1 == regno)
459
    {
460
      fetch_regs (regcache);
461
      fetch_fpregs (regcache);
462
      if (arm_linux_has_wmmx_registers)
463
        fetch_wmmx_regs (regcache);
464
    }
465
  else
466
    {
467
      if (regno < ARM_F0_REGNUM || regno == ARM_PS_REGNUM)
468
        fetch_register (regcache, regno);
469
      else if (regno >= ARM_F0_REGNUM && regno <= ARM_FPS_REGNUM)
470
        fetch_fpregister (regcache, regno);
471
      else if (arm_linux_has_wmmx_registers
472
               && regno >= ARM_WR0_REGNUM && regno <= ARM_WCGR7_REGNUM)
473
        fetch_wmmx_regs (regcache);
474
    }
475
}
476
 
477
/* Store registers back into the inferior.  Store all registers if
478
   regno == -1, otherwise store all general registers or all floating
479
   point registers depending upon the value of regno.  */
480
 
481
static void
482
arm_linux_store_inferior_registers (struct target_ops *ops,
483
                                    struct regcache *regcache, int regno)
484
{
485
  if (-1 == regno)
486
    {
487
      store_regs (regcache);
488
      store_fpregs (regcache);
489
      if (arm_linux_has_wmmx_registers)
490
        store_wmmx_regs (regcache);
491
    }
492
  else
493
    {
494
      if (regno < ARM_F0_REGNUM || regno == ARM_PS_REGNUM)
495
        store_register (regcache, regno);
496
      else if ((regno >= ARM_F0_REGNUM) && (regno <= ARM_FPS_REGNUM))
497
        store_fpregister (regcache, regno);
498
      else if (arm_linux_has_wmmx_registers
499
               && regno >= ARM_WR0_REGNUM && regno <= ARM_WCGR7_REGNUM)
500
        store_wmmx_regs (regcache);
501
    }
502
}
503
 
504
/* Wrapper functions for the standard regset handling, used by
505
   thread debugging.  */
506
 
507
void
508
fill_gregset (const struct regcache *regcache,
509
              gdb_gregset_t *gregsetp, int regno)
510
{
511
  arm_linux_collect_gregset (NULL, regcache, regno, gregsetp, 0);
512
}
513
 
514
void
515
supply_gregset (struct regcache *regcache, const gdb_gregset_t *gregsetp)
516
{
517
  arm_linux_supply_gregset (NULL, regcache, -1, gregsetp, 0);
518
}
519
 
520
void
521
fill_fpregset (const struct regcache *regcache,
522
               gdb_fpregset_t *fpregsetp, int regno)
523
{
524
  arm_linux_collect_nwfpe (NULL, regcache, regno, fpregsetp, 0);
525
}
526
 
527
/* Fill GDB's register array with the floating-point register values
528
   in *fpregsetp.  */
529
 
530
void
531
supply_fpregset (struct regcache *regcache, const gdb_fpregset_t *fpregsetp)
532
{
533
  arm_linux_supply_nwfpe (NULL, regcache, -1, fpregsetp, 0);
534
}
535
 
536
/* Fetch the thread-local storage pointer for libthread_db.  */
537
 
538
ps_err_e
539
ps_get_thread_area (const struct ps_prochandle *ph,
540
                    lwpid_t lwpid, int idx, void **base)
541
{
542
  if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0)
543
    return PS_ERR;
544
 
545
  /* IDX is the bias from the thread pointer to the beginning of the
546
     thread descriptor.  It has to be subtracted due to implementation
547
     quirks in libthread_db.  */
548
  *base = (void *) ((char *)*base - idx);
549
 
550
  return PS_OK;
551
}
552
 
553
static unsigned int
554
get_linux_version (unsigned int *vmajor,
555
                   unsigned int *vminor,
556
                   unsigned int *vrelease)
557
{
558
  struct utsname info;
559
  char *pmajor, *pminor, *prelease, *tail;
560
 
561
  if (-1 == uname (&info))
562
    {
563
      warning (_("Unable to determine GNU/Linux version."));
564
      return -1;
565
    }
566
 
567
  pmajor = strtok (info.release, ".");
568
  pminor = strtok (NULL, ".");
569
  prelease = strtok (NULL, ".");
570
 
571
  *vmajor = (unsigned int) strtoul (pmajor, &tail, 0);
572
  *vminor = (unsigned int) strtoul (pminor, &tail, 0);
573
  *vrelease = (unsigned int) strtoul (prelease, &tail, 0);
574
 
575
  return ((*vmajor << 16) | (*vminor << 8) | *vrelease);
576
}
577
 
578
static const struct target_desc *
579
arm_linux_read_description (struct target_ops *ops)
580
{
581
  int ret;
582
  char regbuf[IWMMXT_REGS_SIZE];
583
 
584
  ret = ptrace (PTRACE_GETWMMXREGS, GET_THREAD_ID (inferior_ptid),
585
                0, regbuf);
586
  if (ret < 0)
587
    arm_linux_has_wmmx_registers = 0;
588
  else
589
    arm_linux_has_wmmx_registers = 1;
590
 
591
  if (arm_linux_has_wmmx_registers)
592
    return tdesc_arm_with_iwmmxt;
593
  else
594
    return NULL;
595
}
596
 
597
void _initialize_arm_linux_nat (void);
598
 
599
void
600
_initialize_arm_linux_nat (void)
601
{
602
  struct target_ops *t;
603
 
604
  os_version = get_linux_version (&os_major, &os_minor, &os_release);
605
 
606
  /* Fill in the generic GNU/Linux methods.  */
607
  t = linux_target ();
608
 
609
  /* Add our register access methods.  */
610
  t->to_fetch_registers = arm_linux_fetch_inferior_registers;
611
  t->to_store_registers = arm_linux_store_inferior_registers;
612
 
613
  t->to_read_description = arm_linux_read_description;
614
 
615
  /* Register the target.  */
616
  linux_nat_add_target (t);
617
 
618
  /* Initialize the standard target descriptions.  */
619
  initialize_tdesc_arm_with_iwmmxt ();
620
}

powered by: WebSVN 2.1.0

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