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

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [gnu-src/] [gdb-7.2/] [gdb/] [arm-linux-nat.c] - Blame information for rev 365

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

Line No. Rev Author Line
1 330 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
#include "auxv.h"
29
 
30
#include "arm-tdep.h"
31
#include "arm-linux-tdep.h"
32
 
33
#include <elf/common.h>
34
#include <sys/user.h>
35
#include <sys/ptrace.h>
36
#include <sys/utsname.h>
37
#include <sys/procfs.h>
38
 
39
/* Prototypes for supply_gregset etc. */
40
#include "gregset.h"
41
 
42
/* Defines ps_err_e, struct ps_prochandle.  */
43
#include "gdb_proc_service.h"
44
 
45
#include "features/arm-with-iwmmxt.c"
46
#include "features/arm-with-vfpv2.c"
47
#include "features/arm-with-vfpv3.c"
48
#include "features/arm-with-neon.c"
49
 
50
#ifndef PTRACE_GET_THREAD_AREA
51
#define PTRACE_GET_THREAD_AREA 22
52
#endif
53
 
54
#ifndef PTRACE_GETWMMXREGS
55
#define PTRACE_GETWMMXREGS 18
56
#define PTRACE_SETWMMXREGS 19
57
#endif
58
 
59
#ifndef PTRACE_GETVFPREGS
60
#define PTRACE_GETVFPREGS 27
61
#define PTRACE_SETVFPREGS 28
62
#endif
63
 
64
/* These are in <asm/elf.h> in current kernels.  */
65
#define HWCAP_VFP       64
66
#define HWCAP_IWMMXT    512
67
#define HWCAP_NEON      4096
68
#define HWCAP_VFPv3     8192
69
#define HWCAP_VFPv3D16  16384
70
 
71
/* A flag for whether the WMMX registers are available.  */
72
static int arm_linux_has_wmmx_registers;
73
 
74
/* The number of 64-bit VFP registers we have (expect this to be 0,
75
   16, or 32). */
76
static int arm_linux_vfp_register_count;
77
 
78
extern int arm_apcs_32;
79
 
80
/* The following variables are used to determine the version of the
81
   underlying GNU/Linux operating system.  Examples:
82
 
83
   GNU/Linux 2.0.35             GNU/Linux 2.2.12
84
   os_version = 0x00020023      os_version = 0x0002020c
85
   os_major = 2                 os_major = 2
86
   os_minor = 0                 os_minor = 2
87
   os_release = 35              os_release = 12
88
 
89
   Note: os_version = (os_major << 16) | (os_minor << 8) | os_release
90
 
91
   These are initialized using get_linux_version() from
92
   _initialize_arm_linux_nat().  */
93
 
94
static unsigned int os_version, os_major, os_minor, os_release;
95
 
96
/* On GNU/Linux, threads are implemented as pseudo-processes, in which
97
   case we may be tracing more than one process at a time.  In that
98
   case, inferior_ptid will contain the main process ID and the
99
   individual thread (process) ID.  get_thread_id () is used to get
100
   the thread id if it's available, and the process id otherwise.  */
101
 
102
int
103
get_thread_id (ptid_t ptid)
104
{
105
  int tid = TIDGET (ptid);
106
  if (0 == tid)
107
    tid = PIDGET (ptid);
108
  return tid;
109
}
110
 
111
#define GET_THREAD_ID(PTID)     get_thread_id (PTID)
112
 
113
/* Get the value of a particular register from the floating point
114
   state of the process and store it into regcache.  */
115
 
116
static void
117
fetch_fpregister (struct regcache *regcache, int regno)
118
{
119
  int ret, tid;
120
  gdb_byte fp[ARM_LINUX_SIZEOF_NWFPE];
121
 
122
  /* Get the thread id for the ptrace call.  */
123
  tid = GET_THREAD_ID (inferior_ptid);
124
 
125
  /* Read the floating point state.  */
126
  ret = ptrace (PT_GETFPREGS, tid, 0, fp);
127
  if (ret < 0)
128
    {
129
      warning (_("Unable to fetch floating point register."));
130
      return;
131
    }
132
 
133
  /* Fetch fpsr.  */
134
  if (ARM_FPS_REGNUM == regno)
135
    regcache_raw_supply (regcache, ARM_FPS_REGNUM,
136
                         fp + NWFPE_FPSR_OFFSET);
137
 
138
  /* Fetch the floating point register.  */
139
  if (regno >= ARM_F0_REGNUM && regno <= ARM_F7_REGNUM)
140
    supply_nwfpe_register (regcache, regno, fp);
141
}
142
 
