1 /* Copyright (C) 2013-2016 Free Software Foundation, Inc.
3 This file is part of GDB.
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.
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.
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/>. */
19 #include "solib-aix.h"
26 #include "xcoffread.h"
30 /* Variable controlling the output of the debugging traces for
32 static int solib_aix_debug;
34 /* Our private data in struct so_list. */
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"
44 /* The name of the shared object file with the actual dynamic
45 loading dependency. This may be NULL (Eg. main executable). */
48 /* The address in inferior memory where the text section got mapped. */
51 /* The size of the text section, obtained via the loader data. */
54 /* The address in inferior memory where the data section got mapped. */
57 /* The size of the data section, obtained via the loader data. */
61 typedef struct lm_info *lm_info_p;
64 /* Return a deep copy of the given struct lm_info object. */
66 static struct lm_info *
67 solib_aix_new_lm_info (struct lm_info *info)
69 struct lm_info *result = XNEW (struct lm_info);
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);
79 /* Free the memory allocated for the given lm_info. */
82 solib_aix_xfree_lm_info (struct lm_info *info)
84 xfree (info->filename);
85 xfree (info->member_name);
89 /* This module's per-inferior data. */
91 struct solib_aix_inferior_data
93 /* The list of shared libraries. NULL if not computed yet.
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
101 VEC (lm_info_p) *library_list;
104 /* Key to our per-inferior data. */
105 static const struct inferior_data *solib_aix_inferior_data_handle;
107 /* Return this module's data for the given inferior.
108 If none is found, add a zero'ed one now. */
110 static struct solib_aix_inferior_data *
111 get_solib_aix_inferior_data (struct inferior *inf)
113 struct solib_aix_inferior_data *data;
115 data = ((struct solib_aix_inferior_data *)
116 inferior_data (inf, solib_aix_inferior_data_handle));
119 data = XCNEW (struct solib_aix_inferior_data);
120 set_inferior_data (inf, solib_aix_inferior_data_handle, data);
126 #if !defined(HAVE_LIBEXPAT)
128 /* Dummy implementation if XML support is not compiled in. */
130 static VEC (lm_info_p) *
131 solib_aix_parse_libraries (const char *library)
133 static int have_warned;
138 warning (_("Can not parse XML library list; XML support was disabled "
145 /* Dummy implementation if XML support is not compiled in. */
148 solib_aix_free_library_list (void *p)
152 #else /* HAVE_LIBEXPAT */
154 #include "xml-support.h"
156 /* Handle the start of a <library> element. */
159 library_list_start_library (struct gdb_xml_parser *parser,
160 const struct gdb_xml_element *element,
162 VEC (gdb_xml_value_s) *attributes)
164 VEC (lm_info_p) **list = (VEC (lm_info_p) **) user_data;
165 struct lm_info *item = XCNEW (struct lm_info);
166 struct gdb_xml_value *attr;
168 attr = xml_find_attribute (attributes, "name");
169 item->filename = xstrdup ((const char *) attr->value);
171 attr = xml_find_attribute (attributes, "member");
173 item->member_name = xstrdup ((const char *) attr->value);
175 attr = xml_find_attribute (attributes, "text_addr");
176 item->text_addr = * (ULONGEST *) attr->value;
178 attr = xml_find_attribute (attributes, "text_size");
179 item->text_size = * (ULONGEST *) attr->value;
181 attr = xml_find_attribute (attributes, "data_addr");
182 item->data_addr = * (ULONGEST *) attr->value;
184 attr = xml_find_attribute (attributes, "data_size");
185 item->data_size = * (ULONGEST *) attr->value;
187 VEC_safe_push (lm_info_p, *list, item);
190 /* Handle the start of a <library-list-aix> element. */
193 library_list_start_list (struct gdb_xml_parser *parser,
194 const struct gdb_xml_element *element,
195 void *user_data, VEC (gdb_xml_value_s) *attributes)
197 char *version = (char *) xml_find_attribute (attributes, "version")->value;
199 if (strcmp (version, "1.0") != 0)
200 gdb_xml_error (parser,
201 _("Library list has unsupported version \"%s\""),
205 /* Discard the constructed library list. */
208 solib_aix_free_library_list (void *p)
210 VEC (lm_info_p) **result = (VEC (lm_info_p) **) p;
211 struct lm_info *info;
215 fprintf_unfiltered (gdb_stdlog, "DEBUG: solib_aix_free_library_list\n");
217 for (ix = 0; VEC_iterate (lm_info_p, *result, ix, info); ix++)
218 solib_aix_xfree_lm_info (info);
219 VEC_free (lm_info_p, *result);
223 /* The allowed elements and attributes for an AIX library list
224 described in XML format. The root element is a <library-list-aix>. */
226 static const struct gdb_xml_attribute library_attributes[] =
228 { "name", GDB_XML_AF_NONE, NULL, NULL },
229 { "member", GDB_XML_AF_OPTIONAL, NULL, NULL },
230 { "text_addr", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
231 { "text_size", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
232 { "data_addr", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
233 { "data_size", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
234 { NULL, GDB_XML_AF_NONE, NULL, NULL }
237 static const struct gdb_xml_element library_list_children[] =
239 { "library", library_attributes, NULL,
240 GDB_XML_EF_REPEATABLE | GDB_XML_EF_OPTIONAL,
241 library_list_start_library, NULL},
242 { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
245 static const struct gdb_xml_attribute library_list_attributes[] =
247 { "version", GDB_XML_AF_NONE, NULL, NULL },
248 { NULL, GDB_XML_AF_NONE, NULL, NULL }
251 static const struct gdb_xml_element library_list_elements[] =
253 { "library-list-aix", library_list_attributes, library_list_children,
254 GDB_XML_EF_NONE, library_list_start_list, NULL },
255 { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
258 /* Parse LIBRARY, a string containing the loader info in XML format,
259 and return an lm_info_p vector.
261 Return NULL if the parsing failed. */
263 static VEC (lm_info_p) *
264 solib_aix_parse_libraries (const char *library)
266 VEC (lm_info_p) *result = NULL;
267 struct cleanup *back_to = make_cleanup (solib_aix_free_library_list,
270 if (gdb_xml_parse_quick (_("aix library list"), "library-list-aix.dtd",
271 library_list_elements, library, &result) == 0)
273 /* Parsed successfully, keep the result. */
274 discard_cleanups (back_to);
278 do_cleanups (back_to);
282 #endif /* HAVE_LIBEXPAT */
284 /* Return the loader info for the given inferior (INF), or NULL if
285 the list could not be computed.
287 Cache the result in per-inferior data, so as to avoid recomputing it
288 each time this function is called.
290 If an error occurs while computing this list, and WARNING_MSG
291 is not NULL, then print a warning including WARNING_MSG and
292 a description of the error. */
294 static VEC (lm_info_p) *
295 solib_aix_get_library_list (struct inferior *inf, const char *warning_msg)
297 struct solib_aix_inferior_data *data;
298 char *library_document;
299 struct cleanup *cleanup;
301 /* If already computed, return the cached value. */
302 data = get_solib_aix_inferior_data (inf);
303 if (data->library_list != NULL)
304 return data->library_list;
306 library_document = target_read_stralloc (¤t_target,
307 TARGET_OBJECT_LIBRARIES_AIX,
309 if (library_document == NULL && warning_msg != NULL)
311 warning (_("%s (failed to read TARGET_OBJECT_LIBRARIES_AIX)"),
315 cleanup = make_cleanup (xfree, library_document);
318 fprintf_unfiltered (gdb_stdlog,
319 "DEBUG: TARGET_OBJECT_LIBRARIES_AIX = \n%s\n",
322 data->library_list = solib_aix_parse_libraries (library_document);
323 if (data->library_list == NULL && warning_msg != NULL)
325 warning (_("%s (missing XML support?)"), warning_msg);
326 do_cleanups (cleanup);
330 do_cleanups (cleanup);
331 return data->library_list;
334 /* If the .bss section's VMA is set to an address located before
335 the end of the .data section, causing the two sections to overlap,
336 return the overlap in bytes. Otherwise, return zero.
340 The GNU linker sometimes sets the start address of the .bss session
341 before the end of the .data section, making the 2 sections overlap.
342 The loader appears to handle this situation gracefully, by simply
343 loading the bss section right after the end of the .data section.
345 This means that the .data and the .bss sections are sometimes
346 no longer relocated by the same amount. The problem is that
347 the ldinfo data does not contain any information regarding
348 the relocation of the .bss section, assuming that it would be
349 identical to the information provided for the .data section
350 (this is what would normally happen if the program was linked
353 GDB therefore needs to detect those cases, and make the corresponding
354 adjustment to the .bss section offset computed from the ldinfo data
355 when necessary. This function returns the adjustment amount (or
356 zero when no adjustment is needed). */
359 solib_aix_bss_data_overlap (bfd *abfd)
361 struct bfd_section *data_sect, *bss_sect;
363 data_sect = bfd_get_section_by_name (abfd, ".data");
364 if (data_sect == NULL)
365 return 0; /* No overlap possible. */
367 bss_sect = bfd_get_section_by_name (abfd, ".bss");
368 if (bss_sect == NULL)
369 return 0; /* No overlap possible. */
371 /* Assume the problem only occurs with linkers that place the .bss
372 section after the .data section (the problem has only been
373 observed when using the GNU linker, and the default linker
374 script always places the .data and .bss sections in that order). */
375 if (bfd_section_vma (abfd, bss_sect)
376 < bfd_section_vma (abfd, data_sect))
379 if (bfd_section_vma (abfd, bss_sect)
380 < bfd_section_vma (abfd, data_sect) + bfd_get_section_size (data_sect))
381 return ((bfd_section_vma (abfd, data_sect)
382 + bfd_get_section_size (data_sect))
383 - bfd_section_vma (abfd, bss_sect));
388 /* Implement the "relocate_section_addresses" target_so_ops method. */
391 solib_aix_relocate_section_addresses (struct so_list *so,
392 struct target_section *sec)
394 struct bfd_section *bfd_sect = sec->the_bfd_section;
395 bfd *abfd = bfd_sect->owner;
396 const char *section_name = bfd_section_name (abfd, bfd_sect);
397 struct lm_info *info = so->lm_info;
399 if (strcmp (section_name, ".text") == 0)
401 sec->addr = info->text_addr;
402 sec->endaddr = sec->addr + info->text_size;
404 /* The text address given to us by the loader contains
405 XCOFF headers, so we need to adjust by this much. */
406 sec->addr += bfd_sect->filepos;
408 else if (strcmp (section_name, ".data") == 0)
410 sec->addr = info->data_addr;
411 sec->endaddr = sec->addr + info->data_size;
413 else if (strcmp (section_name, ".bss") == 0)
415 /* The information provided by the loader does not include
416 the address of the .bss section, but we know that it gets
417 relocated by the same offset as the .data section. So,
418 compute the relocation offset for the .data section, and
419 apply it to the .bss section as well. If the .data section
420 is not defined (which seems highly unlikely), do our best
421 by assuming no relocation. */
422 struct bfd_section *data_sect
423 = bfd_get_section_by_name (abfd, ".data");
424 CORE_ADDR data_offset = 0;
426 if (data_sect != NULL)
427 data_offset = info->data_addr - bfd_section_vma (abfd, data_sect);
429 sec->addr = bfd_section_vma (abfd, bfd_sect) + data_offset;
430 sec->addr += solib_aix_bss_data_overlap (abfd);
431 sec->endaddr = sec->addr + bfd_section_size (abfd, bfd_sect);
435 /* All other sections should not be relocated. */
436 sec->addr = bfd_section_vma (abfd, bfd_sect);
437 sec->endaddr = sec->addr + bfd_section_size (abfd, bfd_sect);
441 /* Implement the "free_so" target_so_ops method. */
444 solib_aix_free_so (struct so_list *so)
447 fprintf_unfiltered (gdb_stdlog, "DEBUG: solib_aix_free_so (%s)\n",
449 solib_aix_xfree_lm_info (so->lm_info);
452 /* Implement the "clear_solib" target_so_ops method. */
455 solib_aix_clear_solib (void)
457 /* Nothing needed. */
460 /* Compute and return the OBJFILE's section_offset array, using
461 the associated loader info (INFO).
463 The resulting array is computed on the heap and must be
464 deallocated after use. */
466 static struct section_offsets *
467 solib_aix_get_section_offsets (struct objfile *objfile,
468 struct lm_info *info)
470 struct section_offsets *offsets;
471 bfd *abfd = objfile->obfd;
473 offsets = XCNEWVEC (struct section_offsets, objfile->num_sections);
477 if (objfile->sect_index_text != -1)
479 struct bfd_section *sect
480 = objfile->sections[objfile->sect_index_text].the_bfd_section;
482 offsets->offsets[objfile->sect_index_text]
483 = info->text_addr + sect->filepos - bfd_section_vma (abfd, sect);
488 if (objfile->sect_index_data != -1)
490 struct bfd_section *sect
491 = objfile->sections[objfile->sect_index_data].the_bfd_section;
493 offsets->offsets[objfile->sect_index_data]
494 = info->data_addr - bfd_section_vma (abfd, sect);
499 The offset of the .bss section should be identical to the offset
500 of the .data section. If no .data section (which seems hard to
501 believe it is possible), assume it is zero. */
503 if (objfile->sect_index_bss != -1
504 && objfile->sect_index_data != -1)
506 offsets->offsets[objfile->sect_index_bss]
507 = (offsets->offsets[objfile->sect_index_data]
508 + solib_aix_bss_data_overlap (abfd));
511 /* All other sections should not need relocation. */
516 /* Implement the "solib_create_inferior_hook" target_so_ops method. */
519 solib_aix_solib_create_inferior_hook (int from_tty)
521 const char *warning_msg = "unable to relocate main executable";
522 VEC (lm_info_p) *library_list;
523 struct lm_info *exec_info;
525 /* We need to relocate the main executable... */
527 library_list = solib_aix_get_library_list (current_inferior (),
529 if (library_list == NULL)
530 return; /* Warning already printed. */
532 if (VEC_length (lm_info_p, library_list) < 1)
534 warning (_("unable to relocate main executable (no info from loader)"));
538 exec_info = VEC_index (lm_info_p, library_list, 0);
540 if (symfile_objfile != NULL)
542 struct section_offsets *offsets
543 = solib_aix_get_section_offsets (symfile_objfile, exec_info);
544 struct cleanup *cleanup = make_cleanup (xfree, offsets);
546 objfile_relocate (symfile_objfile, offsets);
547 do_cleanups (cleanup);
551 /* Implement the "special_symbol_handling" target_so_ops method. */
554 solib_aix_special_symbol_handling (void)
556 /* Nothing needed. */
559 /* Implement the "current_sos" target_so_ops method. */
561 static struct so_list *
562 solib_aix_current_sos (void)
564 struct so_list *start = NULL, *last = NULL;
565 VEC (lm_info_p) *library_list;
566 struct lm_info *info;
569 library_list = solib_aix_get_library_list (current_inferior (), NULL);
570 if (library_list == NULL)
573 /* Build a struct so_list for each entry on the list.
574 We skip the first entry, since this is the entry corresponding
575 to the main executable, not a shared library. */
576 for (ix = 1; VEC_iterate (lm_info_p, library_list, ix, info); ix++)
578 struct so_list *new_solib = XCNEW (struct so_list);
581 if (info->member_name == NULL)
583 /* INFO->FILENAME is probably not an archive, but rather
584 a shared object. Unusual, but it should be possible
585 to link a program against a shared object directory,
586 without having to put it in an archive first. */
587 so_name = xstrdup (info->filename);
591 /* This is the usual case on AIX, where the shared object
592 is a member of an archive. Create a synthetic so_name
593 that follows the same convention as AIX's ldd tool
594 (Eg: "/lib/libc.a(shr.o)"). */
595 so_name = xstrprintf ("%s(%s)", info->filename, info->member_name);
597 strncpy (new_solib->so_original_name, so_name,
598 SO_NAME_MAX_PATH_SIZE - 1);
599 new_solib->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0';
600 memcpy (new_solib->so_name, new_solib->so_original_name,
601 SO_NAME_MAX_PATH_SIZE);
602 new_solib->lm_info = solib_aix_new_lm_info (info);
604 /* Add it to the list. */
606 last = start = new_solib;
609 last->next = new_solib;
617 /* Implement the "open_symbol_file_object" target_so_ops method. */
620 solib_aix_open_symbol_file_object (void *from_ttyp)
625 /* Implement the "in_dynsym_resolve_code" target_so_ops method. */
628 solib_aix_in_dynsym_resolve_code (CORE_ADDR pc)
633 /* Implement the "bfd_open" target_so_ops method. */
636 solib_aix_bfd_open (char *pathname)
638 /* The pathname is actually a synthetic filename with the following
639 form: "/path/to/sharedlib(member.o)" (double-quotes excluded).
640 split this into archive name and member name.
642 FIXME: This is a little hacky. Perhaps we should provide access
643 to the solib's lm_info here? */
644 const int path_len = strlen (pathname);
649 bfd *archive_bfd, *object_bfd;
650 struct cleanup *cleanup;
652 char *found_pathname;
654 if (pathname[path_len - 1] != ')')
655 return solib_bfd_open (pathname);
657 /* Search for the associated parens. */
658 sep = strrchr (pathname, '(');
661 /* Should never happen, but recover as best as we can (trying
662 to open pathname without decoding, possibly leading to
663 a failure), rather than triggering an assert failure). */
664 warning (_("missing '(' in shared object pathname: %s"), pathname);
665 return solib_bfd_open (pathname);
667 filename_len = sep - pathname;
669 filename = xstrprintf ("%.*s", filename_len, pathname);
670 cleanup = make_cleanup (xfree, filename);
671 member_name = xstrprintf ("%.*s", path_len - filename_len - 2, sep + 1);
672 make_cleanup (xfree, member_name);
674 /* Calling solib_find makes certain that sysroot path is set properly
675 if program has a dependency on .a archive and sysroot is set via
676 set sysroot command. */
677 found_pathname = solib_find (filename, &found_file);
678 if (found_pathname == NULL)
679 perror_with_name (pathname);
680 archive_bfd = solib_bfd_fopen (found_pathname, found_file);
681 if (archive_bfd == NULL)
683 warning (_("Could not open `%s' as an executable file: %s"),
684 filename, bfd_errmsg (bfd_get_error ()));
685 do_cleanups (cleanup);
689 if (bfd_check_format (archive_bfd, bfd_object))
691 do_cleanups (cleanup);
695 if (! bfd_check_format (archive_bfd, bfd_archive))
697 warning (_("\"%s\": not in executable format: %s."),
698 filename, bfd_errmsg (bfd_get_error ()));
699 gdb_bfd_unref (archive_bfd);
700 do_cleanups (cleanup);
704 object_bfd = gdb_bfd_openr_next_archived_file (archive_bfd, NULL);
705 while (object_bfd != NULL)
709 if (strcmp (member_name, object_bfd->filename) == 0)
712 next = gdb_bfd_openr_next_archived_file (archive_bfd, object_bfd);
713 gdb_bfd_unref (object_bfd);
717 if (object_bfd == NULL)
719 warning (_("\"%s\": member \"%s\" missing."), filename, member_name);
720 gdb_bfd_unref (archive_bfd);
721 do_cleanups (cleanup);
725 if (! bfd_check_format (object_bfd, bfd_object))
727 warning (_("%s(%s): not in object format: %s."),
728 filename, member_name, bfd_errmsg (bfd_get_error ()));
729 gdb_bfd_unref (archive_bfd);
730 gdb_bfd_unref (object_bfd);
731 do_cleanups (cleanup);
735 /* Override the returned bfd's name with the name returned from solib_find
736 along with appended parenthesized member name in order to allow commands
737 listing all shared libraries to display. Otherwise, we would only be
738 displaying the name of the archive member object. */
739 xfree (bfd_get_filename (object_bfd));
740 object_bfd->filename = xstrprintf ("%s%s",
741 bfd_get_filename (archive_bfd), sep);
743 gdb_bfd_unref (archive_bfd);
744 do_cleanups (cleanup);
748 /* Return the obj_section corresponding to OBJFILE's data section,
749 or NULL if not found. */
750 /* FIXME: Define in a more general location? */
752 static struct obj_section *
753 data_obj_section_from_objfile (struct objfile *objfile)
755 struct obj_section *osect;
757 ALL_OBJFILE_OSECTIONS (objfile, osect)
758 if (strcmp (bfd_section_name (objfile->obfd, osect->the_bfd_section),
765 /* Return the TOC value corresponding to the given PC address,
766 or raise an error if the value could not be determined. */
769 solib_aix_get_toc_value (CORE_ADDR pc)
771 struct obj_section *pc_osect = find_pc_section (pc);
772 struct obj_section *data_osect;
775 if (pc_osect == NULL)
776 error (_("unable to find TOC entry for pc %s "
777 "(no section contains this PC)"),
778 core_addr_to_string (pc));
780 data_osect = data_obj_section_from_objfile (pc_osect->objfile);
781 if (data_osect == NULL)
782 error (_("unable to find TOC entry for pc %s "
783 "(%s has no data section)"),
784 core_addr_to_string (pc), objfile_name (pc_osect->objfile));
786 result = (obj_section_addr (data_osect)
787 + xcoff_get_toc_offset (pc_osect->objfile));
789 fprintf_unfiltered (gdb_stdlog,
790 "DEBUG: solib_aix_get_toc_value (pc=%s) -> %s\n",
791 core_addr_to_string (pc),
792 core_addr_to_string (result));
797 /* This module's normal_stop observer. */
800 solib_aix_normal_stop_observer (struct bpstats *unused_1, int unused_2)
802 struct solib_aix_inferior_data *data
803 = get_solib_aix_inferior_data (current_inferior ());
805 /* The inferior execution has been resumed, and it just stopped
806 again. This means that the list of shared libraries may have
807 evolved. Reset our cached value. */
808 solib_aix_free_library_list (&data->library_list);
811 /* Implements the "show debug aix-solib" command. */
814 show_solib_aix_debug (struct ui_file *file, int from_tty,
815 struct cmd_list_element *c, const char *value)
817 fprintf_filtered (file, _("solib-aix debugging is %s.\n"), value);
820 /* The target_so_ops for AIX targets. */
821 struct target_so_ops solib_aix_so_ops;
823 /* -Wmissing-prototypes */
824 extern initialize_file_ftype _initialize_solib_aix;
827 _initialize_solib_aix (void)
829 solib_aix_so_ops.relocate_section_addresses
830 = solib_aix_relocate_section_addresses;
831 solib_aix_so_ops.free_so = solib_aix_free_so;
832 solib_aix_so_ops.clear_solib = solib_aix_clear_solib;
833 solib_aix_so_ops.solib_create_inferior_hook
834 = solib_aix_solib_create_inferior_hook;
835 solib_aix_so_ops.special_symbol_handling
836 = solib_aix_special_symbol_handling;
837 solib_aix_so_ops.current_sos = solib_aix_current_sos;
838 solib_aix_so_ops.open_symbol_file_object
839 = solib_aix_open_symbol_file_object;
840 solib_aix_so_ops.in_dynsym_resolve_code
841 = solib_aix_in_dynsym_resolve_code;
842 solib_aix_so_ops.bfd_open = solib_aix_bfd_open;
844 solib_aix_inferior_data_handle = register_inferior_data ();
846 observer_attach_normal_stop (solib_aix_normal_stop_observer);
848 /* Debug this file's internals. */
849 add_setshow_boolean_cmd ("aix-solib", class_maintenance,
850 &solib_aix_debug, _("\
851 Control the debugging traces for the solib-aix module."), _("\
852 Show whether solib-aix debugging traces are enabled."), _("\
853 When on, solib-aix debugging traces are enabled."),
855 show_solib_aix_debug,
856 &setdebuglist, &showdebuglist);