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