143
/* Get the whole floating point state of the process and store it
144
   into regcache.  */
145
 
146
static void
147
fetch_fpregs (struct regcache *regcache)
148
{
149
  int ret, regno, tid;
150
  gdb_byte fp[ARM_LINUX_SIZEOF_NWFPE];
151
 
152
  /* Get the thread id for the ptrace call.  */
153
  tid = GET_THREAD_ID (inferior_ptid);
154
 
155
  /* Read the floating point state.  */
156
  ret = ptrace (PT_GETFPREGS, tid, 0, fp);
157
  if (ret < 0)
158
    {
159
      warning (_("Unable to fetch the floating point registers."));
160
      return;
161
    }
162
 
163
  /* Fetch fpsr.  */
164
  regcache_raw_supply (regcache, ARM_FPS_REGNUM,
165
                       fp + NWFPE_FPSR_OFFSET);
166
 
167
  /* Fetch the floating point registers.  */
168
  for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++)
169
    supply_nwfpe_register (regcache, regno, fp);
170
}
171
 
172
/* Save a particular register into the floating point state of the
173
   process using the contents from regcache.  */
174
 
175
static void
176
store_fpregister (const struct regcache *regcache, int regno)
177
{
178
  int ret, tid;
179
  gdb_byte fp[ARM_LINUX_SIZEOF_NWFPE];
180
 
181
  /* Get the thread id for the ptrace call.  */
182
  tid = GET_THREAD_ID (inferior_ptid);
183
 
184
  /* Read the floating point state.  */
185
  ret = ptrace (PT_GETFPREGS, tid, 0, fp);
186
  if (ret < 0)
187
    {
188
      warning (_("Unable to fetch the floating point registers."));
189
      return;
190
    }
191
 
192
  /* Store fpsr.  */
193
  if (ARM_FPS_REGNUM == regno && regcache_valid_p (regcache, ARM_FPS_REGNUM))
194
    regcache_raw_collect (regcache, ARM_FPS_REGNUM, fp + NWFPE_FPSR_OFFSET);
195
 
196
  /* Store the floating point register.  */
197
  if (regno >= ARM_F0_REGNUM && regno <= ARM_F7_REGNUM)
198
    collect_nwfpe_register (regcache, regno, fp);
199
 
200
  ret = ptrace (PTRACE_SETFPREGS, tid, 0, fp);
201
  if (ret < 0)
202
    {
203
      warning (_("Unable to store floating point register."));
204
      return;
205
    }
206
}
207
 
208
/* Save the whole floating point state of the process using
209
   the contents from regcache.  */
210
 
211
static void
212
store_fpregs (const struct regcache *regcache)
213
{
214
  int ret, regno, tid;
215
  gdb_byte fp[ARM_LINUX_SIZEOF_NWFPE];
216
 
217
  /* Get the thread id for the ptrace call.  */
218
  tid = GET_THREAD_ID (inferior_ptid);
219
 
220
  /* Read the floating point state.  */
221
  ret = ptrace (PT_GETFPREGS, tid, 0, fp);
222
  if (ret < 0)
223
    {
224
      warning (_("Unable to fetch the floating point registers."));
225
      return;
226
    }
227
 
228
  /* Store fpsr.  */
229
  if (regcache_valid_p (regcache, ARM_FPS_REGNUM))
230
    regcache_raw_collect (regcache, ARM_FPS_REGNUM, fp + NWFPE_FPSR_OFFSET);
231
 
232
  /* Store the floating point registers.  */
233
  for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++)
234
    if (regcache_valid_p (regcache, regno))
235
      collect_nwfpe_register (regcache, regno, fp);
236
 
237
  ret = ptrace (PTRACE_SETFPREGS, tid, 0, fp);
