DDR_RC PdbScanner::addEnumMembers(IDiaSymbol *symbol, EnumUDT *enumUDT) { DDR_RC rc = DDR_RC_OK; /* All children symbols of a symbol for an Enum type should be * enum members. */ IDiaEnumSymbols *enumSymbols = NULL; HRESULT hr = symbol->findChildren(SymTagNull, NULL, nsNone, &enumSymbols); if (FAILED(hr)) { ERRMSG("findChildren() failed with HRESULT = %08lX", hr); rc = DDR_RC_ERROR; } if (DDR_RC_OK == rc) { vector<EnumMember *> *members = NULL; NamespaceUDT *outerUDT = enumUDT->_outerNamespace; /* literals of a nested anonymous enum are collected in the enclosing namespace */ if ((NULL != outerUDT) && enumUDT->isAnonymousType()) { members = &outerUDT->_enumMembers; } else { members = &enumUDT->_enumMembers; } set<string> memberNames; for (vector<EnumMember *>::iterator m = members->begin(); m != members->end(); ++m) { memberNames.insert((*m)->_name); } IDiaSymbol *childSymbol = NULL; ULONG celt = 0; LONG count = 0; enumSymbols->get_Count(&count); members->reserve(count); while (SUCCEEDED(enumSymbols->Next(1, &childSymbol, &celt)) && (1 == celt) && (DDR_RC_OK == rc) ) { string name = ""; int value = 0; rc = getName(childSymbol, &name); if (DDR_RC_OK == rc) { VARIANT variantValue; variantValue.vt = VT_EMPTY; hr = childSymbol->get_value(&variantValue); if (FAILED(hr)) { ERRMSG("get_value() failed with HRESULT = %08lX", hr); rc = DDR_RC_ERROR; } else { switch (variantValue.vt) { case VT_I1: value = variantValue.cVal; break; case VT_I2: value = variantValue.iVal; break; case VT_I4: value = (int)variantValue.lVal; break; case VT_UI1: value = variantValue.bVal; break; case VT_UI2: value = variantValue.uiVal; break; case VT_UI4: value = (int)variantValue.ulVal; break; case VT_INT: value = variantValue.intVal; break; case VT_UINT: value = (int)variantValue.uintVal; break; default: ERRMSG("get_value() unexpected variant: 0x%02X", variantValue.vt); rc = DDR_RC_ERROR; break; } } } if (DDR_RC_OK == rc) { if (memberNames.end() == memberNames.find(name)) { EnumMember *enumMember = new EnumMember; enumMember->_name = name; enumMember->_value = value; members->push_back(enumMember); memberNames.insert(name); } } childSymbol->Release(); } enumSymbols->Release(); } return rc; }
DDR_RC PdbScanner::addChildrenSymbols(IDiaSymbol *symbol, enum SymTagEnum symTag, NamespaceUDT *outerNamespace) { DDR_RC rc = DDR_RC_OK; IDiaEnumSymbols *classSymbols = NULL; /* Find children symbols. SymTagUDT covers struct, union, and class symbols. */ HRESULT hr = symbol->findChildren(symTag, NULL, nsNone, &classSymbols); if (FAILED(hr)) { ERRMSG("findChildren() failed with HRESULT = %08lX", hr); rc = DDR_RC_ERROR; } /* Allocate space for the children symbols. */ LONG count = 0; if (DDR_RC_OK == rc) { hr = classSymbols->get_Count(&count); if (FAILED(hr)) { ERRMSG("Failed to get count of children symbols with HRESULT = %08lX", hr); rc = DDR_RC_ERROR; } } IDiaSymbol **childSymbols = NULL; ULONG celt = 0; if ((DDR_RC_OK == rc) && (0 != count)) { childSymbols = new IDiaSymbol*[count]; hr = classSymbols->Next(count, childSymbols, &celt); if (FAILED(hr)) { ERRMSG("Failed to get children symbols with HRESULT = %08lX", hr); rc = DDR_RC_ERROR; } } /* Iterate the children symbols, adding them to the IR. * Inner symbols are first found with a decorated name and no * parent reference. Ignore these for now and add the outer * types first. */ vector<ULONG> innerTypeSymbols; if (DDR_RC_OK == rc) { bool alreadyHadFields = false; bool alreadyCheckedFields = false; bool alreadyHadSubtypes = false; if (NULL != outerNamespace) { alreadyHadSubtypes = !outerNamespace->_subUDTs.empty(); } for (ULONG index = 0; index < celt; ++index) { string udtName = ""; DWORD childTag = 0; hr = childSymbols[index]->get_symTag(&childTag); if (FAILED(hr)) { ERRMSG("Failed to get child symbol SymTag with HRESULT = %08lX", hr); rc = DDR_RC_ERROR; } if ((DDR_RC_OK == rc) && ((SymTagEnum == childTag) || (SymTagUDT == childTag))) { rc = getName(childSymbols[index], &udtName); } if (DDR_RC_OK == rc) { if ((NULL == outerNamespace) || (string::npos == udtName.find("::"))) { /* When adding fields/subtypes to a type, only add fields to a type with no fields * and only add subtypes to a type with no subtypes. This avoids adding duplicates * fields/subtypes when scanning multiple files. Children symbols must be processed * for already existing symbols because fields and subtypes can appear separately. */ if (!alreadyCheckedFields && (SymTagData == childTag)) { alreadyCheckedFields = true; alreadyHadFields = !((ClassType *)outerNamespace)->_fieldMembers.empty(); } if (!((SymTagData == childTag) ? alreadyHadFields : alreadyHadSubtypes)) { rc = addSymbol(childSymbols[index], outerNamespace); } childSymbols[index]->Release(); } else { innerTypeSymbols.push_back(index); } } if (DDR_RC_OK != rc) { break; } } } /* Iterate the inner types. Only namespaces will be added to the IR * here, since they have no associated symbol. */ if (DDR_RC_OK == rc) { for (vector<ULONG>::iterator it = innerTypeSymbols.begin(); it != innerTypeSymbols.end() && DDR_RC_OK == rc; ++it) { rc = addSymbol(childSymbols[*it], outerNamespace); childSymbols[*it]->Release(); } } if (NULL != childSymbols) { delete childSymbols; } if (NULL != classSymbols) { classSymbols->Release(); } return rc; }