[Patch] Add --identify option to dlltool

classic Classic list List threaded Threaded
16 messages Options
Reply | Threaded
Open this post in threaded view
|

[Patch] Add --identify option to dlltool

Charles Wilson-2
To solve a problem with libtool on cygwin (dlpreopen), I needed a
mechanism to determine the DLL associated with a specified import
library. I was surprised to discover that there does not seem to be an
easy way to do this, so I added the functionality to dlltool.

$ dlltool --identify /usr/lib/libz.dll.a
cygz.dll

$ dlltool.exe --identify /usr/lib/mingw/libz.dll.a
mgwz.dll

--
Chuck

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

        Add --identify option to dlltool.

        * binutils/dlltool.c: Added 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): Ditto.
        (main): Handle --identify option.


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 8 Nov 2008 05:18:41 -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,133 @@
   inform (_("Created lib file"));
 }
 
+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);
+    }
+}
+
+static void
+identify_search_archive (bfd* abfd)
+{
+  bfd *arfile = NULL;
+  bfd *last_arfile = NULL;
+  char **matching;
+
+  while (identify_dll_name == NULL)
+    {
+      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);
+    }
+}
+
+static void
+identify_search_member (bfd* abfd, bfd* archive_bfd ATTRIBUTE_UNUSED)
+{
+  bfd_map_over_sections (abfd, identify_search_section, NULL);
+}
+
+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;
+}
+
+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);
+  data[0] = '\0';
+
+  bfd_get_section_contents (abfd, section, data, 0, datasize);
+
+  if (data[0] != '\0')
+    {
+      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 +3305,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 +3346,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 +3385,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 +3453,9 @@
  case 'm':
   mname = optarg;
   break;
+ case 'I':
+  identify_imp_name = optarg;
+  break;
  case 'v':
   verbose = 1;
   break;
@@ -3440,6 +3579,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 ();
Reply | Threaded
Open this post in threaded view
|

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

Christopher Faylor-9
On Sat, Nov 08, 2008 at 12:31:09AM -0500, Charles Wilson wrote:

>To solve a problem with libtool on cygwin (dlpreopen), I needed a
>mechanism to determine the DLL associated with a specified import
>library. I was surprised to discover that there does not seem to be an
>easy way to do this, so I added the functionality to dlltool.
>
>$ dlltool --identify /usr/lib/libz.dll.a
>cygz.dll
>
>$ dlltool.exe --identify /usr/lib/mingw/libz.dll.a
>mgwz.dll
>
>--
>Chuck

>2008-11-08  Charles Wilson  <...>
>
> Add --identify option to dlltool.
>
> * binutils/dlltool.c: Added 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): Ditto.
> (main): Handle --identify option.

This looks useful but I think it needs a few more comments.

cgf
Reply | Threaded
Open this post in threaded view
|

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

Charles Wilson-2
Christopher Faylor wrote:

>> 2008-11-08  Charles Wilson  <...>
>>
>> Add --identify option to dlltool.
>>
>> * binutils/dlltool.c: Added 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): Ditto.
>> (main): Handle --identify option.
>
> This looks useful

Thanks!

> but I think it needs a few more comments.

Fair enough. I didn't want to spend too much time on that without some
feedback on (a) whether it was acceptable at all [*] (b) implementation
-- perhaps there's a better way to implement this, as well as stylistic
comments, and (c) ...lurking bugs?

I'll take "useful" as answering (a), but I'll hold off for some (b) and
(c) comments before reworking the patch.

[*] otherwise, I'd've had to add a new utility to cygutils, but then it
wouldn't be universally available for libtool to use (given a
cygwin/mingw-target toolchain), and I'd have to add another
win32-specific prog/var (DLLTOOL, OBJDUMP, and ???) to the libtool
script's TAG_VARS...I much prefer extending dlltool!

--
Chuck
Reply | Threaded
Open this post in threaded view
|

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

Kai Tietz-2
Hello,

2008/11/8  <[hidden email]>:

