diff options
author | sagitario <sagitario@fc51e93f-b9fe-4711-8d8d-3ae870c5f7d8> | 2009-05-08 15:54:32 (GMT) |
---|---|---|
committer | sagitario <sagitario@fc51e93f-b9fe-4711-8d8d-3ae870c5f7d8> | 2009-05-08 15:54:32 (GMT) |
commit | d3adcbbc0c51ab693e7fcbd95569ffd548128d02 (patch) | |
tree | 2d821e16fcb0b09ae7c43629366499bd1a4dc33a /src | |
download | cv2pdb-d3adcbbc0c51ab693e7fcbd95569ffd548128d02.zip cv2pdb-d3adcbbc0c51ab693e7fcbd95569ffd548128d02.tar.gz cv2pdb-d3adcbbc0c51ab693e7fcbd95569ffd548128d02.tar.bz2 |
Diffstat (limited to 'src')
-rw-r--r-- | src/LastError.h | 24 | ||||
-rw-r--r-- | src/PEImage.cpp | 238 | ||||
-rw-r--r-- | src/PEImage.h | 86 | ||||
-rw-r--r-- | src/cv2pdb.cpp | 2000 | ||||
-rw-r--r-- | src/cv2pdb.h | 148 | ||||
-rw-r--r-- | src/cv2pdb.sln | 20 | ||||
-rw-r--r-- | src/cv2pdb.vcproj | 232 | ||||
-rw-r--r-- | src/demangle.cpp | 493 | ||||
-rw-r--r-- | src/demangle.h | 12 | ||||
-rw-r--r-- | src/main.cpp | 165 | ||||
-rw-r--r-- | src/mscvpdb.h | 2083 | ||||
-rw-r--r-- | src/mspdb.cpp | 91 | ||||
-rw-r--r-- | src/mspdb.h | 494 | ||||
-rw-r--r-- | src/symutil.cpp | 152 | ||||
-rw-r--r-- | src/symutil.h | 29 |
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 |