]>
Commit | Line | Data |
---|---|---|
1d506c26 | 1 | /* Copyright (C) 2013-2024 Free Software Foundation, Inc. |
4d1eb6b4 JB |
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" | |
e26d0dab | 20 | #include "solib.h" |
4d1eb6b4 JB |
21 | #include "solist.h" |
22 | #include "inferior.h" | |
23 | #include "gdb_bfd.h" | |
4d1eb6b4 JB |
24 | #include "objfiles.h" |
25 | #include "symtab.h" | |
26 | #include "xcoffread.h" | |
76727919 | 27 | #include "observable.h" |
4d1eb6b4 | 28 | |
3fe0dfd1 | 29 | /* Our private data in struct shobj. */ |
4d1eb6b4 | 30 | |
e3b63a79 | 31 | struct lm_info_aix final : public lm_info |
4d1eb6b4 JB |
32 | { |
33 | /* The name of the file mapped by the loader. Apart from the entry | |
34 | for the main executable, this is usually a shared library (which, | |
35 | on AIX, is an archive library file, created using the "ar" | |
36 | command). */ | |
6c401f72 | 37 | std::string filename; |
4d1eb6b4 JB |
38 | |
39 | /* The name of the shared object file with the actual dynamic | |
6c401f72 SM |
40 | loading dependency. This may be empty (Eg. main executable). */ |
41 | std::string member_name; | |
4d1eb6b4 JB |
42 | |
43 | /* The address in inferior memory where the text section got mapped. */ | |
6c401f72 | 44 | CORE_ADDR text_addr = 0; |
4d1eb6b4 JB |
45 | |
46 | /* The size of the text section, obtained via the loader data. */ | |
6c401f72 | 47 | ULONGEST text_size = 0; |
4d1eb6b4 JB |
48 | |
49 | /* The address in inferior memory where the data section got mapped. */ | |
6c401f72 | 50 | CORE_ADDR data_addr = 0; |
4d1eb6b4 JB |
51 | |
52 | /* The size of the data section, obtained via the loader data. */ | |
6c401f72 | 53 | ULONGEST data_size = 0; |
4d1eb6b4 JB |
54 | }; |
55 | ||
4d1eb6b4 JB |
56 | /* This module's per-inferior data. */ |
57 | ||
58 | struct solib_aix_inferior_data | |
59 | { | |
a269fbf1 | 60 | /* The list of shared libraries. |
4d1eb6b4 JB |
61 | |
62 | Note that the first element of this list is always the main | |
63 | executable, which is not technically a shared library. But | |
64 | we need that information to perform its relocation, and | |
65 | the same principles applied to shared libraries also apply | |
66 | to the main executable. So it's simpler to keep it as part | |
67 | of this list. */ | |
6b09f134 | 68 | std::optional<std::vector<lm_info_aix>> library_list; |
4d1eb6b4 JB |
69 | }; |
70 | ||
71 | /* Key to our per-inferior data. */ | |
08b8a139 TT |
72 | static const registry<inferior>::key<solib_aix_inferior_data> |
73 | solib_aix_inferior_data_handle; | |
4d1eb6b4 JB |
74 | |
75 | /* Return this module's data for the given inferior. | |
76 | If none is found, add a zero'ed one now. */ | |
77 | ||
78 | static struct solib_aix_inferior_data * | |
79 | get_solib_aix_inferior_data (struct inferior *inf) | |
80 | { | |
81 | struct solib_aix_inferior_data *data; | |
82 | ||
a269fbf1 | 83 | data = solib_aix_inferior_data_handle.get (inf); |
4d1eb6b4 | 84 | if (data == NULL) |
a269fbf1 | 85 | data = solib_aix_inferior_data_handle.emplace (inf); |
4d1eb6b4 JB |
86 | |
87 | return data; | |
88 | } | |
89 | ||
90 | #if !defined(HAVE_LIBEXPAT) | |
91 | ||
92 | /* Dummy implementation if XML support is not compiled in. */ | |
93 | ||
6b09f134 | 94 | static std::optional<std::vector<lm_info_aix>> |
4d1eb6b4 JB |
95 | solib_aix_parse_libraries (const char *library) |
96 | { | |
97 | static int have_warned; | |
98 | ||
99 | if (!have_warned) | |
100 | { | |
101 | have_warned = 1; | |
102 | warning (_("Can not parse XML library list; XML support was disabled " | |
dda83cd7 | 103 | "at compile time")); |
4d1eb6b4 JB |
104 | } |
105 | ||
a269fbf1 | 106 | return {}; |
814a3ff7 JB |
107 | } |
108 | ||
4d1eb6b4 JB |
109 | #else /* HAVE_LIBEXPAT */ |
110 | ||
111 | #include "xml-support.h" | |
112 | ||
113 | /* Handle the start of a <library> element. */ | |
114 | ||
115 | static void | |
116 | library_list_start_library (struct gdb_xml_parser *parser, | |
117 | const struct gdb_xml_element *element, | |
118 | void *user_data, | |
4d0fdd9b | 119 | std::vector<gdb_xml_value> &attributes) |
4d1eb6b4 | 120 | { |
a269fbf1 TT |
121 | std::vector<lm_info_aix> *list = (std::vector<lm_info_aix> *) user_data; |
122 | lm_info_aix item; | |
4d1eb6b4 JB |
123 | struct gdb_xml_value *attr; |
124 | ||
125 | attr = xml_find_attribute (attributes, "name"); | |
a269fbf1 | 126 | item.filename = (const char *) attr->value.get (); |
4d1eb6b4 JB |
127 | |
128 | attr = xml_find_attribute (attributes, "member"); | |
129 | if (attr != NULL) | |
a269fbf1 | 130 | item.member_name = (const char *) attr->value.get (); |
4d1eb6b4 JB |
131 | |
132 | attr = xml_find_attribute (attributes, "text_addr"); | |
a269fbf1 | 133 | item.text_addr = * (ULONGEST *) attr->value.get (); |
4d1eb6b4 JB |
134 | |
135 | attr = xml_find_attribute (attributes, "text_size"); | |
a269fbf1 | 136 | item.text_size = * (ULONGEST *) attr->value.get (); |
4d1eb6b4 JB |
137 | |
138 | attr = xml_find_attribute (attributes, "data_addr"); | |
a269fbf1 | 139 | item.data_addr = * (ULONGEST *) attr->value.get (); |
4d1eb6b4 JB |
140 | |
141 | attr = xml_find_attribute (attributes, "data_size"); | |
a269fbf1 | 142 | item.data_size = * (ULONGEST *) attr->value.get (); |
4d1eb6b4 | 143 | |
a269fbf1 | 144 | list->push_back (std::move (item)); |
4d1eb6b4 JB |
145 | } |
146 | ||
8c56e112 | 147 | /* Handle the start of a <library-list-aix> element. */ |
4d1eb6b4 JB |
148 | |
149 | static void | |
150 | library_list_start_list (struct gdb_xml_parser *parser, | |
dda83cd7 SM |
151 | const struct gdb_xml_element *element, |
152 | void *user_data, | |
4d0fdd9b | 153 | std::vector<gdb_xml_value> &attributes) |
4d1eb6b4 | 154 | { |
4d0fdd9b SM |
155 | char *version |
156 | = (char *) xml_find_attribute (attributes, "version")->value.get (); | |
4d1eb6b4 JB |
157 | |
158 | if (strcmp (version, "1.0") != 0) | |
159 | gdb_xml_error (parser, | |
dda83cd7 SM |
160 | _("Library list has unsupported version \"%s\""), |
161 | version); | |
4d1eb6b4 JB |
162 | } |
163 | ||
4d1eb6b4 | 164 | /* The allowed elements and attributes for an AIX library list |
8c56e112 | 165 | described in XML format. The root element is a <library-list-aix>. */ |
4d1eb6b4 JB |
166 | |
167 | static const struct gdb_xml_attribute library_attributes[] = | |
168 | { | |
169 | { "name", GDB_XML_AF_NONE, NULL, NULL }, | |
170 | { "member", GDB_XML_AF_OPTIONAL, NULL, NULL }, | |
171 | { "text_addr", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, | |
172 | { "text_size", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, | |
173 | { "data_addr", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, | |
174 | { "data_size", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, | |
175 | { NULL, GDB_XML_AF_NONE, NULL, NULL } | |
176 | }; | |
177 | ||
178 | static const struct gdb_xml_element library_list_children[] = | |
179 | { | |
180 | { "library", library_attributes, NULL, | |
181 | GDB_XML_EF_REPEATABLE | GDB_XML_EF_OPTIONAL, | |
182 | library_list_start_library, NULL}, | |
183 | { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL } | |
184 | }; | |
185 | ||
186 | static const struct gdb_xml_attribute library_list_attributes[] = | |
187 | { | |
188 | { "version", GDB_XML_AF_NONE, NULL, NULL }, | |
189 | { NULL, GDB_XML_AF_NONE, NULL, NULL } | |
190 | }; | |
191 | ||
192 | static const struct gdb_xml_element library_list_elements[] = | |
193 | { | |
8c56e112 | 194 | { "library-list-aix", library_list_attributes, library_list_children, |
4d1eb6b4 JB |
195 | GDB_XML_EF_NONE, library_list_start_list, NULL }, |
196 | { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL } | |
197 | }; | |
198 | ||
199 | /* Parse LIBRARY, a string containing the loader info in XML format, | |
a269fbf1 | 200 | and return a vector of lm_info_aix objects. |
4d1eb6b4 | 201 | |
a269fbf1 | 202 | Return an empty option if the parsing failed. */ |
4d1eb6b4 | 203 | |
6b09f134 | 204 | static std::optional<std::vector<lm_info_aix>> |
4d1eb6b4 JB |
205 | solib_aix_parse_libraries (const char *library) |
206 | { | |
a269fbf1 | 207 | std::vector<lm_info_aix> result; |
4d1eb6b4 JB |
208 | |
209 | if (gdb_xml_parse_quick (_("aix library list"), "library-list-aix.dtd", | |
a269fbf1 TT |
210 | library_list_elements, library, &result) == 0) |
211 | return result; | |
4d1eb6b4 | 212 | |
a269fbf1 | 213 | return {}; |
4d1eb6b4 JB |
214 | } |
215 | ||
216 | #endif /* HAVE_LIBEXPAT */ | |
217 | ||
a269fbf1 TT |
218 | /* Return the loader info for the given inferior (INF), or an empty |
219 | option if the list could not be computed. | |
4d1eb6b4 JB |
220 | |
221 | Cache the result in per-inferior data, so as to avoid recomputing it | |
222 | each time this function is called. | |
223 | ||
224 | If an error occurs while computing this list, and WARNING_MSG | |
225 | is not NULL, then print a warning including WARNING_MSG and | |
226 | a description of the error. */ | |
227 | ||
6b09f134 | 228 | static std::optional<std::vector<lm_info_aix>> & |
4d1eb6b4 JB |
229 | solib_aix_get_library_list (struct inferior *inf, const char *warning_msg) |
230 | { | |
231 | struct solib_aix_inferior_data *data; | |
4d1eb6b4 JB |
232 | |
233 | /* If already computed, return the cached value. */ | |
234 | data = get_solib_aix_inferior_data (inf); | |
a269fbf1 | 235 | if (data->library_list.has_value ()) |
4d1eb6b4 JB |
236 | return data->library_list; |
237 | ||
6b09f134 | 238 | std::optional<gdb::char_vector> library_document |
328d42d8 SM |
239 | = target_read_stralloc (current_inferior ()->top_target (), |
240 | TARGET_OBJECT_LIBRARIES_AIX, | |
b7b030ad | 241 | NULL); |
9018be22 | 242 | if (!library_document && warning_msg != NULL) |
4d1eb6b4 | 243 | { |
ff99b71b | 244 | warning (_("%s (failed to read TARGET_OBJECT_LIBRARIES_AIX)"), |
4d1eb6b4 | 245 | warning_msg); |
a269fbf1 | 246 | return data->library_list; |
4d1eb6b4 | 247 | } |
4d1eb6b4 | 248 | |
e26d0dab SM |
249 | solib_debug_printf ("TARGET_OBJECT_LIBRARIES_AIX = %s", |
250 | library_document->data ()); | |
4d1eb6b4 | 251 | |
9018be22 | 252 | data->library_list = solib_aix_parse_libraries (library_document->data ()); |
a269fbf1 TT |
253 | if (!data->library_list.has_value () && warning_msg != NULL) |
254 | warning (_("%s (missing XML support?)"), warning_msg); | |
4d1eb6b4 | 255 | |
4d1eb6b4 JB |
256 | return data->library_list; |
257 | } | |
258 | ||
259 | /* If the .bss section's VMA is set to an address located before | |
260 | the end of the .data section, causing the two sections to overlap, | |
261 | return the overlap in bytes. Otherwise, return zero. | |
262 | ||
263 | Motivation: | |
264 | ||
265 | The GNU linker sometimes sets the start address of the .bss session | |
266 | before the end of the .data section, making the 2 sections overlap. | |
267 | The loader appears to handle this situation gracefully, by simply | |
268 | loading the bss section right after the end of the .data section. | |
269 | ||
270 | This means that the .data and the .bss sections are sometimes | |
271 | no longer relocated by the same amount. The problem is that | |
272 | the ldinfo data does not contain any information regarding | |
273 | the relocation of the .bss section, assuming that it would be | |
274 | identical to the information provided for the .data section | |
275 | (this is what would normally happen if the program was linked | |
276 | correctly). | |
277 | ||
278 | GDB therefore needs to detect those cases, and make the corresponding | |
279 | adjustment to the .bss section offset computed from the ldinfo data | |
280 | when necessary. This function returns the adjustment amount (or | |
281 | zero when no adjustment is needed). */ | |
282 | ||
283 | static CORE_ADDR | |
284 | solib_aix_bss_data_overlap (bfd *abfd) | |
285 | { | |
286 | struct bfd_section *data_sect, *bss_sect; | |
287 | ||
288 | data_sect = bfd_get_section_by_name (abfd, ".data"); | |
289 | if (data_sect == NULL) | |
290 | return 0; /* No overlap possible. */ | |
291 | ||
292 | bss_sect = bfd_get_section_by_name (abfd, ".bss"); | |
293 | if (bss_sect == NULL) | |
294 | return 0; /* No overlap possible. */ | |
295 | ||
296 | /* Assume the problem only occurs with linkers that place the .bss | |
297 | section after the .data section (the problem has only been | |
298 | observed when using the GNU linker, and the default linker | |
299 | script always places the .data and .bss sections in that order). */ | |
fd361982 | 300 | if (bfd_section_vma (bss_sect) < bfd_section_vma (data_sect)) |
4d1eb6b4 JB |
301 | return 0; |
302 | ||
fd361982 AM |
303 | if (bfd_section_vma (bss_sect) |
304 | < bfd_section_vma (data_sect) + bfd_section_size (data_sect)) | |
305 | return (bfd_section_vma (data_sect) + bfd_section_size (data_sect) | |
306 | - bfd_section_vma (bss_sect)); | |
4d1eb6b4 JB |
307 | |
308 | return 0; | |
309 | } | |
310 | ||
311 | /* Implement the "relocate_section_addresses" target_so_ops method. */ | |
312 | ||
313 | static void | |
3fe0dfd1 | 314 | solib_aix_relocate_section_addresses (shobj &so, target_section *sec) |
4d1eb6b4 | 315 | { |
4d1eb6b4 | 316 | struct bfd_section *bfd_sect = sec->the_bfd_section; |
57e6060e | 317 | bfd *abfd = bfd_sect->owner; |
fd361982 | 318 | const char *section_name = bfd_section_name (bfd_sect); |
7ad0a42e | 319 | auto *info = gdb::checked_static_cast<lm_info_aix *> (so.lm_info.get ()); |
4d1eb6b4 JB |
320 | |
321 | if (strcmp (section_name, ".text") == 0) | |
322 | { | |
323 | sec->addr = info->text_addr; | |
324 | sec->endaddr = sec->addr + info->text_size; | |
325 | ||
326 | /* The text address given to us by the loader contains | |
327 | XCOFF headers, so we need to adjust by this much. */ | |
328 | sec->addr += bfd_sect->filepos; | |
329 | } | |
330 | else if (strcmp (section_name, ".data") == 0) | |
331 | { | |
332 | sec->addr = info->data_addr; | |
333 | sec->endaddr = sec->addr + info->data_size; | |
334 | } | |
335 | else if (strcmp (section_name, ".bss") == 0) | |
336 | { | |
060cfbef JB |
337 | /* The information provided by the loader does not include |
338 | the address of the .bss section, but we know that it gets | |
339 | relocated by the same offset as the .data section. So, | |
340 | compute the relocation offset for the .data section, and | |
341 | apply it to the .bss section as well. If the .data section | |
342 | is not defined (which seems highly unlikely), do our best | |
343 | by assuming no relocation. */ | |
344 | struct bfd_section *data_sect | |
345 | = bfd_get_section_by_name (abfd, ".data"); | |
346 | CORE_ADDR data_offset = 0; | |
347 | ||
348 | if (data_sect != NULL) | |
fd361982 | 349 | data_offset = info->data_addr - bfd_section_vma (data_sect); |
060cfbef | 350 | |
fd361982 | 351 | sec->addr = bfd_section_vma (bfd_sect) + data_offset; |
4d1eb6b4 | 352 | sec->addr += solib_aix_bss_data_overlap (abfd); |
fd361982 | 353 | sec->endaddr = sec->addr + bfd_section_size (bfd_sect); |
4d1eb6b4 JB |
354 | } |
355 | else | |
356 | { | |
357 | /* All other sections should not be relocated. */ | |
fd361982 AM |
358 | sec->addr = bfd_section_vma (bfd_sect); |
359 | sec->endaddr = sec->addr + bfd_section_size (bfd_sect); | |
4d1eb6b4 JB |
360 | } |
361 | } | |
362 | ||
4d1eb6b4 | 363 | /* Compute and return the OBJFILE's section_offset array, using |
6a053cb1 | 364 | the associated loader info (INFO). */ |
4d1eb6b4 | 365 | |
6a053cb1 | 366 | static section_offsets |
4d1eb6b4 | 367 | solib_aix_get_section_offsets (struct objfile *objfile, |
d0e449a1 | 368 | lm_info_aix *info) |
4d1eb6b4 | 369 | { |
98badbfd | 370 | bfd *abfd = objfile->obfd.get (); |
4d1eb6b4 | 371 | |
6a053cb1 | 372 | section_offsets offsets (objfile->section_offsets.size ()); |
4d1eb6b4 JB |
373 | |
374 | /* .text */ | |
375 | ||
376 | if (objfile->sect_index_text != -1) | |
377 | { | |
378 | struct bfd_section *sect | |
9ed8433a | 379 | = objfile->sections_start[objfile->sect_index_text].the_bfd_section; |
4d1eb6b4 | 380 | |
6a053cb1 | 381 | offsets[objfile->sect_index_text] |
fd361982 | 382 | = info->text_addr + sect->filepos - bfd_section_vma (sect); |
4d1eb6b4 JB |
383 | } |
384 | ||
385 | /* .data */ | |
386 | ||
387 | if (objfile->sect_index_data != -1) | |
388 | { | |
389 | struct bfd_section *sect | |
9ed8433a | 390 | = objfile->sections_start[objfile->sect_index_data].the_bfd_section; |
4d1eb6b4 | 391 | |
6a053cb1 | 392 | offsets[objfile->sect_index_data] |
fd361982 | 393 | = info->data_addr - bfd_section_vma (sect); |
4d1eb6b4 JB |
394 | } |
395 | ||
396 | /* .bss | |
397 | ||
398 | The offset of the .bss section should be identical to the offset | |
399 | of the .data section. If no .data section (which seems hard to | |
400 | believe it is possible), assume it is zero. */ | |
401 | ||
402 | if (objfile->sect_index_bss != -1 | |
403 | && objfile->sect_index_data != -1) | |
404 | { | |
6a053cb1 TT |
405 | offsets[objfile->sect_index_bss] |
406 | = (offsets[objfile->sect_index_data] | |
4d1eb6b4 JB |
407 | + solib_aix_bss_data_overlap (abfd)); |
408 | } | |
409 | ||
410 | /* All other sections should not need relocation. */ | |
411 | ||
412 | return offsets; | |
413 | } | |
414 | ||
415 | /* Implement the "solib_create_inferior_hook" target_so_ops method. */ | |
416 | ||
417 | static void | |
418 | solib_aix_solib_create_inferior_hook (int from_tty) | |
419 | { | |
420 | const char *warning_msg = "unable to relocate main executable"; | |
4d1eb6b4 JB |
421 | |
422 | /* We need to relocate the main executable... */ | |
423 | ||
6b09f134 | 424 | std::optional<std::vector<lm_info_aix>> &library_list |
a269fbf1 TT |
425 | = solib_aix_get_library_list (current_inferior (), warning_msg); |
426 | if (!library_list.has_value ()) | |
4d1eb6b4 JB |
427 | return; /* Warning already printed. */ |
428 | ||
a269fbf1 | 429 | if (library_list->empty ()) |
4d1eb6b4 JB |
430 | { |
431 | warning (_("unable to relocate main executable (no info from loader)")); | |
432 | return; | |
433 | } | |
434 | ||
a269fbf1 | 435 | lm_info_aix &exec_info = (*library_list)[0]; |
a42d7dd8 | 436 | if (current_program_space->symfile_object_file != NULL) |
4d1eb6b4 | 437 | { |
a42d7dd8 TT |
438 | objfile *objf = current_program_space->symfile_object_file; |
439 | section_offsets offsets = solib_aix_get_section_offsets (objf, | |
440 | &exec_info); | |
4d1eb6b4 | 441 | |
a42d7dd8 | 442 | objfile_relocate (objf, offsets); |
4d1eb6b4 JB |
443 | } |
444 | } | |
445 | ||
4d1eb6b4 JB |
446 | /* Implement the "current_sos" target_so_ops method. */ |
447 | ||
3fe0dfd1 | 448 | static intrusive_list<shobj> |
8971d278 | 449 | solib_aix_current_sos () |
4d1eb6b4 | 450 | { |
6b09f134 | 451 | std::optional<std::vector<lm_info_aix>> &library_list |
a269fbf1 TT |
452 | = solib_aix_get_library_list (current_inferior (), NULL); |
453 | if (!library_list.has_value ()) | |
8971d278 SM |
454 | return {}; |
455 | ||
3fe0dfd1 | 456 | intrusive_list<shobj> sos; |
4d1eb6b4 | 457 | |
3fe0dfd1 | 458 | /* Build a struct shobj for each entry on the list. |
4d1eb6b4 JB |
459 | We skip the first entry, since this is the entry corresponding |
460 | to the main executable, not a shared library. */ | |
8971d278 | 461 | for (int ix = 1; ix < library_list->size (); ix++) |
4d1eb6b4 | 462 | { |
3fe0dfd1 | 463 | shobj *new_solib = new shobj; |
6c401f72 | 464 | std::string so_name; |
4d1eb6b4 | 465 | |
a269fbf1 TT |
466 | lm_info_aix &info = (*library_list)[ix]; |
467 | if (info.member_name.empty ()) | |
4d1eb6b4 | 468 | { |
a269fbf1 | 469 | /* INFO.FILENAME is probably not an archive, but rather |
4d1eb6b4 JB |
470 | a shared object. Unusual, but it should be possible |
471 | to link a program against a shared object directory, | |
472 | without having to put it in an archive first. */ | |
a269fbf1 | 473 | so_name = info.filename; |
4d1eb6b4 JB |
474 | } |
475 | else | |
476 | { | |
477 | /* This is the usual case on AIX, where the shared object | |
478 | is a member of an archive. Create a synthetic so_name | |
479 | that follows the same convention as AIX's ldd tool | |
480 | (Eg: "/lib/libc.a(shr.o)"). */ | |
a269fbf1 TT |
481 | so_name = string_printf ("%s(%s)", info.filename.c_str (), |
482 | info.member_name.c_str ()); | |
4d1eb6b4 | 483 | } |
98107b0b SM |
484 | |
485 | new_solib->so_original_name = so_name; | |
486 | new_solib->so_name = so_name; | |
6b62451a | 487 | new_solib->lm_info = std::make_unique<lm_info_aix> (info); |
4d1eb6b4 JB |
488 | |
489 | /* Add it to the list. */ | |
8971d278 | 490 | sos.push_back (*new_solib); |
4d1eb6b4 JB |
491 | } |
492 | ||
8971d278 | 493 | return sos; |
4d1eb6b4 JB |
494 | } |
495 | ||
496 | /* Implement the "open_symbol_file_object" target_so_ops method. */ | |
497 | ||
498 | static int | |
bf469271 | 499 | solib_aix_open_symbol_file_object (int from_tty) |
4d1eb6b4 JB |
500 | { |
501 | return 0; | |
502 | } | |
503 | ||
504 | /* Implement the "in_dynsym_resolve_code" target_so_ops method. */ | |
505 | ||
506 | static int | |
507 | solib_aix_in_dynsym_resolve_code (CORE_ADDR pc) | |
508 | { | |
509 | return 0; | |
510 | } | |
511 | ||
512 | /* Implement the "bfd_open" target_so_ops method. */ | |
513 | ||
192b62ce | 514 | static gdb_bfd_ref_ptr |
692d6f97 | 515 | solib_aix_bfd_open (const char *pathname) |
4d1eb6b4 JB |
516 | { |
517 | /* The pathname is actually a synthetic filename with the following | |
518 | form: "/path/to/sharedlib(member.o)" (double-quotes excluded). | |
519 | split this into archive name and member name. | |
520 | ||
521 | FIXME: This is a little hacky. Perhaps we should provide access | |
522 | to the solib's lm_info here? */ | |
523 | const int path_len = strlen (pathname); | |
692d6f97 | 524 | const char *sep; |
4d1eb6b4 | 525 | int filename_len; |
754c39c2 | 526 | int found_file; |
4d1eb6b4 JB |
527 | |
528 | if (pathname[path_len - 1] != ')') | |
529 | return solib_bfd_open (pathname); | |
530 | ||
531 | /* Search for the associated parens. */ | |
532 | sep = strrchr (pathname, '('); | |
533 | if (sep == NULL) | |
534 | { | |
535 | /* Should never happen, but recover as best as we can (trying | |
536 | to open pathname without decoding, possibly leading to | |
537 | a failure), rather than triggering an assert failure). */ | |
538 | warning (_("missing '(' in shared object pathname: %s"), pathname); | |
539 | return solib_bfd_open (pathname); | |
540 | } | |
541 | filename_len = sep - pathname; | |
542 | ||
192b62ce TT |
543 | std::string filename (string_printf ("%.*s", filename_len, pathname)); |
544 | std::string member_name (string_printf ("%.*s", path_len - filename_len - 2, | |
545 | sep + 1)); | |
4d1eb6b4 | 546 | |
754c39c2 UW |
547 | /* Calling solib_find makes certain that sysroot path is set properly |
548 | if program has a dependency on .a archive and sysroot is set via | |
549 | set sysroot command. */ | |
797bc1cb TT |
550 | gdb::unique_xmalloc_ptr<char> found_pathname |
551 | = solib_find (filename.c_str (), &found_file); | |
754c39c2 UW |
552 | if (found_pathname == NULL) |
553 | perror_with_name (pathname); | |
797bc1cb TT |
554 | gdb_bfd_ref_ptr archive_bfd (solib_bfd_fopen (found_pathname.get (), |
555 | found_file)); | |
4d1eb6b4 JB |
556 | if (archive_bfd == NULL) |
557 | { | |
558 | warning (_("Could not open `%s' as an executable file: %s"), | |
192b62ce | 559 | filename.c_str (), bfd_errmsg (bfd_get_error ())); |
4d1eb6b4 JB |
560 | return NULL; |
561 | } | |
562 | ||
192b62ce TT |
563 | if (bfd_check_format (archive_bfd.get (), bfd_object)) |
564 | return archive_bfd; | |
4d1eb6b4 | 565 | |
192b62ce | 566 | if (! bfd_check_format (archive_bfd.get (), bfd_archive)) |
4d1eb6b4 JB |
567 | { |
568 | warning (_("\"%s\": not in executable format: %s."), | |
192b62ce | 569 | filename.c_str (), bfd_errmsg (bfd_get_error ())); |
4d1eb6b4 JB |
570 | return NULL; |
571 | } | |
572 | ||
192b62ce TT |
573 | gdb_bfd_ref_ptr object_bfd |
574 | (gdb_bfd_openr_next_archived_file (archive_bfd.get (), NULL)); | |
4d1eb6b4 JB |
575 | while (object_bfd != NULL) |
576 | { | |
c7e97679 | 577 | if (member_name == bfd_get_filename (object_bfd.get ())) |
4d1eb6b4 JB |
578 | break; |
579 | ||
7a2a5ff8 AVK |
580 | std::string s = bfd_get_filename (object_bfd.get ()); |
581 | ||
582 | /* For every inferior after first int bfd system we | |
583 | will have the pathname instead of the member name | |
584 | registered. Hence the below condition exists. */ | |
585 | ||
586 | if (s.find ('(') != std::string::npos) | |
587 | { | |
588 | int pos = s.find ('('); | |
589 | int len = s.find (')') - s.find ('('); | |
590 | if (s.substr (pos+1, len-1) == member_name) | |
591 | return object_bfd; | |
592 | } | |
593 | ||
192b62ce TT |
594 | object_bfd = gdb_bfd_openr_next_archived_file (archive_bfd.get (), |
595 | object_bfd.get ()); | |
4d1eb6b4 JB |
596 | } |
597 | ||
598 | if (object_bfd == NULL) | |
599 | { | |
192b62ce TT |
600 | warning (_("\"%s\": member \"%s\" missing."), filename.c_str (), |
601 | member_name.c_str ()); | |
4d1eb6b4 JB |
602 | return NULL; |
603 | } | |
604 | ||
192b62ce | 605 | if (! bfd_check_format (object_bfd.get (), bfd_object)) |
4d1eb6b4 JB |
606 | { |
607 | warning (_("%s(%s): not in object format: %s."), | |
192b62ce TT |
608 | filename.c_str (), member_name.c_str (), |
609 | bfd_errmsg (bfd_get_error ())); | |
4d1eb6b4 JB |
610 | return NULL; |
611 | } | |
612 | ||
754c39c2 UW |
613 | /* Override the returned bfd's name with the name returned from solib_find |
614 | along with appended parenthesized member name in order to allow commands | |
615 | listing all shared libraries to display. Otherwise, we would only be | |
616 | displaying the name of the archive member object. */ | |
7b958a48 AM |
617 | std::string fname = string_printf ("%s%s", |
618 | bfd_get_filename (archive_bfd.get ()), | |
619 | sep); | |
620 | bfd_set_filename (object_bfd.get (), fname.c_str ()); | |
b030cf11 | 621 | |
4d1eb6b4 JB |
622 | return object_bfd; |
623 | } | |
624 | ||
625 | /* Return the obj_section corresponding to OBJFILE's data section, | |
626 | or NULL if not found. */ | |
627 | /* FIXME: Define in a more general location? */ | |
628 | ||
629 | static struct obj_section * | |
630 | data_obj_section_from_objfile (struct objfile *objfile) | |
631 | { | |
5250cbc8 | 632 | for (obj_section *osect : objfile->sections ()) |
fd361982 | 633 | if (strcmp (bfd_section_name (osect->the_bfd_section), ".data") == 0) |
4d1eb6b4 JB |
634 | return osect; |
635 | ||
636 | return NULL; | |
637 | } | |
638 | ||
639 | /* Return the TOC value corresponding to the given PC address, | |
640 | or raise an error if the value could not be determined. */ | |
641 | ||
642 | CORE_ADDR | |
643 | solib_aix_get_toc_value (CORE_ADDR pc) | |
644 | { | |
645 | struct obj_section *pc_osect = find_pc_section (pc); | |
646 | struct obj_section *data_osect; | |
647 | CORE_ADDR result; | |
648 | ||
649 | if (pc_osect == NULL) | |
650 | error (_("unable to find TOC entry for pc %s " | |
651 | "(no section contains this PC)"), | |
652 | core_addr_to_string (pc)); | |
653 | ||
654 | data_osect = data_obj_section_from_objfile (pc_osect->objfile); | |
655 | if (data_osect == NULL) | |
656 | error (_("unable to find TOC entry for pc %s " | |
657 | "(%s has no data section)"), | |
4262abfb | 658 | core_addr_to_string (pc), objfile_name (pc_osect->objfile)); |
4d1eb6b4 | 659 | |
0c1bcd23 | 660 | result = data_osect->addr () + xcoff_get_toc_offset (pc_osect->objfile); |
eef401dc | 661 | |
e26d0dab SM |
662 | solib_debug_printf ("pc=%s -> %s", core_addr_to_string (pc), |
663 | core_addr_to_string (result)); | |
4d1eb6b4 JB |
664 | |
665 | return result; | |
666 | } | |
667 | ||
668 | /* This module's normal_stop observer. */ | |
669 | ||
670 | static void | |
313f3b21 | 671 | solib_aix_normal_stop_observer (struct bpstat *unused_1, int unused_2) |
4d1eb6b4 JB |
672 | { |
673 | struct solib_aix_inferior_data *data | |
674 | = get_solib_aix_inferior_data (current_inferior ()); | |
675 | ||
676 | /* The inferior execution has been resumed, and it just stopped | |
677 | again. This means that the list of shared libraries may have | |
678 | evolved. Reset our cached value. */ | |
a269fbf1 | 679 | data->library_list.reset (); |
4d1eb6b4 JB |
680 | } |
681 | ||
4d1eb6b4 | 682 | /* The target_so_ops for AIX targets. */ |
549dfc51 TT |
683 | const struct target_so_ops solib_aix_so_ops = |
684 | { | |
685 | solib_aix_relocate_section_addresses, | |
549dfc51 | 686 | nullptr, |
6fe4d5bf | 687 | nullptr, |
549dfc51 TT |
688 | solib_aix_solib_create_inferior_hook, |
689 | solib_aix_current_sos, | |
690 | solib_aix_open_symbol_file_object, | |
691 | solib_aix_in_dynsym_resolve_code, | |
692 | solib_aix_bfd_open, | |
693 | }; | |
4d1eb6b4 | 694 | |
6c265988 | 695 | void _initialize_solib_aix (); |
4d1eb6b4 | 696 | void |
6c265988 | 697 | _initialize_solib_aix () |
4d1eb6b4 | 698 | { |
c90e7d63 SM |
699 | gdb::observers::normal_stop.attach (solib_aix_normal_stop_observer, |
700 | "solib-aix"); | |
4d1eb6b4 | 701 | } |