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