|
From: <sv...@va...> - 2009-04-22 22:42:24
|
Author: sewardj
Date: 2009-04-22 23:42:10 +0100 (Wed, 22 Apr 2009)
New Revision: 9580
Log:
Add support for reading Windows PDB debug info (symbols and line
numbers) when Valgrind is running Wine. Modified version of a
patch by John Reiser (vgsvn+wine-load-pdb-debuginfo.patch) with
extensions to read a second format of line number tables.
Wine uses a new client request, VG_USERREQ__LOAD_PDB_DEBUGINFO,
to tell Valgrind when to read PDB info. Wine's implementation
of module loading is vastly different from that used by
ld-linux.so, and it is too difficult to recognize what is going
on just by observing the calls to mmap and mprotect.
Added:
trunk/coregrind/m_debuginfo/priv_readpdb.h
trunk/coregrind/m_debuginfo/readpdb.c
Modified:
trunk/coregrind/Makefile.am
trunk/coregrind/m_debuginfo/debuginfo.c
trunk/coregrind/m_debuginfo/priv_storage.h
trunk/coregrind/m_debuginfo/readelf.c
trunk/coregrind/m_debuginfo/storage.c
trunk/coregrind/m_scheduler/scheduler.c
trunk/coregrind/m_stacktrace.c
trunk/coregrind/pub_core_debuginfo.h
trunk/include/valgrind.h
Modified: trunk/coregrind/Makefile.am
===================================================================
--- trunk/coregrind/Makefile.am 2009-04-22 19:15:50 UTC (rev 9579)
+++ trunk/coregrind/Makefile.am 2009-04-22 22:42:10 UTC (rev 9580)
@@ -158,6 +158,7 @@
m_debuginfo/priv_storage.h \
m_debuginfo/priv_tytypes.h \
m_debuginfo/priv_readstabs.h \
+ m_debuginfo/priv_readpdb.h \
m_debuginfo/priv_d3basics.h \
m_debuginfo/priv_readdwarf.h \
m_debuginfo/priv_readdwarf3.h \
@@ -246,6 +247,7 @@
m_debuginfo/readdwarf.c \
m_debuginfo/readdwarf3.c \
m_debuginfo/readstabs.c \
+ m_debuginfo/readpdb.c \
m_syswrap/syswrap-generic.c \
m_ume/elf.c \
m_ume/main.c \
Modified: trunk/coregrind/m_debuginfo/debuginfo.c
===================================================================
--- trunk/coregrind/m_debuginfo/debuginfo.c 2009-04-22 19:15:50 UTC (rev 9579)
+++ trunk/coregrind/m_debuginfo/debuginfo.c 2009-04-22 22:42:10 UTC (rev 9580)
@@ -61,6 +61,7 @@
#if defined(VGO_linux)
# include "priv_readelf.h"
# include "priv_readdwarf3.h"
+# include "priv_readpdb.h"
#elif defined(VGO_aix5)
# include "pub_core_debuglog.h"
# include "pub_core_libcproc.h"
@@ -217,6 +218,7 @@
if (di->loctab) ML_(dinfo_free)(di->loctab);
if (di->cfsi) ML_(dinfo_free)(di->cfsi);
if (di->cfsi_exprs) VG_(deleteXA)(di->cfsi_exprs);
+ if (di->fpo) ML_(dinfo_free)(di->fpo);
for (chunk = di->strchunks; chunk != NULL; chunk = next) {
next = chunk->next;
@@ -872,6 +874,143 @@
}
}
+/*--------- PDB (windows debug info) reading --------- */
+
+/* this should really return ULong, as per VG_(di_notify_mmap). */
+void VG_(di_notify_pdb_debuginfo)( Int fd_obj, Addr avma_obj,
+ SizeT total_size,
+ PtrdiffT unknown_purpose__reloc )
+{
+ Int r, sz_exename;
+ ULong obj_mtime, pdb_mtime;
+ Char exename[VKI_PATH_MAX];
+ Char* pdbname = NULL;
+ Char* dot;
+ SysRes sres;
+ Int fd_pdbimage;
+ SizeT n_pdbimage;
+ struct vg_stat stat_buf;
+
+ if (VG_(clo_verbosity) > 0) {
+ VG_(message)(Vg_UserMsg, "");
+ VG_(message)(Vg_UserMsg,
+ "LOAD_PDB_DEBUGINFO(fd=%d, avma=%#lx, total_size=%lu, "
+ "uu_reloc=%#lx)",
+ fd_obj, avma_obj, total_size, unknown_purpose__reloc
+ );
+ }
+
+ /* 'fd' refers to the .exe/.dll we're dealing with. Get its modification
+ time into obj_mtime. */
+ r = VG_(fstat)(fd_obj, &stat_buf);
+ if (r == -1)
+ goto out; /* stat failed ?! */
+ vg_assert(r == 0);
+ obj_mtime = stat_buf.st_mtime;
+
+ /* and get its name into exename[]. */
+ vg_assert(VKI_PATH_MAX > 100); /* to ensure /proc/self/fd/%d is safe */
+ VG_(memset)(exename, 0, sizeof(exename));
+ VG_(sprintf)(exename, "/proc/self/fd/%d", fd_obj);
+ /* convert exename from a symlink to real name .. overwrites the
+ old contents of the buffer. Ick. */
+ sz_exename = VG_(readlink)(exename, exename, sizeof(exename)-2 );
+ if (sz_exename == -1)
+ goto out; /* readlink failed ?! */
+ vg_assert(sz_exename >= 0 && sz_exename < sizeof(exename));
+ vg_assert(exename[sizeof(exename)-1] == 0);
+
+ if (VG_(clo_verbosity) > 0) {
+ VG_(message)(Vg_UserMsg, "LOAD_PDB_DEBUGINFO: objname: %s", exename);
+ }
+
+ /* Try to find a matching PDB file from which to read debuginfo.
+ Windows PE files have symbol tables and line number information,
+ but MSVC doesn't seem to use them. */
+ /* Why +5 ? Because in the worst case, we could find a dot as the
+ last character of pdbname, and we'd then put "pdb" right after
+ it, hence extending it a bit. */
+ pdbname = ML_(dinfo_zalloc)("di.debuginfo.lpd1", sz_exename+5);
+ VG_(strcpy)(pdbname, exename);
+ vg_assert(pdbname[sz_exename+5-1] == 0);
+ dot = VG_(strrchr)(pdbname, '.');
+ if (!dot)
+ goto out; /* there's no dot in the exe's name ?! */
+ if (dot[1] == 0)
+ goto out; /* hmm, path ends in "." */
+
+ if ('A' <= dot[1] && dot[1] <= 'Z')
+ VG_(strcpy)(dot, ".PDB");
+ else
+ VG_(strcpy)(dot, ".pdb");
+
+ vg_assert(pdbname[sz_exename+5-1] == 0);
+
+ /* See if we can find it, and check it's in-dateness. */
+ sres = VG_(stat)(pdbname, &stat_buf);
+ if (sres.isError) {
+ VG_(message)(Vg_UserMsg, "Warning: Missing or un-stat-able %s",
+ pdbname);
+ if (VG_(clo_verbosity) > 0)
+ VG_(message)(Vg_UserMsg, "LOAD_PDB_DEBUGINFO: missing: %s", pdbname);
+ goto out;
+ }
+ pdb_mtime = stat_buf.st_mtime;
+ if (pdb_mtime < obj_mtime ) {
+ /* PDB file is older than PE file - ignore it or we will either
+ (a) print wrong stack traces or more likely (b) crash. */
+ VG_(message)(Vg_UserMsg, "Warning: Ignoring %s since it is older than %s",
+ pdbname, exename);
+ goto out;
+ }
+
+ sres = VG_(open)(pdbname, VKI_O_RDONLY, 0);
+ if (sres.isError) {
+ VG_(message)(Vg_UserMsg, "Warning: Can't open %s", pdbname);
+ goto out;
+ }
+
+ /* Looks promising; go on to try and read stuff from it. */
+ fd_pdbimage = sres.res;
+ n_pdbimage = stat_buf.st_size;
+ sres = VG_(am_mmap_file_float_valgrind)( n_pdbimage, VKI_PROT_READ,
+ fd_pdbimage, 0 );
+ if (sres.isError) {
+ VG_(close)(fd_pdbimage);
+ goto out;
+ }
+
+ if (VG_(clo_verbosity) > 0)
+ VG_(message)(Vg_UserMsg, "LOAD_PDB_DEBUGINFO: pdbname: %s", pdbname);
+
+ /* play safe; always invalidate the CFI cache. I don't know if
+ this is necessary, but anyway .. */
+ cfsi_cache__invalidate();
+ /* dump old info for this range, if any */
+ discard_syms_in_range( avma_obj, total_size );
+
+ { void* pdbimage = (void*)sres.res;
+ DebugInfo* di = find_or_create_DebugInfo_for(exename, NULL/*membername*/ );
+
+ /* this di must be new, since we just nuked any old stuff in the range */
+ vg_assert(di && !di->have_rx_map && !di->have_rw_map);
+ vg_assert(!di->have_dinfo);
+
+ /* don't set up any of the di-> fields; let
+ ML_(read_pdb_debug_info) do it. */
+ ML_(read_pdb_debug_info)( di, avma_obj, unknown_purpose__reloc,
+ pdbimage, n_pdbimage, pdbname, pdb_mtime );
+ // JRS fixme: take notice of return value from read_pdb_debug_info,
+ // and handle failure
+ vg_assert(di->have_dinfo); // fails if PDB read failed
+ VG_(am_munmap_valgrind)( (Addr)pdbimage, n_pdbimage );
+ VG_(close)(fd_pdbimage);
+ }
+
+ out:
+ if (pdbname) ML_(dinfo_free)(pdbname);
+}
+
#endif /* defined(VGO_linux) */
@@ -1983,6 +2122,127 @@
/*--------------------------------------------------------------*/
/*--- ---*/
+/*--- TOP LEVEL: FOR UNWINDING THE STACK USING ---*/
+/*--- MSVC FPO INFO ---*/
+/*--- ---*/
+/*--------------------------------------------------------------*/
+
+Bool VG_(use_FPO_info) ( /*MOD*/Addr* ipP,
+ /*MOD*/Addr* spP,
+ /*MOD*/Addr* fpP,
+ Addr min_accessible,
+ Addr max_accessible )
+{
+ Word i;
+ DebugInfo* di;
+ FPO_DATA* fpo = NULL;
+ Addr spHere;
+
+ static UWord n_search = 0;
+ static UWord n_steps = 0;
+ n_search++;
+
+ if (0) VG_(printf)("search FPO for %#lx\n", *ipP);
+
+ for (di = debugInfo_list; di != NULL; di = di->next) {
+ n_steps++;
+
+ /* Use the per-DebugInfo summary address ranges to skip
+ inapplicable DebugInfos quickly. */
+ if (di->fpo == NULL)
+ continue;
+ if (*ipP < di->fpo_minavma || *ipP > di->fpo_maxavma)
+ continue;
+
+ i = ML_(search_one_fpotab)( di, *ipP );
+ if (i != -1) {
+ Word j;
+ if (0) {
+ /* debug printing only */
+ VG_(printf)("look for %#lx size %ld i %ld\n",
+ *ipP, di->fpo_size, i);
+ for (j = 0; j < di->fpo_size; j++)
+ VG_(printf)("[%02ld] %#x %d\n",
+ j, di->fpo[j].ulOffStart, di->fpo[j].cbProcSize);
+ }
+ vg_assert(i >= 0 && i < di->fpo_size);
+ fpo = &di->fpo[i];
+ break;
+ }
+ }
+
+ if (fpo == NULL)
+ return False;
+
+ if (0 && ((n_search & 0x7FFFF) == 0))
+ VG_(printf)("VG_(use_FPO_info): %lu searches, "
+ "%lu DebugInfos looked at\n",
+ n_search, n_steps);
+
+
+ /* Start of performance-enhancing hack: once every 64 (chosen
+ hackily after profiling) successful searches, move the found
+ DebugInfo one step closer to the start of the list. This makes
+ future searches cheaper. For starting konqueror on amd64, this
+ in fact reduces the total amount of searching done by the above
+ find-the-right-DebugInfo loop by more than a factor of 20. */
+ if ((n_search & 0x3F) == 0) {
+ /* Move si one step closer to the start of the list. */
+ //move_DebugInfo_one_step_forward( di );
+ }
+ /* End of performance-enhancing hack. */
+
+ if (0) {
+ VG_(printf)("found fpo: ");
+ //ML_(ppFPO)(fpo);
+ }
+
+ /*
+ Stack layout is:
+ %esp->
+ 4*.cbRegs {%edi, %esi, %ebp, %ebx}
+ 4*.cdwLocals
+ return_pc
+ 4*.cdwParams
+ prior_%esp->
+
+ Typical code looks like:
+ sub $4*.cdwLocals,%esp
+ Alternative to above for >=4KB (and sometimes for smaller):
+ mov $size,%eax
+ call __chkstk # WinNT performs page-by-page probe!
+ __chkstk is much like alloc(), except that on return
+ %eax= 5+ &CALL. Thus it could be used as part of
+ Position Independent Code to locate the Global Offset Table.
+ push %ebx
+ push %ebp
+ push %esi
+ Other once-only instructions often scheduled >here<.
+ push %edi
+
+ If the pc is within the first .cbProlog bytes of the function,
+ then you must disassemble to see how many registers have been pushed,
+ because instructions in the prolog may be scheduled for performance.
+ The order of PUSH is always %ebx, %ebp, %esi, %edi, with trailing
+ registers not pushed when .cbRegs < 4. This seems somewhat strange
+ because %ebp is the register whose usage you want to minimize,
+ yet it is in the first half of the PUSH list.
+
+ I don't know what happens when the compiler constructs an outgoing CALL.
+ %esp could move if outgoing parameters are PUSHed, and this affects
+ traceback for errors during the PUSHes. */
+
+ spHere = *spP;
+
+ *ipP = *(Addr *)(spHere + 4*(fpo->cbRegs + fpo->cdwLocals));
+ *spP = spHere + 4*(fpo->cbRegs + fpo->cdwLocals + 1 + fpo->cdwParams);
+ *fpP = *(Addr *)(spHere + 4*2);
+ return True;
+}
+
+
+/*--------------------------------------------------------------*/
+/*--- ---*/
/*--- TOP LEVEL: GENERATE DESCRIPTION OF DATA ADDRESSES ---*/
/*--- FROM DWARF3 DEBUG INFO ---*/
/*--- ---*/
@@ -2914,7 +3174,6 @@
}
-
/*------------------------------------------------------------*/
/*--- DebugInfo accessor functions ---*/
/*------------------------------------------------------------*/
Added: trunk/coregrind/m_debuginfo/priv_readpdb.h
===================================================================
--- trunk/coregrind/m_debuginfo/priv_readpdb.h (rev 0)
+++ trunk/coregrind/m_debuginfo/priv_readpdb.h 2009-04-22 22:42:10 UTC (rev 9580)
@@ -0,0 +1,53 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Reading of syms & debug info from PDB-format files. ---*/
+/*--- priv_readpdb.h ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+ Spring 2008:
+ derived from readelf.c and valgrind-20031012-wine/vg_symtab2.c
+ derived from wine-1.0/tools/winedump/pdb.c and msc.c
+
+ Copyright (C) 2000-2008 Julian Seward
+ js...@ac...
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+#ifndef __PRIV_READPDB_H
+#define __PRIV_READPDB_H
+
+/* Returns True if OK, False for any kind of failure. */
+extern Bool ML_(read_pdb_debug_info)(
+ DebugInfo* di,
+ Addr obj_avma,
+ PtrdiffT unknown_purpose__reloc,
+ void* pdbimage,
+ SizeT n_pdbimage,
+ Char* pdbname,
+ ULong pdbmtime
+ );
+
+#endif /* ndef __PRIV_READPDB_H */
+
+/*--------------------------------------------------------------------*/
+/*--- end priv_readpdb.h ---*/
+/*--------------------------------------------------------------------*/
Modified: trunk/coregrind/m_debuginfo/priv_storage.h
===================================================================
--- trunk/coregrind/m_debuginfo/priv_storage.h 2009-04-22 19:15:50 UTC (rev 9579)
+++ trunk/coregrind/m_debuginfo/priv_storage.h 2009-04-22 22:42:10 UTC (rev 9580)
@@ -208,6 +208,29 @@
extern void ML_(ppCfiExpr)( XArray* src, Int ix );
+/* ---------------- FPO INFO (Windows PE) -------------- */
+
+/* for apps using Wine: MSVC++ PDB FramePointerOmitted: somewhat like
+ a primitive CFI */
+typedef
+ struct _FPO_DATA { /* 16 bytes */
+ UInt ulOffStart; /* offset of 1st byte of function code */
+ UInt cbProcSize; /* # bytes in function */
+ UInt cdwLocals; /* # bytes/4 in locals */
+ UShort cdwParams; /* # bytes/4 in params */
+ UChar cbProlog; /* # bytes in prolog */
+ UChar cbRegs :3; /* # regs saved */
+ UChar fHasSEH:1; /* Structured Exception Handling */
+ UChar fUseBP :1; /* EBP has been used */
+ UChar reserved:1;
+ UChar cbFrame:2; /* frame type */
+ }
+ FPO_DATA;
+
+#define PDB_FRAME_FPO 0
+#define PDB_FRAME_TRAP 1
+#define PDB_FRAME_TSS 2
+
/* --------------------- VARIABLES --------------------- */
typedef
@@ -441,6 +464,13 @@
Addr cfsi_maxavma;
XArray* cfsi_exprs; /* XArray of CfiExpr */
+ /* Optimized code under Wine x86: MSVC++ PDB FramePointerOmitted
+ data. Non-expandable array, hence .size == .used. */
+ FPO_DATA* fpo;
+ UWord fpo_size;
+ Addr fpo_minavma;
+ Addr fpo_maxavma;
+
/* Expandable arrays of characters -- the string table. Pointers
into this are stable (the arrays are not reallocated). */
struct strchunk {
@@ -539,6 +569,10 @@
not found. Binary search. */
extern Word ML_(search_one_cfitab) ( struct _DebugInfo* di, Addr ptr );
+/* Find a FPO-table index containing the specified pointer, or -1
+ if not found. Binary search. */
+extern Word ML_(search_one_fpotab) ( struct _DebugInfo* di, Addr ptr );
+
/* ------ Misc ------ */
/* Show a non-fatal debug info reading error. Use vg_panic if
Modified: trunk/coregrind/m_debuginfo/readelf.c
===================================================================
--- trunk/coregrind/m_debuginfo/readelf.c 2009-04-22 19:15:50 UTC (rev 9579)
+++ trunk/coregrind/m_debuginfo/readelf.c 2009-04-22 22:42:10 UTC (rev 9580)
@@ -1114,6 +1114,8 @@
plt, and toc.
---------------------------------------------------------- */
+ res = False;
+
oimage = (Addr)NULL;
if (VG_(clo_verbosity) > 1 || VG_(clo_trace_redir))
VG_(message)(Vg_DebugMsg, "Reading syms from %s (%#lx)",
Added: trunk/coregrind/m_debuginfo/readpdb.c
===================================================================
--- trunk/coregrind/m_debuginfo/readpdb.c (rev 0)
+++ trunk/coregrind/m_debuginfo/readpdb.c 2009-04-22 22:42:10 UTC (rev 9580)
@@ -0,0 +1,2267 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Reading of syms & debug info from PDB-format files. ---*/
+/*--- readpdb.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+ Spring 2008:
+ derived from readelf.c and valgrind-20031012-wine/vg_symtab2.c
+ derived from wine-1.0/tools/winedump/pdb.c and msc.c
+
+ Copyright (C) 2000-2008 Julian Seward
+ js...@ac...
+ Copyright 2006 Eric Pouech (winedump/pdb.c and msc.c)
+ GNU Lesser General Public License version 2.1 or later applies.
+ Copyright (C) 2008 BitWagon Software LLC
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "pub_core_basics.h"
+#include "pub_core_debuginfo.h"
+#include "pub_core_vki.h" // VKI_PAGE_SIZE
+#include "pub_core_libcbase.h"
+#include "pub_core_libcassert.h"
+#include "pub_core_libcprint.h"
+#include "pub_core_options.h" // VG_(clo_verbosity)
+#include "pub_core_xarray.h" // keeps priv_storage.h happy
+#include "pub_core_redir.h"
+
+#include "priv_misc.h" /* dinfo_zalloc/free/strdup */
+#include "priv_d3basics.h"
+#include "priv_storage.h"
+#include "priv_readpdb.h" // self
+
+
+/*------------------------------------------------------------*/
+/*--- ---*/
+/*--- Biasing ---*/
+/*--- ---*/
+/*------------------------------------------------------------*/
+
+/* JRS 2009-Apr-13: Mostly this PDB reader is straightforward. But
+ the biasing is incomprehensible, and I don't claim to understand it
+ at all. There are four places where biasing is required:
+
+ - when reading symbol addresses (DEBUG_SnarfCodeView)
+ - when reading old-style line number tables (DEBUG_SnarfLinetab)
+ - when reading new-style line number tables (codeview_dump_linetab2)
+ - when reading FPO (stack-unwind) tables (pdb_dump)
+
+ To complicate matters further, Wine supplies us, via the
+ VG_USERREQ__LOAD_PDB_DEBUGINFO client request that initiates PDB
+ reading, a value 'reloc' which, if you read 'virtual.c' in the Wine
+ sources, looks a lot like a text bias value. Yet the code below
+ ignores it.
+
+ To make future experimentation with biasing easier, here are four
+ macros which give the bias to use in each of the four cases. Be
+ warned, they can and do refer to local vars in the relevant
+ functions. */
+
+/* This is the biasing arrangement in John's original patch. I don't
+ see that is makes any sense for the FPO bias to be hardwired to
+ zero, but perhaps that's OK when the reloc value is also zero.
+ (iow, the FPO bias should actually be 'reloc' ?) */
+#define BIAS_FOR_SYMBOLS (di->rx_map_avma)
+#define BIAS_FOR_LINETAB (di->rx_map_avma)
+#define BIAS_FOR_LINETAB2 (di->text_bias)
+#define BIAS_FOR_FPO 0 /* no, really */
+
+/* This module leaks space; enable m_main's calling of
+ VG_(di_discard_ALL_debuginfo)() at shutdown and run with
+ --profile-heap=yes to see. The main culprit appears to be
+ di.readpe.pdr.1. I haven't bothered to chase it further. */
+
+
+/*------------------------------------------------------------*/
+/*--- ---*/
+/*--- PE/PDB definitions ---*/
+/*--- ---*/
+/*------------------------------------------------------------*/
+
+typedef UInt DWORD;
+typedef UShort WORD;
+typedef UChar BYTE;
+
+
+/* the following DOS and WINDOWS structures, defines and PE/PDB
+ * parsing code are copied or derived from the WINE
+ * project - http://www.winehq.com/
+ */
+
+/*
+ * File formats definitions
+ */
+#define OFFSET_OF(__c,__f) ((int)(((char*)&(((__c*)0)->__f))-((char*)0)))
+#define WIN32_PATH_MAX 256
+
+#pragma pack(2)
+typedef struct _IMAGE_DOS_HEADER {
+ unsigned short e_magic; /* 00: MZ Header signature */
+ unsigned short e_cblp; /* 02: Bytes on last page of file */
+ unsigned short e_cp; /* 04: Pages in file */
+ unsigned short e_crlc; /* 06: Relocations */
+ unsigned short e_cparhdr; /* 08: Size of header in paragraphs */
+ unsigned short e_minalloc; /* 0a: Minimum extra paragraphs needed */
+ unsigned short e_maxalloc; /* 0c: Maximum extra paragraphs needed */
+ unsigned short e_ss; /* 0e: Initial (relative) SS value */
+ unsigned short e_sp; /* 10: Initial SP value */
+ unsigned short e_csum; /* 12: Checksum */
+ unsigned short e_ip; /* 14: Initial IP value */
+ unsigned short e_cs; /* 16: Initial (relative) CS value */
+ unsigned short e_lfarlc; /* 18: File address of relocation table */
+ unsigned short e_ovno; /* 1a: Overlay number */
+ unsigned short e_res[4]; /* 1c: Reserved words */
+ unsigned short e_oemid; /* 24: OEM identifier (for e_oeminfo) */
+ unsigned short e_oeminfo; /* 26: OEM information; e_oemid specific */
+ unsigned short e_res2[10]; /* 28: Reserved words */
+ unsigned long e_lfanew; /* 3c: Offset to extended header */
+} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
+
+#define IMAGE_DOS_SIGNATURE 0x5A4D /* MZ */
+#define IMAGE_OS2_SIGNATURE 0x454E /* NE */
+#define IMAGE_OS2_SIGNATURE_LE 0x454C /* LE */
+#define IMAGE_OS2_SIGNATURE_LX 0x584C /* LX */
+#define IMAGE_VXD_SIGNATURE 0x454C /* LE */
+#define IMAGE_NT_SIGNATURE 0x00004550 /* PE00 */
+
+/* Subsystem Values */
+
+#define IMAGE_SUBSYSTEM_UNKNOWN 0
+#define IMAGE_SUBSYSTEM_NATIVE 1
+#define IMAGE_SUBSYSTEM_WINDOWS_GUI 2 /* Windows GUI subsystem */
+#define IMAGE_SUBSYSTEM_WINDOWS_CUI 3 /* Windows character subsystem*/
+#define IMAGE_SUBSYSTEM_OS2_CUI 5
+#define IMAGE_SUBSYSTEM_POSIX_CUI 7
+
+typedef struct _IMAGE_FILE_HEADER {
+ unsigned short Machine;
+ unsigned short NumberOfSections;
+ unsigned long TimeDateStamp;
+ unsigned long PointerToSymbolTable;
+ unsigned long NumberOfSymbols;
+ unsigned short SizeOfOptionalHeader;
+ unsigned short Characteristics;
+} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
+
+typedef struct _IMAGE_DATA_DIRECTORY {
+ unsigned long VirtualAddress;
+ unsigned long Size;
+} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
+
+#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
+
+typedef struct _IMAGE_OPTIONAL_HEADER {
+
+ /* Standard fields */
+
+ unsigned short Magic; /* 0x10b or 0x107 */ /* 0x00 */
+ unsigned char MajorLinkerVersion;
+ unsigned char MinorLinkerVersion;
+ unsigned long SizeOfCode;
+ unsigned long SizeOfInitializedData;
+ unsigned long SizeOfUninitializedData;
+ unsigned long AddressOfEntryPoint; /* 0x10 */
+ unsigned long BaseOfCode;
+ unsigned long BaseOfData;
+
+ /* NT additional fields */
+
+ unsigned long ImageBase;
+ unsigned long SectionAlignment; /* 0x20 */
+ unsigned long FileAlignment;
+ unsigned short MajorOperatingSystemVersion;
+ unsigned short MinorOperatingSystemVersion;
+ unsigned short MajorImageVersion;
+ unsigned short MinorImageVersion;
+ unsigned short MajorSubsystemVersion; /* 0x30 */
+ unsigned short MinorSubsystemVersion;
+ unsigned long Win32VersionValue;
+ unsigned long SizeOfImage;
+ unsigned long SizeOfHeaders;
+ unsigned long CheckSum; /* 0x40 */
+ unsigned short Subsystem;
+ unsigned short DllCharacteristics;
+ unsigned long SizeOfStackReserve;
+ unsigned long SizeOfStackCommit;
+ unsigned long SizeOfHeapReserve; /* 0x50 */
+ unsigned long SizeOfHeapCommit;
+ unsigned long LoaderFlags;
+ unsigned long NumberOfRvaAndSizes;
+ IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; /* 0x60 */
+ /* 0xE0 */
+} IMAGE_OPTIONAL_HEADER, *PIMAGE_OPTIONAL_HEADER;
+
+typedef struct _IMAGE_NT_HEADERS {
+ unsigned long Signature; /* "PE"\0\0 */ /* 0x00 */
+ IMAGE_FILE_HEADER FileHeader; /* 0x04 */
+ IMAGE_OPTIONAL_HEADER OptionalHeader; /* 0x18 */
+} IMAGE_NT_HEADERS, *PIMAGE_NT_HEADERS;
+
+#define IMAGE_SIZEOF_SHORT_NAME 8
+
+typedef struct _IMAGE_SECTION_HEADER {
+ unsigned char Name[IMAGE_SIZEOF_SHORT_NAME];
+ union {
+ unsigned long PhysicalAddress;
+ unsigned long VirtualSize;
+ } Misc;
+ unsigned long VirtualAddress;
+ unsigned long SizeOfRawData;
+ unsigned long PointerToRawData;
+ unsigned long PointerToRelocations;
+ unsigned long PointerToLinenumbers;
+ unsigned short NumberOfRelocations;
+ unsigned short NumberOfLinenumbers;
+ unsigned long Characteristics;
+} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
+
+#define IMAGE_SIZEOF_SECTION_HEADER 40
+
+#define IMAGE_FIRST_SECTION(ntheader) \
+ ((PIMAGE_SECTION_HEADER)((LPunsigned char)&((PIMAGE_NT_HEADERS)(ntheader))->OptionalHeader + \
+ ((PIMAGE_NT_HEADERS)(ntheader))->FileHeader.SizeOfOptionalHeader))
+
+/* These defines are for the Characteristics bitfield. */
+/* #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 */
+
+#define IMAGE_SCN_CNT_CODE 0x00000020
+#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040
+#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080
+
+#define IMAGE_SCN_LNK_OTHER 0x00000100
+#define IMAGE_SCN_LNK_INFO 0x00000200
+/* #define IMAGE_SCN_TYPE_OVER 0x00000400 - Reserved */
+#define IMAGE_SCN_LNK_REMOVE 0x00000800
+#define IMAGE_SCN_LNK_COMDAT 0x00001000
+
+/* 0x00002000 - Reserved */
+/* #define IMAGE_SCN_MEM_PROTECTED 0x00004000 - Obsolete */
+#define IMAGE_SCN_MEM_FARDATA 0x00008000
+
+/* #define IMAGE_SCN_MEM_SYSHEAP 0x00010000 - Obsolete */
+#define IMAGE_SCN_MEM_PURGEABLE 0x00020000
+#define IMAGE_SCN_MEM_16BIT 0x00020000
+#define IMAGE_SCN_MEM_LOCKED 0x00040000
+#define IMAGE_SCN_MEM_PRELOAD 0x00080000
+
+#define IMAGE_SCN_ALIGN_1BYTES 0x00100000
+#define IMAGE_SCN_ALIGN_2BYTES 0x00200000
+#define IMAGE_SCN_ALIGN_4BYTES 0x00300000
+#define IMAGE_SCN_ALIGN_8BYTES 0x00400000
+#define IMAGE_SCN_ALIGN_16BYTES 0x00500000 /* Default */
+#define IMAGE_SCN_ALIGN_32BYTES 0x00600000
+#define IMAGE_SCN_ALIGN_64BYTES 0x00700000
+/* 0x00800000 - Unused */
+
+#define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000
+
+
+#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000
+#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000
+#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000
+#define IMAGE_SCN_MEM_SHARED 0x10000000
+#define IMAGE_SCN_MEM_EXECUTE 0x20000000
+#define IMAGE_SCN_MEM_READ 0x40000000
+#define IMAGE_SCN_MEM_WRITE 0x80000000
+
+#pragma pack()
+
+typedef struct _GUID /* 16 bytes */
+{
+ unsigned int Data1;
+ unsigned short Data2;
+ unsigned short Data3;
+ unsigned char Data4[ 8 ];
+} GUID;
+
+/*========================================================================
+ * Process PDB file.
+ */
+
+#pragma pack(1)
+typedef struct _PDB_FILE
+{
+ unsigned long size;
+ unsigned long unknown;
+
+} PDB_FILE, *PPDB_FILE;
+
+// A .pdb file begins with a variable-length one-line text string
+// that ends in "\r\n\032". This is followed by a 4-byte "signature"
+// ("DS\0\0" for newer files, "JG\0\0" for older files), then
+// aligned up to a 4-byte boundary, then the struct below:
+struct PDB_JG_HEADER
+{
+ //char ident[40]; // "Microsoft C/C++ program database 2.00\r\n\032"
+ //unsigned long signature; // "JG\0\0"
+ unsigned int blocksize; // 0x400 typical; also 0x800, 0x1000
+ unsigned short freelist;
+ unsigned short total_alloc;
+ PDB_FILE toc;
+ unsigned short toc_block[ 1 ];
+};
+
+struct PDB_DS_HEADER
+{
+ //char signature[32]; // "Microsoft C/C++ MSF 7.00\r\n\032DS\0\0"
+ unsigned int block_size;
+ unsigned int unknown1;
+ unsigned int num_pages;
+ unsigned int toc_size;
+ unsigned int unknown2;
+ unsigned int toc_page;
+};
+
+struct PDB_JG_TOC
+{
+ unsigned int nFiles;
+ PDB_FILE file[ 1 ];
+
+};
+
+struct PDB_DS_TOC
+{
+ unsigned int num_files;
+ unsigned int file_size[1];
+};
+
+struct PDB_JG_ROOT
+{
+ unsigned int version;
+ unsigned int TimeDateStamp;
+ unsigned int age;
+ unsigned int cbNames;
+ char names[ 1 ];
+};
+
+struct PDB_DS_ROOT
+{
+ unsigned int version;
+ unsigned int TimeDateStamp;
+ unsigned int age;
+ GUID guid;
+ unsigned int cbNames;
+ char names[1];
+};
+
+typedef struct _PDB_TYPES_OLD
+{
+ unsigned long version;
+ unsigned short first_index;
+ unsigned short last_index;
+ unsigned long type_size;
+ unsigned short file;
+ unsigned short pad;
+
+} PDB_TYPES_OLD, *PPDB_TYPES_OLD;
+
+typedef struct _PDB_TYPES
+{
+ unsigned long version;
+ unsigned long type_offset;
+ unsigned long first_index;
+ unsigned long last_index;
+ unsigned long type_size;
+ unsigned short file;
+ unsigned short pad;
+ unsigned long hash_size;
+ unsigned long hash_base;
+ unsigned long hash_offset;
+ unsigned long hash_len;
+ unsigned long search_offset;
+ unsigned long search_len;
+ unsigned long unknown_offset;
+ unsigned long unknown_len;
+
+} PDB_TYPES, *PPDB_TYPES;
+
+typedef struct _PDB_SYMBOL_RANGE
+{
+ unsigned short segment;
+ unsigned short pad1;
+ unsigned long offset;
+ unsigned long size;
+ unsigned long characteristics;
+ unsigned short index;
+ unsigned short pad2;
+
+} PDB_SYMBOL_RANGE, *PPDB_SYMBOL_RANGE;
+
+typedef struct _PDB_SYMBOL_RANGE_EX
+{
+ unsigned short segment;
+ unsigned short pad1;
+ unsigned long offset;
+ unsigned long size;
+ unsigned long characteristics;
+ unsigned short index;
+ unsigned short pad2;
+ unsigned long timestamp;
+ unsigned long unknown;
+
+} PDB_SYMBOL_RANGE_EX, *PPDB_SYMBOL_RANGE_EX;
+
+typedef struct _PDB_SYMBOL_FILE
+{
+ unsigned long unknown1;
+ PDB_SYMBOL_RANGE range;
+ unsigned short flag;
+ unsigned short file;
+ unsigned long symbol_size;
+ unsigned long lineno_size;
+ unsigned long unknown2;
+ unsigned long nSrcFiles;
+ unsigned long attribute;
+ char filename[ 1 ];
+
+} PDB_SYMBOL_FILE, *PPDB_SYMBOL_FILE;
+
+typedef struct _PDB_SYMBOL_FILE_EX
+{
+ unsigned long unknown1;
+ PDB_SYMBOL_RANGE_EX range;
+ unsigned short flag;
+ unsigned short file;
+ unsigned long symbol_size;
+ unsigned long lineno_size;
+ unsigned long unknown2;
+ unsigned long nSrcFiles;
+ unsigned long attribute;
+ unsigned long reserved[ 2 ];
+ char filename[ 1 ];
+
+} PDB_SYMBOL_FILE_EX, *PPDB_SYMBOL_FILE_EX;
+
+typedef struct _PDB_SYMBOL_SOURCE
+{
+ unsigned short nModules;
+ unsigned short nSrcFiles;
+ unsigned short table[ 1 ];
+
+} PDB_SYMBOL_SOURCE, *PPDB_SYMBOL_SOURCE;
+
+typedef struct _PDB_SYMBOL_IMPORT
+{
+ unsigned long unknown1;
+ unsigned long unknown2;
+ unsigned long TimeDateStamp;
+ unsigned long nRequests;
+ char filename[ 1 ];
+
+} PDB_SYMBOL_IMPORT, *PPDB_SYMBOL_IMPORT;
+
+typedef struct _PDB_SYMBOLS_OLD
+{
+ unsigned short hash1_file;
+ unsigned short hash2_file;
+ unsigned short gsym_file;
+ unsigned short pad;
+ unsigned long module_size;
+ unsigned long offset_size;
+ unsigned long hash_size;
+ unsigned long srcmodule_size;
+
+} PDB_SYMBOLS_OLD, *PPDB_SYMBOLS_OLD;
+
+typedef struct _PDB_SYMBOLS
+{
+ unsigned long signature;
+ unsigned long version;
+ unsigned long unknown;
+ unsigned long hash1_file;
+ unsigned long hash2_file;
+ unsigned long gsym_file;
+ unsigned long module_size;
+ unsigned long offset_size;
+ unsigned long hash_size;
+ unsigned long srcmodule_size;
+ unsigned long pdbimport_size;
+ unsigned long resvd[ 5 ];
+
+} PDB_SYMBOLS, *PPDB_SYMBOLS;
+#pragma pack()
+
+/*========================================================================
+ * Process CodeView symbol information.
+ */
+
+/* from wine-1.0/include/wine/mscvpdb.h */
+
+struct p_string /* "Pascal string": prefixed by byte containing length */
+{
+ unsigned char namelen;
+ char name[1];
+};
+/* The other kind of "char name[1]" is a "C++ string" terminated by '\0'.
+ * "Name mangling" to encode type information often exceeds 255 bytes.
+ * Instead of using a 2-byte explicit length, they save one byte of space
+ * but incur a strlen(). This is justified by other code that wants
+ * a "C string" [terminated by '\0'] anyway.
+ */
+
+union codeview_symbol
+{
+ struct
+ {
+ short int len;
+ short int id;
+ } generic;
+
+ struct
+ {
+ short int len;
+ short int id;
+ unsigned int offset;
+ unsigned short segment;
+ unsigned short symtype;
+ struct p_string p_name;
+ } data_v1;
+
+ struct
+ {
+ short int len;
+ short int id;
+ unsigned int symtype;
+ unsigned int offset;
+ unsigned short segment;
+ struct p_string p_name;
+ } data_v2;
+
+ struct
+ {
+ short int len;
+ short int id;
+ unsigned int symtype;
+ unsigned int offset;
+ unsigned short segment;
+ char name[1]; /* terminated by '\0' */
+ } data_v3;
+
+ struct
+ {
+ short int len;
+ short int id;
+ unsigned int pparent;
+ unsigned int pend;
+ unsigned int next;
+ unsigned int offset;
+ unsigned short segment;
+ unsigned short thunk_len;
+ unsigned char thtype;
+ struct p_string p_name;
+ } thunk_v1;
+
+ struct
+ {
+ short int len;
+ short int id;
+ unsigned int pparent;
+ unsigned int pend;
+ unsigned int next;
+ unsigned int offset;
+ unsigned short segment;
+ unsigned short thunk_len;
+ unsigned char thtype;
+ char name[1]; /* terminated by '\0' */
+ } thunk_v3;
+
+ struct
+ {
+ short int len;
+ short int id;
+ unsigned int pparent;
+ unsigned int pend;
+ unsigned int next;
+ unsigned int proc_len;
+ unsigned int debug_start;
+ unsigned int debug_end;
+ unsigned int offset;
+ unsigned short segment;
+ unsigned short proctype;
+ unsigned char flags;
+ struct p_string p_name;
+ } proc_v1;
+
+ struct
+ {
+ short int len;
+ short int id;
+ unsigned int pparent;
+ unsigned int pend;
+ unsigned int next;
+ unsigned int proc_len;
+ unsigned int debug_start;
+ unsigned int debug_end;
+ unsigned int proctype;
+ unsigned int offset;
+ unsigned short segment;
+ unsigned char flags;
+ struct p_string p_name;
+ } proc_v2;
+
+ struct
+ {
+ short int len;
+ short int id;
+ unsigned int pparent;
+ unsigned int pend;
+ unsigned int next;
+ unsigned int proc_len;
+ unsigned int debug_start;
+ unsigned int debug_end;
+ unsigned int proctype;
+ unsigned int offset;
+ unsigned short segment;
+ unsigned char flags;
+ char name[1]; /* terminated by '\0' */
+ } proc_v3;
+
+ struct
+ {
+ short int len;
+ short int id;
+ unsigned int symtype;
+ unsigned int offset;
+ unsigned short segment;
+ struct p_string p_name;
+ } public_v2;
+
+ struct
+ {
+ short int len;
+ short int id;
+ unsigned int symtype;
+ unsigned int offset;
+ unsigned short segment;
+ char name[1]; /* terminated by '\0' */
+ } public_v3;
+
+ struct
+ {
+ short int len; /* Total length of this entry */
+ short int id; /* Always S_BPREL_V1 */
+ unsigned int offset; /* Stack offset relative to BP */
+ unsigned short symtype;
+ struct p_string p_name;
+ } stack_v1;
+
+ struct
+ {
+ short int len; /* Total length of this entry */
+ short int id; /* Always S_BPREL_V2 */
+ unsigned int offset; /* Stack offset relative to EBP */
+ unsigned int symtype;
+ struct p_string p_name;
+ } stack_v2;
+
+ struct
+ {
+ short int len; /* Total length of this entry */
+ short int id; /* Always S_BPREL_V3 */
+ int offset; /* Stack offset relative to BP */
+ unsigned int symtype;
+ char name[1]; /* terminated by '\0' */
+ } stack_v3;
+
+ struct
+ {
+ short int len; /* Total length of this entry */
+ short int id; /* Always S_BPREL_V3 */
+ int offset; /* Stack offset relative to BP */
+ unsigned int symtype;
+ unsigned short unknown;
+ char name[1]; /* terminated by '\0' */
+ } stack_xxxx_v3;
+
+ struct
+ {
+ short int len; /* Total length of this entry */
+ short int id; /* Always S_REGISTER */
+ unsigned short type;
+ unsigned short reg;
+ struct p_string p_name;
+ /* don't handle register tracking */
+ } register_v1;
+
+ struct
+ {
+ short int len; /* Total length of this entry */
+ short int id; /* Always S_REGISTER_V2 */
+ unsigned int type; /* check whether type & reg are correct */
+ unsigned short reg;
+ struct p_string p_name;
+ /* don't handle register tracking */
+ } register_v2;
+
+ struct
+ {
+ short int len; /* Total length of this entry */
+ short int id; /* Always S_REGISTER_V3 */
+ unsigned int type; /* check whether type & reg are correct */
+ unsigned short reg;
+ char name[1]; /* terminated by '\0' */
+ /* don't handle register tracking */
+ } register_v3;
+
+ struct
+ {
+ short int len;
+ short int id;
+ unsigned int parent;
+ unsigned int end;
+ unsigned int length;
+ unsigned int offset;
+ unsigned short segment;
+ struct p_string p_name;
+ } block_v1;
+
+ struct
+ {
+ short int len;
+ short int id;
+ unsigned int parent;
+ unsigned int end;
+ unsigned int length;
+ unsigned int offset;
+ unsigned short segment;
+ char name[1]; /* terminated by '\0' */
+ } block_v3;
+
+ struct
+ {
+ short int len;
+ short int id;
+ unsigned int offset;
+ unsigned short segment;
+ unsigned char flags;
+ struct p_string p_name;
+ } label_v1;
+
+ struct
+ {
+ short int len;
+ short int id;
+ unsigned int offset;
+ unsigned short segment;
+ unsigned char flags;
+ char name[1]; /* terminated by '\0' */
+ } label_v3;
+
+ struct
+ {
+ short int len;
+ short int id;
+ unsigned short type;
+ unsigned short cvalue; /* numeric leaf */
+#if 0
+ struct p_string p_name;
+#endif
+ } constant_v1;
+
+ struct
+ {
+ short int len;
+ short int id;
+ unsigned type;
+ unsigned short cvalue; /* numeric leaf */
+#if 0
+ struct p_string p_name;
+#endif
+ } constant_v2;
+
+ struct
+ {
+ short int len;
+ short int id;
+ unsigned type;
+ unsigned short cvalue;
+#if 0
+ char name[1]; /* terminated by '\0' */
+#endif
+ } constant_v3;
+
+ struct
+ {
+ short int len;
+ short int id;
+ unsigned short type;
+ struct p_string p_name;
+ } udt_v1;
+
+ struct
+ {
+ short int len;
+ short int id;
+ unsigned type;
+ struct p_string p_name;
+ } udt_v2;
+
+ struct
+ {
+ short int len;
+ short int id;
+ unsigned int type;
+ char name[1]; /* terminated by '\0' */
+ } udt_v3;
+
+ struct
+ {
+ short int len;
+ short int id;
+ char signature[4];
+ struct p_string p_name;
+ } objname_v1;
+
+ struct
+ {
+ short int len;
+ short int id;
+ unsigned int unknown;
+ struct p_string p_name;
+ } compiland_v1;
+
+ struct
+ {
+ short int len;
+ short int id;
+ unsigned unknown1[4];
+ unsigned short unknown2;
+ struct p_string p_name;
+ } compiland_v2;
+
+ struct
+ {
+ short int len;
+ short int id;
+ unsigned int unknown;
+ char name[1]; /* terminated by '\0' */
+ } compiland_v3;
+
+ struct
+ {
+ short int len;
+ short int id;
+ unsigned int offset;
+ unsigned short segment;
+ } ssearch_v1;
+};
+
+#define S_COMPILAND_V1 0x0001
+#define S_REGISTER_V1 0x0002
+#define S_CONSTANT_V1 0x0003
+#define S_UDT_V1 0x0004
+#define S_SSEARCH_V1 0x0005
+#define S_END_V1 0x0006
+#define S_SKIP_V1 0x0007
+#define S_CVRESERVE_V1 0x0008
+#define S_OBJNAME_V1 0x0009
+#define S_ENDARG_V1 0x000a
+#define S_COBOLUDT_V1 0x000b
+#define S_MANYREG_V1 0x000c
+#define S_RETURN_V1 0x000d
+#define S_ENTRYTHIS_V1 0x000e
+
+#define S_BPREL_V1 0x0200
+#define S_LDATA_V1 0x0201
+#define S_GDATA_V1 0x0202
+#define S_PUB_V1 0x0203
+#define S_LPROC_V1 0x0204
+#define S_GPROC_V1 0x0205
+#define S_THUNK_V1 0x0206
+#define S_BLOCK_V1 0x0207
+#define S_WITH_V1 0x0208
+#define S_LABEL_V1 0x0209
+#define S_CEXMODEL_V1 0x020a
+#define S_VFTPATH_V1 0x020b
+#define S_REGREL_V1 0x020c
+#define S_LTHREAD_V1 0x020d
+#define S_GTHREAD_V1 0x020e
+
+#define S_PROCREF_V1 0x0400
+#define S_DATAREF_V1 0x0401
+#define S_ALIGN_V1 0x0402
+#define S_LPROCREF_V1 0x0403
+
+#define S_REGISTER_V2 0x1001 /* Variants with new 32-bit type indices */
+#define S_CONSTANT_V2 0x1002
+#define S_UDT_V2 0x1003
+#define S_COBOLUDT_V2 0x1004
+#define S_MANYREG_V2 0x1005
+#define S_BPREL_V2 0x1006
+#define S_LDATA_V2 0x1007
+#define S_GDATA_V2 0x1008
+#define S_PUB_V2 0x1009
+#define S_LPROC_V2 0x100a
+#define S_GPROC_V2 0x100b
+#define S_VFTTABLE_V2 0x100c
+#define S_REGREL_V2 0x100d
+#define S_LTHREAD_V2 0x100e
+#define S_GTHREAD_V2 0x100f
+#if 0
+#define S_XXXXXXXXX_32 0x1012 /* seems linked to a function, content unknown */
+#endif
+#define S_COMPILAND_V2 0x1013
+
+#define S_COMPILAND_V3 0x1101
+#define S_THUNK_V3 0x1102
+#define S_BLOCK_V3 0x1103
+#define S_LABEL_V3 0x1105
+#define S_REGISTER_V3 0x1106
+#define S_CONSTANT_V3 0x1107
+#define S_UDT_V3 0x1108
+#define S_BPREL_V3 0x110B
+#define S_LDATA_V3 0x110C
+#define S_GDATA_V3 0x110D
+#define S_PUB_V3 0x110E
+#define S_LPROC_V3 0x110F
+#define S_GPROC_V3 0x1110
+#define S_BPREL_XXXX_V3 0x1111 /* not really understood, but looks like bprel... */
+#define S_MSTOOL_V3 0x1116 /* compiler command line options and build information */
+#define S_PUB_FUNC1_V3 0x1125 /* didn't get the difference between the two */
+#define S_PUB_FUNC2_V3 0x1127
+
+
+/*------------------------------------------------------------*/
+/*--- ---*/
+/*--- pdb-reading: bits and pieces ---*/
+/*--- ---*/
+/*------------------------------------------------------------*/
+
+struct pdb_reader
+{
+ void* (*read_file)(struct pdb_reader*, unsigned, unsigned *);
+ // JRS 2009-Apr-8: .uu_n_pdbimage is never used.
+ UChar* pdbimage; // image address
+ SizeT uu_n_pdbimage; // size
+ union {
+ struct {
+ struct PDB_JG_HEADER* header;
+ struct PDB_JG_TOC* toc;
+ } jg;
+ struct {
+ struct PDB_DS_HEADER* header;
+ struct PDB_DS_TOC* toc;
+ } ds;
+ } u;
+};
+
+
+static void* pdb_ds_read( struct pdb_reader* pdb,
+ unsigned* block_list,
+ unsigned size )
+{
+ unsigned blocksize, nBlocks;
+ UChar* buffer;
+ UInt i;
+
+ if (!size) return NULL;
+
+ blocksize = pdb->u.ds.header->block_size;
+ nBlocks = (size + blocksize - 1) / blocksize;
+ buffer = ML_(dinfo_zalloc)("di.readpe.pdr.1", nBlocks * blocksize);
+ for (i = 0; i < nBlocks; i++)
+ VG_(memcpy)( buffer + i * blocksize,
+ pdb->pdbimage + block_list[i] * blocksize,
+ blocksize );
+ return buffer;
+}
+
+
+static void* pdb_jg_read( struct pdb_reader* pdb,
+ unsigned short* block_list,
+ int size )
+{
+ unsigned blocksize, nBlocks;
+ UChar* buffer;
+ UInt i;
+ //VG_(printf)("pdb_read %p %p %d\n", pdb, block_list, size);
+ if ( !size ) return NULL;
+
+ blocksize = pdb->u.jg.header->blocksize;
+ nBlocks = (size + blocksize-1) / blocksize;
+ buffer = ML_(dinfo_zalloc)("di.readpe.pjr.1", nBlocks * blocksize);
+ for ( i = 0; i < nBlocks; i++ )
+ VG_(memcpy)( buffer + i*blocksize,
+ pdb->pdbimage + block_list[i]*blocksize, blocksize );
+ return buffer;
+}
+
+
+static void* find_pdb_header( UChar* pdbimage,
+ unsigned* signature )
+{
+ static char pdbtxt[]= "Microsoft C/C++";
+ UChar* txteof = (UChar*)VG_(strchr)(pdbimage, '\032');
+ if (! txteof)
+ return NULL;
+ if (0!=VG_(strncmp)(pdbimage, pdbtxt, -1+ sizeof(pdbtxt)))
+ return NULL;
+
+ *signature = *(unsigned*)(1+ txteof);
+ return (void*)((~3& (3+ (4+ 1+ (txteof - pdbimage)))) + pdbimage);
+}
+
+
+static void* pdb_ds_read_file( struct pdb_reader* reader,
+ unsigned file_number,
+ unsigned* plength )
+{
+ unsigned i, *block_list;
+ if (!reader->u.ds.toc || file_number >= reader->u.ds.toc->num_files)
+ return NULL;
+ if (reader->u.ds.toc->file_size[file_number] == 0
+ || reader->u.ds.toc->file_size[file_number] == 0xFFFFFFFF)
+ return NULL;
+
+ block_list
+ = reader->u.ds.toc->file_size + reader->u.ds.toc->num_files;
+ for (i = 0; i < file_number; i++)
+ block_list += (reader->u.ds.toc->file_size[i]
+ + reader->u.ds.header->block_size - 1)
+ /
+ reader->u.ds.header->block_size;
+ if (plength)
+ *plength = reader->u.ds.toc->file_size[file_number];
+ return pdb_ds_read( reader, block_list,
+ reader->u.ds.toc->file_size[file_number]);
+}
+
+
+static void* pdb_jg_read_file( struct pdb_reader* pdb,
+ unsigned fileNr,
+ unsigned *plength )
+{
+ //VG_(printf)("pdb_read_file %p %d\n", pdb, fileNr);
+ unsigned blocksize = pdb->u.jg.header->blocksize;
+ struct PDB_JG_TOC* toc = pdb->u.jg.toc;
+ unsigned i;
+ unsigned short* block_list;
+
+ if ( !toc || fileNr >= toc->nFiles )
+ return NULL;
+
+ block_list
+ = (unsigned short *) &toc->file[ toc->nFiles ];
+ for ( i = 0; i < fileNr; i++ )
+ block_list += (toc->file[i].size + blocksize-1) / blocksize;
+
+ if (plength)
+ *plength = toc->file[fileNr].size;
+ return pdb_jg_read( pdb, block_list, toc->file[fileNr].size );
+}
+
+
+static void pdb_ds_init( struct pdb_reader * reader,
+ UChar* pdbimage,
+ SizeT n_pdbimage )
+{
+ reader->read_file = pdb_ds_read_file;
+ reader->pdbimage = pdbimage;
+ reader->uu_n_pdbimage = n_pdbimage;
+ reader->u.ds.toc
+ = pdb_ds_read(
+ reader,
+ (unsigned*)(reader->u.ds.header->block_size
+ * reader->u.ds.header->toc_page
+ + reader->pdbimage),
+ reader->u.ds.header->toc_size
+ );
+}
+
+
+static void pdb_jg_init( struct pdb_reader* reader,
+ char* pdbimage,
+ unsigned n_pdbimage )
+{
+ reader->read_file = pdb_jg_read_file;
+ reader->pdbimage = pdbimage;
+ reader->uu_n_pdbimage = n_pdbimage;
+ reader->u.jg.toc = pdb_jg_read(reader,
+ reader->u.jg.header->toc_block,
+ reader->u.jg.header->toc.size);
+}
+
+
+
+
+static
+void pdb_check_root_version_and_timestamp( char* pdbname,
+ ULong pdbmtime,
+ unsigned version,
+ UInt TimeDateStamp )
+{
+ switch ( version ) {
+ case 19950623: /* VC 4.0 */
+ case 19950814:
+ case 19960307: /* VC 5.0 */
+ case 19970604: /* VC 6.0 */
+ case 20000404: /* VC 7.0 FIXME?? */
+ break;
+ default:
+ if (VG_(clo_verbosity) > 1)
+ VG_(message)(Vg_UserMsg,
+ "Unknown .pdb root block version %d\n", version );
+ }
+ if ( TimeDateStamp != pdbmtime ) {
+ if (VG_(clo_verbosity) > 1)
+ VG_(message)(Vg_UserMsg,
+ "Wrong time stamp of .PDB file %s (0x%08x, 0x%08llx)\n",
+ pdbname, TimeDateStamp, pdbmtime );
+ }
+}
+
+
+static DWORD pdb_get_file_size( struct pdb_reader* reader, unsigned idx )
+{
+ if (reader->read_file == pdb_jg_read_file)
+ return reader->u.jg.toc->file[idx].size;
+ else
+ return reader->u.ds.toc->file_size[idx];
+}
+
+
+static void pdb_convert_types_header( PDB_TYPES *types, char* image )
+{
+ VG_(memset)( types, 0, sizeof(PDB_TYPES) );
+ if ( !image )
+ return;
+ if ( *(unsigned long *)image < 19960000 ) { /* FIXME: correct version? */
+ /* Old version of the types record header */
+ PDB_TYPES_OLD *old = (PDB_TYPES_OLD *)image;
+ types->version = old->version;
+ types->type_offset = sizeof(PDB_TYPES_OLD);
+ types->type_size = old->type_size;
+ types->first_index = old->first_index;
+ types->last_index = old->last_index;
+ types->file = old->file;
+ } else {
+ /* New version of the types record header */
+ *types = *(PDB_TYPES *)image;
+ }
+}
+
+
+static void pdb_convert_symbols_header( PDB_SYMBOLS *symbols,
+ int *header_size, char* image )
+{
+ VG_(memset)( symbols, 0, sizeof(PDB_SYMBOLS) );
+ if ( !image )
+ return;
+ if ( *(unsigned long *)image != 0xffffffff ) {
+ /* Old version of the symbols record header */
+ PDB_SYMBOLS_OLD *old = (PDB_SYMBOLS_OLD *)image;
+ symbols->version = 0;
+ symbols->module_size = old->module_size;
+ symbols->offset_size = old->offset_size;
+ symbols->hash_size = old->hash_size;
+ symbols->srcmodule_size = old->srcmodule_size;
+ symbols->pdbimport_size = 0;
+ symbols->hash1_file = old->hash1_file;
+ symbols->hash2_file = old->hash2_file;
+ symbols->gsym_file = old->gsym_file;
+ *header_size = sizeof(PDB_SYMBOLS_OLD);
+ } else {
+ /* New version of the symbols record header */
+ *symbols = *(PDB_SYMBOLS *)image;
+ *header_size = sizeof(PDB_SYMBOLS);
+ }
+}
+
+
+/*------------------------------------------------------------*/
+/*--- ---*/
+/*--- Main stuff: reading of symbol addresses ---*/
+/*--- ---*/
+/*------------------------------------------------------------*/
+
+static Bool debug = False; // JRS: fixme
+
+static ULong DEBUG_SnarfCodeView(
+ DebugInfo* di,
+ IMAGE_SECTION_HEADER* sectp,
+ void* root, /* FIXME: better name */
+ Int offset,
+ Int size
+ )
+{
+ Int i, length;
+ DiSym vsym;
+ UChar* nmstr;
+ Char symname[4096 /*WIN32_PATH_MAX*/];
+
+ Addr bias = BIAS_FOR_SYMBOLS;
+ ULong n_syms_read = 0;
+
+ if (debug)
+ VG_(message)(Vg_UserMsg, "SnarfCodeView addr=%p offset=%d length=%d",
+ root, offset, size );
+
+ VG_(memset)(&vsym, 0, sizeof(vsym)); /* avoid holes */
+ /*
+ * Loop over the different types of records and whenever we
+ * find something we are interested in, record it and move on.
+ */
+ for ( i = offset; i < size; i += length )
+ {
+ union codeview_symbol *sym = (union codeview_symbol *)((char *)root + i);
+
+ length = sym->generic.len + 2;
+
+ //VG_(printf)("id=%x len=%d\n", sym->generic.id, length);
+ switch ( sym->generic.id ) {
+
+ default:
+ if (0) {
+ VG_(printf)("unknown id 0x%x len=0x%x at %p\n",
+ sym->generic.id, sym->generic.len, sym);
+ VG_(printf)(" %8x %8x %8x %8x\n",
+ ((int *)sym)[1],((int *)sym)[2],
+ ((int *)sym)[3],((int *)sym)[4]);
+ VG_(printf)(" %8x %8x %8x %8x\n",
+ ((int *)sym)[5],((int *)sym)[6],
+ ((int *)sym)[7],((int *)sym)[8]);
+ }
+ break;
+ /*
+ * Global and local data symbols. We don't associate these
+ * with any given source file.
+ */
+ case S_GDATA_V1:
+ case S_LDATA_V1:
+ case S_PUB_V1:
+ VG_(memcpy)(symname, sym->data_v1.p_name.name,
+ sym->data_v1.p_name.namelen);
+ symname[sym->data_v1.p_name.namelen] = '\0';
+
+ if (debug)
+ VG_(message)(Vg_UserMsg, "Data %s", symname );
+
+ if (0 /*VG_(needs).data_syms*/) {
+ nmstr = ML_(addStr)(di, symname, sym->data_v1.p_name.namelen);
+
+ vsym.addr = bias + sectp[sym->data_v1.segment-1].VirtualAddress
+ + sym->data_v1.offset;
+ vsym.name = nmstr;
+ vsym.size = sym->data_v1.p_name.namelen;
+ // FIXME: .namelen is sizeof(.data) including .name[]
+ vsym.isText = (sym->generic.id == S_PUB_V1);
+ ML_(addSym)( di, &vsym );
+ n_syms_read++;
+ }
+ break;
+ case S_GDATA_V2:
+ case S_LDATA_V2:
+ case S_PUB_V2: {
+ Int const k = sym->data_v2.p_name.namelen;
+ VG_(memcpy)(symname, sym->data_v2.p_name.name, k);
+ symname[k] = '\0';
+
+ if (debug)
+ VG_(message)(Vg_UserMsg,
+ "S_GDATA_V2/S_LDATA_V2/S_PUB_V2 %s", symname );
+
+ if (sym->generic.id==S_PUB_V2 /*VG_(needs).data_syms*/) {
+ nmstr = ML_(addStr)(di, symname, k);
+
+ vsym.addr = bias + sectp[sym->data_v2.segment-1].VirtualAddress
+ + sym->data_v2.offset;
+ vsym.name = nmstr;
+ vsym.size = 4000;
+ // FIXME: data_v2.len is sizeof(.data),
+ // not size of function!
+ vsym.isText = !!(IMAGE_SCN_CNT_CODE
+ & sectp[sym->data_v2.segment-1].Characteristics);
+ ML_(addSym)( di, &vsym );
+ n_syms_read++;
+ }
+ break;
+ }
+ case S_PUB_V3:
+ /* not completely sure of those two anyway */
+ case S_PUB_FUNC1_V3:
+ case S_PUB_FUNC2_V3: {
+ Int k = sym->public_v3.len - (-1+ sizeof(sym->public_v3));
+ if ((-1+ sizeof(symname)) < k)
+ ...
[truncated message content] |
|
From: Tor L. <tm...@ik...> - 2009-04-23 07:29:40
|
> Add support for reading Windows PDB debug info (symbols and line > numbers) when Valgrind is running Wine. Yay! This code will probably also be useful when running VG on real Windows. (Sure, there is also a native API on Windows (dbghelp.dll) to read PDB files of course, but it is IMHO too complex and pulls in too many other DLLs to be used inside a VG tool, so using it would have to be relegated to a separate helper process, with some trivial shared memory and event -style request/reply IPC between the tool and helper processes.) (Of course, no new separate process is needed as such, the launcher could act also as such a helper process, after all it has nothing else to do while the tool is running.) --tml |