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

Subversion Repositories scarts

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 25 jlechner
/* SPU native-dependent code for GDB, the GNU debugger.
2
   Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc.
3
 
4
   Contributed by Ulrich Weigand <uweigand@de.ibm.com>.
5
 
6
   This file is part of GDB.
7
 
8
   This program is free software; you can redistribute it and/or modify
9
   it under the terms of the GNU General Public License as published by
10
   the Free Software Foundation; either version 3 of the License, or
11
   (at your option) any later version.
12
 
13
   This program is distributed in the hope that it will be useful,
14
   but WITHOUT ANY WARRANTY; without even the implied warranty of
15
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
   GNU General Public License for more details.
17
 
18
   You should have received a copy of the GNU General Public License
19
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
20
 
21
#include "defs.h"
22
#include "gdbcore.h"
23
#include "gdb_string.h"
24
#include "target.h"
25
#include "inferior.h"
26
#include "inf-ptrace.h"
27
#include "regcache.h"
28
#include "symfile.h"
29
#include "gdb_wait.h"
30
#include "gdb_stdint.h"
31
 
32
#include <sys/ptrace.h>
33
#include <asm/ptrace.h>
34
#include <sys/types.h>
35
#include <sys/param.h>
36
 
37
#include "spu-tdep.h"
38
 
39
/* PPU side system calls.  */
40
#define INSTR_SC        0x44000002
41
#define NR_spu_run      0x0116
42
 
43
 
44
/* Fetch PPU register REGNO.  */
45
static ULONGEST
46
fetch_ppc_register (int regno)
47
{
48
  PTRACE_TYPE_RET res;
49
 
50
  int tid = TIDGET (inferior_ptid);
51
  if (tid == 0)
52
    tid = PIDGET (inferior_ptid);
53
 
54
#ifndef __powerpc64__
55
  /* If running as a 32-bit process on a 64-bit system, we attempt
56
     to get the full 64-bit register content of the target process.
57
     If the PPC special ptrace call fails, we're on a 32-bit system;
58
     just fall through to the regular ptrace call in that case.  */
59
  {
60
    gdb_byte buf[8];
61
 
62
    errno = 0;
63
    ptrace (PPC_PTRACE_PEEKUSR_3264, tid,
64
            (PTRACE_TYPE_ARG3) (regno * 8), buf);
65
    if (errno == 0)
66
      ptrace (PPC_PTRACE_PEEKUSR_3264, tid,
67
              (PTRACE_TYPE_ARG3) (regno * 8 + 4), buf + 4);
68
    if (errno == 0)
69
      return (ULONGEST) *(uint64_t *)buf;
70
  }
71
#endif
72
 
73
  errno = 0;
74
  res = ptrace (PT_READ_U, tid,
75
                (PTRACE_TYPE_ARG3) (regno * sizeof (PTRACE_TYPE_RET)), 0);
76
  if (errno != 0)
77
    {
78
      char mess[128];
79
      xsnprintf (mess, sizeof mess, "reading PPC register #%d", regno);
80
      perror_with_name (_(mess));
81
    }
82
 
83
  return (ULONGEST) (unsigned long) res;
84
}
85
 
86
/* Fetch WORD from PPU memory at (aligned) MEMADDR in thread TID.  */
87
static int
88
fetch_ppc_memory_1 (int tid, ULONGEST memaddr, PTRACE_TYPE_RET *word)
89
{
90
  errno = 0;
91
 
92
#ifndef __powerpc64__
93
  if (memaddr >> 32)
94
    {
95
      uint64_t addr_8 = (uint64_t) memaddr;
96
      ptrace (PPC_PTRACE_PEEKTEXT_3264, tid, (PTRACE_TYPE_ARG3) &addr_8, word);
97
    }
98
  else
99
#endif
100
    *word = ptrace (PT_READ_I, tid, (PTRACE_TYPE_ARG3) (size_t) memaddr, 0);
101
 
102
  return errno;
103
}
104
 
105
/* Store WORD into PPU memory at (aligned) MEMADDR in thread TID.  */
106
static int
107
store_ppc_memory_1 (int tid, ULONGEST memaddr, PTRACE_TYPE_RET word)
108
{
109
  errno = 0;
110
 
111
#ifndef __powerpc64__
112
  if (memaddr >> 32)
113
    {
114
      uint64_t addr_8 = (uint64_t) memaddr;
115
      ptrace (PPC_PTRACE_POKEDATA_3264, tid, (PTRACE_TYPE_ARG3) &addr_8, word);
116
    }
117
  else
118
#endif
119
    ptrace (PT_WRITE_D, tid, (PTRACE_TYPE_ARG3) (size_t) memaddr, word);
120
 
121
  return errno;
122
}
123
 
