GDB (API)
/home/stan/gdb/src/gdb/solib-spu.c
Go to the documentation of this file.
00001 /* Cell SPU GNU/Linux support -- shared library handling.
00002    Copyright (C) 2009-2013 Free Software Foundation, Inc.
00003 
00004    Contributed by Ulrich Weigand <uweigand@de.ibm.com>.
00005 
00006    This file is part of GDB.
00007 
00008    This program is free software; you can redistribute it and/or modify
00009    it under the terms of the GNU General Public License as published by
00010    the Free Software Foundation; either version 3 of the License, or
00011    (at your option) any later version.
00012 
00013    This program is distributed in the hope that it will be useful,
00014    but WITHOUT ANY WARRANTY; without even the implied warranty of
00015    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016    GNU General Public License for more details.
00017 
00018    You should have received a copy of the GNU General Public License
00019    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
00020 
00021 #include "defs.h"
00022 #include "solib-spu.h"
00023 #include "gdbcore.h"
00024 #include "gdb_string.h"
00025 #include "gdb_assert.h"
00026 #include "gdb_stat.h"
00027 #include "arch-utils.h"
00028 #include "bfd.h"
00029 #include "symtab.h"
00030 #include "solib.h"
00031 #include "solib-svr4.h"
00032 #include "solist.h"
00033 #include "inferior.h"
00034 #include "objfiles.h"
00035 #include "observer.h"
00036 #include "breakpoint.h"
00037 #include "gdbthread.h"
00038 #include "exceptions.h"
00039 #include "gdb_bfd.h"
00040 
00041 #include "spu-tdep.h"
00042 
00043 /* Highest SPE id (file handle) the inferior may have.  */
00044 #define MAX_SPE_FD 1024
00045 
00046 /* Stand-alone SPE executable?  */
00047 #define spu_standalone_p() \
00048   (symfile_objfile && symfile_objfile->obfd \
00049    && bfd_get_arch (symfile_objfile->obfd) == bfd_arch_spu)
00050 
00051 
00052 /* Relocate main SPE executable.  */
00053 static void
00054 spu_relocate_main_executable (int spufs_fd)
00055 {
00056   struct section_offsets *new_offsets;
00057   int i;
00058 
00059   if (symfile_objfile == NULL)
00060     return;
00061 
00062   new_offsets = alloca (symfile_objfile->num_sections
00063                         * sizeof (struct section_offsets));
00064 
00065   for (i = 0; i < symfile_objfile->num_sections; i++)
00066     new_offsets->offsets[i] = SPUADDR (spufs_fd, 0);
00067 
00068   objfile_relocate (symfile_objfile, new_offsets);
00069 }
00070 
00071 /* When running a stand-alone SPE executable, we may need to skip one more
00072    exec event on startup, to get past the binfmt_misc loader.  */
00073 static void
00074 spu_skip_standalone_loader (void)
00075 {
00076   if (target_has_execution && !current_inferior ()->attach_flag)
00077     {
00078       struct target_waitstatus ws;
00079 
00080       /* Only some kernels report an extra SIGTRAP with the binfmt_misc
00081          loader; others do not.  In addition, if we have attached to an
00082          already running inferior instead of starting a new one, we will
00083          not see the extra SIGTRAP -- and we cannot readily distinguish
00084          the two cases, in particular with the extended-remote target.
00085 
00086          Thus we issue a single-step here.  If no extra SIGTRAP was pending,
00087          this will step past the first instruction of the stand-alone SPE
00088          executable loader, but we don't care about that.  */
00089 
00090       inferior_thread ()->control.in_infcall = 1; /* Suppress MI messages.  */
00091 
00092       target_resume (inferior_ptid, 1, GDB_SIGNAL_0);
00093       target_wait (minus_one_ptid, &ws, 0);
00094       set_executing (minus_one_ptid, 0);
00095 
00096       inferior_thread ()->control.in_infcall = 0;
00097     }
00098 }
00099 
00100 static const struct objfile_data *ocl_program_data_key;
00101 
00102 /* Appends OpenCL programs to the list of `struct so_list' objects.  */
00103 static void
00104 append_ocl_sos (struct so_list **link_ptr)
00105 {
00106   CORE_ADDR *ocl_program_addr_base;
00107   struct objfile *objfile;
00108 
00109   ALL_OBJFILES (objfile)
00110     {
00111       ocl_program_addr_base = objfile_data (objfile, ocl_program_data_key);
00112       if (ocl_program_addr_base != NULL)
00113         {
00114           enum bfd_endian byte_order = bfd_big_endian (objfile->obfd)?
00115                                          BFD_ENDIAN_BIG : BFD_ENDIAN_LITTLE;
00116           volatile struct gdb_exception ex;
00117           TRY_CATCH (ex, RETURN_MASK_ALL)
00118             {
00119               CORE_ADDR data =
00120                 read_memory_unsigned_integer (*ocl_program_addr_base,
00121                                               sizeof (CORE_ADDR),
00122                                               byte_order);
00123               if (data != 0x0)
00124                 {
00125                   struct so_list *new;
00126 
00127                   /* Allocate so_list structure.  */
00128                   new = XZALLOC (struct so_list);
00129 
00130                   /* Encode FD and object ID in path name.  */
00131                   xsnprintf (new->so_name, sizeof new->so_name, "@%s <%d>",
00132                              hex_string (data),
00133                              SPUADDR_SPU (*ocl_program_addr_base));
00134                   strcpy (new->so_original_name, new->so_name);
00135 
00136                   *link_ptr = new;
00137                   link_ptr = &new->next;
00138                 }
00139             }
00140           if (ex.reason < 0)
00141             {
00142               /* Ignore memory errors.  */
00143               switch (ex.error)
00144                 {
00145                 case MEMORY_ERROR:
00146                   break;
00147                 default:
00148                   throw_exception (ex);
00149                   break;
00150                 }
00151             }
00152         }
00153     }
00154 }
00155 
00156 /* Build a list of `struct so_list' objects describing the shared
00157    objects currently loaded in the inferior.  */
00158 static struct so_list *
00159 spu_current_sos (void)
00160 {
00161   enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ());
00162   struct so_list *head;
00163   struct so_list **link_ptr;
00164 
00165   gdb_byte buf[MAX_SPE_FD * 4];
00166   int i, size;
00167 
00168   /* First, retrieve the SVR4 shared library list.  */
00169   head = svr4_so_ops.current_sos ();
00170 
00171   /* Append our libraries to the end of the list.  */
00172   for (link_ptr = &head; *link_ptr; link_ptr = &(*link_ptr)->next)
00173     ;
00174 
00175   /* Determine list of SPU ids.  */
00176   size = target_read (&current_target, TARGET_OBJECT_SPU, NULL,
00177                       buf, 0, sizeof buf);
00178 
00179   /* Do not add stand-alone SPE executable context as shared library,
00180      but relocate main SPE executable objfile.  */
00181   if (spu_standalone_p ())
00182     {
00183       if (size == 4)
00184         {
00185           int fd = extract_unsigned_integer (buf, 4, byte_order);
00186 
00187           spu_relocate_main_executable (fd);
00188 
00189           /* Re-enable breakpoints after main SPU context was established;
00190              see also comments in spu_solib_create_inferior_hook.  */
00191           enable_breakpoints_after_startup ();
00192         }
00193 
00194       return head;
00195     }
00196 
00197   /* Create an so_list entry for each SPU id.  */
00198   for (i = 0; i < size; i += 4)
00199     {
00200       int fd = extract_unsigned_integer (buf + i, 4, byte_order);
00201       struct so_list *new;
00202 
00203       unsigned long long addr;
00204       char annex[32], id[100];
00205       int len;
00206 
00207       /* Read object ID.  There's a race window where the inferior may have
00208          already created the SPE context, but not installed the object-id
00209          yet.  Skip such entries; we'll be back for them later.  */
00210       xsnprintf (annex, sizeof annex, "%d/object-id", fd);
00211       len = target_read (&current_target, TARGET_OBJECT_SPU, annex,
00212                          (gdb_byte *) id, 0, sizeof id);
00213       if (len <= 0 || len >= sizeof id)
00214         continue;
00215       id[len] = 0;
00216       if (sscanf (id, "0x%llx", &addr) != 1 || !addr)
00217         continue;
00218 
00219       /* Allocate so_list structure.  */
00220       new = XZALLOC (struct so_list);
00221 
00222       /* Encode FD and object ID in path name.  Choose the name so as not
00223          to conflict with any (normal) SVR4 library path name.  */
00224       xsnprintf (new->so_name, sizeof new->so_name, "@%s <%d>",
00225                  hex_string (addr), fd);
00226       strcpy (new->so_original_name, new->so_name);
00227 
00228       *link_ptr = new;
00229       link_ptr = &new->next;
00230     }
00231 
00232   /* Append OpenCL sos.  */
00233   append_ocl_sos (link_ptr);
00234 
00235   return head;
00236 }
00237 
00238 /* Free so_list information.  */
00239 static void
00240 spu_free_so (struct so_list *so)
00241 {
00242   if (so->so_original_name[0] != '@')
00243     svr4_so_ops.free_so (so);
00244 }
00245 
00246 /* Relocate section addresses.  */
00247 static void
00248 spu_relocate_section_addresses (struct so_list *so,
00249                                 struct target_section *sec)
00250 {
00251   if (so->so_original_name[0] != '@')
00252     svr4_so_ops.relocate_section_addresses (so, sec);
00253   else
00254     {
00255       unsigned long long addr;
00256       int fd;
00257 
00258       /* Set addr_low/high to just LS offset for display.  */
00259       if (so->addr_low == 0 && so->addr_high == 0
00260           && strcmp (sec->the_bfd_section->name, ".text") == 0)
00261         {
00262           so->addr_low = sec->addr;
00263           so->addr_high = sec->endaddr;
00264         }
00265 
00266       /* Decode object ID.  */
00267       if (sscanf (so->so_original_name, "@0x%llx <%d>", &addr, &fd) != 2)
00268         internal_error (__FILE__, __LINE__, "bad object ID");
00269 
00270       sec->addr = SPUADDR (fd, sec->addr);
00271       sec->endaddr = SPUADDR (fd, sec->endaddr);
00272     }
00273 }
00274 
00275 
00276 /* Inferior memory should contain an SPE executable image at location ADDR.
00277    Allocate a BFD representing that executable.  Return NULL on error.  */
00278 
00279 static void *
00280 spu_bfd_iovec_open (bfd *nbfd, void *open_closure)
00281 {
00282   return open_closure;
00283 }
00284 
00285 static int
00286 spu_bfd_iovec_close (bfd *nbfd, void *stream)
00287 {
00288   xfree (stream);
00289 
00290   /* Zero means success.  */
00291   return 0;
00292 }
00293 
00294 static file_ptr
00295 spu_bfd_iovec_pread (bfd *abfd, void *stream, void *buf,
00296                      file_ptr nbytes, file_ptr offset)
00297 {
00298   CORE_ADDR addr = *(CORE_ADDR *)stream;
00299   int ret;
00300 
00301   ret = target_read_memory (addr + offset, buf, nbytes);
00302   if (ret != 0)
00303     {
00304       bfd_set_error (bfd_error_invalid_operation);
00305       return -1;
00306     }
00307 
00308   return nbytes;
00309 }
00310 
00311 static int
00312 spu_bfd_iovec_stat (bfd *abfd, void *stream, struct stat *sb)
00313 {
00314   /* We don't have an easy way of finding the size of embedded spu
00315      images.  We could parse the in-memory ELF header and section
00316      table to find the extent of the last section but that seems
00317      pointless when the size is needed only for checks of other
00318      parsed values in dbxread.c.  */
00319   sb->st_size = INT_MAX;
00320   return 0;
00321 }
00322 
00323 static bfd *
00324 spu_bfd_fopen (char *name, CORE_ADDR addr)
00325 {
00326   bfd *nbfd;
00327 
00328   CORE_ADDR *open_closure = xmalloc (sizeof (CORE_ADDR));
00329   *open_closure = addr;
00330 
00331   nbfd = gdb_bfd_openr_iovec (name, "elf32-spu",
00332                               spu_bfd_iovec_open, open_closure,
00333                               spu_bfd_iovec_pread, spu_bfd_iovec_close,
00334                               spu_bfd_iovec_stat);
00335   if (!nbfd)
00336     return NULL;
00337 
00338   if (!bfd_check_format (nbfd, bfd_object))
00339     {
00340       gdb_bfd_unref (nbfd);
00341       return NULL;
00342     }
00343 
00344   return nbfd;
00345 }
00346 
00347 /* Open shared library BFD.  */
00348 static bfd *
00349 spu_bfd_open (char *pathname)
00350 {
00351   char *original_name = strrchr (pathname, '@');
00352   bfd *abfd;
00353   asection *spu_name;
00354   unsigned long long addr;
00355   int fd;
00356 
00357   /* Handle regular SVR4 libraries.  */
00358   if (!original_name)
00359     return svr4_so_ops.bfd_open (pathname);
00360 
00361   /* Decode object ID.  */
00362   if (sscanf (original_name, "@0x%llx <%d>", &addr, &fd) != 2)
00363     internal_error (__FILE__, __LINE__, "bad object ID");
00364 
00365   /* Open BFD representing SPE executable.  */
00366   abfd = spu_bfd_fopen (original_name, (CORE_ADDR) addr);
00367   if (!abfd)
00368     error (_("Cannot read SPE executable at %s"), original_name);
00369 
00370   /* Retrieve SPU name note.  */
00371   spu_name = bfd_get_section_by_name (abfd, ".note.spu_name");
00372   if (spu_name)
00373     {
00374       int sect_size = bfd_section_size (abfd, spu_name);
00375 
00376       if (sect_size > 20)
00377         {
00378           char *buf = alloca (sect_size - 20 + strlen (original_name) + 1);
00379 
00380           bfd_get_section_contents (abfd, spu_name, buf, 20, sect_size - 20);
00381           buf[sect_size - 20] = '\0';
00382 
00383           strcat (buf, original_name);
00384 
00385           xfree ((char *)abfd->filename);
00386           abfd->filename = xstrdup (buf);
00387         }
00388     }
00389 
00390   return abfd;
00391 }
00392 
00393 /* Lookup global symbol in a SPE executable.  */
00394 static struct symbol *
00395 spu_lookup_lib_symbol (const struct objfile *objfile,
00396                        const char *name,
00397                        const domain_enum domain)
00398 {
00399   if (bfd_get_arch (objfile->obfd) == bfd_arch_spu)
00400     return lookup_global_symbol_from_objfile (objfile, name, domain);
00401 
00402   if (svr4_so_ops.lookup_lib_global_symbol != NULL)
00403     return svr4_so_ops.lookup_lib_global_symbol (objfile, name, domain);
00404   return NULL;
00405 }
00406 
00407 /* Enable shared library breakpoint.  */
00408 static int
00409 spu_enable_break (struct objfile *objfile)
00410 {
00411   struct minimal_symbol *spe_event_sym = NULL;
00412 
00413   /* The libspe library will call __spe_context_update_event whenever any
00414      SPE context is allocated or destroyed.  */
00415   spe_event_sym = lookup_minimal_symbol ("__spe_context_update_event",
00416                                          NULL, objfile);
00417 
00418   /* Place a solib_event breakpoint on the symbol.  */
00419   if (spe_event_sym)
00420     {
00421       CORE_ADDR addr = SYMBOL_VALUE_ADDRESS (spe_event_sym);
00422 
00423       addr = gdbarch_convert_from_func_ptr_addr (target_gdbarch (), addr,
00424                                                  &current_target);
00425       create_solib_event_breakpoint (target_gdbarch (), addr);
00426       return 1;
00427     }
00428 
00429   return 0;
00430 }
00431 
00432 /* Enable shared library breakpoint for the
00433    OpenCL runtime running on the SPU.  */
00434 static void
00435 ocl_enable_break (struct objfile *objfile)
00436 {
00437   struct minimal_symbol *event_sym = NULL;
00438   struct minimal_symbol *addr_sym = NULL;
00439 
00440   /* The OpenCL runtime on the SPU will call __opencl_program_update_event
00441      whenever an OpenCL program is loaded.  */
00442   event_sym = lookup_minimal_symbol ("__opencl_program_update_event", NULL,
00443                                      objfile);
00444   /* The PPU address of the OpenCL program can be found
00445      at opencl_elf_image_address.  */
00446   addr_sym = lookup_minimal_symbol ("opencl_elf_image_address", NULL, objfile);
00447 
00448   if (event_sym && addr_sym)
00449     {
00450       /* Place a solib_event breakpoint on the symbol.  */
00451       CORE_ADDR event_addr = SYMBOL_VALUE_ADDRESS (event_sym);
00452       create_solib_event_breakpoint (get_objfile_arch (objfile), event_addr);
00453 
00454       /* Store the address of the symbol that will point to OpenCL program
00455          using the per-objfile private data mechanism.  */
00456       if (objfile_data (objfile, ocl_program_data_key) == NULL)
00457         {
00458           CORE_ADDR *ocl_program_addr_base = OBSTACK_CALLOC (
00459                   &objfile->objfile_obstack,
00460                   objfile->sections_end - objfile->sections,
00461                   CORE_ADDR);
00462           *ocl_program_addr_base = SYMBOL_VALUE_ADDRESS (addr_sym);
00463           set_objfile_data (objfile, ocl_program_data_key,
00464                             ocl_program_addr_base);
00465         }
00466     }
00467 }
00468 
00469 /* Create inferior hook.  */
00470 static void
00471 spu_solib_create_inferior_hook (int from_tty)
00472 {
00473   /* Handle SPE stand-alone executables.  */
00474   if (spu_standalone_p ())
00475     {
00476       /* After an SPE stand-alone executable was loaded, we'll receive
00477          an additional trap due to the binfmt_misc handler.  Make sure
00478          to skip that trap.  */
00479       spu_skip_standalone_loader ();
00480 
00481       /* If the user established breakpoints before starting the inferior, GDB
00482          would attempt to insert those now.  This would fail because the SPU
00483          context has not yet been created and the SPU executable has not yet
00484          been loaded.  To prevent such failures, we disable all user-created
00485          breakpoints now; they will be re-enabled in spu_current_sos once the
00486          main SPU context has been detected.  */
00487       disable_breakpoints_before_startup ();
00488 
00489       /* A special case arises when re-starting an executable, because at
00490          this point it still resides at the relocated address range that was
00491          determined during its last execution.  We need to undo the relocation
00492          so that that multi-architecture target recognizes the stand-alone
00493          initialization special case.  */
00494       spu_relocate_main_executable (-1);
00495     }
00496 
00497   /* Call SVR4 hook -- this will re-insert the SVR4 solib breakpoints.  */
00498   svr4_so_ops.solib_create_inferior_hook (from_tty);
00499 
00500   /* If the inferior is statically linked against libspe, we need to install
00501      our own solib breakpoint right now.  Otherwise, it will be installed by
00502      the solib_loaded observer below as soon as libspe is loaded.  */
00503   spu_enable_break (NULL);
00504 }
00505 
00506 /* Install SPE "shared library" handling.  This is called by -tdep code
00507    that wants to support SPU as a secondary architecture.  */
00508 void
00509 set_spu_solib_ops (struct gdbarch *gdbarch)
00510 {
00511   static struct target_so_ops spu_so_ops;
00512 
00513   /* Initialize this lazily, to avoid an initialization order
00514      dependency on solib-svr4.c's _initialize routine.  */
00515   if (spu_so_ops.current_sos == NULL)
00516     {
00517       spu_so_ops = svr4_so_ops;
00518       spu_so_ops.solib_create_inferior_hook = spu_solib_create_inferior_hook;
00519       spu_so_ops.relocate_section_addresses = spu_relocate_section_addresses;
00520       spu_so_ops.free_so = spu_free_so;
00521       spu_so_ops.current_sos = spu_current_sos;
00522       spu_so_ops.bfd_open = spu_bfd_open;
00523       spu_so_ops.lookup_lib_global_symbol = spu_lookup_lib_symbol;
00524     }
00525 
00526   set_solib_ops (gdbarch, &spu_so_ops);
00527 }
00528 
00529 /* Observer for the solib_loaded event.  Used to install our breakpoint
00530    if libspe is a shared library.  */
00531 static void
00532 spu_solib_loaded (struct so_list *so)
00533 {
00534   if (strstr (so->so_original_name, "/libspe") != NULL)
00535     {
00536       solib_read_symbols (so, 0);
00537       spu_enable_break (so->objfile);
00538     }
00539   /* In case the OpenCL runtime is loaded we install a breakpoint
00540      to get notified whenever an OpenCL program gets loaded.  */
00541   if (strstr (so->so_name, "CLRuntimeAccelCellSPU@") != NULL)
00542     {
00543       solib_read_symbols (so, 0);
00544       ocl_enable_break (so->objfile);
00545     }
00546 }
00547 
00548 /* -Wmissing-prototypes */
00549 extern initialize_file_ftype _initialize_spu_solib;
00550 
00551 void
00552 _initialize_spu_solib (void)
00553 {
00554   observer_attach_solib_loaded (spu_solib_loaded);
00555   ocl_program_data_key = register_objfile_data ();
00556 }
00557 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines