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