From 890a9b3e4f9384f8937646d49848aa669f93ed8e Mon Sep 17 00:00:00 2001 From: sagitario Date: Thu, 4 Jun 2009 21:34:44 +0000 Subject: --- CHANGES | 10 ++ INSTALL | 15 ++- Makefile | 9 +- README | 10 +- TODO | 6 +- VERSION | 2 +- autoexp.snippet | 46 ++++++--- src/cv2pdb.cpp | 203 +++++++++++++++++++++++++++---------- src/cv2pdb.h | 2 + src/cv2pdb.sln | 18 ++++ src/dviewhelper/dviewhelper.cpp | 110 ++++++++++++++++++++ src/dviewhelper/dviewhelper.vcproj | 186 +++++++++++++++++++++++++++++++++ src/main.cpp | 2 + 13 files changed, 538 insertions(+), 81 deletions(-) create mode 100644 src/dviewhelper/dviewhelper.cpp create mode 100644 src/dviewhelper/dviewhelper.vcproj diff --git a/CHANGES b/CHANGES index 6c51426..5728ff6 100644 --- a/CHANGES +++ b/CHANGES @@ -18,3 +18,13 @@ Version history * support for field type LF_VFUNCTAB and symbol type S_CONSTANT used by DMC. * added stringview to autoexp.dat for full length text display. +2009-06-01 Version 0.3 + + * static members' debug info was not correctly converted, causing debugger confusion + * now works on executables compiled by DMC + - added command line switch -C to disable some D feature and + to remove function name from local variables + - added support for type LF_BITFIELD. + * added fields __viewhelper to classes string and object + * new addin dviewhelper.dll to display correctly terminated strings + and derived object type diff --git a/INSTALL b/INSTALL index 16a0a97..4b82dbd 100644 --- a/INSTALL +++ b/INSTALL @@ -34,18 +34,23 @@ navigating to the file extensions option page (found in Tools -> Options with editor "Microsoft Visual C++". This will also enable display of variables in the "Auto" watch window. -4. You should also add the contents of the file autoexp.snippet to the -[AutoExpand] section of the file autoexp.dat found in +4. the file dviewhelper.dll must be copied into a directory where +the debugger can find it. This can be any directory accessible through your +PATH variable or \Common7\IDE. + +5. You should also add the contents of the file autoexp.snippet to the +[AutoExpand] and [Visualizer] sections of the file autoexp.dat found in \Common7\Packages\Debugger. Please note that in a standard installation of Visual Studio, the -section [AutoExpand] extends to the bottom of the file but a few lines +section [AutoExpand] is at the beginning of that file, followed by +the section [Visualizer], which extends to the bottom of the file but a few lines for the section [hresult]. These lines will enable a convenient display of strings, dynamic arrays, -associative arrays and null references. +associative arrays, object types and null references. Building from source -------------------- The source package comes with a Visual Studio 2008 project and solution that work with both the Standard and the Express version. These won't -work in VS2005, but creating a VS2005 project should be easy. +work in VS2005, but creating VS2005 projects should be easy. diff --git a/Makefile b/Makefile index b6b1595..3d1be76 100644 --- a/Makefile +++ b/Makefile @@ -29,13 +29,14 @@ SRC = src\cv2pdb.cpp \ src\PEImage.cpp \ src\PEImage.h \ src\symutil.cpp \ - src\symutil.h + src\symutil.h \ + src\dviewhelper\dviewhelper.cpp -ADD = Makefile src\cv2pdb.vcproj src\cv2pdb.sln +ADD = Makefile src\cv2pdb.vcproj src\dviewhelper\dviewhelper.vcproj src\cv2pdb.sln DOC = VERSION README INSTALL LICENSE CHANGES TODO autoexp.snippet -BIN = bin\Release\cv2pdb.exe +BIN = bin\Release\cv2pdb.exe bin\Release\dviewhelper.dll TEST = test\cvtest.d @@ -48,7 +49,7 @@ DOWNLOADS = ..\downloads $(DOWNLOADS): if not exist $(DOWNLOADS)\nul mkdir $(DOWNLOADS) - + ############################### SRC_ZIP = $(DOWNLOADS)\cv2pdb_src_$(VERSION).zip diff --git a/README b/README index f2df67b..5311130 100644 --- a/README +++ b/README @@ -9,7 +9,7 @@ were created with the Digital Mars DMD compiler, as seamless as possible in current versions of Visual Studio (i.e Visual Studio 2008 and VCExpress). As a side effect, other applications might also benefit from the -converted debug information, like WinDbg. +converted debug information, like WinDbg or DMC. Features -------- @@ -19,6 +19,7 @@ Features * generates generic debug info for dynamic arrays, associative arrays and delegates * autoexp.dat allows convenient display of dynamic and associative arrays in watch windows * demangles function names for convenient display of callstack +* support for DMC CodeView information License information ------------------- @@ -63,13 +64,16 @@ Description: cv2pdb.exe is a command line tool which outputs its usage information if run without arguments: - usage: cv2pdb [-Dversion] [new-exe-file] [pdb-file] + usage: cv2pdb [-Dversion|-C] [new-exe-file] [pdb-file] With the -D option, you can specify the version of the DMD compiler you are using. Unfortunately, this information is not embedded into the debug information. The default is -D2. So far, this information is only needed to determine whether "char[]" or "const char[]" is -translated to "string". +translated to "string". +Option -C tells the program, that you want to debug a program compiled +with DMC, the Digital Mars C/C++ compiler. It will disable some of the +D specific functions and will enable adjustment of stack variable names. The first file name on the command line is expected to be the executable or dynamic library compiled by the DMD compiler and containing the diff --git a/TODO b/TODO index f40c257..774b819 100644 --- a/TODO +++ b/TODO @@ -12,8 +12,6 @@ in the future, but not all have a known solution. but it looks ugly * "this.var" is not a valid debugger expression, you have to use "var" or "this->var" -* strings are displayed zero-terminated, not D style (though display - is often ok) * global/static vars have to be watched with full module and class name specified (e.g. module@globvar) * type of associative arrays is displayed as aa<*> to allow overload @@ -21,5 +19,5 @@ in the future, but not all have a known solution. * DMD does not emit different debug information for const and invariant, type info is the same * type display of delegate does not have arguments -* assoc_array.length cannot be displayed (it is assoc_array.a->length) -* support DMC debug info? +* assoc_array.length cannot be displayed (it is assoc_array.a->nodes) +* enum values not displayed diff --git a/VERSION b/VERSION index ec3d324..29f5f7d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -VERSION = 0.2 +VERSION = 0.3 diff --git a/autoexp.snippet b/autoexp.snippet index 0d9c132..6dd1a3b 100644 --- a/autoexp.snippet +++ b/autoexp.snippet @@ -6,25 +6,44 @@ ;; ;; D types ;; -;; add the content of this file to the [AutoExpand] section -;; of +;; add the content of this file to ;; \Common7\Package\Debugger\autoexp.dat ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; load helper dll dviewhelper.dll to display strings +;; +;; add the following 2 lines to the [AutoExpand] section +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; [AutoExpand] + +string_viewhelper=$ADDIN(dviewhelper.dll,_DStringView@28) +object_viewhelper=$ADDIN(dviewhelper.dll,_DObjectView@28) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; D types visualizer +;; +;; add the remainder of this file to the [Visualizer] section +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; [Visualizer] + ; string: dynamic array of char const char[]|char[]|string { preview ( - #if ($e.data == 0) ( "null" ) - #else ( + #if ($e.data == 0) ( "null" ) + #else ( #( - "[", $e.length, "] ", [$e.data, s] + "[", $e.length, "] ", [$e.__viewhelper] + ;; "[", $e.length, "] ", [$e.data,s] ) ) ) stringview ( - #if ($e.data == 0) ( "null" ) - #else ( + #if ($e.data == 0) ( "null" ) + #else ( #( [$e.data, s] ) @@ -85,7 +104,6 @@ aa<*> { right : right, ; size : $c.size ) : $e - ) ) } @@ -99,10 +117,12 @@ internal@aaA<*,*> { ;; display null references for class objects *@* { - preview( - #( - #if (&$e == 0) ( "null" ) - #else ( [$e,!] ) - ) + preview( + #( + #if (&$e == 0) ( "null" ) + #else ( #( "[", [$e.__viewhelper], "] ", [$e,!] ) ) + ;; #else ( #( [$e,!] ) ) + ) ) } + diff --git a/src/cv2pdb.cpp b/src/cv2pdb.cpp index bb91af7..f2ead36 100644 --- a/src/cv2pdb.cpp +++ b/src/cv2pdb.cpp @@ -446,7 +446,7 @@ int CV2PDB::addFields(codeview_reftype* dfieldlist, const codeview_reftype* fiel break; case LF_STMEMBER_V1: - dfieldtype->stmember_v2.id = v3 ? LF_METHOD_V3 : LF_METHOD_V2; + dfieldtype->stmember_v2.id = v3 ? LF_STMEMBER_V3 : LF_STMEMBER_V2; dfieldtype->stmember_v2.attribute = fieldtype->stmember_v1.attribute; dfieldtype->stmember_v2.type = translateType(fieldtype->stmember_v1.type); pos += sizeof(dfieldtype->stmember_v1) - sizeof(dfieldtype->stmember_v1.p_name); @@ -576,6 +576,34 @@ int CV2PDB::addFieldMember(codeview_fieldtype* dfieldtype, int attr, int offset, return len; } +int CV2PDB::addFieldStaticMember(codeview_fieldtype* dfieldtype, int attr, int type, const char* name) +{ + dfieldtype->stmember_v2.id = v3 ? LF_STMEMBER_V3 : LF_STMEMBER_V2; + dfieldtype->stmember_v2.attribute = attr; + dfieldtype->stmember_v2.type = translateType(type); + int len = cstrcpy_v(v3, (BYTE*)(&dfieldtype->stmember_v2.p_name), name); + len += sizeof (dfieldtype->stmember_v2) - sizeof (dfieldtype->stmember_v2.p_name); + + unsigned char* p = (unsigned char*) dfieldtype; + for (; len & 3; len++) + p[len] = 0xf4 - (len & 3); + return len; +} + +int CV2PDB::addFieldNestedType(codeview_fieldtype* dfieldtype, int type, const char* name) +{ + dfieldtype->nesttype_v2.id = v3 ? LF_NESTTYPE_V3 : LF_NESTTYPE_V2; + dfieldtype->nesttype_v2._pad0 = 0; + dfieldtype->nesttype_v2.type = type; + int len = cstrcpy_v(v3, (BYTE*)(&dfieldtype->nesttype_v2.p_name), name); + len += sizeof (dfieldtype->nesttype_v2) - sizeof(dfieldtype->nesttype_v2.p_name); + + 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) @@ -1078,12 +1106,34 @@ const char* CV2PDB::appendDynamicArray(int indexType, int elemType) checkUserTypeAlloc(); + static char name[256]; + nameOfDynamicArray(indexType, elemType, name, sizeof(name)); + // nextUserType: pointer to elemType cbUserTypes += addPointerType(userTypes + cbUserTypes, elemType); + int dataptrType = nextUserType++; + + int dstringType = 0; + if(strcmp(name, "string") == 0) + { + // nextUserType + 1: field list (size, array) + rdtype = (codeview_reftype*) (userTypes + cbUserTypes); + rdtype->fieldlist.id = LF_FIELDLIST_V2; + int helpfieldlistType = nextUserType++; + + rdtype->fieldlist.len = 2; + cbUserTypes += rdtype->fieldlist.len + 2; + + dtype = (codeview_type*) (userTypes + cbUserTypes); + cbUserTypes += addClass(dtype, 2, helpfieldlistType, 0, 0, 0, 0, "string_viewhelper"); + dstringType = nextUserType++; + addUdtSymbol(dstringType, "string_viewhelper"); + } // nextUserType + 1: field list (size, array) rdtype = (codeview_reftype*) (userTypes + cbUserTypes); rdtype->fieldlist.id = LF_FIELDLIST_V2; + int fieldlistType = nextUserType++; // member indexType length codeview_fieldtype* dfieldtype = (codeview_fieldtype*)rdtype->fieldlist.list; @@ -1091,20 +1141,24 @@ const char* CV2PDB::appendDynamicArray(int indexType, int elemType) // member elemType* data[] dfieldtype = (codeview_fieldtype*)(rdtype->fieldlist.list + len1); - int len2 = addFieldMember(dfieldtype, 1, 4, nextUserType, "data"); + int len2 = addFieldMember(dfieldtype, 1, 4, dataptrType, "data"); + int numElem = 2; rdtype->fieldlist.len = len1 + len2 + 2; - cbUserTypes += rdtype->fieldlist.len + 2; - static char name[256]; - nameOfDynamicArray(indexType, elemType, name, sizeof(name)); + if(strcmp(name, "string") == 0) + { + dfieldtype = (codeview_fieldtype*)(rdtype->fieldlist.list + rdtype->fieldlist.len - 2); + rdtype->fieldlist.len = addFieldMember(dfieldtype, 1, 0, dstringType, "__viewhelper"); + numElem++; + } - // nextUserType + 2: struct + cbUserTypes += rdtype->fieldlist.len + 2; dtype = (codeview_type*) (userTypes + cbUserTypes); - cbUserTypes += addClass(dtype, 2, nextUserType + 1, 0, 0, 0, 8, name); + cbUserTypes += addClass(dtype, numElem, fieldlistType, 0, 0, 0, 8, name); + int udType = nextUserType++; - nextUserType += 3; - addUdtSymbol(nextUserType - 1, name); + addUdtSymbol(udType, name); return name; } @@ -1291,53 +1345,65 @@ int CV2PDB::appendObjectType (int object_derived_type) checkUserTypeAlloc(); // append object type info - int typeNo = nextUserType; - codeview_reftype* rdtype = (codeview_reftype*) (userTypes + cbUserTypes); - + codeview_reftype* rdtype; + codeview_type* dtype; + + int viewHelperType = 0; + bool addViewHelper = true; + if(addViewHelper) + { + rdtype = (codeview_reftype*) (userTypes + cbUserTypes); + rdtype->fieldlist.id = LF_FIELDLIST_V2; + int helpfieldlistType = nextUserType++; + rdtype->fieldlist.len = 2; + cbUserTypes += rdtype->fieldlist.len + 2; + + dtype = (codeview_type*) (userTypes + cbUserTypes); + cbUserTypes += addClass(dtype, 2, helpfieldlistType, 0, 0, 0, 0, "object_viewhelper"); + viewHelperType = nextUserType++; + addUdtSymbol(viewHelperType, "object_viewhelper"); + } + // vtable + rdtype = (codeview_reftype*) (userTypes + cbUserTypes); rdtype->generic.len = 6; rdtype->generic.id = LF_VTSHAPE_V1; ((unsigned short*) (&rdtype->generic + 1))[0] = 1; ((unsigned short*) (&rdtype->generic + 1))[1] = 0xf150; cbUserTypes += rdtype->generic.len + 2; + int vtableType = nextUserType++; // vtable* - codeview_type* dtype = (codeview_type*) (userTypes + cbUserTypes); - dtype->pointer_v2.id = LF_POINTER_V2; - dtype->pointer_v2.len = 10; - dtype->pointer_v2.datatype = typeNo; - dtype->pointer_v2.attribute = 0x800A; - cbUserTypes += dtype->generic.len + 2; + dtype = (codeview_type*) (userTypes + cbUserTypes); + cbUserTypes += addPointerType(dtype, vtableType); + int vtablePtrType = nextUserType++; // field list rdtype = (codeview_reftype*) (userTypes + cbUserTypes); rdtype->fieldlist.id = LF_FIELDLIST_V2; + codeview_fieldtype* dfieldtype = (codeview_fieldtype*)rdtype->fieldlist.list; dfieldtype->vfunctab_v2.id = LF_VFUNCTAB_V2; // id correct? dfieldtype->vfunctab_v2._pad0 = 0; - dfieldtype->vfunctab_v2.type = typeNo + 1; // vtable* + dfieldtype->vfunctab_v2.type = vtablePtrType; // vtable* rdtype->fieldlist.len = sizeof(dfieldtype->vfunctab_v2) + 2; + int numElem = 1; + + if(addViewHelper) + { + dfieldtype = (codeview_fieldtype*)(rdtype->fieldlist.list + rdtype->fieldlist.len - 2); + rdtype->fieldlist.len += addFieldMember(dfieldtype, 1, 0, viewHelperType, "__viewhelper"); + numElem++; + } + cbUserTypes += rdtype->generic.len + 2; + int fieldListType = nextUserType++; #define OBJECT_SYMBOL "object@Object" dtype = (codeview_type*) (userTypes + cbUserTypes); - dtype->struct_v2.id = v3 ? LF_CLASS_V3 : LF_CLASS_V2; - dtype->struct_v2.n_element = 1; - dtype->struct_v2.fieldlist = typeNo + 2; - dtype->struct_v2.property = 0; - dtype->struct_v2.derived = object_derived_type; - dtype->struct_v2.vshape = typeNo; - dtype->struct_v2.structlen = 4; - int len = cstrcpy_v (v3, (BYTE*) (&dtype->struct_v2 + 1), OBJECT_SYMBOL); - len += sizeof (dtype->struct_v2); - for (; len & 3; len++) - userTypes[cbUserTypes + len] = 0xf4 - (len & 3); - dtype->struct_v2.len = len - 2; - cbUserTypes += dtype->generic.len + 2; - - objectType = typeNo + 3; - nextUserType += 4; + cbUserTypes += addClass(dtype, numElem, fieldListType, 0, object_derived_type, vtableType, 4, OBJECT_SYMBOL); + objectType = nextUserType++; addUdtSymbol(objectType, OBJECT_SYMBOL); return objectType; @@ -1398,7 +1464,7 @@ bool CV2PDB::initGlobalTypes() codeview_reftype* rdtype = (codeview_reftype*) (globalTypes + cbGlobalTypes); // for debugging, cancel special processing after the limit - unsigned int typeLimit = 0x7fffffff; + unsigned int typeLimit = 0x7fffffff; // 0x1ddd; // if (t > typeLimit) { dtype->pointer_v2.id = LF_POINTER_V2; @@ -1483,7 +1549,7 @@ bool CV2PDB::initGlobalTypes() len += leaf_len + sizeof(dtype->struct_v2) - sizeof(type->struct_v2.structlen); // remember type index of derived list for object.Object - if (type->struct_v1.derived) + if (Dversion > 0 && type->struct_v1.derived) if (memcmp((char*) &type->struct_v1.structlen + leaf_len, "\x0dobject.Object", 14) == 0) object_derived_type = type->struct_v1.derived; break; @@ -1503,11 +1569,12 @@ bool CV2PDB::initGlobalTypes() case LF_POINTER_V1: dtype->pointer_v2.id = LF_POINTER_V2; dtype->pointer_v2.datatype = translateType(type->pointer_v1.datatype); - if (type->pointer_v1.datatype >= 0x1000 && (type->pointer_v1.attribute & 0xE0) == 0) + if (Dversion > 0 && type->pointer_v1.datatype >= 0x1000 + && (type->pointer_v1.attribute & 0xE0) == 0) { if (thisIsNotRef) // const pointer for this pointerTypes[t] = appendPointerType(type->pointer_v1.datatype, - type->pointer_v1.attribute | 0x400); + type->pointer_v1.attribute | 0x400); dtype->pointer_v2.attribute = type->pointer_v1.attribute | 0x20; // convert to reference } else @@ -1611,6 +1678,14 @@ bool CV2PDB::initGlobalTypes() len = sizeof(dtype->modifier_v2); break; + case LF_BITFIELD_V1: + rdtype->bitfield_v2.id = LF_BITFIELD_V2; + rdtype->bitfield_v2.nbits = rtype->bitfield_v1.nbits; + rdtype->bitfield_v2.bitoff = rtype->bitfield_v1.bitoff; + rdtype->bitfield_v2.type = translateType(rtype->bitfield_v1.type); + len = sizeof(rdtype->bitfield_v2); + break; + default: memcpy(dtype, type, len); break; @@ -1624,7 +1699,8 @@ bool CV2PDB::initGlobalTypes() } #if 1 - appendObjectType (object_derived_type); + if(Dversion > 0) + appendObjectType (object_derived_type); #endif #if 1 if (cbGlobalTypes + cbUserTypes > allocGlobalTypes) @@ -1695,17 +1771,19 @@ bool CV2PDB::addSrcLines() int segoff = lnSegStartEnd[2*s]; int seglength = lnSegStartEnd[2*s + 1] - segoff; + int cnt = sourceLine->cLnOff; - mspdb::LineInfoEntry* lineInfo = new mspdb::LineInfoEntry[sourceLine->cLnOff]; - for (int ln = 0; ln < sourceLine->cLnOff; ln++) + mspdb::LineInfoEntry* lineInfo = new mspdb::LineInfoEntry[cnt]; + for (int ln = 0; ln < cnt; ln++) { lineInfo[ln].offset = sourceLine->offset[ln] - segoff; lineInfo[ln].line = lineNo[ln] - lineNo[0]; } int rc = mod->AddLines(name, sourceLine->Seg, segoff, seglength, segoff, lineNo[0], - (unsigned char*) lineInfo, sourceLine->cLnOff * sizeof(*lineInfo)); + (unsigned char*) lineInfo, cnt * sizeof(*lineInfo)); if (rc <= 0) return setError("cannot add line number info to module"); + delete [] lineInfo; } } } @@ -1872,6 +1950,23 @@ int CV2PDB::copySymbols(BYTE* srcSymbols, int srcSize, BYTE* destSymbols, int de type = pointerTypes[type - 0x1000]; } } + else if(Dversion == 0) + { + int p = -1; + for(int i = 0; i < dsym->stack_v1.p_name.namelen; i++) + if(dsym->stack_v1.p_name.name[i] == ':') + p = i + 1; + if(p > 0) + { + for(int i = p; i < dsym->stack_v1.p_name.namelen; i++) + dsym->stack_v1.p_name.name[i - p] = dsym->stack_v1.p_name.name[i]; + dsym->stack_v1.p_name.namelen -= p; + destlength = sizeof(dsym->stack_v1) + dsym->stack_v1.p_name.namelen - 1; + for (; destlength & 3; destlength++) + destSymbols[destSize + destlength] = 0; + dsym->stack_v1.len = destlength - 2; + } + } dsym->stack_v1.symtype = translateType(type); //sym->stack_v1.symtype = 0x1012; break; @@ -1889,18 +1984,24 @@ int CV2PDB::copySymbols(BYTE* srcSymbols, int srcSize, BYTE* destSymbols, int de case S_PROCREF_V1: case S_DATAREF_V1: case S_LPROCREF_V1: - // dmd does not add a string, but it's not obvious to detect whether it exists or not - if (dsym->procref_v1.len != sizeof(dsym->procref_v1) - 4) - break; - - dsym->procref_v1.p_name.namelen = 0; - memset (dsym->procref_v1.p_name.name, 0, 3); // also 4-byte alignment assumed - destSize += 4; + if(Dversion > 0) + { + // dmd does not add a string, but it's not obvious to detect whether it exists or not + if (dsym->procref_v1.len != sizeof(dsym->procref_v1) - 4) + break; + + dsym->procref_v1.p_name.namelen = 0; + memset (dsym->procref_v1.p_name.name, 0, 3); // also 4-byte alignment assumed + destlength += 4; + } + else + // throw entry away, it's use is unknown anyway, and it causes a lot of trouble + destlength = 0; break; case S_CONSTANT_V1: dsym->constant_v2.id = v3 ? S_CONSTANT_V3 : S_CONSTANT_V2; - dsym->constant_v2.type = sym->constant_v1.type; + dsym->constant_v2.type = translateType(sym->constant_v1.type); leaf_len = numeric_leaf(&value, &sym->constant_v1.cvalue); memcpy(&dsym->constant_v2.cvalue, &sym->constant_v1.cvalue, leaf_len); destlength = pstrcpy_v (v3, (BYTE*) &dsym->constant_v2.cvalue + leaf_len, diff --git a/src/cv2pdb.h b/src/cv2pdb.h index a900e6c..fec2dff 100644 --- a/src/cv2pdb.h +++ b/src/cv2pdb.h @@ -47,6 +47,8 @@ public: int addPointerType(unsigned char* dtype, int type, int attr = 0x800A); 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); void checkUserTypeAlloc(int size = 1000, int add = 10000); diff --git a/src/cv2pdb.sln b/src/cv2pdb.sln index 451ef68..e83abbb 100644 --- a/src/cv2pdb.sln +++ b/src/cv2pdb.sln @@ -3,6 +3,20 @@ Microsoft Visual Studio Solution File, Format Version 10.00 # Visual Studio 2008 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cv2pdb", "cv2pdb.vcproj", "{5E2BD27D-446A-4C99-9829-135F7C000D90}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dviewhelper", "dviewhelper\dviewhelper.vcproj", "{E4424774-A7A0-4502-8626-2723904D70EA}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{7F4A9B6A-05A2-45D0-AFC3-3754B7FB77B9}" + ProjectSection(SolutionItems) = preProject + ..\autoexp.snippet = ..\autoexp.snippet + ..\CHANGES = ..\CHANGES + ..\INSTALL = ..\INSTALL + ..\LICENSE = ..\LICENSE + ..\Makefile = ..\Makefile + ..\README = ..\README + ..\TODO = ..\TODO + ..\VERSION = ..\VERSION + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -13,6 +27,10 @@ Global {5E2BD27D-446A-4C99-9829-135F7C000D90}.Debug|Win32.Build.0 = Debug|Win32 {5E2BD27D-446A-4C99-9829-135F7C000D90}.Release|Win32.ActiveCfg = Release|Win32 {5E2BD27D-446A-4C99-9829-135F7C000D90}.Release|Win32.Build.0 = Release|Win32 + {E4424774-A7A0-4502-8626-2723904D70EA}.Debug|Win32.ActiveCfg = Debug|Win32 + {E4424774-A7A0-4502-8626-2723904D70EA}.Debug|Win32.Build.0 = Debug|Win32 + {E4424774-A7A0-4502-8626-2723904D70EA}.Release|Win32.ActiveCfg = Release|Win32 + {E4424774-A7A0-4502-8626-2723904D70EA}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/dviewhelper/dviewhelper.cpp b/src/dviewhelper/dviewhelper.cpp new file mode 100644 index 0000000..594c231 --- /dev/null +++ b/src/dviewhelper/dviewhelper.cpp @@ -0,0 +1,110 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// DViewHelper - Expression Evaluator for the D string and object class +// Copyright (c) 2009 by Rainer Schuetze, All Rights Reserved +// +// License for redistribution is given by the Artistic License 2.0 +// see file LICENSE for further details +// +// Compile the DLL and add this to AUTOEXP.DAT in section [AutoExpand] +// string=$ADDIN(\dviewhelper.dll,_DStringView@28) +// +/////////////////////////////////////////////////////////////////////////////// + +#define _CRT_SECURE_NO_WARNINGS + +#include +#include + +extern "C" { + +// Copied from MSDN +struct DEBUGHELPER +{ + DWORD dwVersion; + BOOL (WINAPI *ReadDebuggeeMemory)(DEBUGHELPER *pThis, DWORD dwAddr, DWORD nWant, VOID* pWhere, DWORD *nGot); + // from here only when dwVersion >= 0x20000 + DWORDLONG (WINAPI *GetRealAddress)(DEBUGHELPER *pThis); + BOOL (WINAPI *ReadDebuggeeMemoryEx)(DEBUGHELPER *pThis, DWORDLONG qwAddr, DWORD nWant, VOID* pWhere, DWORD *nGot); + int (WINAPI *GetProcessorType)(DEBUGHELPER *pThis); +}; + +struct DString +{ + DWORD length; + DWORD data; +}; + +__declspec(dllexport) +HRESULT WINAPI DStringView(DWORD dwAddress, DEBUGHELPER *pHelper, int nBase, BOOL bUniStrings, + char *pResult, size_t max, DWORD reserved) +{ + // Get the string struct + DString dstr; + DWORD read; + if (pHelper->ReadDebuggeeMemory(pHelper, dwAddress, sizeof(dstr), &dstr, &read) != S_OK) + { + strncpy(pResult,"Cannot access struct", max); + return S_OK; + } + if (dstr.length == 0) + { + strncpy(pResult,"\"\"", max); + return S_OK; + } + + DWORD cnt = (dstr.length < max - 3 ? dstr.length : max - 3); + if (pHelper->ReadDebuggeeMemory(pHelper, dstr.data, cnt, pResult + 1, &read) != S_OK) + { + strncpy(pResult,"Cannot access data", max); + return S_OK; + } + + pResult[0] = '\"'; + pResult[cnt+1] = '\"'; + pResult[cnt+2] = 0; + return S_OK; +} + +__declspec(dllexport) +HRESULT WINAPI DObjectView(DWORD dwAddress, DEBUGHELPER *pHelper, int nBase, BOOL bUniStrings, + char *pResult, size_t max, DWORD reserved) +{ + if(dwAddress == 0) + { + strncpy(pResult,"null", max); + return S_OK; + } + + DWORD read; + DWORD vtablePtr; + if (pHelper->ReadDebuggeeMemory(pHelper, dwAddress, sizeof(vtablePtr), &vtablePtr, &read) != S_OK) + { + strncpy(pResult,"Cannot access object", max); + return S_OK; + } + DWORD classinfoPtr; + if (pHelper->ReadDebuggeeMemory(pHelper, vtablePtr, sizeof(vtablePtr), &classinfoPtr, &read) != S_OK) + { + strncpy(pResult,"Cannot access vtable", max); + return S_OK; + } + DString dstr; + if (pHelper->ReadDebuggeeMemory(pHelper, classinfoPtr + 16, sizeof(dstr), &dstr, &read) != S_OK) + { + strncpy(pResult,"Cannot access class info", max); + return S_OK; + } + + DWORD cnt = (dstr.length < max - 1 ? dstr.length : max - 1); + if (pHelper->ReadDebuggeeMemory(pHelper, dstr.data, cnt, pResult, &read) != S_OK) + { + strncpy(pResult,"Cannot access name data", max); + return S_OK; + } + + pResult[cnt] = 0; + return S_OK; +} + +} // extern "C" \ No newline at end of file diff --git a/src/dviewhelper/dviewhelper.vcproj b/src/dviewhelper/dviewhelper.vcproj new file mode 100644 index 0000000..67e1907 --- /dev/null +++ b/src/dviewhelper/dviewhelper.vcproj @@ -0,0 +1,186 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main.cpp b/src/main.cpp index 16dbb34..fb80f30 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -101,6 +101,8 @@ int main(int argc, char** argv) break; if (argv[0][1] == 'D') Dversion = strtod (argv[0] + 2, 0); + else if (argv[0][1] == 'C') + Dversion = 0; else fatal("unknwon option: %s", argv[0]); } -- cgit v0.12