From 9d2eeda0383fa55a8dea58f4d6960bb110e77c56 Mon Sep 17 00:00:00 2001 From: Rainer Schuetze Date: Wed, 3 May 2017 12:27:08 +0200 Subject: [PATCH 1/2] fix issue 4014 - add option to add debug info for all referenced types --- src/ddmd/backend/cgcv.c | 2 +- src/ddmd/globals.d | 1 + src/ddmd/globals.h | 1 + src/ddmd/mars.d | 7 +++++++ src/ddmd/toctype.d | 43 +++++++++++++++++++++++++++++++---------- src/ddmd/tocvdebug.d | 11 +++++------ src/ddmd/toobj.d | 17 ++++++++++++---- 7 files changed, 61 insertions(+), 21 deletions(-) diff --git a/src/ddmd/backend/cgcv.c b/src/ddmd/backend/cgcv.c index 159681a59379..8b4b751e63aa 100644 --- a/src/ddmd/backend/cgcv.c +++ b/src/ddmd/backend/cgcv.c @@ -1827,7 +1827,7 @@ unsigned cv4_typidx(type *t) { // This is a hack to duplicate bugs in VC, so that the VC // debugger will work. - tymnext = t->Tnext->Tty; + tymnext = t->Tnext ? t->Tnext->Tty : TYint; if (tymnext & (mTYconst | mTYimmutable | mTYvolatile) && !tycv && tyarithmetic(tymnext) && diff --git a/src/ddmd/globals.d b/src/ddmd/globals.d index 2921b0638094..a7a143632f61 100644 --- a/src/ddmd/globals.d +++ b/src/ddmd/globals.d @@ -81,6 +81,7 @@ struct Param bool vfield; // identify non-mutable field variables bool vcomplex; // identify complex/imaginary type usage ubyte symdebug; // insert debug symbolic information + bool symdebugref; // insert debug information for all referenced types, too bool alwaysframe; // always emit standard stack frame bool optimize; // run optimizer bool map; // generate linker .map file diff --git a/src/ddmd/globals.h b/src/ddmd/globals.h index 4fdcf0a3b583..248ba1e81756 100644 --- a/src/ddmd/globals.h +++ b/src/ddmd/globals.h @@ -70,6 +70,7 @@ struct Param bool vfield; // identify non-mutable field variables bool vcomplex; // identify complex/imaginary type usage char symdebug; // insert debug symbolic information + bool symdebugref; // insert debug information for all referenced types, too bool alwaysframe; // always emit standard stack frame bool optimize; // run optimizer bool map; // generate linker .map file diff --git a/src/ddmd/mars.d b/src/ddmd/mars.d index ca711ed9a32e..717a8e3ffdb9 100644 --- a/src/ddmd/mars.d +++ b/src/ddmd/mars.d @@ -134,6 +134,7 @@ Where: -dip25 implement http://wiki.dlang.org/DIP25 (experimental) -dip1000 implement http://wiki.dlang.org/DIP1000 (experimental) -g add symbolic debug info + -gf emit debug info for all referenced types -gs always emit stack frame -gx add stack stomp code -H generate 'header' file @@ -470,6 +471,12 @@ private int tryMain(size_t argc, const(char)** argv) deprecation(loc, "use -g instead of -gc"); global.params.symdebug = 2; } + else if (strcmp(p + 1, "gf") == 0) + { + if (!global.params.symdebug) + global.params.symdebug = 1; + global.params.symdebugref = true; + } else if (strcmp(p + 1, "gs") == 0) global.params.alwaysframe = true; else if (strcmp(p + 1, "gx") == 0) diff --git a/src/ddmd/toctype.d b/src/ddmd/toctype.d index a36b3c62056b..fef7e0e54214 100644 --- a/src/ddmd/toctype.d +++ b/src/ddmd/toctype.d @@ -22,6 +22,7 @@ import ddmd.globals; import ddmd.glue; import ddmd.id; import ddmd.mtype; +import ddmd.tocvdebug; import ddmd.visitor; extern (C++) final class ToCtypeVisitor : Visitor @@ -143,6 +144,10 @@ public: symbol_struct_addField(cast(Symbol*)t.ctype.Ttag, v.ident.toChars(), Type_toCtype(v.type), v.offset); } } + + if (global.params.symdebugref) + toDebug(sym); + return; } @@ -176,6 +181,10 @@ public: { t.ctype = Type_toCtype(t.sym.memtype); } + + if (global.params.symdebugref) + toDebug(t.sym); + return; } @@ -194,25 +203,39 @@ public: } else t.ctype = mctype; + //printf("t = %p, Tflags = x%x\n", t, t.Tflags); } override void visit(TypeClass t) { - //printf("TypeClass::toCtype() %s\n", toChars()); - type* tc = type_struct_class(t.sym.toPrettyChars(true), t.sym.alignsize, t.sym.structsize, null, null, false, true, true); - t.ctype = type_pointer(tc); - /* Add in fields of the class - * (after setting ctype to avoid infinite recursion) - */ - if (global.params.symdebug) + if (t.mod == 0) { - for (size_t i = 0; i < t.sym.fields.dim; i++) + //printf("TypeClass::toCtype() %s\n", toChars()); + type* tc = type_struct_class(t.sym.toPrettyChars(true), t.sym.alignsize, t.sym.structsize, null, null, false, true, true); + t.ctype = type_pointer(tc); + /* Add in fields of the class + * (after setting ctype to avoid infinite recursion) + */ + if (global.params.symdebug) { - VarDeclaration v = t.sym.fields[i]; - symbol_struct_addField(cast(Symbol*)tc.Ttag, v.ident.toChars(), Type_toCtype(v.type), v.offset); + for (size_t i = 0; i < t.sym.fields.dim; i++) + { + VarDeclaration v = t.sym.fields[i]; + symbol_struct_addField(cast(Symbol*)tc.Ttag, v.ident.toChars(), Type_toCtype(v.type), v.offset); + } } + + if (global.params.symdebugref) + toDebug(t.sym); + return; } + + // Copy mutable version of backend type and add modifiers + type* mctype = Type_toCtype(t.castMod(0)); + t.ctype = type_alloc(tybasic(mctype.Tty)); // pointer to class instance + t.ctype.Tcount++; + addMod(t); } } diff --git a/src/ddmd/tocvdebug.d b/src/ddmd/tocvdebug.d index 1bc87b2142fa..8472a73e3135 100644 --- a/src/ddmd/tocvdebug.d +++ b/src/ddmd/tocvdebug.d @@ -35,6 +35,7 @@ import ddmd.globals; import ddmd.id; import ddmd.mtype; import ddmd.target; +import ddmd.toctype; import ddmd.visitor; import ddmd.backend.cc; @@ -51,10 +52,6 @@ import ddmd.backend.type; extern (C++): - -type *Type_toCtype(Type t); -int cvMember(Dsymbol s, ubyte *p); - /* The CV4 debug format is defined in: * "CV4 Symbolic Debug Information Specification" * rev 3.1 March 5, 1993 @@ -855,8 +852,10 @@ int cvMember(Dsymbol s, ubyte *p) { //printf("FuncDeclaration.cvMember() '%s'\n", fd.toChars()); - if (!fd.type) // if not compiled in, - return; // skip it + if (!fd.type) // if not compiled in, + return; // skip it + if (!fd.type.nextOf()) // if not fully analyzed (e.g. auto return type) + return; // skip it const id = fd.toChars(); diff --git a/src/ddmd/toobj.d b/src/ddmd/toobj.d index 98efe39a3442..67fdd26201ea 100644 --- a/src/ddmd/toobj.d +++ b/src/ddmd/toobj.d @@ -46,6 +46,7 @@ import ddmd.statement; import ddmd.staticassert; import ddmd.target; import ddmd.tocsym; +import ddmd.toctype; import ddmd.tocvdebug; import ddmd.todt; import ddmd.tokens; @@ -327,7 +328,9 @@ void toObjFile(Dsymbol ds, bool multiobj) return; } - if (global.params.symdebug) + if (global.params.symdebugref) + Type_toCtype(cd.type); // calls toDebug() only once + else if (global.params.symdebug) toDebug(cd); assert(cd.semanticRun >= PASSsemantic3done); // semantic() should have been run to completion @@ -646,7 +649,9 @@ void toObjFile(Dsymbol ds, bool multiobj) if (!id.members) return; - if (global.params.symdebug) + if (global.params.symdebugref) + Type_toCtype(id.type); // calls toDebug() only once + else if (global.params.symdebug) toDebug(id); enum_SC scclass = SCcomdat; @@ -828,7 +833,9 @@ void toObjFile(Dsymbol ds, bool multiobj) // do not output forward referenced structs's if (!sd.isAnonymous() && sd.members) { - if (global.params.symdebug) + if (global.params.symdebugref) + Type_toCtype(sd.type); // calls toDebug() only once + else if (global.params.symdebug) toDebug(sd); genTypeInfo(sd.type, null); @@ -987,7 +994,9 @@ void toObjFile(Dsymbol ds, bool multiobj) if (ed.isAnonymous()) return; - if (global.params.symdebug) + if (global.params.symdebugref) + Type_toCtype(ed.type); // calls toDebug() only once + else if (global.params.symdebug) toDebug(ed); genTypeInfo(ed.type, null); From bfc2e597cc78962c104c7176c87ce8eca89ac7e6 Mon Sep 17 00:00:00 2001 From: Rainer Schuetze Date: Sat, 17 Jun 2017 11:53:18 +0200 Subject: [PATCH 2/2] add test for debug info reading PDB --- test/runnable/testpdb.d | 714 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 714 insertions(+) create mode 100644 test/runnable/testpdb.d diff --git a/test/runnable/testpdb.d b/test/runnable/testpdb.d new file mode 100644 index 000000000000..053e19ad900e --- /dev/null +++ b/test/runnable/testpdb.d @@ -0,0 +1,714 @@ +// REQUIRED_ARGS: -gf +import core.time; + +void main(string[] args) +{ + // https://issues.dlang.org/show_bug.cgi?id=4014 + // -gf should drag in full definitions of Object, TickDuration and ClockType + Object o = new Object; + TickDuration duration; // struct + ClockType ct; // enumerator + + version (CRuntime_Microsoft) + { + IDiaDataSource source; + IDiaSession session; + IDiaSymbol globals; + if (!openDebugInfo(&source, &session, &globals)) + { + printf("failed to access debug info, skipping further tests.\n"); + return; + } + + // dumpSymbols(globals, SymTagEnum.SymTagNull, null, 0); + + IDiaSymbol objsym = searchSymbol(globals, "object.Object"); + testSymbolHasChildren(objsym, "object.Object"); + objsym.Release(); + + IDiaSymbol ticksym = searchSymbol(globals, "core.time.TickDuration"); + testSymbolHasChildren(ticksym, "core.time.TickDuration"); + ticksym.Release(); + + IDiaSymbol ctsym = searchSymbol(globals, "core.time.ClockType"); + testSymbolHasChildren(ctsym, "core.time.ClockType"); + ctsym.Release(); + + source.Release(); + session.Release(); + globals.Release(); + } +} + +version(CRuntime_Microsoft): + +void testSymbolHasChildren(IDiaSymbol sym, string name) +{ + sym || assert(false, "no debug info found for " ~ name); + + LONG count; + IDiaEnumSymbols enumSymbols; + HRESULT hr = sym.findChildren(SymTagEnum.SymTagNull, null, NameSearchOptions.nsNone, &enumSymbols); + hr == S_OK || assert(false, "incomplete debug info for " ~ name); + enumSymbols.get_Count(&count) == S_OK || assert(false); + count > 0 || assert(false, "incomplete debug info for " ~ name); + + enumSymbols.Release(); +} + +import core.stdc.stdio; +import core.stdc.wchar_; + +import core.sys.windows.windows; +import core.sys.windows.wtypes; +import core.sys.windows.objbase; +import core.sys.windows.unknwn; + +pragma(lib, "ole32.lib"); +pragma(lib, "oleaut32.lib"); + +// defintions translated from the DIA SDK header dia2.h +GUID uuid_DiaSource_V120 = { 0xe6756135, 0x1e65, 0x4d17, [0x85, 0x76, 0x61, 0x07, 0x61, 0x39, 0x8c, 0x3c] }; +GUID uuid_DiaSource_V140 = { 0x3bfcea48, 0x620f, 0x4b6b, [0x81, 0xf7, 0xb9, 0xaf, 0x75, 0x45, 0x4c, 0x7d] }; + +interface IDiaDataSource : IUnknown +{ + static const GUID iid = { 0x79F1BB5F, 0xB66E, 0x48e5, [0xB6, 0xA9, 0x15, 0x45, 0xC3, 0x23, 0xCA, 0x3D] }; + + HRESULT get_lastError(BSTR* pRetVal); + HRESULT loadDataFromPdb(LPCOLESTR pdbPath); + HRESULT loadAndValidateDataFromPdb(LPCOLESTR pdbPath, GUID* pcsig70, DWORD sig, + DWORD age); + HRESULT loadDataForExe(LPCOLESTR executable, LPCOLESTR searchPath, IUnknown pCallback); + HRESULT loadDataFromIStream(IStream pIStream); + HRESULT openSession(IDiaSession* ppSession); + HRESULT loadDataFromCodeViewInfo(LPCOLESTR executable, + LPCOLESTR searchPath, DWORD cbCvInfo, BYTE* pbCvInfo, IUnknown pCallback); + HRESULT loadDataFromMiscInfo(LPCOLESTR executable, + LPCOLESTR searchPath, DWORD timeStampExe, DWORD timeStampDbg, + DWORD sizeOfExe, DWORD cbMiscInfo, BYTE* pbMiscInfo, IUnknown pCallback); +} + +interface IDiaSession : IUnknown +{ +public: + static const GUID iid = { 0x2F609EE1, 0xD1C8, 0x4E24, [0x82, 0x88, 0x33, 0x26, 0xBA, 0xDC, 0xD2, 0x11] }; + + HRESULT get_loadAddress(ULONGLONG* pRetVal); + HRESULT put_loadAddress(ULONGLONG NewVal); + HRESULT get_globalScope(IDiaSymbol* pRetVal); + HRESULT getEnumTables(IDiaEnumTables* ppEnumTables); + HRESULT getSymbolsByAddr(IDiaEnumSymbolsByAddr* ppEnumbyAddr); + HRESULT findChildren(IDiaSymbol parent, SymTagEnum symtag, + LPCOLESTR name, DWORD compareFlags, IDiaEnumSymbols* ppResult); + HRESULT findChildrenEx(IDiaSymbol parent, SymTagEnum symtag, + LPCOLESTR name, DWORD compareFlags, IDiaEnumSymbols* ppResult); + HRESULT findChildrenExByAddr(IDiaSymbol parent, SymTagEnum symtag, LPCOLESTR name, + DWORD compareFlags, DWORD isect, DWORD offset, IDiaEnumSymbols* ppResult); + HRESULT findChildrenExByVA(IDiaSymbol parent, SymTagEnum symtag, + LPCOLESTR name, DWORD compareFlags, ULONGLONG va, + IDiaEnumSymbols* ppResult); + HRESULT findChildrenExByRVA(IDiaSymbol parent, SymTagEnum symtag, + LPCOLESTR name, DWORD compareFlags, DWORD rva, IDiaEnumSymbols* ppResult); + HRESULT findSymbolByAddr(DWORD isect, DWORD offset, + SymTagEnum symtag, IDiaSymbol* ppSymbol); + HRESULT findSymbolByRVA(DWORD rva, SymTagEnum symtag, IDiaSymbol* ppSymbol); + HRESULT findSymbolByVA(ULONGLONG va, SymTagEnum symtag, IDiaSymbol* ppSymbol); + HRESULT findSymbolByToken(ULONG token, SymTagEnum symtag, IDiaSymbol* ppSymbol); + HRESULT symsAreEquiv(IDiaSymbol symbolA, IDiaSymbol symbolB); + HRESULT symbolById(DWORD id, IDiaSymbol* ppSymbol); + HRESULT findSymbolByRVAEx(DWORD rva, SymTagEnum symtag, + IDiaSymbol* ppSymbol, LONG* displacement); + HRESULT findSymbolByVAEx(ULONGLONG va, SymTagEnum symtag, + IDiaSymbol* ppSymbol, LONG* displacement); + HRESULT findFile(IDiaSymbol pCompiland, LPCOLESTR name, + DWORD compareFlags, IDiaEnumSourceFiles* ppResult); + HRESULT findFileById(DWORD uniqueId, IDiaSourceFile* ppResult); + HRESULT findLines(IDiaSymbol compiland, IDiaSourceFile file, + IDiaEnumLineNumbers* ppResult); + HRESULT findLinesByAddr(DWORD seg, DWORD offset, DWORD length, + IDiaEnumLineNumbers* ppResult); + HRESULT findLinesByRVA(DWORD rva, DWORD length, IDiaEnumLineNumbers* ppResult); + HRESULT findLinesByVA(ULONGLONG va, DWORD length, IDiaEnumLineNumbers* ppResult); + HRESULT findLinesByLinenum(IDiaSymbol compiland, IDiaSourceFile file, + DWORD linenum, DWORD column, IDiaEnumLineNumbers* ppResult); + HRESULT findInjectedSource(LPCOLESTR srcFile, IDiaEnumInjectedSources* ppResult); + HRESULT getEnumDebugStreams(IDiaEnumDebugStreams* ppEnumDebugStreams); + HRESULT findInlineFramesByAddr(IDiaSymbol parent, DWORD isect, + DWORD offset, IDiaEnumSymbols* ppResult); + HRESULT findInlineFramesByRVA(IDiaSymbol parent, DWORD rva, + IDiaEnumSymbols* ppResult); + HRESULT findInlineFramesByVA(IDiaSymbol parent, ULONGLONG va, + IDiaEnumSymbols* ppResult); + HRESULT findInlineeLines(IDiaSymbol parent, IDiaEnumLineNumbers* ppResult); + HRESULT findInlineeLinesByAddr(IDiaSymbol parent, DWORD isect, + DWORD offset, DWORD length, IDiaEnumLineNumbers* ppResult); + HRESULT findInlineeLinesByRVA(IDiaSymbol parent, DWORD rva, + DWORD length, IDiaEnumLineNumbers* ppResult); + HRESULT findInlineeLinesByVA(IDiaSymbol parent, ULONGLONG va, + DWORD length, IDiaEnumLineNumbers* ppResult); + HRESULT findInlineeLinesByLinenum(IDiaSymbol compiland, IDiaSourceFile file, + DWORD linenum, DWORD column, IDiaEnumLineNumbers* ppResult); + HRESULT findInlineesByName(LPCOLESTR name, DWORD option, IDiaEnumSymbols* ppResult); + HRESULT findAcceleratorInlineeLinesByLinenum(IDiaSymbol parent, + IDiaSourceFile file, DWORD linenum, DWORD column, + IDiaEnumLineNumbers* ppResult); + HRESULT findSymbolsForAcceleratorPointerTag(IDiaSymbol parent, + DWORD tagValue, IDiaEnumSymbols* ppResult); + HRESULT findSymbolsByRVAForAcceleratorPointerTag(IDiaSymbol parent, + DWORD tagValue, DWORD rva, IDiaEnumSymbols* ppResult); + HRESULT findAcceleratorInlineesByName(LPCOLESTR name, + DWORD option, IDiaEnumSymbols* ppResult); + HRESULT addressForVA(ULONGLONG va, DWORD* pISect, DWORD* pOffset); + HRESULT addressForRVA(DWORD rva, DWORD* pISect, DWORD* pOffset); + HRESULT findILOffsetsByAddr(DWORD isect, DWORD offset, + DWORD length, IDiaEnumLineNumbers* ppResult); + HRESULT findILOffsetsByRVA(DWORD rva, DWORD length, IDiaEnumLineNumbers* ppResult); + HRESULT findILOffsetsByVA(ULONGLONG va, DWORD length, + IDiaEnumLineNumbers* ppResult); + HRESULT findInputAssemblyFiles(IDiaEnumInputAssemblyFiles* ppResult); + HRESULT findInputAssembly(DWORD index, IDiaInputAssemblyFile* ppResult); + HRESULT findInputAssemblyById(DWORD uniqueId, IDiaInputAssemblyFile* ppResult); + HRESULT getFuncMDTokenMapSize(DWORD* pcb); + HRESULT getFuncMDTokenMap(DWORD cb, DWORD* pcb, BYTE* pb); + HRESULT getTypeMDTokenMapSize(DWORD* pcb); + HRESULT getTypeMDTokenMap(DWORD cb, DWORD* pcb, BYTE* pb); + HRESULT getNumberOfFunctionFragments_VA(ULONGLONG vaFunc, + DWORD cbFunc, DWORD* pNumFragments); + HRESULT getNumberOfFunctionFragments_RVA(DWORD rvaFunc, + DWORD cbFunc, DWORD* pNumFragments); + HRESULT getFunctionFragments_VA(ULONGLONG vaFunc, DWORD cbFunc, + DWORD cFragments, ULONGLONG* pVaFragment, DWORD* pLenFragment); + HRESULT getFunctionFragments_RVA(DWORD rvaFunc, DWORD cbFunc, + DWORD cFragments, DWORD* pRvaFragment, DWORD* pLenFragment); + HRESULT getExports(IDiaEnumSymbols* ppResult); + HRESULT getHeapAllocationSites(IDiaEnumSymbols* ppResult); + HRESULT findInputAssemblyFile(IDiaSymbol pSymbol, IDiaInputAssemblyFile* ppResult); +} + +interface IDiaSymbol : IUnknown +{ + static GUID iid = { 0xcb787b2f, 0xbd6c, 0x4635, [0xba, 0x52, 0x93, 0x31, 0x26, 0xbd, 0x2d, 0xcd] }; + + HRESULT get_symIndexId(DWORD* pRetVal); + HRESULT get_symTag(DWORD* pRetVal); + HRESULT get_name(BSTR* pRetVal); + HRESULT get_lexicalParent(IDiaSymbol* pRetVal); + HRESULT get_classParent(IDiaSymbol* pRetVal); + HRESULT get_type(IDiaSymbol* pRetVal); + HRESULT get_dataKind(DWORD* pRetVal); + HRESULT get_locationType(DWORD* pRetVal); + HRESULT get_addressSection(DWORD* pRetVal); + HRESULT get_addressOffset(DWORD* pRetVal); + HRESULT get_relativeVirtualAddress(DWORD* pRetVal); + HRESULT get_virtualAddress(ULONGLONG* pRetVal); + HRESULT get_registerId(DWORD* pRetVal); + HRESULT get_offset(LONG* pRetVal); + HRESULT get_length(ULONGLONG* pRetVal); + HRESULT get_slot(DWORD* pRetVal); + HRESULT get_volatileType(BOOL* pRetVal); + HRESULT get_constType(BOOL* pRetVal); + HRESULT get_unalignedType(BOOL* pRetVal); + HRESULT get_access(DWORD* pRetVal); + HRESULT get_libraryName(BSTR* pRetVal); + HRESULT get_platform(DWORD* pRetVal); + HRESULT get_language(DWORD* pRetVal); + HRESULT get_editAndContinueEnabled(BOOL* pRetVal); + HRESULT get_frontEndMajor(DWORD* pRetVal); + HRESULT get_frontEndMinor(DWORD* pRetVal); + HRESULT get_frontEndBuild(DWORD* pRetVal); + HRESULT get_backEndMajor(DWORD* pRetVal); + HRESULT get_backEndMinor(DWORD* pRetVal); + HRESULT get_backEndBuild(DWORD* pRetVal); + HRESULT get_sourceFileName(BSTR* pRetVal); + HRESULT get_unused(BSTR* pRetVal); + HRESULT get_thunkOrdinal(DWORD* pRetVal); + HRESULT get_thisAdjust(LONG* pRetVal); + HRESULT get_virtualBaseOffset(DWORD* pRetVal); + HRESULT get_virtual(BOOL* pRetVal); + HRESULT get_intro(BOOL* pRetVal); + HRESULT get_pure(BOOL* pRetVal); + HRESULT get_callingConvention(DWORD* pRetVal); + HRESULT get_value(VARIANT* pRetVal); + HRESULT get_baseType(DWORD* pRetVal); + HRESULT get_token(DWORD* pRetVal); + HRESULT get_timeStamp(DWORD* pRetVal); + HRESULT get_guid(GUID* pRetVal); + HRESULT get_symbolsFileName(BSTR* pRetVal); + HRESULT get_reference(BOOL* pRetVal); + HRESULT get_count(DWORD* pRetVal); + HRESULT get_bitPosition(DWORD* pRetVal); + HRESULT get_arrayIndexType(IDiaSymbol* pRetVal); + HRESULT get_packed(BOOL* pRetVal); + HRESULT get_constructor(BOOL* pRetVal); + HRESULT get_overloadedOperator(BOOL* pRetVal); + HRESULT get_nested(BOOL* pRetVal); + HRESULT get_hasNestedTypes(BOOL* pRetVal); + HRESULT get_hasAssignmentOperator(BOOL* pRetVal); + HRESULT get_hasCastOperator(BOOL* pRetVal); + HRESULT get_scoped(BOOL* pRetVal); + HRESULT get_virtualBaseClass(BOOL* pRetVal); + HRESULT get_indirectVirtualBaseClass(BOOL* pRetVal); + HRESULT get_virtualBasePointerOffset(LONG* pRetVal); + HRESULT get_virtualTableShape(IDiaSymbol* pRetVal); + HRESULT get_lexicalParentId(DWORD* pRetVal); + HRESULT get_classParentId(DWORD* pRetVal); + HRESULT get_typeId(DWORD* pRetVal); + HRESULT get_arrayIndexTypeId(DWORD* pRetVal); + HRESULT get_virtualTableShapeId(DWORD* pRetVal); + HRESULT get_code(BOOL* pRetVal); + HRESULT get_function(BOOL* pRetVal); + HRESULT get_managed(BOOL* pRetVal); + HRESULT get_msil(BOOL* pRetVal); + HRESULT get_virtualBaseDispIndex(DWORD* pRetVal); + HRESULT get_undecoratedName(BSTR* pRetVal); + HRESULT get_age(DWORD* pRetVal); + HRESULT get_signature(DWORD* pRetVal); + HRESULT get_compilerGenerated(BOOL* pRetVal); + HRESULT get_addressTaken(BOOL* pRetVal); + HRESULT get_rank(DWORD* pRetVal); + HRESULT get_lowerBound(IDiaSymbol* pRetVal); + HRESULT get_upperBound(IDiaSymbol* pRetVal); + HRESULT get_lowerBoundId(DWORD* pRetVal); + HRESULT get_upperBoundId(DWORD* pRetVal); + HRESULT get_dataBytes(DWORD cbData, DWORD* pcbData, BYTE* pbData); + HRESULT findChildren(SymTagEnum symtag, LPCOLESTR name, + DWORD compareFlags, IDiaEnumSymbols* ppResult); + HRESULT findChildrenEx(SymTagEnum symtag, LPCOLESTR name, + DWORD compareFlags, IDiaEnumSymbols* ppResult); + HRESULT findChildrenExByAddr(SymTagEnum symtag, LPCOLESTR name, + DWORD compareFlags, DWORD isect, DWORD offset, + IDiaEnumSymbols* ppResult); + HRESULT findChildrenExByVA(SymTagEnum symtag, LPCOLESTR name, + DWORD compareFlags, ULONGLONG va, IDiaEnumSymbols* ppResult); + HRESULT findChildrenExByRVA(SymTagEnum symtag, LPCOLESTR name, + DWORD compareFlags, DWORD rva, IDiaEnumSymbols* ppResult); + HRESULT get_targetSection(DWORD* pRetVal); + HRESULT get_targetOffset(DWORD* pRetVal); + HRESULT get_targetRelativeVirtualAddress(DWORD* pRetVal); + HRESULT get_targetVirtualAddress(ULONGLONG* pRetVal); + HRESULT get_machineType(DWORD* pRetVal); + HRESULT get_oemId(DWORD* pRetVal); + HRESULT get_oemSymbolId(DWORD* pRetVal); + HRESULT get_types(DWORD cTypes, DWORD* pcTypes, IDiaSymbol* pTypes); + HRESULT get_typeIds(DWORD cTypeIds, DWORD* pcTypeIds, DWORD* pdwTypeIds); + HRESULT get_objectPointerType(IDiaSymbol* pRetVal); + HRESULT get_udtKind(DWORD* pRetVal); + HRESULT get_undecoratedNameEx(DWORD undecorateOptions, BSTR* name); + HRESULT get_noReturn(BOOL* pRetVal); + HRESULT get_customCallingConvention(BOOL* pRetVal); + HRESULT get_noInline(BOOL* pRetVal); + HRESULT get_optimizedCodeDebugInfo(BOOL* pRetVal); + HRESULT get_notReached(BOOL* pRetVal); + HRESULT get_interruptReturn(BOOL* pRetVal); + HRESULT get_farReturn(BOOL* pRetVal); + HRESULT get_isStatic(BOOL* pRetVal); + HRESULT get_hasDebugInfo(BOOL* pRetVal); + HRESULT get_isLTCG(BOOL* pRetVal); + HRESULT get_isDataAligned(BOOL* pRetVal); + HRESULT get_hasSecurityChecks(BOOL* pRetVal); + HRESULT get_compilerName(BSTR* pRetVal); + HRESULT get_hasAlloca(BOOL* pRetVal); + HRESULT get_hasSetJump(BOOL* pRetVal); + HRESULT get_hasLongJump(BOOL* pRetVal); + HRESULT get_hasInlAsm(BOOL* pRetVal); + HRESULT get_hasEH(BOOL* pRetVal); + HRESULT get_hasSEH(BOOL* pRetVal); + HRESULT get_hasEHa(BOOL* pRetVal); + HRESULT get_isNaked(BOOL* pRetVal); + HRESULT get_isAggregated(BOOL* pRetVal); + HRESULT get_isSplitted(BOOL* pRetVal); + HRESULT get_container(IDiaSymbol* pRetVal); + HRESULT get_inlSpec(BOOL* pRetVal); + HRESULT get_noStackOrdering(BOOL* pRetVal); + HRESULT get_virtualBaseTableType(IDiaSymbol* pRetVal); + HRESULT get_hasManagedCode(BOOL* pRetVal); + HRESULT get_isHotpatchable(BOOL* pRetVal); + HRESULT get_isCVTCIL(BOOL* pRetVal); + HRESULT get_isMSILNetmodule(BOOL* pRetVal); + HRESULT get_isCTypes(BOOL* pRetVal); + HRESULT get_isStripped(BOOL* pRetVal); + HRESULT get_frontEndQFE(DWORD* pRetVal); + HRESULT get_backEndQFE(DWORD* pRetVal); + HRESULT get_wasInlined(BOOL* pRetVal); + HRESULT get_strictGSCheck(BOOL* pRetVal); + HRESULT get_isCxxReturnUdt(BOOL* pRetVal); + HRESULT get_isConstructorVirtualBase(BOOL* pRetVal); + HRESULT get_RValueReference(BOOL* pRetVal); + HRESULT get_unmodifiedType(IDiaSymbol* pRetVal); + HRESULT get_framePointerPresent(BOOL* pRetVal); + HRESULT get_isSafeBuffers(BOOL* pRetVal); + HRESULT get_intrinsic(BOOL* pRetVal); + HRESULT get_sealed(BOOL* pRetVal); + HRESULT get_hfaFloat(BOOL* pRetVal); + HRESULT get_hfaDouble(BOOL* pRetVal); + HRESULT get_liveRangeStartAddressSection(DWORD* pRetVal); + HRESULT get_liveRangeStartAddressOffset(DWORD* pRetVal); + HRESULT get_liveRangeStartRelativeVirtualAddress(DWORD* pRetVal); + HRESULT get_countLiveRanges(DWORD* pRetVal); + HRESULT get_liveRangeLength(ULONGLONG* pRetVal); + HRESULT get_offsetInUdt(DWORD* pRetVal); + HRESULT get_paramBasePointerRegisterId(DWORD* pRetVal); + HRESULT get_localBasePointerRegisterId(DWORD* pRetVal); + HRESULT get_isLocationControlFlowDependent(BOOL* pRetVal); + HRESULT get_stride(DWORD* pRetVal); + HRESULT get_numberOfRows(DWORD* pRetVal); + HRESULT get_numberOfColumns(DWORD* pRetVal); + HRESULT get_isMatrixRowMajor(BOOL* pRetVal); + HRESULT get_numericProperties(DWORD cnt, DWORD* pcnt, DWORD* pProperties); + HRESULT get_modifierValues(DWORD cnt, DWORD* pcnt, WORD* pModifiers); + HRESULT get_isReturnValue(BOOL* pRetVal); + HRESULT get_isOptimizedAway(BOOL* pRetVal); + HRESULT get_builtInKind(DWORD* pRetVal); + HRESULT get_registerType(DWORD* pRetVal); + HRESULT get_baseDataSlot(DWORD* pRetVal); + HRESULT get_baseDataOffset(DWORD* pRetVal); + HRESULT get_textureSlot(DWORD* pRetVal); + HRESULT get_samplerSlot(DWORD* pRetVal); + HRESULT get_uavSlot(DWORD* pRetVal); + HRESULT get_sizeInUdt(DWORD* pRetVal); + HRESULT get_memorySpaceKind(DWORD* pRetVal); + HRESULT get_unmodifiedTypeId(DWORD* pRetVal); + HRESULT get_subTypeId(DWORD* pRetVal); + HRESULT get_subType(IDiaSymbol* pRetVal); + HRESULT get_numberOfModifiers(DWORD* pRetVal); + HRESULT get_numberOfRegisterIndices(DWORD* pRetVal); + HRESULT get_isHLSLData(BOOL* pRetVal); + HRESULT get_isPointerToDataMember(BOOL* pRetVal); + HRESULT get_isPointerToMemberFunction(BOOL* pRetVal); + HRESULT get_isSingleInheritance(BOOL* pRetVal); + HRESULT get_isMultipleInheritance(BOOL* pRetVal); + HRESULT get_isVirtualInheritance(BOOL* pRetVal); + HRESULT get_restrictedType(BOOL* pRetVal); + HRESULT get_isPointerBasedOnSymbolValue(BOOL* pRetVal); + HRESULT get_baseSymbol(IDiaSymbol* pRetVal); + HRESULT get_baseSymbolId(DWORD* pRetVal); + HRESULT get_objectFileName(BSTR* pRetVal); + HRESULT get_isAcceleratorGroupSharedLocal(BOOL* pRetVal); + HRESULT get_isAcceleratorPointerTagLiveRange(BOOL* pRetVal); + HRESULT get_isAcceleratorStubFunction(BOOL* pRetVal); + HRESULT get_numberOfAcceleratorPointerTags(DWORD* pRetVal); + HRESULT get_isSdl(BOOL* pRetVal); + HRESULT get_isWinRTPointer(BOOL* pRetVal); + HRESULT get_isRefUdt(BOOL* pRetVal); + HRESULT get_isValueUdt(BOOL* pRetVal); + HRESULT get_isInterfaceUdt(BOOL* pRetVal); + HRESULT findInlineFramesByAddr(DWORD isect, DWORD offset, + IDiaEnumSymbols* ppResult); + HRESULT findInlineFramesByRVA(DWORD rva, IDiaEnumSymbols* ppResult); + HRESULT findInlineFramesByVA(ULONGLONG va, IDiaEnumSymbols* ppResult); + HRESULT findInlineeLines(IDiaEnumLineNumbers* ppResult); + HRESULT findInlineeLinesByAddr(DWORD isect, DWORD offset, + DWORD length, IDiaEnumLineNumbers* ppResult); + HRESULT findInlineeLinesByRVA(DWORD rva, DWORD length, + IDiaEnumLineNumbers* ppResult); + HRESULT findInlineeLinesByVA(ULONGLONG va, DWORD length, + IDiaEnumLineNumbers* ppResult); + HRESULT findSymbolsForAcceleratorPointerTag(DWORD tagValue, + IDiaEnumSymbols* ppResult); + HRESULT findSymbolsByRVAForAcceleratorPointerTag(DWORD tagValue, + DWORD rva, IDiaEnumSymbols* ppResult); + HRESULT get_acceleratorPointerTags(DWORD cnt, DWORD* pcnt, DWORD* pPointerTags); + HRESULT getSrcLineOnTypeDefn(IDiaLineNumber* ppResult); + HRESULT get_isPGO(BOOL* pRetVal); + HRESULT get_hasValidPGOCounts(BOOL* pRetVal); + HRESULT get_isOptimizedForSpeed(BOOL* pRetVal); + HRESULT get_PGOEntryCount(DWORD* pRetVal); + HRESULT get_PGOEdgeCount(DWORD* pRetVal); + HRESULT get_PGODynamicInstructionCount(ULONGLONG* pRetVal); + HRESULT get_staticSize(DWORD* pRetVal); + HRESULT get_finalLiveStaticSize(DWORD* pRetVal); + HRESULT get_phaseName(BSTR* pRetVal); + HRESULT get_hasControlFlowCheck(BOOL* pRetVal); + HRESULT get_constantExport(BOOL* pRetVal); + HRESULT get_dataExport(BOOL* pRetVal); + HRESULT get_privateExport(BOOL* pRetVal); + HRESULT get_noNameExport(BOOL* pRetVal); + HRESULT get_exportHasExplicitlyAssignedOrdinal(BOOL* pRetVal); + HRESULT get_exportIsForwarder(BOOL* pRetVal); + HRESULT get_ordinal(DWORD* pRetVal); + HRESULT get_frameSize(DWORD* pRetVal); + HRESULT get_exceptionHandlerAddressSection(DWORD* pRetVal); + HRESULT get_exceptionHandlerAddressOffset(DWORD* pRetVal); + HRESULT get_exceptionHandlerRelativeVirtualAddress(DWORD* pRetVal); + HRESULT get_exceptionHandlerVirtualAddress(ULONGLONG* pRetVal); + HRESULT findInputAssemblyFile(IDiaInputAssemblyFile* ppResult); + HRESULT get_characteristics(DWORD* pRetVal); + HRESULT get_coffGroup(IDiaSymbol* pRetVal); + HRESULT get_bindID(DWORD* pRetVal); + HRESULT get_bindSpace(DWORD* pRetVal); + HRESULT get_bindSlot(DWORD* pRetVal); +} + +interface IDiaEnumSymbols : IUnknown +{ + HRESULT get__NewEnum(IUnknown* pRetVal); + HRESULT get_Count(LONG* pRetVal); + HRESULT Item(DWORD index, IDiaSymbol* symbol); + HRESULT Next(ULONG celt, IDiaSymbol* rgelt, ULONG* pceltFetched); + HRESULT Skip(ULONG celt); + HRESULT Reset(); + HRESULT Clone(IDiaEnumSymbols* ppenum); +}; + +// unused interfaces, stubbed out for now +interface IStream : IUnknown +{ +} + +interface IDiaInputAssemblyFile : IUnknown +{ +} + +interface IDiaEnumTables : IUnknown +{ +} + +interface IDiaEnumSymbolsByAddr : IUnknown +{ +} + +interface IDiaEnumLineNumbers : IUnknown +{ +} + +interface IDiaSourceFile : IUnknown +{ +} + +interface IDiaLineNumber : IUnknown +{ +} + +interface IDiaEnumSourceFiles : IUnknown +{ +} + +interface IDiaEnumInjectedSources : IUnknown +{ +} + +interface IDiaEnumDebugStreams : IUnknown +{ +} + +interface IDiaEnumInputAssemblyFiles : IUnknown +{ +} + +struct VARIANT +{ +} + +enum SymTagEnum +{ + SymTagNull, + SymTagExe, + SymTagCompiland, + SymTagCompilandDetails, + SymTagCompilandEnv, + SymTagFunction, + SymTagBlock, + SymTagData, + SymTagAnnotation, + SymTagLabel, + SymTagPublicSymbol, + SymTagUDT, + SymTagEnum, + SymTagFunctionType, + SymTagPointerType, + SymTagArrayType, + SymTagBaseType, + SymTagTypedef, + SymTagBaseClass, + SymTagFriend, + SymTagFunctionArgType, + SymTagFuncDebugStart, + SymTagFuncDebugEnd, + SymTagUsingNamespace, + SymTagVTableShape, + SymTagVTable, + SymTagCustom, + SymTagThunk, + SymTagCustomType, + SymTagManagedType, + SymTagDimension, + SymTagCallSite, + SymTagInlineSite, + SymTagBaseInterface, + SymTagVectorType, + SymTagMatrixType, + SymTagHLSLType, + SymTagCaller, + SymTagCallee, + SymTagExport, + SymTagHeapAllocationSite, + SymTagCoffGroup, + SymTagMax +}; + +enum LocationType +{ + LocIsNull, + LocIsStatic, + LocIsTLS, + LocIsRegRel, + LocIsThisRel, + LocIsEnregistered, + LocIsBitField, + LocIsSlot, + LocIsIlRel, + LocInMetaData, + LocIsConstant, + LocTypeMax +}; + +enum DataKind +{ + DataIsUnknown, + DataIsLocal, + DataIsStaticLocal, + DataIsParam, + DataIsObjectPtr, + DataIsFileStatic, + DataIsGlobal, + DataIsMember, + DataIsStaticMember, + DataIsConstant +}; + +enum UdtKind +{ + UdtStruct, + UdtClass, + UdtUnion, + UdtInterface +}; + +enum BasicType +{ + btNoType = 0, + btVoid = 1, + btChar = 2, + btWChar = 3, + btInt = 6, + btUInt = 7, + btFloat = 8, + btBCD = 9, + btBool = 10, + btLong = 13, + btULong = 14, + btCurrency = 25, + btDate = 26, + btVariant = 27, + btComplex = 28, + btBit = 29, + btBSTR = 30, + btHresult = 31, + btChar16 = 32, // char16_t + btChar32 = 33, // char32_t +}; + +enum NameSearchOptions +{ + nsNone = 0, + nsfCaseSensitive = 0x1, + nsfCaseInsensitive = 0x2, + nsfFNameExt = 0x4, + nsfRegularExpression = 0x8, + nsfUndecoratedName = 0x10, + nsCaseSensitive = nsfCaseSensitive, + nsCaseInsensitive = nsfCaseInsensitive, + nsFNameExt = (nsfCaseInsensitive | nsfFNameExt), + nsRegularExpression = (nsfRegularExpression | nsfCaseSensitive), + nsCaseInRegularExpression = (nsfRegularExpression | nsfCaseInsensitive) +}; + +bool openDebugInfo(IDiaDataSource* source, IDiaSession* session, IDiaSymbol* globals) +{ + wchar[MAX_PATH] exepath; + DWORD len = GetModuleFileNameW(null, exepath.ptr, MAX_PATH); + len < MAX_PATH || assert("executable path too long"); + + HRESULT hr = CoInitialize(NULL); + + hr = CoCreateInstance(&uuid_DiaSource_V120, null, CLSCTX.CLSCTX_INPROC_SERVER, + &IDiaDataSource.iid, cast(void**)source); + if (hr != S_OK) + hr = CoCreateInstance(&uuid_DiaSource_V140, null, CLSCTX.CLSCTX_INPROC_SERVER, + &IDiaDataSource.iid, cast(void**)source); + if (hr != S_OK) + return false; + + hr = source.loadDataForExe(exepath.ptr, null, null); + hr == S_OK || assert(false, "loadDataForExe failed"); + + // Open a session for querying symbols + hr = source.openSession(session); + hr == S_OK || assert(false, "openSession failed"); + + // Retrieve a reference to the global scope + hr = session.get_globalScope(globals); + hr == S_OK || assert(false, "get_globalScope failed"); + + return true; +} + +void printSymbol(IDiaSymbol sym, int indent) +{ + BSTR name; + DWORD tag; + HRESULT hr = sym.get_symTag(&tag); + hr == S_OK || assert(false, "cannot get SymTag of symbol"); + hr = sym.get_name(&name); + if (hr != S_OK) + name = cast(BSTR) "no-name"w.ptr; + printf("%*s%02x %S\n", indent, "".ptr, tag, name); + if (hr == S_OK) + SysFreeString(name); +} + +void dumpSymbols(IDiaSymbol parent, SymTagEnum tag, const(wchar)* name, int indent) +{ + IDiaEnumSymbols enumSymbols; + HRESULT hr = parent.findChildren(tag, name, NameSearchOptions.nsfRegularExpression, &enumSymbols); + if (hr != S_OK) + return; + + DWORD celt; + IDiaSymbol sym; + while (enumSymbols.Next(1, &sym, &celt) == S_OK && celt == 1) + { + printSymbol(sym, indent + 2); + dumpSymbols(sym, tag, null, indent + 4); + sym.Release(); + } + enumSymbols.Release(); +} + +IDiaSymbol searchSymbol(IDiaSymbol parent, const(wchar)* name, SymTagEnum tag = SymTagEnum.SymTagNull) +{ + IDiaEnumSymbols enumSymbols; + // findChildren by name doesn't seem to work with '.' in name + HRESULT hr = parent.findChildren(tag, null, NameSearchOptions.nsNone, &enumSymbols); + if (hr != S_OK) + return null; + + DWORD celt; + IDiaSymbol sym; + while (enumSymbols.Next(1, &sym, &celt) == S_OK && celt == 1) + { + BSTR symname; + hr = sym.get_name(&symname); + if (hr == S_OK) + { + scope(exit) SysFreeString(symname); + if (wcscmp(symname, name) == 0) + break; + } + sym.Release(); + sym = null; + } + enumSymbols.Release(); + return sym; +}