124
/* Fetch LEN bytes of PPU memory at MEMADDR to MYADDR.  */
125
static int
126
fetch_ppc_memory (ULONGEST memaddr, gdb_byte *myaddr, int len)
127
{
128
  int i, ret;
129
 
130
  ULONGEST addr = memaddr & -(ULONGEST) sizeof (PTRACE_TYPE_RET);
131
  int count = ((((memaddr + len) - addr) + sizeof (PTRACE_TYPE_RET) - 1)
132
               / sizeof (PTRACE_TYPE_RET));
133
  PTRACE_TYPE_RET *buffer;
134
 
135
  int tid = TIDGET (inferior_ptid);
136
  if (tid == 0)
137
    tid = PIDGET (inferior_ptid);
138
 
139
  buffer = (PTRACE_TYPE_RET *) alloca (count * sizeof (PTRACE_TYPE_RET));
140
  for (i = 0; i < count; i++, addr += sizeof (PTRACE_TYPE_RET))
141
    {
142
      ret = fetch_ppc_memory_1 (tid, addr, &buffer[i]);
143
      if (ret)
144
        return ret;
145
    }
146
 
147
  memcpy (myaddr,
148
          (char *) buffer + (memaddr & (sizeof (PTRACE_TYPE_RET) - 1)),
149
          len);
150
 
151
  return 0;
152
}
153
 
154
/* Store LEN bytes from MYADDR to PPU memory at MEMADDR.  */
155
static int
156
store_ppc_memory (ULONGEST memaddr, const gdb_byte *myaddr, int len)
157
{
158
  int i, ret;
159
 
160
  ULONGEST addr = memaddr & -(ULONGEST) sizeof (PTRACE_TYPE_RET);
161
  int count = ((((memaddr + len) - addr) + sizeof (PTRACE_TYPE_RET) - 1)
162
               / sizeof (PTRACE_TYPE_RET));
163
  PTRACE_TYPE_RET *buffer;
164
 
165
  int tid = TIDGET (inferior_ptid);
166
  if (tid == 0)
167
    tid = PIDGET (inferior_ptid);
168
 
169
  buffer = (PTRACE_TYPE_RET *) alloca (count * sizeof (PTRACE_TYPE_RET));
170
 
171
  if (addr != memaddr || len < (int) sizeof (PTRACE_TYPE_RET))
172
    {
173
      ret = fetch_ppc_memory_1 (tid, addr, &buffer[0]);
174
      if (ret)
175
        return ret;
176
    }
177
 
178
  if (count > 1)
179
    {
180
      ret = fetch_ppc_memory_1 (tid, addr + (count - 1)
181
                                               * sizeof (PTRACE_TYPE_RET),
182
                                &buffer[count - 1]);
183
      if (ret)
184
        return ret;
185
    }
186
 
187
  memcpy ((char *) buffer + (memaddr & (sizeof (PTRACE_TYPE_RET) - 1)),
188
          myaddr, len);
189
 
190
  for (i = 0; i < count; i++, addr += sizeof (PTRACE_TYPE_RET))
191
    {
192
      ret = store_ppc_memory_1 (tid, addr, buffer[i]);
193
      if (ret)
194
        return ret;
195
    }
196
 
197
  return 0;
198
}
199
 
200
 
201
/* If the PPU thread is currently stopped on a spu_run system call,
202
   return to FD and ADDR the file handle and NPC parameter address
203
   used with the system call.  Return non-zero if successful.  */
204
static int
205
parse_spufs_run (int *fd, ULONGEST *addr)
206
{
207
  gdb_byte buf[4];
208
  ULONGEST pc = fetch_ppc_register (32);  /* nip */
209
 
210
  /* Fetch instruction preceding current NIP.  */
211
  if (fetch_ppc_memory (pc-4, buf, 4) != 0)
212
    return 0;
213
  /* It should be a "sc" instruction.  */
214
  if (extract_unsigned_integer (buf, 4) != INSTR_SC)
215
    return 0;
216
  /* System call number should be NR_spu_run.  */
217
  if (fetch_ppc_register (0) != NR_spu_run)
218
    return 0;
219
 
220
  /* Register 3 contains fd, register 4 the NPC param pointer.  */
221
  *fd = fetch_ppc_register (34);  /* orig_gpr3 */
222
  *addr = fetch_ppc_register (4);
223
  return 1;
224
}
225
 