> Christopher Faylor wrote:
>>> 2008-11-08  Charles Wilson  <...>
>>>
>>>      Add --identify option to dlltool.
>>>
>>>      * binutils/dlltool.c: Added 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): Ditto.
>>>      (main): Handle --identify option.
>>
>> This looks useful
>
> Thanks!
>
>> but I think it needs a few more comments.
>
> Fair enough. I didn't want to spend too much time on that without some
> feedback on (a) whether it was acceptable at all [*] (b) implementation
> -- perhaps there's a better way to implement this, as well as stylistic
> comments, and (c) ...lurking bugs?
>
> I'll take "useful" as answering (a), but I'll hold off for some (b) and
> (c) comments before reworking the patch.
>
> [*] otherwise, I'd've had to add a new utility to cygutils, but then it
> wouldn't be universally available for libtool to use (given a
> cygwin/mingw-target toolchain), and I'd have to add another
> win32-specific prog/var (DLLTOOL, OBJDUMP, and ???) to the libtool
> script's TAG_VARS...I much prefer extending dlltool!
>
> --
> Chuck
>

I thought about this kind of extension. But wouldn't it be better (at
least for COFF targets) to use the .drectve Section in object. By this
we could even add to the compiler a pragma to specify import library
dependencies.

Cheers
Kai


--
|  (\_/) This is Bunny. Copy and paste
| (='.'=) Bunny into your signature to help
| (")_(") him gain world domination
Reply | Threaded
Open this post in threaded view
|

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

Brian Dessent
Kai Tietz wrote:

> I thought about this kind of extension. But wouldn't it be better (at
> least for COFF targets) to use the .drectve Section in object.

It's not an extension.  The information is already there in the import
lib, the new flag just provides a straightforward way to dump it out.
Why does it make any sense to add a .drectve section to objects in the
import lib and duplicate the information in two places?  And besides, it
would mean that you'd have to rebuild every existing import lib out
there in the wild in order for 'dlltool --identify' to work.  The whole
point of adding this flag is so that libtool can use it, and that goal
isn't met very well if the flag only works with import libs newly
created with bleeding edge tools and not all the existing regular import
libs.

> By this
> we could even add to the compiler a pragma to specify import library
> dependencies.

But that's orthogonal to the problem at hand.  You're talking about
being able to do the MS style trick of being able to supply linker
options in the source code, e.g. #pragma comment(lib,"ws2_32.lib") or
#pragma comment(linker,"/ENTRY:foobar").  This feature is about being
able to map an import lib back to its corresponding DLL.  I don't see
how the two are related.

Brian
Reply | Threaded
Open this post in threaded view
|

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

Kai Tietz-2
2008/11/9 Brian Dessent <[hidden email]>:

> Kai Tietz wrote:
>
>> I thought about this kind of extension. But wouldn't it be better (at
>> least for COFF targets) to use the .drectve Section in object.
>
> It's not an extension.  The information is already there in the import
> lib, the new flag just provides a straightforward way to dump it out.
> Why does it make any sense to add a .drectve section to objects in the
> import lib and duplicate the information in two places?  And besides, it
> would mean that you'd have to rebuild every existing import lib out
> there in the wild in order for 'dlltool --identify' to work.  The whole
> point of adding this flag is so that libtool can use it, and that goal
> isn't met very well if the flag only works with import libs newly
> created with bleeding edge tools and not all the existing regular import
> libs.

I agree that the -identify option is working with existing import
libraries, too. Well, my thoughts were in a more general way. To add
to each object its source dll would help even to identify all related
.dll's by an aggregated import library (which is at least possible).
But I have no objections against the the dlltool's --identify option.

>> By this
>> we could even add to the compiler a pragma to specify import library
>> dependencies.
>
> But that's orthogonal to the problem at hand.  You're talking about
> being able to do the MS style trick of being able to supply linker
> options in the source code, e.g. #pragma comment(lib,"ws2_32.lib") or
> #pragma comment(linker,"/ENTRY:foobar").  This feature is about being
> able to map an import lib back to its corresponding DLL.  I don't see
> how the two are related.

Right, this is orthogonal, just the way round (which is also IMHO an
to be wished feature). I think that the drectve is the more powerful
approach, but of course with the disadvantage of *prior* code.

Kai

--
|  (\_/) This is Bunny. Copy and paste
| (='.'=) Bunny into your signature to help
| (")_(") him gain world domination
Reply | Threaded
Open this post in threaded view
|

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

Christopher Faylor-9
On Sun, Nov 09, 2008 at 11:46:53AM +0100, Kai Tietz wrote:

