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

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gdb/] [gdb-6.8/] [gdb/] [arm-linux-nat.c] - Blame information for rev 25

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 25 jlechner
/* GNU/Linux on ARM native support.
2
   Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2008
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 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_REGNUM]);
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_REGNUM]);
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_REGNUM]);
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_REGNUM]);
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 regcache *regcache, int regno)
456
{
457
  if (-1 == regno)
458
    {
459
      fetch_regs (regcache);
460
      fetch_fpregs (regcache);
461
      if (arm_linux_has_wmmx_registers)
462
        fetch_wmmx_regs (regcache);
463
    }
464
  else
465
    {
466
      if (regno < ARM_F0_REGNUM || regno == ARM_PS_REGNUM)
467
        fetch_register (regcache, regno);
468
      else if (regno >= ARM_F0_REGNUM && regno <= ARM_FPS_REGNUM)
469
        fetch_fpregister (regcache, regno);
470
      else if (arm_linux_has_wmmx_registers
471
               && regno >= ARM_WR0_REGNUM && regno <= ARM_WCGR7_REGNUM)
472
        fetch_wmmx_regs (regcache);
473
    }
474
}
475
 
476
/* Store registers back into the inferior.  Store all registers if
477
   regno == -1, otherwise store all general registers or all floating
478
   point registers depending upon the value of regno.  */
479
 
480
static void
481
arm_linux_store_inferior_registers (struct regcache *regcache, int regno)
482
{
483
  if (-1 == regno)
484
    {
485
      store_regs (regcache);
486
      store_fpregs (regcache);
487
      if (arm_linux_has_wmmx_registers)
488
        store_wmmx_regs (regcache);
489
    }
490
  else
491
    {
492
      if (regno < ARM_F0_REGNUM || regno == ARM_PS_REGNUM)
493
        store_register (regcache, regno);
494
      else if ((regno >= ARM_F0_REGNUM) && (regno <= ARM_FPS_REGNUM))
495
        store_fpregister (regcache, regno);
496
      else if (arm_linux_has_wmmx_registers
497
               && regno >= ARM_WR0_REGNUM && regno <= ARM_WCGR7_REGNUM)
498
        store_wmmx_regs (regcache);
499
    }
500
}
501
 
502
/* Wrapper functions for the standard regset handling, used by
503
   thread debugging.  */
504
 
505
void
506
fill_gregset (const struct regcache *regcache,
507
              gdb_gregset_t *gregsetp, int regno)
508
{
509
  arm_linux_collect_gregset (NULL, regcache, regno, gregsetp, 0);
510
}
511
 
512
void
513
supply_gregset (struct regcache *regcache, const gdb_gregset_t *gregsetp)
514
{
515
  arm_linux_supply_gregset (NULL, regcache, -1, gregsetp, 0);
516
}
517
 
518
void
519
fill_fpregset (const struct regcache *regcache,
520
               gdb_fpregset_t *fpregsetp, int regno)
521
{
522
  arm_linux_collect_nwfpe (NULL, regcache, regno, fpregsetp, 0);
523
}
524
 
525
/* Fill GDB's register array with the floating-point register values
526
   in *fpregsetp.  */
527
 
528
void
529
supply_fpregset (struct regcache *regcache, const gdb_fpregset_t *fpregsetp)
530
{
531
  arm_linux_supply_nwfpe (NULL, regcache, -1, fpregsetp, 0);
532
}
533
 
534
/* Fetch the thread-local storage pointer for libthread_db.  */
535
 
536
ps_err_e
537
ps_get_thread_area (const struct ps_prochandle *ph,
538
                    lwpid_t lwpid, int idx, void **base)
539
{
540
  if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0)
541
    return PS_ERR;
542
 
543
  /* IDX is the bias from the thread pointer to the beginning of the
544
     thread descriptor.  It has to be subtracted due to implementation
545
     quirks in libthread_db.  */
546
  *base = (void *) ((char *)*base - idx);
547
 
548
  return PS_OK;
549
}
550
 
551
static unsigned int
552
get_linux_version (unsigned int *vmajor,
553
                   unsigned int *vminor,
554
                   unsigned int *vrelease)
555
{
556
  struct utsname info;
557
  char *pmajor, *pminor, *prelease, *tail;
558
 
559
  if (-1 == uname (&info))
560
    {
561
      warning (_("Unable to determine GNU/Linux version."));
562
      return -1;
563
    }
564
 
565
  pmajor = strtok (info.release, ".");
566
  pminor = strtok (NULL, ".");
567
  prelease = strtok (NULL, ".");
568
 
569
  *vmajor = (unsigned int) strtoul (pmajor, &tail, 0);
570
  *vminor = (unsigned int) strtoul (pminor, &tail, 0);
571
  *vrelease = (unsigned int) strtoul (prelease, &tail, 0);
572
 
573
  return ((*vmajor << 16) | (*vminor << 8) | *vrelease);
574
}
575
 
576
static const struct target_desc *
577
arm_linux_read_description (struct target_ops *ops)
578
{
579
  int ret;
580
  char regbuf[IWMMXT_REGS_SIZE];
581
 
582
  ret = ptrace (PTRACE_GETWMMXREGS, GET_THREAD_ID (inferior_ptid),
583
                0, regbuf);
584
  if (ret < 0)
585
    arm_linux_has_wmmx_registers = 0;
586
  else
587
    arm_linux_has_wmmx_registers = 1;
588
 
589
  if (arm_linux_has_wmmx_registers)
590
    return tdesc_arm_with_iwmmxt;
591
  else
592
    return NULL;
593
}
594
 
595
void _initialize_arm_linux_nat (void);
596
 
597
void
598
_initialize_arm_linux_nat (void)
599
{
600
  struct target_ops *t;
601
 
602
  os_version = get_linux_version (&os_major, &os_minor, &os_release);
603
 
604
  /* Fill in the generic GNU/Linux methods.  */
605
  t = linux_target ();
606
 
607
  /* Add our register access methods.  */
608
  t->to_fetch_registers = arm_linux_fetch_inferior_registers;
609
  t->to_store_registers = arm_linux_store_inferior_registers;
610
 
611
  t->to_read_description = arm_linux_read_description;
612
 
613
  /* Register the target.  */
614
  linux_nat_add_target (t);
615
 
616
  /* Initialize the standard target descriptions.  */
617
  initialize_tdesc_arm_with_iwmmxt ();
618
}

powered by: WebSVN 2.1.0

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