GDB (API)
|
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 (¤t_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 (¤t_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 ¤t_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