>2008/11/9 Brian Dessent <[hidden email]>:
>> Kai Tietz wrote:
>>
>>> I thought about this kind of extension. But wouldn't it be better (at
>>> least for COFF targets) to use the .drectve Section in object.
>>
>> It's not an extension.  The information is already there in the import
>> lib, the new flag just provides a straightforward way to dump it out.
>> Why does it make any sense to add a .drectve section to objects in the
>> import lib and duplicate the information in two places?  And besides, it
>> would mean that you'd have to rebuild every existing import lib out
>> there in the wild in order for 'dlltool --identify' to work.  The whole
>> point of adding this flag is so that libtool can use it, and that goal
>> isn't met very well if the flag only works with import libs newly
>> created with bleeding edge tools and not all the existing regular import
>> libs.
>
>I agree that the -identify option is working with existing import
>libraries, too. Well, my thoughts were in a more general way. To add
>to each object its source dll would help even to identify all related
>.dll's by an aggregated import library (which is at least possible).
>But I have no objections against the the dlltool's --identify option.

This is possible but what you are talking about is really a separate
proposal that does not, as far as I can tell, have any impact on
implementing this option.

cgf
Reply | Threaded
Open this post in threaded view
|

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

Kai Tietz
[hidden email] wrote on 10.11.2008 02:39:13:

> On Sun, Nov 09, 2008 at 11:46:53AM +0100, Kai Tietz wrote:
> >2008/11/9 Brian Dessent <[hidden email]>:
> >> Kai Tietz wrote:
> >>
> >>> I thought about this kind of extension. But wouldn't it be better
(at
> >>> least for COFF targets) to use the .drectve Section in object.
> >>
> >> It's not an extension.  The information is already there in the
import
> >> lib, the new flag just provides a straightforward way to dump it out.
> >> Why does it make any sense to add a .drectve section to objects in
the
> >> import lib and duplicate the information in two places?  And besides,
it
> >> would mean that you'd have to rebuild every existing import lib out
> >> there in the wild in order for 'dlltool --identify' to work.  The
whole
> >> point of adding this flag is so that libtool can use it, and that
goal
> >> isn't met very well if the flag only works with import libs newly
> >> created with bleeding edge tools and not all the existing regular
import

> >> libs.
> >
> >I agree that the -identify option is working with existing import
> >libraries, too. Well, my thoughts were in a more general way. To add
> >to each object its source dll would help even to identify all related
> >.dll's by an aggregated import library (which is at least possible).
> >But I have no objections against the the dlltool's --identify option.
>
> This is possible but what you are talking about is really a separate
> proposal that does not, as far as I can tell, have any impact on
> implementing this option.
>
> cgf
>

Well, I think I mixed-up here something. The --identify option to dlltool
is fine (as long as there are just import symbols from one dll within the
import-library). I am currently working on delayed dll loading feature an
so this kind of tag in COFF comments would be helpful.

Sorry for the noise,
Kai

|  (\_/)  This is Bunny. Copy and paste Bunny
| (='.'=) into your signature to help him gain
| (")_(") world domination.

Reply | Threaded
Open this post in threaded view
|

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

Charles Wilson-2
Kai Tietz wrote:

> Well, I think I mixed-up here something. The --identify option to dlltool
> is fine (as long as there are just import symbols from one dll within the
> import-library).

I don't understand your parenthetical caveat. If there are forwarded
symbols, I thought the forwarding was handled by the (first) DLL, not by
the import library -- so you'd still have just one direct dependency,
and just an indirect dependency on the forwarded-to DLL.

Can you give me a reference to an import library that exhibits the
behavior you're worried about?

--
Chuck
Reply | Threaded
Open this post in threaded view
|

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

Kai Tietz
In reply to this post by Charles Wilson-2
Hi Chuck,

[hidden email] wrote on 10.11.2008 16:22:47:

> Kai Tietz wrote:
>
> > Well, I think I mixed-up here something. The --identify option to
dlltool
> > is fine (as long as there are just import symbols from one dll within
the

> > import-library).
>
> I don't understand your parenthetical caveat. If there are forwarded
> symbols, I thought the forwarding was handled by the (first) DLL, not by
> the import library -- so you'd still have just one direct dependency,
> and just an indirect dependency on the forwarded-to DLL.
>
> Can you give me a reference to an import library that exhibits the
> behavior you're worried about?
>
> --
> Chuck
>
This issue is a bit constructed but possible. See attached library. It is
a combination of libkernel32.a and libntdll.a.
I need to pack it for message size.