238
  if (ret < 0)
239
    {
240
      warning (_("Unable to store floating point registers."));
241
      return;
242
    }
243
}
244
 
245
/* Fetch a general register of the process and store into
246
   regcache.  */
247
 
248
static void
249
fetch_register (struct regcache *regcache, int regno)
250
{
251
  int ret, tid;
252
  elf_gregset_t regs;
253
 
254
  /* Get the thread id for the ptrace call.  */
255
  tid = GET_THREAD_ID (inferior_ptid);
256
 
257
  ret = ptrace (PTRACE_GETREGS, tid, 0, &regs);
258
  if (ret < 0)
259
    {
260
      warning (_("Unable to fetch general register."));
261
      return;
262
    }
263
 
264
  if (regno >= ARM_A1_REGNUM && regno < ARM_PC_REGNUM)
265
    regcache_raw_supply (regcache, regno, (char *) &regs[regno]);
266
 
267
  if (ARM_PS_REGNUM == regno)
268
    {
269
      if (arm_apcs_32)
270
        regcache_raw_supply (regcache, ARM_PS_REGNUM,
271
                             (char *) &regs[ARM_CPSR_GREGNUM]);
272
      else
273
        regcache_raw_supply (regcache, ARM_PS_REGNUM,
274
                             (char *) &regs[ARM_PC_REGNUM]);
275
    }
276
 
277
  if (ARM_PC_REGNUM == regno)
278
    {
279
      regs[ARM_PC_REGNUM] = gdbarch_addr_bits_remove
280
                              (get_regcache_arch (regcache),
281
                               regs[ARM_PC_REGNUM]);
282
      regcache_raw_supply (regcache, ARM_PC_REGNUM,
283
                           (char *) &regs[ARM_PC_REGNUM]);
284
    }
285
}
286
 
287
/* Fetch all general registers of the process and store into
288
   regcache.  */
289
 
290
static void
291
fetch_regs (struct regcache *regcache)
292
{
293
  int ret, regno, tid;
294
  elf_gregset_t regs;
295
 
296
  /* Get the thread id for the ptrace call.  */
297
  tid = GET_THREAD_ID (inferior_ptid);
298
 
299
  ret = ptrace (PTRACE_GETREGS, tid, 0, &regs);
300
  if (ret < 0)
301
    {
302
      warning (_("Unable to fetch general registers."));
303
      return;
304
    }
305
 
306
  for (regno = ARM_A1_REGNUM; regno < ARM_PC_REGNUM; regno++)
307
    regcache_raw_supply (regcache, regno, (char *) &regs[regno]);
308
 
309
  if (arm_apcs_32)
310
    regcache_raw_supply (regcache, ARM_PS_REGNUM,
311
                         (char *) &regs[ARM_CPSR_GREGNUM]);
312
  else
313
    regcache_raw_supply (regcache, ARM_PS_REGNUM,
314
                         (char *) &regs[ARM_PC_REGNUM]);
315
 
316
  regs[ARM_PC_REGNUM] = gdbarch_addr_bits_remove
317
                          (get_regcache_arch (regcache), regs[ARM_PC_REGNUM]);
318
  regcache_raw_supply (regcache, ARM_PC_REGNUM,
319
                       (char *) &regs[ARM_PC_REGNUM]);
320
}
321
 
322
/* Store all general registers of the process from the values in
323
   regcache.  */
324
 
325
static void
326
store_register (const struct regcache *regcache, int regno)
327
{
328
  int ret, tid;
329
  elf_gregset_t regs;
330
 
331
  if (!regcache_valid_p (regcache, regno))
332
    return;
333
 
334
  /* Get the thread id for the ptrace call.  */
335
  tid = GET_THREAD_ID (inferior_ptid);
336
 
337
  /* Get the general registers from the process.  */
338
  ret = ptrace (PTRACE_GETREGS, tid, 0, &regs);
339
  if (ret < 0)
340
    {
341
      warning (_("Unable to fetch general registers."));
342
      return;
343
    }
344
 
345
  if (regno >= ARM_A1_REGNUM && regno <= ARM_PC_REGNUM)
346
    regcache_raw_collect (regcache, regno, (char *) &regs[regno]);
347
  else if (arm_apcs_32 && regno == ARM_PS_REGNUM)
348
    regcache_raw_collect (regcache, regno,
349
                         (char *) &regs[ARM_CPSR_GREGNUM]);
350
  else if (!arm_apcs_32 && regno == ARM_PS_REGNUM)
351
    regcache_raw_collect (regcache, ARM_PC_REGNUM,
352
                         (char *) &regs[ARM_PC_REGNUM]);
353
 
354
  ret = ptrace (PTRACE_SETREGS, tid, 0, &regs);
355
  if (ret < 0)
356
    {
357
      warning (_("Unable to store general register."));
358
      return;
359
    }
360
}
361
 
