]>
Commit | Line | Data |
---|---|---|
85e747d2 | 1 | /* Cell SPU GNU/Linux support -- shared library handling. |
42a4f53d | 2 | Copyright (C) 2009-2019 Free Software Foundation, Inc. |
85e747d2 UW |
3 | |
4 | Contributed by Ulrich Weigand <[email protected]>. | |
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 | |
dcf7800b | 10 | the Free Software Foundation; either version 3 of the License, or |
85e747d2 UW |
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 | |
dcf7800b | 19 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
85e747d2 UW |
20 | |
21 | #include "defs.h" | |
693be288 | 22 | #include "solib-spu.h" |
85e747d2 | 23 | #include "gdbcore.h" |
53ce3c39 | 24 | #include <sys/stat.h> |
85e747d2 UW |
25 | #include "arch-utils.h" |
26 | #include "bfd.h" | |
27 | #include "symtab.h" | |
28 | #include "solib.h" | |
29 | #include "solib-svr4.h" | |
30 | #include "solist.h" | |
31 | #include "inferior.h" | |
32 | #include "objfiles.h" | |
76727919 | 33 | #include "observable.h" |
85e747d2 UW |
34 | #include "breakpoint.h" |
35 | #include "gdbthread.h" | |
cbb099e8 | 36 | #include "gdb_bfd.h" |
85e747d2 UW |
37 | |
38 | #include "spu-tdep.h" | |
39 | ||
40 | /* Highest SPE id (file handle) the inferior may have. */ | |
41 | #define MAX_SPE_FD 1024 | |
42 | ||
43 | /* Stand-alone SPE executable? */ | |
44 | #define spu_standalone_p() \ | |
45 | (symfile_objfile && symfile_objfile->obfd \ | |
46 | && bfd_get_arch (symfile_objfile->obfd) == bfd_arch_spu) | |
47 | ||
48 | ||
49 | /* Relocate main SPE executable. */ | |
50 | static void | |
51 | spu_relocate_main_executable (int spufs_fd) | |
52 | { | |
85e747d2 UW |
53 | struct section_offsets *new_offsets; |
54 | int i; | |
55 | ||
567995e1 JK |
56 | if (symfile_objfile == NULL) |
57 | return; | |
85e747d2 | 58 | |
224c3ddb SM |
59 | new_offsets = XALLOCAVEC (struct section_offsets, |
60 | symfile_objfile->num_sections); | |
85e747d2 | 61 | |
567995e1 JK |
62 | for (i = 0; i < symfile_objfile->num_sections; i++) |
63 | new_offsets->offsets[i] = SPUADDR (spufs_fd, 0); | |
64 | ||
65 | objfile_relocate (symfile_objfile, new_offsets); | |
85e747d2 UW |
66 | } |
67 | ||
68 | /* When running a stand-alone SPE executable, we may need to skip one more | |
69 | exec event on startup, to get past the binfmt_misc loader. */ | |
70 | static void | |
71 | spu_skip_standalone_loader (void) | |
72 | { | |
73 | if (target_has_execution && !current_inferior ()->attach_flag) | |
74 | { | |
75 | struct target_waitstatus ws; | |
76 | ||
77 | /* Only some kernels report an extra SIGTRAP with the binfmt_misc | |
78 | loader; others do not. In addition, if we have attached to an | |
79 | already running inferior instead of starting a new one, we will | |
80 | not see the extra SIGTRAP -- and we cannot readily distinguish | |
81 | the two cases, in particular with the extended-remote target. | |
82 | ||
83 | Thus we issue a single-step here. If no extra SIGTRAP was pending, | |
84 | this will step past the first instruction of the stand-alone SPE | |
85 | executable loader, but we don't care about that. */ | |
86 | ||
16c381f0 | 87 | inferior_thread ()->control.in_infcall = 1; /* Suppress MI messages. */ |
85e747d2 | 88 | |
a493e3e2 | 89 | target_resume (inferior_ptid, 1, GDB_SIGNAL_0); |
85e747d2 UW |
90 | target_wait (minus_one_ptid, &ws, 0); |
91 | set_executing (minus_one_ptid, 0); | |
92 | ||
16c381f0 | 93 | inferior_thread ()->control.in_infcall = 0; |
85e747d2 UW |
94 | } |
95 | } | |
96 | ||
f1d8ee66 UW |
97 | static const struct objfile_data *ocl_program_data_key; |
98 | ||
99 | /* Appends OpenCL programs to the list of `struct so_list' objects. */ | |
100 | static void | |
101 | append_ocl_sos (struct so_list **link_ptr) | |
102 | { | |
103 | CORE_ADDR *ocl_program_addr_base; | |
f1d8ee66 | 104 | |
2030c079 | 105 | for (objfile *objfile : current_program_space->objfiles ()) |
f1d8ee66 | 106 | { |
19ba03f4 SM |
107 | ocl_program_addr_base |
108 | = (CORE_ADDR *) objfile_data (objfile, ocl_program_data_key); | |
f1d8ee66 UW |
109 | if (ocl_program_addr_base != NULL) |
110 | { | |
111 | enum bfd_endian byte_order = bfd_big_endian (objfile->obfd)? | |
112 | BFD_ENDIAN_BIG : BFD_ENDIAN_LITTLE; | |
492d29ea | 113 | TRY |
f1d8ee66 UW |
114 | { |
115 | CORE_ADDR data = | |
116 | read_memory_unsigned_integer (*ocl_program_addr_base, | |
117 | sizeof (CORE_ADDR), | |
118 | byte_order); | |
119 | if (data != 0x0) | |
120 | { | |
fe978cb0 | 121 | struct so_list *newobj; |
f1d8ee66 UW |
122 | |
123 | /* Allocate so_list structure. */ | |
fe978cb0 | 124 | newobj = XCNEW (struct so_list); |
f1d8ee66 UW |
125 | |
126 | /* Encode FD and object ID in path name. */ | |
fe978cb0 | 127 | xsnprintf (newobj->so_name, sizeof newobj->so_name, "@%s <%d>", |
070c8028 UW |
128 | hex_string (data), |
129 | SPUADDR_SPU (*ocl_program_addr_base)); | |
fe978cb0 | 130 | strcpy (newobj->so_original_name, newobj->so_name); |
f1d8ee66 | 131 | |
fe978cb0 PA |
132 | *link_ptr = newobj; |
133 | link_ptr = &newobj->next; | |
f1d8ee66 UW |
134 | } |
135 | } | |
492d29ea | 136 | CATCH (ex, RETURN_MASK_ALL) |
f1d8ee66 UW |
137 | { |
138 | /* Ignore memory errors. */ | |
139 | switch (ex.error) | |
140 | { | |
141 | case MEMORY_ERROR: | |
142 | break; | |
143 | default: | |
144 | throw_exception (ex); | |
145 | break; | |
146 | } | |
147 | } | |
492d29ea | 148 | END_CATCH |
f1d8ee66 UW |
149 | } |
150 | } | |
151 | } | |
152 | ||
85e747d2 UW |
153 | /* Build a list of `struct so_list' objects describing the shared |
154 | objects currently loaded in the inferior. */ | |
155 | static struct so_list * | |
156 | spu_current_sos (void) | |
157 | { | |
f5656ead | 158 | enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ()); |
85e747d2 UW |
159 | struct so_list *head; |
160 | struct so_list **link_ptr; | |
161 | ||
e362b510 | 162 | gdb_byte buf[MAX_SPE_FD * 4]; |
85e747d2 UW |
163 | int i, size; |
164 | ||
165 | /* First, retrieve the SVR4 shared library list. */ | |
166 | head = svr4_so_ops.current_sos (); | |
167 | ||
168 | /* Append our libraries to the end of the list. */ | |
169 | for (link_ptr = &head; *link_ptr; link_ptr = &(*link_ptr)->next) | |
170 | ; | |
171 | ||
172 | /* Determine list of SPU ids. */ | |
8b88a78e | 173 | size = target_read (current_top_target (), TARGET_OBJECT_SPU, NULL, |
85e747d2 UW |
174 | buf, 0, sizeof buf); |
175 | ||
176 | /* Do not add stand-alone SPE executable context as shared library, | |
177 | but relocate main SPE executable objfile. */ | |
178 | if (spu_standalone_p ()) | |
179 | { | |
180 | if (size == 4) | |
181 | { | |
182 | int fd = extract_unsigned_integer (buf, 4, byte_order); | |
433759f7 | 183 | |
85e747d2 UW |
184 | spu_relocate_main_executable (fd); |
185 | ||
186 | /* Re-enable breakpoints after main SPU context was established; | |
187 | see also comments in spu_solib_create_inferior_hook. */ | |
188 | enable_breakpoints_after_startup (); | |
189 | } | |
190 | ||
191 | return head; | |
192 | } | |
193 | ||
194 | /* Create an so_list entry for each SPU id. */ | |
195 | for (i = 0; i < size; i += 4) | |
196 | { | |
197 | int fd = extract_unsigned_integer (buf + i, 4, byte_order); | |
fe978cb0 | 198 | struct so_list *newobj; |
85e747d2 UW |
199 | |
200 | unsigned long long addr; | |
201 | char annex[32], id[100]; | |
202 | int len; | |
203 | ||
204 | /* Read object ID. There's a race window where the inferior may have | |
205 | already created the SPE context, but not installed the object-id | |
206 | yet. Skip such entries; we'll be back for them later. */ | |
207 | xsnprintf (annex, sizeof annex, "%d/object-id", fd); | |
8b88a78e | 208 | len = target_read (current_top_target (), TARGET_OBJECT_SPU, annex, |
001f13d8 | 209 | (gdb_byte *) id, 0, sizeof id); |
85e747d2 UW |
210 | if (len <= 0 || len >= sizeof id) |
211 | continue; | |
212 | id[len] = 0; | |
213 | if (sscanf (id, "0x%llx", &addr) != 1 || !addr) | |
214 | continue; | |
215 | ||
216 | /* Allocate so_list structure. */ | |
fe978cb0 | 217 | newobj = XCNEW (struct so_list); |
85e747d2 UW |
218 | |
219 | /* Encode FD and object ID in path name. Choose the name so as not | |
220 | to conflict with any (normal) SVR4 library path name. */ | |
fe978cb0 | 221 | xsnprintf (newobj->so_name, sizeof newobj->so_name, "@%s <%d>", |
2244ba2e | 222 | hex_string (addr), fd); |
fe978cb0 | 223 | strcpy (newobj->so_original_name, newobj->so_name); |
85e747d2 | 224 | |
fe978cb0 PA |
225 | *link_ptr = newobj; |
226 | link_ptr = &newobj->next; | |
85e747d2 UW |
227 | } |
228 | ||
c378eb4e | 229 | /* Append OpenCL sos. */ |
f1d8ee66 UW |
230 | append_ocl_sos (link_ptr); |
231 | ||
85e747d2 UW |
232 | return head; |
233 | } | |
234 | ||
235 | /* Free so_list information. */ | |
236 | static void | |
237 | spu_free_so (struct so_list *so) | |
238 | { | |
239 | if (so->so_original_name[0] != '@') | |
240 | svr4_so_ops.free_so (so); | |
241 | } | |
242 | ||
243 | /* Relocate section addresses. */ | |
244 | static void | |
245 | spu_relocate_section_addresses (struct so_list *so, | |
246 | struct target_section *sec) | |
247 | { | |
248 | if (so->so_original_name[0] != '@') | |
249 | svr4_so_ops.relocate_section_addresses (so, sec); | |
250 | else | |
251 | { | |
252 | unsigned long long addr; | |
253 | int fd; | |
254 | ||
255 | /* Set addr_low/high to just LS offset for display. */ | |
256 | if (so->addr_low == 0 && so->addr_high == 0 | |
257 | && strcmp (sec->the_bfd_section->name, ".text") == 0) | |
258 | { | |
259 | so->addr_low = sec->addr; | |
260 | so->addr_high = sec->endaddr; | |
261 | } | |
262 | ||
263 | /* Decode object ID. */ | |
264 | if (sscanf (so->so_original_name, "@0x%llx <%d>", &addr, &fd) != 2) | |
265 | internal_error (__FILE__, __LINE__, "bad object ID"); | |
266 | ||
267 | sec->addr = SPUADDR (fd, sec->addr); | |
268 | sec->endaddr = SPUADDR (fd, sec->endaddr); | |
269 | } | |
270 | } | |
271 | ||
272 | ||
273 | /* Inferior memory should contain an SPE executable image at location ADDR. | |
274 | Allocate a BFD representing that executable. Return NULL on error. */ | |
275 | ||
276 | static void * | |
277 | spu_bfd_iovec_open (bfd *nbfd, void *open_closure) | |
278 | { | |
279 | return open_closure; | |
280 | } | |
281 | ||
282 | static int | |
283 | spu_bfd_iovec_close (bfd *nbfd, void *stream) | |
284 | { | |
285 | xfree (stream); | |
39ed5604 JK |
286 | |
287 | /* Zero means success. */ | |
288 | return 0; | |
85e747d2 UW |
289 | } |
290 | ||
291 | static file_ptr | |
292 | spu_bfd_iovec_pread (bfd *abfd, void *stream, void *buf, | |
293 | file_ptr nbytes, file_ptr offset) | |
294 | { | |
295 | CORE_ADDR addr = *(CORE_ADDR *)stream; | |
296 | int ret; | |
297 | ||
5af9928d | 298 | ret = target_read_memory (addr + offset, (gdb_byte *) buf, nbytes); |
85e747d2 UW |
299 | if (ret != 0) |
300 | { | |
301 | bfd_set_error (bfd_error_invalid_operation); | |
302 | return -1; | |
303 | } | |
304 | ||
305 | return nbytes; | |
306 | } | |
307 | ||
308 | static int | |
309 | spu_bfd_iovec_stat (bfd *abfd, void *stream, struct stat *sb) | |
310 | { | |
311 | /* We don't have an easy way of finding the size of embedded spu | |
312 | images. We could parse the in-memory ELF header and section | |
313 | table to find the extent of the last section but that seems | |
314 | pointless when the size is needed only for checks of other | |
315 | parsed values in dbxread.c. */ | |
326a5c7e | 316 | memset (sb, 0, sizeof (struct stat)); |
85e747d2 UW |
317 | sb->st_size = INT_MAX; |
318 | return 0; | |
319 | } | |
320 | ||
192b62ce | 321 | static gdb_bfd_ref_ptr |
692d6f97 | 322 | spu_bfd_fopen (const char *name, CORE_ADDR addr) |
85e747d2 | 323 | { |
8d749320 | 324 | CORE_ADDR *open_closure = XNEW (CORE_ADDR); |
85e747d2 | 325 | |
85e747d2 UW |
326 | *open_closure = addr; |
327 | ||
192b62ce TT |
328 | gdb_bfd_ref_ptr nbfd (gdb_bfd_openr_iovec (name, "elf32-spu", |
329 | spu_bfd_iovec_open, open_closure, | |
330 | spu_bfd_iovec_pread, | |
331 | spu_bfd_iovec_close, | |
332 | spu_bfd_iovec_stat)); | |
333 | if (nbfd == NULL) | |
85e747d2 UW |
334 | return NULL; |
335 | ||
192b62ce TT |
336 | if (!bfd_check_format (nbfd.get (), bfd_object)) |
337 | return NULL; | |
85e747d2 UW |
338 | |
339 | return nbfd; | |
340 | } | |
341 | ||
342 | /* Open shared library BFD. */ | |
192b62ce | 343 | static gdb_bfd_ref_ptr |
692d6f97 | 344 | spu_bfd_open (const char *pathname) |
85e747d2 | 345 | { |
692d6f97 | 346 | const char *original_name = strrchr (pathname, '@'); |
85e747d2 UW |
347 | asection *spu_name; |
348 | unsigned long long addr; | |
349 | int fd; | |
350 | ||
351 | /* Handle regular SVR4 libraries. */ | |
352 | if (!original_name) | |
353 | return svr4_so_ops.bfd_open (pathname); | |
354 | ||
355 | /* Decode object ID. */ | |
356 | if (sscanf (original_name, "@0x%llx <%d>", &addr, &fd) != 2) | |
357 | internal_error (__FILE__, __LINE__, "bad object ID"); | |
358 | ||
359 | /* Open BFD representing SPE executable. */ | |
192b62ce TT |
360 | gdb_bfd_ref_ptr abfd (spu_bfd_fopen (original_name, (CORE_ADDR) addr)); |
361 | if (abfd == NULL) | |
85e747d2 UW |
362 | error (_("Cannot read SPE executable at %s"), original_name); |
363 | ||
364 | /* Retrieve SPU name note. */ | |
192b62ce | 365 | spu_name = bfd_get_section_by_name (abfd.get (), ".note.spu_name"); |
85e747d2 UW |
366 | if (spu_name) |
367 | { | |
192b62ce | 368 | int sect_size = bfd_section_size (abfd.get (), spu_name); |
433759f7 | 369 | |
85e747d2 UW |
370 | if (sect_size > 20) |
371 | { | |
224c3ddb SM |
372 | char *buf |
373 | = (char *) alloca (sect_size - 20 + strlen (original_name) + 1); | |
433759f7 | 374 | |
192b62ce TT |
375 | bfd_get_section_contents (abfd.get (), spu_name, buf, 20, |
376 | sect_size - 20); | |
85e747d2 UW |
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. */ | |
d12307c1 | 390 | static struct block_symbol |
efad9b6a | 391 | spu_lookup_lib_symbol (struct objfile *objfile, |
85e747d2 | 392 | const char *name, |
85e747d2 UW |
393 | const domain_enum domain) |
394 | { | |
395 | if (bfd_get_arch (objfile->obfd) == bfd_arch_spu) | |
94af9270 | 396 | return lookup_global_symbol_from_objfile (objfile, name, domain); |
85e747d2 UW |
397 | |
398 | if (svr4_so_ops.lookup_lib_global_symbol != NULL) | |
94af9270 | 399 | return svr4_so_ops.lookup_lib_global_symbol (objfile, name, domain); |
d12307c1 | 400 | return (struct block_symbol) {NULL, NULL}; |
85e747d2 UW |
401 | } |
402 | ||
403 | /* Enable shared library breakpoint. */ | |
404 | static int | |
405 | spu_enable_break (struct objfile *objfile) | |
406 | { | |
3b7344d5 | 407 | struct bound_minimal_symbol spe_event_sym; |
85e747d2 UW |
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. */ | |
3b7344d5 | 415 | if (spe_event_sym.minsym) |
85e747d2 | 416 | { |
77e371c0 | 417 | CORE_ADDR addr = BMSYMBOL_VALUE_ADDRESS (spe_event_sym); |
433759f7 | 418 | |
f5656ead | 419 | addr = gdbarch_convert_from_func_ptr_addr (target_gdbarch (), addr, |
8b88a78e | 420 | current_top_target ()); |
f5656ead | 421 | create_solib_event_breakpoint (target_gdbarch (), addr); |
85e747d2 UW |
422 | return 1; |
423 | } | |
424 | ||
425 | return 0; | |
426 | } | |
427 | ||
f1d8ee66 UW |
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 | { | |
3b7344d5 TT |
433 | struct bound_minimal_symbol event_sym; |
434 | struct bound_minimal_symbol addr_sym; | |
f1d8ee66 UW |
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 | ||
3b7344d5 | 444 | if (event_sym.minsym && addr_sym.minsym) |
f1d8ee66 UW |
445 | { |
446 | /* Place a solib_event breakpoint on the symbol. */ | |
77e371c0 | 447 | CORE_ADDR event_addr = BMSYMBOL_VALUE_ADDRESS (event_sym); |
f1d8ee66 UW |
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); | |
77e371c0 | 458 | *ocl_program_addr_base = BMSYMBOL_VALUE_ADDRESS (addr_sym); |
f1d8ee66 UW |
459 | set_objfile_data (objfile, ocl_program_data_key, |
460 | ocl_program_addr_base); | |
461 | } | |
462 | } | |
463 | } | |
464 | ||
85e747d2 UW |
465 | /* Create inferior hook. */ |
466 | static void | |
268a4a75 | 467 | spu_solib_create_inferior_hook (int from_tty) |
85e747d2 | 468 | { |
85e747d2 UW |
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. */ | |
268a4a75 | 494 | svr4_so_ops.solib_create_inferior_hook (from_tty); |
85e747d2 UW |
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 | { | |
7e559477 | 532 | solib_read_symbols (so, 0); |
85e747d2 UW |
533 | spu_enable_break (so->objfile); |
534 | } | |
f1d8ee66 UW |
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 | } | |
85e747d2 UW |
542 | } |
543 | ||
544 | void | |
545 | _initialize_spu_solib (void) | |
546 | { | |
76727919 | 547 | gdb::observers::solib_loaded.attach (spu_solib_loaded); |
f1d8ee66 | 548 | ocl_program_data_key = register_objfile_data (); |
85e747d2 UW |
549 | } |
550 |