From d4732f7c88f3c29788d7d9df21520c1abc66c4b3 Mon Sep 17 00:00:00 2001 From: Charles Wilson Date: Sat, 15 Nov 2008 18:15:18 +0000 Subject: [PATCH] Added --identify option to dlltool. --- binutils/ChangeLog | 13 +++ binutils/dlltool.c | 208 ++++++++++++++++++++++++++++++++++++- binutils/doc/binutils.texi | 24 ++++- 3 files changed, 239 insertions(+), 6 deletions(-) diff --git a/binutils/ChangeLog b/binutils/ChangeLog index ebf4db39e13..43d4d5fc4db 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,16 @@ +2008-11-15 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. + 2008-11-14 Tristan Gingold Remove outdated mach-o specific tests. diff --git a/binutils/dlltool.c b/binutils/dlltool.c index 1e2f1f98e5b..fff8b77e9fe 100644 --- a/binutils/dlltool.c +++ b/binutils/dlltool.c @@ -352,6 +352,8 @@ static int no_idata4; 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_one_lib_file (export_type *, int); 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 @@ gen_lib_file (void) 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 @@ usage (FILE *file, int status) 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 Use to construct temp file names.\n")); + fprintf (file, _(" -I --identify Report the name of the DLL associated with .\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 @@ static const struct option long_options[] = {"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 @@ main (int ac, char **av) 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 @@ main (int ac, char **av) case 'm': mname = optarg; break; + case 'I': + identify_imp_name = optarg; + break; case 'v': verbose = 1; break; @@ -3440,6 +3639,11 @@ main (int ac, char **av) 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 (); diff --git a/binutils/doc/binutils.texi b/binutils/doc/binutils.texi index db09d8ae3c3..e55981bdcac 100644 --- a/binutils/doc/binutils.texi +++ b/binutils/doc/binutils.texi @@ -3371,7 +3371,8 @@ dlltool [@option{-d}|@option{--input-def} @var{def-file-name}] [@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 @@ binary file and it can be created by giving the @option{-e} option to @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 @@ that uses that DLL: 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 @@ Specifies that when @command{dlltool} is creating the exports and library 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 -- 2.30.2