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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-stable/] [gdb-7.2/] [gdb/] [solib-spu.c] - Blame information for rev 850

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

Line No. Rev Author Line
1 330 jeremybenn
/* Cell SPU GNU/Linux support -- shared library handling.
2
   Copyright (C) 2009, 2010 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 "gdb_assert.h"
25
#include "gdb_stat.h"
26
#include "arch-utils.h"
27
#include "bfd.h"
28
#include "symtab.h"
29
#include "solib.h"
30
#include "solib-svr4.h"
31
#include "solist.h"
32
#include "inferior.h"
33
#include "objfiles.h"
34
#include "observer.h"
35
#include "breakpoint.h"
36
#include "gdbthread.h"
37
#include "exceptions.h"
38
 
39
#include "spu-tdep.h"
40
 
41
/* Highest SPE id (file handle) the inferior may have.  */
42
#define MAX_SPE_FD 1024
43
 
44
/* Stand-alone SPE executable?  */
45
#define spu_standalone_p() \
46
  (symfile_objfile && symfile_objfile->obfd \
47
   && bfd_get_arch (symfile_objfile->obfd) == bfd_arch_spu)
48
 
49
 
50
/* Relocate main SPE executable.  */
51
static void
52
spu_relocate_main_executable (int spufs_fd)
53
{
54
  struct section_offsets *new_offsets;
55
  int i;
56
 
57
  if (symfile_objfile == NULL)
58
    return;
59
 
60
  new_offsets = alloca (symfile_objfile->num_sections
61
                        * sizeof (struct section_offsets));
62
 
63
  for (i = 0; i < symfile_objfile->num_sections; i++)
64
    new_offsets->offsets[i] = SPUADDR (spufs_fd, 0);
65
 
66
  objfile_relocate (symfile_objfile, new_offsets);
67
}
68
 
69
/* When running a stand-alone SPE executable, we may need to skip one more
70
   exec event on startup, to get past the binfmt_misc loader.  */
71
static void
72
spu_skip_standalone_loader (void)
73
{
74
  if (target_has_execution && !current_inferior ()->attach_flag)
75
    {
76
      struct target_waitstatus ws;
77
 
78
      /* Only some kernels report an extra SIGTRAP with the binfmt_misc
79
         loader; others do not.  In addition, if we have attached to an
80
         already running inferior instead of starting a new one, we will
81
         not see the extra SIGTRAP -- and we cannot readily distinguish
82
         the two cases, in particular with the extended-remote target.
83
 
84
         Thus we issue a single-step here.  If no extra SIGTRAP was pending,
85
         this will step past the first instruction of the stand-alone SPE
86
         executable loader, but we don't care about that.  */
87
 
88
      inferior_thread ()->in_infcall = 1;   /* Suppress MI messages.  */
89
 
90
      target_resume (inferior_ptid, 1, TARGET_SIGNAL_0);
91
      target_wait (minus_one_ptid, &ws, 0);
92
      set_executing (minus_one_ptid, 0);
93
 
94
      inferior_thread ()->in_infcall = 0;
95
    }
96
}
97
 
98
static const struct objfile_data *ocl_program_data_key;
99
 
100
/* Appends OpenCL programs to the list of `struct so_list' objects.  */
101
static void
102
append_ocl_sos (struct so_list **link_ptr)
103
{
104
  CORE_ADDR *ocl_program_addr_base;
105
  struct objfile *objfile;
106
 
107
  ALL_OBJFILES (objfile)
108
    {
109
      ocl_program_addr_base = objfile_data (objfile, ocl_program_data_key);
110
      if (ocl_program_addr_base != NULL)
111
        {
112
          enum bfd_endian byte_order = bfd_big_endian (objfile->obfd)?
113
                                         BFD_ENDIAN_BIG : BFD_ENDIAN_LITTLE;
114
          volatile struct gdb_exception ex;
115
          TRY_CATCH (ex, RETURN_MASK_ALL)
116
            {
117
              CORE_ADDR data =
118
                read_memory_unsigned_integer (*ocl_program_addr_base,
119
                                              sizeof (CORE_ADDR),
120
                                              byte_order);
121
              if (data != 0x0)
122
                {
123
                  struct so_list *new;
124
 
125
                  /* Allocate so_list structure.  */
126
                  new = XZALLOC (struct so_list);
127
 
128
                  /* Encode FD and object ID in path name.  */
129
                  xsnprintf (new->so_name, sizeof new->so_name, "@%s <%d>",
130
                             hex_string (data),
131
                             SPUADDR_SPU (*ocl_program_addr_base));
132
                  strcpy (new->so_original_name, new->so_name);
133
 
134
                  *link_ptr = new;
135
                  link_ptr = &new->next;
136
                }
137
            }
138
          if (ex.reason < 0)
139
            {
140
              /* Ignore memory errors.  */
141
              switch (ex.error)
142
                {
143
                case MEMORY_ERROR:
144
                  break;
145
                default:
146
                  throw_exception (ex);
147
                  break;
148
                }
149
            }
150
        }
151
    }
152
}
153
 