362
static void
363
store_regs (const struct regcache *regcache)
364
{
365
  int ret, regno, tid;
366
  elf_gregset_t regs;
367
 
368
  /* Get the thread id for the ptrace call.  */
369
  tid = GET_THREAD_ID (inferior_ptid);
370
 
371
  /* Fetch the general registers.  */
372
  ret = ptrace (PTRACE_GETREGS, tid, 0, &regs);
373
  if (ret < 0)
374
    {
375
      warning (_("Unable to fetch general registers."));
376
      return;
377
    }
378
 
379
  for (regno = ARM_A1_REGNUM; regno <= ARM_PC_REGNUM; regno++)
380
    {
381
      if (regcache_valid_p (regcache, regno))
382
        regcache_raw_collect (regcache, regno, (char *) &regs[regno]);
383
    }
384
 
385
  if (arm_apcs_32 && regcache_valid_p (regcache, ARM_PS_REGNUM))
386
    regcache_raw_collect (regcache, ARM_PS_REGNUM,
387
                         (char *) &regs[ARM_CPSR_GREGNUM]);
388
 
389
  ret = ptrace (PTRACE_SETREGS, tid, 0, &regs);
390
 
391
  if (ret < 0)
392
    {
393
      warning (_("Unable to store general registers."));
394
      return;
395
    }
396
}
397
 
398
/* Fetch all WMMX registers of the process and store into
399
   regcache.  */
400
 
401
#define IWMMXT_REGS_SIZE (16 * 8 + 6 * 4)
402
 
403
static void
404
fetch_wmmx_regs (struct regcache *regcache)
405
{
406
  char regbuf[IWMMXT_REGS_SIZE];
407
  int ret, regno, tid;
408
 
409
  /* Get the thread id for the ptrace call.  */
410
  tid = GET_THREAD_ID (inferior_ptid);
411
 
412
  ret = ptrace (PTRACE_GETWMMXREGS, tid, 0, regbuf);
413
  if (ret < 0)
414
    {
415
      warning (_("Unable to fetch WMMX registers."));
416
      return;
417
    }
418
 
419
  for (regno = 0; regno < 16; regno++)
420
    regcache_raw_supply (regcache, regno + ARM_WR0_REGNUM,
421
                         &regbuf[regno * 8]);
422
 
423
  for (regno = 0; regno < 2; regno++)
424
    regcache_raw_supply (regcache, regno + ARM_WCSSF_REGNUM,
425
                         &regbuf[16 * 8 + regno * 4]);
426
 
427
  for (regno = 0; regno < 4; regno++)
428
    regcache_raw_supply (regcache, regno + ARM_WCGR0_REGNUM,
429
                         &regbuf[16 * 8 + 2 * 4 + regno * 4]);
430
}
431
 
