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