/* Cell SPU GNU/Linux support -- shared library handling.
- Copyright (C) 2009 Free Software Foundation, Inc.
+ Copyright (C) 2009, 2010 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 "gdbcore.h"
#include "observer.h"
#include "breakpoint.h"
#include "gdbthread.h"
+#include "exceptions.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
}
}
+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 = XZALLOC (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;
+ }
+ }
+ }
+ }
+}
+
/* Build a list of `struct so_list' objects describing the shared
objects currently loaded in the inferior. */
static struct so_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;
/* 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;
}
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;
}
if (spe_event_sym)
{
CORE_ADDR addr = SYMBOL_VALUE_ADDRESS (spe_event_sym);
+
addr = gdbarch_convert_from_func_ptr_addr (target_gdbarch, addr,
¤t_target);
create_solib_event_breakpoint (target_gdbarch, addr);
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 minimal_symbol *event_sym = NULL;
+ struct minimal_symbol *addr_sym = NULL;
+
+ /* 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 && addr_sym)
+ {
+ /* Place a solib_event breakpoint on the symbol. */
+ CORE_ADDR event_addr = SYMBOL_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 = SYMBOL_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);
+ }
}
void
_initialize_spu_solib (void)
{
observer_attach_solib_loaded (spu_solib_loaded);
+ ocl_program_data_key = register_objfile_data ();
}