226
 
227
/* Copy LEN bytes at OFFSET in spufs file ANNEX into/from READBUF or WRITEBUF,
228
   using the /proc file system.  */
229
static LONGEST
230
spu_proc_xfer_spu (const char *annex, gdb_byte *readbuf,
231
                   const gdb_byte *writebuf,
232
                   ULONGEST offset, LONGEST len)
233
{
234
  char buf[128];
235
  int fd = 0;
236
  int ret = -1;
237
  int pid = PIDGET (inferior_ptid);
238
 
239
  if (!annex)
240
    return 0;
241
 
242
  xsnprintf (buf, sizeof buf, "/proc/%d/fd/%s", pid, annex);
243
  fd = open (buf, writebuf? O_WRONLY : O_RDONLY);
244
  if (fd <= 0)
245
    return -1;
246
 
247
  if (offset != 0
248
      && lseek (fd, (off_t) offset, SEEK_SET) != (off_t) offset)
249
    {
250
      close (fd);
251
      return 0;
252
    }
253
 
254
  if (writebuf)
255
    ret = write (fd, writebuf, (size_t) len);
256
  else if (readbuf)
257
    ret = read (fd, readbuf, (size_t) len);
258
 
259
  close (fd);
260
  return ret;
261
}
262
 
263
 
264
/* Inferior memory should contain an SPE executable image at location ADDR.
265
   Allocate a BFD representing that executable.  Return NULL on error.  */
266
 
267
static void *
268
spu_bfd_iovec_open (struct bfd *nbfd, void *open_closure)
269
{
270
  return open_closure;
271
}
272
 
273
static int
274
spu_bfd_iovec_close (struct bfd *nbfd, void *stream)
275
{
276
  xfree (stream);
277
  return 1;
278
}
279
 
280
static file_ptr
281
spu_bfd_iovec_pread (struct bfd *abfd, void *stream, void *buf,
282
                     file_ptr nbytes, file_ptr offset)
283
{
284
  ULONGEST addr = *(ULONGEST *)stream;
285
 
286
  if (fetch_ppc_memory (addr + offset, buf, nbytes) != 0)
287
    {
288
      bfd_set_error (bfd_error_invalid_operation);
289
      return -1;
290
    }
291
 
292
  return nbytes;
293
}
294
 
295
static int
296
spu_bfd_iovec_stat (struct bfd *abfd, void *stream, struct stat *sb)
297
{
298
  /* We don't have an easy way of finding the size of embedded spu
299
     images.  We could parse the in-memory ELF header and section
300
     table to find the extent of the last section but that seems
301
     pointless when the size is needed only for checks of other
302
     parsed values in dbxread.c.  */
303
  sb->st_size = INT_MAX;
304
  return 0;
305
}
306
 
307
static bfd *
308
spu_bfd_open (ULONGEST addr)
309
{
310
  struct bfd *nbfd;
311
 
312
  ULONGEST *open_closure = xmalloc (sizeof (ULONGEST));
313
  *open_closure = addr;
314
 
315
  nbfd = bfd_openr_iovec (xstrdup ("<in-memory>"), "elf32-spu",
316
                          spu_bfd_iovec_open, open_closure,
317
                          spu_bfd_iovec_pread, spu_bfd_iovec_close,
318
                          spu_bfd_iovec_stat);
319
  if (!nbfd)
320
    return NULL;
321
 
322
  if (!bfd_check_format (nbfd, bfd_object))
323
    {
324
      bfd_close (nbfd);
325
      return NULL;
326
    }
327
 
328
  return nbfd;
329
}
330
 
331
/* INFERIOR_FD is a file handle passed by the inferior to the
332
   spu_run system call.  Assuming the SPE context was allocated
333
   by the libspe library, try to retrieve the main SPE executable
334
   file from its copy within the target process.  */
335
static void
336
spu_symbol_file_add_from_memory (int inferior_fd)
337
{
338
  ULONGEST addr;
339
  struct bfd *nbfd;
340
 
341
  char id[128];
342
  char annex[32];
343
  int len;
344
 
345
  /* Read object ID.  */
346
  xsnprintf (annex, sizeof annex, "%d/object-id", inferior_fd);
347
  len = spu_proc_xfer_spu (annex, id, NULL, 0, sizeof id);
348
  if (len <= 0 || len >= sizeof id)
349
    return;
350
  id[len] = 0;
351
  addr = strtoulst (id, NULL, 16);
352
  if (!addr)
353
    return;
354
 
355
  /* Open BFD representing SPE executable and read its symbols.  */
356
  nbfd = spu_bfd_open (addr);
357
  if (nbfd)
358
    symbol_file_add_from_bfd (nbfd, 0, NULL, 1, 0);
359
}
360
 
