transforming specmaker in winedump

eric pouech eric.pouech at wanadoo.fr
Wed Aug 29 15:26:34 CDT 2001


this patch transforms the specmaker tool into winedump (which obviously
won Alexandre's contest :-/
it has to be applied into the old specmaker dir
however, the tools/specmaker has to be renamed (as well as configure.in
to be changed), but
that's not included in the patch
the tools/cvdump and tools/specmaker/dll.c are now obsolete
(specmaker.h has been renamed into winedump.h ; the file has been
appended (as a new file) but
not as changes to specmaker.h)

A+
-- 
---------------
Eric Pouech (http://perso.wanadoo.fr/eric.pouech/)
"The future will be better tomorrow", Vice President Dan Quayle
-------------- next part --------------
Name: dump
ChangeLog: added PE dump capabilities to specmaker and renamed specmaker into winedump
GenDate: 2001/08/29 19:38:11 UTC
ModifiedFiles: tools/specmaker/Makefile.in tools/specmaker/main.c tools/specmaker/misc.c tools/specmaker/msmangle.c tools/specmaker/output.c tools/specmaker/search.c tools/specmaker/symbol.c tools/specmaker/README
AddedFiles: tools/specmaker/cvinclude.h tools/specmaker/debug.c tools/specmaker/pe.c tools/specmaker/pe.h tools/specmaker/winedump.h
===================================================================
RCS file: /usr/share/cvs/cvsroot/wine/wine/tools/specmaker/Makefile.in,v
retrieving revision 1.3
diff -u -u -r1.3 Makefile.in
--- tools/specmaker/Makefile.in	2001/03/19 19:19:23	1.3
+++ tools/specmaker/Makefile.in	2001/08/29 19:08:11
@@ -4,15 +4,16 @@
 SRCDIR    = @srcdir@
 VPATH     = @srcdir@
 
-PROGRAMS = specmaker
+PROGRAMS = winedump
 MODULE   = none
 
 C_SRCS = \
-	dll.c  \
+	debug.c \
 	main.c  \
 	misc.c  \
 	msmangle.c  \
 	output.c  \
+	pe.c \
 	search.c  \
 	symbol.c
 
@@ -20,16 +21,16 @@
 
 @MAKE_RULES@
 
-specmaker: $(OBJS)
-	$(CC) $(CFLAGS) -o specmaker $(OBJS) $(LDFLAGS)
+winedump: $(OBJS)
+	$(CC) $(CFLAGS) -o winedump $(OBJS) $(LDFLAGS)
 
 install:: $(PROGRAMS)
 	[ -d $(bindir) ] || $(MKDIR) $(bindir)
-	$(INSTALL_PROGRAM) specmaker $(bindir)/specmaker
+	$(INSTALL_PROGRAM) winedump $(bindir)/winedump
 	$(INSTALL_SCRIPT) $(SRCDIR)/function_grep.pl $(bindir)/function_grep.pl
 
 uninstall::
-	$(RM) $(bindir)/specmaker
+	$(RM) $(bindir)/winedump
 	$(RM) $(bindir)/function_grep.pl
 
 ### Dependencies:
Index: tools/specmaker/main.c
===================================================================
RCS file: /usr/share/cvs/cvsroot/wine/wine/tools/specmaker/main.c,v
retrieving revision 1.3
diff -u -u -r1.3 main.c
--- tools/specmaker/main.c	2001/02/16 19:06:06	1.3
+++ tools/specmaker/main.c	2001/08/29 19:23:46
@@ -3,7 +3,7 @@
  *
  *  Copyright 2000 Jon Griffiths
  */
-#include "specmaker.h"
+#include "winedump.h"
 
 
 _globals globals; /* All global variables */
@@ -32,17 +32,29 @@
 }
 
 
-static void do_input (const char *arg)
+static void do_spec (const char *arg)
 {
-  globals.input_name = strip_ext (arg);
+    if (globals.mode != NONE) fatal("Only one mode can be specified\n");
+    globals.mode = SPEC;
+    globals.input_name = strip_ext (arg);
 }
 
 
 static void do_demangle (const char *arg)
 {
-  globals.do_demangle = 1;
-  globals.do_code = 1;
-  globals.input_name = arg;
+    if (globals.mode != NONE) fatal("Only one mode can be specified\n");
+    globals.mode = DMGL;
+    globals.do_code = 1;
+    globals.input_name = arg;
+}
+
+
+static void do_dump (const char *arg)
+{
+    if (globals.mode != NONE) fatal("Only one mode can be specified\n");
+    globals.mode = DUMP; 
+    globals.do_code = 1;
+    globals.input_name = arg;
 }
 
 
@@ -105,42 +117,82 @@
 }
 
 
+static void do_symdmngl (void)
+{
+    globals.do_demangle = 1;
+}
+
+static void do_dumphead (void)
+{
+    globals.do_dumpheader = 1;
+}
+
+static void do_dumpsect (const char* arg)
+{
+    globals.dumpsect = arg;
+}
+
+static void do_dumpall(void)
+{
+    globals.do_dumpheader = 1;
+    globals.dumpsect = "ALL";
+}
+
 struct option
 {
   const char *name;
+  Mode mode;
   int   has_arg;
   void  (*func) ();
   const char *usage;
 };
 
-
 static const struct option option_table[] = {
-  {"-d", 1, do_input,    "-d dll   Use dll for input file (mandatory)"},
-  {"-S", 1, do_demangle, "-S sym   Demangle C++ symbol 'sym' and exit"},
-  {"-h", 0, do_usage,    "-h       Display this help message"},
-  {"-I", 1, do_include,  "-I dir   Look for prototypes in 'dir' (implies -c)"},
-  {"-o", 1, do_name,     "-o name  Set the output dll name (default: dll)"},
-  {"-c", 0, do_code,     "-c       Generate skeleton code (requires -I)"},
-  {"-t", 0, do_trace,    "-t       TRACE arguments (implies -c)"},
-  {"-f", 1, do_forward,  "-f dll   Forward calls to 'dll' (implies -t)"},
-  {"-D", 0, do_document, "-D       Generate documentation"},
-  {"-C", 0, do_cdecl,    "-C       Assume __cdecl calls (default: __stdcall)"},
-  {"-s", 1, do_start,    "-s num   Start prototype search after symbol 'num'"},
-  {"-e", 1, do_end,      "-e num   End prototype search after symbol 'num'"},
-  {"-q", 0, do_quiet,    "-q       Don't show progress (quiet)."},
-  {"-v", 0, do_verbose,  "-v       Show lots of detail while working (verbose)."},
-  {NULL, 0, NULL, NULL}
+  {"-h",    NONE, 0, do_usage,    "-h           Display this help message"},
+  {"sym",   DMGL, 2, do_demangle, "sym <sym>    Demangle C++ symbol <sym>' and exit"},
+  {"spec",  SPEC, 2, do_spec,     "spec <dll>   Use dll for input file and generate implementation code"},
+  {"-I",    SPEC, 1, do_include,  "-I dir       Look for prototypes in 'dir' (implies -c)"},
+  {"-c",    SPEC, 0, do_code,     "-c           Generate skeleton code (requires -I)"},
+  {"-t",    SPEC, 0, do_trace,    "-t           TRACE arguments (implies -c)"},
+  {"-f",    SPEC, 1, do_forward,  "-f dll       Forward calls to 'dll' (implies -t)"},
+  {"-D",    SPEC, 0, do_document, "-D           Generate documentation"},
+  {"-o",    SPEC, 1, do_name,     "-o name      Set the output dll name (default: dll)"},
+  {"-C",    SPEC, 0, do_cdecl,    "-C           Assume __cdecl calls (default: __stdcall)"},
+  {"-s",    SPEC, 1, do_start,    "-s num       Start prototype search after symbol 'num'"},
+  {"-e",    SPEC, 1, do_end,      "-e num       End prototype search after symbol 'num'"},
+  {"-q",    SPEC, 0, do_quiet,    "-q           Don't show progress (quiet)."},
+  {"-v",    SPEC, 0, do_verbose,  "-v           Show lots of detail while working (verbose)."},
+  {"dump",  DUMP, 2, do_dump,     "dump <dll>   Dumps the content of the dll named <dll>"},
+  {"-C",    DUMP, 0, do_symdmngl, "-C           Turns on symbol demangling"},
+  {"-f",    DUMP, 0, do_dumphead, "-f           Dumps file header information"},
+  {"-j",    DUMP, 1, do_dumpsect, "-j sect_name Dumps only the content of section sect_name (import, export, debug)"},
+  {"-x",    DUMP, 0, do_dumpall,  "-x           Dumps everything"},
+  {NULL,    NONE, 0, NULL,        NULL}
 };
 
-
 void do_usage (void)
 {
-  const struct option *opt;
-  printf ("Usage: specmaker [options] [-d dll | -S sym]\n\nOptions:\n");
-  for (opt = option_table; opt->name; opt++)
-    printf ("   %s\n", opt->usage);
-  puts ("\n");
-  exit (1);
+    const struct option *opt;
+    printf ("Usage: winedump [-h sym <sym> spec <dll> dump <dll>] [mode options]\n");
+    printf ("When used in -h mode\n");
+    for (opt = option_table; opt->name; opt++)
+	if (opt->mode == NONE)
+	    printf ("   %s\n", opt->usage);
+    printf ("When used in sym mode\n");
+    for (opt = option_table; opt->name; opt++)
+	if (opt->mode == DMGL)
+	    printf ("   %s\n", opt->usage);
+    printf ("When used in spec mode\n");
+    for (opt = option_table; opt->name; opt++)
+	if (opt->mode == SPEC)
+	    printf ("   %s\n", opt->usage);
+    printf ("When used in dump mode\n");
+    for (opt = option_table; opt->name; opt++)
+	if (opt->mode == DUMP)
+	    printf ("   %s\n", opt->usage);
+
+    puts ("\n");
+    exit (1);
 }
 
 
@@ -161,14 +213,13 @@
   {
     for (opt = option_table; opt->name; opt++)
     {
-      if (opt->has_arg && !strncmp (*ptr, opt->name, strlen (opt->name)))
+     if (globals.mode != NONE && opt->mode != NONE && globals.mode != opt->mode)
+       continue;
+     if (((opt->has_arg == 1) && !strncmp (*ptr, opt->name, strlen (opt->name))) ||
+	 ((opt->has_arg == 2) && !strcmp (*ptr, opt->name)))
       {
         arg = *ptr + strlen (opt->name);
-        if (*arg == '\0')
-        {
-          ptr++;
-          arg = *ptr;
-        }
+        if (*arg == '\0') arg = *++ptr;
         break;
       }
       if (!strcmp (*ptr, opt->name))
@@ -179,22 +230,19 @@
     }
 
     if (!opt->name)
-      fatal ("Unrecognized option");
+	fatal ("Unrecognized option");
 
     if (opt->has_arg && arg != NULL)
-      opt->func (arg);
+	opt->func (arg);
     else
-      opt->func ("");
-
+	opt->func ("");
+    
     ptr++;
   }
 
-  if (!globals.do_demangle && globals.do_code && !globals.directory)
+  if (globals.mode == SPEC && globals.do_code && !globals.directory)
     fatal ("-I must be used if generating code");
 
-  if (!globals.input_name)
-    fatal ("Option -d is mandatory");
-
   if (VERBOSE && QUIET)
     fatal ("Options -v and -q are mutually exclusive");
 }
@@ -209,73 +257,85 @@
 int   main (int argc, char *argv[])
 #endif
 {
-  parsed_symbol symbol;
-  int count = 0;
-
-  parse_options (argv);
-
-  memset (&symbol, 0, sizeof (parsed_symbol));
-
-  if (globals.do_demangle)
-  {
+    parsed_symbol symbol;
+    int count = 0;
     int result;
-    globals.uc_dll_name = "";
-    VERBOSE = 1;
-    symbol.symbol = strdup(globals.input_name);
-    result = symbol_demangle (&symbol);
-    if (symbol.flags & SYM_DATA)
-      printf (symbol.arg_text[0]);
-    else
-      output_prototype (stdout, &symbol);
-    fputc ('\n', stdout);
-    return result ? 1 : 0;
-  }
 
-  dll_open (globals.input_name);
+    globals.mode = NONE;
 
-  output_spec_preamble ();
-  output_header_preamble ();
-  output_c_preamble ();
+    parse_options (argv);
 
-  while (!dll_next_symbol (&symbol))
-  {
-    count++;
-
-    if (NORMAL)
-      printf ("Export %3d - '%s' ...%c", count, symbol.symbol,
-              VERBOSE ? '\n' : ' ');
+    memset (&symbol, 0, sizeof (parsed_symbol));
 
-    if (globals.do_code && count >= globals.start_ordinal
-        && (!globals.end_ordinal || count <= globals.end_ordinal))
+    switch (globals.mode)
     {
-      /* Attempt to get information about the symbol */
-      int result = symbol_demangle (&symbol);
-
-      if (result)
-        result = symbol_search (&symbol);
-
-      if (!result && symbol.function_name)
-      /* Clean up the prototype */
-        symbol_clean_string (symbol.function_name);
-
-      if (NORMAL)
-        puts (result ? "[Not Found]" : "[OK]");
+    case DMGL:
+	globals.uc_dll_name = "";
+	VERBOSE = 1;
+	symbol.symbol = strdup(globals.input_name);
+	result = symbol_demangle (&symbol);
+	if (symbol.flags & SYM_DATA)
+	    printf (symbol.arg_text[0]);
+	else
+	    output_prototype (stdout, &symbol);
+	fputc ('\n', stdout);
+	return result ? 1 : 0;
+	break;
+    case SPEC:
+	dll_open (globals.input_name);
+
+	output_spec_preamble ();
+	output_header_preamble ();
+	output_c_preamble ();
+
+	while (!dll_next_symbol (&symbol))
+	{
+	    count++;
+
+	    if (NORMAL)
+		printf ("Export %3d - '%s' ...%c", count, symbol.symbol,
+			VERBOSE ? '\n' : ' ');
+
+	    if (globals.do_code && count >= globals.start_ordinal
+		&& (!globals.end_ordinal || count <= globals.end_ordinal))
+	    {
+		/* Attempt to get information about the symbol */
+		int result = symbol_demangle (&symbol);
+
+		if (result)
+		    result = symbol_search (&symbol);
+
+		if (!result && symbol.function_name)
+		    /* Clean up the prototype */
+		    symbol_clean_string (symbol.function_name);
+
+		if (NORMAL)
+		    puts (result ? "[Not Found]" : "[OK]");
+	    }
+	    else if (NORMAL)
+		puts ("[Ignoring]");
+
+	    output_spec_symbol (&symbol);
+	    output_header_symbol (&symbol);
+	    output_c_symbol (&symbol);
+	    
+	    symbol_clear (&symbol);
+	}
+
+	output_makefile ();
+	output_install_script ();
+
+	if (VERBOSE)
+	    puts ("Finished, Cleaning up...");
+	break;
+    case NONE:
+	do_usage();
+	break;
+    case DUMP:
+	globals.uc_dll_name = "";
+	dump_file(globals.input_name);
+	break;
     }
-    else if (NORMAL)
-      puts ("[Ignoring]");
-
-    output_spec_symbol (&symbol);
-    output_header_symbol (&symbol);
-    output_c_symbol (&symbol);
-
-    symbol_clear (&symbol);
-  }
-
-  output_makefile ();
-  output_install_script ();
-
-  if (VERBOSE)
-    puts ("Finished, Cleaning up...");
 
-  return 0;
+    return 0;
 }
