+ if (main_lm)
+ list->main_lm = *(ULONGEST *) main_lm->value;
+}
+
+/* The allowed elements and attributes for an XML library list.
+ The root element is a <library-list>. */
+
+static const struct gdb_xml_attribute svr4_library_attributes[] =
+{
+ { "name", GDB_XML_AF_NONE, NULL, NULL },
+ { "lm", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
+ { "l_addr", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
+ { "l_ld", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
+ { NULL, GDB_XML_AF_NONE, NULL, NULL }
+};
+
+static const struct gdb_xml_element svr4_library_list_children[] =
+{
+ {
+ "library", svr4_library_attributes, NULL,
+ GDB_XML_EF_REPEATABLE | GDB_XML_EF_OPTIONAL,
+ library_list_start_library, NULL
+ },
+ { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
+};
+
+static const struct gdb_xml_attribute svr4_library_list_attributes[] =
+{
+ { "version", GDB_XML_AF_NONE, NULL, NULL },
+ { "main-lm", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_ulongest, NULL },
+ { NULL, GDB_XML_AF_NONE, NULL, NULL }
+};
+
+static const struct gdb_xml_element svr4_library_list_elements[] =
+{
+ { "library-list-svr4", svr4_library_list_attributes, svr4_library_list_children,
+ GDB_XML_EF_NONE, svr4_library_list_start_list, NULL },
+ { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
+};
+
+/* Parse qXfer:libraries:read packet into *SO_LIST_RETURN. Return 1 if
+
+ Return 0 if packet not supported, *SO_LIST_RETURN is not modified in such
+ case. Return 1 if *SO_LIST_RETURN contains the library list, it may be
+ empty, caller is responsible for freeing all its entries. */
+
+static int
+svr4_parse_libraries (const char *document, struct svr4_library_list *list)
+{
+ struct cleanup *back_to = make_cleanup (svr4_free_library_list,
+ &list->head);
+
+ memset (list, 0, sizeof (*list));
+ list->tailp = &list->head;
+ if (gdb_xml_parse_quick (_("target library list"), "library-list.dtd",
+ svr4_library_list_elements, document, list) == 0)
+ {
+ /* Parsed successfully, keep the result. */
+ discard_cleanups (back_to);
+ return 1;
+ }
+
+ do_cleanups (back_to);
+ return 0;
+}
+
+/* Attempt to get so_list from target via qXfer:libraries-svr4:read packet.
+
+ Return 0 if packet not supported, *SO_LIST_RETURN is not modified in such
+ case. Return 1 if *SO_LIST_RETURN contains the library list, it may be
+ empty, caller is responsible for freeing all its entries.
+
+ Note that ANNEX must be NULL if the remote does not explicitly allow
+ qXfer:libraries-svr4:read packets with non-empty annexes. Support for
+ this can be checked using target_augmented_libraries_svr4_read (). */
+
+static int
+svr4_current_sos_via_xfer_libraries (struct svr4_library_list *list,
+ const char *annex)
+{
+ char *svr4_library_document;
+ int result;
+ struct cleanup *back_to;
+
+ gdb_assert (annex == NULL || target_augmented_libraries_svr4_read ());
+
+ /* Fetch the list of shared libraries. */
+ svr4_library_document = target_read_stralloc (¤t_target,
+ TARGET_OBJECT_LIBRARIES_SVR4,
+ annex);
+ if (svr4_library_document == NULL)
+ return 0;
+
+ back_to = make_cleanup (xfree, svr4_library_document);
+ result = svr4_parse_libraries (svr4_library_document, list);
+ do_cleanups (back_to);
+
+ return result;
+}
+
+#else
+
+static int
+svr4_current_sos_via_xfer_libraries (struct svr4_library_list *list,
+ const char *annex)
+{
+ return 0;
+}
+
+#endif
+
+/* If no shared library information is available from the dynamic
+ linker, build a fallback list from other sources. */
+
+static struct so_list *
+svr4_default_sos (void)
+{
+ struct svr4_info *info = get_svr4_info ();
+ struct so_list *new;
+
+ if (!info->debug_loader_offset_p)
+ return NULL;
+
+ new = XCNEW (struct so_list);
+
+ new->lm_info = xzalloc (sizeof (struct lm_info));
+
+ /* Nothing will ever check the other fields if we set l_addr_p. */
+ new->lm_info->l_addr = info->debug_loader_offset;
+ new->lm_info->l_addr_p = 1;
+
+ strncpy (new->so_name, info->debug_loader_name, SO_NAME_MAX_PATH_SIZE - 1);
+ new->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0';
+ strcpy (new->so_original_name, new->so_name);
+
+ return new;
+}
+
+/* Read the whole inferior libraries chain starting at address LM.
+ Expect the first entry in the chain's previous entry to be PREV_LM.
+ Add the entries to the tail referenced by LINK_PTR_PTR. Ignore the
+ first entry if IGNORE_FIRST and set global MAIN_LM_ADDR according
+ to it. Returns nonzero upon success. If zero is returned the
+ entries stored to LINK_PTR_PTR are still valid although they may
+ represent only part of the inferior library list. */
+
+static int
+svr4_read_so_list (CORE_ADDR lm, CORE_ADDR prev_lm,
+ struct so_list ***link_ptr_ptr, int ignore_first)
+{
+ struct so_list *first = NULL;
+ CORE_ADDR next_lm;
+
+ for (; lm != 0; prev_lm = lm, lm = next_lm)
+ {
+ struct so_list *new;
+ struct cleanup *old_chain;
+ int errcode;
+ char *buffer;
+
+ new = XCNEW (struct so_list);
+ old_chain = make_cleanup_free_so (new);
+
+ new->lm_info = lm_info_read (lm);
+ if (new->lm_info == NULL)
+ {
+ do_cleanups (old_chain);
+ return 0;
+ }
+
+ next_lm = new->lm_info->l_next;
+
+ if (new->lm_info->l_prev != prev_lm)
+ {
+ warning (_("Corrupted shared library list: %s != %s"),
+ paddress (target_gdbarch (), prev_lm),
+ paddress (target_gdbarch (), new->lm_info->l_prev));
+ do_cleanups (old_chain);
+ return 0;
+ }
+
+ /* For SVR4 versions, the first entry in the link map is for the
+ inferior executable, so we must ignore it. For some versions of
+ SVR4, it has no name. For others (Solaris 2.3 for example), it
+ does have a name, so we can no longer use a missing name to
+ decide when to ignore it. */
+ if (ignore_first && new->lm_info->l_prev == 0)
+ {
+ struct svr4_info *info = get_svr4_info ();
+
+ first = new;
+ info->main_lm_addr = new->lm_info->lm_addr;
+ do_cleanups (old_chain);
+ continue;
+ }
+
+ /* Extract this shared object's name. */
+ target_read_string (new->lm_info->l_name, &buffer,
+ SO_NAME_MAX_PATH_SIZE - 1, &errcode);
+ if (errcode != 0)
+ {
+ /* If this entry's l_name address matches that of the
+ inferior executable, then this is not a normal shared
+ object, but (most likely) a vDSO. In this case, silently
+ skip it; otherwise emit a warning. */
+ if (first == NULL
+ || new->lm_info->l_name != first->lm_info->l_name)
+ warning (_("Can't read pathname for load map: %s."),
+ safe_strerror (errcode));
+ do_cleanups (old_chain);
+ continue;
+ }
+
+ strncpy (new->so_name, buffer, SO_NAME_MAX_PATH_SIZE - 1);
+ new->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0';
+ strcpy (new->so_original_name, new->so_name);
+ xfree (buffer);
+
+ /* If this entry has no name, or its name matches the name
+ for the main executable, don't include it in the list. */
+ if (! new->so_name[0] || match_main (new->so_name))
+ {
+ do_cleanups (old_chain);
+ continue;
+ }
+
+ discard_cleanups (old_chain);
+ new->next = 0;
+ **link_ptr_ptr = new;
+ *link_ptr_ptr = &new->next;
+ }
+
+ return 1;
+}
+
+/* Read the full list of currently loaded shared objects directly
+ from the inferior, without referring to any libraries read and
+ stored by the probes interface. Handle special cases relating
+ to the first elements of the list. */
+
+static struct so_list *
+svr4_current_sos_direct (struct svr4_info *info)
+{
+ CORE_ADDR lm;
+ struct so_list *head = NULL;
+ struct so_list **link_ptr = &head;
+ struct cleanup *back_to;
+ int ignore_first;
+ struct svr4_library_list library_list;
+
+ /* Fall back to manual examination of the target if the packet is not
+ supported or gdbserver failed to find DT_DEBUG. gdb.server/solib-list.exp
+ tests a case where gdbserver cannot find the shared libraries list while
+ GDB itself is able to find it via SYMFILE_OBJFILE.
+
+ Unfortunately statically linked inferiors will also fall back through this
+ suboptimal code path. */
+
+ info->using_xfer = svr4_current_sos_via_xfer_libraries (&library_list,
+ NULL);
+ if (info->using_xfer)
+ {
+ if (library_list.main_lm)
+ info->main_lm_addr = library_list.main_lm;
+
+ return library_list.head ? library_list.head : svr4_default_sos ();
+ }
+
+ /* Always locate the debug struct, in case it has moved. */
+ info->debug_base = 0;
+ locate_base (info);
+
+ /* If we can't find the dynamic linker's base structure, this
+ must not be a dynamically linked executable. Hmm. */
+ if (! info->debug_base)
+ return svr4_default_sos ();
+
+ /* Assume that everything is a library if the dynamic loader was loaded
+ late by a static executable. */
+ if (exec_bfd && bfd_get_section_by_name (exec_bfd, ".dynamic") == NULL)
+ ignore_first = 0;
+ else
+ ignore_first = 1;
+
+ back_to = make_cleanup (svr4_free_library_list, &head);
+
+ /* Walk the inferior's link map list, and build our list of
+ `struct so_list' nodes. */
+ lm = solib_svr4_r_map (info);
+ if (lm)
+ svr4_read_so_list (lm, 0, &link_ptr, ignore_first);
+
+ /* On Solaris, the dynamic linker is not in the normal list of
+ shared objects, so make sure we pick it up too. Having
+ symbol information for the dynamic linker is quite crucial
+ for skipping dynamic linker resolver code. */
+ lm = solib_svr4_r_ldsomap (info);
+ if (lm)
+ svr4_read_so_list (lm, 0, &link_ptr, 0);
+
+ discard_cleanups (back_to);
+
+ if (head == NULL)
+ return svr4_default_sos ();
+
+ return head;
+}
+
+/* Implement the "current_sos" target_so_ops method. */
+
+static struct so_list *
+svr4_current_sos (void)
+{
+ struct svr4_info *info = get_svr4_info ();
+
+ /* If the solib list has been read and stored by the probes
+ interface then we return a copy of the stored list. */
+ if (info->solib_list != NULL)
+ return svr4_copy_library_list (info->solib_list);
+
+ /* Otherwise obtain the solib list directly from the inferior. */
+ return svr4_current_sos_direct (info);