361
 
362
/* Override the post_startup_inferior routine to continue running
363
   the inferior until the first spu_run system call.  */
364
static void
365
spu_child_post_startup_inferior (ptid_t ptid)
366
{
367
  int fd;
368
  ULONGEST addr;
369
 
370
  int tid = TIDGET (ptid);
371
  if (tid == 0)
372
    tid = PIDGET (ptid);
373
 
374
  while (!parse_spufs_run (&fd, &addr))
375
    {
376
      ptrace (PT_SYSCALL, tid, (PTRACE_TYPE_ARG3) 0, 0);
377
      waitpid (tid, NULL, __WALL | __WNOTHREAD);
378
    }
379
}
380
 
381
/* Override the post_attach routine to try load the SPE executable
382
   file image from its copy inside the target process.  */
383
static void
384
spu_child_post_attach (int pid)
385
{
386
  int fd;
387
  ULONGEST addr;
388
 
389
  /* Like child_post_startup_inferior, if we happened to attach to
390
     the inferior while it wasn't currently in spu_run, continue
391
     running it until we get back there.  */
392
  while (!parse_spufs_run (&fd, &addr))
393
    {
394
      ptrace (PT_SYSCALL, pid, (PTRACE_TYPE_ARG3) 0, 0);
395
      waitpid (pid, NULL, __WALL | __WNOTHREAD);
396
    }
397
 
398
  /* If the user has not provided an executable file, try to extract
399
     the image from inside the target process.  */
400
  if (!get_exec_file (0))
401
    spu_symbol_file_add_from_memory (fd);
402
}
403
 
404
/* Wait for child PTID to do something.  Return id of the child,
405
   minus_one_ptid in case of error; store status into *OURSTATUS.  */
406
static ptid_t
407
spu_child_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
408
{
409
  int save_errno;
410
  int status;
411
  pid_t pid;
412
 
413
  do
414
    {
415
      set_sigint_trap ();       /* Causes SIGINT to be passed on to the
416
                                   attached process.  */
417
      set_sigio_trap ();
418
 
419
      pid = waitpid (PIDGET (ptid), &status, 0);
420
      if (pid == -1 && errno == ECHILD)
421
        /* Try again with __WCLONE to check cloned processes.  */
422
        pid = waitpid (PIDGET (ptid), &status, __WCLONE);
423
 
424
      save_errno = errno;
425
 
426
      /* Make sure we don't report an event for the exit of the
427
         original program, if we've detached from it.  */
428
      if (pid != -1 && !WIFSTOPPED (status) && pid != PIDGET (inferior_ptid))
429
        {
430
          pid = -1;
431
          save_errno = EINTR;
432
        }
433
 
434
      clear_sigio_trap ();
435
      clear_sigint_trap ();
436
    }
437
  while (pid == -1 && save_errno == EINTR);
438
 
439
  if (pid == -1)
440
    {
441
      warning (_("Child process unexpectedly missing: %s"),
442
               safe_strerror (save_errno));
443
 
444
      /* Claim it exited with unknown signal.  */
445
      ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
446
      ourstatus->value.sig = TARGET_SIGNAL_UNKNOWN;
447
      return minus_one_ptid;
448
    }
449
 
450
  store_waitstatus (ourstatus, status);
451
  return pid_to_ptid (pid);
452
}
453
 