432
static void
433
store_wmmx_regs (const struct regcache *regcache)
434
{
435
  char regbuf[IWMMXT_REGS_SIZE];
436
  int ret, regno, tid;
437
 
438
  /* Get the thread id for the ptrace call.  */
439
  tid = GET_THREAD_ID (inferior_ptid);
440
 
441
  ret = ptrace (PTRACE_GETWMMXREGS, tid, 0, regbuf);
442
  if (ret < 0)
443
    {
444
      warning (_("Unable to fetch WMMX registers."));
445
      return;
446
    }
447
 
448
  for (regno = 0; regno < 16; regno++)
449
    if (regcache_valid_p (regcache, regno + ARM_WR0_REGNUM))
450
      regcache_raw_collect (regcache, regno + ARM_WR0_REGNUM,
451
                            &regbuf[regno * 8]);
452
 
453
  for (regno = 0; regno < 2; regno++)
454
    if (regcache_valid_p (regcache, regno + ARM_WCSSF_REGNUM))
455
      regcache_raw_collect (regcache, regno + ARM_WCSSF_REGNUM,
456
                            &regbuf[16 * 8 + regno * 4]);
457
 
458
  for (regno = 0; regno < 4; regno++)
459
    if (regcache_valid_p (regcache, regno + ARM_WCGR0_REGNUM))
460
      regcache_raw_collect (regcache, regno + ARM_WCGR0_REGNUM,
461
                            &regbuf[16 * 8 + 2 * 4 + regno * 4]);
462
 
463
  ret = ptrace (PTRACE_SETWMMXREGS, tid, 0, regbuf);
464
 
465
  if (ret < 0)
466
    {
467
      warning (_("Unable to store WMMX registers."));
468
      return;
469
    }
470
}
471
 
472
/* Fetch and store VFP Registers.  The kernel object has space for 32
473
   64-bit registers, and the FPSCR.  This is even when on a VFPv2 or
474
   VFPv3D16 target.  */
475
#define VFP_REGS_SIZE (32 * 8 + 4)
476
 
477
static void
478
fetch_vfp_regs (struct regcache *regcache)
479
{
480
  char regbuf[VFP_REGS_SIZE];
481
  int ret, regno, tid;
482
 
483
  /* Get the thread id for the ptrace call.  */
484
  tid = GET_THREAD_ID (inferior_ptid);
485
 
486
  ret = ptrace (PTRACE_GETVFPREGS, tid, 0, regbuf);
487
  if (ret < 0)
488
    {
489
      warning (_("Unable to fetch VFP registers."));
490
      return;
491
    }
492
 
493
  for (regno = 0; regno < arm_linux_vfp_register_count; regno++)
494
    regcache_raw_supply (regcache, regno + ARM_D0_REGNUM,
495
                         (char *) regbuf + regno * 8);
496
 
497
  regcache_raw_supply (regcache, ARM_FPSCR_REGNUM,
498
                       (char *) regbuf + 32 * 8);
499
}
500
 
501
static void
502
store_vfp_regs (const struct regcache *regcache)
503
{
504
  char regbuf[VFP_REGS_SIZE];
505
  int ret, regno, tid;
506
 
507
  /* Get the thread id for the ptrace call.  */
508
  tid = GET_THREAD_ID (inferior_ptid);
509
 
510
  ret = ptrace (PTRACE_GETVFPREGS, tid, 0, regbuf);
511
  if (ret < 0)
512
    {
513
      warning (_("Unable to fetch VFP registers (for update)."));
514
      return;
515
    }
516
 
517
  for (regno = 0; regno < arm_linux_vfp_register_count; regno++)
518
    regcache_raw_collect (regcache, regno + ARM_D0_REGNUM,
519
                          (char *) regbuf + regno * 8);
520
 
521
  regcache_raw_collect (regcache, ARM_FPSCR_REGNUM,
522
                        (char *) regbuf + 32 * 8);
523
 
524
  ret = ptrace (PTRACE_SETVFPREGS, tid, 0, regbuf);
525
 
526
  if (ret < 0)
527
    {
528
      warning (_("Unable to store VFP registers."));
529
      return;
530
    }
531
}
532
 
533
/* Fetch registers from the child process.  Fetch all registers if
534
   regno == -1, otherwise fetch all general registers or all floating
535
   point registers depending upon the value of regno.  */
536
 
537
static void
538
arm_linux_fetch_inferior_registers (struct target_ops *ops,
539
                                    struct regcache *regcache, int regno)
