+ unlink (imp_name);
+
+ outarch = bfd_openw (imp_name, HOW_BFD_WRITE_TARGET);
+
+ if (!outarch)
+ /* xgettext:c-format */
+ fatal (_("Can't create .lib file: %s: %s"),
+ imp_name, bfd_get_errmsg ());
+
+ /* xgettext:c-format */
+ inform (_("Creating library file: %s"), imp_name);
+
+ xatexit (unlink_temp_files);
+
+ bfd_set_format (outarch, bfd_archive);
+ outarch->has_armap = 1;
+ outarch->is_thin_archive = 0;
+
+ /* Work out a reasonable size of things to put onto one line. */
+ if (delay)
+ {
+ ar_head = make_delay_head ();
+ }
+ else
+ {
+ ar_head = make_head ();
+ }
+ ar_tail = make_tail();
+
+ if (ar_head == NULL || ar_tail == NULL)
+ return;
+
+ for (i = 0; (exp = d_exports_lexically[i]); i++)
+ {
+ bfd *n;
+ /* Don't add PRIVATE entries to import lib. */
+ if (exp->private)
+ continue;
+ n = make_one_lib_file (exp, i, delay);
+ n->archive_next = head;
+ head = n;
+ if (ext_prefix_alias)
+ {
+ export_type alias_exp;
+
+ assert (i < PREFIX_ALIAS_BASE);
+ alias_exp.name = make_imp_label (ext_prefix_alias, exp->name);
+ alias_exp.internal_name = exp->internal_name;
+ alias_exp.its_name = exp->its_name;
+ alias_exp.import_name = exp->name;
+ alias_exp.ordinal = exp->ordinal;
+ alias_exp.constant = exp->constant;
+ alias_exp.noname = exp->noname;
+ alias_exp.private = exp->private;
+ alias_exp.data = exp->data;
+ alias_exp.forward = exp->forward;
+ alias_exp.next = exp->next;
+ n = make_one_lib_file (&alias_exp, i + PREFIX_ALIAS_BASE, delay);
+ n->archive_next = head;
+ head = n;
+ }
+ }
+
+ /* Now stick them all into the archive. */
+ ar_head->archive_next = head;
+ ar_tail->archive_next = ar_head;
+ head = ar_tail;
+
+ if (! bfd_set_archive_head (outarch, head))
+ bfd_fatal ("bfd_set_archive_head");
+
+ if (! bfd_close (outarch))
+ bfd_fatal (imp_name);
+
+ while (head != NULL)
+ {
+ bfd *n = head->archive_next;
+ bfd_close (head);
+ head = n;
+ }
+
+ /* Delete all the temp files. */
+ unlink_temp_files ();
+
+ if (dontdeltemps < 2)
+ {
+ char *name;
+
+ name = xmalloc (strlen (TMP_STUB) + 10);
+ for (i = 0; (exp = d_exports_lexically[i]); i++)
+ {
+ /* Don't delete non-existent stubs for PRIVATE entries. */
+ if (exp->private)
+ continue;
+ sprintf (name, "%s%05d.o", TMP_STUB, i);
+ if (unlink (name) < 0)
+ /* xgettext:c-format */
+ non_fatal (_("cannot delete %s: %s"), name, strerror (errno));
+ if (ext_prefix_alias)
+ {
+ sprintf (name, "%s%05d.o", TMP_STUB, i + PREFIX_ALIAS_BASE);
+ if (unlink (name) < 0)
+ /* xgettext:c-format */
+ non_fatal (_("cannot delete %s: %s"), name, strerror (errno));
+ }
+ }
+ free (name);
+ }
+
+ inform (_("Created lib file"));
+}
+
+/* Append a copy of data (cast to char *) to list. */
+
+static void
+dll_name_list_append (dll_name_list_type * list, bfd_byte * data)
+{
+ dll_name_list_node_type * entry;
+
+ /* Error checking. */
+ if (! list || ! list->tail)
+ return;
+
+ /* Allocate new node. */
+ entry = ((dll_name_list_node_type *)
+ xmalloc (sizeof (dll_name_list_node_type)));
+
+ /* Initialize its values. */
+ entry->dllname = xstrdup ((char *) data);
+ entry->next = NULL;
+
+ /* Add to tail, and move tail. */
+ list->tail->next = entry;
+ list->tail = entry;
+}
+
+/* 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);
+ entry->next = NULL;
+ }
+ if (entry->dllname)
+ {
+ free (entry->dllname);
+ entry->dllname = NULL;
+ }
+ 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);
+ }
+
+ if (last_arfile != NULL)
+ {
+ bfd_close (last_arfile);
+ /* PR 17512: file: 8b2168d4. */
+ if (last_arfile == arfile)
+ {
+ last_arfile = NULL;
+ break;
+ }
+ }
+
+ last_arfile = arfile;
+ }
+
+ if (last_arfile != NULL)
+ {
+ bfd_close (last_arfile);
+ }
+}
+
+/* Call the identify_search_section() function for each section of this
+ archive member. */