Index: tools/specmaker/misc.c
===================================================================
RCS file: /usr/share/cvs/cvsroot/wine/wine/tools/specmaker/misc.c,v
retrieving revision 1.2
diff -u -u -r1.2 misc.c
--- tools/specmaker/misc.c	2001/03/05 19:34:22	1.2
+++ tools/specmaker/misc.c	2001/08/29 19:10:10
@@ -3,7 +3,7 @@
  *
  *  Copyright 2000 Jon Griffiths
  */
-#include "specmaker.h"
+#include "winedump.h"
 
 
 /*******************************************************************
Index: tools/specmaker/msmangle.c
===================================================================
RCS file: /usr/share/cvs/cvsroot/wine/wine/tools/specmaker/msmangle.c,v
retrieving revision 1.4
diff -u -u -r1.4 msmangle.c
--- tools/specmaker/msmangle.c	2001/05/09 17:13:14	1.4
+++ tools/specmaker/msmangle.c	2001/08/29 19:10:17
@@ -3,7 +3,7 @@
  *
  *  Copyright 2000 Jon Griffiths
  */
-#include "specmaker.h"
+#include "winedump.h"
 
 /* Type for parsing mangled types */
 typedef struct _compound_type
Index: tools/specmaker/output.c
===================================================================
RCS file: /usr/share/cvs/cvsroot/wine/wine/tools/specmaker/output.c,v
retrieving revision 1.5
diff -u -u -r1.5 output.c
--- tools/specmaker/output.c	2001/02/16 19:06:06	1.5
+++ tools/specmaker/output.c	2001/08/29 19:10:26
@@ -3,7 +3,7 @@
  *
  *  Copyright 2000 Jon Griffiths
  */
-#include "specmaker.h"
+#include "winedump.h"
 
 /* Output files */
 static FILE *specfile = NULL;
@@ -33,7 +33,7 @@
     puts ("Creating .spec preamble");
 
   fprintf (specfile,
-           "# Generated from %s.dll by specmaker\nname    %s\n"
+           "# Generated from %s.dll by winedump\nname    %s\n"
            "type    win32\ninit    %s_Init\n\nimport kernel32.dll\n"
            "import ntdll.dll\n", globals.input_name, OUTPUT_DLL_NAME,
            OUTPUT_UC_DLL_NAME);
