summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGES13
-rw-r--r--TODO1
-rw-r--r--VERSION2
-rw-r--r--autoexp.visualizer16
-rw-r--r--src/PEImage.cpp10
-rw-r--r--src/cv2pdb.cpp568
-rw-r--r--src/cv2pdb.h49
-rw-r--r--src/cv2pdb.sln3
-rw-r--r--src/cv2pdb.vcproj8
-rw-r--r--src/cvutil.cpp169
-rw-r--r--src/cvutil.h51
-rw-r--r--src/demangle.cpp26
-rw-r--r--src/main.cpp3
-rw-r--r--src/symutil.cpp91
-rw-r--r--src/symutil.h5
-rw-r--r--test/cvtest.d54
16 files changed, 904 insertions, 165 deletions
diff --git a/CHANGES b/CHANGES
index 83259ab..1cf36d1 100644
--- a/CHANGES
+++ b/CHANGES
@@ -106,3 +106,16 @@ Version history
translated back to the correct types if command option -C is used
* now adding properties "has nested type" and "is nested type" to class/struct/union/enum types
* better support for enumerators: now added as user defined types (DMD patch needed)
+
+2010-08-08 Version 0.15
+
+ * thanks to patches by Z3N, the resulting pdb is now usable by more debuggers
+ * now uses shared file access to executable
+ * incomplete structs/classes are now added as user defined types to avoid confusing
+ debugger for following symbols
+ * fixed name demangling of very long names
+ * added name demangling support for @safe/@trusted/@property/pure/nothrow/ref
+ * base classes are added to D/cpp-interfaces to allow viewing the virtual function
+ table pointer
+ * structs, classes and interfaces now have an internal qualifier attached that allows
+ the preview in autoexp.dat to show better info for structs and interfaces
diff --git a/TODO b/TODO
index ae2c7c8..979f607 100644
--- a/TODO
+++ b/TODO
@@ -24,6 +24,5 @@ in the future, but not all have a known solution.
* assoc_array.length cannot be displayed (it is assoc_array.a->nodes)
* enum values not displayed
* watch incorrect if same variable name used in different parts of a function
-* rtti display: disable for structs
* line number in templates sometimes off by 1 or 2
* call to other function jumps to called function while pushing default arguments
diff --git a/VERSION b/VERSION
index 0f273a4..d44ad2b 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-VERSION = 0.14
+VERSION = 0.15
diff --git a/autoexp.visualizer b/autoexp.visualizer
index ea62187..46b2d1c 100644
--- a/autoexp.visualizer
+++ b/autoexp.visualizer
@@ -217,14 +217,26 @@ internal@aaA<*,*> {
)
}
-; display null references for class objects
+; display null references and class name for class objects
*@* {
preview(
#(
#if (&$e == 0) ( "null" )
- #else (
+ #elif ($e.__classtype == 1) ( ;;; classes
#( "[", [$e.__viewhelper], "] ", [$e,!] )
)
+ #elif ($e.__classtype == 2) ( ;;; DInterface
+ #( "[D-Interface ", [**(object_viewhelper**)&$e], "] " )
+ )
+ #elif ($e.__classtype == 3) ( ;;; CppInterface
+ #( "[C++Interface]")
+ )
+ #elif ($e.__classtype == 4) ( ;;; Struct
+ #( [$e,!] )
+ )
+ #elif (1) (
+ #( [$e,!] )
+ )
)
)
}
diff --git a/src/PEImage.cpp b/src/PEImage.cpp
index 2a3cbc0..bc996a7 100644
--- a/src/PEImage.cpp
+++ b/src/PEImage.cpp
@@ -15,6 +15,7 @@ extern "C" {
#include <fcntl.h>
#include <ctype.h>
#include <direct.h>
+#include <share.h>
#include <sys/stat.h>
///////////////////////////////////////////////////////////////////////
@@ -42,7 +43,7 @@ bool PEImage::load(const char* iname)
if (fd != -1)
return setError("file already open");
- fd = open(iname, O_RDONLY | O_BINARY);
+ fd = sopen(iname, O_RDONLY | O_BINARY, SH_DENYWR);
if (fd == -1)
return setError("Can't open file");
@@ -156,9 +157,14 @@ bool PEImage::replaceDebugSection (const void* data, int datalen)
memcpy(dbgDir, &debugdir, sizeof(debugdir));
dbgDir->PointerToRawData = sec[s].PointerToRawData;
+#if 0
dbgDir->AddressOfRawData = sec[s].PointerToRawData;
dbgDir->SizeOfData = sec[s].SizeOfRawData;
-
+#else // suggested by Z3N
+ dbgDir->AddressOfRawData = sec[s].VirtualAddress;
+ dbgDir->SizeOfData = sec[s].SizeOfRawData - sizeof(IMAGE_DEBUG_DIRECTORY);
+#endif
+
free_aligned(dump_base);
dump_base = newdata;
dump_total_len += fill + xdatalen;
diff --git a/src/cv2pdb.cpp b/src/cv2pdb.cpp
index 3d50c93..27fbb28 100644
--- a/src/cv2pdb.cpp
+++ b/src/cv2pdb.cpp
@@ -7,6 +7,7 @@
#include "cv2pdb.h"
#include "PEImage.h"
#include "symutil.h"
+#include "cvutil.h"
#include <stdio.h>
#include <direct.h>
@@ -14,17 +15,6 @@
#define REMOVE_LF_DERIVED 1 // types wrong by DMD
#define PRINT_INTERFACEVERSON 0
-// class properties (also apply to struct,union and enum)
-static const int kPropPacked = 0x01;
-static const int kPropHasCtorDtor = 0x02;
-static const int kPropHasOverOps = 0x04;
-static const int kPropIsNested = 0x08;
-static const int kPropHasNested = 0x10;
-static const int kPropHasOverAsgn = 0x20;
-static const int kPropHasCasting = 0x40;
-static const int kPropIncomplete = 0x80;
-static const int kPropScoped = 0x100;
-
CV2PDB::CV2PDB(PEImage& image)
: img(image), pdb(0), dbi(0), libraries(0), rsds(0), modules(0), globmod(0)
, segMap(0), segMapDesc(0), segFrame2Index(0), globalTypeHeader(0)
@@ -33,13 +23,16 @@ CV2PDB::CV2PDB(PEImage& image)
, globalSymbols(0), cbGlobalSymbols(0), staticSymbols(0), cbStaticSymbols(0)
, udtSymbols(0), cbUdtSymbols(0), allocUdtSymbols(0)
, srcLineStart(0), srcLineSections(0)
-, pointerTypes(0), objectType(0)
+, pointerTypes(0)
, Dversion(2)
+, classEnumType(0), ifaceEnumType(0), cppIfaceEnumType(0), structEnumType(0)
+, classBaseType(0), ifaceBaseType(0), cppIfaceBaseType(0), structBaseType(0)
{
memset(typedefs, 0, sizeof(typedefs));
memset(translatedTypedefs, 0, sizeof(translatedTypedefs));
cntTypedefs = 0;
+ addClassTypeEnum = true;
useGlobalMod = true;
thisIsNotRef = true;
v3 = true;
@@ -114,9 +107,7 @@ bool CV2PDB::cleanup(bool commit)
segMap = 0;
segMapDesc = 0;
globalTypeHeader = 0;
- objectType = 0;
pointerTypes = 0;
- objectType = 0;
memset(typedefs, 0, sizeof(typedefs));
memset(translatedTypedefs, 0, sizeof(translatedTypedefs));
cntTypedefs = 0;
@@ -303,74 +294,9 @@ bool CV2PDB::initSegMap()
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;
- }
+ int length = ::numeric_leaf(value, leaf);
+ if(length == 0)
+ setError("unsupported numeric leaf");
return length;
}
@@ -402,6 +328,7 @@ int CV2PDB::_doFields(int cmd, codeview_reftype* dfieldlist, const codeview_reft
int pos = 0, dpos = 0;
int leaf_len, value;
int nested_types = 0;
+ int base_classes = 0;
int test_nested_type = (cmd == kCmdNestedTypes ? arg : 0);
int cntFields = 0;
@@ -482,6 +409,7 @@ int CV2PDB::_doFields(int cmd, codeview_reftype* dfieldlist, const codeview_reft
break;
case LF_BCLASS_V1:
+ base_classes++;
if (dp)
{
dfieldtype->bclass_v2.id = LF_BCLASS_V2;
@@ -515,6 +443,7 @@ int CV2PDB::_doFields(int cmd, codeview_reftype* dfieldlist, const codeview_reft
break;
case LF_BCLASS_V2:
+ base_classes++;
leaf_len = numeric_leaf(&value, &fieldtype->bclass_v2.offset);
copylen = sizeof(dfieldtype->bclass_v2) - 2 + leaf_len;
break;
@@ -532,6 +461,17 @@ int CV2PDB::_doFields(int cmd, codeview_reftype* dfieldlist, const codeview_reft
copy_p2dsym(dp, dpos, p, pos, maxdlen);
else
copylen = fieldtype->method_v1.p_name.namelen + 1;
+
+ if(cmd == kCmdOffsetFirstVirtualMethod)
+ if(const codeview_type* cvtype = getTypeData(fieldtype->method_v1.mlist))
+ if(cvtype->common.id == LF_METHODLIST_V1 && cvtype->common.len > 2)
+ {
+ // just check the first entry
+ const unsigned short *pattr = (const unsigned short*)(&cvtype->common + 1);
+ int mode =(*pattr >> 2) & 7;
+ if(mode == 4 || mode == 6)
+ return *(const unsigned*)(&pattr[2]);
+ }
break;
case LF_METHOD_V2:
@@ -584,6 +524,8 @@ int CV2PDB::_doFields(int cmd, codeview_reftype* dfieldlist, const codeview_reft
copylen = fieldtype->nesttype_v1.p_name.namelen + 1;
if(test_nested_type == 0 || test_nested_type == fieldtype->nesttype_v1.type)
nested_types++;
+ if(cmd == kCmdHasClassTypeEnum && p2ccmp(fieldtype->nesttype_v1.p_name, CLASSTYPEENUM_TYPE))
+ return true;
break;
case LF_NESTTYPE_V2:
@@ -591,6 +533,8 @@ int CV2PDB::_doFields(int cmd, codeview_reftype* dfieldlist, const codeview_reft
copylen += fieldtype->nesttype_v2.p_name.namelen + 1;
if(test_nested_type == 0 || test_nested_type == fieldtype->nesttype_v1.type)
nested_types++;
+ if(cmd == kCmdHasClassTypeEnum && p2ccmp(fieldtype->nesttype_v2.p_name, CLASSTYPEENUM_TYPE))
+ return true;
break;
case LF_NESTTYPE_V3:
@@ -598,6 +542,8 @@ int CV2PDB::_doFields(int cmd, codeview_reftype* dfieldlist, const codeview_reft
copylen += strlen(fieldtype->nesttype_v3.name) + 1;
if(test_nested_type == 0 || test_nested_type == fieldtype->nesttype_v1.type)
nested_types++;
+ if(cmd == kCmdHasClassTypeEnum && strcmp(fieldtype->nesttype_v3.name, CLASSTYPEENUM_TYPE) == 0)
+ return true;
break;
case LF_VFUNCTAB_V1:
@@ -640,6 +586,7 @@ int CV2PDB::_doFields(int cmd, codeview_reftype* dfieldlist, const codeview_reft
// necessary to convert this info? no data associated with it, so it might not be used
case LF_VBCLASS_V1:
case LF_IVBCLASS_V1:
+ base_classes++;
if (dp)
{
dfieldtype->vbclass_v2.id = fieldtype->common.id == LF_VBCLASS_V1 ? LF_VBCLASS_V2 : LF_IVBCLASS_V2;
@@ -656,6 +603,7 @@ int CV2PDB::_doFields(int cmd, codeview_reftype* dfieldlist, const codeview_reft
case LF_VBCLASS_V2:
case LF_IVBCLASS_V2:
+ base_classes++;
leaf_len = numeric_leaf(&value, &fieldtype->vbclass_v2.vbpoff);
leaf_len += numeric_leaf(&value, (char*) &fieldtype->vbclass_v2.vbpoff + leaf_len);
copylen = sizeof(fieldtype->vbclass_v2) - sizeof(fieldtype->vbclass_v2.vbpoff) + leaf_len;
@@ -685,6 +633,12 @@ int CV2PDB::_doFields(int cmd, codeview_reftype* dfieldlist, const codeview_reft
return cntFields;
case kCmdNestedTypes:
return nested_types;
+ case kCmdCountBaseClasses:
+ return base_classes;
+ case kCmdOffsetFirstVirtualMethod:
+ return -1;
+ case kCmdHasClassTypeEnum:
+ return false;
}
return setError("_doFields: unknown command");
@@ -737,6 +691,24 @@ int CV2PDB::addStruct(codeview_type* dtype, int n_element, int fieldlist, int pr
return addAggregate(dtype, false, n_element, fieldlist, property, derived, vshape, structlen, name);
}
+int CV2PDB::addEnum(codeview_type* dtype, int count, int fieldlist, int property,
+ int type, const char*name)
+{
+ dtype->enumeration_v2.id = (v3 ? LF_ENUM_V3 : LF_ENUM_V2);
+ dtype->enumeration_v2.count = count;
+ dtype->enumeration_v2.fieldlist = fieldlist;
+ dtype->enumeration_v2.property = property;
+ dtype->enumeration_v2.type = type;
+ int len = cstrcpy_v(v3, (BYTE*)(&dtype->enumeration_v2.p_name), name);
+ len += sizeof (dtype->enumeration_v2) - sizeof(dtype->enumeration_v2.p_name);
+
+ unsigned char* p = (unsigned char*) dtype;
+ for (; len & 3; len++)
+ p[len] = 0xf4 - (len & 3);
+ dtype->enumeration_v2.len = len - 2;
+ return len;
+}
+
int CV2PDB::addPointerType(codeview_type* dtype, int type, int attr)
{
dtype->pointer_v2.id = LF_POINTER_V2;
@@ -793,6 +765,21 @@ int CV2PDB::addFieldNestedType(codeview_fieldtype* dfieldtype, int type, const c
return len;
}
+int CV2PDB::addFieldEnumerate(codeview_fieldtype* dfieldtype, const char* name, int val)
+{
+ dfieldtype->enumerate_v1.id = v3 ? LF_ENUMERATE_V3 : LF_ENUMERATE_V1;
+ dfieldtype->enumerate_v1.attribute = 0;
+ //assert(val < LF_NUMERIC);
+ dfieldtype->enumerate_v1.value = val;
+ int len = cstrcpy_v(v3, (BYTE*)(&dfieldtype->enumerate_v1 + 1), name);
+ len += sizeof (dfieldtype->enumerate_v1);
+
+ 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)
@@ -802,6 +789,25 @@ void CV2PDB::checkUserTypeAlloc(int size, int add)
}
}
+void CV2PDB::writeUserTypeLen(codeview_type* type, int len)
+{
+ unsigned char* p = (unsigned char*) type;
+ for (; len & 3; len++)
+ p[len] = 0xf4 - (len & 3);
+
+ type->common.len = len - 2;
+ cbUserTypes += len;
+}
+
+void CV2PDB::checkGlobalTypeAlloc(int size, int add)
+{
+ if (cbGlobalTypes + size > allocGlobalTypes)
+ {
+ allocGlobalTypes += size + add;
+ globalTypes = (unsigned char*) realloc(globalTypes, allocGlobalTypes);
+ }
+}
+
const codeview_type* CV2PDB::getTypeData(int type)
{
if (!globalTypeHeader)
@@ -824,7 +830,7 @@ const codeview_type* CV2PDB::getUserTypeData(int type)
return 0;
int pos = 0;
- while(type > 0)
+ while(type > 0 && pos < cbUserTypes)
{
const codeview_type* ptype = (codeview_type*)(userTypes + pos);
int len = ptype->common.len + 2;
@@ -834,30 +840,60 @@ const codeview_type* CV2PDB::getUserTypeData(int type)
return (codeview_type*)(userTypes + pos);
}
-const codeview_type* CV2PDB::findCompleteClassType(const codeview_type* cvtype)
+const codeview_type* CV2PDB::getConvertedTypeData(int type)
{
- if (!globalTypeHeader)
+ type -= 0x1000;
+ if (type < 0 || type >= nextUserType - 0x1000)
return 0;
- int value;
- int cvleaf_len = numeric_leaf(&value, &cvtype->struct_v1.structlen);
+ int pos = 4;
+ while(type > 0 && pos < cbGlobalTypes)
+ {
+ const codeview_type* ptype = (codeview_type*)(globalTypes + pos);
+ int len = ptype->common.len + 2;
+ pos += len;
+ type--;
+ }
+ return (codeview_type*)(globalTypes + pos);
+}
- DWORD* offset = (DWORD*)(globalTypeHeader + 1);
- BYTE* typeData = (BYTE*)(offset + globalTypeHeader->cTypes);
- for (unsigned int t = 0; t < globalTypeHeader->cTypes; t++)
+const codeview_type* CV2PDB::findCompleteClassType(const codeview_type* cvtype, int* ptype)
+{
+ bool cstr;
+ const BYTE* pname = getStructName(cvtype, cstr);
+ if(!pname)
+ return 0;
+
+ if(globalTypeHeader)
{
- const codeview_type* type = (const codeview_type*)(typeData + offset[t]);
- if (type->common.id == LF_CLASS_V1 || type->common.id == LF_STRUCTURE_V1)
+ DWORD* offset = (DWORD*)(globalTypeHeader + 1);
+ BYTE* typeData = (BYTE*)(offset + globalTypeHeader->cTypes);
+ for (unsigned int t = 0; t < globalTypeHeader->cTypes; t++)
{
- if (!(type->struct_v1.property & kPropIncomplete))
+ const codeview_type* type = (const codeview_type*)(typeData + offset[t]);
+ if (isCompleteStruct(type, pname, cstr))
{
- 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;
+ if(ptype)
+ *ptype = t;
+ return type;
}
}
}
+ if(userTypes)
+ {
+ int t = globalTypeHeader->cTypes;
+ for(int pos = 0; pos < cbUserTypes; t++)
+ {
+ const codeview_type* type = (codeview_type*)(userTypes + pos);
+ if (isCompleteStruct(type, pname, cstr))
+ {
+ if(ptype)
+ *ptype = t;
+ return type;
+ }
+ pos += type->common.len + 2;
+ }
+ }
return cvtype;
}
@@ -919,7 +955,7 @@ int CV2PDB::fixProperty(int type, int prop, int fieldType)
int CV2PDB::sizeofClassType(const codeview_type* cvtype)
{
- if (cvtype->struct_v1.property & kPropIncomplete)
+ if (getStructProperty(cvtype) & kPropIncomplete)
cvtype = findCompleteClassType(cvtype);
int value;
@@ -1371,7 +1407,7 @@ const char* CV2PDB::appendDynamicArray(int indexType, int elemType)
char helpertype[64];
strcat(strcpy(helpertype, name), "_viewhelper");
dtype = (codeview_type*) (userTypes + cbUserTypes);
- cbUserTypes += addClass(dtype, 0, helpfieldlistType, 0, 0, 0, 0, helpertype);
+ cbUserTypes += addClass(dtype, 0, helpfieldlistType, 0, 0, 0, 4, helpertype);
dstringType = nextUserType++;
addUdtSymbol(dstringType, helpertype);
}
@@ -1609,7 +1645,7 @@ const char* CV2PDB::appendDelegate(int thisType, int funcType)
return name;
}
-int CV2PDB::appendObjectType (int object_derived_type)
+int CV2PDB::appendObjectType (int object_type, int enumType, const char* classSymbol)
{
checkUserTypeAlloc();
@@ -1618,7 +1654,7 @@ int CV2PDB::appendObjectType (int object_derived_type)
codeview_type* dtype;
int viewHelperType = 0;
- bool addViewHelper = true;
+ bool addViewHelper = object_type == kClassTypeObject;
if(addViewHelper)
{
rdtype = (codeview_reftype*) (userTypes + cbUserTypes);
@@ -1664,18 +1700,23 @@ int CV2PDB::appendObjectType (int object_derived_type)
rdtype->fieldlist.len += addFieldMember(dfieldtype, 1, 0, viewHelperType, "__viewhelper");
numElem++;
}
+ if(addClassTypeEnum)
+ {
+ dfieldtype = (codeview_fieldtype*)(rdtype->fieldlist.list + rdtype->fieldlist.len - 2);
+ rdtype->fieldlist.len += addFieldNestedType(dfieldtype, enumType, CLASSTYPEENUM_TYPE);
+ numElem++;
+ }
cbUserTypes += rdtype->common.len + 2;
int fieldListType = nextUserType++;
-#define OBJECT_SYMBOL "object@Object"
-
dtype = (codeview_type*) (userTypes + cbUserTypes);
- cbUserTypes += addClass(dtype, numElem, fieldListType, 0, object_derived_type, vtableType, 4, OBJECT_SYMBOL);
- objectType = nextUserType++;
+ int prop = addClassTypeEnum ? kPropHasNested : 0;
+ cbUserTypes += addClass(dtype, numElem, fieldListType, prop, 0, vtableType, 4, classSymbol);
+ int objType = nextUserType++;
- addUdtSymbol(objectType, OBJECT_SYMBOL);
- return objectType;
+ addUdtSymbol(objType, classSymbol);
+ return objType;
}
int CV2PDB::appendPointerType(int pointedType, int attr)
@@ -1727,6 +1768,124 @@ int CV2PDB::appendComplex(int cplxtype, int basetype, int elemsize, const char*
return classType;
}
+int CV2PDB::appendEnumerator(const char* typeName, const char* enumName, int enumValue, int prop)
+{
+ codeview_reftype* rdtype;
+ codeview_type* dtype;
+
+ checkUserTypeAlloc();
+
+ // nextUserType: field list (size, array)
+ rdtype = (codeview_reftype*) (userTypes + cbUserTypes);
+ rdtype->fieldlist.id = LF_FIELDLIST_V2;
+
+ // member type re
+ codeview_fieldtype* dfieldtype = (codeview_fieldtype*)rdtype->fieldlist.list;
+ int len1 = addFieldEnumerate(dfieldtype, enumName, enumValue);
+
+ rdtype->fieldlist.len = len1 + 2;
+ cbUserTypes += rdtype->fieldlist.len + 2;
+ int fieldlistType = nextUserType++;
+
+ dtype = (codeview_type*) (userTypes + cbUserTypes);
+ cbUserTypes += addEnum(dtype, 1, fieldlistType, prop, 0x74, typeName);
+ int enumType = nextUserType++;
+
+ addUdtSymbol(enumType, typeName);
+ return enumType;
+}
+
+int CV2PDB::getBaseClass(const codeview_type* cvtype)
+{
+ if (getStructProperty(cvtype) & kPropIncomplete)
+ cvtype = findCompleteClassType(cvtype);
+
+ const codeview_reftype* fieldlist = (const codeview_reftype*) getConvertedTypeData(getStructFieldlist(cvtype));
+ if(!fieldlist || (fieldlist->common.id != LF_FIELDLIST_V1 && fieldlist->common.id != LF_FIELDLIST_V2))
+ return 0;
+
+ codeview_fieldtype* fieldtype = (codeview_fieldtype*)(fieldlist->fieldlist.list);
+ if(fieldtype->common.id == LF_BCLASS_V1)
+ return fieldtype->bclass_v1.type;
+ if(fieldtype->common.id == LF_BCLASS_V2)
+ return fieldtype->bclass_v2.type;
+ return 0;
+}
+
+int CV2PDB::countBaseClasses(const codeview_type* cvtype)
+{
+ if (getStructProperty(cvtype) & kPropIncomplete)
+ cvtype = findCompleteClassType(cvtype);
+
+ const codeview_reftype* fieldlist = (const codeview_reftype*) getConvertedTypeData(getStructFieldlist(cvtype));
+ if(!fieldlist || (fieldlist->common.id != LF_FIELDLIST_V1 && fieldlist->common.id != LF_FIELDLIST_V2))
+ return 0;
+
+ return _doFields(kCmdCountBaseClasses, 0, fieldlist, 0);
+}
+
+bool CV2PDB::derivesFromObject(const codeview_type* cvtype)
+{
+ if(cmpStructName(cvtype, (const BYTE*) OBJECT_SYMBOL, true))
+ return true;
+
+ int baseType = getBaseClass(cvtype);
+ const codeview_type* basetype = getTypeData(baseType);
+ if(!basetype)
+ return false;
+
+ return derivesFromObject(basetype);
+}
+
+bool CV2PDB::isCppInterface(const codeview_type* cvtype)
+{
+ // check whether the first virtual function is at offset 0 (C++) or 4 (D)
+
+ if (getStructProperty(cvtype) & kPropIncomplete)
+ cvtype = findCompleteClassType(cvtype);
+
+ const codeview_reftype* fieldlist = (const codeview_reftype*) getTypeData(getStructFieldlist(cvtype));
+ if(!fieldlist || (fieldlist->common.id != LF_FIELDLIST_V1 && fieldlist->common.id != LF_FIELDLIST_V2))
+ return false;
+
+ codeview_fieldtype* fieldtype = (codeview_fieldtype*)(fieldlist->fieldlist.list);
+ const codeview_type* basetype = 0;
+ if(fieldtype->common.id == LF_BCLASS_V1)
+ basetype = getTypeData(fieldtype->bclass_v1.type);
+ if(fieldtype->common.id == LF_BCLASS_V2)
+ basetype = getTypeData(fieldtype->bclass_v2.type);
+ if(basetype)
+ return isCppInterface(basetype);
+
+ int off = _doFields(kCmdOffsetFirstVirtualMethod, 0, fieldlist, 0);
+ return off == 0;
+}
+
+void CV2PDB::ensureUDT(int type, const codeview_type* cvtype)
+{
+ if (getStructProperty(cvtype) & kPropIncomplete)
+ cvtype = findCompleteClassType(cvtype, &type);
+
+ if(!findUdtSymbol(type + 0x1000))
+ {
+ char name[300];
+ int value, leaf_len = numeric_leaf(&value, &cvtype->struct_v1.structlen);
+ pstrcpy_v(true, (BYTE*) name, (const BYTE*) &cvtype->struct_v1.structlen + leaf_len);
+
+ codeview_reftype* rdtype = (codeview_reftype*) (userTypes + cbUserTypes);
+ rdtype->fieldlist.id = LF_FIELDLIST_V2;
+ int helpfieldlistType = nextUserType++;
+ rdtype->fieldlist.len = 2;
+ cbUserTypes += rdtype->fieldlist.len + 2;
+
+ codeview_type*dtype = (codeview_type*) (userTypes + cbUserTypes);
+ cbUserTypes += addClass(dtype, 0, helpfieldlistType, 0, 0, 0, 4, name);
+ int viewHelperType = nextUserType++;
+ // addUdtSymbol(viewHelperType, "object_viewhelper");
+ addUdtSymbol(viewHelperType, name);
+ }
+}
+
int CV2PDB::appendTypedef(int type, const char* name)
{
checkUserTypeAlloc();
@@ -1749,8 +1908,7 @@ int CV2PDB::appendTypedef(int type, const char* name)
dtype->enumeration_v2.property = 0x200;
int len = cstrcpy_v (v3, (BYTE*) &dtype->enumeration_v2.p_name, name);
len += sizeof(dtype->enumeration_v2) - sizeof(dtype->enumeration_v2.p_name);
- dtype->enumeration_v2.len = len - 2;
- cbUserTypes += len;
+ writeUserTypeLen(dtype, len);
typedefs[cntTypedefs] = type;
translatedTypedefs[cntTypedefs] = nextUserType;
@@ -1809,6 +1967,20 @@ bool CV2PDB::initGlobalTypes()
nextUserType = globalTypeHeader->cTypes + 0x1000;
appendTypedefs();
+ if(Dversion > 0)
+ {
+ if(addClassTypeEnum)
+ {
+ classEnumType = appendEnumerator("__ClassType", CLASSTYPEENUM_NAME, kClassTypeObject, kPropIsNested);
+ ifaceEnumType = appendEnumerator("__IfaceType", CLASSTYPEENUM_NAME, kClassTypeIface, kPropIsNested);
+ cppIfaceEnumType = appendEnumerator("__CppIfaceType", CLASSTYPEENUM_NAME, kClassTypeCppIface, kPropIsNested);
+ structEnumType = appendEnumerator("__StructType", CLASSTYPEENUM_NAME, kClassTypeStruct, kPropIsNested);
+
+ ifaceBaseType = appendObjectType (kClassTypeIface, ifaceEnumType, IFACE_SYMBOL);
+ cppIfaceBaseType = appendObjectType (kClassTypeCppIface, cppIfaceEnumType, CPPIFACE_SYMBOL);
+ }
+ classBaseType = appendObjectType (kClassTypeObject, classEnumType, OBJECT_SYMBOL);
+ }
for (unsigned int t = 0; t < globalTypeHeader->cTypes && !hadError(); t++)
{
@@ -1817,11 +1989,7 @@ bool CV2PDB::initGlobalTypes()
int leaf_len, value;
int len = type->common.len + 2;
- if (cbGlobalTypes + len + 1000 > allocGlobalTypes)
- {
- allocGlobalTypes += len + 1000;
- globalTypes = (unsigned char*) realloc(globalTypes, allocGlobalTypes);
- }
+ checkGlobalTypeAlloc(len + 1000);
unsigned int clsstype;
codeview_type* dtype = (codeview_type*) (globalTypes + cbGlobalTypes);
@@ -1931,6 +2099,7 @@ bool CV2PDB::initGlobalTypes()
#endif
len += leaf_len + sizeof(dtype->struct_v2) - sizeof(type->struct_v2.structlen);
+ ensureUDT(t, type);
// remember type index of derived list for object.Object
if (Dversion > 0 && dtype->struct_v2.derived)
if (memcmp((char*) &type->struct_v1.structlen + leaf_len, "\x0dobject.Object", 14) == 0)
@@ -2089,25 +2258,148 @@ bool CV2PDB::initGlobalTypes()
cbGlobalTypes += len;
}
-#if 1
+#if 0
if(Dversion > 0)
- appendObjectType (object_derived_type);
+ appendObjectType (object_derived_type, 0, OBJECT_SYMBOL);
#endif
#if 1
- if (cbGlobalTypes + cbUserTypes > allocGlobalTypes)
- {
- allocGlobalTypes += cbUserTypes + 1000;
- globalTypes = (unsigned char*) realloc(globalTypes, allocGlobalTypes);
- }
+ checkGlobalTypeAlloc(cbUserTypes);
memcpy (globalTypes + cbGlobalTypes, userTypes, cbUserTypes);
cbGlobalTypes += cbUserTypes;
#endif
+ if(addClassTypeEnum)
+ insertClassTypeEnums();
}
}
return !hadError();
}
+bool CV2PDB::hasClassTypeEnum(const codeview_type* fieldlist)
+{
+ const codeview_reftype* rfieldlist = (const codeview_reftype*) fieldlist;
+ return _doFields(kCmdHasClassTypeEnum, 0, rfieldlist, 0) != 0;
+}
+
+int CV2PDB::appendClassTypeEnum(const codeview_type* fieldlist, int type, const char* name)
+{
+ BYTE data[200];
+ int len = addFieldNestedType((codeview_fieldtype*) data, type, name);
+
+ int fieldlen = fieldlist->common.len + 2;
+ int off = (unsigned char*) fieldlist - globalTypes;
+ checkGlobalTypeAlloc(len);
+
+ int copyoff = off + fieldlen;
+ memmove(globalTypes + copyoff + len, globalTypes + copyoff, cbGlobalTypes - copyoff);
+ memcpy(globalTypes + copyoff, data, len);
+ cbGlobalTypes += len;
+
+ codeview_type* nfieldlist = (codeview_type*) (globalTypes + off);
+ nfieldlist->common.len = fieldlen + len - 2;
+ return len;
+}
+
+int CV2PDB::insertBaseClass(const codeview_type* fieldlist, int type)
+{
+ codeview_fieldtype cvtype;
+ cvtype.bclass_v2.id = LF_BCLASS_V2;
+ cvtype.bclass_v2.type = type;
+ cvtype.bclass_v2.attribute = 3; // public
+ cvtype.bclass_v2.offset = 0;
+ int len = sizeof(cvtype.bclass_v2);
+ unsigned char* p = (unsigned char*) &cvtype;
+ for (; len & 3; len++)
+ p[len] = 0xf4 - (len & 3);
+
+ int fieldlen = fieldlist->common.len + 2;
+ int off = (unsigned char*) fieldlist - globalTypes;
+ checkGlobalTypeAlloc(len);
+
+ int copyoff = off + 4;
+ memmove(globalTypes + copyoff + len, globalTypes + copyoff, cbGlobalTypes - copyoff);
+ memcpy(globalTypes + copyoff, &cvtype, len);
+ cbGlobalTypes += len;
+
+ codeview_type* nfieldlist = (codeview_type*) (globalTypes + off);
+ nfieldlist->common.len = fieldlen + len - 2;
+ return len;
+}
+
+bool CV2PDB::insertClassTypeEnums()
+{
+ int pos = 4; // skip prefix
+ for (unsigned int t = 0; pos < cbGlobalTypes && t < globalTypeHeader->cTypes; t++)
+ {
+ codeview_type* type = (codeview_type*)(globalTypes + pos);
+ int typelen = type->common.len + 2;
+
+ switch(type->common.id)
+ {
+ case LF_STRUCTURE_V3:
+ case LF_STRUCTURE_V2:
+ case LF_CLASS_V3:
+ case LF_CLASS_V2:
+ if(const codeview_type* fieldlist = getConvertedTypeData(type->struct_v2.fieldlist))
+ {
+ if(!hasClassTypeEnum(fieldlist))
+ {
+ int enumtype = 0;
+ int basetype = 0;
+ const char* name;
+
+ if(type->common.id == LF_STRUCTURE_V2 || type->common.id == LF_STRUCTURE_V3)
+ {
+ enumtype = structEnumType;
+ basetype = structBaseType;
+ name = "__StructType";
+ }
+ else if(derivesFromObject(type))
+ {
+ enumtype = classEnumType;
+ basetype = classBaseType;
+ name = "__ClassType";
+ }
+ else if(isCppInterface(type))
+ {
+ enumtype = cppIfaceEnumType;
+ basetype = cppIfaceBaseType;
+ name = "__CppIfaceType";
+ }
+ else
+ {
+ enumtype = ifaceEnumType;
+ basetype = ifaceBaseType;
+ name = "__IfaceType";
+ }
+ if(basetype && !getBaseClass(type))
+ {
+ type->struct_v2.n_element++;
+ // appending can realloc globalTypes, changing its address!
+ int flpos = (unsigned char*) fieldlist - globalTypes;
+ int len = insertBaseClass(fieldlist, basetype);
+ if(fieldlist < type)
+ pos += len;
+ type = (codeview_type*)(globalTypes + pos);
+ fieldlist = (codeview_type*)(globalTypes + flpos);
+ }
+ if(enumtype)
+ {
+ type->struct_v2.n_element++;
+ // appending can realloc globalTypes, changing its address!
+ int len = appendClassTypeEnum(fieldlist, enumtype, name);
+ if(fieldlist < type)
+ pos += len;
+ }
+ }
+ }
+ break;
+ }
+ pos += typelen;
+ }
+ return true;
+}
+
bool CV2PDB::addTypes()
{
if (!globalTypes)
@@ -2458,6 +2750,7 @@ int CV2PDB::copySymbols(BYTE* srcSymbols, int srcSize, BYTE* destSymbols, int de
dsym->common.id = S_END_V1;
dsym->common.len = destlength - 2;
}
+ else
#endif
if (p2ccmp(dsym->stack_v1.p_name, "this"))
{
@@ -2485,9 +2778,11 @@ int CV2PDB::copySymbols(BYTE* srcSymbols, int srcSize, BYTE* destSymbols, int de
if (type >= 0x1000 && pointerTypes[type - 0x1000])
type = pointerTypes[type - 0x1000];
}
+ dsym->stack_v1.symtype = translateType(type);
}
else if(Dversion == 0)
{
+ // remove function scope from variable name
int p = -1;
for(int i = 0; i < dsym->stack_v1.p_name.namelen; i++)
if(dsym->stack_v1.p_name.name[i] == ':')
@@ -2502,8 +2797,18 @@ int CV2PDB::copySymbols(BYTE* srcSymbols, int srcSize, BYTE* destSymbols, int de
destSymbols[destSize + destlength] = 0;
dsym->stack_v1.len = destlength - 2;
}
+ dsym->stack_v1.symtype = translateType(type);
+ }
+ else
+ {
+ dsym->stack_v2.id = v3 ? S_BPREL_V3 : S_BPREL_V1;
+ dsym->stack_v2.offset = sym->stack_v1.offset;
+ dsym->stack_v2.symtype = translateType(type);
+ destlength = pstrcpy_v (v3, (BYTE*) &dsym->stack_v2.p_name,
+ (BYTE*) &sym->stack_v1.p_name);
+ destlength += sizeof(dsym->stack_v2) - sizeof(dsym->stack_v2.p_name);
+ dsym->stack_v2.len = destlength - 2;
}
- dsym->stack_v1.symtype = translateType(type);
//sym->stack_v1.symtype = 0x1012;
break;
case S_ENDARG_V1:
@@ -2563,9 +2868,23 @@ int CV2PDB::copySymbols(BYTE* srcSymbols, int srcSize, BYTE* destSymbols, int de
codeview_symbol* CV2PDB::findUdtSymbol(int type)
{
type = translateType(type);
+ for(int p = 0; p < cbGlobalSymbols; )
+ {
+ codeview_symbol* sym = (codeview_symbol*) (globalSymbols + p);
+ if(sym->common.id == S_UDT_V1 && sym->udt_v1.type == type)
+ return sym;
+ p += sym->common.len + 2;
+ }
+ for(int p = 0; p < cbStaticSymbols; )
+ {
+ codeview_symbol* sym = (codeview_symbol*) (staticSymbols + p);
+ if(sym->common.id == S_UDT_V1 && sym->udt_v1.type == type)
+ return sym;
+ p += sym->common.len + 2;
+ }
for(int p = 0; p < cbUdtSymbols; )
{
- codeview_symbol* sym = (codeview_symbol*) (udtSymbols + cbUdtSymbols);
+ codeview_symbol* sym = (codeview_symbol*) (udtSymbols + p);
if(sym->common.id == S_UDT_V1 && sym->udt_v1.type == type)
return sym;
p += sym->common.len + 2;
@@ -2644,9 +2963,6 @@ bool CV2PDB::addSymbols(int iMod, BYTE* symbols, int cb, bool addGlobals)
bool CV2PDB::addSymbols()
{
- if (!initGlobalSymbols())
- return false;
-
int prefix = 4;
DWORD* data = 0;
int databytes = 0;
diff --git a/src/cv2pdb.h b/src/cv2pdb.h
index 0dfa0f3..0b93b38 100644
--- a/src/cv2pdb.h
+++ b/src/cv2pdb.h
@@ -34,7 +34,15 @@ public:
const BYTE* getLibrary(int i);
bool initSegMap();
- enum { kCmdAdd, kCmdCount, kCmdNestedTypes };
+ enum
+ {
+ kCmdAdd,
+ kCmdCount,
+ kCmdNestedTypes,
+ kCmdOffsetFirstVirtualMethod,
+ kCmdHasClassTypeEnum,
+ kCmdCountBaseClasses
+ };
int _doFields(int cmd, codeview_reftype* dfieldlist, const codeview_reftype* fieldlist, int arg);
int addFields(codeview_reftype* dfieldlist, const codeview_reftype* fieldlist, int maxdlen);
int countFields(const codeview_reftype* fieldlist);
@@ -46,6 +54,8 @@ public:
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 addEnum(codeview_type* dtype, int count, int fieldlist, int property,
+ int type, const char*name);
int addPointerType(codeview_type* dtype, int type, int attr = 0x800A);
int addPointerType(unsigned char* dtype, int type, int attr = 0x800A);
@@ -53,16 +63,22 @@ public:
int addFieldMember(codeview_fieldtype* dfieldtype, int attr, int offset, int type, const char* name);
int addFieldStaticMember(codeview_fieldtype* dfieldtype, int attr, int type, const char* name);
int addFieldNestedType(codeview_fieldtype* dfieldtype, int type, const char* name);
+ int addFieldEnumerate(codeview_fieldtype* dfieldtype, const char* name, int val);
void checkUserTypeAlloc(int size = 1000, int add = 10000);
+ void checkGlobalTypeAlloc(int size, int add = 1000);
+ void writeUserTypeLen(codeview_type* type, int len);
const codeview_type* getTypeData(int type);
const codeview_type* getUserTypeData(int type);
- const codeview_type* findCompleteClassType(const codeview_type* cvtype);
+ const codeview_type* getConvertedTypeData(int type);
+ const codeview_type* findCompleteClassType(const codeview_type* cvtype, int* ptype = 0);
int findMemberFunctionType(codeview_symbol* lastGProcSym, int thisPtrType);
- int fixProperty(int type, int prop, int fieldType);
+ int fixProperty(int type, int prop, int fieldType);
+ bool derivesFromObject(const codeview_type* cvtype);
+ bool isCppInterface(const codeview_type* cvtype);
int sizeofClassType(const codeview_type* cvtype);
int sizeofBasicType(int type);
@@ -70,6 +86,8 @@ public:
// to be used when writing new type only to avoid double translation
int translateType(int type);
+ int getBaseClass(const codeview_type* cvtype);
+ int countBaseClasses(const codeview_type* cvtype);
bool nameOfBasicType(int type, char* name, int maxlen);
bool nameOfType(int type, char* name, int maxlen);
@@ -85,11 +103,16 @@ public:
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);
- int appendTypedef(int type, const char* name);
- int appendComplex(int cplxtype, int basetype, int elemsize, const char* name);
+ int appendObjectType (int object_derived_type, int enumType, const char* classSymbol);
+ int appendPointerType(int pointedType, int attr);
+ int appendTypedef(int type, const char* name);
+ int appendComplex(int cplxtype, int basetype, int elemsize, const char* name);
void appendTypedefs();
+ int appendEnumerator(const char* typeName, const char* enumName, int enumValue, int prop);
+ int appendClassTypeEnum(const codeview_type* fieldlist, int type, const char* name);
+ bool hasClassTypeEnum(const codeview_type* fieldlist);
+ bool insertClassTypeEnums();
+ int insertBaseClass(const codeview_type* fieldlist, int type);
bool initGlobalTypes();
bool initGlobalSymbols();
@@ -100,6 +123,7 @@ public:
codeview_symbol* findUdtSymbol(int type);
bool addUdtSymbol(int type, const char* name);
+ void ensureUDT(int type, const codeview_type* cvtype);
// returns new destSize
int copySymbols(BYTE* srcSymbols, int srcSize, BYTE* destSymbols, int destSize);
@@ -160,11 +184,22 @@ public:
int nextUserType;
int objectType;
+ int classEnumType;
+ int ifaceEnumType;
+ int cppIfaceEnumType;
+ int structEnumType;
+
+ int classBaseType;
+ int ifaceBaseType;
+ int cppIfaceBaseType;
+ int structBaseType;
+
// D named types
int typedefs[20];
int translatedTypedefs[20];
int cntTypedefs;
+ bool addClassTypeEnum;
bool useGlobalMod;
bool thisIsNotRef;
bool v3;
diff --git a/src/cv2pdb.sln b/src/cv2pdb.sln
index 53eb722..ddb3df0 100644
--- a/src/cv2pdb.sln
+++ b/src/cv2pdb.sln
@@ -7,7 +7,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dviewhelper", "dviewhelper\
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{7F4A9B6A-05A2-45D0-AFC3-3754B7FB77B9}"
ProjectSection(SolutionItems) = preProject
- ..\autoexp.snippet = ..\autoexp.snippet
+ ..\autoexp.expand = ..\autoexp.expand
+ ..\autoexp.visualizer = ..\autoexp.visualizer
..\CHANGES = ..\CHANGES
..\FEATURES = ..\FEATURES
..\INSTALL = ..\INSTALL
diff --git a/src/cv2pdb.vcproj b/src/cv2pdb.vcproj
index 71a7252..cc0a479 100644
--- a/src/cv2pdb.vcproj
+++ b/src/cv2pdb.vcproj
@@ -182,6 +182,14 @@
>
</File>
<File
+ RelativePath=".\cvutil.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\cvutil.h"
+ >
+ </File>
+ <File
RelativePath=".\demangle.cpp"
>
</File>
diff --git a/src/cvutil.cpp b/src/cvutil.cpp
new file mode 100644
index 0000000..c125b41
--- /dev/null
+++ b/src/cvutil.cpp
@@ -0,0 +1,169 @@
+// Convert DMD CodeView debug information to PDB files
+// Copyright (c) 2009-2010 by Rainer Schuetze, All Rights Reserved
+//
+// License for redistribution is given by the Artistic License 2.0
+// see file LICENSE for further details
+
+#include "cvutil.h"
+
+bool isStruct(const codeview_type* cvtype)
+{
+ switch(cvtype->common.id)
+ {
+ case LF_STRUCTURE_V1:
+ case LF_CLASS_V1:
+ case LF_STRUCTURE_V2:
+ case LF_CLASS_V2:
+ case LF_STRUCTURE_V3:
+ case LF_CLASS_V3:
+ return true;
+ }
+ return false;
+}
+
+int getStructProperty(const codeview_type* cvtype)
+{
+ switch(cvtype->common.id)
+ {
+ case LF_STRUCTURE_V1:
+ case LF_CLASS_V1:
+ return cvtype->struct_v1.property;
+ case LF_STRUCTURE_V2:
+ case LF_CLASS_V2:
+ return cvtype->struct_v2.property;
+ case LF_STRUCTURE_V3:
+ case LF_CLASS_V3:
+ return cvtype->struct_v3.property;
+ }
+ return 0;
+}
+
+int getStructFieldlist(const codeview_type* cvtype)
+{
+ switch(cvtype->common.id)
+ {
+ case LF_STRUCTURE_V1:
+ case LF_CLASS_V1:
+ return cvtype->struct_v1.fieldlist;
+ case LF_STRUCTURE_V2:
+ case LF_CLASS_V2:
+ return cvtype->struct_v2.fieldlist;
+ case LF_STRUCTURE_V3:
+ case LF_CLASS_V3:
+ return cvtype->struct_v3.fieldlist;
+ }
+ return 0;
+}
+
+const BYTE* getStructName(const codeview_type* cvtype, bool &cstr)
+{
+ int value, leaf_len;
+ switch(cvtype->common.id)
+ {
+ case LF_STRUCTURE_V1:
+ case LF_CLASS_V1:
+ cstr = false;
+ leaf_len = numeric_leaf(&value, &cvtype->struct_v1.structlen);
+ return (const BYTE*) &cvtype->struct_v1.structlen + leaf_len;
+ case LF_STRUCTURE_V2:
+ case LF_CLASS_V2:
+ cstr = false;
+ leaf_len = numeric_leaf(&value, &cvtype->struct_v2.structlen);
+ return (const BYTE*) &cvtype->struct_v2.structlen + leaf_len;
+ case LF_STRUCTURE_V3:
+ case LF_CLASS_V3:
+ cstr = true;
+ leaf_len = numeric_leaf(&value, &cvtype->struct_v3.structlen);
+ return (const BYTE*) &cvtype->struct_v3.structlen + leaf_len;
+ }
+ return 0;
+}
+
+bool cmpStructName(const codeview_type* cvtype, const BYTE* name, bool cstr)
+{
+ bool cstr2;
+ const BYTE* name2 = getStructName(cvtype, cstr2);
+ if(!name || !name2)
+ return name == name2;
+ return dstrcmp(name, cstr, name2, cstr2);
+}
+
+bool isCompleteStruct(const codeview_type* type, const BYTE* name, bool cstr)
+{
+ return isStruct(type)
+ && !(getStructProperty(type) & kPropIncomplete)
+ && cmpStructName(type, name, cstr);
+}
+
+int 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
+ {
+ length = 0; // error!
+ }
+ break;
+ }
+ return length;
+}
+
diff --git a/src/cvutil.h b/src/cvutil.h
new file mode 100644
index 0000000..83b0939
--- /dev/null
+++ b/src/cvutil.h
@@ -0,0 +1,51 @@
+// Convert DMD CodeView debug information to PDB files
+// Copyright (c) 2009-2010 by Rainer Schuetze, All Rights Reserved
+//
+// License for redistribution is given by the Artistic License 2.0
+// see file LICENSE for further details
+
+#ifndef __CVUTIL_H__
+#define __CVUTIL_H__
+
+#include "cv2pdb.h"
+#include "symutil.h"
+
+#define OBJECT_SYMBOL "object@Object"
+#define IFACE_SYMBOL "DInterface"
+#define CPPIFACE_SYMBOL "CppInterface"
+
+#define P_OBJECT_SYMBOL ((const BYTE*)("\x0d" OBJECT_SYMBOL))
+
+#define CLASSTYPEENUM_TYPE "__ClassType"
+#define CLASSTYPEENUM_NAME "__classtype"
+
+enum
+{
+ kClassTypeObject = 1,
+ kClassTypeIface = 2,
+ kClassTypeCppIface = 3,
+ kClassTypeStruct = 4
+};
+
+// class properties (also apply to struct,union and enum)
+static const int kPropPacked = 0x01;
+static const int kPropHasCtorDtor = 0x02;
+static const int kPropHasOverOps = 0x04;
+static const int kPropIsNested = 0x08;
+static const int kPropHasNested = 0x10;
+static const int kPropHasOverAsgn = 0x20;
+static const int kPropHasCasting = 0x40;
+static const int kPropIncomplete = 0x80;
+static const int kPropScoped = 0x100;
+
+bool isStruct(const codeview_type* cvtype);
+int getStructProperty(const codeview_type* cvtype);
+int getStructFieldlist(const codeview_type* cvtype);
+bool isCompleteStruct(const codeview_type* type, const BYTE* name, bool cstr);
+
+const BYTE* getStructName(const codeview_type* cvtype, bool &cstr);
+bool cmpStructName(const codeview_type* cvtype, const BYTE* name, bool cstr);
+
+int numeric_leaf(int* value, const void* leaf);
+
+#endif // __CVUTIL_H__
diff --git a/src/demangle.cpp b/src/demangle.cpp
index ef5dec6..6c1ff30 100644
--- a/src/demangle.cpp
+++ b/src/demangle.cpp
@@ -202,8 +202,26 @@ public:
case 'W': // Windows function
case 'V': // Pascal function
case 'R': // C++ function
- { char mc = name[ni - 1];
+ {
+ char mc = name[ni - 1];
string args;
+ string prop;
+ while(name[ni] == 'N')
+ {
+ switch(name[ni+1])
+ {
+ case 'a': prop += "pure "; break;
+ case 'b': prop += "nothrow "; break;
+ case 'c': prop += "ref "; break;
+ case 'd': prop += "@property "; break;
+ case 'e': prop += "@trusted "; break;
+ case 'f': prop += "@safe "; break;
+ default:
+ goto no_prop;
+ }
+ ni += 2;
+ }
+ no_prop:
while (1)
{
@@ -260,9 +278,9 @@ public:
default: assert(0);
}
p += parseType() + " " + identifier + "(" + args + ")";
- return p;
+ return prop + p;
}
- p = parseType() +
+ p = prop + parseType() +
(isdelegate ? " delegate(" : " function(") + args + ")";
isdelegate = 0;
goto L1;
@@ -504,7 +522,7 @@ void unittest()
bool d_demangle(const char* name, char* demangled, int maxlen, bool plain)
{
-#ifdef _DEBUG
+#if 0 // && def _DEBUG
static bool once; if(!once) { once = true; unittest(); }
#endif
diff --git a/src/main.cpp b/src/main.cpp
index 644e27d..2c6da50 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -142,6 +142,9 @@ int main(int argc, char** argv)
if (!cv2pdb.initSegMap())
fatal("%s: %s", argv[1], cv2pdb.getLastError());
+ if (!cv2pdb.initGlobalSymbols())
+ fatal("%s: %s", argv[1], cv2pdb.getLastError());
+
if (!cv2pdb.initGlobalTypes())
fatal("%s: %s", argv[1], cv2pdb.getLastError());
diff --git a/src/symutil.cpp b/src/symutil.cpp
index 0b761f2..0c2c3ee 100644
--- a/src/symutil.cpp
+++ b/src/symutil.cpp
@@ -15,20 +15,23 @@ extern "C" {
char dotReplacementChar = '@';
-int dsym2c(const BYTE* p, BYTE len, char* cname, int maxclen)
+int dsym2c(const BYTE* p, int len, char* cname, int maxclen)
{
+ const BYTE* end = p + len;
int zlen, zpos, cpos = 0;
// decompress symbol
- while (len-- > 0)
+ while (p < end)
{
int ch = *p++;
+ if(ch == 0)
+ break;
if (ch == 0x80)
{
- if (len-- <= 0)
+ if (p >= end)
break;
zlen = *p++ & 0x7f;
- if (len-- <= 0)
+ if (p >= end)
break;
zpos = *p++ & 0x7f;
if (zpos > cpos)
@@ -62,10 +65,28 @@ int dsym2c(const BYTE* p, BYTE len, char* cname, int maxclen)
return cpos;
}
+int pstrlen(const BYTE* &p)
+{
+ int len = *p++;
+ if(len == 0xff && *p == 0)
+ {
+ len = p[1] | (p[2] << 8);
+ p += 3;
+ }
+ return len;
+}
+
+int dstrlen(const BYTE* &p, bool cstr)
+{
+ if(cstr)
+ return strlen((const char*)p);
+ return pstrlen(p);
+}
+
char* p2c(const BYTE* p, int idx)
{
static char cname[4][2560];
- int len = *p++;
+ int len = pstrlen(p);
#if 1
memcpy(cname[idx], p, len);
@@ -83,15 +104,20 @@ char* p2c(const p_string& p, int idx)
int p2ccpy(char* p, const BYTE* s)
{
- memcpy(p, s + 1, *s);
- p[*s] = 0;
- return *s + 1;
+ int len = pstrlen(s);
+ memcpy(p, s, len);
+ p[len] = 0;
+ return len + 1;
}
int pstrcpy(BYTE* p, const BYTE* s)
{
- int len = *p = *s;
- for(int i = 1; i <= len; i++)
+ const BYTE* src = s;
+ int len = pstrlen(s);
+ for(int i = 0; i <= s - src; i++)
+ *p++ = src[i];
+
+ for(int i = 0; i < len; i++)
if (s[i] == '.')
{
//p[i++] = ':';
@@ -99,7 +125,25 @@ int pstrcpy(BYTE* p, const BYTE* s)
}
else
p[i] = s[i];
- return len + 1; // *(BYTE*) memcpy (p, s, *s + 1) + 1;
+ return len + src - s; // *(BYTE*) memcpy (p, s, *s + 1) + 1;
+}
+
+int dmemcmp(const void* v1, const void* v2, int len)
+{
+ const BYTE* p1 = (const BYTE*) v1;
+ const BYTE* p2 = (const BYTE*) v2;
+ for(int i = 0; i < len; i++)
+ {
+ int b1 = p1[i];
+ int b2 = p2[i];
+ if(b1 == '.')
+ b1 = dotReplacementChar;
+ if(b2 == '.')
+ b2 = dotReplacementChar;
+ if(b1 != b2)
+ return b2 - b1;
+ }
+ return 0;
}
int pstrcpy(p_string& p, const p_string& s)
@@ -109,29 +153,42 @@ int pstrcpy(p_string& p, const p_string& s)
int pstrcmp(const BYTE* p1, const BYTE* p2)
{
- if (*p1 != *p2)
- return *p2 - *p1;
- return memcmp(p1 + 1, p2 + 1, *p1);
+ int len1 = pstrlen(p1);
+ int len2 = pstrlen(p2);
+ if (len1 != len2)
+ return len2 - len1;
+ return dmemcmp(p1, p2, len1);
}
bool p2ccmp(const BYTE* pp, const char* cp)
{
int len = strlen(cp);
- if (len != *pp)
+ int plen = pstrlen(pp);
+ if (len != plen)
return false;
- return memcmp(pp + 1, cp, len) == 0;
+ return dmemcmp(pp, cp, len) == 0;
}
+
bool p2ccmp(const p_string& pp, const char* cp)
{
return p2ccmp(&pp.namelen, cp);
}
+bool dstrcmp(const BYTE* s1, bool cstr1, const BYTE* s2, bool cstr2)
+{
+ int len1 = dstrlen(s1, cstr1);
+ int len2 = dstrlen(s2, cstr2);
+ if(len1 != len2)
+ return false;
+ return dmemcmp(s1, s2, len1) == 0;
+}
+
int pstrcpy_v(bool v3, BYTE* d, const BYTE* s)
{
if (!v3)
return pstrcpy(d, s);
- int len = *s++;
+ int len = pstrlen(s);
int clen = dsym2c(s, len, (char*) d, 1000) + 1;
return clen;
diff --git a/src/symutil.h b/src/symutil.h
index aa69987..2fd483d 100644
--- a/src/symutil.h
+++ b/src/symutil.h
@@ -11,7 +11,7 @@
struct p_string;
-int dsym2c(const BYTE* p, BYTE len, char* cname, int maxclen);
+int dsym2c(const BYTE* p, int len, char* cname, int maxclen);
char* p2c(const BYTE* p, int idx = 0);
char* p2c(const p_string& p, int idx = 0);
@@ -23,7 +23,8 @@ 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);
+bool dstrcmp(const BYTE* s1, bool cstr1, const BYTE* s2, bool cstr2);
extern char dotReplacementChar;
-#endif //__SYMUTIL_H__ \ No newline at end of file
+#endif //__SYMUTIL_H__
diff --git a/test/cvtest.d b/test/cvtest.d
index 8be7b67..5bdc819 100644
--- a/test/cvtest.d
+++ b/test/cvtest.d
@@ -9,9 +9,10 @@ import std.stdio;
enum enum_name
{
kEnum1 = 1,
- kEnum2,
+ kEnum2 = cast(uint) 2,
kEnum3,
kEnum500 = 500,
+ E_NOTIMPL = cast(int)0x80004001,
};
// field type LF_MEMBER_V1
@@ -144,6 +145,34 @@ class class_with_struct_member
this() { s1 = new struc; }
};
+interface iface
+{
+ void foo();
+}
+
+interface iface2 : iface
+{
+ void foo2();
+}
+
+class iface_impl : iface2
+{
+ void foo() {}
+ void foo2() {}
+}
+
+interface IUnknown
+{
+ void addref();
+ void release();
+}
+
+class CUnknown : IUnknown
+{
+ void addref() {}
+ void release() {}
+}
+
version(D2)
{
string stringMixin = "int a = 0;
@@ -202,10 +231,23 @@ int main2(char[][]argv)
class_outer inst_outer = new class_outer;
class_outer.class_inner inst_inner = inst_outer.inner; // = new class_outer.class_inner(inst_outer);
struct_name inst_struct;
+ struct_name* pinst_struct;
+ pinst_struct = &inst_struct;
inst_struct.member = 1;
struct_name.static_member = 3;
this_is_a_rather_long_classname_to_test_what_happens_if_the_classname_gets_longer_than_the_limit_imposed_by_the_old_codeview_format_which_limits_the_length_of_names_to_tw0_hundred_and_fifty_five_characters_because_it_uses_pascal_strings_with_a_length_byte_and_chars_appended long_class_name;
+ int this_is_a_rather_long_varname_to_test_what_happens_if_the_classname_gets_longer_than_the_limit_imposed_by_the_old_codeview_format_which_limits_the_length_of_names_to_tw0_hundred_and_fifty_five_characters_because_it_uses_pascal_strings_with_a_length_byte_and_chars_appended = 1;
+ int *plongname = &this_is_a_rather_long_varname_to_test_what_happens_if_the_classname_gets_longer_than_the_limit_imposed_by_the_old_codeview_format_which_limits_the_length_of_names_to_tw0_hundred_and_fifty_five_characters_because_it_uses_pascal_strings_with_a_length_byte_and_chars_appended;
+ iface_impl impl = new iface_impl;
+ iface face = impl;
+ iface_impl nimpl = cast(iface_impl) face;
+
+ CUnknown unkn = new CUnknown;
+ IUnknown iunkn = unkn;
+ CUnknown nunkn = cast(CUnknown) iunkn;
+
+ FILE stdfile;
inst_member.member1 = 2;
union_name inst_union;
@@ -260,6 +302,12 @@ int main(char[][]argv)
int_arr[17] = 28;
int_arr[45] = 91;
+ float f = 2.4;
+ double d = 2.4;
+ if(d == f)
+ d = 0;
+ assert(2.4 == 2.4f);
+
struct ab {
int a;
int b;
@@ -286,7 +334,9 @@ int main(char[][]argv)
int[] dynint_arr;
dynint_arr ~= 12;
- return dynint_arr.length;
+
+ return enum_name.E_NOTIMPL;
+ //return dynint_arr.length;
}
// alias invariant(char)[] string;