[6/6] Add a partial COFF library support to the winedump

Dmitry Timoshkov dmitry at codeweavers.com
Sun Nov 26 02:06:46 CST 2006


Hello,

this implementation is able to parse imports libraries from the PSDK
and hopefully should help interested parties to check/synchronize ordinal
imports between Wine and Windows.

The dumper is not able (yet) to parse import libraries with the long format
described in Portable Executable and Common Object File Format Specification
and uuid.lib.

Here is a sample output of the dumper (emulating what dumpbin emits):

  Contents of "ComCtl32.Lib": 26302 bytes

  Version      : 0
  Machine      : 14C (i386)
  TimeDateStamp: 40760E7E Fri Apr  9 11:46:22 2004
  SizeOfData   : 00000055
  DLL name     : COMCTL32.dll
  Symbol name  : ?CreateToolbar@@YGPAUHWND__@@PAU1 at KIHPAUHINSTANCE__@@IPBU_TBBUTTON@@H at Z
  Type         : code
  Name type    : ordinal
  Ordinal      : 7

  Version      : 0
  Machine      : 14C (i386)
  TimeDateStamp: 40760E7E Fri Apr  9 11:46:22 2004
  SizeOfData   : 0000001E
  DLL name     : COMCTL32.dll
  Symbol name  : _AddMRUStringW at 8
  Type         : code
  Name type    : ordinal
  Ordinal      : 401

  Version      : 0
  Machine      : 14C (i386)
  TimeDateStamp: 40760E7E Fri Apr  9 11:46:22 2004
  SizeOfData   : 0000001F
  DLL name     : COMCTL32.dll
  Symbol name  : _CreateMRUListW at 4
  Type         : code
  Name type    : ordinal
  Ordinal      : 400

  Version      : 0
  Machine      : 14C (i386)
  TimeDateStamp: 40760E7E Fri Apr  9 11:46:22 2004
  SizeOfData   : 00000024
  DLL name     : COMCTL32.dll
  Symbol name  : _CreateMappedBitmap at 20
  Type         : code
  Name type    : ordinal
  Ordinal      : 8

  Version      : 0
  Machine      : 14C (i386)
  TimeDateStamp: 40760E7E Fri Apr  9 11:46:22 2004
  SizeOfData   : 00000028
  DLL name     : COMCTL32.dll
  Symbol name  : _CreatePropertySheetPage at 4
  Type         : code
  Name type    : undecorate
  Hint         : 3

Changelog:
    winedump: Add a partial COFF library support to the winedump.

---
 tools/winedump/Makefile.in |    1 
 tools/winedump/lib.c       |  164 ++++++++++++++++++++++++++++++++++++++++++++
 tools/winedump/main.c      |   19 +++++
 tools/winedump/pe.c        |    2 -
 tools/winedump/winedump.h  |    7 ++
 5 files changed, 190 insertions(+), 3 deletions(-)

diff --git a/tools/winedump/Makefile.in b/tools/winedump/Makefile.in
index 909a135..a670ceb 100644
--- a/tools/winedump/Makefile.in
+++ b/tools/winedump/Makefile.in
@@ -13,6 +13,7 @@ C_SRCS = \
 	dump.c \
 	emf.c \
 	le.c \
+	lib.c \
 	lnk.c \
 	main.c \
 	minidump.c \
