summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorsagitario <sagitario@fc51e93f-b9fe-4711-8d8d-3ae870c5f7d8>2009-05-08 15:54:32 (GMT)
committersagitario <sagitario@fc51e93f-b9fe-4711-8d8d-3ae870c5f7d8>2009-05-08 15:54:32 (GMT)
commitd3adcbbc0c51ab693e7fcbd95569ffd548128d02 (patch)
tree2d821e16fcb0b09ae7c43629366499bd1a4dc33a /src
downloadcv2pdb-d3adcbbc0c51ab693e7fcbd95569ffd548128d02.zip
cv2pdb-d3adcbbc0c51ab693e7fcbd95569ffd548128d02.tar.gz
cv2pdb-d3adcbbc0c51ab693e7fcbd95569ffd548128d02.tar.bz2
Diffstat (limited to 'src')
-rw-r--r--src/LastError.h24
-rw-r--r--src/PEImage.cpp238
-rw-r--r--src/PEImage.h86
-rw-r--r--src/cv2pdb.cpp2000
-rw-r--r--src/cv2pdb.h148
-rw-r--r--src/cv2pdb.sln20
-rw-r--r--src/cv2pdb.vcproj232
-rw-r--r--src/demangle.cpp493
-rw-r--r--src/demangle.h12
-rw-r--r--src/main.cpp165
-rw-r--r--src/mscvpdb.h2083
-rw-r--r--src/mspdb.cpp91
-rw-r--r--src/mspdb.h494
-rw-r--r--src/symutil.cpp152
-rw-r--r--src/symutil.h29
15 files changed, 6267 insertions, 0 deletions
diff --git a/src/LastError.h b/src/LastError.h
new file mode 100644
index 0000000..b7b6f27
--- /dev/null
+++ b/src/LastError.h
@@ -0,0 +1,24 @@
+// Convert DMD CodeView debug information to PDB files
+// Copyright (c) 2009 by Rainer Schuetze, All Rights Reserved
+//
+// License for redistribution is given by the Artistic License 2.0
+// see file LICENSE for further details
+
+#ifndef __LASTERROR_H__
+#define __LASTERROR_H__
+
+class LastError
+{
+public:
+ LastError() : lastError("") {}
+
+ bool setError(const char* msg) { lastError = msg; return false; }
+ const char* getLastError() const { return lastError; }
+ bool hadError() const { return lastError != 0 && *lastError; }
+
+private:
+ const char* lastError;
+};
+
+
+#endif //__LASTERROR_H__ \ No newline at end of file
diff --git a/src/PEImage.cpp b/src/PEImage.cpp
new file mode 100644
index 0000000..ec826a8
--- /dev/null
+++ b/src/PEImage.cpp
@@ -0,0 +1,238 @@
+// Convert DMD CodeView debug information to PDB files
+// Copyright (c) 2009 by Rainer Schuetze, All Rights Reserved
+//
+// License for redistribution is given by the Artistic License 2.0
+// see file LICENSE for further details
+
+#include "PEImage.h"
+
+extern "C" {
+#include "mscvpdb.h"
+}
+
+#include <io.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <direct.h>
+#include <sys/stat.h>
+
+///////////////////////////////////////////////////////////////////////
+PEImage::PEImage(const char* iname)
+: dump_base(0)
+, dump_total_len(0)
+, dirHeader(0)
+, fd(-1)
+{
+ if(iname)
+ load(iname);
+}
+
+PEImage::~PEImage()
+{
+ if(fd != -1)
+ close(fd);
+ if(dump_base)
+ free_aligned(dump_base);
+}
+
+///////////////////////////////////////////////////////////////////////
+bool PEImage::load(const char* iname)
+{
+ if (fd != -1)
+ return setError("file already open");
+
+ fd = open(iname, O_RDONLY | O_BINARY);
+ if (fd == -1)
+ return setError("Can't open file");
+
+ struct stat s;
+ if (fstat(fd, &s) < 0)
+ return setError("Can't get size");
+ dump_total_len = s.st_size;
+
+ dump_base = alloc_aligned(dump_total_len, 0x1000);
+ if (!dump_base)
+ return setError("Out of memory");
+ if (read(fd, dump_base, dump_total_len) != dump_total_len)
+ return setError("Cannot read file");
+
+
+ close(fd);
+ fd = -1;
+ return initPtr();
+}
+
+///////////////////////////////////////////////////////////////////////
+bool PEImage::save(const char* oname)
+{
+ if (fd != -1)
+ return setError("file already open");
+
+ if (!dump_base)
+ return setError("no data to dump");
+
+ fd = open(oname, O_WRONLY | O_CREAT | O_BINARY | O_TRUNC, S_IREAD | S_IWRITE | S_IEXEC);
+ if (fd == -1)
+ return setError("Can't create file");
+
+ if (write(fd, dump_base, dump_total_len) != dump_total_len)
+ return setError("Cannot write file");
+
+ close(fd);
+ fd = -1;
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////
+bool PEImage::replaceDebugSection (const void* data, int datalen)
+{
+ int align = hdr->OptionalHeader.FileAlignment;
+ int align_len = datalen;
+ int fill = 0;
+ if (align > 0)
+ {
+ fill = (align - (dump_total_len % align)) % align;
+ align_len = ((datalen + align - 1) / align) * align;
+ }
+ char* newdata = (char*) alloc_aligned(dump_total_len + fill + datalen, 0x1000);
+ if(!newdata)
+ return setError("cannot alloc new image");
+
+ // assume there is place for another section because of section alignment
+ int s;
+ DWORD lastVirtualAddress = 0;
+ for(s = 0; s < hdr->FileHeader.NumberOfSections; s++)
+ {
+ if (strcmp ((char*) sec [s].Name, ".debug") == 0)
+ strcpy ((char*) sec [s].Name, ".ddebug");
+ lastVirtualAddress = sec [s].VirtualAddress + sec[s].Misc.VirtualSize;
+ }
+
+ int salign_len = datalen;
+ align = hdr->OptionalHeader.SectionAlignment;
+ if (align > 0)
+ {
+ lastVirtualAddress = ((lastVirtualAddress + align - 1) / align) * align;
+ salign_len = ((datalen + align - 1) / align) * align;
+ }
+
+ strcpy((char*) sec[s].Name, ".debug");
+ sec[s].Misc.VirtualSize = align_len; // union with PhysicalAddress;
+ sec[s].VirtualAddress = lastVirtualAddress;
+ sec[s].SizeOfRawData = datalen;
+ sec[s].PointerToRawData = dump_total_len + fill;
+ sec[s].PointerToRelocations = 0;
+ sec[s].PointerToLinenumbers = 0;
+ sec[s].NumberOfRelocations = 0;
+ sec[s].NumberOfLinenumbers = 0;
+ sec[s].Characteristics = IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_CNT_INITIALIZED_DATA;
+
+ hdr->FileHeader.NumberOfSections++;
+ hdr->OptionalHeader.SizeOfImage += salign_len;
+
+ dbgDir->PointerToRawData = sec[s].PointerToRawData;
+ dbgDir->AddressOfRawData = sec[s].PointerToRawData;
+ dbgDir->SizeOfData = sec[s].SizeOfRawData;
+
+ // append debug data chunk to existing file image
+ memcpy(newdata, dump_base, dump_total_len);
+ memset(newdata + dump_total_len, 0, fill);
+ memcpy(newdata + dump_total_len + fill, data, datalen);
+
+ free_aligned(dump_base);
+ dump_base = newdata;
+ dump_total_len += fill + datalen;
+
+ return initPtr();
+}
+
+///////////////////////////////////////////////////////////////////////
+bool PEImage::initPtr()
+{
+ dos = DPV<IMAGE_DOS_HEADER> (0);
+ if(!dos)
+ return setError("file too small for DOS header");
+ if(dos->e_magic != IMAGE_DOS_SIGNATURE)
+ return setError("this is not a DOS executable");
+
+ hdr = DPV<IMAGE_NT_HEADERS32> (dos->e_lfanew);
+ if(!hdr)
+ return setError("no optional header found");
+
+ if(hdr->Signature != IMAGE_NT_SIGNATURE)
+ return setError("optional header does not have PE signature");
+ if(hdr->FileHeader.SizeOfOptionalHeader < sizeof(IMAGE_OPTIONAL_HEADER32))
+ return setError("optional header too small");
+
+ sec = IMAGE_FIRST_SECTION(hdr);
+
+ if(hdr->OptionalHeader.NumberOfRvaAndSizes <= IMAGE_DIRECTORY_ENTRY_DEBUG)
+ return setError("too few entries in data directory");
+
+ if(hdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size != 0x1c)
+ return setError("unexpected size of DEBUG data directory entry");
+
+ int off = hdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress;
+ dbgDir = RVA<IMAGE_DEBUG_DIRECTORY>(off, 0x1c);
+ if (!dbgDir)
+ return setError("debug directory not placed in image");
+ if (dbgDir->Type != IMAGE_DEBUG_TYPE_CODEVIEW)
+ return setError("debug directory not of type CodeView");
+
+ cv_base = dbgDir->PointerToRawData;
+ OMFSignature* sig = DPV<OMFSignature>(cv_base, dbgDir->SizeOfData);
+ if (!sig)
+ return setError("invalid debug data base address and size");
+ if (memcmp(sig->Signature, "NB09", 4) != 0 && memcmp(sig->Signature, "NB11", 4) != 0)
+ {
+ // return setError("can only handle debug info of type NB09 and NB11");
+ dirHeader = 0;
+ dirEntry = 0;
+ return true;
+ }
+ dirHeader = CVP<OMFDirHeader>(sig->filepos);
+ if (!dirHeader)
+ return setError("invalid cv dir header data base address");
+ dirEntry = CVP<OMFDirEntry>(sig->filepos + dirHeader->cbDirHeader);
+ if (!dirEntry)
+ return setError("cv debug dir entries invalid");
+
+ //if (dirHeader->cDir == 0)
+ // return setError("cv debug dir has no entries");
+
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////
+int PEImage::countCVEntries() const
+{
+ return dirHeader ? dirHeader->cDir : 0;
+}
+
+OMFDirEntry* PEImage::getCVEntry(int i) const
+{
+ return dirEntry + i;
+}
+
+
+///////////////////////////////////////////////////////////////////////
+// utilities
+void* PEImage::alloc_aligned(unsigned int size, unsigned int align, unsigned int alignoff)
+{
+ if (align & (align - 1))
+ return 0;
+
+ unsigned int pad = align + sizeof(void*);
+ char* p = (char*) malloc(size + pad);
+ unsigned int off = (align + alignoff - sizeof(void*) - (p - (char*) 0)) & (align - 1);
+ char* q = p + sizeof(void*) + off;
+ ((void**) q)[-1] = p;
+ return q;
+}
+
+///////////////////////////////////////////////////////////////////////
+void PEImage::free_aligned(void* p)
+{
+ void* q = ((void**) p)[-1];
+ free(q);
+}
diff --git a/src/PEImage.h b/src/PEImage.h
new file mode 100644
index 0000000..bbc2eb9
--- /dev/null
+++ b/src/PEImage.h
@@ -0,0 +1,86 @@
+// Convert DMD CodeView debug information to PDB files
+// Copyright (c) 2009 by Rainer Schuetze, All Rights Reserved
+//
+// License for redistribution is given by the Artistic License 2.0
+// see file LICENSE for further details
+
+#ifndef __PEIMAGE_H__
+#define __PEIMAGE_H__
+
+#include "LastError.h"
+
+#include <windows.h>
+
+struct OMFDirHeader;
+struct OMFDirEntry;
+
+class PEImage : public LastError
+{
+public:
+ PEImage(const char* iname = 0);
+ ~PEImage();
+
+ template<class P> P* DP(int off)
+ {
+ return (P*) ((char*) dump_base + off);
+ }
+ template<class P> P* DPV(int off, int size)
+ {
+ if(off < 0 || off + size > dump_total_len)
+ return 0;
+ return (P*) ((char*) dump_base + off);
+ }
+ template<class P> P* DPV(int off)
+ {
+ return DPV<P>(off, sizeof(P));
+ }
+ template<class P> P* CVP(int off)
+ {
+ return DPV<P>(cv_base + off, sizeof(P));
+ }
+
+ template<class P> P* RVA(unsigned long rva, int len)
+ {
+ IMAGE_DOS_HEADER *dos = DPV<IMAGE_DOS_HEADER> (0);
+ IMAGE_NT_HEADERS32* hdr = DPV<IMAGE_NT_HEADERS32> (dos->e_lfanew);
+ IMAGE_SECTION_HEADER* sec = IMAGE_FIRST_SECTION(hdr);
+
+ for (int i = 0; i < hdr->FileHeader.NumberOfSections; i++)
+ {
+ if (rva >= sec[i].VirtualAddress &&
+ rva + len <= sec[i].VirtualAddress + sec[i].SizeOfRawData)
+ return DPV<P>(sec[i].PointerToRawData + rva - sec[i].VirtualAddress, len);
+ }
+ return 0;
+ }
+
+ bool load(const char* iname);
+ bool save(const char* oname);
+
+ bool replaceDebugSection (const void* data, int datalen);
+ bool initPtr();
+
+ int countCVEntries() const;
+ OMFDirEntry* getCVEntry(int i) const;
+
+ // utilities
+ static void* alloc_aligned(unsigned int size, unsigned int align, unsigned int alignoff = 0);
+ static void free_aligned(void* p);
+
+private:
+ int fd;
+ void* dump_base;
+ int dump_total_len;
+
+ IMAGE_DOS_HEADER *dos;
+ IMAGE_NT_HEADERS32* hdr;
+ IMAGE_SECTION_HEADER* sec;
+ IMAGE_DEBUG_DIRECTORY* dbgDir;
+ OMFDirHeader* dirHeader;
+ OMFDirEntry* dirEntry;
+
+ int cv_base;
+};
+
+
+#endif //__PEIMAGE_H__ \ No newline at end of file
diff --git a/src/cv2pdb.cpp b/src/cv2pdb.cpp
new file mode 100644
index 0000000..b1a932d
--- /dev/null
+++ b/src/cv2pdb.cpp
@@ -0,0 +1,2000 @@
+// Convert DMD CodeView debug information to PDB files
+// Copyright (c) 2009 by Rainer Schuetze, All Rights Reserved
+//
+// License for redistribution is given by the Artistic License 2.0
+// see file LICENSE for further details
+
+#include "cv2pdb.h"
+#include "PEImage.h"
+#include "symutil.h"
+
+#include <stdio.h>
+#include <direct.h>
+
+static const int kIncomplete = 0x80;
+
+CV2PDB::CV2PDB(PEImage& image)
+: img(image), pdb(0), dbi(0), libraries(0), rsds(0), modules(0), globmod(0)
+, segMap(0), segMapDesc(0), globalTypeHeader(0)
+, globalTypes(0), cbGlobalTypes(0), allocGlobalTypes(0)
+, userTypes(0), cbUserTypes(0), allocUserTypes(0)
+, globalSymbols(0), cbGlobalSymbols(0), staticSymbols(0), cbStaticSymbols(0)
+, udtSymbols(0), cbUdtSymbols(0), allocUdtSymbols(0)
+, pointerTypes(0)
+, Dversion(2)
+{
+ thisIsNotRef = true;
+ v3 = true;
+ countEntries = img.countCVEntries();
+}
+
+CV2PDB::~CV2PDB()
+{
+ cleanup(false);
+}
+
+bool CV2PDB::cleanup(bool commit)
+{
+ if (modules)
+ for (int m = 0; m < countEntries; m++)
+ if (modules[m])
+ modules[m]->Close();
+ delete [] modules;
+ if (globmod)
+ globmod->Close();
+
+ if (dbi)
+ dbi->SetMachineType(0x14c);
+
+ if (dbi)
+ dbi->Close();
+ if (tpi)
+ tpi->Close();
+ if (pdb)
+ pdb->Commit();
+ if (pdb)
+ pdb->Close();
+
+ if (rsds)
+ delete [] (char*) rsds;
+ if (globalTypes)
+ free(globalTypes);
+ if (userTypes)
+ free(userTypes);
+ if (udtSymbols)
+ free(udtSymbols);
+ delete [] pointerTypes;
+
+ globalTypes = 0;
+ cbGlobalTypes = 0;
+ allocGlobalTypes = 0;
+ userTypes = 0;
+ cbUserTypes = 0;
+ allocUserTypes = 0;
+ globalSymbols = 0;
+ cbGlobalSymbols = 0;
+ staticSymbols = 0;
+ cbStaticSymbols = 0;
+ udtSymbols = 0;
+ cbUdtSymbols = 0;
+ allocUdtSymbols = 0;
+ modules = 0;
+ globmod = 0;
+ countEntries = 0;
+ dbi = 0;
+ pdb = 0;
+ rsds = 0;
+ segMap = 0;
+ segMapDesc = 0;
+ globalTypeHeader = 0;
+ objectType = 0;
+ pointerTypes = 0;
+
+ return true;
+}
+
+bool CV2PDB::openPDB(const char* pdbname)
+{
+ wchar_t pdbnameW[260]; // = L"c:\\tmp\\aa\\ddoc4.pdb";
+ mbstowcs (pdbnameW, pdbname, 260);
+
+ if (!initMsPdb ())
+ return setError("cannot load PDB helper DLL");
+ pdb = CreatePDB (pdbnameW);
+ if (!pdb)
+ return setError("cannot create PDB file");
+
+ //printf("PDB::QueryInterfaceVersion() = %d\n", pdb->QueryInterfaceVersion());
+ //printf("PDB::QueryImplementationVersion() = %d\n", pdb->QueryImplementationVersion());
+ //printf("PDB::QueryPdbImplementationVersion() = %d\n", pdb->QueryPdbImplementationVersion());
+
+ rsds = (OMFSignatureRSDS *) new char[24 + strlen(pdbname) + 1]; // sizeof(OMFSignatureRSDS) without name
+ memcpy (rsds->Signature, "RSDS", 4);
+ pdb->QuerySignature2(&rsds->guid);
+ rsds->unknown = pdb->QueryAge();
+ strcpy(rsds->name, pdbname);
+
+ int rc = pdb->CreateDBI("", &dbi);
+ if (rc <= 0 || !dbi)
+ return setError("cannot create DBI");
+
+ rc = pdb->OpenTpi("", &tpi);
+ if (rc <= 0 || !tpi)
+ return setError("cannot create TPI");
+
+ return true;
+}
+
+bool CV2PDB::setError(const char* msg)
+{
+ char pdbmsg[256];
+ if(pdb)
+ pdb->QueryLastError (pdbmsg);
+ return LastError::setError(msg);
+}
+
+bool CV2PDB::createModules()
+{
+ // assumes libraries and segMap initialized
+ countEntries = img.countCVEntries();
+ modules = new mspdb::Mod* [countEntries];
+ memset (modules, 0, countEntries * sizeof(*modules));
+
+ for (int m = 0; m < countEntries; m++)
+ {
+ OMFDirEntry* entry = img.getCVEntry(m);
+ if (entry->SubSection == sstModule)
+ {
+ OMFModule* module = img.CVP<OMFModule>(entry->lfo);
+ OMFSegDesc* segDesc = img.CVP<OMFSegDesc>(entry->lfo + sizeof(OMFModule));
+ BYTE* pname = img.CVP<BYTE>(entry->lfo + sizeof(OMFModule) + sizeof(OMFSegDesc) * module->cSeg);
+ char *name = p2c(pname);
+ const BYTE* plib = getLibrary (module->iLib);
+ const char* lib = (!plib || !*plib ? name : p2c(plib, 1));
+
+ if (modules[entry->iMod])
+ {
+ modules[entry->iMod]->Close();
+ modules[entry->iMod] = 0;
+ }
+ int rc = dbi->OpenMod(name, lib, &modules[entry->iMod]);
+ if (rc <= 0 || !modules[entry->iMod])
+ return setError("cannot create mod");
+
+ for (int s = 0; s < module->cSeg; s++)
+ {
+ int segIndex = segDesc[s].Seg;
+ int segFlags = 0;
+ if (segMap && segIndex < segMap->cSeg)
+ segFlags = segMapDesc[segIndex].flags;
+ segFlags = 0x60101020; // 0x40401040, 0x60500020; // TODO
+ rc = modules[entry->iMod]->AddSecContrib(segIndex, segDesc[s].Off, segDesc[s].cbSeg, segFlags);
+ if (rc <= 0)
+ return setError("cannot add section contribution to module");
+ }
+ }
+ }
+ return true;
+}
+
+bool CV2PDB::initLibraries()
+{
+ libraries = 0;
+ for (int m = 0; m < countEntries; m++)
+ if (img.getCVEntry(m)->SubSection == sstLibraries)
+ libraries = img.CVP<BYTE> (img.getCVEntry(m)->lfo);
+
+ return true;
+}
+
+const BYTE* CV2PDB::getLibrary(int i)
+{
+ if (!libraries)
+ return 0;
+ const BYTE* p = libraries;
+ for (int j = 0; j < i; j++)
+ p += *p + 1;
+ return p;
+}
+
+bool CV2PDB::initSegMap()
+{
+ for (int m = 0; m < countEntries; m++)
+ {
+ OMFDirEntry* entry = img.getCVEntry(m);
+ switch(entry->SubSection)
+ {
+ case sstSegMap:
+ segMap = img.CVP<OMFSegMap>(entry->lfo);
+ segMapDesc = img.CVP<OMFSegMapDesc>(entry->lfo + sizeof(OMFSegMap));
+ for (int s = 0; s < segMap->cSeg; s++)
+ {
+ int rc = dbi->AddSec(segMapDesc[s].frame, segMapDesc[s].flags, segMapDesc[s].offset, segMapDesc[s].cbSeg);
+ if (rc <= 0)
+ return setError("cannot add section");
+ }
+ break;
+ }
+ }
+ return true;
+}
+
+int CV2PDB::numeric_leaf(int* value, const void* leaf)
+{
+ unsigned short int type = *(const unsigned short int*) leaf;
+ leaf = (const unsigned short int*) leaf + 2;
+ int length = 2;
+
+ *value = 0;
+ switch (type)
+ {
+ case LF_CHAR:
+ length += 1;
+ *value = *(const char*)leaf;
+ break;
+
+ case LF_SHORT:
+ length += 2;
+ *value = *(const short*)leaf;
+ break;
+
+ case LF_USHORT:
+ length += 2;
+ *value = *(const unsigned short*)leaf;
+ break;
+
+ case LF_LONG:
+ case LF_ULONG:
+ length += 4;
+ *value = *(const int*)leaf;
+ break;
+
+ case LF_COMPLEX64:
+ case LF_QUADWORD:
+ case LF_UQUADWORD:
+ case LF_REAL64:
+ length += 8;
+ break;
+
+ case LF_COMPLEX32:
+ case LF_REAL32:
+ length += 4;
+ break;
+
+ case LF_REAL48:
+ length += 6;
+ break;
+
+ case LF_COMPLEX80:
+ case LF_REAL80:
+ length += 10;
+ break;
+
+ case LF_COMPLEX128:
+ case LF_REAL128:
+ length += 16;
+ break;
+
+ case LF_VARSTRING:
+ length += 2 + *(const unsigned short*)leaf;
+ break;
+
+ default:
+ if (type < LF_NUMERIC)
+ *value = type;
+ else
+ {
+ setError("unsupported numeric leaf");
+ length = 0;
+ }
+ break;
+ }
+ return length;
+}
+
+int CV2PDB::copy_leaf(unsigned char* dp, int& dpos, const unsigned char* p, int& pos)
+{
+ int value;
+ int leaf_len = numeric_leaf(&value, p + pos);
+ memcpy(dp + dpos, p + pos, leaf_len);
+ pos += leaf_len;
+ dpos += leaf_len;
+ return leaf_len;
+}
+
+static int copy_p2dsym(unsigned char* dp, int& dpos, const unsigned char* p, int& pos, int maxdlen)
+{
+ int len = dsym2c(p + pos + 1, p[pos], (char*) dp + dpos, maxdlen - dpos) + 1;
+ dpos += len;
+ pos += p[pos] + 1;
+ return len;
+}
+
+int CV2PDB::addFields(codeview_reftype* dfieldlist, const codeview_reftype* fieldlist, int maxdlen)
+{
+ int len = fieldlist->fieldlist.len - 2;
+ const unsigned char* p = fieldlist->fieldlist.list;
+ unsigned char* dp = dfieldlist->fieldlist.list;
+ int pos = 0, dpos = 0;
+ int leaf_len, value;
+
+ int prev = pos;
+ while (pos < len && !hadError())
+ {
+ if (p[pos] >= 0xf1) /* LF_PAD... */
+ {
+ pos += p[pos] & 0x0f;
+ continue;
+ }
+ if(pos & 3)
+ {
+ setError("bad field alignment!");
+ break;
+ }
+
+ prev = pos;
+ const codeview_fieldtype* fieldtype = (const codeview_fieldtype*)(p + pos);
+ codeview_fieldtype* dfieldtype = (codeview_fieldtype*)(dp + dpos);
+ int copylen = 0;
+
+ switch (fieldtype->generic.id)
+ {
+ case LF_ENUMERATE_V1:
+ if (v3)
+ {
+ dfieldtype->enumerate_v3.id = LF_ENUMERATE_V3;
+ dfieldtype->enumerate_v3.attribute = fieldtype->enumerate_v1.attribute;
+ pos += sizeof(fieldtype->enumerate_v1) - sizeof(fieldtype->enumerate_v1.value);
+ dpos += sizeof(fieldtype->enumerate_v3) - sizeof(fieldtype->enumerate_v3.value);
+ copy_leaf(dp, dpos, p, pos);
+ copy_p2dsym(dp, dpos, p, pos, maxdlen);
+ }
+ else
+ {
+ leaf_len = numeric_leaf(&value, &fieldtype->enumerate_v1.value);
+ copylen = 2 + 2 + leaf_len + p[pos + 4 + leaf_len] + 1; // id,attr,value,name
+ }
+ break;
+
+ case LF_ENUMERATE_V3:
+ leaf_len = numeric_leaf(&value, &fieldtype->enumerate_v3.value);
+ copylen = 2 + 2 + leaf_len + strlen((const char*) p + pos + 4 + leaf_len) + 1; // id,attr,value,name
+ break;
+
+ case LF_MEMBER_V1:
+ dfieldtype->member_v2.id = v3 ? LF_MEMBER_V3 : LF_MEMBER_V2;
+ dfieldtype->member_v2.attribute = fieldtype->member_v1.attribute;
+ dfieldtype->member_v2.type = translateType(fieldtype->member_v1.type);
+ pos += sizeof(dfieldtype->member_v1.id) + sizeof(dfieldtype->member_v1.attribute) + sizeof(dfieldtype->member_v1.type);
+ dpos += sizeof(dfieldtype->member_v2.id) + sizeof(dfieldtype->member_v2.attribute) + sizeof(dfieldtype->member_v2.type);
+ if (v3)
+ {
+ copy_leaf(dp, dpos, p, pos);
+ copy_p2dsym(dp, dpos, p, pos, maxdlen);
+ }
+ else
+ {
+ leaf_len = numeric_leaf(&value, &fieldtype->member_v1.offset);
+ copylen = leaf_len + p[pos + leaf_len] + 1; // value,name
+ }
+ break;
+
+ case LF_MEMBER_V2:
+ leaf_len = numeric_leaf(&value, &fieldtype->member_v1.offset);
+ copylen = sizeof(dfieldtype->member_v2) - sizeof(dfieldtype->member_v2.offset);
+ copylen += leaf_len + p[pos + copylen + leaf_len] + 1; // value,name
+ break;
+
+ case LF_MEMBER_V3:
+ leaf_len = numeric_leaf(&value, &fieldtype->member_v3.offset);
+ copylen = sizeof(dfieldtype->member_v3) - sizeof(dfieldtype->member_v3.offset);
+ copylen += leaf_len + strlen((const char*) p + pos + copylen + leaf_len) + 1; // value,name
+ break;
+
+ case LF_BCLASS_V1:
+ dfieldtype->bclass_v2.id = LF_BCLASS_V2;
+ dfieldtype->bclass_v2.attribute = fieldtype->bclass_v1.attribute;
+ dfieldtype->bclass_v2.type = translateType(fieldtype->bclass_v1.type);
+ pos += sizeof(fieldtype->bclass_v1) - sizeof(fieldtype->bclass_v1.offset);
+#if 1
+ dpos += sizeof(dfieldtype->bclass_v2) - sizeof(fieldtype->bclass_v2.offset);
+ copylen = numeric_leaf(&value, &fieldtype->bclass_v1.offset);
+ memcpy (dp + dpos, p + pos, copylen);
+ pos += copylen;
+ dpos += copylen;
+ // dp[dpos++] = 0;
+ copylen = 0;
+#else
+ dfieldtype->member_v2.id = LF_MEMBER_V2;
+ dfieldtype->member_v2.attribute = 0;
+ dfieldtype->member_v2.type = fieldtype->bclass_v1.type;
+ dfieldtype->member_v2.offset = fieldtype->bclass_v1.offset;
+ //memcpy (&dfieldtype->member_v2 + 1, "\0", 1);
+ //dpos += sizeof(dfieldtype->member_v2) + 1;
+ memcpy (&dfieldtype->member_v2 + 1, "\004base", 5);
+ dpos += sizeof(dfieldtype->member_v2) + 5;
+
+ pos += numeric_leaf(&value, &fieldtype->bclass_v1.offset);
+#endif
+ break;
+
+ case LF_BCLASS_V2:
+ leaf_len = numeric_leaf(&value, &fieldtype->bclass_v2.offset);
+ copylen = sizeof(dfieldtype->bclass_v2) - 2 + leaf_len;
+ break;
+
+ case LF_METHOD_V1:
+ dfieldtype->method_v2.id = v3 ? LF_METHOD_V3 : LF_METHOD_V2;
+ dfieldtype->method_v2.count = fieldtype->method_v1.count;
+ dfieldtype->method_v2.mlist = fieldtype->method_v1.mlist;
+ pos += sizeof(dfieldtype->method_v1) - sizeof(dfieldtype->method_v1.p_name);
+ dpos += sizeof(dfieldtype->method_v2) - sizeof(dfieldtype->method_v2.p_name);
+ if (v3)
+ copy_p2dsym(dp, dpos, p, pos, maxdlen);
+ else
+ copylen = fieldtype->method_v1.p_name.namelen + 1;
+ break;
+
+ case LF_METHOD_V2:
+ copylen = sizeof(dfieldtype->method_v2) - sizeof(dfieldtype->method_v2.p_name);
+ copylen += fieldtype->method_v2.p_name.namelen + 1;
+ break;
+
+ case LF_METHOD_V3:
+ copylen = sizeof(dfieldtype->method_v3);
+ copylen += strlen((const char*) p + pos + copylen) + 1;
+ break;
+
+ case LF_STMEMBER_V1:
+ dfieldtype->stmember_v2.id = v3 ? LF_METHOD_V3 : LF_METHOD_V2;
+ dfieldtype->stmember_v2.attribute = fieldtype->stmember_v1.attribute;
+ dfieldtype->stmember_v2.type = translateType(fieldtype->stmember_v1.type);
+ pos += sizeof(dfieldtype->stmember_v1) - sizeof(dfieldtype->stmember_v1.p_name);
+ dpos += sizeof(dfieldtype->stmember_v2) - sizeof(dfieldtype->stmember_v2.p_name);
+ if (v3)
+ copy_p2dsym(dp, dpos, p, pos, maxdlen);
+ else
+ copylen = fieldtype->stmember_v1.p_name.namelen + 1;
+ break;
+
+ case LF_STMEMBER_V2:
+ copylen = sizeof(dfieldtype->stmember_v2) - sizeof(dfieldtype->stmember_v2.p_name);
+ copylen += fieldtype->stmember_v2.p_name.namelen + 1;
+ break;
+
+ case LF_STMEMBER_V3:
+ copylen = sizeof(dfieldtype->stmember_v3) - sizeof(dfieldtype->stmember_v3.name);
+ copylen += strlen(fieldtype->stmember_v3.name) + 1;
+ break;
+
+ case LF_NESTTYPE_V1:
+ dfieldtype->nesttype_v2.id = v3 ? LF_NESTTYPE_V3 : LF_NESTTYPE_V2;
+ dfieldtype->nesttype_v2.type = translateType(fieldtype->nesttype_v1.type);
+ dfieldtype->nesttype_v2._pad0 = 0;
+ pos += sizeof(dfieldtype->nesttype_v1) - sizeof(dfieldtype->nesttype_v1.p_name);
+ dpos += sizeof(dfieldtype->nesttype_v2) - sizeof(dfieldtype->nesttype_v2.p_name);
+ if (v3)
+ copy_p2dsym(dp, dpos, p, pos, maxdlen);
+ else
+ copylen = fieldtype->nesttype_v1.p_name.namelen + 1;
+ break;
+
+ case LF_NESTTYPE_V2:
+ copylen = sizeof(dfieldtype->nesttype_v2) - sizeof(dfieldtype->nesttype_v2.p_name);
+ copylen += fieldtype->nesttype_v2.p_name.namelen + 1;
+ break;
+
+ case LF_NESTTYPE_V3:
+ copylen = sizeof(dfieldtype->nesttype_v3) - sizeof(dfieldtype->nesttype_v3.name);
+ copylen += strlen(fieldtype->nesttype_v3.name) + 1;
+ break;
+
+ default:
+ setError("unsupported field entry");
+ break;
+ }
+
+ memcpy (dp + dpos, p + pos, copylen);
+ pos += copylen;
+ dpos += copylen;
+
+ for ( ; dpos & 3; dpos++)
+ dp[dpos] = 0xf4 - (dpos & 3);
+ }
+ return dpos;
+}
+
+int CV2PDB::addAggregate(codeview_type* dtype, bool clss, int n_element, int fieldlist, int property,
+ int derived, int vshape, int structlen, const char*name)
+{
+ dtype->struct_v2.id = clss ? (v3 ? LF_CLASS_V3 : LF_CLASS_V2) : (v3 ? LF_STRUCTURE_V3 : LF_STRUCTURE_V2);
+ dtype->struct_v2.n_element = n_element;
+ dtype->struct_v2.fieldlist = fieldlist;
+ dtype->struct_v2.property = property;
+ dtype->struct_v2.derived = derived;
+ dtype->struct_v2.vshape = vshape;
+ dtype->struct_v2.structlen = structlen;
+ int len = cstrcpy_v(v3, (BYTE*)(&dtype->struct_v2 + 1), name);
+ len += sizeof (dtype->struct_v2);
+
+ unsigned char* p = (unsigned char*) dtype;
+ for (; len & 3; len++)
+ p[len] = 0xf4 - (len & 3);
+ dtype->struct_v2.len = len - 2;
+ return len;
+}
+
+int CV2PDB::addClass(codeview_type* dtype, int n_element, int fieldlist, int property,
+ int derived, int vshape, int structlen, const char*name)
+{
+ return addAggregate(dtype, true, n_element, fieldlist, property, derived, vshape, structlen, name);
+}
+
+int CV2PDB::addStruct(codeview_type* dtype, int n_element, int fieldlist, int property,
+ int derived, int vshape, int structlen, const char*name)
+{
+ return addAggregate(dtype, false, n_element, fieldlist, property, derived, vshape, structlen, name);
+}
+
+int CV2PDB::addPointerType(codeview_type* dtype, int type, int attr)
+{
+ dtype->pointer_v2.id = LF_POINTER_V2;
+ dtype->pointer_v2.len = 10;
+ dtype->pointer_v2.datatype = translateType(type);
+ dtype->pointer_v2.attribute = attr;
+ return dtype->generic.len + 2; // no alignment data needed, because always 12 bytes
+}
+int CV2PDB::addPointerType(unsigned char* dtype, int type, int attr)
+{
+ return addPointerType((codeview_type*) dtype, type, attr);
+}
+
+int CV2PDB::addFieldMember(codeview_fieldtype* dfieldtype, int attr, int offset, int type, const char* name)
+{
+ dfieldtype->member_v2.id = v3 ? LF_MEMBER_V3 : LF_MEMBER_V2;
+ dfieldtype->member_v2.attribute = attr;
+ dfieldtype->member_v2.offset = offset;
+ dfieldtype->member_v2.type = translateType(type);
+ int len = cstrcpy_v(v3, (BYTE*)(&dfieldtype->member_v2 + 1), name);
+ len += sizeof (dfieldtype->member_v2);
+
+ unsigned char* p = (unsigned char*) dfieldtype;
+ for (; len & 3; len++)
+ p[len] = 0xf4 - (len & 3);
+ return len;
+}
+
+void CV2PDB::checkUserTypeAlloc(int size, int add)
+{
+ if (cbUserTypes + size >= allocUserTypes)
+ {
+ allocUserTypes += add;
+ userTypes = (BYTE*) realloc(userTypes, allocUserTypes);
+ }
+}
+
+const codeview_type* CV2PDB::getTypeData(int type)
+{
+ if (!globalTypeHeader)
+ return 0;
+ if (type < 0x1000 || type >= (int) (0x1000 + globalTypeHeader->cTypes + nextUserType))
+ return 0;
+ if (type >= (int) (0x1000 + globalTypeHeader->cTypes))
+ return getUserTypeData(type);
+
+ DWORD* offset = (DWORD*)(globalTypeHeader + 1);
+ BYTE* typeData = (BYTE*)(offset + globalTypeHeader->cTypes);
+
+ return (codeview_type*)(typeData + offset[type - 0x1000]);
+}
+
+const codeview_type* CV2PDB::getUserTypeData(int type)
+{
+ type -= 0x1000 + globalTypeHeader->cTypes;
+ if (type < 0 || type >= nextUserType - 0x1000)
+ return 0;
+
+ int pos = 0;
+ while(type > 0)
+ {
+ const codeview_type* ptype = (codeview_type*)(userTypes + pos);
+ int len = ptype->generic.len + 2;
+ pos += len;
+ type--;
+ }
+ return (codeview_type*)(userTypes + pos);
+}
+
+const codeview_type* CV2PDB::findCompleteClassType(const codeview_type* cvtype)
+{
+ if (!globalTypeHeader)
+ return 0;
+
+ int value;
+ int cvleaf_len = numeric_leaf(&value, &cvtype->struct_v1.structlen);
+
+ DWORD* offset = (DWORD*)(globalTypeHeader + 1);
+ BYTE* typeData = (BYTE*)(offset + globalTypeHeader->cTypes);
+ for (unsigned int t = 0; t < globalTypeHeader->cTypes; t++)
+ {
+ const codeview_type* type = (const codeview_type*)(typeData + offset[t]);
+ if (type->generic.id == LF_CLASS_V1 || type->generic.id == LF_STRUCTURE_V1)
+ {
+ if (!(type->struct_v1.property & kIncomplete))
+ {
+ int leaf_len = numeric_leaf(&value, &type->struct_v1.structlen);
+ if (pstrcmp((const BYTE*) &cvtype->struct_v1.structlen + cvleaf_len,
+ (const BYTE*) &type->struct_v1.structlen + leaf_len) == 0)
+ return type;
+ }
+ }
+ }
+ return cvtype;
+}
+
+int CV2PDB::findMemberFunctionType(codeview_symbol* lastGProcSym, int thisPtrType)
+{
+ const codeview_type* proctype = getTypeData(lastGProcSym->proc_v2.proctype);
+ if (!proctype || proctype->generic.id != LF_PROCEDURE_V1)
+ return lastGProcSym->proc_v2.proctype;
+
+ const codeview_type* thisPtrData = getTypeData(thisPtrType);
+ if (!thisPtrData || thisPtrData->generic.id != LF_POINTER_V1)
+ return lastGProcSym->proc_v2.proctype;
+
+ int thistype = thisPtrData->pointer_v1.datatype;
+
+ // search method with same arguments and return type
+ DWORD* offset = (DWORD*)(globalTypeHeader + 1);
+ BYTE* typeData = (BYTE*)(offset + globalTypeHeader->cTypes);
+ for (unsigned int t = 0; t < globalTypeHeader->cTypes; t++)
+ {
+ // remember: mfunction_v1.class_type falsely is pointer, not class type
+ const codeview_type* type = (const codeview_type*)(typeData + offset[t]);
+ if (type->generic.id == LF_MFUNCTION_V1 && type->mfunction_v1.this_type == thisPtrType)
+ {
+ if (type->mfunction_v1.arglist == proctype->procedure_v1.arglist &&
+ type->mfunction_v1.call == proctype->procedure_v1.call &&
+ type->mfunction_v1.rvtype == proctype->procedure_v1.rvtype)
+ {
+ return t + 0x1000;
+ }
+ }
+ }
+ return lastGProcSym->proc_v2.proctype;
+}
+
+int CV2PDB::sizeofClassType(const codeview_type* cvtype)
+{
+ if (cvtype->struct_v1.property & kIncomplete)
+ cvtype = findCompleteClassType(cvtype);
+
+ int value;
+ int leaf_len = numeric_leaf(&value, &cvtype->struct_v1.structlen);
+ return value;
+}
+
+int CV2PDB::sizeofBasicType(int type)
+{
+ int size = type & 7;
+ int typ = (type & 0xf0) >> 4;
+ int mode = (type & 0x700) >> 8;
+
+ switch (mode)
+ {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5: // pointer variations
+ return 4;
+ case 6: // 64-bit pointer
+ return 8;
+ case 7: // reserved
+ return 4;
+ case 0: // not pointer
+ switch (typ)
+ {
+ case 0: // special, cannot determine
+ return 4;
+ case 1:
+ case 2: // integral types
+ switch (size)
+ {
+ case 0: return 1;
+ case 1: return 2;
+ case 2: return 4;
+ case 3: return 8;
+ // other reserved
+ }
+ return 4;
+ case 3: // boolean
+ return 1;
+ case 4:
+ case 5: // real and complex
+ switch (size)
+ {
+ case 0: return 4;
+ case 1: return 8;
+ case 2: return 10;
+ case 3: return 16;
+ case 4: return 6;
+ // other reserved
+ }
+ return 4;
+ case 6: // special2 (bit or pascal char)
+ return 1;
+ case 7: // real int
+ switch (size)
+ {
+ case 0: return 1; // char
+ case 1: return 4; // wide char
+ case 2: return 2;
+ case 3: return 2;
+ case 4: return 4;
+ case 5: return 4;
+ case 6: return 8;
+ case 7: return 8;
+ }
+ }
+ }
+ return 4;
+}
+
+int CV2PDB::sizeofType(int type)
+{
+ if (type < 0x1000)
+ return sizeofBasicType(type);
+
+ const codeview_type* cvtype = getTypeData(type);
+ if (!cvtype)
+ return 4;
+
+ if (cvtype->generic.id == LF_CLASS_V1 || cvtype->generic.id == LF_STRUCTURE_V1)
+ return sizeofClassType(cvtype);
+
+ if (cvtype->generic.id == LF_OEM_V1 || cvtype->generic.id == LF_OEM_V2)
+ if (((codeview_oem_type*) (&cvtype->generic + 1))->generic.oemid == 0x42)
+ return 8; // all D oem types
+
+ // everything else must be pointer or function pointer
+ return 4;
+}
+
+// to be used when writing new type only to avoid double translation
+int CV2PDB::translateType(int type)
+{
+ if (type < 0x1000)
+ return type;
+ const codeview_type* cvtype = getTypeData(type);
+ if (!cvtype)
+ return type;
+
+ if (cvtype->generic.id != LF_OEM_V1)
+ return type;
+
+ codeview_oem_type* oem = (codeview_oem_type*) (&cvtype->generic + 1);
+ if (oem->generic.oemid == 0x42 && oem->generic.id == 3)
+ {
+ if (oem->d_delegate.this_type == 0x403 && oem->d_delegate.func_type == 0x74)
+ return 0x76; // long
+ }
+
+ return type;
+}
+
+bool CV2PDB::nameOfBasicType(int type, char* name, int maxlen)
+{
+ int size = type & 7;
+ int typ = (type & 0xf0) >> 4;
+ int mode = (type & 0x700) >> 8;
+
+ switch (typ)
+ {
+ case 0: // special, cannot determine
+ if (size == 3)
+ strcpy(name, "void");
+ else
+ return setError("nameOfBasicType: unsupported basic special type");
+ break;
+ case 1: // signed integral types
+ switch (size)
+ {
+ case 0: strcpy(name, "byte"); break; // cannot distinguish char und byte
+ case 1: strcpy(name, "short"); break;
+ case 2: strcpy(name, "int"); break;
+ case 3: strcpy(name, "long"); break;
+ default:
+ return setError("nameOfBasicType: unsupported basic signed integral type");
+ // other reserved
+ }
+ break;
+ case 2: // unsigned integral types
+ switch (size)
+ {
+ case 0: strcpy(name, "ubyte"); break;
+ case 1: strcpy(name, "ushort"); break;
+ case 2: strcpy(name, "uint"); break;
+ case 3: strcpy(name, "ulong"); break;
+ default:
+ return setError("nameOfBasicType: unsupported basic unsigned integral type");
+ }
+ break;
+ case 3: // boolean
+ strcpy(name, "bool");
+ break;
+ case 4:
+ switch (size)
+ {
+ case 0: strcpy(name, "ifloat"); break;
+ case 1: strcpy(name, "idouble"); break;
+ case 2: strcpy(name, "ireal"); break;
+ default:
+ return setError("nameOfBasicType: unsupported basic complex type");
+ }
+ break;
+ case 5: // real and complex
+ switch (size)
+ {
+ case 0: strcpy(name, "float"); break;
+ case 1: strcpy(name, "double"); break;
+ case 2: strcpy(name, "real"); break;
+ default:
+ return setError("nameOfBasicType: unsupported basic real type");
+ }
+ break;
+ case 6: // special2 (bit or pascal char)
+ return setError("nameOfBasicType: unsupported basic special2 type");
+ return 1;
+ case 7: // real int
+ switch (size)
+ {
+ case 0: strcpy(name, "char"); break;
+ case 1: strcpy(name, "wchar"); break; //??
+ case 2: strcpy(name, "short"); break;
+ case 3: strcpy(name, "ushort"); break;
+ case 4: strcpy(name, "int"); break;
+ case 5: strcpy(name, "uint"); break;
+ case 6: strcpy(name, "long"); break;
+ case 7: strcpy(name, "ulong"); break;
+ }
+ }
+ if (mode != 0 && mode != 7)
+ strcat(name, "*");
+ return true;
+}
+
+bool CV2PDB::nameOfModifierType(int type, int mod, char* name, int maxlen)
+{
+ *name = 0;
+ if(mod & 1)
+ strcat(name, "const ");
+ if(mod & 2)
+ strcat(name, "volatile ");
+ if(mod & 4)
+ strcat(name, "unaligned ");
+ int len = strlen(name);
+ if(!nameOfType(type, name + len, maxlen - len))
+ return false;
+ return true;
+}
+
+bool CV2PDB::nameOfType(int type, char* name, int maxlen)
+{
+ if(type < 0x1000)
+ return nameOfBasicType(type, name, maxlen);
+
+ const codeview_type* ptype = getTypeData(type);
+ if(!ptype)
+ return setError("nameOfType: invalid type while retreiving name of type");
+
+ int leaf_len, value, len;
+ switch(ptype->generic.id)
+ {
+ case LF_CLASS_V1:
+ case LF_STRUCTURE_V1:
+ leaf_len = numeric_leaf(&value, &ptype->struct_v1.structlen);
+ p2ccpy(name, (const BYTE*) &ptype->struct_v1.structlen + leaf_len);
+ break;
+ case LF_CLASS_V2:
+ case LF_STRUCTURE_V2:
+ leaf_len = numeric_leaf(&value, &ptype->struct_v2.structlen);
+ p2ccpy(name, (const BYTE*) &ptype->struct_v2.structlen + leaf_len);
+ break;
+ case LF_CLASS_V3:
+ case LF_STRUCTURE_V3:
+ leaf_len = numeric_leaf(&value, &ptype->struct_v3.structlen);
+ strcpy(name, (const char*) &ptype->struct_v3.structlen + leaf_len);
+ break;
+
+ case LF_UNION_V1:
+ leaf_len = numeric_leaf(&value, &ptype->union_v1.un_len);
+ p2ccpy(name, (const BYTE*) &ptype->union_v1.un_len + leaf_len);
+ break;
+ case LF_UNION_V2:
+ leaf_len = numeric_leaf(&value, &ptype->union_v2.un_len);
+ p2ccpy(name, (const BYTE*) &ptype->union_v2.un_len + leaf_len);
+ break;
+ case LF_UNION_V3:
+ leaf_len = numeric_leaf(&value, &ptype->union_v3.un_len);
+ strcpy(name, (const char*) &ptype->union_v3.un_len + leaf_len);
+ break;
+
+ case LF_POINTER_V1:
+ if(!nameOfType(ptype->pointer_v1.datatype, name, maxlen))
+ return false;
+ strcat(name,"*");
+ break;
+ case LF_POINTER_V2:
+ if(!nameOfType(ptype->pointer_v2.datatype, name, maxlen))
+ return false;
+ strcat(name,"*");
+ break;
+
+ case LF_ARRAY_V1:
+ if(!nameOfType(ptype->array_v1.elemtype, name, maxlen))
+ return false;
+ leaf_len = numeric_leaf(&value, &ptype->array_v1.arrlen);
+ len = strlen(name);
+ sprintf(name + len, "[%d]", leaf_len);
+ break;
+ case LF_ARRAY_V2:
+ if(!nameOfType(ptype->array_v2.elemtype, name, maxlen))
+ return false;
+ leaf_len = numeric_leaf(&value, &ptype->array_v2.arrlen);
+ len = strlen(name);
+ sprintf(name + len, "[%d]", leaf_len);
+ break;
+ case LF_ARRAY_V3:
+ if(!nameOfType(ptype->array_v3.elemtype, name, maxlen))
+ return false;
+ leaf_len = numeric_leaf(&value, &ptype->array_v3.arrlen);
+ len = strlen(name);
+ sprintf(name + len, "[%d]", leaf_len);
+ break;
+
+ case LF_ENUM_V1:
+ strcpy(name, "enum ");
+ p2ccpy(name + 5, (const BYTE*) &ptype->enumeration_v1.p_name);
+ break;
+ case LF_ENUM_V2:
+ strcpy(name, "enum ");
+ p2ccpy(name + 5, (const BYTE*) &ptype->enumeration_v2.p_name);
+ break;
+ case LF_ENUM_V3:
+ strcpy(name, "enum ");
+ strcpy(name + 5, ptype->enumeration_v3.name);
+ break;
+
+ case LF_MODIFIER_V1:
+ if (!nameOfModifierType(ptype->modifier_v1.type, ptype->modifier_v1.attribute, name, maxlen))
+ return false;
+ break;
+ case LF_MODIFIER_V2:
+ if (!nameOfModifierType(ptype->modifier_v2.type, ptype->modifier_v2.attribute, name, maxlen))
+ return false;
+ break;
+
+ case LF_PROCEDURE_V1:
+ if(!nameOfType(ptype->procedure_v1.rvtype, name, maxlen))
+ return false;
+ strcat(name, "()");
+ break;
+ case LF_PROCEDURE_V2:
+ if(!nameOfType(ptype->procedure_v2.rvtype, name, maxlen))
+ return false;
+ strcat(name, "()");
+ break;
+
+ case LF_MFUNCTION_V1:
+ if(!nameOfType(ptype->mfunction_v1.rvtype, name, maxlen))
+ return false;
+ strcat(name, "()");
+ break;
+ case LF_MFUNCTION_V2:
+ if(!nameOfType(ptype->mfunction_v2.rvtype, name, maxlen))
+ return false;
+ strcat(name, "()");
+ break;
+
+ case LF_OEM_V1:
+ if (!nameOfOEMType((codeview_oem_type*) (&ptype->generic + 1), name, maxlen))
+ return false;
+ break;
+ default:
+ return setError("nameOfType: unsupported type");
+ }
+ return true;
+}
+
+bool CV2PDB::nameOfDynamicArray(int indexType, int elemType, char* name, int maxlen)
+{
+ if (!nameOfType(elemType, name, maxlen))
+ return false;
+ if (Dversion >= 2 && strcmp(name, "const char") == 0)
+ strcpy(name, "string");
+ else if (Dversion < 2 && strcmp(name, "char") == 0)
+ strcpy(name, "string");
+ else
+ strcat (name, "[]");
+ // sprintf(name, "dyn_array<%X,%X>", indexType, elemType);
+ return true;
+}
+
+bool CV2PDB::nameOfAssocArray(int indexType, int elemType, char* name, int maxlen)
+{
+ strcpy(name, "aa<");
+ int len = strlen(name);
+ if (!nameOfType(elemType, name + len, maxlen - len))
+ return false;
+ strcat(name, "[");
+ len = strlen(name);
+ if (!nameOfType(indexType, name + len, maxlen - len))
+ return false;
+ strcat(name,"]>");
+
+ // sprintf(name, "assoc_array<%X,%X>", indexType, elemType);
+ return true;
+}
+
+bool CV2PDB::nameOfDelegate(int thisType, int funcType, char* name, int maxlen)
+{
+ strcat(name, "delegate ");
+ int len = strlen(name);
+ if (!nameOfType(funcType, name + len, maxlen - len))
+ return false;
+ // sprintf(name, "delegate<%X,%X>", indexType, elemType);
+ return true;
+}
+
+bool CV2PDB::nameOfOEMType(codeview_oem_type* oem, char* name, int maxlen)
+{
+ if (oem->generic.oemid == 0x42 && oem->generic.id == 1)
+ return nameOfDynamicArray(oem->d_dyn_array.index_type, oem->d_dyn_array.elem_type, name, maxlen);
+ if (oem->generic.oemid == 0x42 && oem->generic.id == 2)
+ return nameOfAssocArray(oem->d_assoc_array.key_type, oem->d_assoc_array.elem_type, name, maxlen);
+ if (oem->generic.oemid == 0x42 && oem->generic.id == 3)
+ return nameOfDelegate(oem->d_delegate.this_type, oem->d_delegate.func_type, name, maxlen);
+
+ return setError("nameOfOEMType: unknown OEM type record");
+}
+
+const char* CV2PDB::appendDynamicArray(int indexType, int elemType)
+{
+ codeview_reftype* rdtype;
+ codeview_type* dtype;
+
+ checkUserTypeAlloc();
+
+ // nextUserType: pointer to elemType
+ cbUserTypes += addPointerType(userTypes + cbUserTypes, elemType);
+
+ // nextUserType + 1: field list (size, array)
+ rdtype = (codeview_reftype*) (userTypes + cbUserTypes);
+ rdtype->fieldlist.id = LF_FIELDLIST_V2;
+
+ // member indexType length
+ codeview_fieldtype* dfieldtype = (codeview_fieldtype*)rdtype->fieldlist.list;
+ int len1 = addFieldMember(dfieldtype, 1, 0, indexType, "length");
+
+ // member elemType* data[]
+ dfieldtype = (codeview_fieldtype*)(rdtype->fieldlist.list + len1);
+ int len2 = addFieldMember(dfieldtype, 1, 4, nextUserType, "data");
+
+ rdtype->fieldlist.len = len1 + len2 + 2;
+ cbUserTypes += rdtype->fieldlist.len + 2;
+
+ static char name[256];
+ nameOfDynamicArray(indexType, elemType, name, sizeof(name));
+
+ // nextUserType + 2: struct
+ dtype = (codeview_type*) (userTypes + cbUserTypes);
+ cbUserTypes += addClass(dtype, 2, nextUserType + 1, 0, 0, 0, 8, name);
+
+ nextUserType += 3;
+ addUdtSymbol(nextUserType - 1, name);
+ return name;
+}
+
+const char* CV2PDB::appendAssocArray(int keyType, int elemType)
+{
+ // rebuilding types
+ // struct aaA {
+ // aaA *left;
+ // aaA *right;
+ // hash_t hash;
+ // keyType key;
+ // elemType value;
+ // };
+
+ codeview_reftype* rdtype;
+ codeview_type* dtype;
+ codeview_fieldtype* dfieldtype;
+
+ checkUserTypeAlloc();
+
+ static char name[256];
+#if 1
+ char keyname[256];
+ char elemname[256];
+ if(!nameOfType(keyType, keyname, sizeof(keyname)))
+ return false;
+ if(!nameOfType(elemType, elemname, sizeof(elemname)))
+ return false;
+
+ sprintf(name, "internal@aaA<%s,%s>", keyname, elemname);
+
+ // undefined struct aaA
+ dtype = (codeview_type*) (userTypes + cbUserTypes);
+ cbUserTypes += addClass(dtype, 0, 0, kIncomplete, 0, 0, 0, name);
+ int aaAType = nextUserType++;
+
+ // pointer to aaA
+ cbUserTypes += addPointerType(userTypes + cbUserTypes, aaAType);
+ int aaAPtrType = nextUserType++;
+
+ // field list (left, right, hash, key, value)
+ rdtype = (codeview_reftype*) (userTypes + cbUserTypes);
+ rdtype->fieldlist.id = LF_FIELDLIST_V2;
+
+ // member aaA* left
+ dfieldtype = (codeview_fieldtype*)rdtype->fieldlist.list;
+ int len1 = addFieldMember(dfieldtype, 1, 0, aaAPtrType, "left");
+
+ dfieldtype = (codeview_fieldtype*)(rdtype->fieldlist.list + len1);
+ int len2 = addFieldMember(dfieldtype, 1, 4, aaAPtrType, "right");
+
+ dfieldtype = (codeview_fieldtype*)(rdtype->fieldlist.list + len1 + len2);
+ int len3 = addFieldMember(dfieldtype, 1, 8, 0x74, "hash");
+
+ dfieldtype = (codeview_fieldtype*)(rdtype->fieldlist.list + len1 + len2 + len3);
+ int len4 = addFieldMember(dfieldtype, 1, 12, keyType, "key");
+
+ int typeLen = sizeofType(keyType);
+ typeLen = (typeLen + 3) & ~3; // align to 4 byte
+ dfieldtype = (codeview_fieldtype*)(rdtype->fieldlist.list + len1 + len2 + len3 + len4);
+ int len5 = addFieldMember(dfieldtype, 1, 12 + typeLen, elemType, "value");
+
+ int elemLen = sizeofType(elemType);
+ elemLen = (elemLen + 3) & ~3; // align to 4 byte
+
+ rdtype->fieldlist.len = len1 + len2 + len3 + len4 + len5 + 2;
+ cbUserTypes += rdtype->fieldlist.len + 2;
+ int fieldListType = nextUserType++;
+
+ dtype = (codeview_type*) (userTypes + cbUserTypes);
+ cbUserTypes += addClass(dtype, 5, fieldListType, 0, 0, 0, 12 + typeLen + elemLen, name);
+ addUdtSymbol(nextUserType, name);
+ int completeAAAType = nextUserType++;
+
+ // struct BB {
+ // aaA*[] b;
+ // size_t nodes; // total number of aaA nodes
+ // };
+ const char* dynArray = appendDynamicArray(0x74, aaAPtrType);
+ int dynArrType = nextUserType - 1;
+
+ // field list (aaA*[] b, size_t nodes)
+ rdtype = (codeview_reftype*) (userTypes + cbUserTypes);
+ rdtype->fieldlist.id = LF_FIELDLIST_V2;
+
+ // member aaA*[] b
+ dfieldtype = (codeview_fieldtype*)rdtype->fieldlist.list;
+ len1 = addFieldMember(dfieldtype, 1, 0, dynArrType, "b");
+
+ dfieldtype = (codeview_fieldtype*)(rdtype->fieldlist.list + len1);
+ len2 = addFieldMember(dfieldtype, 1, 8, 0x74, "nodes");
+
+ rdtype->fieldlist.len = len1 + len2 + 2;
+ cbUserTypes += rdtype->fieldlist.len + 2;
+ int bbFieldListType = nextUserType++;
+
+ sprintf(name, "internal@BB<%s,%s>", keyname, elemname);
+
+ // struct BB
+ dtype = (codeview_type*) (userTypes + cbUserTypes);
+ cbUserTypes += addClass(dtype, 2, bbFieldListType, 0, 0, 0, 12, name);
+ addUdtSymbol(nextUserType, name);
+ int bbType = nextUserType++;
+
+ // struct AA {
+ // BB* a;
+ // };
+ // pointer to BB
+ cbUserTypes += addPointerType(userTypes + cbUserTypes, bbType);
+ int bbPtrType = nextUserType++;
+#else
+ int len1, bbPtrType = elemType;
+#endif
+
+ // field list (BB* aa)
+ rdtype = (codeview_reftype*) (userTypes + cbUserTypes);
+ rdtype->fieldlist.id = LF_FIELDLIST_V2;
+
+ // member aaA*[] b
+ dfieldtype = (codeview_fieldtype*)rdtype->fieldlist.list;
+ len1 = addFieldMember(dfieldtype, 1, 0, bbPtrType, "a");
+
+ rdtype->fieldlist.len = len1 + 2;
+ cbUserTypes += rdtype->fieldlist.len + 2;
+ int aaFieldListType = nextUserType++;
+
+ nameOfAssocArray(keyType, elemType, name, sizeof(name));
+ dtype = (codeview_type*) (userTypes + cbUserTypes);
+ cbUserTypes += addClass(dtype, 1, aaFieldListType, 0, 0, 0, 4, name);
+
+ addUdtSymbol(nextUserType, name);
+ nextUserType++;
+
+ return name;
+}
+
+const char* CV2PDB::appendDelegate(int thisType, int funcType)
+{
+ codeview_reftype* rdtype;
+ codeview_type* dtype;
+
+ checkUserTypeAlloc();
+
+ // nextUserType + 1: pointer to funcType
+ cbUserTypes += addPointerType(userTypes + cbUserTypes, funcType);
+
+ bool thisTypeIsVoid = (thisType == 0x403);
+ if (!thisTypeIsVoid)
+ {
+ // nextUserType: pointer to thisType
+ dtype = (codeview_type*) (userTypes + cbUserTypes);
+ cbUserTypes += addPointerType(dtype, thisType);
+ }
+
+ // nextUserType + 2: field list (size, array)
+ rdtype = (codeview_reftype*) (userTypes + cbUserTypes);
+ rdtype->fieldlist.id = LF_FIELDLIST_V2;
+
+ // member thisType* thisptr
+ codeview_fieldtype* dfieldtype = (codeview_fieldtype*)rdtype->fieldlist.list;
+ int len1 = addFieldMember(dfieldtype, 1, 0, thisTypeIsVoid ? thisType : nextUserType + 1, "thisptr");
+
+ // member funcType* funcptr
+ dfieldtype = (codeview_fieldtype*)(rdtype->fieldlist.list + len1);
+ int len2 = addFieldMember(dfieldtype, 1, 4, nextUserType, "funcptr");
+
+ rdtype->fieldlist.len = len1 + len2 + 2;
+ cbUserTypes += rdtype->fieldlist.len + 2;
+
+ static char name[256];
+ nameOfDelegate(thisType, funcType, name, sizeof(name));
+
+ // nextUserType + 3: struct delegate<>
+ dtype = (codeview_type*) (userTypes + cbUserTypes);
+ cbUserTypes += addClass(dtype, 2, nextUserType + (thisTypeIsVoid ? 1 : 2), 0, 0, 0, 8, name);
+
+ nextUserType += thisTypeIsVoid ? 3 : 4;
+ addUdtSymbol(nextUserType - 1, name);
+ return name;
+}
+
+int CV2PDB::appendObjectType (int object_derived_type)
+{
+ checkUserTypeAlloc();
+
+ // append object type info
+ int typeNo = nextUserType;
+ codeview_reftype* rdtype = (codeview_reftype*) (userTypes + cbUserTypes);
+
+ // vtable
+ rdtype->generic.len = 6;
+ rdtype->generic.id = LF_VTSHAPE_V1;
+ ((unsigned short*) (&rdtype->generic + 1))[0] = 1;
+ ((unsigned short*) (&rdtype->generic + 1))[1] = 0xf150;
+ cbUserTypes += rdtype->generic.len + 2;
+
+ // vtable*
+ codeview_type* dtype = (codeview_type*) (userTypes + cbUserTypes);
+ dtype->pointer_v2.id = LF_POINTER_V2;
+ dtype->pointer_v2.len = 10;
+ dtype->pointer_v2.datatype = typeNo;
+ dtype->pointer_v2.attribute = 0x800A;
+ cbUserTypes += dtype->generic.len + 2;
+
+ // field list
+ rdtype = (codeview_reftype*) (userTypes + cbUserTypes);
+ rdtype->fieldlist.id = LF_FIELDLIST_V2;
+ codeview_fieldtype* dfieldtype = (codeview_fieldtype*)rdtype->fieldlist.list;
+ dfieldtype->vfunctab_v2.id = LF_VFUNCTAB_V2; // id correct?
+ dfieldtype->vfunctab_v2._pad0 = 0;
+ dfieldtype->vfunctab_v2.type = typeNo + 1; // vtable*
+ rdtype->fieldlist.len = sizeof(dfieldtype->vfunctab_v2) + 2;
+ cbUserTypes += rdtype->generic.len + 2;
+
+#define OBJECT_SYMBOL "object@Object"
+
+ dtype = (codeview_type*) (userTypes + cbUserTypes);
+ dtype->struct_v2.id = v3 ? LF_CLASS_V3 : LF_CLASS_V2;
+ dtype->struct_v2.n_element = 1;
+ dtype->struct_v2.fieldlist = typeNo + 2;
+ dtype->struct_v2.property = 0;
+ dtype->struct_v2.derived = object_derived_type;
+ dtype->struct_v2.vshape = typeNo;
+ dtype->struct_v2.structlen = 4;
+ int len = cstrcpy_v (v3, (BYTE*) (&dtype->struct_v2 + 1), OBJECT_SYMBOL);
+ len += sizeof (dtype->struct_v2);
+ for (; len & 3; len++)
+ userTypes[cbUserTypes + len] = 0xf4 - (len & 3);
+ dtype->struct_v2.len = len - 2;
+ cbUserTypes += dtype->generic.len + 2;
+
+ objectType = typeNo + 3;
+ nextUserType += 4;
+
+ addUdtSymbol(objectType, OBJECT_SYMBOL);
+ return objectType;
+}
+
+int CV2PDB::appendPointerType(int pointedType, int attr)
+{
+ checkUserTypeAlloc();
+
+ cbUserTypes += addPointerType(userTypes + cbUserTypes, pointedType, attr);
+ nextUserType++;
+
+ return nextUserType - 1;
+}
+
+bool CV2PDB::initGlobalTypes()
+{
+ int object_derived_type = 0;
+ for (int m = 0; m < countEntries; m++)
+ {
+ OMFDirEntry* entry = img.getCVEntry(m);
+ if(entry->SubSection == sstGlobalTypes)
+ {
+ globalTypeHeader = img.CVP<OMFGlobalTypes>(entry->lfo);
+ DWORD* offset = img.CVP<DWORD>(entry->lfo + sizeof(OMFGlobalTypes));
+ BYTE* typeData = img.CVP<BYTE>(entry->lfo + sizeof(OMFGlobalTypes) + 4*globalTypeHeader->cTypes);
+
+ if (globalTypes)
+ return setError("only one global type entry expected");
+
+ pointerTypes = new int[globalTypeHeader->cTypes];
+ memset(pointerTypes, 0, globalTypeHeader->cTypes * sizeof(*pointerTypes));
+
+ globalTypes = (unsigned char*) malloc(entry->cb + 4);
+ allocGlobalTypes = entry->cb + 4;
+ if (!globalTypes)
+ return setError("Out of memory");
+ *(DWORD*) globalTypes = 4;
+ cbGlobalTypes = 4;
+
+ nextUserType = globalTypeHeader->cTypes + 0x1000;
+
+ for (unsigned int t = 0; t < globalTypeHeader->cTypes && !hadError(); t++)
+ {
+ const codeview_type* type = (codeview_type*)(typeData + offset[t]);
+ const codeview_reftype* rtype = (codeview_reftype*)(typeData + offset[t]);
+ int leaf_len, value;
+
+ int len = type->generic.len + 2;
+ if (cbGlobalTypes + len + 1000 > allocGlobalTypes)
+ {
+ allocGlobalTypes += len + 1000;
+ globalTypes = (unsigned char*) realloc(globalTypes, allocGlobalTypes);
+ }
+
+ unsigned int clsstype;
+ codeview_type* dtype = (codeview_type*) (globalTypes + cbGlobalTypes);
+ codeview_reftype* rdtype = (codeview_reftype*) (globalTypes + cbGlobalTypes);
+
+ // for debugging, cancel special processing after the limit
+ unsigned int typeLimit = 0x7fffffff;
+ if (t > typeLimit)
+ {
+ dtype->pointer_v2.id = LF_POINTER_V2;
+ dtype->pointer_v2.len = 10;
+ dtype->pointer_v2.datatype = 0x74;
+ dtype->pointer_v2.attribute = 0x800a;
+ cbGlobalTypes += 12;
+ continue;
+ }
+
+ switch (type->generic.id)
+ {
+ case LF_OEM_V1:
+ {
+ codeview_oem_type* oem = (codeview_oem_type*) (&type->generic + 1);
+
+ if (oem->generic.oemid == 0x42 && oem->generic.id == 1)
+ {
+ const char* name = appendDynamicArray(oem->d_dyn_array.index_type, oem->d_dyn_array.elem_type);
+ len = addClass(dtype, 0, 0, kIncomplete, 0, 0, 0, name);
+ }
+ else if (oem->generic.oemid == 0x42 && oem->generic.id == 3)
+ {
+ const char* name = appendDelegate(oem->d_delegate.this_type, oem->d_delegate.func_type);
+ len = addClass(dtype, 0, 0, kIncomplete, 0, 0, 0, name);
+ }
+ else if (oem->generic.oemid == 0x42 && oem->generic.id == 2)
+ {
+ const char* name = appendAssocArray(oem->d_assoc_array.key_type, oem->d_assoc_array.elem_type);
+ len = addClass(dtype, 0, 0, kIncomplete, 0, 0, 0, name);
+ }
+ else
+ {
+ dtype->pointer_v2.id = LF_POINTER_V2;
+ dtype->pointer_v2.len = 10;
+ dtype->pointer_v2.datatype = oem->d_dyn_array.elem_type;
+ dtype->pointer_v2.attribute = 0x800a;
+ len = 12;
+ }
+ break;
+ }
+ case LF_ARGLIST_V1:
+ rdtype->arglist_v2.id = LF_ARGLIST_V2;
+ rdtype->arglist_v2.num = rtype->arglist_v1.num;
+ for (int i = 0; i < rtype->arglist_v1.num; i++)
+ rdtype->arglist_v2.args [i] = translateType(rtype->arglist_v1.args [i]);
+ len = sizeof(rdtype->arglist_v2) + 4 * rdtype->arglist_v2.num - sizeof(rdtype->arglist_v2.args);
+ break;
+
+ case LF_PROCEDURE_V1:
+ dtype->procedure_v2.id = LF_PROCEDURE_V2;
+ dtype->procedure_v2.rvtype = translateType(type->procedure_v1.rvtype);
+ dtype->procedure_v2.call = type->procedure_v1.call;
+ dtype->procedure_v2.reserved = type->procedure_v1.reserved;
+ dtype->procedure_v2.params = type->procedure_v1.params;
+ dtype->procedure_v2.arglist = type->procedure_v1.arglist;
+ len = sizeof(dtype->procedure_v2);
+ break;
+
+ case LF_STRUCTURE_V1:
+ dtype->struct_v2.id = v3 ? LF_STRUCTURE_V3 : LF_STRUCTURE_V2;
+ goto LF_CLASS_V1_struct;
+ case LF_CLASS_V1:
+ //dtype->struct_v2.id = v3 ? LF_STRUCTURE_V3 : LF_STRUCTURE_V2;
+ dtype->struct_v2.id = v3 ? LF_CLASS_V3 : LF_CLASS_V2;
+ LF_CLASS_V1_struct:
+ dtype->struct_v2.n_element = type->struct_v1.n_element;
+ dtype->struct_v2.fieldlist = type->struct_v1.fieldlist;
+ dtype->struct_v2.property = type->struct_v1.property | 0x200;
+ dtype->struct_v2.derived = type->struct_v1.derived;
+ dtype->struct_v2.vshape = type->struct_v1.vshape;
+ leaf_len = numeric_leaf(&value, &type->struct_v1.structlen);
+ memcpy (&dtype->struct_v2.structlen, &type->struct_v1.structlen, leaf_len);
+ len = pstrcpy_v(v3, (BYTE*) &dtype->struct_v2.structlen + leaf_len,
+ (const BYTE*) &type->struct_v1.structlen + leaf_len);
+ // alternate name can be added here?
+#if 0
+ if (dtype->struct_v2.id == LF_CLASS_V2)
+ len += pstrcpy((BYTE*) &dtype->struct_v2.structlen + leaf_len + len,
+ (const BYTE*) &type->struct_v1.structlen + leaf_len);
+#endif
+ len += leaf_len + sizeof(dtype->struct_v2) - sizeof(type->struct_v2.structlen);
+
+ // remember type index of derived list for object.Object
+ if (type->struct_v1.derived)
+ if (memcmp((char*) &type->struct_v1.structlen + leaf_len, "\x0dobject.Object", 14) == 0)
+ object_derived_type = type->struct_v1.derived;
+ break;
+
+ case LF_UNION_V1:
+ dtype->union_v2.id = v3 ? LF_UNION_V3 : LF_UNION_V2;
+ dtype->union_v2.count = type->union_v1.count;
+ dtype->union_v2.fieldlist = type->struct_v1.fieldlist;
+ dtype->union_v2.property = type->struct_v1.property;
+ leaf_len = numeric_leaf(&value, &type->union_v1.un_len);
+ memcpy (&dtype->union_v2.un_len, &type->union_v1.un_len, leaf_len);
+ len = pstrcpy_v(v3, (BYTE*) &dtype->union_v2.un_len + leaf_len,
+ (const BYTE*) &type->union_v1.un_len + leaf_len);
+ len += leaf_len + sizeof(dtype->union_v2) - sizeof(type->union_v2.un_len);
+ break;
+
+ case LF_POINTER_V1:
+ dtype->pointer_v2.id = LF_POINTER_V2;
+ dtype->pointer_v2.datatype = translateType(type->pointer_v1.datatype);
+ if (type->pointer_v1.datatype >= 0x1000 && (type->pointer_v1.attribute & 0xE0) == 0)
+ {
+ if (thisIsNotRef) // const pointer for this
+ pointerTypes[t] = appendPointerType(type->pointer_v1.datatype,
+ type->pointer_v1.attribute | 0x400);
+ dtype->pointer_v2.attribute = type->pointer_v1.attribute | 0x20; // convert to reference
+ }
+ else
+ dtype->pointer_v2.attribute = type->pointer_v1.attribute;
+ len = 12; // ignore p_name field in type->pointer_v1/2
+ break;
+
+ case LF_ARRAY_V1:
+ dtype->array_v2.id = v3 ? LF_ARRAY_V3 : LF_ARRAY_V2;
+ dtype->array_v2.elemtype = translateType(type->array_v1.elemtype);
+ dtype->array_v2.idxtype = translateType(type->array_v1.idxtype);
+ leaf_len = numeric_leaf(&value, &type->array_v1.arrlen);
+ memcpy (&dtype->array_v2.arrlen, &type->array_v1.arrlen, leaf_len);
+ len = pstrcpy_v(v3, (BYTE*) &dtype->array_v2.arrlen + leaf_len,
+ (const BYTE*) &type->array_v1.arrlen + leaf_len);
+ len += leaf_len + sizeof(dtype->array_v2) - sizeof(dtype->array_v2.arrlen);
+ // followed by name
+ break;
+
+ case LF_MFUNCTION_V1:
+ dtype->mfunction_v2.id = LF_MFUNCTION_V2;
+ dtype->mfunction_v2.rvtype = translateType(type->mfunction_v1.rvtype);
+ clsstype = type->mfunction_v1.class_type;
+ dtype->mfunction_v2.class_type = translateType(clsstype);
+ if (clsstype >= 0x1000 && clsstype < 0x1000 + globalTypeHeader->cTypes)
+ {
+ // fix class_type to point to class, not pointer to class
+ codeview_type* ctype = (codeview_type*)(typeData + offset[clsstype - 0x1000]);
+ if (ctype->generic.id == LF_POINTER_V1)
+ dtype->mfunction_v2.class_type = translateType(ctype->pointer_v1.datatype);
+ }
+ dtype->mfunction_v2.this_type = translateType(type->mfunction_v1.this_type);
+ dtype->mfunction_v2.call = type->mfunction_v1.call;
+ dtype->mfunction_v2.reserved = type->mfunction_v1.reserved;
+ dtype->mfunction_v2.params = type->mfunction_v1.params;
+ dtype->mfunction_v2.arglist = type->mfunction_v1.arglist;
+ dtype->mfunction_v2.this_adjust = type->mfunction_v1.this_adjust;
+ len = sizeof(dtype->mfunction_v2);
+ break;
+
+ case LF_ENUM_V1:
+ dtype->enumeration_v2.id = v3 ? LF_ENUM_V3 : LF_ENUM_V2;
+ dtype->enumeration_v2.count = type->enumeration_v1.count;
+ dtype->enumeration_v2.type = translateType(type->enumeration_v1.type);
+ dtype->enumeration_v2.fieldlist = type->enumeration_v1.fieldlist;
+ dtype->enumeration_v2.property = type->enumeration_v1.property;
+ len = pstrcpy_v (v3, (BYTE*) &dtype->enumeration_v2.p_name, (BYTE*) &type->enumeration_v1.p_name);
+ len += sizeof(dtype->enumeration_v2) - sizeof(dtype->enumeration_v2.p_name);
+ break;
+
+ case LF_FIELDLIST_V1:
+ case LF_FIELDLIST_V2:
+ rdtype->fieldlist.id = LF_FIELDLIST_V2;
+ len = addFields(rdtype, rtype, allocGlobalTypes - cbGlobalTypes) + 4;
+ break;
+
+ case LF_DERIVED_V1:
+ rdtype->derived_v2.id = LF_DERIVED_V2;
+ rdtype->derived_v2.num = rtype->derived_v1.num;
+ for (int i = 0; i < rtype->derived_v1.num; i++)
+ if (rtype->derived_v1.drvdcls[i] < 0x1000) // + globalTypeHeader->cTypes)
+ rdtype->derived_v2.drvdcls[i] = translateType(rtype->derived_v1.drvdcls[i] + 0xfff);
+ else
+ rdtype->derived_v2.drvdcls[i] = translateType(rtype->derived_v1.drvdcls[i]);
+ len = sizeof(rdtype->derived_v2) + 4 * rdtype->derived_v2.num - sizeof(rdtype->derived_v2.drvdcls);
+ break;
+
+ case LF_VTSHAPE_V1: // no alternate version known
+ len = ((short*)type)[2]; // number of nibbles following
+ len = 6 + (len + 1) / 2; // cut-off extra bytes
+ memcpy(dtype, type, len);
+ //*((char*)dtype + 6) = 0x50;
+ break;
+
+ case LF_METHODLIST_V1:
+ {
+ dtype->generic.id = LF_METHODLIST_V2;
+ const unsigned short* pattr = (const unsigned short*)((const char*)type + 4);
+ unsigned* dpattr = (unsigned*)((char*)dtype + 4);
+ while ((const char*)pattr + 4 <= (const char*)type + type->generic.len + 2)
+ {
+ // type translation?
+ switch ((*pattr >> 2) & 7)
+ {
+ case 4:
+ case 6:
+ *dpattr++ = *pattr++;
+ default:
+ *dpattr++ = *pattr++;
+ *dpattr++ = *pattr++;
+ break;
+ }
+ }
+ len = (char*) dpattr - (char*)dtype;
+ break;
+ }
+ case LF_MODIFIER_V1:
+ dtype->modifier_v2.id = LF_MODIFIER_V2;
+ dtype->modifier_v2.attribute = type->modifier_v1.attribute;
+ dtype->modifier_v2.type = translateType(type->modifier_v1.type);
+ len = sizeof(dtype->modifier_v2);
+ break;
+
+ default:
+ memcpy(dtype, type, len);
+ break;
+ }
+
+ for (; len & 3; len++)
+ globalTypes[cbGlobalTypes + len] = 0xf4 - (len & 3);
+ dtype->generic.len = len - 2;
+
+ cbGlobalTypes += len;
+ }
+
+#if 1
+ appendObjectType (object_derived_type);
+#endif
+#if 1
+ if (cbGlobalTypes + cbUserTypes > allocGlobalTypes)
+ {
+ allocGlobalTypes += cbUserTypes + 1000;
+ globalTypes = (unsigned char*) realloc(globalTypes, allocGlobalTypes);
+ }
+
+ memcpy (globalTypes + cbGlobalTypes, userTypes, cbUserTypes);
+ cbGlobalTypes += cbUserTypes;
+#endif
+ }
+ }
+ return !hadError();
+}
+
+bool CV2PDB::addTypes()
+{
+ if (!globalTypes)
+ return true;
+
+ for (int m = 0; m < countEntries; m++)
+ {
+ OMFDirEntry* entry = img.getCVEntry(m);
+ if(entry->SubSection == sstSrcModule)
+ {
+ mspdb::Mod* mod = modules[entry->iMod];
+ if (!mod)
+ return setError("sstSrcModule for non-existing module");
+
+ int cb = cbGlobalTypes;
+ int rc = mod->AddTypes(globalTypes, cb);
+ if (rc <= 0)
+ return setError("cannot add type info to module");
+ }
+ }
+ return true;
+}
+
+bool CV2PDB::addSrcLines()
+{
+ for (int m = 0; m < countEntries; m++)
+ {
+ OMFDirEntry* entry = img.getCVEntry(m);
+ if(entry->SubSection == sstSrcModule)
+ {
+ mspdb::Mod* mod = modules[entry->iMod];
+ if (!mod)
+ return setError("sstSrcModule for non-existing module");
+
+ OMFSourceModule* sourceModule = img.CVP<OMFSourceModule>(entry->lfo);
+ int* segStartEnd = img.CVP<int>(entry->lfo + 4 + 4 * sourceModule->cFile);
+ short* seg = img.CVP<short>(entry->lfo + 4 + 4 * sourceModule->cFile + 8 * sourceModule->cSeg);
+
+ for (int f = 0; f < sourceModule->cFile; f++)
+ {
+ int cvoff = entry->lfo + sourceModule->baseSrcFile[f];
+ OMFSourceFile* sourceFile = img.CVP<OMFSourceFile> (cvoff);
+ int* lnSegStartEnd = img.CVP<int>(cvoff + 4 + 4 * sourceFile->cSeg);
+ BYTE* pname = (BYTE*)(lnSegStartEnd + 2 * sourceFile->cSeg);
+ char* name = p2c (pname);
+
+ for (int s = 0; s < sourceFile->cSeg; s++)
+ {
+ int lnoff = entry->lfo + sourceFile->baseSrcLn[s];
+ OMFSourceLine* sourceLine = img.CVP<OMFSourceLine> (lnoff);
+ short* lineNo = img.CVP<short> (lnoff + 4 + 4 * sourceLine->cLnOff);
+
+ int segoff = lnSegStartEnd[2*s];
+ int seglength = lnSegStartEnd[2*s + 1] - segoff;
+
+ mspdb::LineInfoEntry* lineInfo = new mspdb::LineInfoEntry[sourceLine->cLnOff];
+ for (int ln = 0; ln < sourceLine->cLnOff; ln++)
+ {
+ lineInfo[ln].offset = sourceLine->offset[ln] - segoff;
+ lineInfo[ln].line = lineNo[ln] - lineNo[0];
+ }
+ int rc = mod->AddLines(name, sourceLine->Seg, segoff, seglength, segoff, lineNo[0],
+ (unsigned char*) lineInfo, sourceLine->cLnOff * sizeof(*lineInfo));
+ if (rc <= 0)
+ return setError("cannot add line number info to module");
+ }
+ }
+ }
+ }
+ return true;
+}
+
+bool CV2PDB::addPublics()
+{
+ for (int m = 0; m < countEntries; m++)
+ {
+ OMFDirEntry* entry = img.getCVEntry(m);
+ if(entry->SubSection == sstGlobalPub)
+ {
+ mspdb::Mod* mod = 0;
+ if (entry->iMod < countEntries)
+ mod = modules[entry->iMod];
+
+ OMFSymHash* header = img.CVP<OMFSymHash>(entry->lfo);
+ BYTE* symbols = img.CVP<BYTE>(entry->lfo + sizeof(OMFSymHash));
+ int length;
+ for (unsigned int i = 0; i < header->cbSymbol; i += length)
+ {
+ union codeview_symbol* sym = (union codeview_symbol*)(symbols + i);
+ length = sym->generic.len + 2;
+ if (!sym->generic.id || length < 4)
+ break;
+
+ int rc;
+ switch (sym->generic.id)
+ {
+ case S_GDATA_V1:
+ case S_LDATA_V1:
+ case S_PUB_V1:
+ char symname[2000];
+ dsym2c((BYTE*)sym->data_v1.p_name.name, sym->data_v1.p_name.namelen, symname, sizeof(symname));
+ int type = translateType(sym->data_v1.symtype);
+ if (mod)
+ rc = mod->AddPublic2(symname, sym->data_v1.segment, sym->data_v1.offset, type);
+ else
+ rc = dbi->AddPublic2(symname, sym->data_v1.segment, sym->data_v1.offset, type);
+ if (rc <= 0)
+ return setError("cannot add public");
+ break;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+bool CV2PDB::initGlobalSymbols()
+{
+ for (int m = 0; m < countEntries; m++)
+ {
+ OMFDirEntry* entry = img.getCVEntry(m);
+ if (entry->SubSection == sstGlobalSym)
+ {
+ BYTE* symbols = img.CVP<BYTE>(entry->lfo);
+ OMFSymHash* header = (OMFSymHash*) symbols;
+ globalSymbols = symbols + sizeof(OMFSymHash);
+ cbGlobalSymbols = header->cbSymbol;
+ }
+ if (entry->SubSection == sstStaticSym)
+ {
+ BYTE* symbols = img.CVP<BYTE>(entry->lfo);
+ OMFSymHash* header = (OMFSymHash*) symbols;
+ staticSymbols = symbols + sizeof(OMFSymHash);
+ cbStaticSymbols = header->cbSymbol;
+ }
+ }
+ return true;
+}
+
+// returns new destSize
+int CV2PDB::copySymbols(BYTE* srcSymbols, int srcSize, BYTE* destSymbols, int destSize)
+{
+ codeview_symbol* lastGProcSym = 0;
+ int type, length, destlength;
+ for (int i = 0; i < srcSize; i += length)
+ {
+ codeview_symbol* sym = (codeview_symbol*)(srcSymbols + i);
+ length = sym->generic.len + 2;
+ if (!sym->generic.id || length < 4)
+ break;
+
+ codeview_symbol* dsym = (codeview_symbol*)(destSymbols + destSize);
+ memcpy(dsym, sym, length);
+ destlength = length;
+
+ switch (sym->generic.id)
+ {
+ case S_UDT_V1:
+ dsym->udt_v1.type = translateType(sym->udt_v1.type);
+ //sym->udt_v1.type = 0x101e;
+ break;
+
+ case S_LDATA_V1:
+ dsym->data_v2.id = v3 ? S_LDATA_V3 : S_LDATA_V2;
+ goto case_DATA_V1;
+ case S_GDATA_V1:
+ dsym->data_v2.id = v3 ? S_GDATA_V3 : S_GDATA_V2;
+ case_DATA_V1:
+ dsym->data_v2.symtype = translateType(sym->data_v1.symtype);
+ dsym->data_v2.offset = sym->data_v1.offset;
+ dsym->data_v2.offset = sym->data_v1.offset;
+ dsym->data_v2.segment = sym->data_v1.segment;
+ destlength = pstrcpy_v (v3, (BYTE*) &dsym->data_v2.p_name, (BYTE*) &sym->data_v1.p_name);
+ destlength += (BYTE*) &dsym->data_v2.p_name - (BYTE*) dsym;
+ dsym->data_v2.len = destlength - 2;
+ break;
+
+ case S_LPROC_V1:
+ dsym->proc_v2.id = v3 ? S_LPROC_V3 : S_LPROC_V2;
+ goto case_PROC_V1;
+ case S_GPROC_V1:
+ dsym->proc_v2.id = v3 ? S_GPROC_V3 : S_GPROC_V2;
+ case_PROC_V1:
+ dsym->proc_v2.pparent = sym->proc_v1.pparent;
+ dsym->proc_v2.pend = sym->proc_v1.pend;
+ dsym->proc_v2.next = sym->proc_v1.next;
+ dsym->proc_v2.proc_len = sym->proc_v1.proc_len;
+ dsym->proc_v2.debug_start = sym->proc_v1.debug_start;
+ dsym->proc_v2.debug_end = sym->proc_v1.debug_end;
+ dsym->proc_v2.offset = sym->proc_v1.offset;
+ dsym->proc_v2.segment = sym->proc_v1.segment;
+ dsym->proc_v2.proctype = translateType(sym->proc_v1.proctype);
+ dsym->proc_v2.flags = sym->proc_v1.flags;
+
+ destlength = pstrcpy_v (v3, (BYTE*) &dsym->proc_v2.p_name, (BYTE*) &sym->proc_v1.p_name);
+ destlength += (BYTE*) &dsym->proc_v2.p_name - (BYTE*) dsym;
+ dsym->data_v2.len = destlength - 2;
+
+ lastGProcSym = dsym;
+ break;
+
+ case S_BPREL_V1:
+ type = dsym->stack_v1.symtype;
+ if (p2ccmp(dsym->stack_v1.p_name, "this"))
+ {
+ if (lastGProcSym)
+ lastGProcSym->proc_v2.proctype = findMemberFunctionType(lastGProcSym, type);
+ if (thisIsNotRef && pointerTypes)
+ {
+#if 0
+ // insert function info before this
+ memset (&dsym->funcinfo_32, 0, sizeof (dsym->funcinfo_32));
+ dsym->funcinfo_32.id = S_FUNCINFO_32;
+ dsym->funcinfo_32.len = sizeof (dsym->funcinfo_32) - 2;
+ dsym->funcinfo_32.sizeLocals = 4;
+ dsym->funcinfo_32.info = 0x220;
+ destSize += sizeof (dsym->funcinfo_32);
+ codeview_symbol* dsym = (codeview_symbol*)(destSymbols + destSize);
+ memcpy(dsym, sym, length);
+#endif
+#if 0
+ // create another "this" symbol that is a pointer to the object, not a reference
+ destSize += length;
+ codeview_symbol* dsym = (codeview_symbol*)(destSymbols + destSize);
+ memcpy(dsym, sym, length);
+#endif
+ if (type >= 0x1000 && pointerTypes[type - 0x1000])
+ type = pointerTypes[type - 0x1000];
+ }
+ }
+ dsym->stack_v1.symtype = translateType(type);
+ //sym->stack_v1.symtype = 0x1012;
+ break;
+ case S_ENDARG_V1:
+ case S_RETURN_V1:
+ case S_SSEARCH_V1:
+ break;
+ case S_END_V1:
+ lastGProcSym = 0;
+ break;
+ case S_COMPILAND_V1:
+ if (((dsym->compiland_v1.unknown >> 8) & 0xFF) == 0) // C?
+ dsym->compiland_v1.unknown = (dsym->compiland_v1.unknown & ~0xFF00 | 0x100); // C++
+ break;
+ case S_PROCREF_V1:
+ case S_DATAREF_V1:
+ case S_LPROCREF_V1:
+ // dmd does not add a string, but it's not obvious to detect whether it exists or not
+ if (dsym->procref_v1.len != sizeof(dsym->procref_v1) - 4)
+ break;
+
+ dsym->procref_v1.p_name.namelen = 0;
+ memset (dsym->procref_v1.p_name.name, 0, 3); // also 4-byte alignment assumed
+ destSize += 4;
+ break;
+
+ case S_ALIGN_V1:
+ continue; // throw away
+ break;
+ default:
+ sym = sym;
+ break;
+ }
+
+ destSize += destlength;
+ }
+ return destSize;
+}
+
+bool CV2PDB::addUdtSymbol(int type, const char* name)
+{
+ if (cbUdtSymbols + 100 > allocUdtSymbols)
+ {
+ allocUdtSymbols += 1000;
+ udtSymbols = (BYTE*) realloc(udtSymbols, allocUdtSymbols);
+ }
+
+ codeview_symbol* sym = (codeview_symbol*) (udtSymbols + cbUdtSymbols);
+ sym->udt_v1.id = S_UDT_V1;
+ sym->udt_v1.type = translateType(type);
+ strcpy (sym->udt_v1.p_name.name, name);
+ sym->udt_v1.p_name.namelen = strlen(sym->udt_v1.p_name.name);
+ sym->udt_v1.len = sizeof(sym->udt_v1) + sym->udt_v1.p_name.namelen - 1 - 2;
+ cbUdtSymbols += sym->udt_v1.len + 2;
+
+ return true;
+}
+
+bool CV2PDB::addSymbols(int iMod, BYTE* symbols, int cb)
+{
+ mspdb::Mod* mod = 0;
+ if (iMod < countEntries)
+ mod = modules[iMod];
+ for (int i = 0; !mod && i < countEntries; i++)
+ mod = modules[i]; // add global symbols to first module
+ if (!mod)
+ {
+ if (!globmod)
+ {
+ int rc = dbi->OpenMod("<Globals>", "<Globals>", &globmod);
+ if (rc <= 0 || !globmod)
+ return setError("cannot create global module");
+ }
+ mod = globmod;
+ }
+ if (!mod)
+ return setError("no module to set symbols");
+
+ int prefix = mod == globmod ? 3 : 4;
+ int words = (cb + cbGlobalSymbols + cbStaticSymbols + cbUdtSymbols + 3) / 4 + prefix;
+ DWORD* data = new DWORD[2 * words];
+
+ int databytes = copySymbols(symbols, cb, (BYTE*) (data + prefix), 0);
+ if (staticSymbols)
+ databytes = copySymbols(staticSymbols, cbStaticSymbols, (BYTE*) (data + prefix), databytes);
+ if (globalSymbols)
+ databytes = copySymbols(globalSymbols, cbGlobalSymbols, (BYTE*) (data + prefix), databytes);
+ if (udtSymbols)
+ databytes = copySymbols(udtSymbols, cbUdtSymbols, (BYTE*) (data + prefix), databytes);
+
+ data[0] = 4;
+ data[1] = 0xf1;
+ data[2] = databytes + 4 * (prefix - 3);
+ if (prefix > 3)
+ data[3] = 1;
+ int rc = mod->AddSymbols((BYTE*) data, ((databytes + 3) / 4 + prefix) * 4);
+ if (rc <= 0)
+ return setError("cannot add symbols to module");
+ delete [] data;
+ return true;
+}
+
+bool CV2PDB::addSymbols()
+{
+ if (!initGlobalSymbols())
+ return false;
+
+ for (int m = 0; m < countEntries; m++)
+ {
+ OMFDirEntry* entry = img.getCVEntry(m);
+ mspdb::Mod* mod = 0;
+ BYTE* symbols = img.CVP<BYTE>(entry->lfo);
+
+ switch(entry->SubSection)
+ {
+ case sstAlignSym:
+ if (!addSymbols (entry->iMod, symbols + 4, entry->cb - 4))
+ return false;
+ break;
+
+ case sstStaticSym:
+ case sstGlobalSym:
+ break; // handled in initGlobalSymbols
+ }
+ }
+ return true;
+}
+
+bool CV2PDB::writeImage(const char* opath)
+{
+ int len = sizeof(*rsds) + strlen((char*)(rsds + 1)) + 1;
+ if (!img.replaceDebugSection(rsds, len))
+ return setError(img.getLastError());
+
+ if (!img.save(opath))
+ return setError(img.getLastError());
+
+ return true;
+}
diff --git a/src/cv2pdb.h b/src/cv2pdb.h
new file mode 100644
index 0000000..a900e6c
--- /dev/null
+++ b/src/cv2pdb.h
@@ -0,0 +1,148 @@
+// Convert DMD CodeView debug information to PDB files
+// Copyright (c) 2009 by Rainer Schuetze, All Rights Reserved
+//
+// License for redistribution is given by the Artistic License 2.0
+// see file LICENSE for further details
+
+#ifndef __CV2PDB_H__
+#define __CV2PDB_H__
+
+#include "LastError.h"
+#include "mspdb.h"
+
+#include <windows.h>
+
+extern "C" {
+#include "mscvpdb.h"
+}
+
+class PEImage;
+
+class CV2PDB : public LastError
+{
+public:
+ CV2PDB(PEImage& image);
+ ~CV2PDB();
+
+ bool cleanup(bool commit);
+ bool openPDB(const char* pdbname);
+
+ bool setError(const char* msg);
+ bool createModules();
+
+ bool initLibraries();
+ const BYTE* getLibrary(int i);
+ bool initSegMap();
+
+ int addFields(codeview_reftype* dfieldlist, const codeview_reftype* fieldlist, int maxdlen);
+
+ int addAggregate(codeview_type* dtype, bool clss, int n_element, int fieldlist, int property,
+ int derived, int vshape, int structlen, const char*name);
+ int addClass(codeview_type* dtype, int n_element, int fieldlist, int property,
+ int derived, int vshape, int structlen, const char*name);
+ int addStruct(codeview_type* dtype, int n_element, int fieldlist, int property,
+ int derived, int vshape, int structlen, const char*name);
+
+ int addPointerType(codeview_type* dtype, int type, int attr = 0x800A);
+ int addPointerType(unsigned char* dtype, int type, int attr = 0x800A);
+
+ int addFieldMember(codeview_fieldtype* dfieldtype, int attr, int offset, int type, const char* name);
+
+ void checkUserTypeAlloc(int size = 1000, int add = 10000);
+
+ const codeview_type* getTypeData(int type);
+ const codeview_type* getUserTypeData(int type);
+ const codeview_type* findCompleteClassType(const codeview_type* cvtype);
+
+ int findMemberFunctionType(codeview_symbol* lastGProcSym, int thisPtrType);
+
+ int sizeofClassType(const codeview_type* cvtype);
+ int sizeofBasicType(int type);
+ int sizeofType(int type);
+
+ // to be used when writing new type only to avoid double translation
+ int translateType(int type);
+
+ bool nameOfBasicType(int type, char* name, int maxlen);
+ bool nameOfType(int type, char* name, int maxlen);
+ bool nameOfDynamicArray(int indexType, int elemType, char* name, int maxlen);
+ bool nameOfAssocArray(int indexType, int elemType, char* name, int maxlen);
+ bool nameOfDelegate(int thisType, int funcType, char* name, int maxlen);
+ bool nameOfOEMType(codeview_oem_type* oem, char* name, int maxlen);
+ bool nameOfModifierType(int type, int mod, char* name, int maxlen);
+
+ int numeric_leaf(int* value, const void* leaf);
+ int copy_leaf(unsigned char* dp, int& dpos, const unsigned char* p, int& pos);
+
+ const char* appendDynamicArray(int indexType, int elemType);
+ const char* appendAssocArray(int keyType, int elemType);
+ const char* appendDelegate(int thisType, int funcType);
+ int appendObjectType (int object_derived_type);
+ int appendPointerType(int pointedType, int attr);
+
+ bool initGlobalTypes();
+ bool initGlobalSymbols();
+
+ bool addTypes();
+ bool addSrcLines();
+ bool addPublics();
+
+ // returns new destSize
+ int copySymbols(BYTE* srcSymbols, int srcSize, BYTE* destSymbols, int destSize);
+
+ bool addUdtSymbol(int type, const char* name);
+ bool addSymbols(int iMod, BYTE* symbols, int cb);
+ bool addSymbols();
+
+ bool writeImage(const char* opath);
+
+// private:
+ BYTE* libraries;
+
+ PEImage& img;
+
+ mspdb::PDB* pdb;
+ mspdb::DBI *dbi;
+ mspdb::TPI *tpi;
+
+ mspdb::Mod** modules;
+ mspdb::Mod* globmod;
+ int countEntries;
+
+ OMFSignatureRSDS* rsds;
+
+ OMFSegMap* segMap;
+ OMFSegMapDesc* segMapDesc;
+ OMFGlobalTypes* globalTypeHeader;
+
+ unsigned char* globalTypes;
+ int cbGlobalTypes;
+ int allocGlobalTypes;
+
+ unsigned char* userTypes;
+ int* pointerTypes;
+ int cbUserTypes;
+ int allocUserTypes;
+
+ unsigned char* globalSymbols;
+ int cbGlobalSymbols;
+
+ unsigned char* staticSymbols;
+ int cbStaticSymbols;
+
+ unsigned char* udtSymbols;
+ int cbUdtSymbols;
+ int allocUdtSymbols;
+
+ int nextUserType;
+ int objectType;
+
+ bool thisIsNotRef;
+ bool v3;
+ const char* lastError;
+
+ double Dversion;
+};
+
+
+#endif //__CV2PDB_H__ \ No newline at end of file
diff --git a/src/cv2pdb.sln b/src/cv2pdb.sln
new file mode 100644
index 0000000..451ef68
--- /dev/null
+++ b/src/cv2pdb.sln
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cv2pdb", "cv2pdb.vcproj", "{5E2BD27D-446A-4C99-9829-135F7C000D90}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {5E2BD27D-446A-4C99-9829-135F7C000D90}.Debug|Win32.ActiveCfg = Debug|Win32
+ {5E2BD27D-446A-4C99-9829-135F7C000D90}.Debug|Win32.Build.0 = Debug|Win32
+ {5E2BD27D-446A-4C99-9829-135F7C000D90}.Release|Win32.ActiveCfg = Release|Win32
+ {5E2BD27D-446A-4C99-9829-135F7C000D90}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/src/cv2pdb.vcproj b/src/cv2pdb.vcproj
new file mode 100644
index 0000000..71a7252
--- /dev/null
+++ b/src/cv2pdb.vcproj
@@ -0,0 +1,232 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9,00"
+ Name="cv2pdb"
+ ProjectGUID="{5E2BD27D-446A-4C99-9829-135F7C000D90}"
+ RootNamespace="cv2pdb"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="..\bin\$(ConfigurationName)"
+ IntermediateDirectory="..\bin\$(ConfigurationName)\$(ProjectName)"
+ ConfigurationType="1"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/wd4996"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ TreatWChar_tAsBuiltInType="false"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="dbghelp.lib"
+ OutputFile="$(OutDir)\$(ProjectName).exe"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="..\bin\$(ConfigurationName)"
+ IntermediateDirectory="..\bin\$(ConfigurationName)\$(ProjectName)"
+ ConfigurationType="1"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalOptions="/wd4996"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="true"
+ TreatWChar_tAsBuiltInType="false"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\cv2pdb.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\demangle.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\demangle.h"
+ >
+ </File>
+ <File
+ RelativePath=".\LastError.h"
+ >
+ </File>
+ <File
+ RelativePath=".\main.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\mscvpdb.h"
+ >
+ </File>
+ <File
+ RelativePath=".\mspdb.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\mspdb.h"
+ >
+ </File>
+ <File
+ RelativePath=".\PEImage.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\PEImage.h"
+ >
+ </File>
+ <File
+ RelativePath=".\symutil.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\symutil.h"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/src/demangle.cpp b/src/demangle.cpp
new file mode 100644
index 0000000..883680c
--- /dev/null
+++ b/src/demangle.cpp
@@ -0,0 +1,493 @@
+// adopted from demangle.d distributed with DMD
+
+/****
+ * Demangle D mangled names.
+ * Macros:
+ * WIKI = Phobos/StdDemangle
+ */
+
+/* Authors:
+ * Walter Bright, Digital Mars, www.digitalmars.com
+ * Thomas Kuehne
+ * Frits van Bommel
+ */
+
+#include <string>
+#include <ctype.h>
+#include <assert.h>
+
+using namespace std;
+
+typedef unsigned char ubyte;
+typedef long double real;
+
+#define length length()
+
+#define size_t_max 0x7FFFFFFFU
+
+class MangleException
+{
+public:
+ virtual ~MangleException() {}
+};
+
+class Demangle
+{
+public:
+ size_t ni;
+ string name;
+ string (Demangle::*fparseTemplateInstanceName)();
+
+ static void error()
+ {
+ //writefln("error()");
+ throw MangleException();
+ }
+
+ static ubyte ascii2hex(char c)
+ {
+ if (!isxdigit(c))
+ error();
+ return (ubyte)
+ ( (c >= 'a') ? c - 'a' + 10 :
+ (c >= 'A') ? c - 'A' + 10 : c - '0' );
+ }
+
+ size_t parseNumber()
+ {
+ //writefln("parseNumber() %d", ni);
+ size_t result = 0;
+
+ while (ni < name.length && isdigit(name[ni]))
+ {
+ int i = name[ni] - '0';
+ if (result > (size_t_max - i) / 10)
+ error();
+ result = result * 10 + i;
+ ni++;
+ }
+ return result;
+ }
+
+ string parseSymbolName()
+ {
+ //writefln("parseSymbolName() %d", ni);
+ size_t i = parseNumber();
+ if (ni + i > name.length)
+ error();
+ string result;
+ if (i >= 5 &&
+ name[ni] == '_' &&
+ name[ni + 1] == '_' &&
+ name[ni + 2] == 'T')
+ {
+ size_t nisave = ni;
+ bool err = false;
+ ni += 3;
+ try
+ {
+ result = parseTemplateInstanceName(); // (this->*fparseTemplateInstanceName)();
+ if (ni != nisave + i)
+ err = true;
+ }
+ catch (MangleException me)
+ {
+ err = true;
+ }
+ ni = nisave;
+ if (err)
+ goto L1;
+ goto L2;
+ }
+ L1:
+ result = name.substr(ni, i);
+ L2:
+ ni += i;
+ return result;
+ }
+
+ string parseQualifiedName()
+ {
+ //writefln("parseQualifiedName() %d", ni);
+ string result;
+
+ while (ni < name.length && isdigit(name[ni]))
+ {
+ if (result.length)
+ result += ".";
+ result += parseSymbolName();
+ }
+ return result;
+ }
+
+ string parseType(string identifier = string())
+ {
+ //writefln("parseType() %d", ni);
+ int isdelegate = 0;
+ bool hasthisptr = false; /// For function/delegate types: expects a 'this' pointer as last argument
+ Lagain:
+ if (ni >= name.length)
+ error();
+ string p;
+ switch (name[ni++])
+ {
+ case 'v': p = "void"; goto L1;
+ case 'b': p = "bool"; goto L1;
+ case 'g': p = "byte"; goto L1;
+ case 'h': p = "ubyte"; goto L1;
+ case 's': p = "short"; goto L1;
+ case 't': p = "ushort"; goto L1;
+ case 'i': p = "int"; goto L1;
+ case 'k': p = "uint"; goto L1;
+ case 'l': p = "long"; goto L1;
+ case 'm': p = "ulong"; goto L1;
+ case 'f': p = "float"; goto L1;
+ case 'd': p = "double"; goto L1;
+ case 'e': p = "real"; goto L1;
+ case 'o': p = "ifloat"; goto L1;
+ case 'p': p = "idouble"; goto L1;
+ case 'j': p = "ireal"; goto L1;
+ case 'q': p = "cfloat"; goto L1;
+ case 'r': p = "cdouble"; goto L1;
+ case 'c': p = "creal"; goto L1;
+ case 'a': p = "char"; goto L1;
+ case 'u': p = "wchar"; goto L1;
+ case 'w': p = "dchar"; goto L1;
+
+ case 'A': // dynamic array
+ p = parseType() + "[]";
+ goto L1;
+
+ case 'P': // pointer
+ p = parseType() + "*";
+ goto L1;
+
+ case 'G': // static array
+ { size_t ns = ni;
+ parseNumber();
+ size_t ne = ni;
+ p = parseType() + "[" + name.substr(ns, ne-ns) + "]";
+ goto L1;
+ }
+
+ case 'H': // associative array
+ p = parseType();
+ p = parseType() + "[" + p + "]";
+ goto L1;
+
+ case 'D': // delegate
+ isdelegate = 1;
+ goto Lagain;
+
+ case 'M':
+ hasthisptr = true;
+ goto Lagain;
+
+ case 'F': // D function
+ case 'U': // C function
+ case 'W': // Windows function
+ case 'V': // Pascal function
+ case 'R': // C++ function
+ { char mc = name[ni - 1];
+ string args;
+
+ while (1)
+ {
+ if (ni >= name.length)
+ error();
+ char c = name[ni];
+ if (c == 'Z')
+ break;
+ if (c == 'X')
+ {
+ if (!args.length) error();
+ args += " ...";
+ break;
+ }
+ if (args.length)
+ args += ", ";
+ switch (c)
+ {
+ case 'J':
+ args += "out ";
+ ni++;
+ goto Ldefault;
+
+ case 'K':
+ args += "inout ";
+ ni++;
+ goto Ldefault;
+
+ case 'L':
+ args += "lazy ";
+ ni++;
+ goto Ldefault;
+
+ default:
+ Ldefault:
+ args += parseType();
+ continue;
+
+ case 'Y':
+ args += "...";
+ break;
+ }
+ break;
+ }
+ ni++;
+ if (!isdelegate && identifier.length)
+ {
+ switch (mc)
+ {
+ case 'F': p = ""; break; // D function
+ case 'U': p = "extern (C) "; break; // C function
+ case 'W': p = "extern (Windows) "; break; // Windows function
+ case 'V': p = "extern (Pascal) "; break; // Pascal function
+ default: assert(0);
+ }
+ p += parseType() + " " + identifier + "(" + args + ")";
+ return p;
+ }
+ p = parseType() +
+ (isdelegate ? " delegate(" : " function(") + args + ")";
+ isdelegate = 0;
+ goto L1;
+ }
+
+ case 'C': p = "class "; goto L2;
+ case 'S': p = "struct "; goto L2;
+ case 'E': p = "enum "; goto L2;
+ case 'T': p = "typedef "; goto L2;
+
+ L2: p += parseQualifiedName();
+ goto L1;
+
+ L1:
+ if (isdelegate)
+ error(); // 'D' must be followed by function
+ if (identifier.length)
+ p += " " + identifier;
+ return p;
+
+ default:
+ size_t i = ni - 1;
+ ni = name.length;
+ p = name.substr(i, name.length-i);
+ goto L1;
+ }
+ }
+
+ void getReal(string &result)
+ {
+ real r;
+ ubyte rdata[10];
+ ubyte *p = rdata;
+
+ if (ni + 10 * 2 > name.length)
+ error();
+ for (size_t i = 0; i < 10; i++)
+ {
+ ubyte b;
+
+ b = (ubyte) ((ascii2hex(name[ni + i * 2]) << 4) + ascii2hex(name[ni + i * 2 + 1]));
+ p[i] = b;
+ }
+ // extract 10-byte double from rdata
+ __asm {
+ fld TBYTE PTR rdata;
+ fstp r;
+ }
+
+ char num[30];
+ sprintf(num, "%g", r);
+ result += num; // format(r);
+ ni += 10 * 2;
+ }
+
+ string parseTemplateInstanceName()
+ {
+ string result = parseSymbolName() + "!(";
+ int nargs = 0;
+
+ while (1)
+ {
+ size_t i;
+
+ if (ni >= name.length)
+ error();
+ if (nargs && name[ni] != 'Z')
+ result += ", ";
+ nargs++;
+ switch (name[ni++])
+ {
+ case 'T':
+ result += parseType();
+ continue;
+
+ case 'V':
+
+ result += parseType() + " ";
+ if (ni >= name.length)
+ error();
+ switch (name[ni++])
+ {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ i = ni - 1;
+ while (ni < name.length && isdigit(name[ni]))
+ ni++;
+ result += name.substr(i, ni - i);
+ break;
+
+ case 'N':
+ i = ni;
+ while (ni < name.length && isdigit(name[ni]))
+ ni++;
+ if (i == ni)
+ error();
+ result += "-" + name.substr(i, ni - i);
+ break;
+
+ case 'n':
+ result += "null";
+ break;
+
+ case 'e':
+ getReal(result);
+ break;
+
+ case 'c':
+ getReal(result);
+ result += '+';
+ getReal(result);
+ result += 'i';
+ break;
+
+ case 'a':
+ case 'w':
+ case 'd':
+ { char m = name[ni - 1];
+ if (m == 'a')
+ m = 'c';
+ size_t n = parseNumber();
+ if (ni >= name.length || name[ni++] != '_' ||
+ ni + n * 2 > name.length)
+ error();
+ result += '"';
+ for (i = 0; i < n; i++)
+ { char c;
+
+ c = (char)((ascii2hex(name[ni + i * 2]) << 4) +
+ ascii2hex(name[ni + i * 2 + 1]));
+ result += c;
+ }
+ ni += n * 2;
+ result += '"';
+ result += m;
+ break;
+ }
+
+ default:
+ error();
+ break;
+ }
+ continue;
+
+ case 'S':
+ result += parseSymbolName();
+ continue;
+
+ case 'Z':
+ break;
+
+ default:
+ error();
+ }
+ break;
+ }
+ result += ")";
+ return result;
+ }
+
+ string demangle(string _name, bool plainName = false)
+ {
+ ni = 2;
+ name = _name;
+
+ if (name.length < 3 ||
+ name[0] != '_' ||
+ name[1] != 'D' ||
+ !isdigit(name[2]))
+ {
+ goto Lnot;
+ }
+
+ // fparseTemplateInstanceName = &parseTemplateInstanceName;
+
+ try
+ {
+ string result = parseQualifiedName();
+ if (!plainName)
+ {
+ result = parseType(result);
+ while(ni < name.length){
+ result += " . " + parseType(parseQualifiedName());
+ }
+
+ if (ni != name.length)
+ goto Lnot;
+ }
+ return result;
+ }
+ catch (MangleException e)
+ {
+ }
+
+ Lnot:
+ // Not a recognized D mangled name; so return original
+ return name;
+ }
+
+};
+
+void unittest()
+{
+ // debug(demangle) printf("demangle.demangle.unittest\n");
+
+ static string table[][2] =
+ {
+ { "_D7dparser3dmd8Template21TemplateTypeParameter13overloadMatchMFC7dparser3dmd8Template17TemplateParameterZi", "int dparser.dmd.Template.TemplateTypeParameter.overloadMatch(class dparser.dmd.Template.TemplateParameter)"},
+ { "printf", "printf" },
+ { "_foo", "_foo" },
+ { "_D88", "_D88" }, // causes exception error, return symbol as is
+ { "_D4test3fooAa", "char[] test.foo"},
+ { "_D8demangle8demangleFAaZAa", "char[] demangle.demangle(char[])" },
+ { "_D6object6Object8opEqualsFC6ObjectZi", "int object.Object.opEquals(class Object)" },
+ { "_D4test2dgDFiYd", "double delegate(int, ...) test.dg" },
+ { "_D4test58__T9factorialVde67666666666666860140VG5aa5_68656c6c6fVPvnZ9factorialf", "float test.factorial!(double 4.2, char[5] \"hello\"c, void* null).factorial" },
+ { "_D4test101__T9factorialVde67666666666666860140Vrc9a999999999999d9014000000000000000c00040VG5aa5_68656c6c6fVPvnZ9factorialf", "float test.factorial!(double 4.2, cdouble 6.8+3i, char[5] \"hello\"c, void* null).factorial" },
+ { "_D4test34__T3barVG3uw3_616263VG3wd3_646566Z1xi", "int test.bar!(wchar[3] \"abc\"w, dchar[3] \"def\"d).x" },
+ { "_D8demangle4testFLC6ObjectLDFLiZiZi", "int demangle.test(lazy class Object, lazy int delegate(lazy int))"},
+ { "_D8demangle4testFAiXi", "int demangle.test(int[] ...)"},
+ { "_D8demangle4testFLAiXi", "int demangle.test(lazy int[] ...)"} ,
+ };
+
+ Demangle d;
+ for(int i = 0; i < sizeof(table)/sizeof(table[0]); i++)
+ {
+ string r = d.demangle(table[i][0]);
+ assert(r == table[i][1]);
+ // "table entry #" + toString(i) + ": '" + name[0] + "' demangles as '" + r + "' but is expected to be '" + name[1] + "'");
+
+ }
+}
+
+bool d_demangle(const char* name, char* demangled, int maxlen, bool plain)
+{
+ Demangle d;
+ string r = d.demangle(name, plain);
+ if (r.length == 0)
+ return false;
+ strncpy(demangled, r.c_str(), maxlen);
+ return true;
+}
diff --git a/src/demangle.h b/src/demangle.h
new file mode 100644
index 0000000..0a63c60
--- /dev/null
+++ b/src/demangle.h
@@ -0,0 +1,12 @@
+// Convert DMD CodeView debug information to PDB files
+// Copyright (c) 2009 by Rainer Schuetze, All Rights Reserved
+//
+// License for redistribution is given by the Artistic License 2.0
+// see file LICENSE for further details
+
+#ifndef __DEMANGLE_H__
+#define __DEMANGLE_H__
+
+bool d_demangle(const char* name, char* demangled, int maxlen, bool plain);
+
+#endif //__DEMANGLE_H__ \ No newline at end of file
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644
index 0000000..16dbb34
--- /dev/null
+++ b/src/main.cpp
@@ -0,0 +1,165 @@
+// Convert DMD CodeView debug information to PDB files
+// Copyright (c) 2009 by Rainer Schuetze, All Rights Reserved
+//
+// License for redistribution is given by the Artistic License 2.0
+// see file LICENSE for further details
+
+#include "PEImage.h"
+#include "cv2pdb.h"
+
+#include <direct.h>
+
+double
+#include "../VERSION"
+;
+
+void fatal(const char *message, ...)
+{
+ va_list argptr;
+ va_start(argptr, message);
+ vprintf(message, argptr);
+ va_end(argptr);
+ printf("\n");
+ exit(1);
+}
+
+void makefullpath(char* pdbname)
+{
+ char* pdbstart = pdbname;
+ char fullname[260];
+ char* pfullname = fullname;
+
+ int drive = 0;
+ if (pdbname[0] && pdbname[1] == ':')
+ {
+ if (pdbname[2] == '\\' || pdbname[2] == '/')
+ return;
+ drive = toupper (pdbname[0]);
+ pdbname += 2;
+ }
+ else
+ {
+ drive = _getdrive();
+ }
+
+ if (*pdbname != '\\' && *pdbname != '/')
+ {
+ _getdcwd(drive, pfullname, sizeof(fullname) - 2);
+ pfullname += strlen(pfullname);
+ if (pfullname[-1] != '\\')
+ *pfullname++ = '\\';
+ }
+ else
+ {
+ *pfullname++ = 'a' - 1 + drive;
+ *pfullname++ = ':';
+ }
+ strcpy(pfullname, pdbname);
+ strcpy(pdbstart, fullname);
+
+ for(char*p = pdbstart; *p; p++)
+ if (*p == '/')
+ *p = '\\';
+
+ // remove relative parts "./" and "../"
+ while (char* p = strstr (pdbstart, "\\.\\"))
+ strcpy(p, p + 2);
+
+ while (char* p = strstr (pdbstart, "\\..\\"))
+ {
+ for (char* q = p - 1; q >= pdbstart; q--)
+ if (*q == '\\')
+ {
+ strcpy(q, p + 3);
+ break;
+ }
+ }
+}
+
+int main(int argc, char** argv)
+{
+ if (argc < 2)
+ {
+ printf("Convert DMD CodeView debug information to PDB files, Version %g\n", VERSION);
+ printf("Copyright (c) 2009 by Rainer Schuetze, All Rights Reserved\n");
+ printf("\n");
+ printf("License for redistribution is given by the Artistic License 2.0\n");
+ printf("see file LICENSE for further details\n");
+ printf("\n");
+ printf("usage: %s [-Dversion] <exe-file> [new-exe-file] [pdb-file]\n", argv[0]);
+ return -1;
+ }
+
+ PEImage img;
+ double Dversion = 2;
+
+ while (argc > 1 && argv[1][0] == '-')
+ {
+ argv++;
+ argc--;
+ if (argv[0][1] == '-')
+ break;
+ if (argv[0][1] == 'D')
+ Dversion = strtod (argv[0] + 2, 0);
+ else
+ fatal("unknwon option: %s", argv[0]);
+ }
+
+ if (!img.load(argv[1]))
+ fatal("%s: %s", argv[1], img.getLastError());
+ if (img.countCVEntries() == 0)
+ fatal("%s: no codeview debug entries found", argv[1]);
+
+ CV2PDB cv2pdb(img);
+ cv2pdb.initLibraries();
+ cv2pdb.Dversion = Dversion;
+
+ char* outname = argv[1];
+ if (argc > 2 && argv[2][0])
+ outname = argv[2];
+
+ char pdbname[260];
+ if (argc > 3)
+ strcpy (pdbname, argv[3]);
+ else
+ {
+ strcpy (pdbname, outname);
+ char *pDot = strrchr (pdbname, '.');
+ if (!pDot || pDot <= strrchr (pdbname, '/') || pDot <= strrchr (pdbname, '\\'))
+ strcat (pdbname, ".pdb");
+ else
+ strcpy (pDot, ".pdb");
+ }
+ makefullpath(pdbname);
+
+ unlink(pdbname);
+
+ if(!cv2pdb.openPDB(pdbname))
+ fatal("%s: %s", pdbname, cv2pdb.getLastError());
+
+ if (!cv2pdb.initSegMap())
+ fatal("%s: %s", argv[1], cv2pdb.getLastError());
+
+ if (!cv2pdb.initGlobalTypes())
+ fatal("%s: %s", argv[1], cv2pdb.getLastError());
+
+ if (!cv2pdb.createModules())
+ fatal("%s: %s", pdbname, cv2pdb.getLastError());
+
+ if (!cv2pdb.addTypes())
+ fatal("%s: %s", pdbname, cv2pdb.getLastError());
+
+ if (!cv2pdb.addSymbols())
+ fatal("%s: %s", pdbname, cv2pdb.getLastError());
+
+ if (!cv2pdb.addSrcLines())
+ fatal("%s: %s", pdbname, cv2pdb.getLastError());
+
+ if (!cv2pdb.addPublics())
+ fatal("%s: %s", pdbname, cv2pdb.getLastError());
+
+ if (!cv2pdb.writeImage(outname))
+ fatal("%s: %s", outname, cv2pdb.getLastError());
+
+ return 0;
+}
diff --git a/src/mscvpdb.h b/src/mscvpdb.h
new file mode 100644
index 0000000..12b4177
--- /dev/null
+++ b/src/mscvpdb.h
@@ -0,0 +1,2083 @@
+/*
+ * MS debug information definitions.
+ *
+ * Copyright (C) 1996 Eric Youngdale
+ * Copyright (C) 1999-2000 Ulrich Weigand
+ * Copyright (C) 2004 Eric Pouech
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/* MS has stored all its debug information in a set of structures
+ * which has been rather consistent across the years (ie you can grasp
+ * some continuity, and not so many drastic changes).
+ *
+ * A bit of history on the various formats
+ * MSVC 1.0 PDB v1 (new format for debug info)
+ * MSVC 2.0 Inclusion in link of debug info (PDB v2)
+ * MSVC 5.0 Types are 24 bits (instead of 16 for <= 4.x)
+ * MSVC x.0 PDB (change in internal streams layout)
+ *
+ * .DBG Contains COFF, FPO and Codeview info
+ * .PDB New format for debug info (information is
+ * derived from Codeview information)
+ * VCx0.PDB x major MSVC number, stores types, while
+ * <project>.PDB stores symbols.
+ *
+ * Debug information can either be found in the debug section of a PE
+ * module (in something close to a .DBG file), or the debug section
+ * can actually refer to an external file, which can be in turn,
+ * either a .DBG or .PDB file.
+ *
+ * Regarding PDB files:
+ * -------------------
+ * They are implemented as a set of internal files (as a small file
+ * system). The file is split into blocks, an internal file is made
+ * of a set of blocks. Internal files are accessed through
+ * numbers. For example,
+ * 1/ is the ROOT (basic information on the file)
+ * 2/ is the Symbol information (global symbols, local variables...)
+ * 3/ is the Type internal file (each the symbols can have type
+ * information associated with it).
+ *
+ * Over the years, three formats existed for the PDB:
+ * - ?? was rather linked to 16 bit code (our support shall be rather
+ * bad)
+ * - JG: it's the signature embedded in the file header. This format
+ * has been used in MSVC 2.0 => 5.0.
+ * - DS: it's the signature embedded in the file header. It's the
+ * current format supported my MS.
+ *
+ * Types internal stream
+ * ---------------------
+ * Types (from the Type internal file) have existed in three flavors
+ * (note that those flavors came as historical evolution, but there
+ * isn't a one to one link between types evolution and PDB formats'
+ * evolutions:
+ * - the first flavor (suffixed by V1 in this file), where the types
+ * and subtypes are 16 bit entities; and where strings are in Pascal
+ * format (first char is their length and are not 0 terminated)
+ * - the second flavor (suffixed by V2) differs from first flavor with
+ * types and subtypes as 32 bit entities. This forced some
+ * reordering of fields in some types
+ * - the third flavor (suffixed by V3) differs from second flavor with
+ * strings stored as C strings (ie are 0 terminated, instead of
+ * length prefixed)
+ * The different flavors can coexist in the same file (is this really
+ * true ??)
+ *
+ * For the evolution of types, the need of the second flavor was the
+ * number of types to be defined (limited to 0xFFFF, including the C
+ * basic types); the need of the third flavor is the increase of
+ * symbol size (to be greater than 256), which was likely needed for
+ * complex C++ types (nested + templates).
+ *
+ * It's somehow difficult to represent the layout of those types on
+ * disk because:
+ * - some integral values are stored as numeric leaf, which size is
+ * variable depending on its value
+ *
+ * Symbols internal stream
+ * -----------------------
+ * Here also we find three flavors (that we've suffixed with _V1, _V2
+ * and _V3) even if their evolution is closer to the evolution of
+ * types, they are not completely linked together.
+ */
+
+/*
+ * some minor modifications have been done by Rainer Schuetze, mainly
+ * adding structs for the OEM types used by the DMD compiler
+ */
+
+#include "pshpack1.h"
+
+/* ======================================== *
+ * Type information
+ * ======================================== */
+
+struct p_string
+{
+ unsigned char namelen;
+ char name[1];
+};
+
+union codeview_type
+{
+ struct
+ {
+ unsigned short int len;
+ short int id;
+ } generic;
+
+ struct
+ {
+ unsigned short int len;
+ short int id;
+ short int attribute;
+ short int type;
+ } modifier_v1;
+
+ struct
+ {
+ unsigned short int len;
+ short int id;
+ int type;
+ short int attribute;
+ } modifier_v2;
+
+ struct
+ {
+ unsigned short int len;
+ short int id;
+ short int attribute;
+ short int datatype;
+ struct p_string p_name;
+ } pointer_v1;
+
+ struct
+ {
+ unsigned short int len;
+ short int id;
+ unsigned int datatype;
+ unsigned int attribute;
+ struct p_string p_name;
+ } pointer_v2;
+
+ struct
+ {
+ unsigned short int len;
+ short int id;
+ short int elemtype;
+ short int idxtype;
+ unsigned short int arrlen; /* numeric leaf */
+#if 0
+ struct p_string p_name;
+#endif
+ } array_v1;
+
+ struct
+ {
+ unsigned short int len;
+ short int id;
+ unsigned int elemtype;
+ unsigned int idxtype;
+ unsigned short int arrlen; /* numeric leaf */
+#if 0
+ struct p_string p_name;
+#endif
+ } array_v2;
+
+ struct
+ {
+ unsigned short int len;
+ short int id;
+ unsigned int elemtype;
+ unsigned int idxtype;
+ unsigned short int arrlen; /* numeric leaf */
+#if 0
+ char name[1];
+#endif
+ } array_v3;
+
+ struct
+ {
+ unsigned short int len;
+ short int id;
+ short int n_element;
+ short int fieldlist;
+ short int property;
+ short int derived;
+ short int vshape;
+ unsigned short int structlen; /* numeric leaf */
+#if 0
+ struct p_string p_name;
+#endif
+ } struct_v1;
+
+ struct
+ {
+ unsigned short int len;
+ short int id;
+ short int n_element;
+ short int property;
+ unsigned int fieldlist;
+ unsigned int derived;
+ unsigned int vshape;
+ unsigned short int structlen; /* numeric leaf */
+#if 0
+ struct p_string p_name;
+#endif
+ } struct_v2;
+
+ struct
+ {
+ unsigned short int len;
+ short int id;
+ short int n_element;
+ short int property;
+ unsigned int fieldlist;
+ unsigned int derived;
+ unsigned int vshape;
+ unsigned short int structlen; /* numeric leaf */
+#if 0
+ char name[1];
+#endif
+ } struct_v3;
+
+ struct
+ {
+ unsigned short int len;
+ short int id;
+ short int count;
+ short int fieldlist;
+ short int property;
+ unsigned short int un_len; /* numeric leaf */
+#if 0
+ struct p_string p_name;
+#endif
+ } union_v1;
+
+ struct
+ {
+ unsigned short int len;
+ short int id;
+ short int count;
+ short int property;
+ unsigned int fieldlist;
+ unsigned short int un_len; /* numeric leaf */
+#if 0
+ struct p_string p_name;
+#endif
+ } union_v2;
+
+ struct
+ {
+ unsigned short int len;
+ short int id;
+ short int count;
+ short int property;
+ unsigned int fieldlist;
+ unsigned short int un_len; /* numeric leaf */
+#if 0
+ char name[1];
+#endif
+ } union_v3;
+
+ struct
+ {
+ unsigned short int len;
+ short int id;
+ short int count;
+ short int type;
+ short int fieldlist;
+ short int property;
+ struct p_string p_name;
+ } enumeration_v1;
+
+ struct
+ {
+ unsigned short int len;
+ short int id;
+ short int count;
+ short int property;
+ unsigned int type;
+ unsigned int fieldlist;
+ struct p_string p_name;
+ } enumeration_v2;
+
+ struct
+ {
+ unsigned short int len;
+ short int id;
+ short int count;
+ short int property;
+ unsigned int type;
+ unsigned int fieldlist;
+ char name[1];
+ } enumeration_v3;
+
+ struct
+ {
+ unsigned short int len;
+ short int id;
+ unsigned short int rvtype;
+ unsigned char call;
+ unsigned char reserved;
+ unsigned short int params;
+ unsigned short int arglist;
+ } procedure_v1;
+
+ struct
+ {
+ unsigned short int len;
+ short int id;
+ unsigned int rvtype;
+ unsigned char call;
+ unsigned char reserved;
+ unsigned short int params;
+ unsigned int arglist;
+ } procedure_v2;
+
+ struct
+ {
+ unsigned short int len;
+ short int id;
+ unsigned short int rvtype;
+ unsigned short int class_type;
+ unsigned short int this_type;
+ unsigned char call;
+ unsigned char reserved;
+ unsigned short int params;
+ unsigned short int arglist;
+ unsigned int this_adjust;
+ } mfunction_v1;
+
+ struct
+ {
+ unsigned short int len;
+ short int id;
+ unsigned int rvtype;
+ unsigned int class_type;
+ unsigned this_type;
+ unsigned char call;
+ unsigned char reserved;
+ unsigned short params;
+ unsigned int arglist;
+ unsigned int this_adjust;
+ } mfunction_v2;
+};
+
+union codeview_reftype
+{
+ struct
+ {
+ unsigned short int len;
+ short int id;
+ } generic;
+
+ struct
+ {
+ unsigned short int len;
+ short int id;
+ unsigned char list[1];
+ } fieldlist;
+
+ struct
+ {
+ unsigned short int len;
+ short int id;
+ unsigned char nbits;
+ unsigned char bitoff;
+ unsigned short type;
+ } bitfield_v1;
+
+ struct
+ {
+ unsigned short int len;
+ short int id;
+ unsigned int type;
+ unsigned char nbits;
+ unsigned char bitoff;
+ } bitfield_v2;
+
+ struct
+ {
+ unsigned short int len;
+ short int id;
+ unsigned short num;
+ unsigned short args[1];
+ } arglist_v1;
+
+ struct
+ {
+ unsigned short int len;
+ short int id;
+ unsigned num;
+ unsigned args[1];
+ } arglist_v2;
+
+ struct
+ {
+ unsigned short int len;
+ short int id;
+ unsigned short num;
+ unsigned short drvdcls[1];
+ } derived_v1;
+
+ struct
+ {
+ unsigned short int len;
+ short int id;
+ unsigned num;
+ unsigned drvdcls[1];
+ } derived_v2;
+};
+
+union codeview_fieldtype
+{
+ struct
+ {
+ short int id;
+ } generic;
+
+ struct
+ {
+ short int id;
+ short int type;
+ short int attribute;
+ unsigned short int offset; /* numeric leaf */
+ } bclass_v1;
+
+ struct
+ {
+ short int id;
+ short int attribute;
+ unsigned int type;
+ unsigned short int offset; /* numeric leaf */
+ } bclass_v2;
+
+ struct
+ {
+ short int id;
+ short int btype;
+ short int vbtype;
+ short int attribute;
+ unsigned short int vbpoff; /* numeric leaf */
+#if 0
+ unsigned short int vboff; /* numeric leaf */
+#endif
+ } vbclass_v1;
+
+ struct
+ {
+ short int id;
+ short int attribute;
+ unsigned int btype;
+ unsigned int vbtype;
+ unsigned short int vbpoff; /* numeric leaf */
+#if 0
+ unsigned short int vboff; /* numeric leaf */
+#endif
+ } vbclass_v2;
+
+ struct
+ {
+ short int id;
+ short int attribute;
+ unsigned short int value; /* numeric leaf */
+#if 0
+ struct p_string p_name;
+#endif
+ } enumerate_v1;
+
+ struct
+ {
+ short int id;
+ short int attribute;
+ unsigned short int value; /* numeric leaf */
+#if 0
+ char name[1];
+#endif
+ } enumerate_v3;
+
+ struct
+ {
+ short int id;
+ short int type;
+ struct p_string p_name;
+ } friendfcn_v1;
+
+ struct
+ {
+ short int id;
+ short int _pad0;
+ unsigned int type;
+ struct p_string p_name;
+ } friendfcn_v2;
+
+ struct
+ {
+ short int id;
+ short int type;
+ short int attribute;
+ unsigned short int offset; /* numeric leaf */
+#if 0
+ struct p_string p_name;
+#endif
+ } member_v1;
+
+ struct
+ {
+ short int id;
+ short int attribute;
+ unsigned int type;
+ unsigned short int offset; /* numeric leaf */
+#if 0
+ struct p_string p_name;
+#endif
+ } member_v2;
+
+ struct
+ {
+ short int id;
+ short int attribute;
+ unsigned int type;
+ unsigned short int offset; /* numeric leaf */
+#if 0
+ unsigned char name[1];
+#endif
+ }
+ member_v3;
+
+ struct
+ {
+ short int id;
+ short int type;
+ short int attribute;
+ struct p_string p_name;
+ } stmember_v1;
+
+ struct
+ {
+ short int id;
+ short int attribute;
+ unsigned int type;
+ struct p_string p_name;
+ } stmember_v2;
+
+ struct
+ {
+ short int id;
+ short int attribute;
+ unsigned int type;
+ char name[1];
+ } stmember_v3;
+
+ struct
+ {
+ short int id;
+ short int count;
+ short int mlist;
+ struct p_string p_name;
+ } method_v1;
+
+ struct
+ {
+ short int id;
+ short int count;
+ unsigned int mlist;
+ struct p_string p_name;
+ } method_v2;
+
+ struct
+ {
+ short int id;
+ short int count;
+ unsigned int mlist;
+ char name[1];
+ } method_v3;
+
+ struct
+ {
+ short int id;
+ short int type;
+ struct p_string p_name;
+ } nesttype_v1;
+
+ struct
+ {
+ short int id;
+ short int _pad0;
+ unsigned int type;
+ struct p_string p_name;
+ } nesttype_v2;
+
+ struct
+ {
+ short int id;
+ short int _pad0;
+ unsigned int type;
+ char name[1];
+ } nesttype_v3;
+
+ struct
+ {
+ short int id;
+ short int type;
+ } vfunctab_v1;
+
+ struct
+ {
+ short int id;
+ short int _pad0;
+ unsigned int type;
+ } vfunctab_v2;
+
+ struct
+ {
+ short int id;
+ short int type;
+ } friendcls_v1;
+
+ struct
+ {
+ short int id;
+ short int _pad0;
+ unsigned int type;
+ } friendcls_v2;
+
+ struct
+ {
+ short int id;
+ short int attribute;
+ short int type;
+ struct p_string p_name;
+ } onemethod_v1;
+
+ struct
+ {
+ short int id;
+ short int attribute;
+ unsigned int type;
+ struct p_string p_name;
+ } onemethod_v2;
+
+ struct
+ {
+ short int id;
+ short int attribute;
+ unsigned int type;
+ char name[1];
+ } onemethod_v3;
+
+ struct
+ {
+ short int id;
+ short int attribute;
+ short int type;
+ unsigned int vtab_offset;
+ struct p_string p_name;
+ } onemethod_virt_v1;
+
+ struct
+ {
+ short int id;
+ short int attribute;
+ unsigned int type;
+ unsigned int vtab_offset;
+ struct p_string p_name;
+ } onemethod_virt_v2;
+
+ struct
+ {
+ short int id;
+ short int attribute;
+ unsigned int type;
+ unsigned int vtab_offset;
+ char name[1];
+ } onemethod_virt_v3;
+
+ struct
+ {
+ short int id;
+ short int type;
+ unsigned int offset;
+ } vfuncoff_v1;
+
+ struct
+ {
+ short int id;
+ short int _pad0;
+ unsigned int type;
+ unsigned int offset;
+ } vfuncoff_v2;
+
+ struct
+ {
+ short int id;
+ short int attribute;
+ short int type;
+ struct p_string p_name;
+ } nesttypeex_v1;
+
+ struct
+ {
+ short int id;
+ short int attribute;
+ unsigned int type;
+ struct p_string p_name;
+ } nesttypeex_v2;
+
+ struct
+ {
+ short int id;
+ short int attribute;
+ unsigned int type;
+ struct p_string p_name;
+ } membermodify_v2;
+
+};
+
+union codeview_oem_type
+{
+ struct
+ {
+ short int oemid;
+ short int id;
+ short int count;
+ } generic;
+
+ struct
+ {
+ short int oemid; // 0x42 for D
+ short int id; // 1
+ short int count; // 2
+ short int index_type;
+ short int elem_type;
+ } d_dyn_array;
+
+ struct
+ {
+ short int oemid; // 0x42 for D
+ short int id; // 2
+ short int count; // 2
+ short int key_type;
+ short int elem_type;
+ } d_assoc_array;
+
+ struct
+ {
+ short int oemid; // 0x42 for D
+ short int id; // 3
+ short int count; // 2
+ short int this_type;
+ short int func_type;
+ } d_delegate;
+};
+
+/*
+ * This covers the basic datatypes that VC++ seems to be using these days.
+ * 32 bit mode only. There are additional numbers for the pointers in 16
+ * bit mode. There are many other types listed in the documents, but these
+ * are apparently not used by the compiler, or represent pointer types
+ * that are not used.
+ *
+ * Official MS documentation says that type (< 0x4000, so 12 bits) is made of:
+ * +----------+------+------+----------+------+
+ * | 11 | 10-8 | 7-4 | 3 | 2-0 |
+ * +----------+------+------+----------+------+
+ * | reserved | mode | type | reserved | size |
+ * +----------+------+------+----------+------+
+ * In recent PDB files, type 8 exists, and is seen as an HRESULT... So we've
+ * added this basic type... as if bit 3 had been integrated into the size field
+ */
+
+/* the type number of a built-in type is a 16-bit value specified in the following format:
+ bit # | 11 | 10-8 | 7-4 | 3 | 2-0 |
+ field | reserved | mode | type | reserved | size |
+
+ where
+ <type> is one of the following types:
+ 0x00 Special
+ 0x01 Signed integral value
+ 0x02 Unsigned integral value
+ 0x03 Boolean
+ 0x04 Real
+ 0x05 Complex
+ 0x06 Special2
+ 0x07 Real int value
+ 0x08 Reserved
+ 0x09 Reserved
+ 0x0a Reserved
+ 0x0b Reserved
+ 0x0c Reserved
+ 0x0d Reserved
+ 0x0e Reserved
+ 0x0f Reserved for debugger expression evaluator
+
+ <size> is an enumerated value for each of the types.
+ Type = special
+ 0x00 No type
+ 0x01 Absolute symbol
+ 0x02 Segment
+ 0x03 Void
+ 0x04 Basic 8-byte currency value
+ 0x05 Near Basic string
+ 0x06 Far Basic string
+ 0x07 Untranslated type from previous Microsoft symbol formats
+ Type = signed/unsigned integral and Boolean values
+ 0x00 1 byte
+ 0x01 2 byte
+ 0x02 4 byte
+ 0x03 8 byte
+ 0x04 Reserved
+ 0x05 Reserved
+ 0x06 Reserved
+ 0x07 Reserved
+ Type = real and complex
+ 0x00 32 bit
+ 0x01 64 bit
+ 0x02 80 bit
+ 0x03 128 bit
+ 0x04 48 bit
+ 0x05 Reserved
+ 0x06 Reserved
+ 0x07 Reserved
+ Type = special2
+ 0x00 Bit
+ 0x01 Pascal CHAR
+ Type = Real int
+ 0x00 Char
+ 0x01 Wide character
+ 0x02 2-byte signed integer
+ 0x03 2-byte unsigned integer
+ 0x04 4-byte signed integer
+ 0x05 4-byte unsigned integer
+ 0x06 8-byte signed integer
+ 0x07 8-byte unsigned integer
+
+ <mode> is the pointer mode:
+ 0x00 Direct; not a pointer
+ 0x01 Near pointer
+ 0x02 Far pointer
+ 0x03 Huge pointer
+ 0x04 32-bit near pointer
+ 0x05 32-bit far pointer
+ 0x06 64-bit near pointer
+ 0x07 Reserved
+*/
+
+/* basic types */
+#define T_NOTYPE 0x0000 /* Notype */
+#define T_ABS 0x0001 /* Abs */
+#define T_SEGMENT 0x0002 /* segment type */
+#define T_VOID 0x0003 /* Void */
+#define T_CURRENCY 0x0004 /* basic 8-byte currency value */
+#define T_NBASICSTR 0x0005 /* near basic string */
+#define T_FBASICSTR 0x0006 /* far basic string */
+#define T_NOTTRANS 0x0007 /* untranslated type record from MS symbol format */
+#define T_HRESULT 0x0008 /* HRESULT - or error code ??? */
+#define T_CHAR 0x0010 /* signed char */
+#define T_SHORT 0x0011 /* short */
+#define T_LONG 0x0012 /* long */
+#define T_QUAD 0x0013 /* long long */
+#define T_UCHAR 0x0020 /* unsigned char */
+#define T_USHORT 0x0021 /* unsigned short */
+#define T_ULONG 0x0022 /* unsigned long */
+#define T_UQUAD 0x0023 /* unsigned long long */
+#define T_BOOL08 0x0030 /* 8-bit boolean */
+#define T_BOOL16 0x0031 /* 16-bit boolean */
+#define T_BOOL32 0x0032 /* 32-bit boolean */
+#define T_BOOL64 0x0033 /* 64-bit boolean */
+#define T_REAL32 0x0040 /* float */
+#define T_REAL64 0x0041 /* double */
+#define T_REAL80 0x0042 /* 80-bit real */
+#define T_REAL128 0x0043 /* 128-bit real */
+#define T_REAL48 0x0044 /* 48-bit real */
+#define T_CPLX32 0x0050 /* 32-bit complex number */
+#define T_CPLX64 0x0051 /* 64-bit complex number */
+#define T_CPLX80 0x0052 /* 80-bit complex number */
+#define T_CPLX128 0x0053 /* 128-bit complex number */
+#define T_BIT 0x0060 /* bit */
+#define T_PASCHAR 0x0061 /* pascal CHAR */
+#define T_RCHAR 0x0070 /* real char */
+#define T_WCHAR 0x0071 /* wide char */
+#define T_INT2 0x0072 /* real 16-bit signed int */
+#define T_UINT2 0x0073 /* real 16-bit unsigned int */
+#define T_INT4 0x0074 /* int */
+#define T_UINT4 0x0075 /* unsigned int */
+#define T_INT8 0x0076 /* 64-bit signed int */
+#define T_UINT8 0x0077 /* 64-bit unsigned int */
+
+
+/* near pointers to basic types */
+#define T_PVOID 0x0103 /* near pointer to void */
+#define T_PCHAR 0x0110 /* Near pointer to 8-bit signed */
+#define T_PSHORT 0x0111 /* Near pointer to 16-bit signed */
+#define T_PLONG 0x0112 /* Near pointer to 32-bit signed */
+#define T_PQUAD 0x0113 /* Near pointer to 64-bit signed */
+#define T_PUCHAR 0x0120 /* Near pointer to 8-bit unsigned */
+#define T_PUSHORT 0x0121 /* Near pointer to 16-bit unsigned */
+#define T_PULONG 0x0122 /* Near pointer to 32-bit unsigned */
+#define T_PUQUAD 0x0123 /* Near pointer to 64-bit unsigned */
+#define T_PBOOL08 0x0130 /* Near pointer to 8-bit Boolean */
+#define T_PBOOL16 0x0131 /* Near pointer to 16-bit Boolean */
+#define T_PBOOL32 0x0132 /* Near pointer to 32-bit Boolean */
+#define T_PBOOL64 0x0133 /* Near pointer to 64-bit Boolean */
+#define T_PREAL32 0x0140 /* Near pointer to 32-bit real */
+#define T_PREAL64 0x0141 /* Near pointer to 64-bit real */
+#define T_PREAL80 0x0142 /* Near pointer to 80-bit real */
+#define T_PREAL128 0x0143 /* Near pointer to 128-bit real */
+#define T_PREAL48 0x0144 /* Near pointer to 48-bit real */
+#define T_PCPLX32 0x0150 /* Near pointer to 32-bit complex */
+#define T_PCPLX64 0x0151 /* Near pointer to 64-bit complex */
+#define T_PCPLX80 0x0152 /* Near pointer to 80-bit complex */
+#define T_PCPLX128 0x0153 /* Near pointer to 128-bit complex */
+#define T_PRCHAR 0x0170 /* Near pointer to a real char */
+#define T_PWCHAR 0x0171 /* Near pointer to a wide char */
+#define T_PINT2 0x0172 /* Near pointer to 16-bit signed int */
+#define T_PUINT2 0x0173 /* Near pointer to 16-bit unsigned int */
+#define T_PINT4 0x0174 /* Near pointer to 32-bit signed int */
+#define T_PUINT4 0x0175 /* Near pointer to 32-bit unsigned int */
+#define T_PINT8 0x0176 /* Near pointer to 64-bit signed int */
+#define T_PUINT8 0x0177 /* Near pointer to 64-bit unsigned int */
+
+
+/* far pointers to basic types */
+#define T_PFVOID 0x0203 /* Far pointer to void */
+#define T_PFCHAR 0x0210 /* Far pointer to 8-bit signed */
+#define T_PFSHORT 0x0211 /* Far pointer to 16-bit signed */
+#define T_PFLONG 0x0212 /* Far pointer to 32-bit signed */
+#define T_PFQUAD 0x0213 /* Far pointer to 64-bit signed */
+#define T_PFUCHAR 0x0220 /* Far pointer to 8-bit unsigned */
+#define T_PFUSHORT 0x0221 /* Far pointer to 16-bit unsigned */
+#define T_PFULONG 0x0222 /* Far pointer to 32-bit unsigned */
+#define T_PFUQUAD 0x0223 /* Far pointer to 64-bit unsigned */
+#define T_PFBOOL08 0x0230 /* Far pointer to 8-bit Boolean */
+#define T_PFBOOL16 0x0231 /* Far pointer to 16-bit Boolean */
+#define T_PFBOOL32 0x0232 /* Far pointer to 32-bit Boolean */
+#define T_PFBOOL64 0x0233 /* Far pointer to 64-bit Boolean */
+#define T_PFREAL32 0x0240 /* Far pointer to 32-bit real */
+#define T_PFREAL64 0x0241 /* Far pointer to 64-bit real */
+#define T_PFREAL80 0x0242 /* Far pointer to 80-bit real */
+#define T_PFREAL128 0x0243 /* Far pointer to 128-bit real */
+#define T_PFREAL48 0x0244 /* Far pointer to 48-bit real */
+#define T_PFCPLX32 0x0250 /* Far pointer to 32-bit complex */
+#define T_PFCPLX64 0x0251 /* Far pointer to 64-bit complex */
+#define T_PFCPLX80 0x0252 /* Far pointer to 80-bit complex */
+#define T_PFCPLX128 0x0253 /* Far pointer to 128-bit complex */
+#define T_PFRCHAR 0x0270 /* Far pointer to a real char */
+#define T_PFWCHAR 0x0271 /* Far pointer to a wide char */
+#define T_PFINT2 0x0272 /* Far pointer to 16-bit signed int */
+#define T_PFUINT2 0x0273 /* Far pointer to 16-bit unsigned int */
+#define T_PFINT4 0x0274 /* Far pointer to 32-bit signed int */
+#define T_PFUINT4 0x0275 /* Far pointer to 32-bit unsigned int */
+#define T_PFINT8 0x0276 /* Far pointer to 64-bit signed int */
+#define T_PFUINT8 0x0277 /* Far pointer to 64-bit unsigned int */
+
+
+/* huge pointers to basic types */
+#define T_PHVOID 0x0303 /* Huge pointer to void */
+#define T_PHCHAR 0x0310 /* Huge pointer to 8-bit signed */
+#define T_PHSHORT 0x0311 /* Huge pointer to 16-bit signed */
+#define T_PHLONG 0x0312 /* Huge pointer to 32-bit signed */
+#define T_PHQUAD 0x0313 /* Huge pointer to 64-bit signed */
+#define T_PHUCHAR 0x0320 /* Huge pointer to 8-bit unsigned */
+#define T_PHUSHORT 0x0321 /* Huge pointer to 16-bit unsigned */
+#define T_PHULONG 0x0322 /* Huge pointer to 32-bit unsigned */
+#define T_PHUQUAD 0x0323 /* Huge pointer to 64-bit unsigned */
+#define T_PHBOOL08 0x0330 /* Huge pointer to 8-bit Boolean */
+#define T_PHBOOL16 0x0331 /* Huge pointer to 16-bit Boolean */
+#define T_PHBOOL32 0x0332 /* Huge pointer to 32-bit Boolean */
+#define T_PHBOOL64 0x0333 /* Huge pointer to 64-bit Boolean */
+#define T_PHREAL32 0x0340 /* Huge pointer to 32-bit real */
+#define T_PHREAL64 0x0341 /* Huge pointer to 64-bit real */
+#define T_PHREAL80 0x0342 /* Huge pointer to 80-bit real */
+#define T_PHREAL128 0x0343 /* Huge pointer to 128-bit real */
+#define T_PHREAL48 0x0344 /* Huge pointer to 48-bit real */
+#define T_PHCPLX32 0x0350 /* Huge pointer to 32-bit complex */
+#define T_PHCPLX64 0x0351 /* Huge pointer to 64-bit complex */
+#define T_PHCPLX80 0x0352 /* Huge pointer to 80-bit complex */
+#define T_PHCPLX128 0x0353 /* Huge pointer to 128-bit real */
+#define T_PHRCHAR 0x0370 /* Huge pointer to a real char */
+#define T_PHWCHAR 0x0371 /* Huge pointer to a wide char */
+#define T_PHINT2 0x0372 /* Huge pointer to 16-bit signed int */
+#define T_PHUINT2 0x0373 /* Huge pointer to 16-bit unsigned int */
+#define T_PHINT4 0x0374 /* Huge pointer to 32-bit signed int */
+#define T_PHUINT4 0x0375 /* Huge pointer to 32-bit unsigned int */
+#define T_PHINT8 0x0376 /* Huge pointer to 64-bit signed int */
+#define T_PHUINT8 0x0377 /* Huge pointer to 64-bit unsigned int */
+
+
+/* 32-bit near pointers to basic types */
+#define T_32PVOID 0x0403 /* 32-bit near pointer to void */
+#define T_32PHRESULT 0x0408 /* 16:32 near pointer to HRESULT - or error code ??? */
+#define T_32PCHAR 0x0410 /* 16:32 near pointer to 8-bit signed */
+#define T_32PSHORT 0x0411 /* 16:32 near pointer to 16-bit signed */
+#define T_32PLONG 0x0412 /* 16:32 near pointer to 32-bit signed */
+#define T_32PQUAD 0x0413 /* 16:32 near pointer to 64-bit signed */
+#define T_32PUCHAR 0x0420 /* 16:32 near pointer to 8-bit unsigned */
+#define T_32PUSHORT 0x0421 /* 16:32 near pointer to 16-bit unsigned */
+#define T_32PULONG 0x0422 /* 16:32 near pointer to 32-bit unsigned */
+#define T_32PUQUAD 0x0423 /* 16:32 near pointer to 64-bit unsigned */
+#define T_32PBOOL08 0x0430 /* 16:32 near pointer to 8-bit Boolean */
+#define T_32PBOOL16 0x0431 /* 16:32 near pointer to 16-bit Boolean */
+#define T_32PBOOL32 0x0432 /* 16:32 near pointer to 32-bit Boolean */
+#define T_32PBOOL64 0x0433 /* 16:32 near pointer to 64-bit Boolean */
+#define T_32PREAL32 0x0440 /* 16:32 near pointer to 32-bit real */
+#define T_32PREAL64 0x0441 /* 16:32 near pointer to 64-bit real */
+#define T_32PREAL80 0x0442 /* 16:32 near pointer to 80-bit real */
+#define T_32PREAL128 0x0443 /* 16:32 near pointer to 128-bit real */
+#define T_32PREAL48 0x0444 /* 16:32 near pointer to 48-bit real */
+#define T_32PCPLX32 0x0450 /* 16:32 near pointer to 32-bit complex */
+#define T_32PCPLX64 0x0451 /* 16:32 near pointer to 64-bit complex */
+#define T_32PCPLX80 0x0452 /* 16:32 near pointer to 80-bit complex */
+#define T_32PCPLX128 0x0453 /* 16:32 near pointer to 128-bit complex */
+#define T_32PRCHAR 0x0470 /* 16:32 near pointer to a real char */
+#define T_32PWCHAR 0x0471 /* 16:32 near pointer to a wide char */
+#define T_32PINT2 0x0472 /* 16:32 near pointer to 16-bit signed int */
+#define T_32PUINT2 0x0473 /* 16:32 near pointer to 16-bit unsigned int */
+#define T_32PINT4 0x0474 /* 16:32 near pointer to 32-bit signed int */
+#define T_32PUINT4 0x0475 /* 16:32 near pointer to 32-bit unsigned int */
+#define T_32PINT8 0x0476 /* 16:32 near pointer to 64-bit signed int */
+#define T_32PUINT8 0x0477 /* 16:32 near pointer to 64-bit unsigned int */
+
+
+/* 32-bit far pointers to basic types */
+#define T_32PFVOID 0x0503 /* 32-bit far pointer to void */
+#define T_32PFCHAR 0x0510 /* 16:32 far pointer to 8-bit signed */
+#define T_32PFSHORT 0x0511 /* 16:32 far pointer to 16-bit signed */
+#define T_32PFLONG 0x0512 /* 16:32 far pointer to 32-bit signed */
+#define T_32PFQUAD 0x0513 /* 16:32 far pointer to 64-bit signed */
+#define T_32PFUCHAR 0x0520 /* 16:32 far pointer to 8-bit unsigned */
+#define T_32PFUSHORT 0x0521 /* 16:32 far pointer to 16-bit unsigned */
+#define T_32PFULONG 0x0522 /* 16:32 far pointer to 32-bit unsigned */
+#define T_32PFUQUAD 0x0523 /* 16:32 far pointer to 64-bit unsigned */
+#define T_32PFBOOL08 0x0530 /* 16:32 far pointer to 8-bit Boolean */
+#define T_32PFBOOL16 0x0531 /* 16:32 far pointer to 16-bit Boolean */
+#define T_32PFBOOL32 0x0532 /* 16:32 far pointer to 32-bit Boolean */
+#define T_32PFBOOL64 0x0533 /* 16:32 far pointer to 64-bit Boolean */
+#define T_32PFREAL32 0x0540 /* 16:32 far pointer to 32-bit real */
+#define T_32PFREAL64 0x0541 /* 16:32 far pointer to 64-bit real */
+#define T_32PFREAL80 0x0542 /* 16:32 far pointer to 80-bit real */
+#define T_32PFREAL128 0x0543 /* 16:32 far pointer to 128-bit real */
+#define T_32PFREAL48 0x0544 /* 16:32 far pointer to 48-bit real */
+#define T_32PFCPLX32 0x0550 /* 16:32 far pointer to 32-bit complex */
+#define T_32PFCPLX64 0x0551 /* 16:32 far pointer to 64-bit complex */
+#define T_32PFCPLX80 0x0552 /* 16:32 far pointer to 80-bit complex */
+#define T_32PFCPLX128 0x0553 /* 16:32 far pointer to 128-bit complex */
+#define T_32PFRCHAR 0x0570 /* 16:32 far pointer to a real char */
+#define T_32PFWCHAR 0x0571 /* 16:32 far pointer to a wide char */
+#define T_32PFINT2 0x0572 /* 16:32 far pointer to 16-bit signed int */
+#define T_32PFUINT2 0x0573 /* 16:32 far pointer to 16-bit unsigned int */
+#define T_32PFINT4 0x0574 /* 16:32 far pointer to 32-bit signed int */
+#define T_32PFUINT4 0x0575 /* 16:32 far pointer to 32-bit unsigned int */
+#define T_32PFINT8 0x0576 /* 16:32 far pointer to 64-bit signed int */
+#define T_32PFUINT8 0x0577 /* 16:32 far pointer to 64-bit unsigned int */
+
+
+/* counts, bit masks, and shift values needed to access various parts of the built-in type numbers */
+#define T_MAXPREDEFINEDTYPE 0x0580 /* maximum type index for all built-in types */
+#define T_MAXBASICTYPE 0x0080 /* maximum type index all non-pointer built-in types */
+#define T_BASICTYPE_MASK 0x00ff /* mask of bits that can potentially identify a non-pointer basic type */
+#define T_BASICTYPE_SHIFT 8 /* shift count to push out the basic type bits from a type number */
+#define T_MODE_MASK 0x0700 /* type mode mask (ptr/non-ptr) */
+#define T_SIZE_MASK 0x0007 /* type size mask (depends on 'type' value) */
+#define T_TYPE_MASK 0x00f0 /* type type mask (data treatment mode) */
+
+/* bit patterns for the <mode> portion of a built-in type number */
+#define T_NEARPTR_BITS 0x0100
+#define T_FARPTR_BITS 0x0200
+#define T_HUGEPTR_BITS 0x0300
+#define T_NEAR32PTR_BITS 0x0400
+#define T_FAR32PTR_BITS 0x0500
+#define T_NEAR64PTR_BITS 0x0600
+
+#define LF_MODIFIER_V1 0x0001
+#define LF_POINTER_V1 0x0002
+#define LF_ARRAY_V1 0x0003
+#define LF_CLASS_V1 0x0004
+#define LF_STRUCTURE_V1 0x0005
+#define LF_UNION_V1 0x0006
+#define LF_ENUM_V1 0x0007
+#define LF_PROCEDURE_V1 0x0008
+#define LF_MFUNCTION_V1 0x0009
+#define LF_VTSHAPE_V1 0x000a
+#define LF_COBOL0_V1 0x000b
+#define LF_COBOL1_V1 0x000c
+#define LF_BARRAY_V1 0x000d
+#define LF_LABEL_V1 0x000e
+#define LF_NULL_V1 0x000f
+#define LF_NOTTRAN_V1 0x0010
+#define LF_DIMARRAY_V1 0x0011
+#define LF_VFTPATH_V1 0x0012
+#define LF_PRECOMP_V1 0x0013
+#define LF_ENDPRECOMP_V1 0x0014
+#define LF_OEM_V1 0x0015
+#define LF_TYPESERVER_V1 0x0016
+
+#define LF_MODIFIER_V2 0x1001 /* variants with new 32-bit type indices (V2) */
+#define LF_POINTER_V2 0x1002
+#define LF_ARRAY_V2 0x1003
+#define LF_CLASS_V2 0x1004
+#define LF_STRUCTURE_V2 0x1005
+#define LF_UNION_V2 0x1006
+#define LF_ENUM_V2 0x1007
+#define LF_PROCEDURE_V2 0x1008
+#define LF_MFUNCTION_V2 0x1009
+#define LF_COBOL0_V2 0x100a
+#define LF_BARRAY_V2 0x100b
+#define LF_DIMARRAY_V2 0x100c
+#define LF_VFTPATH_V2 0x100d
+#define LF_PRECOMP_V2 0x100e
+#define LF_OEM_V2 0x100f
+
+#define LF_SKIP_V1 0x0200
+#define LF_ARGLIST_V1 0x0201
+#define LF_DEFARG_V1 0x0202
+#define LF_LIST_V1 0x0203
+#define LF_FIELDLIST_V1 0x0204
+#define LF_DERIVED_V1 0x0205
+#define LF_BITFIELD_V1 0x0206
+#define LF_METHODLIST_V1 0x0207
+#define LF_DIMCONU_V1 0x0208
+#define LF_DIMCONLU_V1 0x0209
+#define LF_DIMVARU_V1 0x020a
+#define LF_DIMVARLU_V1 0x020b
+#define LF_REFSYM_V1 0x020c
+
+#define LF_SKIP_V2 0x1200 /* variants with new 32-bit type indices (V2) */
+#define LF_ARGLIST_V2 0x1201
+#define LF_DEFARG_V2 0x1202
+#define LF_FIELDLIST_V2 0x1203
+#define LF_DERIVED_V2 0x1204
+#define LF_BITFIELD_V2 0x1205
+#define LF_METHODLIST_V2 0x1206
+#define LF_DIMCONU_V2 0x1207
+#define LF_DIMCONLU_V2 0x1208
+#define LF_DIMVARU_V2 0x1209
+#define LF_DIMVARLU_V2 0x120a
+
+/* Field lists */
+#define LF_BCLASS_V1 0x0400
+#define LF_VBCLASS_V1 0x0401
+#define LF_IVBCLASS_V1 0x0402
+#define LF_ENUMERATE_V1 0x0403
+#define LF_FRIENDFCN_V1 0x0404
+#define LF_INDEX_V1 0x0405
+#define LF_MEMBER_V1 0x0406
+#define LF_STMEMBER_V1 0x0407
+#define LF_METHOD_V1 0x0408
+#define LF_NESTTYPE_V1 0x0409
+#define LF_VFUNCTAB_V1 0x040a
+#define LF_FRIENDCLS_V1 0x040b
+#define LF_ONEMETHOD_V1 0x040c
+#define LF_VFUNCOFF_V1 0x040d
+#define LF_NESTTYPEEX_V1 0x040e
+#define LF_MEMBERMODIFY_V1 0x040f
+
+#define LF_BCLASS_V2 0x1400 /* variants with new 32-bit type indices (V2) */
+#define LF_VBCLASS_V2 0x1401
+#define LF_IVBCLASS_V2 0x1402
+#define LF_FRIENDFCN_V2 0x1403
+#define LF_INDEX_V2 0x1404
+#define LF_MEMBER_V2 0x1405
+#define LF_STMEMBER_V2 0x1406
+#define LF_METHOD_V2 0x1407
+#define LF_NESTTYPE_V2 0x1408
+#define LF_VFUNCTAB_V2 0x1409
+#define LF_FRIENDCLS_V2 0x140a
+#define LF_ONEMETHOD_V2 0x140b
+#define LF_VFUNCOFF_V2 0x140c
+#define LF_NESTTYPEEX_V2 0x140d
+
+#define LF_ENUMERATE_V3 0x1502
+#define LF_ARRAY_V3 0x1503
+#define LF_CLASS_V3 0x1504
+#define LF_STRUCTURE_V3 0x1505
+#define LF_UNION_V3 0x1506
+#define LF_ENUM_V3 0x1507
+#define LF_MEMBER_V3 0x150d
+#define LF_STMEMBER_V3 0x150e
+#define LF_METHOD_V3 0x150f
+#define LF_NESTTYPE_V3 0x1510
+#define LF_ONEMETHOD_V3 0x1511
+
+#define LF_NUMERIC 0x8000 /* numeric leaf types */
+#define LF_CHAR 0x8000
+#define LF_SHORT 0x8001
+#define LF_USHORT 0x8002
+#define LF_LONG 0x8003
+#define LF_ULONG 0x8004
+#define LF_REAL32 0x8005
+#define LF_REAL64 0x8006
+#define LF_REAL80 0x8007
+#define LF_REAL128 0x8008
+#define LF_QUADWORD 0x8009
+#define LF_UQUADWORD 0x800a
+#define LF_REAL48 0x800b
+#define LF_COMPLEX32 0x800c
+#define LF_COMPLEX64 0x800d
+#define LF_COMPLEX80 0x800e
+#define LF_COMPLEX128 0x800f
+#define LF_VARSTRING 0x8010
+
+/* ======================================== *
+ * Symbol information
+ * ======================================== */
+
+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];
+ } 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];
+ } 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];
+ } 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];
+ } 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];
+ } 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];
+ } 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];
+ /* 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];
+ } 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];
+ } 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];
+#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];
+ } 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];
+ } compiland_v3;
+
+ struct
+ {
+ short int len;
+ short int id;
+ unsigned int offset;
+ unsigned short segment;
+ } ssearch_v1;
+
+ struct
+ {
+ short int len;
+ short int id;
+ short int flags;
+ char style;
+ char count; /* optional */
+ char reglist[1]; /* count elements */
+
+ } functionret_v1;
+
+ struct
+ {
+ short int len;
+ short int id;
+ unsigned int checksum;
+ unsigned int offset;
+ unsigned int module;
+ struct p_string p_name; // not included in len
+ } procref_v1;
+
+ struct
+ {
+ short int len;
+ short int id;
+ unsigned short int sizeLocals; // sum of size of locals and arguments
+ unsigned short int unknown[10];
+ unsigned short int info; // hasAlloca,hasSetjmp,hasLongjmp,hasInlAsm,hasEH,inl_specified,hasSEH,naked,hasGsChecks,hasEHa,noStackOrdering,wasInlined,strictGsCheck
+ // return UDT,instance constructor,instance constructor with virtual base
+ unsigned int unknown2;
+ } funcinfo_32;
+};
+
+#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_FUNCINFO_32 0x1012
+#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
+
+#define S_COMPILER_V4 0x113c /* compiler version info? */
+#define S_MSTOOL_V4 0x113d /* compiler command line options and build information */
+
+#define S_LINKER_1 0x112c /* symbol info emitted from linker */
+#define S_SEGINFO_1 0x1136 /* emitted by linker */
+#define S_SEGINFO_2 0x1137 /* emitted by linker */
+
+/* ======================================== *
+ * Line number information
+ * ======================================== */
+
+union any_size
+{
+ const char* c;
+ const unsigned char* uc;
+ const short* s;
+ const int* i;
+ const unsigned int* ui;
+};
+
+struct startend
+{
+ unsigned int start;
+ unsigned int end;
+};
+
+struct codeview_linetab
+{
+ unsigned int nline;
+ unsigned int segno;
+ unsigned int start;
+ unsigned int end;
+ unsigned int source;
+ const unsigned short* linetab;
+ const unsigned int* offtab;
+};
+
+
+/* ======================================== *
+ * PDB file information
+ * ======================================== */
+
+
+struct PDB_FILE
+{
+ DWORD size;
+ DWORD unknown;
+};
+
+struct PDB_JG_HEADER
+{
+ CHAR ident[40];
+ DWORD signature;
+ DWORD block_size;
+ WORD free_list;
+ WORD total_alloc;
+ struct PDB_FILE toc;
+ WORD toc_block[1];
+};
+
+struct PDB_DS_HEADER
+{
+ char signature[32];
+ DWORD block_size;
+ DWORD unknown1;
+ DWORD num_pages;
+ DWORD toc_size;
+ DWORD unknown2;
+ DWORD toc_page;
+};
+
+struct PDB_JG_TOC
+{
+ DWORD num_files;
+ struct PDB_FILE file[1];
+};
+
+struct PDB_DS_TOC
+{
+ DWORD num_files;
+ DWORD file_size[1];
+};
+
+struct PDB_JG_ROOT
+{
+ DWORD Version;
+ DWORD TimeDateStamp;
+ DWORD Age;
+ DWORD cbNames;
+ CHAR names[1];
+};
+
+struct PDB_DS_ROOT
+{
+ DWORD Version;
+ DWORD TimeDateStamp;
+ DWORD Age;
+ GUID guid;
+ DWORD cbNames;
+ CHAR names[1];
+};
+
+typedef struct _PDB_TYPES_OLD
+{
+ DWORD version;
+ WORD first_index;
+ WORD last_index;
+ DWORD type_size;
+ WORD file;
+ WORD pad;
+} PDB_TYPES_OLD, *PPDB_TYPES_OLD;
+
+typedef struct _PDB_TYPES
+{
+ DWORD version;
+ DWORD type_offset;
+ DWORD first_index;
+ DWORD last_index;
+ DWORD type_size;
+ WORD file;
+ WORD pad;
+ DWORD hash_size;
+ DWORD hash_base;
+ DWORD hash_offset;
+ DWORD hash_len;
+ DWORD search_offset;
+ DWORD search_len;
+ DWORD unknown_offset;
+ DWORD unknown_len;
+} PDB_TYPES, *PPDB_TYPES;
+
+typedef struct _PDB_SYMBOL_RANGE
+{
+ WORD segment;
+ WORD pad1;
+ DWORD offset;
+ DWORD size;
+ DWORD characteristics;
+ WORD index;
+ WORD pad2;
+} PDB_SYMBOL_RANGE, *PPDB_SYMBOL_RANGE;
+
+typedef struct _PDB_SYMBOL_RANGE_EX
+{
+ WORD segment;
+ WORD pad1;
+ DWORD offset;
+ DWORD size;
+ DWORD characteristics;
+ WORD index;
+ WORD pad2;
+ DWORD timestamp;
+ DWORD unknown;
+} PDB_SYMBOL_RANGE_EX, *PPDB_SYMBOL_RANGE_EX;
+
+typedef struct _PDB_SYMBOL_FILE
+{
+ DWORD unknown1;
+ PDB_SYMBOL_RANGE range;
+ WORD flag;
+ WORD file;
+ DWORD symbol_size;
+ DWORD lineno_size;
+ DWORD unknown2;
+ DWORD nSrcFiles;
+ DWORD attribute;
+ CHAR filename[1];
+} PDB_SYMBOL_FILE, *PPDB_SYMBOL_FILE;
+
+typedef struct _PDB_SYMBOL_FILE_EX
+{
+ DWORD unknown1;
+ PDB_SYMBOL_RANGE_EX range;
+ WORD flag;
+ WORD file;
+ DWORD symbol_size;
+ DWORD lineno_size;
+ DWORD unknown2;
+ DWORD nSrcFiles;
+ DWORD attribute;
+ DWORD reserved[2];
+ CHAR filename[1];
+} PDB_SYMBOL_FILE_EX, *PPDB_SYMBOL_FILE_EX;
+
+typedef struct _PDB_SYMBOL_SOURCE
+{
+ WORD nModules;
+ WORD nSrcFiles;
+ WORD table[1];
+} PDB_SYMBOL_SOURCE, *PPDB_SYMBOL_SOURCE;
+
+typedef struct _PDB_SYMBOL_IMPORT
+{
+ DWORD unknown1;
+ DWORD unknown2;
+ DWORD TimeDateStamp;
+ DWORD Age;
+ CHAR filename[1];
+} PDB_SYMBOL_IMPORT, *PPDB_SYMBOL_IMPORT;
+
+typedef struct _PDB_SYMBOLS_OLD
+{
+ WORD hash1_file;
+ WORD hash2_file;
+ WORD gsym_file;
+ WORD pad;
+ DWORD module_size;
+ DWORD offset_size;
+ DWORD hash_size;
+ DWORD srcmodule_size;
+} PDB_SYMBOLS_OLD, *PPDB_SYMBOLS_OLD;
+
+typedef struct _PDB_SYMBOLS
+{
+ DWORD signature;
+ DWORD version;
+ DWORD unknown;
+ DWORD hash1_file;
+ DWORD hash2_file;
+ WORD gsym_file;
+ WORD unknown1;
+ DWORD module_size;
+ DWORD offset_size;
+ DWORD hash_size;
+ DWORD srcmodule_size;
+ DWORD pdbimport_size;
+ DWORD resvd[5];
+} PDB_SYMBOLS, *PPDB_SYMBOLS;
+
+#include "poppack.h"
+
+/* ----------------------------------------------
+ * Information used for parsing
+ * ---------------------------------------------- */
+
+typedef struct
+{
+ DWORD from;
+ DWORD to;
+} OMAP_DATA;
+
+struct msc_debug_info
+{
+ struct module* module;
+ int nsect;
+ const IMAGE_SECTION_HEADER* sectp;
+ int nomap;
+ const OMAP_DATA* omapp;
+ const BYTE* root;
+};
+
+/* coff.c */
+extern BOOL coff_process_info(const struct msc_debug_info* msc_dbg);
+
+/* ===================================================
+ * The old CodeView stuff (for NB09 and NB11)
+ * =================================================== */
+
+#define sstModule 0x120
+#define sstTypes 0x121
+#define sstPublic 0x122
+#define sstPublicSym 0x123
+#define sstSymbols 0x124
+#define sstAlignSym 0x125
+#define sstSrcLnSeg 0x126
+#define sstSrcModule 0x127
+#define sstLibraries 0x128
+#define sstGlobalSym 0x129
+#define sstGlobalPub 0x12a
+#define sstGlobalTypes 0x12b
+#define sstMPC 0x12c
+#define sstSegMap 0x12d
+#define sstSegName 0x12e
+#define sstPreComp 0x12f
+#define sstFileIndex 0x133
+#define sstStaticSym 0x134
+
+/* overall structure information */
+typedef struct OMFSignature
+{
+ char Signature[4];
+ long filepos;
+} OMFSignature;
+
+typedef struct OMFSignatureRSDS
+{
+ char Signature[4];
+ GUID guid;
+ DWORD unknown;
+ CHAR name[1];
+} OMFSignatureRSDS;
+
+typedef struct _CODEVIEW_PDB_DATA
+{
+ char Signature[4];
+ long filepos;
+ DWORD timestamp;
+ DWORD unknown;
+ CHAR name[1];
+} CODEVIEW_PDB_DATA, *PCODEVIEW_PDB_DATA;
+
+typedef struct OMFDirHeader
+{
+ WORD cbDirHeader;
+ WORD cbDirEntry;
+ DWORD cDir;
+ DWORD lfoNextDir;
+ DWORD flags;
+} OMFDirHeader;
+
+typedef struct OMFDirEntry
+{
+ WORD SubSection;
+ WORD iMod;
+ DWORD lfo;
+ DWORD cb;
+} OMFDirEntry;
+
+/* sstModule subsection */
+
+typedef struct OMFSegDesc
+{
+ WORD Seg;
+ WORD pad;
+ DWORD Off;
+ DWORD cbSeg;
+} OMFSegDesc;
+
+typedef struct OMFModule
+{
+ WORD ovlNumber;
+ WORD iLib;
+ WORD cSeg;
+ char Style[2];
+/*
+ OMFSegDesc SegInfo[cSeg];
+ p_string Name;
+*/
+} OMFModule;
+
+typedef struct OMFGlobalTypes
+{
+ DWORD flags;
+ DWORD cTypes;
+/*
+ DWORD offset[cTypes];
+ types_record[];
+*/
+} OMFGlobalTypes;
+
+/* 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;
+
+/* 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;
diff --git a/src/mspdb.cpp b/src/mspdb.cpp
new file mode 100644
index 0000000..b7a92a4
--- /dev/null
+++ b/src/mspdb.cpp
@@ -0,0 +1,91 @@
+// Convert DMD CodeView debug information to PDB files
+// Copyright (c) 2009 by Rainer Schuetze, All Rights Reserved
+//
+// License for redistribution is given by the Artistic License 2.0
+// see file LICENSE for further details
+
+#include "mspdb.h"
+
+#include <windows.h>
+
+#pragma comment(lib, "rpcrt4.lib")
+
+HMODULE modMsPdb;
+mspdb::fnPDBOpen2W *pPDBOpen2W;
+
+char* mspdb_dll = "mspdb80.dll";
+
+bool getInstallDir(const char* version, char* installDir, DWORD size)
+{
+ char key[260] = "SOFTWARE\\Microsoft\\";
+ strcat(key, version);
+
+ HKEY hkey;
+ if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, key, 0, KEY_QUERY_VALUE, &hkey) != ERROR_SUCCESS)
+ return false;
+
+ bool rc = RegQueryValueExA(hkey, "InstallDir", 0, 0, (LPBYTE)installDir, &size) == ERROR_SUCCESS;
+ RegCloseKey(hkey);
+ return rc;
+}
+
+bool tryLoadMsPdb(const char* version, const char* mspdb)
+{
+ char installDir[260];
+ if (!getInstallDir(version, installDir, sizeof(installDir)))
+ return false;
+ char* p = installDir + strlen(installDir);
+ if (p[-1] != '\\' && p[-1] != '/')
+ *p++ = '\\';
+ strcpy(p, mspdb);
+
+ modMsPdb = LoadLibraryA(installDir);
+ return modMsPdb != 0;
+}
+
+bool initMsPdb()
+{
+ if (!modMsPdb)
+ modMsPdb = LoadLibraryA(mspdb_dll);
+ if (!modMsPdb)
+ tryLoadMsPdb("VisualStudio\\9.0", mspdb_dll);
+ if (!modMsPdb)
+ tryLoadMsPdb("VisualStudio\\8.0", mspdb_dll);
+ if (!modMsPdb)
+ tryLoadMsPdb("VCExpress\\9.0", mspdb_dll);
+ if (!modMsPdb)
+ tryLoadMsPdb("VCExpress\\8.0", mspdb_dll);
+
+ if (!modMsPdb)
+ return false;
+
+ if (!pPDBOpen2W)
+ pPDBOpen2W = (mspdb::fnPDBOpen2W*) GetProcAddress(modMsPdb, "PDBOpen2W");
+ if (!pPDBOpen2W)
+ return false;
+
+ return true;
+}
+
+bool exitMsPdb()
+{
+ pPDBOpen2W = 0;
+ if (modMsPdb)
+ FreeLibrary(modMsPdb);
+ modMsPdb = 0;
+ return true;
+}
+
+mspdb::PDB* CreatePDB(wchar_t* pdbname)
+{
+ if (!initMsPdb ())
+ return 0;
+
+ mspdb::PDB* pdb = 0;
+ long data[194] = { 193, 0 };
+ wchar_t ext[256] = L".exe";
+ if (!(*pPDBOpen2W) (pdbname, "wf", data, ext, 0x400, &pdb))
+ return 0;
+
+ return pdb;
+}
diff --git a/src/mspdb.h b/src/mspdb.h
new file mode 100644
index 0000000..c3b92ec
--- /dev/null
+++ b/src/mspdb.h
@@ -0,0 +1,494 @@
+// Convert DMD CodeView debug information to PDB files
+// Copyright (c) 2009 by Rainer Schuetze, All Rights Reserved
+//
+// License for redistribution is given by the Artistic License 2.0
+// see file LICENSE for further details
+
+#ifndef __MSPDB_H__
+#define __MSPDB_H__
+
+#include <stdio.h>
+
+namespace mspdb
+{
+
+struct MREUtil;
+struct MREFile;
+struct MREBag;
+struct BufferDefaultAllocator;
+struct EnumSC;
+struct Stream;
+struct EnumThunk;
+struct EnumSyms;
+struct EnumLines;
+struct Dbg;
+struct EnumSrc;
+struct MREDrv;
+struct MREngine;
+struct EnumNameMap_Special;
+struct MRECmp2;
+struct PDB;
+struct Src;
+struct Mod;
+struct DBI;
+struct StreamCached;
+struct GSI;
+struct TPI;
+struct NameMap;
+struct EnumNameMap;
+
+#define MRECmp MRECmp2
+#define PDBCommon PDB
+#define SrcCommon Src
+#define ModCommon Mod
+#define DBICommon DBI
+
+#define MREUtil2 MREUtil
+#define MREFile2 MREFile
+#define MREBag2 MREBag
+#define Mod2 Mod
+#define DBI2 DBI
+#define GSI2 GSI
+#define TPI2 TPI
+#define NameMap2 NameMap
+#define EnumNameMap2 EnumNameMap
+
+struct MREUtil {
+public: virtual int MREUtil::FRelease(void);
+public: virtual void MREUtil::EnumSrcFiles(int (__stdcall*)(struct MREUtil *,struct EnumFile &,enum EnumType),unsigned short const *,void *);
+public: virtual void MREUtil::EnumDepFiles(struct EnumFile &,int (__stdcall*)(struct MREUtil *,struct EnumFile &,enum EnumType));
+public: virtual void MREUtil::EnumAllFiles(int (__stdcall*)(struct MREUtil *,struct EnumFile &),unsigned short const *,void *);
+public: virtual void MREUtil::Enumstructes(int (__stdcall*)(struct MREUtil *,struct Enumstruct &),unsigned short const *,void *);
+public: virtual void MREUtil::SummaryStats(struct MreStats &);
+};
+
+struct MREFile {
+public: virtual int MREFile::FOpenBag(struct MREBag * *,unsigned long);
+public: virtual int MREFile::FnoteEndInclude(unsigned long);
+public: virtual int MREFile::FnotestructMod(unsigned long,unsigned long);
+public: virtual int MREFile::FnoteInlineMethodMod(unsigned long,char const *,unsigned long);
+public: virtual int MREFile::FnoteLineDelta(unsigned long,int);
+public: virtual void MREFile::EnumerateChangedstructes(int (__cdecl*)(unsigned long,struct MREFile *,int (MREFile::*)(unsigned long,unsigned long)));
+public: virtual int MREFile::FnotestructTI(unsigned long,unsigned long);
+public: virtual int MREFile::FIsBoring(void);
+public: virtual int MREFile::FnotePchCreateUse(unsigned short const *,unsigned short const *);
+};
+
+struct MREBag {
+public: virtual int MREBag::FAddDep(unsigned long,unsigned long,char const *,enum DEPON,unsigned long);
+public: virtual int MREBag::FClose(void);
+};
+
+struct BufferDefaultAllocator {
+public: virtual unsigned char * BufferDefaultAllocator::Alloc(long);
+public: virtual unsigned char * BufferDefaultAllocator::AllocZeroed(long);
+public: virtual void BufferDefaultAllocator::DeAlloc(unsigned char *);
+};
+
+
+struct EnumSC {
+public: virtual int EnumSC::next(void);
+public: virtual void EnumSC::get(unsigned short *,unsigned short *,long *,long *,unsigned long *);
+public: virtual void EnumSC::getCrcs(unsigned long *,unsigned long *);
+public: virtual bool EnumSC::fUpdate(long,long);
+public: virtual int EnumSC::prev(void);
+public: virtual int EnumSC::clone(struct EnumContrib * *);
+public: virtual int EnumSC::locate(long,long);
+};
+
+struct Stream {
+public: virtual long Stream::QueryCb(void);
+public: virtual int Stream::Read(long,void *,long *);
+public: virtual int Stream::Write(long,void *,long);
+public: virtual int Stream::Replace(void *,long);
+public: virtual int Stream::Append(void *,long);
+public: virtual int Stream::Delete(void);
+public: virtual int Stream::Release(void);
+public: virtual int Stream::Read2(long,void *,long);
+public: virtual int Stream::Truncate(long);
+};
+
+struct EnumThunk {
+public: virtual void EnumThunk::release(void);
+public: virtual void EnumThunk::reset(void);
+public: virtual int EnumThunk::next(void);
+public: virtual void EnumThunk::get(unsigned short *,long *,long *);
+};
+
+struct EnumSyms {
+public: virtual void EnumSyms::release(void);
+public: virtual void EnumSyms::reset(void);
+public: virtual int EnumSyms::next(void);
+public: virtual void EnumSyms::get(unsigned char * *);
+public: virtual int EnumSyms::prev(void);
+public: virtual int EnumSyms::clone(struct EnumSyms * *);
+public: virtual int EnumSyms::locate(long,long);
+};
+
+struct EnumLines {
+public: virtual void EnumLines::release(void);
+public: virtual void EnumLines::reset(void);
+public: virtual int EnumLines::next(void);
+public: virtual bool EnumLines::getLines(unsigned long *,unsigned long *,unsigned short *,unsigned long *,unsigned long *,struct CV_Line_t *);
+public: virtual bool EnumLines::getLinesColumns(unsigned long *,unsigned long *,unsigned short *,unsigned long *,unsigned long *,struct CV_Line_t *,struct CV_Column_t *);
+public: virtual bool EnumLines::clone(struct EnumLines * *);
+};
+
+struct Dbg {
+public: virtual int Dbg::Close(void);
+public: virtual long Dbg::QuerySize(void);
+public: virtual void Dbg::Reset(void);
+public: virtual int Dbg::Skip(unsigned long);
+public: virtual int Dbg::QueryNext(unsigned long,void *);
+public: virtual int Dbg::Find(void *);
+public: virtual int Dbg::Clear(void);
+public: virtual int Dbg::Append(unsigned long,void const *);
+public: virtual int Dbg::ReplaceNext(unsigned long,void const *);
+public: virtual int Dbg::Clone(struct Dbg * *);
+public: virtual long Dbg::QueryElementSize(void);
+};
+
+struct EnumSrc {
+public: virtual void EnumSrc::release(void);
+public: virtual void EnumSrc::reset(void);
+public: virtual int EnumSrc::next(void);
+public: virtual void EnumSrc::get(struct SrcHeaderOut const * *);
+};
+
+struct MREDrv {
+public: virtual int MREDrv::FRelease(void);
+public: virtual int MREDrv::FRefreshFileSysInfo(void);
+public: virtual int MREDrv::FSuccessfulCompile(int,unsigned short const *,unsigned short const *);
+public: virtual enum YNM MREDrv::YnmFileOutOfDate(struct SRCTARG &);
+public: virtual int MREDrv::FFilesOutOfDate(struct CAList *);
+public: virtual int MREDrv::FUpdateTargetFile(unsigned short const *,enum TrgType);
+public: virtual void MREDrv::OneTimeInit(void);
+};
+
+struct MREngine {
+public: virtual int MREngine::FDelete(void);
+public: virtual int MREngine::FClose(int);
+public: virtual void MREngine::QueryPdbApi(struct PDB * &,struct NameMap * &);
+public: virtual void MREngine::_Reserved_was_QueryMreLog(void);
+public: virtual void MREngine::QueryMreDrv(struct MREDrv * &);
+public: virtual void MREngine::QueryMreCmp(struct MRECmp * &,struct TPI *);
+public: virtual void MREngine::QueryMreUtil(struct MREUtil * &);
+public: virtual int MREngine::FCommit(void);
+};
+
+struct MRECmp2 {
+public: virtual int MRECmp2::FRelease(void);
+public: virtual int MRECmp2::FOpenCompiland(struct MREFile * *,unsigned short const *,unsigned short const *);
+public: virtual int MRECmp2::FCloseCompiland(struct MREFile *,int);
+public: virtual int MRECmp2::FPushFile(struct MREFile * *,unsigned short const *,void *);
+public: virtual struct MREFile * MRECmp2::PmrefilePopFile(void);
+public: virtual int MRECmp::FStoreDepData(struct DepData *);
+public: virtual int MRECmp::FRestoreDepData(struct DepData *);
+public: virtual void MRECmp::structIsBoring(unsigned long);
+};
+
+//public: virtual void * Pool<16384>::AllocBytes(unsigned int);
+//public: virtual void EnumSyms::get(unsigned char * *);
+//public: virtual void * Pool<65536>::AllocBytes(unsigned int);
+//public: virtual void EnumSyms::get(unsigned char * *);
+
+typedef int __cdecl fnPDBOpen2W(unsigned short const *path,char const *mode,long *p,
+ unsigned short *ext,unsigned int flags,struct PDB **pPDB);
+
+struct PDB {
+public: static int __cdecl PDBCommon::Open2W(unsigned short const *path,char const *mode,long *p,unsigned short *ext,unsigned int flags,struct PDB **pPDB);
+
+public: virtual unsigned long PDB::QueryInterfaceVersion(void);
+public: virtual unsigned long PDB::QueryImplementationVersion(void);
+public: virtual long PDBCommon::QueryLastError(char * const);
+public: virtual char * PDB::QueryPDBName(char * const);
+public: virtual unsigned long PDB::QuerySignature(void);
+public: virtual unsigned long PDB::QueryAge(void);
+public: virtual int PDB::CreateDBI(char const *,struct DBI * *);
+public: virtual int PDB::OpenDBI(char const *,char const *,struct DBI * *);
+public: virtual int PDB::OpenTpi(char const *,struct TPI * *);
+public: virtual int PDB::Commit(void);
+public: virtual int PDB::Close(void);
+public: virtual int PDBCommon::OpenStreamW(unsigned short const *,struct Stream * *);
+public: virtual int PDB::GetEnumStreamNameMap(struct Enum * *);
+public: virtual int PDB::GetRawBytes(int (__cdecl*)(void const *,long));
+public: virtual unsigned long PDB::QueryPdbImplementationVersion(void);
+public: virtual int PDB::OpenDBIEx(char const *,char const *,struct DBI * *,int (__stdcall*)(struct _tagSEARCHDEBUGINFO *));
+public: virtual int PDBCommon::CopyTo(char const *,unsigned long,unsigned long);
+public: virtual int PDB::OpenSrc(struct Src * *);
+public: virtual long PDB::QueryLastErrorExW(unsigned short *,unsigned int);
+public: virtual unsigned short * PDB::QueryPDBNameExW(unsigned short *,unsigned int);
+public: virtual int PDB::QuerySignature2(struct _GUID *);
+public: virtual int PDBCommon::CopyToW(unsigned short const *,unsigned long,unsigned long);
+public: virtual int PDB::fIsSZPDB(void)const ;
+public: virtual int PDB::containsW(unsigned short const *,unsigned long *);
+public: virtual int PDB::CopyToW2(unsigned short const *,unsigned long,int (__cdecl*(__cdecl*)(void *,enum PCC))(void),void *);
+public: virtual int PDB::OpenStreamEx(char const *,char const *,struct Stream * *);
+};
+
+struct Src {
+public: virtual bool Src::Close(void);
+public: virtual bool SrcCommon::Add(struct SrcHeader const *,void const *);
+public: virtual bool Src::Remove(char const *);
+public: virtual bool SrcCommon::QueryByName(char const *,struct SrcHeaderOut *)const ;
+public: virtual bool Src::GetData(struct SrcHeaderOut const *,void *)const ;
+public: virtual bool Src::GetEnum(struct EnumSrc * *)const ;
+public: virtual bool Src::GetHeaderBlock(struct SrcHeaderBlock &)const ;
+public: virtual bool Src::RemoveW(unsigned short *);
+public: virtual bool Src::QueryByNameW(unsigned short *,struct SrcHeaderOut *)const ;
+public: virtual bool Src::AddW(struct SrcHeaderW const *,void const *);
+};
+
+#include "pshpack1.h"
+
+struct LineInfoEntry
+{
+ unsigned int offset;
+ unsigned short line;
+};
+
+struct LineInfo
+{
+ unsigned int cntEntries;
+ unsigned short unknown;
+ LineInfoEntry entries[1]; // first entry { 0, 0x7fff }
+};
+
+struct SymbolChunk
+{
+ unsigned int chunkType; // seen 0xf1 (symbols), f2(??) f3 (FPO), f4 (MD5?), f5 (NEWFPO)
+ unsigned int chunkSize; // 0x18a: size of compiler symbols
+
+ // symbol entries
+ // S_COMPILER_V4
+ // S_MSTOOL_V4
+};
+
+struct SymbolData
+{
+ unsigned int magic; // 4: version? sizeof header?
+ // followed by SymbolChunks
+};
+
+struct TypeChunk
+{
+ // see also codeview_type
+
+ unsigned short len;
+ unsigned short type;
+
+ union
+ {
+ struct _refpdb // type 0x1515
+ {
+ unsigned int md5[4];
+ unsigned int unknown;
+ unsigned pdbname[1];
+ } refpdb;
+ };
+};
+
+struct TypeData
+{
+ unsigned int magic; // 4: version? sizeof header?
+ // followed by TypeChunks
+};
+
+#include "poppack.h"
+
+struct Mod {
+public: virtual unsigned long Mod::QueryInterfaceVersion(void);
+public: virtual unsigned long Mod::QueryImplementationVersion(void);
+public: virtual int Mod::AddTypes(unsigned char *pTypeData,long cbTypeData);
+public: virtual int Mod::AddSymbols(unsigned char *pSymbolData,long cbSymbolData);
+public: virtual int Mod2::AddPublic(char const *,unsigned short,long); // forwards to AddPublic2(...,0)
+public: virtual int ModCommon::AddLines(char const *fname,unsigned short sec,long off,long size,long off2,unsigned short firstline,unsigned char *pLineInfo,long cbLineInfo); // forwards to AddLinesW
+public: virtual int Mod2::AddSecContrib(unsigned short sec,long off,long size,unsigned long secflags); // forwards to Mod2::AddSecContribEx(..., 0, 0)
+public: virtual int ModCommon::QueryCBName(long *);
+public: virtual int ModCommon::QueryName(char * const,long *);
+public: virtual int Mod::QuerySymbols(unsigned char *,long *);
+public: virtual int Mod::QueryLines(unsigned char *,long *);
+public: virtual int Mod2::SetPvClient(void *);
+public: virtual int Mod2::GetPvClient(void * *);
+public: virtual int Mod2::QueryFirstCodeSecContrib(unsigned short *,long *,long *,unsigned long *);
+public: virtual int Mod2::QueryImod(unsigned short *);
+public: virtual int Mod2::QueryDBI(struct DBI * *);
+public: virtual int Mod2::Close(void);
+public: virtual int ModCommon::QueryCBFile(long *);
+public: virtual int ModCommon::QueryFile(char * const,long *);
+public: virtual int Mod::QueryTpi(struct TPI * *);
+public: virtual int Mod2::AddSecContribEx(unsigned short sec,long off,long size,unsigned long secflags,unsigned long crc/*???*/,unsigned long);
+public: virtual int Mod::QueryItsm(unsigned short *);
+public: virtual int ModCommon::QuerySrcFile(char * const,long *);
+public: virtual int Mod::QuerySupportsEC(void);
+public: virtual int ModCommon::QueryPdbFile(char * const,long *);
+public: virtual int Mod::ReplaceLines(unsigned char *,long);
+public: virtual bool Mod::GetEnumLines(struct EnumLines * *);
+public: virtual bool Mod::QueryLineFlags(unsigned long *);
+public: virtual bool Mod::QueryFileNameInfo(unsigned long,unsigned short *,unsigned long *,unsigned long *,unsigned char *,unsigned long *);
+public: virtual int Mod::AddPublicW(unsigned short const *,unsigned short,long,unsigned long);
+public: virtual int Mod::AddLinesW(unsigned short const *fname,unsigned short sec,long off,long size,long off2,unsigned long firstline,unsigned char *plineInfo,long cbLineInfo);
+public: virtual int Mod::QueryNameW(unsigned short * const,long *);
+public: virtual int Mod::QueryFileW(unsigned short * const,long *);
+public: virtual int Mod::QuerySrcFileW(unsigned short * const,long *);
+public: virtual int Mod::QueryPdbFileW(unsigned short * const,long *);
+public: virtual int Mod2::AddPublic2(char const *name,unsigned short sec,long off,unsigned long type);
+public: virtual int Mod::InsertLines(unsigned char *,long);
+public: virtual int Mod::QueryLines2(long,unsigned char *,long *);
+};
+
+
+struct DBI {
+public: virtual unsigned long DBI::QueryImplementationVersion(void);
+public: virtual unsigned long DBI::QueryInterfaceVersion(void);
+public: virtual int DBICommon::OpenMod(char const *objName,char const *libName,struct Mod * *);
+public: virtual int DBI::DeleteMod(char const *);
+public: virtual int DBI2::QueryNextMod(struct Mod *,struct Mod * *);
+public: virtual int DBI::OpenGlobals(struct GSI * *);
+public: virtual int DBI::OpenPublics(struct GSI * *);
+public: virtual int DBI::AddSec(unsigned short sec,unsigned short flags,long offset,long cbseg);
+public: virtual int DBI2::QueryModFromAddr(unsigned short,long,struct Mod * *,unsigned short *,long *,long *);
+public: virtual int DBI::QuerySecMap(unsigned char *,long *);
+public: virtual int DBI::QueryFileInfo(unsigned char *,long *);
+public: virtual void DBI::DumpMods(void);
+public: virtual void DBI::DumpSecContribs(void);
+public: virtual void DBI::DumpSecMap(void);
+public: virtual int DBI2::Close(void);
+public: virtual int DBI::AddThunkMap(long *,unsigned int,long,struct SO *,unsigned int,unsigned short,long);
+public: virtual int DBI::AddPublic(char const *,unsigned short,long);
+public: virtual int DBI2::getEnumContrib(struct Enum * *);
+public: virtual int DBI::QueryTypeServer(unsigned char,struct TPI * *);
+public: virtual int DBI::QueryItsmForTi(unsigned long,unsigned char *);
+public: virtual int DBI::QueryNextItsm(unsigned char,unsigned char *);
+public: virtual int DBI::reinitialize(void); // returns 0
+public: virtual int DBI::SetLazyTypes(int);
+public: virtual int DBI::FindTypeServers(long *,char *);
+public: virtual void DBI::noop(void); // noop
+public: virtual int DBI::OpenDbg(enum DBGTYPE,struct Dbg * *);
+public: virtual int DBI::QueryDbgTypes(enum DBGTYPE *,long *);
+public: virtual int DBI::QueryAddrForSec(unsigned short *,long *,unsigned short,long,unsigned long,unsigned long);
+public: virtual int DBI::QuerySupportsEC(void);
+public: virtual int DBI2::QueryPdb(struct PDB * *);
+public: virtual int DBI::AddLinkInfo(struct LinkInfo *);
+public: virtual int DBI::QueryLinkInfo(struct LinkInfo *,long *);
+public: virtual unsigned long DBI::QueryAge(void)const ;
+public: virtual int DBI2::reinitialize2(void); // returns 0
+public: virtual void DBI::FlushTypeServers(void);
+public: virtual int DBICommon::QueryTypeServerByPdb(char const *,unsigned char *);
+public: virtual int DBI2::OpenModW(unsigned short const *objName,unsigned short const *libName,struct Mod * *);
+public: virtual int DBI::DeleteModW(unsigned short const *);
+public: virtual int DBI::AddPublicW(unsigned short const *name,unsigned short sec,long off,unsigned long type);
+public: virtual int DBI::QueryTypeServerByPdbW(unsigned short const *,unsigned char *);
+public: virtual int DBI::AddLinkInfoW(struct LinkInfoW *);
+public: virtual int DBI::AddPublic2(char const *name,unsigned short sec,long off,unsigned long type);
+public: virtual unsigned short DBI::QueryMachineType(void)const ;
+public: virtual void DBI::SetMachineType(unsigned short);
+public: virtual void DBI::RemoveDataForRva(unsigned long,unsigned long);
+public: virtual int DBI::FStripped(void);
+public: virtual int DBI2::QueryModFromAddr2(unsigned short,long,struct Mod * *,unsigned short *,long *,long *,unsigned long *);
+public: virtual int DBI::QueryNoOfMods(long *);
+public: virtual int DBI2::QueryMods(struct Mod * *,long);
+public: virtual int DBI2::QueryImodFromAddr(unsigned short,long,unsigned short *,unsigned short *,long *,long *,unsigned long *);
+public: virtual int DBI2::OpenModFromImod(unsigned short,struct Mod * *);
+public: virtual int DBI::QueryHeader2(long,unsigned char *,long *);
+public: virtual int DBI::FAddSourceMappingItem(unsigned short const *,unsigned short const *,unsigned long);
+public: virtual int DBI::FSetPfnNotePdbUsed(void *,void (__cdecl*)(void *,unsigned short const *,int,int));
+public: virtual int DBI::FCTypes(void);
+public: virtual int DBI::QueryFileInfo2(unsigned char *,long *);
+public: virtual int DBI::FSetPfnQueryCallback(void *,int (__cdecl*(__cdecl*)(void *,enum DOVC))(void));
+};
+
+struct StreamCached {
+public: virtual long StreamCached::QueryCb(void);
+public: virtual int StreamCached::Read(long,void *,long *);
+public: virtual int StreamCached::Write(long,void *,long);
+public: virtual int StreamCached::Replace(void *,long);
+public: virtual int StreamCached::Append(void *,long);
+public: virtual int StreamCached::Delete(void);
+public: virtual int StreamCached::Release(void);
+public: virtual int StreamCached::Read2(long,void *,long);
+public: virtual int StreamCached::Truncate(long);
+};
+
+struct GSI {
+public: virtual unsigned long GSI::QueryInterfaceVersion(void);
+public: virtual unsigned long GSI::QueryImplementationVersion(void);
+public: virtual unsigned char * GSI::NextSym(unsigned char *);
+public: virtual unsigned char * GSI::HashSymW(unsigned short const *,unsigned char *);
+public: virtual unsigned char * GSI2::NearestSym(unsigned short,long,long *);
+public: virtual int GSI::Close(void);
+public: virtual int GSI::getEnumThunk(unsigned short,long,struct EnumThunk * *);
+public: virtual int GSI::QueryTpi(struct TPI * *); // returns 0
+public: virtual int GSI::QueryTpi2(struct TPI * *); // returns 0
+public: virtual unsigned char * GSI2::HashSymW2(unsigned short const *,unsigned char *); // same as GSI2::HashSymW
+public: virtual int GSI::getEnumByAddr(struct EnumSyms * *);
+};
+
+struct TPI {
+public: virtual unsigned long TPI::QueryInterfaceVersion(void);
+public: virtual unsigned long TPI::QueryImplementationVersion(void);
+public: virtual int TPI::QueryTi16ForCVRecord(unsigned char *,unsigned short *);
+public: virtual int TPI::QueryCVRecordForTi16(unsigned short,unsigned char *,long *);
+public: virtual int TPI::QueryPbCVRecordForTi16(unsigned short,unsigned char * *);
+public: virtual unsigned short TPI::QueryTi16Min(void);
+public: virtual unsigned short TPI::QueryTi16Mac(void);
+public: virtual long TPI::QueryCb(void);
+public: virtual int TPI::Close(void);
+public: virtual int TPI::Commit(void);
+public: virtual int TPI::QueryTi16ForUDT(char const *,int,unsigned short *);
+public: virtual int TPI::SupportQueryTiForUDT(void);
+public: virtual int TPI::fIs16bitTypePool(void);
+public: virtual int TPI::QueryTiForUDT(char const *,int,unsigned long *);
+public: virtual int TPI2::QueryTiForCVRecord(unsigned char *,unsigned long *);
+public: virtual int TPI2::QueryCVRecordForTi(unsigned long,unsigned char *,long *);
+public: virtual int TPI2::QueryPbCVRecordForTi(unsigned long,unsigned char * *);
+public: virtual unsigned long TPI::QueryTiMin(void);
+public: virtual unsigned long TPI::QueryTiMac(void);
+public: virtual int TPI::AreTypesEqual(unsigned long,unsigned long);
+public: virtual int TPI2::IsTypeServed(unsigned long);
+public: virtual int TPI::QueryTiForUDTW(unsigned short const *,int,unsigned long *);
+};
+
+
+struct NameMap {
+public: virtual int NameMap::close(void);
+public: virtual int NameMap2::reinitialize(void);
+public: virtual int NameMap2::getNi(char const *,unsigned long *);
+public: virtual int NameMap2::getName(unsigned long,char const * *);
+public: virtual int NameMap2::getEnumNameMap(struct Enum * *);
+public: virtual int NameMap2::contains(char const *,unsigned long *);
+public: virtual int NameMap::commit(void);
+public: virtual int NameMap2::isValidNi(unsigned long);
+public: virtual int NameMap2::getNiW(unsigned short const *,unsigned long *);
+public: virtual int NameMap2::getNameW(unsigned long,unsigned short *,unsigned int *);
+public: virtual int NameMap2::containsW(unsigned short const *,unsigned long *);
+public: virtual int NameMap2::containsUTF8(char const *,unsigned long *);
+public: virtual int NameMap2::getNiUTF8(char const *,unsigned long *);
+public: virtual int NameMap2::getNameA(unsigned long,char const * *);
+public: virtual int NameMap2::getNameW2(unsigned long,unsigned short const * *);
+};
+
+struct EnumNameMap {
+public: virtual void EnumNameMap::release(void);
+public: virtual void EnumNameMap::reset(void);
+public: virtual int EnumNameMap::next(void);
+public: virtual void EnumNameMap2::get(char const * *,unsigned long *);
+};
+
+struct EnumNameMap_Special {
+public: virtual void EnumNameMap_Special::release(void);
+public: virtual void EnumNameMap_Special::reset(void);
+public: virtual int EnumNameMap_Special::next(void);
+public: virtual void EnumNameMap_Special::get(char const * *,unsigned long *);
+};
+
+} // namespace mspdb
+
+bool initMsPdb();
+bool exitMsPdb();
+
+mspdb::PDB* CreatePDB(wchar_t* pdbname);
+
+extern char* mspdb_dll;
+
+#endif // __MSPDB_H__
diff --git a/src/symutil.cpp b/src/symutil.cpp
new file mode 100644
index 0000000..6f5e42f
--- /dev/null
+++ b/src/symutil.cpp
@@ -0,0 +1,152 @@
+// Convert DMD CodeView debug information to PDB files
+// Copyright (c) 2009 by Rainer Schuetze, All Rights Reserved
+//
+// License for redistribution is given by the Artistic License 2.0
+// see file LICENSE for further details
+
+#include "symutil.h"
+#include "demangle.h"
+
+extern "C" {
+#include "mscvpdb.h"
+}
+
+#include <assert.h>
+
+char dotReplacementChar = '@';
+
+int dsym2c(const BYTE* p, BYTE len, char* cname, int maxclen)
+{
+ int zlen, zpos, cpos = 0;
+
+ // decompress symbol
+ while (len-- > 0)
+ {
+ int ch = *p++;
+ if (ch == 0x80)
+ {
+ if (len-- <= 0)
+ break;
+ zlen = *p++ & 0x7f;
+ if (len-- <= 0)
+ break;
+ zpos = *p++ & 0x7f;
+ if (zpos > cpos)
+ break;
+ for(int z = 0; z < zlen; z++)
+ cname[cpos + z] = cname[cpos - zpos + z];
+ cpos += zlen;
+ break;
+ }
+ else if (ch > 0x80)
+ {
+ zlen = (ch & 0x7) + 1;
+ zpos = ((ch >> 3) & 0xf) - 7; // + zlen;
+ for(int z = 0; z < zlen; z++)
+ cname[cpos + z] = cname[cpos - zpos + z];
+ cpos += zlen;
+ }
+ else
+ cname[cpos++] = ch;
+ }
+
+ cname[cpos] = 0;
+ if (cname[0] == '_' && cname[1] == 'D' && isdigit(cname[2]))
+ d_demangle(cname, cname, maxclen, true);
+
+#if 1
+ for(int i = 0; i < cpos; i++)
+ if (cname[i] == '.')
+ cname[i] = dotReplacementChar;
+#endif
+
+ return cpos;
+}
+
+char* p2c(const BYTE* p, int idx)
+{
+ static char cname[4][2560];
+ int len = *p++;
+
+#if 1
+ memcpy(cname[idx], p, len);
+ cname[idx][len] = 0;
+#else
+ dsym2c(p, len, cname[idx], 2560);
+#endif
+ return cname[idx];
+}
+
+char* p2c(const p_string& p, int idx)
+{
+ return p2c(&p.namelen, idx);
+}
+
+int p2ccpy(char* p, const BYTE* s)
+{
+ memcpy(p, s + 1, *s);
+ p[*s] = 0;
+ return *s + 1;
+}
+
+int pstrcpy(BYTE* p, const BYTE* s)
+{
+ int len = *p = *s;
+ for(int i = 1; i <= len; i++)
+ if (s[i] == '.')
+ {
+ //p[i++] = ':';
+ p[i] = dotReplacementChar;
+ }
+ else
+ p[i] = s[i];
+ return len + 1; // *(BYTE*) memcpy (p, s, *s + 1) + 1;
+}
+
+int pstrcpy(p_string& p, const p_string& s)
+{
+ return *(BYTE*) memcpy (&p, &s, s.namelen + 1) + 1;
+}
+
+int pstrcmp(const BYTE* p1, const BYTE* p2)
+{
+ if (*p1 != *p2)
+ return *p2 - *p1;
+ return memcmp(p1 + 1, p2 + 1, *p1);
+}
+
+bool p2ccmp(const BYTE* pp, const char* cp)
+{
+ int len = strlen(cp);
+ if (len != *pp)
+ return false;
+ return memcmp(pp + 1, cp, len) == 0;
+}
+bool p2ccmp(const p_string& pp, const char* cp)
+{
+ return p2ccmp(&pp.namelen, cp);
+}
+
+int pstrcpy_v(bool v3, BYTE* d, const BYTE* s)
+{
+ if (!v3)
+ return pstrcpy(d, s);
+
+ int len = *s++;
+ int clen = dsym2c(s, len, (char*) d, 1000) + 1;
+
+ return clen;
+}
+
+int cstrcpy_v(bool v3, BYTE* d, const char* s)
+{
+ int len = strlen(s);
+ if(!v3)
+ *d++ = len;
+ else
+ assert(len < 256);
+
+ memcpy(d, s, len + 1);
+ return len + 1;
+}
+
diff --git a/src/symutil.h b/src/symutil.h
new file mode 100644
index 0000000..a055a7a
--- /dev/null
+++ b/src/symutil.h
@@ -0,0 +1,29 @@
+// Convert DMD CodeView debug information to PDB files
+// Copyright (c) 2009 by Rainer Schuetze, All Rights Reserved
+//
+// License for redistribution is given by the Artistic License 2.0
+// see file LICENSE for further details
+
+#ifndef __SYMUTIL_H__
+#define __SYMUTIL_H__
+
+#include <windows.h>
+
+struct p_string;
+
+int dsym2c(const BYTE* p, BYTE len, char* cname, int maxclen);
+
+char* p2c(const BYTE* p, int idx = 0);
+char* p2c(const p_string& p, int idx = 0);
+int p2ccpy(char* p, const BYTE* s);
+int pstrcpy(BYTE* p, const BYTE* s);
+int pstrcpy(p_string& p, const p_string& s);
+int pstrcmp(const BYTE* p1, const BYTE* p2);
+bool p2ccmp(const BYTE* pp, const char* cp);
+bool p2ccmp(const p_string& pp, const char* cp);
+int pstrcpy_v(bool v3, BYTE* d, const BYTE* s);
+int cstrcpy_v(bool v3, BYTE* d, const char* s);
+
+extern char dotReplacementChar;
+
+#endif //__SYMUTIL_H__ \ No newline at end of file