This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [Patch] Add --identify option to dlltool


Kai Tietz wrote:
>> I guess there are two choices:
>>
>> 1) ignore it. Only return "the first" .idata$7 entry.
> 
> IMHO case 1) is that one to choose. Maybe it would be even better to check 
> if there is just one .idata$7 section present, and if not to reject it at 
> all.

I decided it would be best to report only the first DLL name, but
continue searching through the archive. If there are more than one
assoicated dll names, then treat that as an error.

Revised patch attached, now with comments and documentation!

--
Chuck

2008-11-14  Charles Wilson  <...>

	Added --identify option to dlltool.

	* binutils/dlltool.c: Add new global variables
	identify_imp_name and identify_dll_name.
	(identify_dll_for_implib, identify_search_archive,
	identify_search_member, identify_process_section_p,
	identify_search_section): New functions.
	(usage): Added --identify.
	(long_options): Added --identify.
	(main): Handle --identify option.
	* binutils/doc/binutils.texi: Document --identify.

Index: binutils/dlltool.c
===================================================================
RCS file: /cvs/src/src/binutils/dlltool.c,v
retrieving revision 1.83
diff -u -r1.83 dlltool.c
--- binutils/dlltool.c	9 Oct 2008 09:00:08 -0000	1.83
+++ binutils/dlltool.c	15 Nov 2008 03:59:05 -0000
@@ -352,6 +352,8 @@
 static int no_idata5;
 static char *exp_name;
 static char *imp_name;
+static char *identify_imp_name;
+static char *identify_dll_name;
 static char *head_label;
 static char *imp_name_lab;
 static char *dll_name;
@@ -724,6 +726,11 @@
 static bfd *make_head (void);
 static bfd *make_tail (void);
 static void gen_lib_file (void);
+static void identify_dll_for_implib (void);
+static void identify_search_archive (bfd*);
+static void identify_search_member (bfd*, bfd*);
+static bfd_boolean identify_process_section_p (asection *);
+static void identify_search_section (bfd *, asection *, void *);
 static int pfunc (const void *, const void *);
 static int nfunc (const void *, const void *);
 static void remove_null_names (export_type **);
@@ -2918,6 +2925,193 @@
   inform (_("Created lib file"));
 }
 
