dumping utility

eric pouech eric.pouech at wanadoo.fr
Thu Aug 23 15:44:21 CDT 2001


this is a first shot at the PE-dump utility for wine
since, lots of code could/will be shared with specmaker (PE image file
browsing, symbol demangling...), I decided to turn specmaker into a 
multi-mode utility

the executable made out of the sources in specmaker dir can now be 
launched under 3 different names:
- specmaker: you keep all the old features of specmaker (except -S
option)
- winedemangle: this replaces the -S option of specmaker
- pedump: PE (and .DBG) file dumping utility... lots of PE dir dumping
still 
  need to be written (like resources or typelib information)

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
GenDate: 2001/08/23 20:04:50 UTC
ModifiedFiles: tools/specmaker/Makefile.in tools/specmaker/main.c tools/specmaker/specmaker.h tools/specmaker/README
AddedFiles: tools/specmaker/cvinclude.h tools/specmaker/debug.c tools/specmaker/pe.c tools/specmaker/pe.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/23 19:48:35
@@ -4,15 +4,16 @@
 SRCDIR    = @srcdir@
 VPATH     = @srcdir@
 
-PROGRAMS = specmaker
+PROGRAMS = specmaker winedemangle pedump
 MODULE   = none
 
 C_SRCS = \
-	dll.c  \
+	debug.c \
 	main.c  \
 	misc.c  \
 	msmangle.c  \
 	output.c  \
+	pe.c \
 	search.c  \
 	symbol.c
 
@@ -23,9 +24,17 @@
 specmaker: $(OBJS)
 	$(CC) $(CFLAGS) -o specmaker $(OBJS) $(LDFLAGS)
 
+winedemangle: specmaker
+	$(LN_S) specmaker $@
+
+pedump: specmaker
+	$(LN_S) specmaker $@
+
 install:: $(PROGRAMS)
 	[ -d $(bindir) ] || $(MKDIR) $(bindir)
 	$(INSTALL_PROGRAM) specmaker $(bindir)/specmaker
+	$(LN_S) specmaker $(bindir)/pedump
+	$(LN_S) specmaker $(bindir)/winedemangle
 	$(INSTALL_SCRIPT) $(SRCDIR)/function_grep.pl $(bindir)/function_grep.pl
 
 uninstall::
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/23 20:04:43
@@ -32,17 +32,23 @@
 }
 
 
-static void do_input (const char *arg)
+static void do_spec (const char *arg)
 {
-  globals.input_name = strip_ext (arg);
+    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;
+    globals.do_code = 1;
+    globals.input_name = arg;
+}
+
+
+static void do_dump (const char *arg)
+{
+    globals.do_code = 1;
+    globals.input_name = arg;
 }
 
 
@@ -105,42 +111,69 @@
 }
 
 
+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"},
+  {"-S", DMGL, 1, do_demangle, "-S <sym>     Demangle C++ symbol <sym>' and exit"},
+  {"-d", SPEC, 1, do_spec,     "-d <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)."},
+  {"-d", DUMP, 1, do_dump,     "-d <dll>     Use dll for input file and generate implementation code"},
+  {"-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:\n");
+    for (opt = option_table; opt->name; opt++)
+	if (opt->mode == NONE || opt->mode == globals.mode)
+	    printf ("   %s\n", opt->usage);
+
+    puts ("\n");
+    exit (1);
 }
 
 
@@ -155,20 +188,28 @@
   char *const *ptr;
   const char *arg = NULL;
 
+  ptr = argv;
+  arg = strrchr(*ptr, '/');
+  if (!arg) arg = *ptr; else arg++;
+
+  if (strcmp(arg, "pedump") == 0) globals.mode = DUMP;
+  if (strcmp(arg, "winedemangle") == 0) globals.mode = DMGL;
+  if (strcmp(arg, "specmaker") == 0) globals.mode = SPEC;
+  if (globals.mode == NONE) fatal("this executable must be run as winedemandle, pedump or specmaker\n");
+
   ptr = argv + 1;
 
   while (*ptr != NULL)
   {
     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 +220,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 +247,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:
+	printf("Shouldn't happen\n");
+	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/specmaker.h
===================================================================
RCS file: /usr/share/cvs/cvsroot/wine/wine/tools/specmaker/specmaker.h,v
retrieving revision 1.3
diff -u -u -r1.3 specmaker.h
--- tools/specmaker/specmaker.h	2001/02/16 19:06:06	1.3
+++ tools/specmaker/specmaker.h	2001/08/23 19:39:29
@@ -58,6 +58,8 @@
 #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
 {
@@ -78,23 +80,37 @@
 /* All globals */
 typedef struct __globals
 {
-  /* Options */
+  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_quiet;          /* -q */
-  int   do_verbose;        /* -v */
   int   do_documentation;  /* -D */
-  int   do_demangle;       /* -S */
+
+  /* Options: dump mode */
+  int   do_demangle;        /* -d */
+  int   do_dumpheader;      /* -f */
 
-  /* Option arguments */
+  /* Option arguments: spec mode */
   int   start_ordinal;     /* -s */
   int   end_ordinal;       /* -e */
   const char *directory;   /* -I */
-  const char *input_name;  /* -d */
   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;
 
@@ -113,6 +129,8 @@
 /* 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);
@@ -174,11 +192,12 @@
 
 #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
 
-void  fatal (const char *message);
 
 
 #endif /* __WINE_SPECMAKER_H */
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/23 19:53:47
@@ -54,48 +54,28 @@
 Specmaker 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]
+Usage:
+   -h           Display this help message
+   -d <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).                                                                                                                      
 
-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.
+for. You *must* give this option when using specmaker.
 
 16 bit DLL's are not currently supported (Note that Winelib is intended
 only for Win32 programs).
@@ -575,3 +555,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 winedemangle 
+command line tool. This is useful for testing the demangler or implementing
+C++ functions in partially implemented wine DLLS. As an example:
+
+winedemangle "??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:
+pedump -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	Thu Aug 23 22:00:05 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 "specmaker.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	Thu Aug 23 22:01:13 2001
@@ -0,0 +1,841 @@
+/*
+ *	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 "specmaker.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);
+    }
+    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);
+


More information about the wine-patches mailing list