Commit | Line | Data |
---|---|---|
4d1eb6b4 JB |
1 | /* Copyright (C) 2013 Free Software Foundation, Inc. |
2 | ||
3 | This file is part of GDB. | |
4 | ||
5 | This program is free software; you can redistribute it and/or modify | |
6 | it under the terms of the GNU General Public License as published by | |
7 | the Free Software Foundation; either version 3 of the License, or | |
8 | (at your option) any later version. | |
9 | ||
10 | This program is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | GNU General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU General Public License | |
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | |
17 | ||
18 | #include "defs.h" | |
19 | #include "solib-aix.h" | |
20 | #include "solist.h" | |
21 | #include "inferior.h" | |
22 | #include "gdb_bfd.h" | |
23 | #include "gdbcore.h" | |
24 | #include "objfiles.h" | |
25 | #include "symtab.h" | |
26 | #include "xcoffread.h" | |
27 | #include "observer.h" | |
28 | #include "gdbcmd.h" | |
29 | ||
30 | /* Variable controlling the output of the debugging traces for | |
31 | this module. */ | |
32 | static int solib_aix_debug; | |
33 | ||
34 | /* Our private data in struct so_list. */ | |
35 | ||
36 | struct lm_info | |
37 | { | |
38 | /* The name of the file mapped by the loader. Apart from the entry | |
39 | for the main executable, this is usually a shared library (which, | |
40 | on AIX, is an archive library file, created using the "ar" | |
41 | command). */ | |
42 | char *filename; | |
43 | ||
44 | /* The name of the shared object file with the actual dynamic | |
45 | loading dependency. This may be NULL (Eg. main executable). */ | |
46 | char *member_name; | |
47 | ||
48 | /* The address in inferior memory where the text section got mapped. */ | |
49 | CORE_ADDR text_addr; | |
50 | ||
51 | /* The size of the text section, obtained via the loader data. */ | |
52 | ULONGEST text_size; | |
53 | ||
54 | /* The address in inferior memory where the data section got mapped. */ | |
55 | CORE_ADDR data_addr; | |
56 | ||
57 | /* The size of the data section, obtained via the loader data. */ | |
58 | ULONGEST data_size; | |
59 | }; | |
60 | ||
61 | typedef struct lm_info *lm_info_p; | |
62 | DEF_VEC_P(lm_info_p); | |
63 | ||
64 | /* Return a deep copy of the given struct lm_info object. */ | |
65 | ||
66 | static struct lm_info * | |
67 | solib_aix_new_lm_info (struct lm_info *info) | |
68 | { | |
69 | struct lm_info *result = xmalloc (sizeof (struct lm_info)); | |
70 | ||
71 | memcpy (result, info, sizeof (struct lm_info)); | |
72 | result->filename = xstrdup (info->filename); | |
73 | if (info->member_name != NULL) | |
74 | result->member_name = xstrdup (info->member_name); | |
75 | ||
76 | return result; | |
77 | } | |
78 | ||
79 | /* Free the memory allocated for the given lm_info. */ | |
80 | ||
81 | static void | |
82 | solib_aix_xfree_lm_info (struct lm_info *info) | |
83 | { | |
84 | xfree (info->filename); | |
85 | xfree (info->member_name); | |
86 | xfree (info); | |
87 | } | |
88 | ||
89 | /* This module's per-inferior data. */ | |
90 | ||
91 | struct solib_aix_inferior_data | |
92 | { | |
93 | /* The list of shared libraries. NULL if not computed yet. | |
94 | ||
95 | Note that the first element of this list is always the main | |
96 | executable, which is not technically a shared library. But | |
97 | we need that information to perform its relocation, and | |
98 | the same principles applied to shared libraries also apply | |
99 | to the main executable. So it's simpler to keep it as part | |
100 | of this list. */ | |
101 | VEC (lm_info_p) *library_list; | |
102 | }; | |
103 | ||
104 | /* Key to our per-inferior data. */ | |
105 | static const struct inferior_data *solib_aix_inferior_data_handle; | |
106 | ||
107 | /* Return this module's data for the given inferior. | |
108 | If none is found, add a zero'ed one now. */ | |
109 | ||
110 | static struct solib_aix_inferior_data * | |
111 | get_solib_aix_inferior_data (struct inferior *inf) | |
112 | { | |
113 | struct solib_aix_inferior_data *data; | |
114 | ||
115 | data = inferior_data (inf, solib_aix_inferior_data_handle); | |
116 | if (data == NULL) | |
117 | { | |
118 | data = XZALLOC (struct solib_aix_inferior_data); | |
119 | set_inferior_data (inf, solib_aix_inferior_data_handle, data); | |
120 | } | |
121 | ||
122 | return data; | |
123 | } | |
124 | ||
125 | #if !defined(HAVE_LIBEXPAT) | |
126 | ||
127 | /* Dummy implementation if XML support is not compiled in. */ | |
128 | ||
129 | static VEC (lm_info_p) * | |
130 | solib_aix_parse_libraries (const char *library) | |
131 | { | |
132 | static int have_warned; | |
133 | ||
134 | if (!have_warned) | |
135 | { | |
136 | have_warned = 1; | |
137 | warning (_("Can not parse XML library list; XML support was disabled " | |
138 | "at compile time")); | |
139 | } | |
140 | ||
141 | return NULL; | |
142 | } | |
143 | ||
144 | #else /* HAVE_LIBEXPAT */ | |
145 | ||
146 | #include "xml-support.h" | |
147 | ||
148 | /* Handle the start of a <library> element. */ | |
149 | ||
150 | static void | |
151 | library_list_start_library (struct gdb_xml_parser *parser, | |
152 | const struct gdb_xml_element *element, | |
153 | void *user_data, | |
154 | VEC (gdb_xml_value_s) *attributes) | |
155 | { | |
156 | VEC (lm_info_p) **list = user_data; | |
157 | struct lm_info *item = XZALLOC (struct lm_info); | |
158 | struct gdb_xml_value *attr; | |
159 | ||
160 | attr = xml_find_attribute (attributes, "name"); | |
161 | item->filename = xstrdup (attr->value); | |
162 | ||
163 | attr = xml_find_attribute (attributes, "member"); | |
164 | if (attr != NULL) | |
165 | item->member_name = xstrdup (attr->value); | |
166 | ||
167 | attr = xml_find_attribute (attributes, "text_addr"); | |
168 | item->text_addr = * (ULONGEST *) attr->value; | |
169 | ||
170 | attr = xml_find_attribute (attributes, "text_size"); | |
171 | item->text_size = * (ULONGEST *) attr->value; | |
172 | ||
173 | attr = xml_find_attribute (attributes, "data_addr"); | |
174 | item->data_addr = * (ULONGEST *) attr->value; | |
175 | ||
176 | attr = xml_find_attribute (attributes, "data_size"); | |
177 | item->data_size = * (ULONGEST *) attr->value; | |
178 | ||
179 | VEC_safe_push (lm_info_p, *list, item); | |
180 | } | |
181 | ||
182 | /* Handle the start of a <library-list> element. */ | |
183 | ||
184 | static void | |
185 | library_list_start_list (struct gdb_xml_parser *parser, | |
186 | const struct gdb_xml_element *element, | |
187 | void *user_data, VEC (gdb_xml_value_s) *attributes) | |
188 | { | |
189 | char *version = xml_find_attribute (attributes, "version")->value; | |
190 | ||
191 | if (strcmp (version, "1.0") != 0) | |
192 | gdb_xml_error (parser, | |
193 | _("Library list has unsupported version \"%s\""), | |
194 | version); | |
195 | } | |
196 | ||
197 | /* Discard the constructed library list. */ | |
198 | ||
199 | static void | |
200 | solib_aix_free_library_list (void *p) | |
201 | { | |
202 | VEC (lm_info_p) **result = p; | |
203 | struct lm_info *info; | |
204 | int ix; | |
205 | ||
206 | if (solib_aix_debug) | |
207 | fprintf_unfiltered (gdb_stdlog, "DEBUG: solib_aix_free_library_list\n"); | |
208 | ||
209 | for (ix = 0; VEC_iterate (lm_info_p, *result, ix, info); ix++) | |
210 | solib_aix_xfree_lm_info (info); | |
211 | VEC_free (lm_info_p, *result); | |
212 | *result = NULL; | |
213 | } | |
214 | ||
215 | /* The allowed elements and attributes for an AIX library list | |
216 | described in XML format. The root element is a <library-list>. */ | |
217 | ||
218 | static const struct gdb_xml_attribute library_attributes[] = | |
219 | { | |
220 | { "name", GDB_XML_AF_NONE, NULL, NULL }, | |
221 | { "member", GDB_XML_AF_OPTIONAL, NULL, NULL }, | |
222 | { "text_addr", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, | |
223 | { "text_size", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, | |
224 | { "data_addr", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, | |
225 | { "data_size", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, | |
226 | { NULL, GDB_XML_AF_NONE, NULL, NULL } | |
227 | }; | |
228 | ||
229 | static const struct gdb_xml_element library_list_children[] = | |
230 | { | |
231 | { "library", library_attributes, NULL, | |
232 | GDB_XML_EF_REPEATABLE | GDB_XML_EF_OPTIONAL, | |
233 | library_list_start_library, NULL}, | |
234 | { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL } | |
235 | }; | |
236 | ||
237 | static const struct gdb_xml_attribute library_list_attributes[] = | |
238 | { | |
239 | { "version", GDB_XML_AF_NONE, NULL, NULL }, | |
240 | { NULL, GDB_XML_AF_NONE, NULL, NULL } | |
241 | }; | |
242 | ||
243 | static const struct gdb_xml_element library_list_elements[] = | |
244 | { | |
245 | { "library-list", library_list_attributes, library_list_children, | |
246 | GDB_XML_EF_NONE, library_list_start_list, NULL }, | |
247 | { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL } | |
248 | }; | |
249 | ||
250 | /* Parse LIBRARY, a string containing the loader info in XML format, | |
251 | and return an lm_info_p vector. | |
252 | ||
253 | Return NULL if the parsing failed. */ | |
254 | ||
255 | static VEC (lm_info_p) * | |
256 | solib_aix_parse_libraries (const char *library) | |
257 | { | |
258 | VEC (lm_info_p) *result = NULL; | |
259 | struct cleanup *back_to = make_cleanup (solib_aix_free_library_list, | |
260 | &result); | |
261 | ||
262 | if (gdb_xml_parse_quick (_("aix library list"), "library-list-aix.dtd", | |
263 | library_list_elements, library, &result) == 0) | |
264 | { | |
265 | /* Parsed successfully, keep the result. */ | |
266 | discard_cleanups (back_to); | |
267 | return result; | |
268 | } | |
269 | ||
270 | do_cleanups (back_to); | |
271 | return NULL; | |
272 | } | |
273 | ||
274 | #endif /* HAVE_LIBEXPAT */ | |
275 | ||
276 | /* Return the loader info for the given inferior (INF), or NULL if | |
277 | the list could not be computed. | |
278 | ||
279 | Cache the result in per-inferior data, so as to avoid recomputing it | |
280 | each time this function is called. | |
281 | ||
282 | If an error occurs while computing this list, and WARNING_MSG | |
283 | is not NULL, then print a warning including WARNING_MSG and | |
284 | a description of the error. */ | |
285 | ||
286 | static VEC (lm_info_p) * | |
287 | solib_aix_get_library_list (struct inferior *inf, const char *warning_msg) | |
288 | { | |
289 | struct solib_aix_inferior_data *data; | |
290 | char *library_document; | |
291 | struct cleanup *cleanup; | |
292 | ||
293 | /* If already computed, return the cached value. */ | |
294 | data = get_solib_aix_inferior_data (inf); | |
295 | if (data->library_list != NULL) | |
296 | return data->library_list; | |
297 | ||
298 | library_document = target_read_stralloc (¤t_target, | |
299 | TARGET_OBJECT_AIX_LIBRARIES, | |
300 | NULL); | |
301 | if (library_document == NULL && warning_msg != NULL) | |
302 | { | |
303 | warning (_("%s (failed to read TARGET_OBJECT_AIX_LIBRARIES)"), | |
304 | warning_msg); | |
305 | return NULL; | |
306 | } | |
307 | cleanup = make_cleanup (xfree, library_document); | |
308 | ||
309 | if (solib_aix_debug) | |
310 | fprintf_unfiltered (gdb_stdlog, | |
311 | "DEBUG: TARGET_OBJECT_AIX_LIBRARIES = \n%s\n", | |
312 | library_document); | |
313 | ||
314 | data->library_list = solib_aix_parse_libraries (library_document); | |
315 | if (data->library_list == NULL && warning_msg != NULL) | |
316 | { | |
317 | warning (_("%s (missing XML support?)"), warning_msg); | |
318 | do_cleanups (cleanup); | |
319 | return NULL; | |
320 | } | |
321 | ||
322 | do_cleanups (cleanup); | |
323 | return data->library_list; | |
324 | } | |
325 | ||
326 | /* If the .bss section's VMA is set to an address located before | |
327 | the end of the .data section, causing the two sections to overlap, | |
328 | return the overlap in bytes. Otherwise, return zero. | |
329 | ||
330 | Motivation: | |
331 | ||
332 | The GNU linker sometimes sets the start address of the .bss session | |
333 | before the end of the .data section, making the 2 sections overlap. | |
334 | The loader appears to handle this situation gracefully, by simply | |
335 | loading the bss section right after the end of the .data section. | |
336 | ||
337 | This means that the .data and the .bss sections are sometimes | |
338 | no longer relocated by the same amount. The problem is that | |
339 | the ldinfo data does not contain any information regarding | |
340 | the relocation of the .bss section, assuming that it would be | |
341 | identical to the information provided for the .data section | |
342 | (this is what would normally happen if the program was linked | |
343 | correctly). | |
344 | ||
345 | GDB therefore needs to detect those cases, and make the corresponding | |
346 | adjustment to the .bss section offset computed from the ldinfo data | |
347 | when necessary. This function returns the adjustment amount (or | |
348 | zero when no adjustment is needed). */ | |
349 | ||
350 | static CORE_ADDR | |
351 | solib_aix_bss_data_overlap (bfd *abfd) | |
352 | { | |
353 | struct bfd_section *data_sect, *bss_sect; | |
354 | ||
355 | data_sect = bfd_get_section_by_name (abfd, ".data"); | |
356 | if (data_sect == NULL) | |
357 | return 0; /* No overlap possible. */ | |
358 | ||
359 | bss_sect = bfd_get_section_by_name (abfd, ".bss"); | |
360 | if (bss_sect == NULL) | |
361 | return 0; /* No overlap possible. */ | |
362 | ||
363 | /* Assume the problem only occurs with linkers that place the .bss | |
364 | section after the .data section (the problem has only been | |
365 | observed when using the GNU linker, and the default linker | |
366 | script always places the .data and .bss sections in that order). */ | |
367 | if (bfd_section_vma (abfd, bss_sect) | |
368 | < bfd_section_vma (abfd, data_sect)) | |
369 | return 0; | |
370 | ||
371 | if (bfd_section_vma (abfd, bss_sect) | |
372 | < bfd_section_vma (abfd, data_sect) + bfd_get_section_size (data_sect)) | |
373 | return ((bfd_section_vma (abfd, data_sect) | |
374 | + bfd_get_section_size (data_sect)) | |
375 | - bfd_section_vma (abfd, bss_sect)); | |
376 | ||
377 | return 0; | |
378 | } | |
379 | ||
380 | /* Implement the "relocate_section_addresses" target_so_ops method. */ | |
381 | ||
382 | static void | |
383 | solib_aix_relocate_section_addresses (struct so_list *so, | |
384 | struct target_section *sec) | |
385 | { | |
386 | bfd *abfd = sec->bfd; | |
387 | struct bfd_section *bfd_sect = sec->the_bfd_section; | |
388 | const char *section_name = bfd_section_name (abfd, bfd_sect); | |
389 | struct lm_info *info = so->lm_info; | |
390 | ||
391 | if (strcmp (section_name, ".text") == 0) | |
392 | { | |
393 | sec->addr = info->text_addr; | |
394 | sec->endaddr = sec->addr + info->text_size; | |
395 | ||
396 | /* The text address given to us by the loader contains | |
397 | XCOFF headers, so we need to adjust by this much. */ | |
398 | sec->addr += bfd_sect->filepos; | |
399 | } | |
400 | else if (strcmp (section_name, ".data") == 0) | |
401 | { | |
402 | sec->addr = info->data_addr; | |
403 | sec->endaddr = sec->addr + info->data_size; | |
404 | } | |
405 | else if (strcmp (section_name, ".bss") == 0) | |
406 | { | |
407 | sec->addr = bfd_section_vma (abfd, bfd_sect) + info->data_addr; | |
408 | sec->addr += solib_aix_bss_data_overlap (abfd); | |
409 | sec->endaddr = sec->addr + bfd_section_size (abfd, bfd_sect); | |
410 | } | |
411 | else | |
412 | { | |
413 | /* All other sections should not be relocated. */ | |
414 | /* FIXME: GDB complains that the .loader section sometimes | |
415 | overlaps with other sections (Eg: the .data section). | |
416 | As far as I can tell, the loader section had the LOAD flag | |
417 | set, but not the RELOC. So it should not be relocated. | |
418 | There seems to be a problem there, and maybe it has to do | |
419 | with setting sec->addr to 0 (when the vma is indeed 0). | |
420 | But even if there wasn't, the problem then becomes the fact | |
421 | that many shared objects inside shared libraries have | |
422 | a .loader section whose vma is 0, thus also triggering | |
423 | an overlap warning. */ | |
424 | sec->addr = bfd_section_vma (abfd, bfd_sect); | |
425 | sec->endaddr = sec->addr + bfd_section_size (abfd, bfd_sect); | |
426 | } | |
427 | } | |
428 | ||
429 | /* Implement the "free_so" target_so_ops method. */ | |
430 | ||
431 | static void | |
432 | solib_aix_free_so (struct so_list *so) | |
433 | { | |
434 | if (solib_aix_debug) | |
435 | fprintf_unfiltered (gdb_stdlog, "DEBUG: solib_aix_free_so (%s)\n", | |
436 | so->so_name); | |
437 | solib_aix_xfree_lm_info (so->lm_info); | |
438 | } | |
439 | ||
440 | /* Implement the "clear_solib" target_so_ops method. */ | |
441 | ||
442 | static void | |
443 | solib_aix_clear_solib (void) | |
444 | { | |
445 | /* Nothing needed. */ | |
446 | } | |
447 | ||
448 | /* Compute and return the OBJFILE's section_offset array, using | |
449 | the associated loader info (INFO). | |
450 | ||
451 | The resulting array is computed on the heap and must be | |
452 | deallocated after use. */ | |
453 | ||
454 | static struct section_offsets * | |
455 | solib_aix_get_section_offsets (struct objfile *objfile, | |
456 | struct lm_info *info) | |
457 | { | |
458 | struct section_offsets *offsets; | |
459 | bfd *abfd = objfile->obfd; | |
460 | int i; | |
461 | ||
462 | offsets = XCALLOC (objfile->num_sections, struct section_offsets); | |
463 | ||
464 | /* .text */ | |
465 | ||
466 | if (objfile->sect_index_text != -1) | |
467 | { | |
468 | struct bfd_section *sect | |
469 | = objfile->sections[objfile->sect_index_text].the_bfd_section; | |
470 | ||
471 | offsets->offsets[objfile->sect_index_text] | |
472 | = info->text_addr + sect->filepos - bfd_section_vma (abfd, sect); | |
473 | } | |
474 | ||
475 | /* .data */ | |
476 | ||
477 | if (objfile->sect_index_data != -1) | |
478 | { | |
479 | struct bfd_section *sect | |
480 | = objfile->sections[objfile->sect_index_data].the_bfd_section; | |
481 | ||
482 | offsets->offsets[objfile->sect_index_data] | |
483 | = info->data_addr - bfd_section_vma (abfd, sect); | |
484 | } | |
485 | ||
486 | /* .bss | |
487 | ||
488 | The offset of the .bss section should be identical to the offset | |
489 | of the .data section. If no .data section (which seems hard to | |
490 | believe it is possible), assume it is zero. */ | |
491 | ||
492 | if (objfile->sect_index_bss != -1 | |
493 | && objfile->sect_index_data != -1) | |
494 | { | |
495 | offsets->offsets[objfile->sect_index_bss] | |
496 | = (offsets->offsets[objfile->sect_index_data] | |
497 | + solib_aix_bss_data_overlap (abfd)); | |
498 | } | |
499 | ||
500 | /* All other sections should not need relocation. */ | |
501 | ||
502 | return offsets; | |
503 | } | |
504 | ||
505 | /* Implement the "solib_create_inferior_hook" target_so_ops method. */ | |
506 | ||
507 | static void | |
508 | solib_aix_solib_create_inferior_hook (int from_tty) | |
509 | { | |
510 | const char *warning_msg = "unable to relocate main executable"; | |
511 | VEC (lm_info_p) *library_list; | |
512 | struct lm_info *exec_info; | |
513 | ||
514 | /* We need to relocate the main executable... */ | |
515 | ||
516 | library_list = solib_aix_get_library_list (current_inferior (), | |
517 | warning_msg); | |
518 | if (library_list == NULL) | |
519 | return; /* Warning already printed. */ | |
520 | ||
521 | if (VEC_length (lm_info_p, library_list) < 1) | |
522 | { | |
523 | warning (_("unable to relocate main executable (no info from loader)")); | |
524 | return; | |
525 | } | |
526 | ||
527 | exec_info = VEC_index (lm_info_p, library_list, 0); | |
528 | ||
529 | if (symfile_objfile != NULL) | |
530 | { | |
531 | struct section_offsets *offsets | |
532 | = solib_aix_get_section_offsets (symfile_objfile, exec_info); | |
533 | struct cleanup *cleanup = make_cleanup (xfree, offsets); | |
534 | ||
535 | objfile_relocate (symfile_objfile, offsets); | |
536 | do_cleanups (cleanup); | |
537 | } | |
538 | } | |
539 | ||
540 | /* Implement the "special_symbol_handling" target_so_ops method. */ | |
541 | ||
542 | static void | |
543 | solib_aix_special_symbol_handling (void) | |
544 | { | |
545 | /* Nothing needed. */ | |
546 | } | |
547 | ||
548 | /* Implement the "current_sos" target_so_ops method. */ | |
549 | ||
550 | static struct so_list * | |
551 | solib_aix_current_sos (void) | |
552 | { | |
553 | struct so_list *start = NULL, *last = NULL; | |
554 | VEC (lm_info_p) *library_list; | |
555 | struct lm_info *info; | |
556 | int ix; | |
557 | ||
558 | library_list = solib_aix_get_library_list (current_inferior (), NULL); | |
559 | if (library_list == NULL) | |
560 | return NULL; | |
561 | ||
562 | /* Build a struct so_list for each entry on the list. | |
563 | We skip the first entry, since this is the entry corresponding | |
564 | to the main executable, not a shared library. */ | |
565 | for (ix = 1; VEC_iterate (lm_info_p, library_list, ix, info); ix++) | |
566 | { | |
567 | struct so_list *new_solib = XZALLOC (struct so_list); | |
568 | char *so_name; | |
569 | ||
570 | if (info->member_name == NULL) | |
571 | { | |
572 | /* INFO->FILENAME is probably not an archive, but rather | |
573 | a shared object. Unusual, but it should be possible | |
574 | to link a program against a shared object directory, | |
575 | without having to put it in an archive first. */ | |
576 | so_name = xstrdup (info->filename); | |
577 | } | |
578 | else | |
579 | { | |
580 | /* This is the usual case on AIX, where the shared object | |
581 | is a member of an archive. Create a synthetic so_name | |
582 | that follows the same convention as AIX's ldd tool | |
583 | (Eg: "/lib/libc.a(shr.o)"). */ | |
584 | so_name = xstrprintf ("%s(%s)", info->filename, info->member_name); | |
585 | } | |
586 | strncpy (new_solib->so_original_name, so_name, | |
587 | SO_NAME_MAX_PATH_SIZE - 1); | |
588 | new_solib->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0'; | |
589 | memcpy (new_solib->so_name, new_solib->so_original_name, | |
590 | SO_NAME_MAX_PATH_SIZE); | |
591 | new_solib->lm_info = solib_aix_new_lm_info (info); | |
592 | ||
593 | /* Add it to the list. */ | |
594 | if (!start) | |
595 | last = start = new_solib; | |
596 | else | |
597 | { | |
598 | last->next = new_solib; | |
599 | last = new_solib; | |
600 | } | |
601 | } | |
602 | ||
603 | return start; | |
604 | } | |
605 | ||
606 | /* Implement the "open_symbol_file_object" target_so_ops method. */ | |
607 | ||
608 | static int | |
609 | solib_aix_open_symbol_file_object (void *from_ttyp) | |
610 | { | |
611 | return 0; | |
612 | } | |
613 | ||
614 | /* Implement the "in_dynsym_resolve_code" target_so_ops method. */ | |
615 | ||
616 | static int | |
617 | solib_aix_in_dynsym_resolve_code (CORE_ADDR pc) | |
618 | { | |
619 | return 0; | |
620 | } | |
621 | ||
622 | /* Implement the "bfd_open" target_so_ops method. */ | |
623 | ||
624 | static bfd * | |
625 | solib_aix_bfd_open (char *pathname) | |
626 | { | |
627 | /* The pathname is actually a synthetic filename with the following | |
628 | form: "/path/to/sharedlib(member.o)" (double-quotes excluded). | |
629 | split this into archive name and member name. | |
630 | ||
631 | FIXME: This is a little hacky. Perhaps we should provide access | |
632 | to the solib's lm_info here? */ | |
633 | const int path_len = strlen (pathname); | |
634 | char *sep; | |
635 | char *filename; | |
636 | int filename_len; | |
637 | char *member_name; | |
638 | bfd *archive_bfd, *object_bfd; | |
639 | struct cleanup *cleanup = make_cleanup (null_cleanup, NULL); | |
640 | ||
641 | if (pathname[path_len - 1] != ')') | |
642 | return solib_bfd_open (pathname); | |
643 | ||
644 | /* Search for the associated parens. */ | |
645 | sep = strrchr (pathname, '('); | |
646 | if (sep == NULL) | |
647 | { | |
648 | /* Should never happen, but recover as best as we can (trying | |
649 | to open pathname without decoding, possibly leading to | |
650 | a failure), rather than triggering an assert failure). */ | |
651 | warning (_("missing '(' in shared object pathname: %s"), pathname); | |
652 | return solib_bfd_open (pathname); | |
653 | } | |
654 | filename_len = sep - pathname; | |
655 | ||
656 | filename = xstrprintf ("%.*s", filename_len, pathname); | |
657 | make_cleanup (xfree, filename); | |
658 | member_name = xstrprintf ("%.*s", path_len - filename_len - 2, sep + 1); | |
659 | make_cleanup (xfree, member_name); | |
660 | ||
661 | archive_bfd = gdb_bfd_open (filename, gnutarget, -1); | |
662 | if (archive_bfd == NULL) | |
663 | { | |
664 | warning (_("Could not open `%s' as an executable file: %s"), | |
665 | filename, bfd_errmsg (bfd_get_error ())); | |
666 | do_cleanups (cleanup); | |
667 | return NULL; | |
668 | } | |
669 | ||
670 | if (bfd_check_format (archive_bfd, bfd_object)) | |
671 | { | |
672 | do_cleanups (cleanup); | |
673 | return archive_bfd; | |
674 | } | |
675 | ||
676 | if (! bfd_check_format (archive_bfd, bfd_archive)) | |
677 | { | |
678 | warning (_("\"%s\": not in executable format: %s."), | |
679 | filename, bfd_errmsg (bfd_get_error ())); | |
680 | gdb_bfd_unref (archive_bfd); | |
681 | do_cleanups (cleanup); | |
682 | return NULL; | |
683 | } | |
684 | ||
685 | object_bfd = gdb_bfd_openr_next_archived_file (archive_bfd, NULL); | |
686 | while (object_bfd != NULL) | |
687 | { | |
688 | bfd *next; | |
689 | ||
690 | if (strcmp (member_name, object_bfd->filename) == 0) | |
691 | break; | |
692 | ||
693 | next = gdb_bfd_openr_next_archived_file (archive_bfd, object_bfd); | |
694 | gdb_bfd_unref (object_bfd); | |
695 | object_bfd = next; | |
696 | } | |
697 | ||
698 | if (object_bfd == NULL) | |
699 | { | |
700 | warning (_("\"%s\": member \"%s\" missing."), filename, member_name); | |
701 | gdb_bfd_unref (archive_bfd); | |
702 | do_cleanups (cleanup); | |
703 | return NULL; | |
704 | } | |
705 | ||
706 | if (! bfd_check_format (object_bfd, bfd_object)) | |
707 | { | |
708 | warning (_("%s(%s): not in object format: %s."), | |
709 | filename, member_name, bfd_errmsg (bfd_get_error ())); | |
710 | gdb_bfd_unref (archive_bfd); | |
711 | gdb_bfd_unref (object_bfd); | |
712 | do_cleanups (cleanup); | |
713 | return NULL; | |
714 | } | |
715 | ||
716 | gdb_bfd_unref (archive_bfd); | |
717 | do_cleanups (cleanup); | |
718 | return object_bfd; | |
719 | } | |
720 | ||
721 | /* Return the obj_section corresponding to OBJFILE's data section, | |
722 | or NULL if not found. */ | |
723 | /* FIXME: Define in a more general location? */ | |
724 | ||
725 | static struct obj_section * | |
726 | data_obj_section_from_objfile (struct objfile *objfile) | |
727 | { | |
728 | struct obj_section *osect; | |
729 | ||
730 | ALL_OBJFILE_OSECTIONS (objfile, osect) | |
731 | if (strcmp (bfd_section_name (objfile->obfd, osect->the_bfd_section), | |
732 | ".data") == 0) | |
733 | return osect; | |
734 | ||
735 | return NULL; | |
736 | } | |
737 | ||
738 | /* Return the TOC value corresponding to the given PC address, | |
739 | or raise an error if the value could not be determined. */ | |
740 | ||
741 | CORE_ADDR | |
742 | solib_aix_get_toc_value (CORE_ADDR pc) | |
743 | { | |
744 | struct obj_section *pc_osect = find_pc_section (pc); | |
745 | struct obj_section *data_osect; | |
746 | CORE_ADDR result; | |
747 | ||
748 | if (pc_osect == NULL) | |
749 | error (_("unable to find TOC entry for pc %s " | |
750 | "(no section contains this PC)"), | |
751 | core_addr_to_string (pc)); | |
752 | ||
753 | data_osect = data_obj_section_from_objfile (pc_osect->objfile); | |
754 | if (data_osect == NULL) | |
755 | error (_("unable to find TOC entry for pc %s " | |
756 | "(%s has no data section)"), | |
757 | core_addr_to_string (pc), pc_osect->objfile->name); | |
758 | ||
759 | result = (obj_section_addr (data_osect) | |
760 | + xcoff_get_toc_offset (pc_osect->objfile)); | |
761 | if (solib_aix_debug) | |
762 | fprintf_unfiltered (gdb_stdlog, | |
763 | "DEBUG: solib_aix_get_toc_value (pc=%s) -> %s\n", | |
764 | core_addr_to_string (pc), | |
765 | core_addr_to_string (result)); | |
766 | ||
767 | return result; | |
768 | } | |
769 | ||
770 | /* This module's normal_stop observer. */ | |
771 | ||
772 | static void | |
773 | solib_aix_normal_stop_observer (struct bpstats *unused_1, int unused_2) | |
774 | { | |
775 | struct solib_aix_inferior_data *data | |
776 | = get_solib_aix_inferior_data (current_inferior ()); | |
777 | ||
778 | /* The inferior execution has been resumed, and it just stopped | |
779 | again. This means that the list of shared libraries may have | |
780 | evolved. Reset our cached value. */ | |
781 | solib_aix_free_library_list (&data->library_list); | |
782 | } | |
783 | ||
784 | /* Implements the "show debug aix-solib" command. */ | |
785 | ||
786 | static void | |
787 | show_solib_aix_debug (struct ui_file *file, int from_tty, | |
788 | struct cmd_list_element *c, const char *value) | |
789 | { | |
790 | fprintf_filtered (file, _("solib-aix debugging is %s.\n"), value); | |
791 | } | |
792 | ||
793 | /* The target_so_ops for AIX targets. */ | |
794 | struct target_so_ops solib_aix_so_ops; | |
795 | ||
796 | /* -Wmissing-prototypes */ | |
797 | extern initialize_file_ftype _initialize_solib_aix; | |
798 | ||
799 | void | |
800 | _initialize_solib_aix (void) | |
801 | { | |
802 | solib_aix_so_ops.relocate_section_addresses | |
803 | = solib_aix_relocate_section_addresses; | |
804 | solib_aix_so_ops.free_so = solib_aix_free_so; | |
805 | solib_aix_so_ops.clear_solib = solib_aix_clear_solib; | |
806 | solib_aix_so_ops.solib_create_inferior_hook | |
807 | = solib_aix_solib_create_inferior_hook; | |
808 | solib_aix_so_ops.special_symbol_handling | |
809 | = solib_aix_special_symbol_handling; | |
810 | solib_aix_so_ops.current_sos = solib_aix_current_sos; | |
811 | solib_aix_so_ops.open_symbol_file_object | |
812 | = solib_aix_open_symbol_file_object; | |
813 | solib_aix_so_ops.in_dynsym_resolve_code | |
814 | = solib_aix_in_dynsym_resolve_code; | |
815 | solib_aix_so_ops.bfd_open = solib_aix_bfd_open; | |
816 | ||
817 | solib_aix_inferior_data_handle = register_inferior_data (); | |
818 | ||
819 | observer_attach_normal_stop (solib_aix_normal_stop_observer); | |
820 | ||
821 | /* Debug this file's internals. */ | |
822 | add_setshow_boolean_cmd ("aix-solib", class_maintenance, | |
823 | &solib_aix_debug, _("\ | |
824 | Control the debugging traces for the solib-aix module."), _("\ | |
825 | Show whether solib-aix debugging traces are enabled."), _("\ | |
826 | When on, solib-aix debugging traces are enabled."), | |
827 | NULL, | |
828 | show_solib_aix_debug, | |
829 | &setdebuglist, &showdebuglist); | |
830 | } |