154
/* Build a list of `struct so_list' objects describing the shared
155
   objects currently loaded in the inferior.  */
156
static struct so_list *
157
spu_current_sos (void)
158
{
159
  enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch);
160
  struct so_list *head;
161
  struct so_list **link_ptr;
162
 
163
  char buf[MAX_SPE_FD * 4];
164
  int i, size;
165
 
166
  /* First, retrieve the SVR4 shared library list.  */
167
  head = svr4_so_ops.current_sos ();
168
 
169
  /* Append our libraries to the end of the list.  */
170
  for (link_ptr = &head; *link_ptr; link_ptr = &(*link_ptr)->next)
171
    ;
172
 
173
  /* Determine list of SPU ids.  */
174
  size = target_read (&current_target, TARGET_OBJECT_SPU, NULL,
175
                      buf, 0, sizeof buf);
176
 
177
  /* Do not add stand-alone SPE executable context as shared library,
178
     but relocate main SPE executable objfile.  */
179
  if (spu_standalone_p ())
180
    {
181
      if (size == 4)
182
        {
183
          int fd = extract_unsigned_integer (buf, 4, byte_order);
184
 
185
          spu_relocate_main_executable (fd);
186
 
187
          /* Re-enable breakpoints after main SPU context was established;
188
             see also comments in spu_solib_create_inferior_hook.  */
189
          enable_breakpoints_after_startup ();
190
        }
191
 
192
      return head;
193
    }
194
 
195
  /* Create an so_list entry for each SPU id.  */
196
  for (i = 0; i < size; i += 4)
197
    {
198
      int fd = extract_unsigned_integer (buf + i, 4, byte_order);
199
      struct so_list *new;
200
 
201
      unsigned long long addr;
202
      char annex[32], id[100];
203
      int len;
204
 
205
      /* Read object ID.  There's a race window where the inferior may have
206
         already created the SPE context, but not installed the object-id
207
         yet.  Skip such entries; we'll be back for them later.  */
208
      xsnprintf (annex, sizeof annex, "%d/object-id", fd);
209
      len = target_read (&current_target, TARGET_OBJECT_SPU, annex,
210
                         id, 0, sizeof id);
211
      if (len <= 0 || len >= sizeof id)
212
        continue;
213
      id[len] = 0;
214
      if (sscanf (id, "0x%llx", &addr) != 1 || !addr)
215
        continue;
216
 
217
      /* Allocate so_list structure.  */
218
      new = XZALLOC (struct so_list);
219
 
220
      /* Encode FD and object ID in path name.  Choose the name so as not
221
         to conflict with any (normal) SVR4 library path name.  */
222
      xsnprintf (new->so_name, sizeof new->so_name, "@%s <%d>",
223
                 hex_string (addr), fd);
224
      strcpy (new->so_original_name, new->so_name);
225
 
226
      *link_ptr = new;
227
      link_ptr = &new->next;
228
    }
229
 
230
  /* Append OpenCL sos. */
231
  append_ocl_sos (link_ptr);
232
 
233
  return head;
234
}
235
 
