From 68e0196f31f8d6fef0d7ccaa21c0f33d5fa5504e Mon Sep 17 00:00:00 2001 From: sagitario Date: Tue, 29 Dec 2009 17:24:15 +0000 Subject: Version 0.11 * basic types now show with their D names, not as C types * "enum" prefix removed from type names of enumerator types * added type information for complex data types * dmd-patch needed for long/ulong support * experimental hack to add lexical scope to local variables --- CHANGES | 9 ++++ FEATURES | 33 ++++++++++++++ Makefile | 2 +- TODO | 4 +- VERSION | 2 +- src/cv2pdb.cpp | 142 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--- src/cv2pdb.h | 8 ++++ src/cv2pdb.sln | 1 + 8 files changed, 190 insertions(+), 11 deletions(-) create mode 100644 FEATURES diff --git a/CHANGES b/CHANGES index e4f5650..8060c7d 100644 --- a/CHANGES +++ b/CHANGES @@ -71,3 +71,12 @@ Version history - entries LF_FRIENDCLS, LF_VBCLASS and LF_IVBCLASS converted thanks to Andrew. * derived-classes info in class entry now cleared to be consistent with removal of LF_DERIVED + +2009-12-29 Version 0.11 + + * basic types now show with their D names, not as C types + * "enum" prefix removed from type names of enumerator types + * added type information for complex data types + * dmd-patch needed for long/ulong support (http://d.puremagic.com/issues/show_bug.cgi?id=3373) + * experimental hack to add lexical scope to local variables (dmd patch in + http://d.puremagic.com/issues/show_bug.cgi?id=3657 needed) diff --git a/FEATURES b/FEATURES new file mode 100644 index 0000000..e394ddb --- /dev/null +++ b/FEATURES @@ -0,0 +1,33 @@ +Main Features + +* conversion of DMD/DMC CodeView information to PDB file +* converted line number info allows setting breakpoints +* display of variables, fields and objects in watch, local and auto + window and in data tooltips +* convenient display of dynamic and associative arrays in watch windows +* demangled function names for convenient display of callstack + +More features + +This list is a bit more technical and shows what is actually done to +achieve the desired functionality: + +* replaces '.' in class names with '@' to avoid confusing debugger +* converts class pointers to reference for "clss.field" syntax +* converts the type of member function, so that "this" is an object + pointer, allowing the debugger to display fields without "this." +* generates generic debug info for dynamic arrays, associative arrays + and delegates +* creates readable type names for display of D specific types +* autoexp.dat formats output for dynamic and associative arrays in + watch windows +* autoexp.dat filters display of null references +* adds object class debug info +* "char[]", "wchar[]" and "dchar[]" (D1) or "const char[]", + "const wchar[]" and "const dchar[]" (D2) translated to "string", + "wstring" and "dstring", respectively +* converts type delegate to __int64 +* addin dviewhelper.dll allows correct display of D style strings + and derived object type +* maps D basic types to enumerators to overload C style names +* add struct definitions for complex data types diff --git a/Makefile b/Makefile index ef11080..a7230f8 100644 --- a/Makefile +++ b/Makefile @@ -37,7 +37,7 @@ ADD = Makefile \ src\dviewhelper\dviewhelper.vcproj \ src\cv2pdb.sln -DOC = VERSION README INSTALL LICENSE CHANGES TODO autoexp.snippet +DOC = VERSION README INSTALL LICENSE CHANGES TODO FEATURES autoexp.snippet BIN = bin\Release\cv2pdb.exe bin\Release\dviewhelper.dll diff --git a/TODO b/TODO index 94431ef..ae2c7c8 100644 --- a/TODO +++ b/TODO @@ -18,11 +18,11 @@ in the future, but not all have a known solution. in autoexp.dat * DMD does not emit different debug information for const and invariant, type info is the same +* DMD does not emit different debug information for float and ifloat, + type info is the same * type display of delegate does not have arguments * assoc_array.length cannot be displayed (it is assoc_array.a->nodes) * enum values not displayed -* map dchar to something displayable -* workaround for ulong (written by DMD as int[]) * 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 diff --git a/VERSION b/VERSION index e7544c4..2a01178 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -VERSION = 0.10 +VERSION = 0.11 diff --git a/src/cv2pdb.cpp b/src/cv2pdb.cpp index f8621c1..00ff969 100644 --- a/src/cv2pdb.cpp +++ b/src/cv2pdb.cpp @@ -23,9 +23,13 @@ CV2PDB::CV2PDB(PEImage& image) , globalSymbols(0), cbGlobalSymbols(0), staticSymbols(0), cbStaticSymbols(0) , udtSymbols(0), cbUdtSymbols(0), allocUdtSymbols(0) , srcLineStart(0), srcLineSections(0) -, pointerTypes(0) +, pointerTypes(0), objectType(0) , Dversion(2) { + memset(typedefs, 0, sizeof(typedefs)); + memset(translatedTypedefs, 0, sizeof(translatedTypedefs)); + cntTypedefs = 0; + useGlobalMod = true; thisIsNotRef = true; v3 = true; @@ -102,6 +106,10 @@ bool CV2PDB::cleanup(bool commit) globalTypeHeader = 0; objectType = 0; pointerTypes = 0; + objectType = 0; + memset(typedefs, 0, sizeof(typedefs)); + memset(translatedTypedefs, 0, sizeof(translatedTypedefs)); + cntTypedefs = 0; return true; } @@ -926,7 +934,13 @@ int CV2PDB::sizeofType(int type) int CV2PDB::translateType(int type) { if (type < 0x1000) + { + for(int i = 0; i < cntTypedefs; i++) + if(type == typedefs[i]) + return translatedTypedefs[i]; return type; + } + const codeview_type* cvtype = getTypeData(type); if (!cvtype) return type; @@ -1118,16 +1132,16 @@ bool CV2PDB::nameOfType(int type, char* name, int maxlen) break; case LF_ENUM_V1: - strcpy(name, "enum "); - p2ccpy(name + 5, (const BYTE*) &ptype->enumeration_v1.p_name); + //strcpy(name, "enum "); + p2ccpy(name, (const BYTE*) &ptype->enumeration_v1.p_name); break; case LF_ENUM_V2: - strcpy(name, "enum "); - p2ccpy(name + 5, (const BYTE*) &ptype->enumeration_v2.p_name); + //strcpy(name, "enum "); + p2ccpy(name, (const BYTE*) &ptype->enumeration_v2.p_name); break; case LF_ENUM_V3: - strcpy(name, "enum "); - strcpy(name + 5, ptype->enumeration_v3.name); + //strcpy(name, "enum "); + strcpy(name, ptype->enumeration_v3.name); break; case LF_MODIFIER_V1: @@ -1564,6 +1578,96 @@ int CV2PDB::appendPointerType(int pointedType, int attr) return nextUserType - 1; } +int CV2PDB::appendComplex(int cplxtype, int basetype, int elemsize, const char* name) +{ + basetype = translateType(basetype); + + 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 = addFieldMember(dfieldtype, 1, 0, basetype, "re"); + + // member funcType* funcptr + dfieldtype = (codeview_fieldtype*)(rdtype->fieldlist.list + len1); + int len2 = addFieldMember(dfieldtype, 1, elemsize, basetype, "im"); + + rdtype->fieldlist.len = len1 + len2 + 2; + cbUserTypes += rdtype->fieldlist.len + 2; + int fieldlistType = nextUserType++; + + // nextUserType + 3: struct delegate<> + dtype = (codeview_type*) (userTypes + cbUserTypes); + cbUserTypes += addClass(dtype, 2, fieldlistType, 0, 0, 0, 2*elemsize, name); + + int classType = nextUserType++; + addUdtSymbol(classType, name); + + typedefs[cntTypedefs] = cplxtype; + translatedTypedefs[cntTypedefs] = classType; + cntTypedefs++; + + return classType; +} + +int CV2PDB::appendTypedef(int type, const char* name) +{ + checkUserTypeAlloc(); + + int basetype = type; + if(type == 0x78) + basetype = 0x75; // dchar type not understood by debugger, use uint instead + + codeview_reftype* rdtype = (codeview_reftype*) (userTypes + cbUserTypes); + rdtype->fieldlist.id = LF_FIELDLIST_V2; + rdtype->fieldlist.len = 2; + cbUserTypes += rdtype->fieldlist.len + 2; + int fieldlistType = nextUserType++; + + codeview_type* dtype = (codeview_type*) (userTypes + cbUserTypes); + dtype->enumeration_v2.id = (v3 ? LF_ENUM_V3 : LF_ENUM_V2); + dtype->enumeration_v2.type = basetype; + dtype->enumeration_v2.fieldlist = fieldlistType; + dtype->enumeration_v2.count = 0; + 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; + + typedefs[cntTypedefs] = type; + translatedTypedefs[cntTypedefs] = nextUserType; + cntTypedefs++; + + nextUserType++; + return nextUserType - 1; +} + +void CV2PDB::appendTypedefs() +{ + appendTypedef(0x10, "byte"); + appendTypedef(0x20, "ubyte"); + appendTypedef(0x21, "ushort"); + appendTypedef(0x75, "uint"); + appendTypedef(0x1002, "dlong"); // instead of "long" + appendTypedef(0x1003, "ulong"); + appendTypedef(0x42, "real"); + // no imaginary types + appendTypedef(0x71, "wchar"); + appendTypedef(0x78, "dchar"); + + appendComplex(0x50, 0x40, 4, "cfloat"); + appendComplex(0x51, 0x41, 8, "cdouble"); + appendComplex(0x52, 0x42, 10, "creal"); +} + bool CV2PDB::initGlobalTypes() { int object_derived_type = 0; @@ -1591,6 +1695,8 @@ bool CV2PDB::initGlobalTypes() nextUserType = globalTypeHeader->cTypes + 0x1000; + appendTypedefs(); + for (unsigned int t = 0; t < globalTypeHeader->cTypes && !hadError(); t++) { const codeview_type* type = (codeview_type*)(typeData + offset[t]); @@ -2200,6 +2306,28 @@ int CV2PDB::copySymbols(BYTE* srcSymbols, int srcSize, BYTE* destSymbols, int de case S_BPREL_V1: type = dsym->stack_v1.symtype; +#if 1 + if (type == 0 && p2ccmp(dsym->stack_v1.p_name, "@sblk")) + { + unsigned offset = dsym->stack_v1.offset & 0xffff; + unsigned length = dsym->stack_v1.offset >> 16; + dsym->block_v3.id = S_BLOCK_V3; + dsym->block_v3.parent = 0; + dsym->block_v3.end = 0; // destSize + sizeof(dsym->block_v3) + 12; + dsym->block_v3.length = length; + dsym->block_v3.offset = offset + (lastGProcSym ? lastGProcSym->proc_v2.offset : 0); + dsym->block_v3.segment = (lastGProcSym ? lastGProcSym->proc_v2.segment : 0); + dsym->block_v3.name[0] = 0; + destlength = sizeof(dsym->block_v3); + dsym->data_v2.len = destlength - 2; + } + else if (type == 0 && p2ccmp(dsym->stack_v1.p_name, "@send")) + { + destlength = 4; + dsym->generic.id = S_END_V1; + dsym->generic.len = destlength - 2; + } +#endif if (p2ccmp(dsym->stack_v1.p_name, "this")) { if (lastGProcSym) diff --git a/src/cv2pdb.h b/src/cv2pdb.h index 06f953a..03271d5 100644 --- a/src/cv2pdb.h +++ b/src/cv2pdb.h @@ -82,6 +82,9 @@ public: 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); + void appendTypedefs(); bool initGlobalTypes(); bool initGlobalSymbols(); @@ -151,6 +154,11 @@ public: int nextUserType; int objectType; + // D named types + int typedefs[20]; + int translatedTypedefs[20]; + int cntTypedefs; + bool useGlobalMod; bool thisIsNotRef; bool v3; diff --git a/src/cv2pdb.sln b/src/cv2pdb.sln index 18f285d..53eb722 100644 --- a/src/cv2pdb.sln +++ b/src/cv2pdb.sln @@ -9,6 +9,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution ProjectSection(SolutionItems) = preProject ..\autoexp.snippet = ..\autoexp.snippet ..\CHANGES = ..\CHANGES + ..\FEATURES = ..\FEATURES ..\INSTALL = ..\INSTALL ..\LICENSE = ..\LICENSE ..\Makefile = ..\Makefile -- cgit v0.12