@@ -133,7 +133,7 @@
   atexit (output_header_postamble);
 
   fprintf (hfile,
-           "/*\n * %s.dll\n *\n * Generated from %s.dll by specmaker.\n *\n"
+           "/*\n * %s.dll\n *\n * Generated from %s.dll by winedump.\n *\n"
            " * DO NOT SEND GENERATED DLLS FOR INCLUSION INTO WINE !\n * \n */"
            "\n#ifndef __WINE_%s_DLL_H\n#define __WINE_%s_DLL_H\n\n#include "
            "\"config.h\"\n#include \"windef.h\"\n#include \"debugtools.h\"\n"
@@ -199,7 +199,7 @@
   atexit (output_c_postamble);
 
   fprintf (cfile,
-           "/*\n * %s.dll\n *\n * Generated from %s.dll by specmaker.\n *\n"
+           "/*\n * %s.dll\n *\n * Generated from %s.dll by winedump.\n *\n"
            " * DO NOT SUBMIT GENERATED DLLS FOR INCLUSION INTO WINE!\n * \n */"
            "\n\n#include \"%s_dll.h\"\n\nDEFAULT_DEBUG_CHANNEL(%s);\n\n",
            OUTPUT_DLL_NAME, globals.input_name, OUTPUT_DLL_NAME,
@@ -419,7 +419,7 @@
     puts ("Creating makefile");
 
   fprintf (makefile,
-           "# Generated from %s.dll by specmaker.\nTOPSRCDIR = @top_srcdir@\n"
+           "# Generated from %s.dll by winedump.\nTOPSRCDIR = @top_srcdir@\n"
            "TOPOBJDIR = ../..\nSRCDIR    = @srcdir@\nVPATH     = @srcdir@\n"
            "MODULE    = %s\nEXTRALIBS = $(LIBUNICODE)\n\n"
            "LDDLLFLAGS = @LDDLLFLAGS@\nSYMBOLFILE = $(MODULE).tmp.o\n\n"
@@ -447,7 +447,7 @@
     puts ("Creating install script");
 
   fprintf (install_file,
-           "#!/bin/bash\n# Generated from %s.dll by specmaker.\n\n"
+           "#!/bin/bash\n# Generated from %s.dll by winedump.\n\n"
            "if [ $# -ne 1 ] || [ ! -d $1 ] || [ ! -f"
            " $1/AUTHORS ]; then\n\t[ $# -eq 1 ] && echo \"Invalid path\"\n"
            "\techo \"Usage: $0 wine-base-dir\"\n\texit 1\nfi\n\n"
Index: tools/specmaker/search.c
===================================================================
RCS file: /usr/share/cvs/cvsroot/wine/wine/tools/specmaker/search.c,v
retrieving revision 1.2
diff -u -u -r1.2 search.c
--- tools/specmaker/search.c	2001/02/16 19:06:06	1.2
+++ tools/specmaker/search.c	2001/08/29 19:10:43
@@ -3,7 +3,7 @@
  *
  *  Copyright 2000 Jon Griffiths
  */
-#include "specmaker.h"
+#include "winedump.h"
 
 static char *grep_buff = NULL;
 static char *fgrep_buff = NULL;
Index: tools/specmaker/symbol.c
===================================================================
RCS file: /usr/share/cvs/cvsroot/wine/wine/tools/specmaker/symbol.c,v
retrieving revision 1.2
diff -u -u -r1.2 symbol.c
--- tools/specmaker/symbol.c	2001/02/16 19:06:06	1.2
+++ tools/specmaker/symbol.c	2001/08/29 19:10:51
@@ -3,7 +3,7 @@
  *
  *  Copyright 2000 Jon Griffiths
  */
-#include "specmaker.h"
+#include "winedump.h"
 
 
 /* Items that are swapped in arguments after the symbol structure
Index: tools/specmaker/README
===================================================================
RCS file: /usr/share/cvs/cvsroot/wine/wine/tools/specmaker/README,v
retrieving revision 1.3
diff -u -u -r1.3 README
--- tools/specmaker/README	2001/02/16 19:06:05	1.3
+++ tools/specmaker/README	2001/08/29 19:31:32
@@ -1,5 +1,5 @@
-Specmaker - A Wine DLL tool
----------------------------
+Winedump - A Wine DLL tool
+--------------------------
 
 Background
 ----------
@@ -35,74 +35,61 @@
 B: Compiling a Win32 application with Winelib that uses x86 DLLs
 
 Then you will need to create a .spec file (amongst other things). If you
-won't be doing either of the above, then you won't need specmaker.
+won't be doing either of the above, then you won't need winedump.
 
 Creating a .spec file is a labour intensive task during which it is easy
-to make a mistake. The idea of specmaker is to automate this task and create
+to make a mistake. The idea of winedump is to automate this task and create
 the majority of the support code needed for your DLL. In addition you can
-have specmaker create code to help you reimplement a DLL, by providing
+have winedump create code to help you reimplement a DLL, by providing
 tracing of calls to the DLL, and (in some cases) automatically determining
 the parameters, calling conventions, and return values of the DLLs functions.
 
-You can think of specmaker as somewhat similar to the IMPLIB tool when
+You can think of winedump as somewhat similar to the IMPLIB tool when
 only its basic functionality is used.
 
 
 Usage
 -----
 
-Specmaker is a command line tool. Running it with no arguments or passing
+Winedump is a command line tool. Running it with no arguments or passing
 it '-h' on the command line lists the available options:
 
-Usage: specmaker [options] [-d dll | -S sym]
+Winedump can be used for different usages:
+- generating default source files (.spec, .c...) for using a native DLL in Wine
+- demangling MSVC C++ symbol names
+- dumping the 'PE' files contents
+
+Usage: winedump [-h sym <sym> spec <dll> dump <dll>] [mode options]
+When used in -h mode
+   -h           Display this help message
+When used in sym mode
+   sym <sym>    Demangle C++ symbol <sym>' and exit
+When used in spec mode
+   spec <dll>   Use dll for input file and generate implementation code
+   -I dir       Look for prototypes in 'dir' (implies -c)
+   -c           Generate skeleton code (requires -I)
+   -t           TRACE arguments (implies -c)
+   -f dll       Forward calls to 'dll' (implies -t)
+   -D           Generate documentation
+   -o name      Set the output dll name (default: dll)
+   -C           Assume __cdecl calls (default: __stdcall)
+   -s num       Start prototype search after symbol 'num'
+   -e num       End prototype search after symbol 'num'
+   -q           Don't show progress (quiet).
+   -v           Show lots of detail while working (verbose).
+When used in dump mode
+   dump <dll>   Dumps the content of the dll named <dll>
+   -C           Turns on symbol demangling
+   -f           Dumps file header information
+   -j sect_name Dumps only the content of section sect_name (import, export, debug)
+   -x           Dumps everything
 
-Options:
-   -d dll   Use dll for input file (mandatory)
-   -S sym   Demangle C++ symbol 'sym' and exit
-   -h       Display this help message
-   -I dir   Look for prototypes in 'dir' (implies -c)
-   -o name  Set the output dll name (default: dll)
-   -c       Generate skeleton code (requires -I)
-   -t       TRACE arguments (implies -c)
-   -f dll   Forward calls to 'dll' (implies -t)
-   -D       Generate documentation
-   -C       Assume __cdecl calls (default: __stdcall)
-   -s num   Start prototype search after symbol 'num'
-   -e num   End prototype search after symbol 'num'
-   -q       Don't show progress (quiet).
-   -v       Show lots of detail while working (verbose).
-
-
 Basic options
 -------------
 
-OPTION: -S sym   Demangle C++ symbol 'sym' and exit
-
-The -S option is used to demangle a C++ symbol as it appears in the exports
-section of a dll. This is useful for testing the demangler or implementing
-C++ functions in partially implemented wine DLLS. As an example:
-
-specmaker -S "??3 at YAXPAX@Z"
-
-Gives:
-
-void __cdecl _global_operator_delete_1(void * arg0)
-
-Which is enough information to begin implementing the function.
-
-
-OPTION: -d dll   Use dll for input file (mandatory)
-
-The -d option tells specmaker which DLL you want to create a .spec file
-for. You *must* give this option, unless you are demangling a single symbol
-using the -S argument.
-
-16 bit DLL's are not currently supported (Note that Winelib is intended
-only for Win32 programs).
-
 OPTION: -o name  Set the output dll name (default: dll)
 
-By default, if specmaker is run on DLL 'foo', it creates files called
+By default, if winedump is run on DLL 'foo', it creates files called
 'foo.spec', 'foo_main.c' etc, and prefixes any functions generated
 with 'FOO_'. If '-o bar' is given, these will become 'bar.spec',
 'bar_main.c' and 'BAR_' respectively.
@@ -113,13 +100,13 @@
 OPTION: -q       Don't show progress (quiet).
         -v       Show lots of detail while working (verbose).
 
-There are 3 levels of output while specmaker is running. The default level,
+There are 3 levels of output while winedump is running. The default level,
 when neither -q or -v are given, prints the number of exported functions
 found in the dll, followed by the name of each function as it is processed,
 and a status indication of whether it was processed OK. With -v given, a
-lot of information is dumped while specmaker works: this is intended to help
+lot of information is dumped while winedump works: this is intended to help
 debug any problems. Giving -q means nothing will be printed unless a fatal
-error occurs, and could be used when calling specmaker from a script.
+error occurs, and could be used when calling winedump from a script.
 
 
 OPTION: -C       Assume __cdecl calls (default: __stdcall)
@@ -129,7 +116,7 @@
 used by default, unless this option has been given.
 
 Unless -q is given, a warning will be printed for every function that
-specmaker determines the calling convention for and which does not match
+winedump determines the calling convention for and which does not match
 the assumed calling convention.
 
 
@@ -142,9 +129,9 @@
 As an example, lets assume the application you are porting uses functions
 from a 3rd party dll called 'zipextra.dll', and the functions in the DLL
 use the __stdcall calling convention. Copy zipextra.dll to an empty directory,
-change to it, and run specmaker as follows:
+change to it, and run winedump as follows:
 
-specmaker -d zipextra  (Note: this assumes specmaker is in your path)
+winedump spec zipextra  (Note: this assumes winedump is in your path)
 
 The output will look something like the following:
 
@@ -153,7 +140,7 @@
 Export    2 - '_UnZipFile' ... [Ignoring]
 ...
 
-"[Ignoring]" Just tells you that specmaker isn't trying to determine the
+"[Ignoring]" Just tells you that winedump isn't trying to determine the
 parameters or return types of the functions, its just creating stubs.
 
 The following files are created:
@@ -214,7 +201,7 @@
 Advanced Options
 ----------------
 
-This section discusses features of specmaker that are useful to Wine Hackers
+This section discusses features of winedump that are useful to Wine Hackers
 or developers looking to reimplement a Win32 DLL for Unix. Using these
 features means you will need to be able to resolve compilation problems and
 have a general understanding of Wine programming.
@@ -222,7 +209,7 @@
 
 OPTION: -I dir   Look for prototypes in 'dir' (implies -c)
 
-For all advanced functionality, you must give specmaker a directoryor file that
+For all advanced functionality, you must give winedump a directoryor file that
 contains prototypes for the DLL. In the case of Windows DLLs, this could be
 either the standard include directory from your compiler, or an SDK include
 directory. If you have a text document with prototypes (such as documentation)
@@ -232,7 +219,7 @@
 The 'dir' argument can also be a file specification (e.g. "include/*"). If
 it contains wildcards you must quote it to prevent the shell from expanding it.
 
-If you have no prototypes, specify /dev/null for 'dir'. Specmaker may still
+If you have no prototypes, specify /dev/null for 'dir'. Winedump may still
 be able to generate some working stub code for you.
 
 Once you have created your DLL, if you generated code (see below), you can
@@ -241,11 +228,11 @@
 allows you to add names to the function arguments, for example, so that the
 comments and prototype in the regenerated DLL will be clearer.
 
-Specmaker searches for prototypes using 'grep', and then retrieves each
+Winedump searches for prototypes using 'grep', and then retrieves each
 prototype by calling 'function_grep.pl', a Perl script. When you pass the -v
 option on the command line, the calls to both of these programs are logged.
 This allows you to see where each function definition has come from. Should
-specmaker take an excessively long time to locate a prototype, you can check
+winedump take an excessively long time to locate a prototype, you can check
 that it is searching the right files; you may want to limit the number of files
 searched if locating the prototype takes too long.
 
@@ -256,7 +243,7 @@
 OPTION: -s num   Start prototype search after symbol 'num'
         -e num   End prototype search after symbol 'num'
 
-By passing the -s or -e options you can have specmaker try to generate code
+By passing the -s or -e options you can have winedump try to generate code
 for only some functions in your DLL. This may be used to generate a single
 function, for example, if you wanted to add functionality to an existing DLL.
 
@@ -265,19 +252,19 @@
 
 OPTION: -D       Generate documentation
 
-By default, specmaker generates a standard comment at the header of each
-function it generates. Passing this option makes specmaker output a full
+By default, winedump generates a standard comment at the header of each
+function it generates. Passing this option makes winedump output a full
 header template for standard Wine documentation, listing the parameters
 and return value of the function.
 
 
 OPTION: -c       Generate skeleton code (requires -I)
 
-This option tells specmaker that you want to create function stubs for
+This option tells winedump that you want to create function stubs for
 each function in the DLL. This is the most basic level of code generation.
-As specmaker reads each exported symbol from the source DLL, it first tries
+As winedump reads each exported symbol from the source DLL, it first tries
 to demangle the name. If the name is a C++ symbol, the arguments, class and
-return value are all encoded into the symbol name. Specmaker converts this
+return value are all encoded into the symbol name. Winedump converts this
 information into a C function prototype. If this fails, the file(s) specified
 in the -I argument are scanned for a function prototype. If one is found it
 is used for the next step of the process, code generation.
@@ -286,7 +273,7 @@
 used is not documented, it must be decoded. Many simple prototypes are already
 working however.
 
-If specmaker does not find a prototype, it emits code like the following:
+If winedump does not find a prototype, it emits code like the following:
 
 In the .spec file:
 
@@ -324,7 +311,7 @@
   return 0;
 }
 
-Note that if the prototype does not contain argument names, specmaker will
+Note that if the prototype does not contain argument names, winedump will
 add them following the convention arg0, arg1 ... argN. If the function is
 demangled C++, the first argument will be called '_this' if an implicit this
 pointer is passed (i.e. the function is a non-static class member function).
@@ -405,7 +392,7 @@
 to change the ouput name of our DLL to something else, and used the -f
 option to forward to the real zipextra DLL:
 
-specmaker -d zipextra -f zipextra -o myzipextra -I "~/zipextra/include/*h"
+winedump spec zipextra -f zipextra -o myzipextra -I "~/zipextra/include/*h"
 
 Then in the .spec file for our Winelib application, we add the line:
 
@@ -427,7 +414,7 @@
 call to the real DLL. A similar feature in wine is +relay debugging. Using a
 fowarding DLL allows more granular reporting of arguments, because you can
 write code to dump out the contents of types/structures rather than just
-their address in memory. A future version of specmaker may generate this
+their address in memory. A future version of winedump may generate this
 code automatically for common Win32 types.
 
 See below for more information on setting up a forwarding DLL.
@@ -457,7 +444,7 @@
 normally be added as an include to the generated DLL header. For other DLLs
 I suggest creating a seperate header in the DLL directory and adding any
 needed types to that. This allows you to rebuild the DLL at whim, for example
-if a new version of specmaker brings increased functionality, then you
+if a new version of winedump brings increased functionality, then you
 only have to overwrite the generated files and re-include the header to take
 advantage of it.
 
@@ -468,10 +455,10 @@
 change to the generated code was one line in the header to include the type
 definitions.
 
-To save some typing in case you don't have headers for your DLL type, specmaker
+To save some typing in case you don't have headers for your DLL type, winedump
 will dump dummy declarations for unknown classes and types it encounters,
 if you use the -v option. These can be piped directly into a fix-up header
-file for use in compiling your DLL. For example, if specmaker encounters the
+file for use in compiling your DLL. For example, if winedump encounters the
 (C++ ) symbol:
 
 ??0foobar@@QAE at ABV0@@Z   (Which is a constructor for a foobar object)
@@ -485,12 +472,12 @@
 The output should be piped through 'sort' and 'uniq' to remove multiple
 declarations, e.g:
 
-specmaker -d foo -c -I "inc/*.h" -v | grep FIXME | sort | uniq > fixup.h
+winedump -d foo -c -I "inc/*.h" -v | grep FIXME | sort | uniq > fixup.h
 
 By adding '#include "fixup.h"' to foobar_dll.h your compile errors will be
 greatly reduced.
 
-If specmaker encounters a type it doesnt know that is passed by value (as in
+If winedump encounters a type it doesnt know that is passed by value (as in
 the _cabs example above), it also prints a FIXME message like:
 
 /* FIXME: By value type: Assumed 'int' */ typedef int ldiv_t;
@@ -512,19 +499,19 @@
 First we create the forwarding DLL. We will rename the real msvcrt.dll on our
 system to ms_msvcrt.dll, and our msvcrt implementation will call it:
 
-specmaker -d msvcrt -C -f ms_msvcrt -I "inc/*.h"
+winedump spec msvcrt -C -f ms_msvcrt -I "inc/*.h"
 
 We then install this DLL into the Wine tree and add the types we need to
 make it compile. Once the DLL compiles, we create a dummy ms_msvcrt DLL so
-winebuild will resolve our forward calls to it (for the cases where specmaker
+winebuild will resolve our forward calls to it (for the cases where winedump
 couldn't generate code and has placed an '@forward' line in the .spec file):
 
-specmaker -d msvcrt -C -o ms_msvcrt
+winedump spec msvcrt -C -o ms_msvcrt
 
 Install this DLL into the wine tree (since its a stub DLL, no changes are
 needed to the code).
 
-Now uncomment the line that specmaker inserted into msvcrt.spec:
+Now uncomment the line that winedump inserted into msvcrt.spec:
 
 #inport ms_msvcrt.dll
 
@@ -556,7 +543,7 @@
 I want to know what _E and _G represent.
 
 If you encounter a C++ symbol that doesn't demangle **AND** you have the
-prototype for it, please send me the symbol as reported by specmaker and the
+prototype for it, please send me the symbol as reported by winedump and the
 prototype. The more examples I have the easier it is to decypher the scheme,
 and generating them myself is very slow.
 
@@ -575,3 +562,44 @@
 [1] See the Wine and Wine.conf man pages for details on how to tell Wine
     whether to use native (Win32) or internal DLLs.
 
+
+Demangling
+----------
+
+If you need to demangle a single C++ symbol, you can use the demangling mode
+of winedump. This is useful for testing the demangler or implementing
+C++ functions in partially implemented wine DLLS. As an example:
+
+winedump sym "??3 at YAXPAX@Z"
+
+Gives:
+
+void __cdecl _global_operator_delete_1(void * arg0)
+
+Which is enough information to begin implementing the function.
+
+
+Dumping
+-------
+
+Another tool might be helpful digging into a 32bit DLL (and any PE image file):
+pedump.
+
+Usage:
+   -h           Display this help message
+   -d <dll>     Use dll for input file and generate implementation code
+   -C           Turns on symbol demangling
+   -f           Dumps file header information
+   -j dir_name  Dumps only the content of directory dir_name (import, export, debug)
+   -x           Dumps everything
+
+The basic usage, to look everything in a file is:
+winedump dump -d mydll.dll -x
+
+It'll print any available information on the file. This information can be splitted
+into sub-categories:
+- file hedaers (request by -f or -x) are made of the standard PE header structures, 
+  plus the COFF sections
+- directories: you can print them one after the other using the -j switch. Currently, 
+  only the import, export and debug directories are implemented.
+- -x displays the file headers and any available directory.
--- /dev/null	Wed Sep 27 12:31:54 2000
+++ tools/specmaker/cvinclude.h	Fri Aug 17 18:32:16 2001
@@ -0,0 +1,172 @@
+/*
+ * CodeView 4 Debug format - declarations
+ *
+ * (based on cvinfo.h and cvexefmt.h from the Win32 SDK)
+ */
+
+#define sstModule           0x120
+#define sstAlignSym         0x125
+#define sstSrcModule        0x127
+#define sstLibraries        0x128
+#define sstGlobalSym        0x129
+#define sstGlobalPub        0x12a
+#define sstGlobalTypes      0x12b
+#define sstSegMap           0x12d
+#define sstFileIndex        0x133
+#define sstStaticSym        0x134
+
+#if 0
+/* Old, crusty value */
+#define S_PUB32             0x0203
+#endif
+
+#define S_PUB32             0x1009
+
+#include "pshpack1.h"
+
+/*
+ * CodeView headers
+ */
+
+typedef struct OMFSignature 
+{
+    char        Signature[4];
+    long        filepos;
+} OMFSignature;
+
+typedef struct OMFDirHeader 
+{
+    unsigned short  cbDirHeader;
+    unsigned short  cbDirEntry;
+    unsigned long   cDir;
+    long            lfoNextDir;
+    unsigned long   flags;
+} OMFDirHeader;
+
+typedef struct OMFDirEntry 
+{
+    unsigned short  SubSection;
+    unsigned short  iMod;
+    long            lfo;
+    unsigned long   cb;
+} OMFDirEntry;
+
+
+/*
+ * sstModule subsection
+ */
+
+typedef struct OMFSegDesc 
+{
+    unsigned short  Seg;
+    unsigned short  pad;
+    unsigned long   Off;
+    unsigned long   cbSeg;
+} OMFSegDesc;
+
+/* Must chop off the OMFSegDesc* field, because we need to write this
+ * struct out to a file.  If we write the whole struct out, we'll end up
+ * with (*OMFSegDesc), not (OMFSegDesc).  See OMFModuleFull.
+ */
+typedef struct OMFModule 
+{
+    unsigned short  ovlNumber;
+    unsigned short  iLib;
+    unsigned short  cSeg;
+    char            Style[2];
+} OMFModule;
+
+/* Full version, with memory pointers, too.  Use OMFModule for writing out to
+ * a file, and OMFModuleFull for reading.  If offsetof() were available, we
+ * could use that instead.
+ */
+typedef struct OMFModuleFull
+{
+    unsigned short  ovlNumber;
+    unsigned short  iLib;
+    unsigned short  cSeg;
+    char            Style[2];
+    OMFSegDesc      *SegInfo;
+    char            *Name;
+} OMFModuleFull;
+
+
+/*
+ * sstGlobalPub section
+ */
+
+/* Header for symbol table.
+ */
+typedef struct OMFSymHash 
+{
+    unsigned short  symhash;
+    unsigned short  addrhash;
+    unsigned long   cbSymbol;
+    unsigned long   cbHSym;
+    unsigned long   cbHAddr;
+} OMFSymHash;
+
+/* Symbol table entry.
+ */
+typedef struct DATASYM32 
+{
+    unsigned short  reclen;
+    unsigned short  rectyp;
+    unsigned long   typind;
+    unsigned long   off;
+    unsigned short  seg;
+} DATASYM32;
+typedef DATASYM32 PUBSYM32;
+
+/*
+ * sstSegMap section
+ */
+
+typedef struct OMFSegMapDesc
+{
+    unsigned short  flags;
+    unsigned short  ovl;
+    unsigned short  group;
+    unsigned short  frame;
+    unsigned short  iSegName;
+    unsigned short  iClassName;
+    unsigned long   offset;
+    unsigned long   cbSeg;
+} OMFSegMapDesc;
+
+typedef struct OMFSegMap
+{
+    unsigned short  cSeg;
+    unsigned short  cSegLog;
+    OMFSegMapDesc   rgDesc[0];
+} OMFSegMap;
+
+
+/*
+ * sstSrcModule section
+ */
+
+typedef struct OMFSourceLine
+{
+    unsigned short  Seg;
+    unsigned short  cLnOff;
+    unsigned long   offset[1];
+    unsigned short  lineNbr[1];
+} OMFSourceLine;
+
+typedef struct OMFSourceFile
+{
+    unsigned short  cSeg;
+    unsigned short  reserved;
+    unsigned long   baseSrcLn[1];
+    unsigned short  cFName;
+    char            Name;
+} OMFSourceFile;
+
+typedef struct OMFSourceModule
+{
+    unsigned short  cFile;
+    unsigned short  cSeg;
+    unsigned long   baseSrcFile[1];
+} OMFSourceModule;
+
--- /dev/null	Wed Sep 27 12:31:54 2000
+++ tools/specmaker/debug.c	Wed Aug 29 21:09:34 2001
@@ -0,0 +1,464 @@
+/*
+ * Made after:
+ *	CVDump - Parses through a Visual Studio .DBG file in CodeView 4 format
+ * 	and dumps the info to STDOUT in a human-readable format
+ *
+ * 	Copyright 2000 John R. Sheets
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+
+#include "winnt.h"
+#include "winedump.h"
+#include "pe.h"
+#include "cvinclude.h"
+
+/*
+ * .DBG File Layout:
+ *
+ * IMAGE_SEPARATE_DEBUG_HEADER
+ * IMAGE_SECTION_HEADER[]
+ * IMAGE_DEBUG_DIRECTORY[]
+ * OMFSignature
+ * debug data (typical example)
+ *   - IMAGE_DEBUG_TYPE_MISC
+ *   - IMAGE_DEBUG_TYPE_FPO
+ *   - IMAGE_DEBUG_TYPE_CODEVIEW
+ * OMFDirHeader
+ * OMFDirEntry[]
+ */
+
+/*
+ * Descriptions:
+ *
+ * (hdr)  IMAGE_SEPARATE_DEBUG_HEADER - .DBG-specific file header; holds info that 
+ *        applies to the file as a whole, including # of COFF sections, file offsets, etc.
+ * (hdr)  IMAGE_SECTION_HEADER - list of COFF sections copied verbatim from .EXE;
+ *        although this directory contains file offsets, these offsets are meaningless
+ *        in the context of the .DBG file, because only the section headers are copied
+ *        to the .DBG file...not the binary data it points to.
+ * (hdr)  IMAGE_DEBUG_DIRECTORY - list of different formats of debug info contained in file
+ *        (see IMAGE_DEBUG_TYPE_* descriptions below); tells where each section starts
+ * (hdr)  OMFSignature (CV) - Contains "NBxx" signature, plus file offset telling how far
+ *        into the IMAGE_DEBUG_TYPE_CODEVIEW section the OMFDirHeader and OMFDirEntry's sit
+ * (data) IMAGE_DEBUG_TYPE_MISC - usually holds name of original .EXE file
+ * (data) IMAGE_DEBUG_TYPE_FPO - Frame Pointer Optimization data; used for dealing with
+ *        optimized stack frames (optional)
+ * (data) IMAGE_DEBUG_TYPE_CODEVIEW - *** THE GOOD STUFF ***
+ *        This block of data contains all the symbol tables, line number info, etc.,
+ *        that the Visual C++ debugger needs.
+ * (hdr)  OMFDirHeader (CV) - 
+ * (hdr)  OMFDirEntry (CV) - list of subsections within CodeView debug data section
+ */
+
+/*
+ * The .DBG file typically has three arrays of directory entries, which tell
+ * the OS or debugger where in the file to look for the actual data
+ *
+ * IMAGE_SECTION_HEADER - number of entries determined by:
+ *    (IMAGE_SEPARATE_DEBUG_HEADER.NumberOfSections)
+ *
+ * IMAGE_DEBUG_DIRECTORY - number of entries determined by:
+ *    (IMAGE_SEPARATE_DEBUG_HEADER.DebugDirectorySize / sizeof (IMAGE_DEBUG_DIRECTORY))
+ *
+ * OMFDirEntry - number of entries determined by:
+ *    (OMFDirHeader.cDir)
+ */
+
+static	void*		cv_base /* = 0 */;
+
+static int dump_cv_sst_module(OMFDirEntry* omfde)
+{
+    OMFModule*	module;
+    OMFSegDesc*	segDesc;
+    int		i;
+
+    module = PRD(Offset(cv_base) + omfde->lfo, sizeof(OMFModule));
+    if (!module) {printf("Can't get the OMF-Module, aborting\n"); return FALSE;}
+
+    printf("    olvNumber:          %u\n", module->ovlNumber);
+    printf("    iLib:               %u\n", module->iLib);
+    printf("    cSeg:               %u\n", module->cSeg);
+    printf("    Style:              %c%c\n", module->Style[0], module->Style[1]);
+    printf("    Name:               %.*s\n", 
+	   *(BYTE*)((char*)(module + 1) + sizeof(OMFSegDesc) * module->cSeg),
+	   (char*)(module + 1) + sizeof(OMFSegDesc) * module->cSeg + 1);
+
+    segDesc = PRD(Offset(module + 1), sizeof(OMFSegDesc) * module->cSeg);
+    if (!segDesc) {printf("Can't get the OMF-SegDesc, aborting\n"); return FALSE;}
+
+    for (i = 0; i < module->cSeg; i++)
+    {
+	printf ("      segment #%2d: offset = [0x%8lx], size = [0x%8lx]\n",
+		segDesc->Seg, segDesc->Off, segDesc->cbSeg);
+	segDesc++;
+    }
+    return TRUE;
+}
+
+static int dump_cv_sst_global_pub(OMFDirEntry* omfde)
+{
+    long	fileoffset;
+    OMFSymHash* header;
+    BYTE*	symbols;
+    BYTE*	curpos;
+    PUBSYM32*	sym;
+    unsigned 	symlen;
+    int		recordlen;
+    char 	nametmp[256];
+
+    fileoffset = Offset(cv_base) + omfde->lfo;
+    printf ("    GlobalPub section starts at file offset 0x%lx\n", fileoffset);
+    printf ("    Symbol table starts at 0x%lx\n", fileoffset + sizeof (OMFSymHash));
+
+    printf ("\n                           ----- Begin Symbol Table -----\n");
+    printf ("      (type)      (symbol name)                 (offset)      (len) (seg) (ind)\n");
+
+    header = PRD(fileoffset, sizeof(OMFSymHash));
+    if (!header) {printf("Can't get OMF-SymHash, aborting\n");return FALSE;}
+
+    symbols = PRD(fileoffset + sizeof(OMFSymHash), header->cbSymbol);
+    if (!symbols) {printf("Can't OMF-SymHash details, aborting\n"); return FALSE;}
+
+    /* We don't know how many symbols are in this block of memory...only what
+     * the total size of the block is.  Because the symbol's name is tacked
+     * on to the end of the PUBSYM32 struct, each symbol may take up a different
+     * # of bytes.  This makes it harder to parse through the symbol table,
+     * since we won't know the exact location of the following symbol until we've
+     * already parsed the current one.
+     */
+    for (curpos = symbols; curpos < symbols + header->cbSymbol; curpos += recordlen)
+    {
+	/* Point to the next PUBSYM32 in the table.
+	 */
+	sym = (PUBSYM32*)curpos;
+
+	if (sym->reclen < sizeof(PUBSYM32)) break;
+
+	symlen = sym->reclen - sizeof(PUBSYM32) + 1;
+	if (symlen > sizeof(nametmp)) {printf("\nsqueeze%d\n", symlen);symlen = sizeof(nametmp) - 1;}
+
+	memcpy(nametmp, curpos + sizeof (PUBSYM32) + 1, symlen);
+	nametmp[symlen] = '\0';
+
+	printf ("      0x%04x  %-30.30s  [0x%8lx]  [0x%4x]  %d     %ld\n",
+		sym->rectyp, nametmp, sym->off, sym->reclen, sym->seg, sym->typind);
+
+	/* The entire record is null-padded to the nearest 4-byte
+	 * boundary, so we must do a little extra math to keep things straight.
+	 */
+	recordlen = (sym->reclen + 3) & ~3;
+    }
+
+    return TRUE;
+}
+
+static int dump_cv_sst_global_sym(OMFDirEntry* omfde)
+{
+    /*** NOT YET IMPLEMENTED ***/
+    return TRUE;
+}
+
+static int dump_cv_sst_static_sym(OMFDirEntry* omfde)
+{
+    /*** NOT YET IMPLEMENTED ***/
+    return TRUE;
+}
+
+static int dump_cv_sst_libraries(OMFDirEntry* omfde)
+{
+    /*** NOT YET IMPLEMENTED ***/
+    return TRUE;
+}
+
+static int dump_cv_sst_global_types(OMFDirEntry* omfde)
+{
+    /*** NOT YET IMPLEMENTED ***/
+    return TRUE;
+}
+
+static int dump_cv_sst_seg_map(OMFDirEntry* omfde)
+{
+    OMFSegMap*		segMap;
+    OMFSegMapDesc*	segMapDesc;
+    int		i;
+
+    segMap = PRD(Offset(cv_base) + omfde->lfo, sizeof(OMFSegMap));
+    if (!segMap) {printf("Can't get SegMap, aborting\n");return FALSE;}
+
+    printf("    cSeg:          %u\n", segMap->cSeg);
+    printf("    cSegLog:       %u\n", segMap->cSegLog);
+
+    segMapDesc = PRD(Offset(segMap + 1), segMap->cSeg * sizeof(OMFSegDesc));
+    if (!segMapDesc) {printf("Can't get SegDescr array, aborting\n");return FALSE;}
+    
+    for (i = 0; i < segMap->cSeg; i++)
+    {
+	printf("    SegDescr #%2d\n", i + 1);
+	printf("      flags:         %04X\n", segMapDesc[i].flags);
+	printf("      ovl:           %u\n", segMapDesc[i].ovl);
+	printf("      group:         %u\n", segMapDesc[i].group);
+	printf("      frame:         %u\n", segMapDesc[i].frame);
+	printf("      iSegName:      %u\n", segMapDesc[i].iSegName);
+	printf("      iClassName:    %u\n", segMapDesc[i].iClassName);
+	printf("      offset:        %lu\n", segMapDesc[i].offset);
+	printf("      cbSeg:         %lu\n", segMapDesc[i].cbSeg);
+    }
+
+    return TRUE;
+}
+
+static int dump_cv_sst_file_index(OMFDirEntry* omfde)
+{
+    /*** NOT YET IMPLEMENTED ***/
+    return TRUE;
+}
+
+static int dump_cv_sst_src_module(OMFDirEntry* omfde)
+{
+    int 		i, j;
+    BYTE*		rawdata;
+    unsigned long*	seg_info_dw;
+    unsigned short*	seg_info_w;
+    unsigned		ofs;
+    OMFSourceModule*	sourceModule;
+    OMFSourceFile*	sourceFile;
+    OMFSourceLine*	sourceLine;
+
+    rawdata = PRD(Offset(cv_base) + omfde->lfo, omfde->cb);
+    if (!rawdata) {printf("Can't get srcModule subsection details, aborting\n");return FALSE;}
+
+    /* FIXME: check ptr validity */
+    sourceModule = (void*)rawdata;
+    printf ("    Module table: Found %d file(s) and %d segment(s)\n", 
+	    sourceModule->cFile, sourceModule->cSeg);
+    for (i = 0; i < sourceModule->cFile; i++)
+    {
+	printf ("      File #%2d begins at an offset of 0x%lx in this section\n",
+		i + 1, sourceModule->baseSrcFile[i]);
+    }
+
+    /* FIXME: check ptr validity */
+    seg_info_dw = (void*)((char*)(sourceModule + 1) + 
+			  sizeof(unsigned long) * (sourceModule->cFile - 1));
+    seg_info_w = (unsigned short*)(&seg_info_dw[sourceModule->cSeg * 2]);
+    for (i = 0; i <  sourceModule->cSeg; i++)
+    {
+	printf ("      Segment #%2d start = 0x%lx, end = 0x%lx, seg index = %u\n",
+		i + 1, seg_info_dw[i * 2], seg_info_dw[(i * 2) + 1], 
+		seg_info_w[i]);
+    }
+    ofs = sizeof(OMFSourceModule) + sizeof(unsigned long) * (sourceModule->cFile - 1) + 
+	sourceModule->cSeg * (2 * sizeof(unsigned long) + sizeof(unsigned short));
+    ofs = (ofs + 3) & ~3;
+
+    /* the OMFSourceFile is quite unpleasant to use:
+     * we have first:
+     * 	unsigned short	number of segments
+     *	unsigned short	reservered
+     *	unsigned long	baseSrcLn[# segments]
+     *  unsigned long	offset[2 * #segments]
+     *				odd indices are start offsets
+     *				even indices are end offsets
+     * 	unsigned char	string length for file name
+     *	char		file name (length is previous field)
+     */
+    /* FIXME: check ptr validity */
+    sourceFile = (void*)(rawdata + ofs);
+    seg_info_dw = (void*)((char*)sourceFile + 2 * sizeof(unsigned short) + 
+			  sourceFile->cSeg * sizeof(unsigned long));
+
+    ofs += 2 * sizeof(unsigned short) + 3 * sourceFile->cSeg * sizeof(unsigned long);
+
+    printf("    File table: %.*s\n", 
+	   *(BYTE*)((char*)sourceModule + ofs), (char*)sourceModule + ofs + 1);
+
+    for (i = 0; i < sourceFile->cSeg; i++)
+    {
+	printf ("      Segment #%2d start = 0x%lx, end = 0x%lx, offset = 0x%lx\n",
+		i + 1, seg_info_dw[i * 2], seg_info_dw[(i * 2) + 1], sourceFile->baseSrcLn[i]);
+    }
+    /* add file name length */
+    ofs += *(BYTE*)((char*)sourceModule + ofs) + 1;
+    ofs = (ofs + 3) & ~3;
+
+    for (i = 0; i < sourceModule->cSeg; i++) 
+    {
+	sourceLine = (void*)(rawdata + ofs);
+	seg_info_dw = (void*)((char*)sourceLine + 2 * sizeof(unsigned short));
+	seg_info_w = (void*)(&seg_info_dw[sourceLine->cLnOff]);
+	
+	printf ("    Line table #%2d: Found %d line numbers for segment index %d\n",
+		i, sourceLine->cLnOff, sourceLine->Seg);
+	
+	for (j = 0; j < sourceLine->cLnOff; j++)
+	{
+	    printf ("      Pair #%2d: offset = [0x%8lx], linenumber = %d\n",
+		    j + 1, seg_info_dw[j], seg_info_w[j]);
+	}
+	ofs += 2 * sizeof(unsigned short) + 
+	    sourceLine->cLnOff * (sizeof(unsigned long) + sizeof(unsigned short));
+	ofs = (ofs + 3) & ~3;
+    }
+
+    return TRUE;
+}
+
+static int dump_cv_sst_align_sym(OMFDirEntry* omfde)
+{
+    /*** NOT YET IMPLEMENTED ***/
+
+    return TRUE;
+}
+
+static void dump_codeview_all_modules(OMFDirHeader *omfdh)
+{
+    int 		i;
+    OMFDirEntry	       *dirEntry;
+    const char*		str;
+
+    if (!omfdh || !omfdh->cDir) return;
+
+    dirEntry = PRD(Offset(omfdh + 1), omfdh->cDir * sizeof(OMFDirEntry));
+    if (!dirEntry) {printf("Can't read DirEntry array, aborting\n"); return;}
+
+    for (i = 0; i < omfdh->cDir; i++)
+    {
+	switch (dirEntry[i].SubSection)
+	{
+	case sstModule:		str = "sstModule";	break;
+	case sstAlignSym:	str = "sstAlignSym";	break;
+	case sstSrcModule:	str = "sstSrcModule";	break;
+	case sstLibraries:	str = "sstLibraries";	break;
+	case sstGlobalSym:	str = "sstGlobalSym";	break;
+	case sstGlobalPub:	str = "sstGlobalPub";	break;
+	case sstGlobalTypes:	str = "sstGlobalTypes";	break;
+	case sstSegMap:		str = "sstSegMap";	break;
+	case sstFileIndex:	str = "sstFileIndex";	break;
+	case sstStaticSym:	str = "sstStaticSym";	break;
+	default:		str = "<undefined>";	break;
+	}
+	printf("Module #%2d (%p)\n", i + 1, &dirEntry[i]);
+	printf("  SubSection:            %04X (%s)\n", dirEntry[i].SubSection, str);
+	printf("  iMod:                  %d\n", dirEntry[i].iMod);
+	printf("  lfo:                   %ld\n", dirEntry[i].lfo);
+	printf("  cb:                    %lu\n", dirEntry[i].cb);
+
+	switch (dirEntry[i].SubSection)
+	{
+	case sstModule:		dump_cv_sst_module(&dirEntry[i]);	break;
+	case sstAlignSym:	dump_cv_sst_align_sym(&dirEntry[i]);	break;
+	case sstSrcModule:	dump_cv_sst_src_module(&dirEntry[i]);	break;
+	case sstLibraries:	dump_cv_sst_libraries(&dirEntry[i]);	break;
+	case sstGlobalSym:	dump_cv_sst_global_sym(&dirEntry[i]);	break;
+	case sstGlobalPub:	dump_cv_sst_global_pub(&dirEntry[i]);	break;
+	case sstGlobalTypes:	dump_cv_sst_global_types(&dirEntry[i]);	break;
+	case sstSegMap:		dump_cv_sst_seg_map(&dirEntry[i]);	break;
+	case sstFileIndex:	dump_cv_sst_file_index(&dirEntry[i]);	break;
+	case sstStaticSym:	dump_cv_sst_static_sym(&dirEntry[i]);	break;
+	default:		printf("unsupported type %x\n", dirEntry[i].SubSection); break;
+	}
+	printf("\n");
+    }
+
+    return;
+}
+
+static void dump_codeview_headers(unsigned long base, unsigned long len)
+{
+    OMFDirHeader	*dirHeader;
+    OMFSignature	*signature;
+    OMFDirEntry		*dirEntry;
+    int			i;
+    int modulecount = 0, alignsymcount = 0, srcmodulecount = 0, librariescount = 0;
+    int globalsymcount = 0, globalpubcount = 0, globaltypescount = 0;
+    int segmapcount = 0, fileindexcount = 0, staticsymcount = 0;
+    
+    cv_base = PRD(base, len);
+    if (!cv_base) {printf("Can't get full debug content, aborting\n");return;}
+
+    signature = cv_base;
+
+    printf("    CodeView Data\n");
+
+    printf("      Signature:         %.4s\n", signature->Signature);
+    printf("      Filepos:           0x%08lX\n", signature->filepos);
+
+    if (memcmp(signature->Signature, "NB10", 4) == 0)
+    {
+	struct {DWORD TimeStamp; DWORD  Dunno; char Name[1];}* pdb_data;
+	pdb_data = (void*)(signature + 1);
+
+	printf("        TimeStamp:            %08lX (%s)\n", 
+	       pdb_data->TimeStamp, get_time_str(pdb_data->TimeStamp));
+	printf("        Dunno:                %08lX\n", pdb_data->Dunno);
+	printf("        Filename:             %s\n", pdb_data->Name);
+	return;
+    } 
+
+    if (memcmp(signature->Signature, "NB09", 4) != 0 && memcmp(signature->Signature, "NB11", 4) != 0)
+    {
+	printf("Unsupported signature, aborting\n");
+	return;
+    }
+
+    dirHeader = PRD(Offset(cv_base) + signature->filepos, sizeof(OMFDirHeader));
+    if (!dirHeader) {printf("Can't get debug header, aborting\n"); return;}
+
+    printf("      Size of header:    0x%4X\n", dirHeader->cbDirHeader);
+    printf("      Size per entry:    0x%4X\n", dirHeader->cbDirEntry);
+    printf("      # of entries:      0x%8lX (%ld)\n", dirHeader->cDir, dirHeader->cDir);
+    printf("      Offset to NextDir: 0x%8lX\n", dirHeader->lfoNextDir);
+    printf("      Flags:             0x%8lX\n", dirHeader->flags);
+
+    if (!dirHeader->cDir) return;
+
+    dirEntry = PRD(Offset(dirHeader + 1), sizeof(OMFDirEntry) * dirHeader->cDir);
+    if (!dirEntry) {printf("Can't get DirEntry array, aborting\n");return;}
+
+    for (i = 0; i < dirHeader->cDir; i++)
+    {
+	switch (dirEntry[i].SubSection)
+	{
+	case sstModule:		modulecount++;		break;
+	case sstAlignSym:	alignsymcount++;	break;
+	case sstSrcModule:	srcmodulecount++;	break;
+	case sstLibraries:	librariescount++;	break;
+	case sstGlobalSym:	globalsymcount++;	break;
+	case sstGlobalPub:	globalpubcount++;	break;
+	case sstGlobalTypes:	globaltypescount++;	break;
+	case sstSegMap:		segmapcount++;		break;
+	case sstFileIndex:	fileindexcount++;	break;
+	case sstStaticSym:	staticsymcount++;	break;
+	}	
+    }
+
+    /* This one has to be > 0
+     */
+    printf ("\nFound: %d sstModule subsections\n", modulecount);
+
+    if (alignsymcount > 0)    printf ("       %d sstAlignSym subsections\n", alignsymcount);
+    if (srcmodulecount > 0)   printf ("       %d sstSrcModule subsections\n", srcmodulecount);
+    if (librariescount > 0)   printf ("       %d sstLibraries subsections\n", librariescount);
+    if (globalsymcount > 0)   printf ("       %d sstGlobalSym subsections\n", globalsymcount);
+    if (globalpubcount > 0)   printf ("       %d sstGlobalPub subsections\n", globalpubcount);
+    if (globaltypescount > 0) printf ("       %d sstGlobalTypes subsections\n", globaltypescount);
+    if (segmapcount > 0)      printf ("       %d sstSegMap subsections\n", segmapcount);
+    if (fileindexcount > 0)   printf ("       %d sstFileIndex subsections\n", fileindexcount);
+    if (staticsymcount > 0)   printf ("       %d sstStaticSym subsections\n", staticsymcount);
+
+    dump_codeview_all_modules(dirHeader);
+}
+
+void	dump_codeview(unsigned long base, unsigned long len)
+{
+    dump_codeview_headers(base, len);
+}
+
--- /dev/null	Wed Sep 27 12:31:54 2000
+++ tools/specmaker/pe.c	Wed Aug 29 21:10:34 2001
@@ -0,0 +1,847 @@
+/*
+ *	PE dumping utility
+ *
+ * 	Copyright 2001 Eric Pouech
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+
+#include "winnt.h"
+#include "winedump.h"
+#include "pe.h"
+
+static void*			base;
+static long			total_len;
+static IMAGE_NT_HEADERS*	nt_headers;
+
+enum FileSig {SIG_UNKNOWN, SIG_DOS, SIG_PE, SIG_DBG};
+
+char*	get_time_str(DWORD _t)
+{
+    time_t 	t = (time_t)_t;
+    static char	buf[128];
+    
+    /* FIXME: I don't get the same values from MS' pedump running under Wine... 
+     * I wonder if Wine isn't broken wrt to GMT settings...
+     */
+    strncpy(buf, ctime(&t), sizeof(buf));
+    buf[sizeof(buf) - 1] = '\0';
+    if (buf[strlen(buf)-1] == '\n')
+	buf[strlen(buf)-1] = '\0';
+    return buf;
+}
+
+static	const char* get_machine_str(DWORD mach)
+{
+    switch (mach)
+    {
+    case IMAGE_FILE_MACHINE_UNKNOWN:	return "Unknown";
+    case IMAGE_FILE_MACHINE_I860:	return "i860";
+    case IMAGE_FILE_MACHINE_I386:	return "i386";
+    case IMAGE_FILE_MACHINE_R3000:	return "R3000";
+    case IMAGE_FILE_MACHINE_R4000:	return "R4000";
+    case IMAGE_FILE_MACHINE_R10000:	return "R10000";
+    case IMAGE_FILE_MACHINE_ALPHA:	return "Alpha";
+    case IMAGE_FILE_MACHINE_POWERPC:	return "PowerPC";
+    }
+    return "???";
+}
+
+void*	PRD(unsigned long prd, unsigned long len)
+{
+    return (prd + len > total_len) ? NULL : (char*)base + prd;
+}
+
+unsigned long Offset(void* ptr)
+{
+    if (ptr < base) {printf("<<<<<ptr below\n");return 0;}
+    if (ptr >= base + total_len) {printf("<<<<<ptr above\n");return 0;}
+    return ptr - base;
+}
+
+void*	RVA(unsigned long rva, unsigned long len)
+{
+    IMAGE_SECTION_HEADER*	sectHead;
+    int				i;
+    
+    sectHead = (IMAGE_SECTION_HEADER*)((char*)nt_headers + sizeof(DWORD) + 
+				       sizeof(IMAGE_FILE_HEADER) + 
+				       nt_headers->FileHeader.SizeOfOptionalHeader);
+    
+    if (rva == 0) return NULL;
+    
+    for (i = nt_headers->FileHeader.NumberOfSections - 1; i >= 0; i--)
+    {
+        if (sectHead[i].VirtualAddress <= rva &&
+            rva + len <= (DWORD)sectHead[i].VirtualAddress + sectHead[i].SizeOfRawData)
+            break;
+    }
+    
+    if (i < 0) 
+    {
+	printf("rva not found in any section (%lu)\n", rva);
+        return NULL;
+    }
+    
+    /* return image import directory offset */
+    return PRD(sectHead[i].PointerToRawData + rva - sectHead[i].VirtualAddress, len);
+}
+
+static	void*	get_dir(unsigned idx)
+{
+    if (idx >= nt_headers->OptionalHeader.NumberOfRvaAndSizes)
+	return NULL;
+    return RVA(nt_headers->OptionalHeader.DataDirectory[idx].VirtualAddress,
+	       nt_headers->OptionalHeader.DataDirectory[idx].Size);
+}
+
+static const char*	DirectoryNames[16] = {
+    "EXPORT",		"IMPORT",	"RESOURCE", 	"EXCEPTION", 	
+    "SECURITY", 	"BASERELOC", 	"DEBUG", 	"ARCHITECTURE", 
+    "GLOBALPTR", 	"TLS", 		"LOAD_CONFIG",	"Bound IAT", 
+    "IAT", 		"Delay IAT",	"COM Descript", ""
+};
+
+static	void	dump_pe_header(void)
+{
+    char			*str;
+    IMAGE_FILE_HEADER		*fileHeader;
+    IMAGE_OPTIONAL_HEADER	*optionalHeader;
+    int				i;
+    
+    printf("File Header\n");
+    fileHeader = &nt_headers->FileHeader;
+    
+    printf("  Machine:                      %04X (%s)\n", 
+	   fileHeader->Machine, get_machine_str(fileHeader->Machine));
+    printf("  Number of Sections:           %d\n", fileHeader->NumberOfSections);
+    printf("  TimeDateStamp:                %08lX (%s) offset %ld\n", 
+	   fileHeader->TimeDateStamp, get_time_str(fileHeader->TimeDateStamp), 
+	   Offset(&(fileHeader->TimeDateStamp)));
+    printf("  PointerToSymbolTable:         %08lX\n", fileHeader->PointerToSymbolTable);
+    printf("  NumberOfSymbols:              %08lX\n", fileHeader->NumberOfSymbols);
+    printf("  SizeOfOptionalHeader:         %04X\n", fileHeader->SizeOfOptionalHeader);
+    printf("  Characteristics:              %04X\n", fileHeader->Characteristics);
+#define	X(f,s)	if (fileHeader->Characteristics & f) printf("    %s\n", s)
+    X(IMAGE_FILE_RELOCS_STRIPPED, 	"RELOCS_STRIPPED");
+    X(IMAGE_FILE_EXECUTABLE_IMAGE, 	"EXECUTABLE_IMAGE");
+    X(IMAGE_FILE_LINE_NUMS_STRIPPED, 	"LINE_NUMS_STRIPPED");
+    X(IMAGE_FILE_LOCAL_SYMS_STRIPPED, 	"LOCAL_SYMS_STRIPPED");
+    X(IMAGE_FILE_16BIT_MACHINE, 	"16BIT_MACHINE");
+    X(IMAGE_FILE_BYTES_REVERSED_LO, 	"BYTES_REVERSED_LO");
+    X(IMAGE_FILE_32BIT_MACHINE, 	"32BIT_MACHINE");
+    X(IMAGE_FILE_DEBUG_STRIPPED, 	"DEBUG_STRIPPED");
+    X(IMAGE_FILE_SYSTEM, 		"SYSTEM");
+    X(IMAGE_FILE_DLL, 			"DLL");
+    X(IMAGE_FILE_BYTES_REVERSED_HI, 	"BYTES_REVERSED_HI");
+#undef X
+    printf("\n");
+    
+    /* hope we have the right size */
+    printf("Optional Header\n");
+    optionalHeader = &nt_headers->OptionalHeader;
+    printf("  Magic                              0x%-4X         %u\n", 
+	   optionalHeader->Magic, optionalHeader->Magic);
+    printf("  linker version                     %u.%02u\n", 
+	   optionalHeader->MajorLinkerVersion, optionalHeader->MinorLinkerVersion);
+    printf("  size of code                       0x%-8lx     %lu\n", 
+	   optionalHeader->SizeOfCode, optionalHeader->SizeOfCode);
+    printf("  size of initialized data           0x%-8lx     %lu\n", 
+	   optionalHeader->SizeOfInitializedData, optionalHeader->SizeOfInitializedData);
+    printf("  size of uninitialized data         0x%-8lx     %lu\n", 
+	   optionalHeader->SizeOfUninitializedData, optionalHeader->SizeOfUninitializedData);
+    printf("  entrypoint RVA                     0x%-8lx     %lu\n", 
+	   optionalHeader->AddressOfEntryPoint, optionalHeader->AddressOfEntryPoint);
+    printf("  base of code                       0x%-8lx     %lu\n", 
+	   optionalHeader->BaseOfCode, optionalHeader->BaseOfCode);
+    printf("  base of data                       0x%-8lX     %lu\n", 
+	   optionalHeader->BaseOfData, optionalHeader->BaseOfData);
+    printf("  image base                         0x%-8lX     %lu\n", 
+	   optionalHeader->ImageBase, optionalHeader->ImageBase);
+    printf("  section align                      0x%-8lx     %lu\n", 
+	   optionalHeader->SectionAlignment, optionalHeader->SectionAlignment);
+    printf("  file align                         0x%-8lx     %lu\n", 
+	   optionalHeader->FileAlignment, optionalHeader->FileAlignment);
+    printf("  required OS version                %u.%02u\n", 
+	   optionalHeader->MajorOperatingSystemVersion, optionalHeader->MinorOperatingSystemVersion);
+    printf("  image version                      %u.%02u\n", 
+	   optionalHeader->MajorImageVersion, optionalHeader->MinorImageVersion);
+    printf("  subsystem version                  %u.%02u\n", 
+	   optionalHeader->MajorSubsystemVersion, optionalHeader->MinorSubsystemVersion);
+    printf("  Win32 Version                      0x%lX\n", optionalHeader->Win32VersionValue);
+    printf("  size of image                      0x%-8lx     %lu\n", 
+	   optionalHeader->SizeOfImage, optionalHeader->SizeOfImage);
+    printf("  size of headers                    0x%-8lx     %lu\n", 
+	   optionalHeader->SizeOfHeaders, optionalHeader->SizeOfHeaders);
+    printf("  checksum                           0x%lX\n", optionalHeader->CheckSum);
+    switch (optionalHeader->Subsystem)
+    {
+    default:
+    case IMAGE_SUBSYSTEM_UNKNOWN: 	str = "Unknown"; 	break;
+    case IMAGE_SUBSYSTEM_NATIVE: 	str = "Native"; 	break;
+    case IMAGE_SUBSYSTEM_WINDOWS_GUI: 	str = "Windows GUI"; 	break;
+    case IMAGE_SUBSYSTEM_WINDOWS_CUI: 	str = "Windows CUI"; 	break;
+    case IMAGE_SUBSYSTEM_OS2_CUI: 	str = "OS/2 CUI"; 	break;
+    case IMAGE_SUBSYSTEM_POSIX_CUI: 	str = "Posix CUI"; 	break;
+    }
+    printf("  Subsystem                          0x%X (%s)\n", optionalHeader->Subsystem, str);
+    printf("  DLL flags                          0x%X\n", optionalHeader->DllCharacteristics);
+    printf("  stack reserve size                 0x%-8lx     %lu\n", 
+	   optionalHeader->SizeOfStackReserve, optionalHeader->SizeOfStackReserve);
+    printf("  stack commit size                  0x%-8lx     %lu\n",
+	   optionalHeader->SizeOfStackCommit, optionalHeader->SizeOfStackCommit);
+    printf("  heap reserve size                  0x%-8lx     %lu\n", 
+	   optionalHeader->SizeOfHeapReserve, optionalHeader->SizeOfHeapReserve);
+    printf("  heap commit size                   0x%-8lx     %lu\n", 
+	   optionalHeader->SizeOfHeapCommit, optionalHeader->SizeOfHeapCommit);
+    printf("  loader flags                       0x%lX\n", optionalHeader->LoaderFlags);
+    printf("  RVAs & sizes                       0x%lX\n", optionalHeader->NumberOfRvaAndSizes);
+    printf("\n");
+    
+    printf("Data Directory\n");
+    printf("%ld\n", optionalHeader->NumberOfRvaAndSizes * sizeof(IMAGE_DATA_DIRECTORY));
+    
+    for (i = 0; i < optionalHeader->NumberOfRvaAndSizes && i < 16; i++)
+    {
+	printf("  %-12s rva: 0x%-8lX  size: %8lu\n", 
+	       DirectoryNames[i], optionalHeader->DataDirectory[i].VirtualAddress, 
+	       optionalHeader->DataDirectory[i].Size);
+    }
+    printf("\n");
+}
+
+static	void	dump_sections(void* addr, unsigned num_sect)
+{
+    IMAGE_SECTION_HEADER*	sectHead = addr;
+    int				i;
+    
+    printf("Section Table\n");
+    for (i = 0; i < num_sect; i++, sectHead++)
+    {
+	printf("  %02d %-8s   VirtSize: %-8lu  VirtAddr:  %-8lu 0x%08lx\n", 
+	       i + 1, sectHead->Name, sectHead->Misc.VirtualSize, sectHead->VirtualAddress, 
+	       sectHead->VirtualAddress);
+	printf("    raw data offs: %-8lu raw data size: %-8lu\n", 
+	       sectHead->PointerToRawData, sectHead->SizeOfRawData);
+	printf("    relocation offs: %-8lu  relocations:   %-8u\n", 
+	       sectHead->PointerToRelocations, sectHead->NumberOfRelocations);
+	printf("    line # offs:     %-8lu  line #'s:      %-8u\n",
+	       sectHead->PointerToLinenumbers, sectHead->NumberOfLinenumbers);
+	printf("    characteristics: 0x$%08lx\n", sectHead->Characteristics);
+	printf("      ");
+#define X(b,s)	if (sectHead->Characteristics & b) printf(s "  ")
+/* #define IMAGE_SCN_TYPE_REG			0x00000000 - Reserved */
+/* #define IMAGE_SCN_TYPE_DSECT			0x00000001 - Reserved */
+/* #define IMAGE_SCN_TYPE_NOLOAD		0x00000002 - Reserved */
+/* #define IMAGE_SCN_TYPE_GROUP			0x00000004 - Reserved */
+/* #define IMAGE_SCN_TYPE_NO_PAD		0x00000008 - Reserved */
+/* #define IMAGE_SCN_TYPE_COPY			0x00000010 - Reserved */
+	
+	X(IMAGE_SCN_CNT_CODE, 			"CODE");
+	X(IMAGE_SCN_CNT_INITIALIZED_DATA, 	"INITIALIZED_DATA");
+	X(IMAGE_SCN_CNT_UNINITIALIZED_DATA, 	"UNINITIALIZED_DATA");
+	
+	X(IMAGE_SCN_LNK_OTHER, 			"LNK_OTHER");
+	X(IMAGE_SCN_LNK_INFO, 			"LNK_INFO");
+/* #define	IMAGE_SCN_TYPE_OVER		0x00000400 - Reserved */
+	X(IMAGE_SCN_LNK_REMOVE, 		"LNK_REMOVE");
+	X(IMAGE_SCN_LNK_COMDAT, 		"LNK_COMDAT");
+	
+/* 						0x00002000 - Reserved */
+/* #define IMAGE_SCN_MEM_PROTECTED 		0x00004000 - Obsolete */
+	X(IMAGE_SCN_MEM_FARDATA, 		"MEM_FARDATA");
+	
+/* #define IMAGE_SCN_MEM_SYSHEAP		0x00010000 - Obsolete */
+	X(IMAGE_SCN_MEM_PURGEABLE, 		"MEM_PURGEABLE");
+	X(IMAGE_SCN_MEM_16BIT, 			"MEM_16BIT");
+	X(IMAGE_SCN_MEM_LOCKED, 		"MEM_LOCKED");
+	X(IMAGE_SCN_MEM_PRELOAD, 		"MEM_PRELOAD");
+	
+	X(IMAGE_SCN_ALIGN_1BYTES, 		"ALIGN_1BYTES");
+	X(IMAGE_SCN_ALIGN_2BYTES, 		"ALIGN_2BYTES");
+	X(IMAGE_SCN_ALIGN_4BYTES, 		"ALIGN_4BYTES");
+	X(IMAGE_SCN_ALIGN_8BYTES, 		"ALIGN_8BYTES");
+	X(IMAGE_SCN_ALIGN_16BYTES, 		"ALIGN_16BYTES");
+	X(IMAGE_SCN_ALIGN_32BYTES, 		"ALIGN_32BYTES");
+	X(IMAGE_SCN_ALIGN_64BYTES, 		"ALIGN_64BYTES");
+/* 						0x00800000 - Unused */
+	
+	X(IMAGE_SCN_LNK_NRELOC_OVFL, 		"LNK_NRELOC_OVFL");
+	
+	X(IMAGE_SCN_MEM_DISCARDABLE, 		"MEM_DISCARDABLE");
+	X(IMAGE_SCN_MEM_NOT_CACHED, 		"MEM_NOT_CACHED");
+	X(IMAGE_SCN_MEM_NOT_PAGED, 		"MEM_NOT_PAGED");
+	X(IMAGE_SCN_MEM_SHARED, 		"MEM_SHARED");
+	X(IMAGE_SCN_MEM_EXECUTE, 		"MEM_EXECUTE");
+	X(IMAGE_SCN_MEM_READ, 			"MEM_READ");
+	X(IMAGE_SCN_MEM_WRITE, 			"MEM_WRITE");
+#undef X
+	printf("\n\n");
+    }
+    printf("\n");
+}
+
+static	void	dump_dir_exported_functions(void)
+{
+    IMAGE_EXPORT_DIRECTORY	*exportDir = get_dir(IMAGE_FILE_EXPORT_DIRECTORY);
+    unsigned			i, j;
+    DWORD*			pFunc;
+    DWORD*			pName;
+    WORD*			pOrdl;
+    DWORD*			map;
+    parsed_symbol		symbol;
+    
+    if (!exportDir) return;
+    
+    printf("Exports table:\n");
+    printf("\n");
+    printf("  Name:            %s\n", (char*)RVA(exportDir->Name, sizeof(DWORD)));
+    printf("  Characteristics: %08lx\n", exportDir->Characteristics);
+    printf("  TimeDateStamp:   %08lX %s\n", 
+	   exportDir->TimeDateStamp, get_time_str(exportDir->TimeDateStamp));
+    printf("  Version:         %u.%02u\n", exportDir->MajorVersion, exportDir->MinorVersion);
+    printf("  Ordinal base:    %lu\n", exportDir->Base);
+    printf("  # of functions:  %lu\n", exportDir->NumberOfFunctions);
+    printf("  # of Names:      %lu\n", exportDir->NumberOfNames);
+    printf("Adresses of functions: %08lX\n", exportDir->AddressOfFunctions);
+    printf("Adresses of name ordinals: %08lX\n", exportDir->AddressOfNameOrdinals);
+    printf("Adresses of names: %08lX\n", exportDir->AddressOfNames);
+    printf("\n");
+    printf("  Entry Pt  Ordn  Name\n");
+    
+    pFunc = RVA(exportDir->AddressOfFunctions, exportDir->NumberOfFunctions * sizeof(DWORD));
+    if (!pFunc) {printf("Can't grab functions' address table\n"); return;}
+    pName = RVA(exportDir->AddressOfNames, exportDir->NumberOfNames * sizeof(DWORD));
+    if (!pName) {printf("Can't grab functions' name table\n"); return;}
+    pOrdl = RVA(exportDir->AddressOfNameOrdinals, exportDir->NumberOfNames * sizeof(WORD));
+    if (!pOrdl) {printf("Can't grab functions' ordinal table\n"); return;}
+    
+    /* bit map of used funcs */
+    map = calloc(((exportDir->NumberOfFunctions + 31) & ~31) / 32, sizeof(DWORD));
+    if (!map) fatal("no memory");
+    
+    for (i = 0; i < exportDir->NumberOfNames; i++)
+    {
+	char*	name;
+	
+	map[*pOrdl / 32] |= 1 << (*pOrdl % 32);
+	
+	name = (char*)RVA(*pName++, sizeof(DWORD));
+	if (name && globals.do_demangle)
+	{
+	    symbol.symbol = strdup(name);
+	    symbol_demangle (&symbol);
+	    
+	    printf("  %08lX  %4lu ", *pFunc++, exportDir->Base + *pOrdl++);
+	    if (symbol.flags & SYM_DATA)
+		printf (symbol.arg_text[0]);
+	    else
+		output_prototype(stdout, &symbol);
+	    printf("\n");
+	}
+	else
+	{
+	    printf("  %08lX  %4lu %s\n", *pFunc++, exportDir->Base + *pOrdl++, name);
+	}
+    }
+    pFunc = RVA(exportDir->AddressOfFunctions, exportDir->NumberOfFunctions * sizeof(DWORD));
+    if (!pFunc) {printf("Can't grab functions' address table\n"); return;}
+    j = exportDir->NumberOfNames;
+    for (i = 0; i < exportDir->NumberOfFunctions; i++)
+    {
+	if (!(map[i / 32] & (1 << (i % 32))))
+	{
+	    printf("  %08lX  %4lu <by ordinal>\n", pFunc[j++], exportDir->Base + i);
+	}
+    }
+    free(map);
+    printf("\n");
+}
+
+static	void	dump_dir_imported_functions(void)
+{
+    IMAGE_IMPORT_DESCRIPTOR	*importDesc = get_dir(IMAGE_FILE_IMPORT_DIRECTORY);
+    unsigned			nb_imp, i;
+    
+    if (!importDesc)	return;
+    nb_imp = nt_headers->OptionalHeader.DataDirectory[IMAGE_FILE_IMPORT_DIRECTORY].Size / 
+	sizeof(*importDesc);
+    if (!nb_imp) return;
+    
+    printf("Import Table size: %lu\n", 
+	   nt_headers->OptionalHeader.DataDirectory[IMAGE_FILE_IMPORT_DIRECTORY].Size);/* FIXME */
+    
+    for (i = 0; i < nb_imp - 1; i++) /* the last descr is set as 0 as a sentinel */
+    {
+	IMAGE_THUNK_DATA*	il;
+	IMAGE_IMPORT_BY_NAME*	iibn;
+	
+	if (!importDesc->Name || 
+	    (importDesc->u.OriginalFirstThunk == NULL && importDesc->FirstThunk == NULL))
+	{
+	    /* FIXME */
+	    printf("<<<<<<<null entry\n");
+	    break;
+	}
+	printf("  offset %lu %s\n", Offset(importDesc), (char*)RVA(importDesc->Name, sizeof(DWORD)));
+	printf("  Hint/Name Table: %08lX\n", (DWORD)importDesc->u.OriginalFirstThunk);
+	printf("  TimeDataStamp:   %08lX (%s)\n", 
+	       importDesc->TimeDateStamp, get_time_str(importDesc->TimeDateStamp));
+	printf("  ForwarderChain:  %08lX\n", importDesc->ForwarderChain);
+	printf("  First thunk RVA: %08lX (delta: %u 0x%x)\n", 
+	       (DWORD)importDesc->FirstThunk, -1, -1); /* FIXME */
+	
+	printf("  Ordn  Name\n");
+	
+	il = (importDesc->u.OriginalFirstThunk != 0) ? 
+	    RVA((DWORD)importDesc->u.OriginalFirstThunk, sizeof(DWORD)) : 
+	    RVA((DWORD)importDesc->FirstThunk, sizeof(DWORD));
+	
+	if (!il) {printf("Can't grab thunk data, going to next imported DLL\n"); continue;}
+	
+	for (; il->u1.Ordinal; il++)
+	{
+	    if (IMAGE_SNAP_BY_ORDINAL(il->u1.Ordinal)) 
+	    {
+		printf("  %4lu  <by ordinal>\n", IMAGE_ORDINAL(il->u1.Ordinal));
+	    }
+	    else
+	    {
+		iibn = RVA((DWORD)il->u1.AddressOfData, sizeof(DWORD));
+		if (!il) 
+		{
+		    printf("Can't grab import by name info, skipping to next ordinal\n"); 
+		}
+		else
+		{
+		    printf("  %4u  %s %lx\n", iibn->Hint, iibn->Name, (DWORD)il->u1.AddressOfData);
+		}
+	    }
+	}
+	printf("\n");
+	importDesc++;
+    }
+    printf("\n");
+}
+
+static	void	dump_dir_debug_dir(IMAGE_DEBUG_DIRECTORY* idd, int idx)
+{
+    const	char*	str;
+    
+    printf("Directory %02u\n", idx + 1);
+    printf("  Characteristics:   %08lX\n", idd->Characteristics);
+    printf("  TimeDateStamp:     %08lX %s\n", 
+	   idd->TimeDateStamp, get_time_str(idd->TimeDateStamp));
+    printf("  Version            %u.%02u\n", idd->MajorVersion, idd->MinorVersion);
+    switch (idd->Type)
+    {
+    default:
+    case IMAGE_DEBUG_TYPE_UNKNOWN:	str = "UNKNOWN"; 	break;
+    case IMAGE_DEBUG_TYPE_COFF:		str = "COFF"; 		break;
+    case IMAGE_DEBUG_TYPE_CODEVIEW:	str = "CODEVIEW"; 	break;
+    case IMAGE_DEBUG_TYPE_FPO:		str = "FPO"; 		break;
+    case IMAGE_DEBUG_TYPE_MISC:		str = "MISC"; 		break;
+    case IMAGE_DEBUG_TYPE_EXCEPTION:	str = "EXCEPTION"; 	break;
+    case IMAGE_DEBUG_TYPE_FIXUP:	str = "FIXUP"; 		break;
+    case IMAGE_DEBUG_TYPE_OMAP_TO_SRC:	str = "OMAP_TO_SRC"; 	break;
+    case IMAGE_DEBUG_TYPE_OMAP_FROM_SRC:str = "OMAP_FROM_SRC"; 	break;
+    case IMAGE_DEBUG_TYPE_BORLAND:	str = "BORLAND"; 	break;
+    case IMAGE_DEBUG_TYPE_RESERVED10:	str = "RESERVED10"; 	break;
+    }
+    printf("  Type:              %lu (%s)\n", idd->Type, str);
+    printf("  SizeOfData:        %lu\n", idd->SizeOfData);
+    printf("  AddressOfRawData:  %08lX\n", idd->AddressOfRawData);
+    printf("  PointerToRawData:  %08lX\n", idd->PointerToRawData);
+    
+    switch (idd->Type)
+    {
+    case IMAGE_DEBUG_TYPE_UNKNOWN:		
+	break;
+    case IMAGE_DEBUG_TYPE_COFF:		
+	break;
+    case IMAGE_DEBUG_TYPE_CODEVIEW:
+	dump_codeview(idd->PointerToRawData, idd->SizeOfData);
+	break;
+    case IMAGE_DEBUG_TYPE_FPO:	
+	break;
+    case IMAGE_DEBUG_TYPE_MISC:
+    {
+	IMAGE_DEBUG_MISC* misc = PRD(idd->PointerToRawData, idd->SizeOfData);
+	if (!misc) {printf("Can't get misc debug information\n"); break;}
+	printf("    DataType:          %lu (%s)\n", 
+	       misc->DataType, 
+	       (misc->DataType == IMAGE_DEBUG_MISC_EXENAME) ? "Exe name" : "Unknown");
+	printf("    Length:            %lu\n", misc->Length);
+	printf("    Unicode:           %s\n", misc->Unicode ? "Yes" : "No");
+	printf("    Data:              %s\n", misc->Data);
+    }
+    break;
+    case IMAGE_DEBUG_TYPE_EXCEPTION:
+	break;
+    case IMAGE_DEBUG_TYPE_FIXUP:	
+	break;
+    case IMAGE_DEBUG_TYPE_OMAP_TO_SRC:
+	break;
+    case IMAGE_DEBUG_TYPE_OMAP_FROM_SRC:
+	break;
+    case IMAGE_DEBUG_TYPE_BORLAND:		
+	break;
+    case IMAGE_DEBUG_TYPE_RESERVED10:
+	break;
+    }
+    printf("\n");
+}
+
+static void	dump_dir_debug(void)
+{
+    IMAGE_DEBUG_DIRECTORY*	debugDir = get_dir(IMAGE_FILE_DEBUG_DIRECTORY);
+    unsigned			nb_dbg, i;
+    
+    if (!debugDir) return;
+    nb_dbg = nt_headers->OptionalHeader.DataDirectory[IMAGE_FILE_DEBUG_DIRECTORY].Size / 
+	sizeof(*debugDir);
+    if (!nb_dbg) return;
+    
+    printf("Debug Table (%u directories)\n", nb_dbg);
+    
+    for (i = 0; i < nb_dbg; i++)
+    {
+	dump_dir_debug_dir(debugDir, i);
+	debugDir++;
+    }
+    printf("\n");
+}
+
+static void	dump_separate_dbg(void)
+{
+    IMAGE_SEPARATE_DEBUG_HEADER*separateDebugHead = PRD(0, sizeof(separateDebugHead));
+    unsigned			nb_dbg;
+    unsigned			i;
+    IMAGE_DEBUG_DIRECTORY*	debugDir;
+    
+    if (!separateDebugHead) {printf("Can't grab the separate header, aborting\n"); return;}
+    
+    printf ("Signature:          %.2s (0x%4X)\n", 
+	    (char*)&separateDebugHead->Signature, separateDebugHead->Signature);
+    printf ("Flags:              0x%04X\n", separateDebugHead->Flags);
+    printf ("Machine:            0x%04X (%s)\n", 
+	    separateDebugHead->Machine, get_machine_str(separateDebugHead->Machine));
+    printf ("Characteristics:    0x%04X\n", separateDebugHead->Characteristics);
+    printf ("TimeDateStamp:      0x%08lX (%s)\n", 
+	    separateDebugHead->TimeDateStamp, get_time_str(separateDebugHead->TimeDateStamp));
+    printf ("CheckSum:           0x%08lX\n", separateDebugHead->CheckSum);
+    printf ("ImageBase:          0x%08lX\n", separateDebugHead->ImageBase);
+    printf ("SizeOfImage:        0x%08lX\n", separateDebugHead->SizeOfImage);
+    printf ("NumberOfSections:   0x%08lX\n", separateDebugHead->NumberOfSections);
+    printf ("ExportedNamesSize:  0x%08lX\n", separateDebugHead->ExportedNamesSize);
+    printf ("DebugDirectorySize: 0x%08lX\n", separateDebugHead->DebugDirectorySize);
+    
+    if (!PRD(sizeof(IMAGE_SEPARATE_DEBUG_HEADER), 
+	     separateDebugHead->NumberOfSections * sizeof(IMAGE_SECTION_HEADER)))
+    {printf("Can't get the sections, aborting\n"); return;}
+    
+    dump_sections(separateDebugHead + 1, separateDebugHead->NumberOfSections);
+    
+    nb_dbg = separateDebugHead->DebugDirectorySize / sizeof(IMAGE_DEBUG_DIRECTORY);
+    debugDir = PRD(sizeof(IMAGE_SEPARATE_DEBUG_HEADER) + 	
+		   separateDebugHead->NumberOfSections * sizeof(IMAGE_SECTION_HEADER) +
+		   separateDebugHead->ExportedNamesSize,
+		   nb_dbg * sizeof(IMAGE_DEBUG_DIRECTORY));
+    if (!debugDir) {printf("Couldn't get the debug directory info, aborting\n");return;}
+    
+    printf("Debug Table (%u directories)\n", nb_dbg);
+    
+    for (i = 0; i < nb_dbg; i++)
+    {
+	dump_dir_debug_dir(debugDir, i);
+	debugDir++;
+    }
+}
+
+static	void	do_dump(void)
+{
+    int	all = (globals.dumpsect != NULL) && strcmp(globals.dumpsect, "ALL") == 0;
+
+    if (globals.do_dumpheader)
+    {
+	dump_pe_header();
+	/* FIX%E: should check ptr */
+	dump_sections((char*)nt_headers + sizeof(DWORD) + 
+		      sizeof(IMAGE_FILE_HEADER) + nt_headers->FileHeader.SizeOfOptionalHeader,
+		      nt_headers->FileHeader.NumberOfSections);
+    }
+    else if (!globals.dumpsect)
+    {
+	/* show at least something here */
+	dump_pe_header();
+    }
+
+    if (globals.dumpsect)
+    {
+	if (all || !strcmp(globals.dumpsect, "import"))
+	    dump_dir_imported_functions();
+	if (all || !strcmp(globals.dumpsect, "export"))
+	    dump_dir_exported_functions();
+	if (all || !strcmp(globals.dumpsect, "debug"))
+	    dump_dir_debug();
+#if 0
+	/* FIXME: not implemented yet */
+	if (all || !strcmp(globals.dumpsect, "resource"))
+	    dump_dir_resource();
+	if (all || !strcmp(globals.dumpsect, "reloc"))
+	    dump_dir_reloc();
+#endif
+    }
+}
+
+static	enum FileSig	check_headers(void)
+{
+    WORD*		pw;
+    DWORD*		pdw;
+    IMAGE_DOS_HEADER*	dh;
+    enum FileSig	sig;
+    
+    pw = PRD(0, sizeof(WORD));
+    if (!pw) {printf("Can't get main signature, aborting\n"); return 0;}
+    
+    switch (*pw)
+    {
+    case IMAGE_DOS_SIGNATURE:	
+	sig = SIG_DOS;
+	dh = PRD(0, sizeof(IMAGE_DOS_HEADER));
+	if (dh && dh->e_lfanew >= sizeof(*dh)) /* reasonable DOS header ? */
+	{
+	    /* the signature is the first DWORD */
+	    pdw = PRD(dh->e_lfanew, sizeof(DWORD));
+	    if (pdw)
+	    {
+		if (*pdw == IMAGE_NT_SIGNATURE)
+		{
+		    nt_headers = PRD(dh->e_lfanew, sizeof(DWORD));
+		    sig = SIG_PE;
+		}
+		else
+		{
+		    printf("No PE Signature found\n");
+		}
+	    }
+	    else
+	    {
+		printf("Can't get the extented signature, aborting\n"); 
+	    }
+	}
+	break;
+    case 0x4944: /* "DI" */
+	sig = SIG_DBG;
+	break;
+    default:
+	printf("No known main signature (%.2s/%x), aborting\n", (char*)pw, *pw); 
+	sig = SIG_UNKNOWN;
+    }
+    
+    return sig;
+}
+
+int pe_analysis(const char* name, void (*fn)(void), enum FileSig wanted_sig)
+{
+    int			fd;
+    enum FileSig	effective_sig;
+    int			ret = 1;
+    
+    setbuf(stdout, NULL);
+    
+    fd = open(name, O_RDONLY);
+    if (fd == -1) fatal("Can't open file");
+    
+    total_len = lseek(fd, 0, SEEK_END);
+    if (total_len < 0) fatal("Can't get size");
+    
+    base = mmap(NULL, total_len, PROT_READ, MAP_PRIVATE, fd, 0);
+    if (base == (void*)-1) fatal("Can't map file");
+    
+    effective_sig = check_headers();
+    
+    if (effective_sig == SIG_UNKNOWN)
+    {
+	printf("Can't get a recognized file signature, aborting\n");
+	ret = 0;
+    }
+    else if (wanted_sig == SIG_UNKNOWN || wanted_sig == effective_sig)
+    {
+	switch (effective_sig)
+	{
+	case SIG_UNKNOWN: /* shouldn't happen... */
+	    ret = 0; break;
+	case SIG_PE:
+	    printf("Contents of \"%s\": %ld bytes\n\n", name, total_len);
+	    do_dump();
+	    break;
+	case SIG_DBG:
+	    dump_separate_dbg();
+	    break;
+	case SIG_DOS:
+	    ret = 0; break;
+	}
+    }
+    else
+    {
+	printf("Can't get a suitable file signature, aborting\n");
+	ret = 0;
+    }
+    
+    if (ret) printf("Done dumping %s\n", name);
+    munmap(base, total_len);
+    close(fd);
+    
+    return ret;
+}
+
+void	dump_file(const char* name)
+{
+    pe_analysis(name, do_dump, SIG_UNKNOWN);
+}
+
+#if 0
+int 	main(int argc, char* argv[])
+{
+    if (argc != 2) fatal("usage");
+    pe_analysis(argv[1], do_dump);
+}
+#endif
+
+typedef struct _dll_symbol {
+    size_t	ordinal;
+    char       *symbol;
+} dll_symbol;
+
+static dll_symbol *dll_symbols = NULL;
+static dll_symbol *dll_current_symbol = NULL;
+
+/* Compare symbols by ordinal for qsort */
+static int symbol_cmp(const void *left, const void *right)
+{
+    return ((dll_symbol *)left)->ordinal > ((dll_symbol *)right)->ordinal;
+}
+
+/*******************************************************************
+ *         dll_close
+ *
+ * Free resources used by DLL
+ */
+static void dll_close (void)
+{
+    dll_symbol*	ds;
+    
+    for (ds = dll_symbols; ds->symbol; ds++)
+	free(ds->symbol);
+    free (dll_symbols);
+    dll_symbols = NULL;
+}
+
+static	void	do_grab_sym(void)
+{
+    IMAGE_EXPORT_DIRECTORY	*exportDir = get_dir(IMAGE_FILE_EXPORT_DIRECTORY);
+    unsigned			i;
+    DWORD*			pName;
+    DWORD*			pFunc;
+    WORD*			pOrdl;
+    char*			ptr;
+    DWORD*			map;
+    
+    if (!exportDir) return;
+    
+    pName = RVA(exportDir->AddressOfNames, exportDir->NumberOfNames * sizeof(DWORD));
+    if (!pName) {printf("Can't grab functions' name table\n"); return;}
+    pOrdl = RVA(exportDir->AddressOfNameOrdinals, exportDir->NumberOfNames * sizeof(WORD));
+    if (!pOrdl) {printf("Can't grab functions' ordinal table\n"); return;}
+    
+    dll_close();
+    
+    if (!(dll_symbols = (dll_symbol *) malloc((exportDir->NumberOfFunctions + 1) * 
+					      sizeof (dll_symbol))))
+	fatal ("Out of memory");
+    if (exportDir->AddressOfFunctions != exportDir->NumberOfNames || exportDir->Base > 1)
+	globals.do_ordinals = 1;
+    
+    /* bit map of used funcs */
+    map = calloc(((exportDir->NumberOfFunctions + 31) & ~31) / 32, sizeof(DWORD));
+    if (!map) fatal("no memory");
+    
+    for (i = 0; i < exportDir->NumberOfNames; i++)
+    {
+	map[*pOrdl / 32] |= 1 << (*pOrdl % 32);
+	ptr = RVA(*pName++, sizeof(DWORD));
+	if (!ptr) ptr = "cant_get_function";
+	dll_symbols[i].symbol = strdup(ptr);
+	assert(dll_symbols[i].symbol);
+    }
+    pFunc = RVA(exportDir->AddressOfFunctions, exportDir->NumberOfFunctions * sizeof(DWORD));
+    if (!pFunc) {printf("Can't grab functions' address table\n"); return;}
+    for (i = 0; i < exportDir->NumberOfFunctions; i++)
+    {
+	if (!(map[i / 32] & (1 << (i % 32))))
+	{
+	    char ordinal_text[256];
+	    /* Ordinal only entry */
+	    snprintf (ordinal_text, sizeof(ordinal_text), "%s_%lu",
+		      globals.forward_dll ? globals.forward_dll : OUTPUT_UC_DLL_NAME,
+		      exportDir->Base + i);
+	    str_toupper(ordinal_text);
+	    dll_symbols[i].symbol = strdup(ordinal_text);
+	    assert(dll_symbols[i].symbol);
+	    dll_symbols[i].ordinal = exportDir->Base + i;
+	}
+    }
+    free(map);
+    
+    if (NORMAL)
+	printf("%lu named symbols in DLL, %lu total\n", 
+	       exportDir->NumberOfNames, exportDir->NumberOfFunctions);
+    
+    qsort( dll_symbols, exportDir->NumberOfFunctions, sizeof(dll_symbol), symbol_cmp );
+    
+    dll_symbols[exportDir->NumberOfFunctions].symbol = NULL;
+    
+    dll_current_symbol = dll_symbols;
+    
+    /* Set DLL output names */
+    if ((ptr = strrchr (globals.input_name, '/')))
+	globals.input_name = ptr + 1; /* Strip path */
+    
+    OUTPUT_UC_DLL_NAME = str_toupper( strdup (OUTPUT_DLL_NAME));
+}
+
+/*******************************************************************
+ *         dll_open
+ *
+ * Open a DLL and read in exported symbols
+ */
+void  dll_open (const char *dll_name)
+{
+    pe_analysis(dll_name, do_grab_sym, SIG_PE);
+}
+
+/*******************************************************************
+ *         dll_next_symbol
+ *
+ * Get next exported symbol from dll
+ */
+int dll_next_symbol (parsed_symbol * sym)
+{
+    if (!dll_current_symbol)
+	return 1;
+    
+    assert (dll_symbols);
+    
+    sym->symbol = strdup (dll_current_symbol->symbol);
+    sym->ordinal = dll_current_symbol->ordinal;
+    dll_current_symbol++;
+    return 0;
+}
--- /dev/null	Wed Sep 27 12:31:54 2000
+++ tools/specmaker/pe.h	Sat Aug 18 14:33:41 2001
@@ -0,0 +1,5 @@
+extern void		dump_codeview(unsigned long ptr, unsigned long len);
+extern void*		PRD(unsigned long prd, unsigned long len);
+extern unsigned long	Offset(void* ptr);
+extern char*		get_time_str(DWORD _t);
+
--- /dev/null	Wed Sep 27 12:31:54 2000
+++ tools/specmaker/winedump.h	Thu Aug 23 21:39:29 2001
@@ -0,0 +1,203 @@
+/*
+ *  Specmaker - A Wine DLL tool
+ *
+ *  Copyright 2000 Jon Griffiths
+ *
+ *  References:
+ *  DLL symbol extraction based on file format from alib (anthonyw.cjb.net).
+ *
+ *  Option processing shamelessly cadged from winebuild (www.winehq.com).
+ *
+ *  All the cool functionality (prototyping, call tracing, forwarding)
+ *  relies on Patrik Stridvall's 'function_grep.pl' script to work.
+ *
+ *  http://msdn.microsoft.com/library/periodic/period96/msj/S330.htm
+ *  This article provides both a description and freely downloadble
+ *  implementation, in source code form, of how to extract symbols
+ *  from Win32 PE executables/DLL's.
+ *
+ *  http://www.kegel.com/mangle.html
+ *  Gives information on the name mangling scheme used by MS compilers,
+ *  used as the starting point for the code here. Contains a few
+ *  mistakes and some incorrect assumptions, but the lists of types
+ *  are pure gold.
+ */
+#ifndef __WINE_SPECMAKER_H
+#define __WINE_SPECMAKER_H
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <assert.h>
+#include <stdarg.h>
+
+/* Argument type constants */
+#define MAX_FUNCTION_ARGS   32
+
+#define ARG_VOID            0x0
+#define ARG_STRING          0x1
+#define ARG_WIDE_STRING     0x2
+#define ARG_POINTER         0x3
+#define ARG_LONG            0x4
+#define ARG_DOUBLE          0x5
+#define ARG_STRUCT          0x6 /* By value */
+#define ARG_FLOAT           0x7
+#define ARG_VARARGS         0x8
+
+/* Compound type flags */
+#define CT_BY_REFERENCE     0x1
+#define CT_VOLATILE         0x2
+#define CT_CONST            0x4
+#define CT_EXTENDED         0x8
+
+/* symbol flags */
+#define SYM_CDECL           0x1
+#define SYM_STDCALL         0x2
+#define SYM_THISCALL        0x4
+#define SYM_DATA            0x8 /* Data, not a function */
+
+typedef enum {NONE, DMGL, SPEC, DUMP} Mode;
+
+/* Structure holding a parsed symbol */
+typedef struct __parsed_symbol
+{
+  char *symbol;
+  int   ordinal;
+  char *return_text;
+  char  return_type;
+  char *function_name;
+  unsigned int varargs;
+  unsigned int argc;
+  unsigned int flags;
+  char  arg_type [MAX_FUNCTION_ARGS];
+  char  arg_flag [MAX_FUNCTION_ARGS];
+  char *arg_text [MAX_FUNCTION_ARGS];
+  char *arg_name [MAX_FUNCTION_ARGS];
+} parsed_symbol;
+
+/* All globals */
+typedef struct __globals
+{
+  Mode  mode;		   /* SPEC, DEMANGLE or DUMP */
+
+  /* Options: generic */
+  int   do_quiet;          /* -q */
+  int   do_verbose;        /* -v */
+
+  /* Option arguments: generic */
+  const char *input_name;  /* */
+
+  /* Options: spec mode */
+  int   do_code;           /* -c, -t, -f */
+  int   do_trace;          /* -t, -f */
+  int   do_cdecl;          /* -C */
+  int   do_documentation;  /* -D */
+
+  /* Options: dump mode */
+  int   do_demangle;        /* -d */
+  int   do_dumpheader;      /* -f */
+
+  /* Option arguments: spec mode */
+  int   start_ordinal;     /* -s */
+  int   end_ordinal;       /* -e */
+  const char *directory;   /* -I */
+  const char *forward_dll; /* -f */
+  const char *dll_name;    /* -o */
+  char *uc_dll_name;       /* -o */
+
+  /* Option arguments: dump mode */
+  const char *dumpsect;    /* -j */
+    
+  /* internal options */
+  int   do_ordinals;
+} _globals;
+
+extern _globals globals;
+
+/* Names to use for output DLL */
+#define OUTPUT_DLL_NAME \
+          (globals.dll_name ? globals.dll_name : globals.input_name)
+#define OUTPUT_UC_DLL_NAME globals.uc_dll_name
+
+/* Verbosity levels */
+#define QUIET   (globals.do_quiet)
+#define NORMAL  (!QUIET)
+#define VERBOSE (globals.do_verbose)
+
+/* Default calling convention */
+#define CALLING_CONVENTION (globals.do_cdecl ? SYM_CDECL : SYM_STDCALL)
+
+/* Image functions */
+void	dump_file(const char* name);
+
+/* DLL functions */
+void  dll_open (const char *dll_name);
+
+int dll_next_symbol (parsed_symbol * sym);
+
+/* Symbol functions */
+int   symbol_demangle (parsed_symbol *symbol);
+
+int   symbol_search (parsed_symbol *symbol);
+
+void  symbol_clear(parsed_symbol *sym);
+
+int   symbol_is_valid_c(const parsed_symbol *sym);
+
+const char *symbol_get_call_convention(const parsed_symbol *sym);
+
+const char *symbol_get_spec_type (const parsed_symbol *sym, size_t arg);
+
+void  symbol_clean_string (const char *string);
+
+int   symbol_get_type (const char *string);
+
+/* Output functions */
+void  output_spec_preamble (void);
+
+void  output_spec_symbol (const parsed_symbol *sym);
+
+void  output_header_preamble (void);
+
+void  output_header_symbol (const parsed_symbol *sym);
+
+void  output_c_preamble (void);
+
+void  output_c_symbol (const parsed_symbol *sym);
+
+void  output_prototype (FILE *file, const parsed_symbol *sym);
+
+void  output_makefile (void);
+
+void  output_install_script (void);
+
+/* Misc functions */
+char *str_create (size_t num_str, ...);
+
+char *str_create_num (size_t num_str, int num, ...);
+
+char *str_substring(const char *start, const char *end);
+
+char *str_replace (char *str, const char *oldstr, const char *newstr);
+
+const char *str_match (const char *str, const char *match, int *found);
+
+const char *str_find_set (const char *str, const char *findset);
+
+char *str_toupper (char *str);
+
+FILE *open_file (const char *name, const char *ext, const char *mode);
+
+#ifdef __GNUC__
+void  do_usage (void) __attribute__ ((noreturn));
+void  fatal (const char *message)  __attribute__ ((noreturn));
+#else
+void  do_usage (void);
+void  fatal (const char *message);
+#endif
+
+
+
+#endif /* __WINE_SPECMAKER_H */


More information about the wine-patches mailing list