540
{
541
  if (-1 == regno)
542
    {
543
      fetch_regs (regcache);
544
      fetch_fpregs (regcache);
545
      if (arm_linux_has_wmmx_registers)
546
        fetch_wmmx_regs (regcache);
547
      if (arm_linux_vfp_register_count > 0)
548
        fetch_vfp_regs (regcache);
549
    }
550
  else
551
    {
552
      if (regno < ARM_F0_REGNUM || regno == ARM_PS_REGNUM)
553
        fetch_register (regcache, regno);
554
      else if (regno >= ARM_F0_REGNUM && regno <= ARM_FPS_REGNUM)
555
        fetch_fpregister (regcache, regno);
556
      else if (arm_linux_has_wmmx_registers
557
               && regno >= ARM_WR0_REGNUM && regno <= ARM_WCGR7_REGNUM)
558
        fetch_wmmx_regs (regcache);
559
      else if (arm_linux_vfp_register_count > 0
560
               && regno >= ARM_D0_REGNUM
561
               && regno <= ARM_D0_REGNUM + arm_linux_vfp_register_count)
562
        fetch_vfp_regs (regcache);
563
    }
564
}
565
 
566
/* Store registers back into the inferior.  Store all registers if
567
   regno == -1, otherwise store all general registers or all floating
568
   point registers depending upon the value of regno.  */
569
 
570
static void
571
arm_linux_store_inferior_registers (struct target_ops *ops,
572
                                    struct regcache *regcache, int regno)
573
{
574
  if (-1 == regno)
575
    {
576
      store_regs (regcache);
577
      store_fpregs (regcache);
578
      if (arm_linux_has_wmmx_registers)
579
        store_wmmx_regs (regcache);
580
      if (arm_linux_vfp_register_count > 0)
581
        store_vfp_regs (regcache);
582
    }
583
  else
584
    {
585
      if (regno < ARM_F0_REGNUM || regno == ARM_PS_REGNUM)
586
        store_register (regcache, regno);
587
      else if ((regno >= ARM_F0_REGNUM) && (regno <= ARM_FPS_REGNUM))
588
        store_fpregister (regcache, regno);
589
      else if (arm_linux_has_wmmx_registers
590
               && regno >= ARM_WR0_REGNUM && regno <= ARM_WCGR7_REGNUM)
591
        store_wmmx_regs (regcache);
592
      else if (arm_linux_vfp_register_count > 0
593
               && regno >= ARM_D0_REGNUM
594
               && regno <= ARM_D0_REGNUM + arm_linux_vfp_register_count)
595
        store_vfp_regs (regcache);
596
    }
597
}
598
 
599
/* Wrapper functions for the standard regset handling, used by
600
   thread debugging.  */
601
 
602
void
603
fill_gregset (const struct regcache *regcache,
604
              gdb_gregset_t *gregsetp, int regno)
605
{
606
  arm_linux_collect_gregset (NULL, regcache, regno, gregsetp, 0);
607
}
608
 
609
void
610
supply_gregset (struct regcache *regcache, const gdb_gregset_t *gregsetp)
611
{
612
  arm_linux_supply_gregset (NULL, regcache, -1, gregsetp, 0);
613
}
614
 
615
void
616
fill_fpregset (const struct regcache *regcache,
617
               gdb_fpregset_t *fpregsetp, int regno)
618
{
619
  arm_linux_collect_nwfpe (NULL, regcache, regno, fpregsetp, 0);
620
}
621
 
622
/* Fill GDB's register array with the floating-point register values
623
   in *fpregsetp.  */
624
 
625
void
626
supply_fpregset (struct regcache *regcache, const gdb_fpregset_t *fpregsetp)
627
{
628
  arm_linux_supply_nwfpe (NULL, regcache, -1, fpregsetp, 0);
629
}
630
 
631
/* Fetch the thread-local storage pointer for libthread_db.  */
632
 
633
ps_err_e
634
ps_get_thread_area (const struct ps_prochandle *ph,
635
                    lwpid_t lwpid, int idx, void **base)
636
{
637
  if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0)
638
    return PS_ERR;
639
 
640
  /* IDX is the bias from the thread pointer to the beginning of the
641
     thread descriptor.  It has to be subtracted due to implementation
642
     quirks in libthread_db.  */
643
  *base = (void *) ((char *)*base - idx);
644
 
645
  return PS_OK;
646
}
647
 
648
static unsigned int
649
get_linux_version (unsigned int *vmajor,
650
                   unsigned int *vminor,
651
                   unsigned int *vrelease)
