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