/* Cell SPU GNU/Linux support -- shared library handling.
- Copyright (C) 2009 Free Software Foundation, Inc.
+ Copyright (C) 2009-2014 Free Software Foundation, Inc.
Contributed by Ulrich Weigand <uweigand@de.ibm.com>.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
+#include "solib-spu.h"
#include "gdbcore.h"
-#include "gdb_string.h"
-#include "gdb_assert.h"
-#include "gdb_stat.h"
+#include <sys/stat.h>
#include "arch-utils.h"
#include "bfd.h"
#include "symtab.h"
#include "observer.h"
#include "breakpoint.h"
#include "gdbthread.h"
+#include "gdb_bfd.h"
#include "spu-tdep.h"
static void
spu_relocate_main_executable (int spufs_fd)
{
- struct objfile *objfile;
- struct cleanup *old_chain;
struct section_offsets *new_offsets;
int i;
- for (objfile = symfile_objfile;
- objfile;
- objfile = objfile->separate_debug_objfile)
- {
- new_offsets = xcalloc (objfile->num_sections,
- sizeof (struct section_offsets));
- old_chain = make_cleanup (xfree, new_offsets);
+ if (symfile_objfile == NULL)
+ return;
- for (i = 0; i < objfile->num_sections; i++)
- new_offsets->offsets[i] = SPUADDR (spufs_fd, 0);
+ new_offsets = alloca (symfile_objfile->num_sections
+ * sizeof (struct section_offsets));
- objfile_relocate (objfile, new_offsets);
- do_cleanups (old_chain);
- }
+ for (i = 0; i < symfile_objfile->num_sections; i++)
+ new_offsets->offsets[i] = SPUADDR (spufs_fd, 0);
+
+ objfile_relocate (symfile_objfile, new_offsets);
}
/* When running a stand-alone SPE executable, we may need to skip one more
this will step past the first instruction of the stand-alone SPE
executable loader, but we don't care about that. */
- inferior_thread ()->in_infcall = 1; /* Suppress MI messages. */
+ inferior_thread ()->control.in_infcall = 1; /* Suppress MI messages. */
- target_resume (inferior_ptid, 1, TARGET_SIGNAL_0);
+ target_resume (inferior_ptid, 1, GDB_SIGNAL_0);
target_wait (minus_one_ptid, &ws, 0);
set_executing (minus_one_ptid, 0);
- inferior_thread ()->in_infcall = 0;
+ inferior_thread ()->control.in_infcall = 0;
+ }
+}
+
+static const struct objfile_data *ocl_program_data_key;
+
+/* Appends OpenCL programs to the list of `struct so_list' objects. */
+static void
+append_ocl_sos (struct so_list **link_ptr)
+{
+ CORE_ADDR *ocl_program_addr_base;
+ struct objfile *objfile;
+
+ ALL_OBJFILES (objfile)
+ {
+ ocl_program_addr_base = objfile_data (objfile, ocl_program_data_key);
+ if (ocl_program_addr_base != NULL)
+ {
+ enum bfd_endian byte_order = bfd_big_endian (objfile->obfd)?
+ BFD_ENDIAN_BIG : BFD_ENDIAN_LITTLE;
+ volatile struct gdb_exception ex;
+ TRY_CATCH (ex, RETURN_MASK_ALL)
+ {
+ CORE_ADDR data =
+ read_memory_unsigned_integer (*ocl_program_addr_base,
+ sizeof (CORE_ADDR),
+ byte_order);
+ if (data != 0x0)
+ {
+ struct so_list *new;
+
+ /* Allocate so_list structure. */
+ new = XCNEW (struct so_list);
+
+ /* Encode FD and object ID in path name. */
+ xsnprintf (new->so_name, sizeof new->so_name, "@%s <%d>",
+ hex_string (data),
+ SPUADDR_SPU (*ocl_program_addr_base));
+ strcpy (new->so_original_name, new->so_name);
+
+ *link_ptr = new;
+ link_ptr = &new->next;
+ }
+ }
+ if (ex.reason < 0)
+ {
+ /* Ignore memory errors. */
+ switch (ex.error)
+ {
+ case MEMORY_ERROR:
+ break;
+ default:
+ throw_exception (ex);
+ break;
+ }
+ }
+ }
}
}
static struct so_list *
spu_current_sos (void)
{
- enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch);
+ enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ());
struct so_list *head;
struct so_list **link_ptr;
- char buf[MAX_SPE_FD * 4];
+ gdb_byte buf[MAX_SPE_FD * 4];
int i, size;
/* First, retrieve the SVR4 shared library list. */
if (size == 4)
{
int fd = extract_unsigned_integer (buf, 4, byte_order);
+
spu_relocate_main_executable (fd);
/* Re-enable breakpoints after main SPU context was established;
yet. Skip such entries; we'll be back for them later. */
xsnprintf (annex, sizeof annex, "%d/object-id", fd);
len = target_read (¤t_target, TARGET_OBJECT_SPU, annex,
- id, 0, sizeof id);
+ (gdb_byte *) id, 0, sizeof id);
if (len <= 0 || len >= sizeof id)
continue;
id[len] = 0;
continue;
/* Allocate so_list structure. */
- new = XZALLOC (struct so_list);
+ new = XCNEW (struct so_list);
/* Encode FD and object ID in path name. Choose the name so as not
to conflict with any (normal) SVR4 library path name. */
- xsnprintf (new->so_name, sizeof new->so_name, "@0x%llx <%d>", addr, fd);
+ xsnprintf (new->so_name, sizeof new->so_name, "@%s <%d>",
+ hex_string (addr), fd);
strcpy (new->so_original_name, new->so_name);
*link_ptr = new;
link_ptr = &new->next;
}
+ /* Append OpenCL sos. */
+ append_ocl_sos (link_ptr);
+
return head;
}
spu_bfd_iovec_close (bfd *nbfd, void *stream)
{
xfree (stream);
- return 1;
+
+ /* Zero means success. */
+ return 0;
}
static file_ptr
CORE_ADDR *open_closure = xmalloc (sizeof (CORE_ADDR));
*open_closure = addr;
- nbfd = bfd_openr_iovec (xstrdup (name), "elf32-spu",
- spu_bfd_iovec_open, open_closure,
- spu_bfd_iovec_pread, spu_bfd_iovec_close,
- spu_bfd_iovec_stat);
+ nbfd = gdb_bfd_openr_iovec (name, "elf32-spu",
+ spu_bfd_iovec_open, open_closure,
+ spu_bfd_iovec_pread, spu_bfd_iovec_close,
+ spu_bfd_iovec_stat);
if (!nbfd)
return NULL;
if (!bfd_check_format (nbfd, bfd_object))
{
- bfd_close (nbfd);
+ gdb_bfd_unref (nbfd);
return NULL;
}
if (spu_name)
{
int sect_size = bfd_section_size (abfd, spu_name);
+
if (sect_size > 20)
{
char *buf = alloca (sect_size - 20 + strlen (original_name) + 1);
+
bfd_get_section_contents (abfd, spu_name, buf, 20, sect_size - 20);
buf[sect_size - 20] = '\0';
static struct symbol *
spu_lookup_lib_symbol (const struct objfile *objfile,
const char *name,
- const char *linkage_name,
const domain_enum domain)
{
if (bfd_get_arch (objfile->obfd) == bfd_arch_spu)
- return lookup_global_symbol_from_objfile (objfile, name, linkage_name,
- domain);
+ return lookup_global_symbol_from_objfile (objfile, name, domain);
if (svr4_so_ops.lookup_lib_global_symbol != NULL)
- return svr4_so_ops.lookup_lib_global_symbol (objfile, name, linkage_name,
- domain);
+ return svr4_so_ops.lookup_lib_global_symbol (objfile, name, domain);
return NULL;
}
static int
spu_enable_break (struct objfile *objfile)
{
- struct minimal_symbol *spe_event_sym = NULL;
+ struct bound_minimal_symbol spe_event_sym;
/* The libspe library will call __spe_context_update_event whenever any
SPE context is allocated or destroyed. */
NULL, objfile);
/* Place a solib_event breakpoint on the symbol. */
- if (spe_event_sym)
+ if (spe_event_sym.minsym)
{
- CORE_ADDR addr = SYMBOL_VALUE_ADDRESS (spe_event_sym);
- addr = gdbarch_convert_from_func_ptr_addr (target_gdbarch, addr,
+ CORE_ADDR addr = BMSYMBOL_VALUE_ADDRESS (spe_event_sym);
+
+ addr = gdbarch_convert_from_func_ptr_addr (target_gdbarch (), addr,
¤t_target);
- create_solib_event_breakpoint (target_gdbarch, addr);
+ create_solib_event_breakpoint (target_gdbarch (), addr);
return 1;
}
return 0;
}
-/* Create inferior hook. */
+/* Enable shared library breakpoint for the
+ OpenCL runtime running on the SPU. */
static void
-spu_solib_create_inferior_hook (void)
+ocl_enable_break (struct objfile *objfile)
{
- /* Remove all previously installed solib breakpoints. Both the SVR4
- code and us will re-install all required breakpoints. */
- remove_solib_event_breakpoints ();
+ struct bound_minimal_symbol event_sym;
+ struct bound_minimal_symbol addr_sym;
+
+ /* The OpenCL runtime on the SPU will call __opencl_program_update_event
+ whenever an OpenCL program is loaded. */
+ event_sym = lookup_minimal_symbol ("__opencl_program_update_event", NULL,
+ objfile);
+ /* The PPU address of the OpenCL program can be found
+ at opencl_elf_image_address. */
+ addr_sym = lookup_minimal_symbol ("opencl_elf_image_address", NULL, objfile);
+
+ if (event_sym.minsym && addr_sym.minsym)
+ {
+ /* Place a solib_event breakpoint on the symbol. */
+ CORE_ADDR event_addr = BMSYMBOL_VALUE_ADDRESS (event_sym);
+ create_solib_event_breakpoint (get_objfile_arch (objfile), event_addr);
+ /* Store the address of the symbol that will point to OpenCL program
+ using the per-objfile private data mechanism. */
+ if (objfile_data (objfile, ocl_program_data_key) == NULL)
+ {
+ CORE_ADDR *ocl_program_addr_base = OBSTACK_CALLOC (
+ &objfile->objfile_obstack,
+ objfile->sections_end - objfile->sections,
+ CORE_ADDR);
+ *ocl_program_addr_base = BMSYMBOL_VALUE_ADDRESS (addr_sym);
+ set_objfile_data (objfile, ocl_program_data_key,
+ ocl_program_addr_base);
+ }
+ }
+}
+
+/* Create inferior hook. */
+static void
+spu_solib_create_inferior_hook (int from_tty)
+{
/* Handle SPE stand-alone executables. */
if (spu_standalone_p ())
{
}
/* Call SVR4 hook -- this will re-insert the SVR4 solib breakpoints. */
- svr4_so_ops.solib_create_inferior_hook ();
+ svr4_so_ops.solib_create_inferior_hook (from_tty);
/* If the inferior is statically linked against libspe, we need to install
our own solib breakpoint right now. Otherwise, it will be installed by
{
if (strstr (so->so_original_name, "/libspe") != NULL)
{
- solib_read_symbols (so, so->from_tty ? SYMFILE_VERBOSE : 0);
+ solib_read_symbols (so, 0);
spu_enable_break (so->objfile);
}
+ /* In case the OpenCL runtime is loaded we install a breakpoint
+ to get notified whenever an OpenCL program gets loaded. */
+ if (strstr (so->so_name, "CLRuntimeAccelCellSPU@") != NULL)
+ {
+ solib_read_symbols (so, 0);
+ ocl_enable_break (so->objfile);
+ }
}
+/* -Wmissing-prototypes */
+extern initialize_file_ftype _initialize_spu_solib;
+
void
_initialize_spu_solib (void)
{
observer_attach_solib_loaded (spu_solib_loaded);
+ ocl_program_data_key = register_objfile_data ();
}