+/* identify_dll_for_implib
+
+   This is the main implementation for the --identify option.
+   Given the name of an import library in identify_imp_name,
+   search all archive members for an .idata$7 section
+   (.idata$6 on PPC). This section will consist of a single
+   char* constant, indicating the name of the DLL represented
+   by the import library.
+
+   It is possible to construct an import library that has
+   two members with a non-empty .idata$7 section, but these
+   are not often seen in normal operation.  In this case,
+   an error is flagged.
+*/   
+static void 
+identify_dll_for_implib (void)
+{
+  bfd* abfd = NULL;
+
+  bfd_init ();
+
+  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);
+    }
+
+  identify_search_archive (abfd);
+
+  if (!bfd_close (abfd))
+    bfd_fatal (identify_imp_name);
+
+  if (identify_dll_name && *identify_dll_name)
+    {
+      printf ("%s\n",identify_dll_name);
+      free (identify_dll_name);
+      identify_dll_name = NULL;
+    }
+  else
+    {
+      fatal ("Unable to determine dll name for %s (not an import library?)", identify_imp_name);
+    }
+}
+
+/* identify_search_archive
+
+   Loop over all members of the archive, inspecting 
+   each for the presence of an .idata$7 (.idata$6 on PPC)
+   section with non-empty contents.
+*/   
+static void
+identify_search_archive (bfd* abfd)
+{
+  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))
+        {
+          identify_search_member (arfile, abfd);
+        }
+      else
+        {
+          bfd_nonfatal (bfd_get_filename (arfile));
+          free (matching);
+        }
+      if (last_arfile != NULL)
+        {
+          bfd_close (last_arfile);
+        }
+      last_arfile = arfile;
+    }
+
+  if (last_arfile != NULL)
+    {
+      bfd_close (last_arfile);
+    }
+}
+
+/* identify_search_member
+
+   Search all sections of an archive member for the 
+   one with section name of .idata$7 (.idata$6 on PPC)
+   and non-empty contents.
+*/   
+static void
+identify_search_member (bfd* abfd, bfd* archive_bfd ATTRIBUTE_UNUSED)
+{
+  bfd_map_over_sections (abfd, identify_search_section, NULL);
+}
+
+/* identify_process_section_p
+
+   This predicate returns true if section->name
+   is .idata$7 (.idata$6 on PPC).
+*/   
+static bfd_boolean
+identify_process_section_p (asection * section)
+{
+  static const char * SECTION_NAME =
+#ifdef DLLTOOL_PPC
+  /* dllname is stored in idata$6 on PPC */
+  ".idata$6";
+#else
+  ".idata$7";
+#endif
+
+  if (strcmp (SECTION_NAME, section->name) == 0)
+    return TRUE;
+  return FALSE;
+}
+
+/* identify_process_section_p
+
+   If *section has contents and its name is .idata$7
+   (.data$6 on PPC) then store the contents in 
+   identify_dll_name as an xmalloc'ed array.
+
+   However, if identify_dll_name already has
+   a value, flag an error. We don't know how to handle
+   import libraries that directly reference more than
+   one DLL. (This is different than forwarded symbols.
+   Such import libraries are not seen in normal operation,
+   and must be specifically constructed.)
+*/   
+static void
+identify_search_section (bfd *abfd, asection *section, void *dummy ATTRIBUTE_UNUSED)
+{
+  bfd_byte *data = 0;
+  bfd_size_type datasize;
+
+  if ((section->flags & SEC_HAS_CONTENTS) == 0)
+    return;
+
+  if (! identify_process_section_p (section))
+    return;
+
+  if ((datasize = bfd_section_size (abfd, section)) == 0)
+    return;
+
+  data = (bfd_byte*) xmalloc (datasize + 1);
+  data[0] = '\0';
+
+  bfd_get_section_contents (abfd, section, data, 0, datasize);
+  data[datasize] = '\0';
+
+  if (data[0] != '\0')
+    {
+      if (identify_dll_name != NULL)
+        {
+          if (*identify_dll_name != '\0')
+            {
+              /* The import library specifies two different DLLs.
+                 Treat this as an error. */
+              fatal ("Import library `%s' specifies two or more dlls: `%s' and `%s'.",
+                     identify_imp_name, identify_dll_name, data);
+            }
+          else
+            {
+              /* For some reason memory was allocated, but the
+                 contents were empty. Free the memory and continue. */
+              free (identify_dll_name);
+            }
+        }
+      identify_dll_name = (char*) xstrdup (data);
+    }
+
+  free (data);
+}
+
 /* Run through the information gathered from the .o files and the
    .def file and work out the best stuff.  */
 
@@ -3171,6 +3365,7 @@
   fprintf (file, _("   -C --compat-implib        Create backward compatible import library.\n"));
   fprintf (file, _("   -n --no-delete            Keep temp files (repeat for extra preservation).\n"));
   fprintf (file, _("   -t --temp-prefix <prefix> Use <prefix> to construct temp file names.\n"));
+  fprintf (file, _("   -I --identify <implib>    Report the name of the DLL associated with <implib>.\n"));
   fprintf (file, _("   -v --verbose              Be verbose.\n"));
   fprintf (file, _("   -V --version              Display the program version.\n"));
   fprintf (file, _("   -h --help                 Display this information.\n"));
@@ -3211,6 +3406,7 @@
   {"kill-at", no_argument, NULL, 'k'},
   {"add-stdcall-alias", no_argument, NULL, 'A'},
   {"ext-prefix-alias", required_argument, NULL, 'p'},
+  {"identify", required_argument, NULL, 'I'},
   {"verbose", no_argument, NULL, 'v'},
   {"version", no_argument, NULL, 'V'},
   {"help", no_argument, NULL, 'h'},
