From 59dc1509092a46bb18e08f54ac5c4f859ca0ffa8 Mon Sep 17 00:00:00 2001 From: sagitario Date: Sun, 8 Aug 2010 08:37:12 +0000 Subject: 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 --- CHANGES | 13 ++ TODO | 1 - VERSION | 2 +- autoexp.visualizer | 16 +- src/PEImage.cpp | 10 +- src/cv2pdb.cpp | 568 +++++++++++++++++++++++++++++++++++++++++------------ src/cv2pdb.h | 49 ++++- src/cv2pdb.sln | 3 +- src/cv2pdb.vcproj | 8 + src/cvutil.cpp | 169 ++++++++++++++++ src/cvutil.h | 51 +++++ src/demangle.cpp | 26 ++- src/main.cpp | 3 + src/symutil.cpp | 91 +++++++-- src/symutil.h | 5 +- test/cvtest.d | 54 ++++- 16 files changed, 904 insertions(+), 165 deletions(-) create mode 100644 src/cvutil.cpp create mode 100644 src/cvutil.h 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 #include #include +#include #include /////////////////////////////////////////////////////////////////////// @@ -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 #include @@ -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 @@ > + + + + 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; -- cgit v0.12