+/* Count the number of entries in list. */
+
+static int
+dll_name_list_count (dll_name_list_type * list)
+{
+ dll_name_list_node_type * p;
+ int count = 0;
+
+ /* Error checking. */
+ if (! list || ! list->head)
+ return 0;
+
+ p = list->head;
+
+ while (p && p->next)
+ {
+ count++;
+ p = p->next;
+ }
+ return count;
+}
+
+/* Print each entry in list to stdout. */
+
+static void
+dll_name_list_print (dll_name_list_type * list)
+{
+ dll_name_list_node_type * p;
+
+ /* Error checking. */
+ if (! list || ! list->head)
+ return;
+
+ p = list->head;
+
+ while (p && p->next && p->next->dllname && *(p->next->dllname))
+ {
+ printf ("%s\n", p->next->dllname);
+ p = p->next;
+ }
+}
+
+/* Free all entries in list, and list itself. */
+
+static void
+dll_name_list_free (dll_name_list_type * list)
+{
+ if (list)
+ {
+ dll_name_list_free_contents (list->head);
+ list->head = NULL;
+ list->tail = NULL;
+ free (list);
+ }
+}
+
+/* Recursive function to free all nodes entry->next->next...
+ as well as entry itself. */
+
+static void
+dll_name_list_free_contents (dll_name_list_node_type * entry)
+{
+ if (entry)
+ {
+ if (entry->next)
+ dll_name_list_free_contents (entry->next);
+ free (entry->dllname);
+ free (entry);
+ }
+}
+
+/* Allocate and initialize a dll_name_list_type object,
+ including its sentinel node. Caller is responsible
+ for calling dll_name_list_free when finished with
+ the list. */
+
+static dll_name_list_type *
+dll_name_list_create (void)
+{
+ /* Allocate list. */
+ dll_name_list_type * list = xmalloc (sizeof (dll_name_list_type));
+
+ /* Allocate and initialize sentinel node. */
+ list->head = xmalloc (sizeof (dll_name_list_node_type));
+ list->head->dllname = NULL;
+ list->head->next = NULL;
+
+ /* Bookkeeping for empty list. */
+ list->tail = list->head;
+
+ return list;
+}
+
+/* Search the symbol table of the suppled BFD for a symbol whose name matches
+ OBJ (where obj is cast to const char *). If found, set global variable
+ identify_member_contains_symname_result TRUE. It is the caller's
+ responsibility to set the result variable FALSE before iterating with
+ this function. */
+
+static void
+identify_member_contains_symname (bfd * abfd,
+ bfd * archive_bfd ATTRIBUTE_UNUSED,
+ void * obj)
+{
+ long storage_needed;
+ asymbol ** symbol_table;
+ long number_of_symbols;
+ long i;
+ symname_search_data_type * search_data = (symname_search_data_type *) obj;
+
+ /* If we already found the symbol in a different member,
+ short circuit. */
+ if (search_data->found)
+ return;
+
+ storage_needed = bfd_get_symtab_upper_bound (abfd);
+ if (storage_needed <= 0)
+ return;
+
+ symbol_table = xmalloc (storage_needed);
+ number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table);
+ if (number_of_symbols < 0)
+ {
+ free (symbol_table);
+ return;
+ }
+
+ for (i = 0; i < number_of_symbols; i++)
+ {
+ if (strncmp (symbol_table[i]->name,
+ search_data->symname,
+ strlen (search_data->symname)) == 0)
+ {
+ search_data->found = TRUE;
+ break;
+ }
+ }
+ free (symbol_table);
+}
+
+/* This is the main implementation for the --identify option.
+ Given the name of an import library in identify_imp_name, first determine
+ if the import library is a GNU binutils-style one (where the DLL name is
+ stored in an .idata$7 (.idata$6 on PPC) section, or if it is a MS-style
+ one (where the DLL name, along with much other data, is stored in the
+ .idata$6 section). We determine the style of import library by searching
+ for the DLL-structure symbol inserted by MS tools:
+ __NULL_IMPORT_DESCRIPTOR.
+
+ Once we know which section to search, evaluate each section for the
+ appropriate properties that indicate it may contain the name of the
+ associated DLL (this differs depending on the style). Add the contents
+ of all sections which meet the criteria to a linked list of dll names.
+
+ Finally, print them all to stdout. (If --identify-strict, an error is
+ reported if more than one match was found). */
+
+static void
+identify_dll_for_implib (void)
+{
+ bfd * abfd = NULL;
+ int count = 0;
+ identify_data_type identify_data;
+ symname_search_data_type search_data;
+
+ /* Initialize identify_data. */
+ identify_data.list = dll_name_list_create ();
+ identify_data.ms_style_implib = FALSE;
+
+ /* Initialize search_data. */
+ search_data.symname = "__NULL_IMPORT_DESCRIPTOR";
+ search_data.found = FALSE;
+
+ if (bfd_init () != BFD_INIT_MAGIC)
+ fatal (_("fatal error: libbfd ABI mismatch"));
+
+ abfd = bfd_openr (identify_imp_name, 0);
+ if (abfd == NULL)
+ /* xgettext:c-format */
+ fatal (_("Can't open .lib file: %s: %s"),
+ identify_imp_name, bfd_get_errmsg ());
+
+ if (! bfd_check_format (abfd, bfd_archive))
+ {
+ if (! bfd_close (abfd))
+ bfd_fatal (identify_imp_name);
+
+ fatal (_("%s is not a library"), identify_imp_name);
+ }
+
+ /* Detect if this a Microsoft import library. */
+ identify_search_archive (abfd,
+ identify_member_contains_symname,
+ (void *)(& search_data));
+ if (search_data.found)
+ identify_data.ms_style_implib = TRUE;
+
+ /* Rewind the bfd. */
+ if (! bfd_close (abfd))
+ bfd_fatal (identify_imp_name);
+ abfd = bfd_openr (identify_imp_name, 0);
+ if (abfd == NULL)
+ bfd_fatal (identify_imp_name);
+
+ if (!bfd_check_format (abfd, bfd_archive))
+ {
+ if (!bfd_close (abfd))
+ bfd_fatal (identify_imp_name);
+
+ fatal (_("%s is not a library"), identify_imp_name);
+ }
+
+ /* Now search for the dll name. */
+ identify_search_archive (abfd,
+ identify_search_member,
+ (void *)(& identify_data));
+
+ if (! bfd_close (abfd))
+ bfd_fatal (identify_imp_name);
+
+ count = dll_name_list_count (identify_data.list);
+ if (count > 0)
+ {
+ if (identify_strict && count > 1)
+ {
+ dll_name_list_free (identify_data.list);
+ identify_data.list = NULL;
+ fatal (_("Import library `%s' specifies two or more dlls"),
+ identify_imp_name);
+ }
+ dll_name_list_print (identify_data.list);
+ dll_name_list_free (identify_data.list);
+ identify_data.list = NULL;
+ }
+ else
+ {
+ dll_name_list_free (identify_data.list);
+ identify_data.list = NULL;
+ fatal (_("Unable to determine dll name for `%s' (not an import library?)"),
+ identify_imp_name);
+ }
+}
+
+/* Loop over all members of the archive, applying the supplied function to
+ each member that is a bfd_object. The function will be called as if:
+ func (member_bfd, abfd, user_storage) */
+
+static void
+identify_search_archive (bfd * abfd,
+ void (* operation) (bfd *, bfd *, void *),
+ void * user_storage)
+{
+ bfd * arfile = NULL;
+ bfd * last_arfile = NULL;
+ char ** matching;
+
+ while (1)
+ {
+ arfile = bfd_openr_next_archived_file (abfd, arfile);
+
+ if (arfile == NULL)
+ {
+ if (bfd_get_error () != bfd_error_no_more_archived_files)
+ bfd_fatal (bfd_get_filename (abfd));
+ break;
+ }
+
+ if (bfd_check_format_matches (arfile, bfd_object, &matching))
+ (*operation) (arfile, abfd, user_storage);
+ else
+ {
+ bfd_nonfatal (bfd_get_filename (arfile));
+ free (matching);
+ }