Cheers,
Kai



|  (\_/)  This is Bunny. Copy and paste Bunny
| (='.'=) into your signature to help him gain
| (")_(") world domination.

libkn.tar.bz2 (73K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

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

Charles Wilson-2
In reply to this post by Charles Wilson-2
Kai Tietz wrote:

> This issue is a bit constructed but possible. See attached library. It is
> a combination of libkernel32.a and libntdll.a.

Hmm. So, in that example there are actually 2 members in the archive
which possess a .idata$7 section for which SECTION_HAS_CONTENTS is true.

That is kind of an odd case. As far as libtool is concerned, it's a
non-issue; a "link library" that directly references two different
runtime libraries is not a portable construct -- on *nix, the link
library is usually an unversioned name of a symbolic link to the
versioned runtime library:

   /usr/lib/libz.so -> libz.so.1.2.3

How could you implement *two* runtime libraries both directly referenced
by the same link library? You can't:

   /usr/lib/libfoo.so -> libfoo.so.0.1.2
                      -> libbar.so.1.2.3

except by forwarding, but that's a whole 'nother kettle of fish (and
looks more like indirect dependency than direct).

I guess there are two choices:

1) ignore it. Only return "the first" .idata$7 entry.

2) return all entries (one per line?). In this case, a client (such as
libtool) could detect a multi-line result and flag an error, or
otherwise handle that exceptional case.

The downside of 2) is that in the VAST majority of cases, there is only
one archive member that has the non-empty .idata$7 section -- and it is
first. So, --identify usually quits after parsing only the very first
archive member; it hunts only until it finds the (one, e.g. first, e.g
only) answer. Option (2) would require parsing *every* archive member
from beginning to end. That's a pretty severe pessimism to handle a case
that is rather pathological in nature.

--
Chuck

Reply | Threaded
Open this post in threaded view
|

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

Kai Tietz
> I guess there are two choices:
>
> 1) ignore it. Only return "the first" .idata$7 entry.
>
> 2) return all entries (one per line?). In this case, a client (such as
> libtool) could detect a multi-line result and flag an error, or
> otherwise handle that exceptional case.
>
> The downside of 2) is that in the VAST majority of cases, there is only
> one archive member that has the non-empty .idata$7 section -- and it is
> first. So, --identify usually quits after parsing only the very first
> archive member; it hunts only until it finds the (one, e.g. first, e.g
> only) answer. Option (2) would require parsing *every* archive member
> from beginning to end. That's a pretty severe pessimism to handle a case
> that is rather pathological in nature.

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. The example I made is for *nix an absolute none-issue, I agree. For
coff targets it is possible but odd and shouldn't be supported at all, but
should be warned.

Cheers
Kai

|  (\_/)  This is Bunny. Copy and paste Bunny
| (='.'=) into your signature to help him gain
| (")_(") world domination.

Reply | Threaded
Open this post in threaded view
|

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

Charles Wilson-2
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
Reply | Threaded
Open this post in threaded view
|

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

Christopher Faylor-9
On Fri, Nov 14, 2008 at 11:12:01PM -0500, Charles Wilson wrote:

>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!

A very minor comment: Most of the error messages in dlltool do not end
in period but you've added a couple that do.  Could you nuke the
periods?

Other than that highly important observation, I think this looks good.

cgf
Reply | Threaded
Open this post in threaded view
|

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

Charles Wilson-2
Christopher Faylor wrote:

> A very minor comment: Most of the error messages in dlltool do not end
> in period but you've added a couple that do.  Could you nuke the
> periods?
>
> Other than that highly important observation, I think this looks good.

Attached. I used to have commit-after-approval access to sourceware, but
I'm not sure if I still do. A) Should I go ahead and try to commit, or
B) do we need another approver, or C) do you want to commit the patch?

--
Chuck

(changelog in previous message)


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 05:01:57 -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_search_section
+
+   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 05:01:59 -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
Reply | Threaded
Open this post in threaded view
|

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

Charles Wilson-2
Charles Wilson wrote:
> Attached. I used to have commit-after-approval access to sourceware, but
> I'm not sure if I still do. A) Should I go ahead and try to commit, or
> B) do we need another approver, or C) do you want to commit the patch?

As instructed offlist, I've committed this change to CVS.

--
Chuck