236
/* Free so_list information.  */
237
static void
238
spu_free_so (struct so_list *so)
239
{
240
  if (so->so_original_name[0] != '@')
241
    svr4_so_ops.free_so (so);
242
}
243
 
244
/* Relocate section addresses.  */
245
static void
246
spu_relocate_section_addresses (struct so_list *so,
247
                                struct target_section *sec)
248
{
249
  if (so->so_original_name[0] != '@')
250
    svr4_so_ops.relocate_section_addresses (so, sec);
251
  else
252
    {
253
      unsigned long long addr;
254
      int fd;
255
 
256
      /* Set addr_low/high to just LS offset for display.  */
257
      if (so->addr_low == 0 && so->addr_high == 0
258
          && strcmp (sec->the_bfd_section->name, ".text") == 0)
259
        {
260
          so->addr_low = sec->addr;
261
          so->addr_high = sec->endaddr;
262
        }
263
 
264
      /* Decode object ID.  */
265
      if (sscanf (so->so_original_name, "@0x%llx <%d>", &addr, &fd) != 2)
266
        internal_error (__FILE__, __LINE__, "bad object ID");
267
 
268
      sec->addr = SPUADDR (fd, sec->addr);
269
      sec->endaddr = SPUADDR (fd, sec->endaddr);
270
    }
271
}
272
 
273
 
274
/* Inferior memory should contain an SPE executable image at location ADDR.
275
   Allocate a BFD representing that executable.  Return NULL on error.  */
276
 
277
static void *
278
spu_bfd_iovec_open (bfd *nbfd, void *open_closure)
279
{
280
  return open_closure;
281
}
282
 
283
static int
284
spu_bfd_iovec_close (bfd *nbfd, void *stream)
285
{
286
  xfree (stream);
287
  return 1;
288
}
289
 
290
static file_ptr
291
spu_bfd_iovec_pread (bfd *abfd, void *stream, void *buf,
292
                     file_ptr nbytes, file_ptr offset)
293
{
294
  CORE_ADDR addr = *(CORE_ADDR *)stream;
295
  int ret;
296
 
297
  ret = target_read_memory (addr + offset, buf, nbytes);
298
  if (ret != 0)
299
    {
300
      bfd_set_error (bfd_error_invalid_operation);
301
      return -1;
302
    }
303
 
304
  return nbytes;
305
}
306
 
307
static int
308
spu_bfd_iovec_stat (bfd *abfd, void *stream, struct stat *sb)
309
{
310
  /* We don't have an easy way of finding the size of embedded spu
311
     images.  We could parse the in-memory ELF header and section
312
     table to find the extent of the last section but that seems
313
     pointless when the size is needed only for checks of other
314
     parsed values in dbxread.c.  */
315
  sb->st_size = INT_MAX;
316
  return 0;
317
}
318
 
319
static bfd *
320
spu_bfd_fopen (char *name, CORE_ADDR addr)
321
{
322
  bfd *nbfd;
323
 
324
  CORE_ADDR *open_closure = xmalloc (sizeof (CORE_ADDR));
325
  *open_closure = addr;
326
 
327
  nbfd = bfd_openr_iovec (xstrdup (name), "elf32-spu",
328
                          spu_bfd_iovec_open, open_closure,
329
                          spu_bfd_iovec_pread, spu_bfd_iovec_close,
330
                          spu_bfd_iovec_stat);
331
  if (!nbfd)
332
    return NULL;
333
 
334
  if (!bfd_check_format (nbfd, bfd_object))
335
    {
336
      bfd_close (nbfd);
337
      return NULL;
338
    }
339
 
340
  return nbfd;
341
}
342
 