diff --git a/tools/winedump/lib.c b/tools/winedump/lib.c
new file mode 100644
index 0000000..e6638a0
--- /dev/null
+++ b/tools/winedump/lib.c
@@ -0,0 +1,164 @@
+/*
+ *  Dump a COFF library (lib) file
+ *
+ * Copyright 2006 Dmitry Timoshkov
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/* FIXME: Add support for import library with the long format described in
+ * Microsoft Portable Executable and Common Object File Format Specification.
+ */
+
+#include "config.h"
+#include "wine/port.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+#include <fcntl.h>
+
+#define NONAMELESSUNION
+#define NONAMELESSSTRUCT
+#include "windef.h"
+#include "winbase.h"
+#include "winnt.h"
+
+#include "winedump.h"
+
+static void dump_import_object(const IMPORT_OBJECT_HEADER *ioh)
+{
+    if (ioh->Version >= 1)
+    {
+#if 0 /* FIXME: supposed to handle uuid.lib but it doesn't */
+        const ANON_OBJECT_HEADER *aoh = (const ANON_OBJECT_HEADER *)ioh;
+
+        printf("CLSID {%08x-%04x-%04x-%02X%02X-%02X%02X%02X%02X%02X%02X}",
+               aoh->ClassID.Data1, aoh->ClassID.Data2, aoh->ClassID.Data3,
+               aoh->ClassID.Data4[0], aoh->ClassID.Data4[1], aoh->ClassID.Data4[2], aoh->ClassID.Data4[3],
+               aoh->ClassID.Data4[4], aoh->ClassID.Data4[5], aoh->ClassID.Data4[6], aoh->ClassID.Data4[7]);
+#endif
+    }
+    else
+    {
+        static const char * const obj_type[] = { "code", "data", "const" };
+        static const char * const name_type[] = { "ordinal", "name", "no prefix", "undecorate" };
+        const char *name;
+
+        printf("  Version      : %X\n", ioh->Version);
+        printf("  Machine      : %X (%s)\n", ioh->Machine, get_machine_str(ioh->Machine));
+        printf("  TimeDateStamp: %08X %s\n", ioh->TimeDateStamp, get_time_str(ioh->TimeDateStamp));
+        printf("  SizeOfData   : %08X\n", ioh->SizeOfData);
+        name = (const char *)ioh + sizeof(*ioh);
+        printf("  DLL name     : %s\n", name + strlen(name) + 1);
+        printf("  Symbol name  : %s\n", name);
+        printf("  Type         : %s\n", (ioh->Type < sizeof(obj_type)/sizeof(obj_type[0])) ? obj_type[ioh->Type] : "unknown");
+        printf("  Name type    : %s\n", (ioh->NameType < sizeof(name_type)/sizeof(name_type[0])) ? name_type[ioh->NameType] : "unknown");
+        printf("  %-13s: %u\n", (ioh->NameType == IMPORT_OBJECT_ORDINAL) ? "Ordinal" : "Hint", ioh->u.Ordinal);
+        printf("\n");
+    }
+}
+
+int dump_lib(const char *lib_name)
+{
+    int fd;
+    struct stat st;
+    long cur_file_pos;
+    char *lib_base;
+    IMAGE_ARCHIVE_MEMBER_HEADER *iamh;
+
+    fd = open(lib_name, O_RDONLY | O_BINARY);
+    if (fd == -1) fatal("Can't open input file");
+
+    if (fstat(fd, &st) < 0) fatal("Can't get input file size");
+    if (st.st_size <= IMAGE_ARCHIVE_START_SIZE) fatal("Not a valid COFF library file");
+
+#ifdef HAVE_MMAP
+    if ((lib_base = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == (void *)-1)
+#endif
+    {
+        if (!(lib_base = malloc(st.st_size)))
+            fatal("Out of memory");
+        if (read(fd, lib_base, st.st_size) != st.st_size)
+            fatal("Cannot read input file");
+    }
+
+    if (strncmp(lib_base, IMAGE_ARCHIVE_START, IMAGE_ARCHIVE_START_SIZE))
+         fatal("Not a valid COFF library file");
+
+    printf("  Contents of \"%s\": %lu bytes\n\n", lib_name, (long)st.st_size);
+
+    iamh = (IMAGE_ARCHIVE_MEMBER_HEADER *)(lib_base + IMAGE_ARCHIVE_START_SIZE);
+    cur_file_pos = IMAGE_ARCHIVE_START_SIZE;
+
+    while (cur_file_pos < st.st_size)
+    {
+        IMPORT_OBJECT_HEADER *ioh;
+        long size;
+
+#if 0 /* left here for debugging purposes, also should be helpful for
+       * adding support for new library formats.
+       */
+        printf("cur_file_pos %08lx\n", (ULONG_PTR)iamh - (ULONG_PTR)lib_base);
+
+        printf("Name %.16s", iamh->Name);
+        if (!strncmp(iamh->Name, IMAGE_ARCHIVE_LINKER_MEMBER, sizeof(iamh->Name)))
+        {
+            printf(" - %s archive linker member\n",
+                   cur_file_pos == IMAGE_ARCHIVE_START_SIZE ? "1st" : "2nd");
+        }
+        else
+            printf("\n");
+        printf("Date %.12s\n", iamh->Date);
+        printf("UserID %.6s\n", iamh->UserID);
+        printf("GroupID %.6s\n", iamh->GroupID);
+        printf("Mode %.8s\n", iamh->Mode);
+        printf("Size %.10s\n", iamh->Size);
+#endif
+        /* FIXME: only import library contents with the short format are
+         * recognized.
+         */
+        ioh = (IMPORT_OBJECT_HEADER *)((char *)iamh + sizeof(IMAGE_ARCHIVE_MEMBER_HEADER));
+        if (ioh->Sig1 == IMAGE_FILE_MACHINE_UNKNOWN && ioh->Sig2 == IMPORT_OBJECT_HDR_SIG2)
+        {
+            dump_import_object(ioh);
+        }
+
+        size = strtoul((const char *)iamh->Size, NULL, 10);
+        size = (size + 1) & ~1; /* align to an even address */
+
+        cur_file_pos += size + sizeof(IMAGE_ARCHIVE_MEMBER_HEADER);
+        iamh = (IMAGE_ARCHIVE_MEMBER_HEADER *)((char *)iamh + size + sizeof(IMAGE_ARCHIVE_MEMBER_HEADER));
+    }
+
+#ifdef HAVE_MMAP
+    if (munmap(lib_base, st.st_size) == -1)
+#endif
+    {
+        free(lib_base);
+    }
+    close(fd);
+
+    return 1;
+}
diff --git a/tools/winedump/main.c b/tools/winedump/main.c
index 36a105b..0c81b69 100644
--- a/tools/winedump/main.c
+++ b/tools/winedump/main.c
@@ -94,6 +94,13 @@ static void do_dumplnk(void)
 }
 
 
