static inline wxDbgHelpDLL::BasicType GetBasicType(PSYMBOL_INFO pSym) { wxDbgHelpDLL::BasicType bt; return DoGetTypeInfo(pSym, TI_GET_BASETYPE, &bt) ? bt : wxDbgHelpDLL::BASICTYPE_NOTYPE; }
/* static */ wxDbgHelpDLL::SymbolTag wxDbgHelpDLL::DereferenceSymbol(PSYMBOL_INFO pSym, void **ppData) { SymbolTag tag = SYMBOL_TAG_NULL; for ( ;; ) { if ( !DoGetTypeInfo(pSym, TI_GET_SYMTAG, &tag) ) break; if ( tag != SYMBOL_TAG_POINTER_TYPE ) break; ULONG tiNew; if ( !DoGetTypeInfo(pSym, TI_GET_TYPEID, &tiNew) || tiNew == pSym->TypeIndex ) break; pSym->TypeIndex = tiNew; // remove one level of indirection except for the char strings: we want // to dump "char *" and not a single "char" for them if ( ppData && *ppData && GetBasicType(pSym) != BASICTYPE_CHAR ) { DWORD_PTR *pData = (DWORD_PTR *)*ppData; if ( ::IsBadReadPtr(pData, sizeof(DWORD_PTR *)) ) { break; } *ppData = (void *)*pData; } } return tag; }
// this function is meant to be called from under debugger to see the // proprieties of the given type id extern "C" void DumpTI(ULONG ti) { SYMBOL_INFO sym = { sizeof(SYMBOL_INFO) }; sym.ModBase = 0x400000; // it's a constant under Win32 sym.TypeIndex = ti; wxDbgHelpDLL::SymbolTag tag = wxDbgHelpDLL::SYMBOL_TAG_NULL; DoGetTypeInfo(&sym, TI_GET_SYMTAG, &tag); DoGetTypeInfo(&sym, TI_GET_TYPEID, &ti); OutputDebugString(wxString::Format(_T("Type 0x%x: "), sym.TypeIndex)); wxString name = wxDbgHelpDLL::GetSymbolName(&sym); if ( !name.empty() ) { OutputDebugString(wxString::Format(_T("name=\"%s\", "), name.c_str())); } DWORD nested; if ( !DoGetTypeInfo(&sym, TI_GET_NESTED, &nested) ) { nested = FALSE; } OutputDebugString(wxString::Format(_T("tag=%s%s"), nested ? _T("nested ") : wxEmptyString, TagString(tag).c_str())); if ( tag == wxDbgHelpDLL::SYMBOL_TAG_UDT ) { wxDbgHelpDLL::UdtKind udtKind; if ( DoGetTypeInfo(&sym, TI_GET_UDTKIND, &udtKind) ) { OutputDebugString(_T(" (") + UdtKindString(udtKind) + _T(')')); } } wxDbgHelpDLL::DataKind kind = wxDbgHelpDLL::DATA_UNKNOWN; if ( DoGetTypeInfo(&sym, TI_GET_DATAKIND, &kind) ) { OutputDebugString(wxString::Format( _T(", kind=%s"), KindString(kind).c_str())); if ( kind == wxDbgHelpDLL::DATA_MEMBER ) { DWORD ofs = 0; if ( DoGetTypeInfo(&sym, TI_GET_OFFSET, &ofs) ) { OutputDebugString(wxString::Format(_T(" (ofs=0x%x)"), ofs)); } } } wxDbgHelpDLL::BasicType bt = GetBasicType(&sym); if ( bt ) { OutputDebugString(wxString::Format(_T(", type=%s"), TypeString(bt).c_str())); } if ( ti != sym.TypeIndex ) { OutputDebugString(wxString::Format(_T(", next ti=0x%x"), ti)); } OutputDebugString(_T("\r\n")); }
/* static */ wxString wxDbgHelpDLL::DumpUDT(PSYMBOL_INFO pSym, void *pVariable, unsigned level) { wxString s; // we have to limit the depth of UDT dumping as otherwise we get in // infinite loops trying to dump linked lists... 10 levels seems quite // reasonable, full information is in minidump file anyhow if ( level > 10 ) return s; s.reserve(512); s = GetSymbolName(pSym); #if !wxUSE_STL // special handling for ubiquitous wxString: although the code below works // for it as well, it shows the wxStringBase class and takes 4 lines // instead of only one as this branch if ( s == _T("wxString") ) { wxString *ps = (wxString *)pVariable; s << _T("(\"") << *ps << _T(")\""); } else // any other UDT #endif // !wxUSE_STL { // Determine how many children this type has. DWORD dwChildrenCount = 0; DoGetTypeInfo(pSym, TI_GET_CHILDRENCOUNT, &dwChildrenCount); // Prepare to get an array of "TypeIds", representing each of the children. TI_FINDCHILDREN_PARAMS *children = (TI_FINDCHILDREN_PARAMS *) malloc(sizeof(TI_FINDCHILDREN_PARAMS) + (dwChildrenCount - 1)*sizeof(ULONG)); if ( !children ) return s; children->Count = dwChildrenCount; children->Start = 0; // Get the array of TypeIds, one for each child type if ( !DoGetTypeInfo(pSym, TI_FINDCHILDREN, children) ) { free(children); return s; } s << _T(" {\n"); // Iterate through all children SYMBOL_INFO sym; wxZeroMemory(sym); sym.ModBase = pSym->ModBase; for ( unsigned i = 0; i < dwChildrenCount; i++ ) { sym.TypeIndex = children->ChildId[i]; // children here are in lexicographic sense, i.e. we get all our nested // classes and not only our member fields, but we can't get the values // for the members of the nested classes, of course! DWORD nested; if ( DoGetTypeInfo(&sym, TI_GET_NESTED, &nested) && nested ) continue; // avoid infinite recursion: this does seem to happen sometimes with // complex typedefs... if ( sym.TypeIndex == pSym->TypeIndex ) continue; s += DumpField(&sym, pVariable, level + 1); } free(children); s << wxString(_T('\t'), level + 1) << _T('}'); } return s; }
wxString wxDbgHelpDLL::DumpField(PSYMBOL_INFO pSym, void *pVariable, unsigned level) { wxString s; // avoid infinite recursion if ( level > 100 ) { return s; } SymbolTag tag = SYMBOL_TAG_NULL; if ( !DoGetTypeInfo(pSym, TI_GET_SYMTAG, &tag) ) { return s; } switch ( tag ) { case SYMBOL_TAG_UDT: case SYMBOL_TAG_BASE_CLASS: s = DumpUDT(pSym, pVariable, level); break; case SYMBOL_TAG_DATA: if ( !pVariable ) { s = _T("NULL"); } else // valid location { wxDbgHelpDLL::DataKind kind; if ( !DoGetTypeInfo(pSym, TI_GET_DATAKIND, &kind) || kind != DATA_MEMBER ) { // maybe it's a static member? we're not interested in them... break; } // get the offset of the child member, relative to its parent DWORD ofs = 0; if ( !DoGetTypeInfo(pSym, TI_GET_OFFSET, &ofs) ) break; pVariable = (void *)((DWORD_PTR)pVariable + ofs); // now pass to the type representing the type of this member SYMBOL_INFO sym = *pSym; if ( !DoGetTypeInfo(pSym, TI_GET_TYPEID, &sym.TypeIndex) ) break; ULONG64 size; DoGetTypeInfo(&sym, TI_GET_LENGTH, &size); switch ( DereferenceSymbol(&sym, &pVariable) ) { case SYMBOL_TAG_BASE_TYPE: { BasicType bt = GetBasicType(&sym); if ( bt ) { s = DumpBaseType(bt, size, pVariable); } } break; case SYMBOL_TAG_UDT: case SYMBOL_TAG_BASE_CLASS: s = DumpUDT(&sym, pVariable, level); break; } } if ( !s.empty() ) { s = GetSymbolName(pSym) + _T(" = ") + s; } break; } if ( !s.empty() ) { s = wxString(_T('\t'), level + 1) + s + _T('\n'); } return s; }
static inline bool DoGetTypeInfo(PSYMBOL_INFO pSym, IMAGEHLP_SYMBOL_TYPE_INFO type, void *rc) { return DoGetTypeInfo(pSym->ModBase, pSym->TypeIndex, type, rc); }
/* static */ wxString wxDbgHelpDLL::DumpUDT(wxPSYMBOL_INFO pSym, void *pVariable, unsigned level) { wxString s; // we have to limit the depth of UDT dumping as otherwise we get in // infinite loops trying to dump linked lists... 10 levels seems quite // reasonable, full information is in minidump file anyhow if ( level > 10 ) return s; s.reserve(512); s = GetSymbolName(pSym); #if !wxUSE_STD_STRING // special handling for ubiquitous wxString: although the code below works // for it as well, it shows the wxStringBase class and takes 4 lines // instead of only one as this branch if ( s == wxT("wxString") ) { wxString *ps = (wxString *)pVariable; // we can't just dump wxString directly as it could be corrupted or // invalid and it could also be locked for writing (i.e. if we're // between GetWriteBuf() and UngetWriteBuf() calls) and assert when we // try to access it contents using public methods, so instead use our // knowledge of its internals const wxChar *p = NULL; if ( !::IsBadReadPtr(ps, sizeof(wxString)) ) { p = ps->data(); wxStringData *data = (wxStringData *)p - 1; if ( ::IsBadReadPtr(data, sizeof(wxStringData)) || ::IsBadReadPtr(p, sizeof(wxChar *)*data->nAllocLength) ) { p = NULL; // don't touch this pointer with 10 feet pole } } s << wxT("(\"") << (p ? p : wxT("???")) << wxT(")\""); } else // any other UDT #endif // !wxUSE_STD_STRING { // Determine how many children this type has. DWORD dwChildrenCount = 0; DoGetTypeInfo(pSym, TI_GET_CHILDRENCOUNT, &dwChildrenCount); // Prepare to get an array of "TypeIds", representing each of the children. TI_FINDCHILDREN_PARAMS *children = (TI_FINDCHILDREN_PARAMS *) malloc(sizeof(TI_FINDCHILDREN_PARAMS) + (dwChildrenCount - 1)*sizeof(ULONG)); if ( !children ) return s; children->Count = dwChildrenCount; children->Start = 0; // Get the array of TypeIds, one for each child type if ( !DoGetTypeInfo(pSym, TI_FINDCHILDREN, children) ) { free(children); return s; } s << wxT(" {\n"); // Iterate through all children wxSYMBOL_INFO sym; wxZeroMemory(sym); sym.ModBase = pSym->ModBase; for ( unsigned i = 0; i < dwChildrenCount; i++ ) { sym.TypeIndex = children->ChildId[i]; // children here are in lexicographic sense, i.e. we get all our nested // classes and not only our member fields, but we can't get the values // for the members of the nested classes, of course! DWORD nested; if ( DoGetTypeInfo(&sym, TI_GET_NESTED, &nested) && nested ) continue; // avoid infinite recursion: this does seem to happen sometimes with // complex typedefs... if ( sym.TypeIndex == pSym->TypeIndex ) continue; s += DumpField(&sym, pVariable, level + 1); } free(children); s << wxString(wxT('\t'), level + 1) << wxT('}'); } return s; }