652
{
653
  struct utsname info;
654
  char *pmajor, *pminor, *prelease, *tail;
655
 
656
  if (-1 == uname (&info))
657
    {
658
      warning (_("Unable to determine GNU/Linux version."));
659
      return -1;
660
    }
661
 
662
  pmajor = strtok (info.release, ".");
663
  pminor = strtok (NULL, ".");
664
  prelease = strtok (NULL, ".");
665
 
666
  *vmajor = (unsigned int) strtoul (pmajor, &tail, 0);
667
  *vminor = (unsigned int) strtoul (pminor, &tail, 0);
668
  *vrelease = (unsigned int) strtoul (prelease, &tail, 0);
669
 
670
  return ((*vmajor << 16) | (*vminor << 8) | *vrelease);
671
}
672
 
673
static const struct target_desc *
674
arm_linux_read_description (struct target_ops *ops)
675
{
676
  CORE_ADDR arm_hwcap = 0;
677
  arm_linux_has_wmmx_registers = 0;
678
  arm_linux_vfp_register_count = 0;
679
 
680
  if (target_auxv_search (ops, AT_HWCAP, &arm_hwcap) != 1)
681
    {
682
      return NULL;
683
    }
684
 
685
  if (arm_hwcap & HWCAP_IWMMXT)
686
    {
687
      arm_linux_has_wmmx_registers = 1;
688
      if (tdesc_arm_with_iwmmxt == NULL)
689
        initialize_tdesc_arm_with_iwmmxt ();
690
      return tdesc_arm_with_iwmmxt;
691
    }
692
 
693
  if (arm_hwcap & HWCAP_VFP)
694
    {
695
      int pid;
696
      char *buf;
697
      const struct target_desc * result = NULL;
698
 
699
      /* NEON implies VFPv3-D32 or no-VFP unit.  Say that we only support
700
         Neon with VFPv3-D32.  */
701
      if (arm_hwcap & HWCAP_NEON)
702
        {
703
          arm_linux_vfp_register_count = 32;
704
          if (tdesc_arm_with_neon == NULL)
705
            initialize_tdesc_arm_with_neon ();
706
          result = tdesc_arm_with_neon;
707
        }
708
      else if ((arm_hwcap & (HWCAP_VFPv3 | HWCAP_VFPv3D16)) == HWCAP_VFPv3)
709
        {
710
          arm_linux_vfp_register_count = 32;
711
          if (tdesc_arm_with_vfpv3 == NULL)
712
            initialize_tdesc_arm_with_vfpv3 ();
713
          result = tdesc_arm_with_vfpv3;
714
        }
715
      else
716
        {
717
          arm_linux_vfp_register_count = 16;
718
          if (tdesc_arm_with_vfpv2 == NULL)
719
            initialize_tdesc_arm_with_vfpv2 ();
720
          result = tdesc_arm_with_vfpv2;
721
        }
722
 
723
      /* Now make sure that the kernel supports reading these
724
         registers.  Support was added in 2.6.30.  */
725
      pid = GET_LWP (inferior_ptid);
726
      errno = 0;
727
      buf = alloca (VFP_REGS_SIZE);
728
      if (ptrace (PTRACE_GETVFPREGS, pid, 0, buf) < 0
729
          && errno == EIO)
730
        result = NULL;
731
 
732
      return result;
733
    }
734
 
735
  return NULL;
736
}
737
 
738
void _initialize_arm_linux_nat (void);
739
 
740
void
741
_initialize_arm_linux_nat (void)
742
{
743
  struct target_ops *t;
744
 
745
  os_version = get_linux_version (&os_major, &os_minor, &os_release);
746
 
747
  /* Fill in the generic GNU/Linux methods.  */
748
  t = linux_target ();
749
 
750
  /* Add our register access methods.  */
751
  t->to_fetch_registers = arm_linux_fetch_inferior_registers;
752
  t->to_store_registers = arm_linux_store_inferior_registers;
753
 
754
  t->to_read_description = arm_linux_read_description;
755
 
756
  /* Register the target.  */
757
  linux_nat_add_target (t);
758
}

powered by: WebSVN 2.1.0

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