+static void do_dumplib(void)
+{
+    if (globals.mode != NONE) fatal("Only one mode can be specified\n");
+    globals.mode = LIB;
+}
+
+
 static void do_code (void)
 {
   globals.do_code = 1;
@@ -238,13 +245,14 @@ static const struct my_option option_tab
   {"-x",    DUMP, 0, do_dumpall,  "-x           Dumps everything"},
   {"emf",   EMF,  0, do_dumpemf,  "emf          Dumps an Enhanced Meta File"},
   {"lnk",   LNK,  0, do_dumplnk,  "lnk          Dumps a shortcut (.lnk) file"},
+  {"lib",   LIB,  0, do_dumplib,  "lib          Dumps a COFF library (.lib) file"},
   {NULL,    NONE, 0, NULL,        NULL}
 };
 
 void do_usage (void)
 {
     const struct my_option *opt;
-    printf ("Usage: winedump [-h | sym <sym> | spec <dll> | dump <dll> | emf <emf> | lnk <lnk>]\n");
+    printf ("Usage: winedump [-h | sym <sym> | spec <dll> | dump <dll> | emf <emf> | lnk <lnk> | lib <lib>]\n");
     printf ("Mode options (can be put as the mode (sym/spec/dump...) is declared):\n");
     printf ("\tWhen used in --help mode\n");
     for (opt = option_table; opt->name; opt++)
@@ -270,6 +278,10 @@ void do_usage (void)
     for (opt = option_table; opt->name; opt++)
 	if (opt->mode == LNK)
 	    printf ("\t   %s\n", opt->usage);
+    printf ("\tWhen used in lib mode\n");
+    for (opt = option_table; opt->name; opt++)
+	if (opt->mode == LIB)
+	    printf ("\t   %s\n", opt->usage);
 
     puts ("");
     exit (1);
@@ -511,6 +523,11 @@ #endif
             fatal("No file name has been given\n");
         dump_lnk(globals.input_name);
         break;
+    case LIB:
+        if (globals.input_name == NULL)
+            fatal("No file name has been given\n");
+        dump_lib(globals.input_name);
+        break;
     }
 
     return 0;
diff --git a/tools/winedump/pe.c b/tools/winedump/pe.c
index d452525..2d31dab 100644
--- a/tools/winedump/pe.c
+++ b/tools/winedump/pe.c
@@ -48,7 +48,7 @@ #include "pe.h"
 
 static const IMAGE_NT_HEADERS32*        PE_nt_headers;
 
-static	const char* get_machine_str(DWORD mach)
+const char *get_machine_str(int mach)
 {
     switch (mach)
     {
diff --git a/tools/winedump/winedump.h b/tools/winedump/winedump.h
index f12b618..909119d 100644
--- a/tools/winedump/winedump.h
+++ b/tools/winedump/winedump.h
@@ -72,7 +72,7 @@ #define SYM_STDCALL         0x2
 #define SYM_THISCALL        0x4
 #define SYM_DATA            0x8 /* Data, not a function */
 
-typedef enum {NONE, DMGL, SPEC, DUMP, EMF, LNK} Mode;
+typedef enum {NONE, DMGL, SPEC, DUMP, EMF, LNK, LIB } Mode;
 
 /* Structure holding a parsed symbol */
 typedef struct __parsed_symbol
@@ -162,6 +162,9 @@ int   dump_emf (const char *emf);
 /* LNK functions */
 int   dump_lnk (const char *lnk);
 
+/* LIB functions */
+int   dump_lib (const char *lib);
+
 /* Image functions */
 void	dump_file(const char* name);
 
@@ -221,6 +224,8 @@ const char *str_find_set (const char *st
 
 char *str_toupper (char *str);
 
+const char *get_machine_str(int mach);
+
 /* file dumping functions */
 enum FileSig {SIG_UNKNOWN, SIG_DOS, SIG_PE, SIG_DBG, SIG_NE, SIG_LE, SIG_MDMP};
 
-- 
1.4.2






More information about the wine-patches mailing list