343
/* Open shared library BFD.  */
344
static bfd *
345
spu_bfd_open (char *pathname)
346
{
347
  char *original_name = strrchr (pathname, '@');
348
  bfd *abfd;
349
  asection *spu_name;
350
  unsigned long long addr;
351
  int fd;
352
 
353
  /* Handle regular SVR4 libraries.  */
354
  if (!original_name)
355
    return svr4_so_ops.bfd_open (pathname);
356
 
357
  /* Decode object ID.  */
358
  if (sscanf (original_name, "@0x%llx <%d>", &addr, &fd) != 2)
359
    internal_error (__FILE__, __LINE__, "bad object ID");
360
 
361
  /* Open BFD representing SPE executable.  */
362
  abfd = spu_bfd_fopen (original_name, (CORE_ADDR) addr);
363
  if (!abfd)
364
    error (_("Cannot read SPE executable at %s"), original_name);
365
 
366
  /* Retrieve SPU name note.  */
367
  spu_name = bfd_get_section_by_name (abfd, ".note.spu_name");
368
  if (spu_name)
369
    {
370
      int sect_size = bfd_section_size (abfd, spu_name);
371
 
372
      if (sect_size > 20)
373
        {
374
          char *buf = alloca (sect_size - 20 + strlen (original_name) + 1);
375
 
376
          bfd_get_section_contents (abfd, spu_name, buf, 20, sect_size - 20);
377
          buf[sect_size - 20] = '\0';
378
 
379
          strcat (buf, original_name);
380
 
381
          xfree ((char *)abfd->filename);
382
          abfd->filename = xstrdup (buf);
383
        }
384
    }
385
 
386
  return abfd;
387
}
388
 
389
/* Lookup global symbol in a SPE executable.  */
390
static struct symbol *
391
spu_lookup_lib_symbol (const struct objfile *objfile,
392
                       const char *name,
393
                       const domain_enum domain)
394
{
395
  if (bfd_get_arch (objfile->obfd) == bfd_arch_spu)
396
    return lookup_global_symbol_from_objfile (objfile, name, domain);
397
 
398
  if (svr4_so_ops.lookup_lib_global_symbol != NULL)
399
    return svr4_so_ops.lookup_lib_global_symbol (objfile, name, domain);
400
  return NULL;
401
}
402
 
403
/* Enable shared library breakpoint.  */
404
static int
405
spu_enable_break (struct objfile *objfile)
406
{
407
  struct minimal_symbol *spe_event_sym = NULL;
408
 
409
  /* The libspe library will call __spe_context_update_event whenever any
410
     SPE context is allocated or destroyed.  */
411
  spe_event_sym = lookup_minimal_symbol ("__spe_context_update_event",
412
                                         NULL, objfile);
413
 
414
  /* Place a solib_event breakpoint on the symbol.  */
415
  if (spe_event_sym)
416
    {
417
      CORE_ADDR addr = SYMBOL_VALUE_ADDRESS (spe_event_sym);
418
 
419
      addr = gdbarch_convert_from_func_ptr_addr (target_gdbarch, addr,
420
                                                 &current_target);
421
      create_solib_event_breakpoint (target_gdbarch, addr);
422
      return 1;
423
    }
424
 
425
  return 0;
426
}
427
 
428
/* Enable shared library breakpoint for the
429
   OpenCL runtime running on the SPU.  */
430
static void
431
ocl_enable_break (struct objfile *objfile)
432
{
433
  struct minimal_symbol *event_sym = NULL;
434
  struct minimal_symbol *addr_sym = NULL;
435
 
436
  /* The OpenCL runtime on the SPU will call __opencl_program_update_event
437
     whenever an OpenCL program is loaded.  */
438
  event_sym = lookup_minimal_symbol ("__opencl_program_update_event", NULL,
439
                                     objfile);
440
  /* The PPU address of the OpenCL program can be found
441
     at opencl_elf_image_address.  */
442
  addr_sym = lookup_minimal_symbol ("opencl_elf_image_address", NULL, objfile);
443
 
444
  if (event_sym && addr_sym)
445
    {
446
      /* Place a solib_event breakpoint on the symbol.  */
447
      CORE_ADDR event_addr = SYMBOL_VALUE_ADDRESS (event_sym);
448
      create_solib_event_breakpoint (get_objfile_arch (objfile), event_addr);
449
 
450
      /* Store the address of the symbol that will point to OpenCL program
451
         using the per-objfile private data mechanism.  */
452
      if (objfile_data (objfile, ocl_program_data_key) == NULL)
453
        {
454
          CORE_ADDR *ocl_program_addr_base = OBSTACK_CALLOC (
455
                  &objfile->objfile_obstack,
456
                  objfile->sections_end - objfile->sections,
457
                  CORE_ADDR);
458
          *ocl_program_addr_base = SYMBOL_VALUE_ADDRESS (addr_sym);
459
          set_objfile_data (objfile, ocl_program_data_key,
460
                            ocl_program_addr_base);
461
        }
462
    }
463
}
464
 