@@ -3249,9 +3445,9 @@
 
   while ((c = getopt_long (ac, av,
 #ifdef DLLTOOL_MCORE_ELF
-			   "m:e:l:aD:d:z:b:xp:cCuUkAS:f:nvVHhM:L:F:",
+			   "m:e:l:aD:d:z:b:xp:cCuUkAS:f:nI:vVHhM:L:F:",
 #else
-			   "m:e:l:aD:d:z:b:xp:cCuUkAS:f:nvVHh",
+			   "m:e:l:aD:d:z:b:xp:cCuUkAS:f:nI:vVHh",
 #endif
 			   long_options, 0))
 	 != EOF)
@@ -3317,6 +3513,9 @@
 	case 'm':
 	  mname = optarg;
 	  break;
+	case 'I':
+	  identify_imp_name = optarg;
+	  break;
 	case 'v':
 	  verbose = 1;
 	  break;
@@ -3440,6 +3639,11 @@
   if (output_def)
     gen_def_file ();
 
+  if (identify_imp_name)
+    {
+      identify_dll_for_implib ();
+    }
+
 #ifdef DLLTOOL_MCORE_ELF
   if (mcore_elf_out_file)
     mcore_elf_gen_out_file ();
Index: binutils/doc/binutils.texi
===================================================================
RCS file: /cvs/src/src/binutils/doc/binutils.texi,v
retrieving revision 1.130
diff -u -r1.130 binutils.texi
--- binutils/doc/binutils.texi	6 Aug 2008 00:42:17 -0000	1.130
+++ binutils/doc/binutils.texi	15 Nov 2008 03:59:10 -0000
@@ -3371,7 +3371,8 @@
         [@option{-U}|@option{--add-underscore}] [@option{--add-stdcall-underscore}]
         [@option{-k}|@option{--kill-at}] [@option{-A}|@option{--add-stdcall-alias}]
         [@option{-p}|@option{--ext-prefix-alias} @var{prefix}]
-        [@option{-x}|@option{--no-idata4}] [@option{-c}|@option{--no-idata5}] [@option{-i}|@option{--interwork}]
+        [@option{-x}|@option{--no-idata4}] [@option{-c}|@option{--no-idata5}]
+        [@option{-I}|@option{--identify} @var{library-file-name}] [@option{-i}|@option{--interwork}]
         [@option{-n}|@option{--nodelete}] [@option{-t}|@option{--temp-prefix} @var{prefix}]
         [@option{-v}|@option{--verbose}]
         [@option{-h}|@option{--help}] [@option{-V}|@option{--version}]
@@ -3421,9 +3422,9 @@
 @command{dlltool} when it is creating or reading in a @file{.def} file.
 
 The third file needed for DLL creation is the library file that programs
-will link with in order to access the functions in the DLL.  This file
-can be created by giving the @option{-l} option to dlltool when it
-is creating or reading in a @file{.def} file.
+will link with in order to access the functions in the DLL (an `import
+library').  This file can be created by giving the @option{-l} option to
+dlltool when it is creating or reading in a @file{.def} file.
 
 @command{dlltool} builds the library file by hand, but it builds the
 exports file by creating temporary files containing assembler statements
@@ -3446,6 +3447,11 @@
   gcc program.o dll.lib -o program
 @end smallexample
 
+
+@command{dlltool} may also be used to query an existing import library
+to determine the name of the DLL to which it is associated.  See the 
+description of the @option{-I} or @option{--identify} option.
+ 
 @c man end
 
 @c man begin OPTIONS dlltool
@@ -3585,6 +3591,16 @@
 files it should omit the @code{.idata5} section.  This is for compatibility
 with certain operating systems.
 
+@item -I @var{filename}
+@itemx --identify @var{filename}
+Specifies that @command{dlltool} should inspect the import library
+indicated by @var{filename} and report, on @code{stdout}, the name of
+the associated DLL.  This can be performed in addition to any other
+operations indicated by the other options and arguments.  @command{dlltool}
+@option{--identify} fails if the import library does not exist, is not
+actually an import library, or (rarely) if the import library somehow
+specifies more than one associated DLL.
+
 @item -i
 @itemx --interwork
 Specifies that @command{dlltool} should mark the objects in the library

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]