454
/* Override the fetch_inferior_register routine.  */
455
static void
456
spu_fetch_inferior_registers (struct regcache *regcache, int regno)
457
{
458
  int fd;
459
  ULONGEST addr;
460
 
461
  /* We must be stopped on a spu_run system call.  */
462
  if (!parse_spufs_run (&fd, &addr))
463
    return;
464
 
465
  /* The ID register holds the spufs file handle.  */
466
  if (regno == -1 || regno == SPU_ID_REGNUM)
467
    {
468
      char buf[4];
469
      store_unsigned_integer (buf, 4, fd);
470
      regcache_raw_supply (regcache, SPU_ID_REGNUM, buf);
471
    }
472
 
473
  /* The NPC register is found at ADDR.  */
474
  if (regno == -1 || regno == SPU_PC_REGNUM)
475
    {
476
      gdb_byte buf[4];
477
      if (fetch_ppc_memory (addr, buf, 4) == 0)
478
        regcache_raw_supply (regcache, SPU_PC_REGNUM, buf);
479
    }
480
 
481
  /* The GPRs are found in the "regs" spufs file.  */
482
  if (regno == -1 || (regno >= 0 && regno < SPU_NUM_GPRS))
483
    {
484
      gdb_byte buf[16 * SPU_NUM_GPRS];
485
      char annex[32];
486
      int i;
487
 
488
      xsnprintf (annex, sizeof annex, "%d/regs", fd);
489
      if (spu_proc_xfer_spu (annex, buf, NULL, 0, sizeof buf) == sizeof buf)
490
        for (i = 0; i < SPU_NUM_GPRS; i++)
491
          regcache_raw_supply (regcache, i, buf + i*16);
492
    }
493
}
494
 
495
/* Override the store_inferior_register routine.  */
496
static void
497
spu_store_inferior_registers (struct regcache *regcache, int regno)
498
{
499
  int fd;
500
  ULONGEST addr;
501
 
502
  /* We must be stopped on a spu_run system call.  */
503
  if (!parse_spufs_run (&fd, &addr))
504
    return;
505
 
506
  /* The NPC register is found at ADDR.  */
507
  if (regno == -1 || regno == SPU_PC_REGNUM)
508
    {
509
      gdb_byte buf[4];
510
      regcache_raw_collect (regcache, SPU_PC_REGNUM, buf);
511
      store_ppc_memory (addr, buf, 4);
512
    }
513
 
514
  /* The GPRs are found in the "regs" spufs file.  */
515
  if (regno == -1 || (regno >= 0 && regno < SPU_NUM_GPRS))
516
    {
517
      gdb_byte buf[16 * SPU_NUM_GPRS];
518
      char annex[32];
519
      int i;
520
 
521
      for (i = 0; i < SPU_NUM_GPRS; i++)
522
        regcache_raw_collect (regcache, i, buf + i*16);
523
 
524
      xsnprintf (annex, sizeof annex, "%d/regs", fd);
525
      spu_proc_xfer_spu (annex, NULL, buf, 0, sizeof buf);
526
    }
527
}
528
 
529
/* Override the to_xfer_partial routine.  */
530
static LONGEST
531
spu_xfer_partial (struct target_ops *ops,
532
                  enum target_object object, const char *annex,
533
                  gdb_byte *readbuf, const gdb_byte *writebuf,
534
                  ULONGEST offset, LONGEST len)
535
{
536
  if (object == TARGET_OBJECT_SPU)
537
    return spu_proc_xfer_spu (annex, readbuf, writebuf, offset, len);
538
 
539
  if (object == TARGET_OBJECT_MEMORY)
540
    {
541
      int fd;
542
      ULONGEST addr;
543
      char mem_annex[32];
544
 
545
      /* We must be stopped on a spu_run system call.  */
546
      if (!parse_spufs_run (&fd, &addr))
547
        return 0;
548
 
549
      /* Use the "mem" spufs file to access SPU local store.  */
550
      xsnprintf (mem_annex, sizeof mem_annex, "%d/mem", fd);
551
      return spu_proc_xfer_spu (mem_annex, readbuf, writebuf, offset, len);
552
    }
553
 
554
  return -1;
555
}
556
 
557
/* Override the to_can_use_hw_breakpoint routine.  */
558
static int
559
spu_can_use_hw_breakpoint (int type, int cnt, int othertype)
560
{
561
  return 0;
562
}
563
 
564
 
565
/* Initialize SPU native target.  */
566
void
567
_initialize_spu_nat (void)
568
{
569
  /* Generic ptrace methods.  */
570
  struct target_ops *t;
571
  t = inf_ptrace_target ();
572
 
573
  /* Add SPU methods.  */
574
  t->to_post_attach = spu_child_post_attach;
575
  t->to_post_startup_inferior = spu_child_post_startup_inferior;
576
  t->to_wait = spu_child_wait;
577
  t->to_fetch_registers = spu_fetch_inferior_registers;
578
  t->to_store_registers = spu_store_inferior_registers;
579
  t->to_xfer_partial = spu_xfer_partial;
580
  t->to_can_use_hw_breakpoint = spu_can_use_hw_breakpoint;
581
 
582
  /* Register SPU target.  */
583
  add_target (t);
584
}
585
 

powered by: WebSVN 2.1.0

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