465
/* Create inferior hook.  */
466
static void
467
spu_solib_create_inferior_hook (int from_tty)
468
{
469
  /* Handle SPE stand-alone executables.  */
470
  if (spu_standalone_p ())
471
    {
472
      /* After an SPE stand-alone executable was loaded, we'll receive
473
         an additional trap due to the binfmt_misc handler.  Make sure
474
         to skip that trap.  */
475
      spu_skip_standalone_loader ();
476
 
477
      /* If the user established breakpoints before starting the inferior, GDB
478
         would attempt to insert those now.  This would fail because the SPU
479
         context has not yet been created and the SPU executable has not yet
480
         been loaded.  To prevent such failures, we disable all user-created
481
         breakpoints now; they will be re-enabled in spu_current_sos once the
482
         main SPU context has been detected.  */
483
      disable_breakpoints_before_startup ();
484
 
485
      /* A special case arises when re-starting an executable, because at
486
         this point it still resides at the relocated address range that was
487
         determined during its last execution.  We need to undo the relocation
488
         so that that multi-architecture target recognizes the stand-alone
489
         initialization special case.  */
490
      spu_relocate_main_executable (-1);
491
    }
492
 
493
  /* Call SVR4 hook -- this will re-insert the SVR4 solib breakpoints.  */
494
  svr4_so_ops.solib_create_inferior_hook (from_tty);
495
 
496
  /* If the inferior is statically linked against libspe, we need to install
497
     our own solib breakpoint right now.  Otherwise, it will be installed by
498
     the solib_loaded observer below as soon as libspe is loaded.  */
499
  spu_enable_break (NULL);
500
}
501
 
502
/* Install SPE "shared library" handling.  This is called by -tdep code
503
   that wants to support SPU as a secondary architecture.  */
504
void
505
set_spu_solib_ops (struct gdbarch *gdbarch)
506
{
507
  static struct target_so_ops spu_so_ops;
508
 
509
  /* Initialize this lazily, to avoid an initialization order
510
     dependency on solib-svr4.c's _initialize routine.  */
511
  if (spu_so_ops.current_sos == NULL)
512
    {
513
      spu_so_ops = svr4_so_ops;
514
      spu_so_ops.solib_create_inferior_hook = spu_solib_create_inferior_hook;
515
      spu_so_ops.relocate_section_addresses = spu_relocate_section_addresses;
516
      spu_so_ops.free_so = spu_free_so;
517
      spu_so_ops.current_sos = spu_current_sos;
518
      spu_so_ops.bfd_open = spu_bfd_open;
519
      spu_so_ops.lookup_lib_global_symbol = spu_lookup_lib_symbol;
520
    }
521
 
522
  set_solib_ops (gdbarch, &spu_so_ops);
523
}
524
 
525
/* Observer for the solib_loaded event.  Used to install our breakpoint
526
   if libspe is a shared library.  */
527
static void
528
spu_solib_loaded (struct so_list *so)
529
{
530
  if (strstr (so->so_original_name, "/libspe") != NULL)
531
    {
532
      solib_read_symbols (so, 0);
533
      spu_enable_break (so->objfile);
534
    }
535
  /* In case the OpenCL runtime is loaded we install a breakpoint
536
     to get notified whenever an OpenCL program gets loaded.  */
537
  if (strstr (so->so_name, "CLRuntimeAccelCellSPU@") != NULL)
538
    {
539
      solib_read_symbols (so, 0);
540
      ocl_enable_break (so->objfile);
541
    }
542
}
543
 
544
void
545
_initialize_spu_solib (void)
546
{
547
  observer_attach_solib_loaded (spu_solib_loaded);
548
  ocl_program_data_key = register_objfile_data ();
549
}
550
 

powered by: WebSVN 2.1.0

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