// the result doesn't have to be free()d but is only valid until the next call to this function static const char *GetObjFileName(IDiaSectionContrib *item) { static str::Str<char> strTmp; BSTR name = 0; IDiaSymbol * compiland = 0; item->get_compiland(&compiland); if (compiland) { compiland->get_name(&name); compiland->Release(); } BStrToString(strTmp, name, "<noobjfile>"); SysFreeStringSafe(name); return strTmp.Get(); }
AddrInfo GetAddr(wstring req) { uint32_t module; uint64_t addr; int charsRead = swscanf_s(req.c_str(), L"%d %llu", &module, &addr); AddrInfo ret; ZeroMemory(&ret, sizeof(ret)); if(module > 0 && module < modules.size()) { SymTagEnum tag = SymTagFunction; IDiaSymbol *pFunc = NULL; HRESULT hr = modules[module].pSession->findSymbolByVA(addr, tag, &pFunc); if(hr != S_OK) { if(pFunc) pFunc->Release(); // try again looking for public symbols tag = SymTagPublicSymbol; hr = modules[module].pSession->findSymbolByVA(addr, tag, &pFunc); if(hr != S_OK) { if(pFunc) pFunc->Release(); return ret; } } DWORD opts = 0; opts |= UNDNAME_NO_LEADING_UNDERSCORES; opts |= UNDNAME_NO_MS_KEYWORDS; opts |= UNDNAME_NO_FUNCTION_RETURNS; opts |= UNDNAME_NO_ALLOCATION_MODEL; opts |= UNDNAME_NO_ALLOCATION_LANGUAGE; opts |= UNDNAME_NO_THISTYPE; opts |= UNDNAME_NO_ACCESS_SPECIFIERS; opts |= UNDNAME_NO_THROW_SIGNATURES; opts |= UNDNAME_NO_MEMBER_TYPE; opts |= UNDNAME_NO_RETURN_UDT_MODEL; opts |= UNDNAME_32_BIT_DECODE; opts |= UNDNAME_NO_LEADING_UNDERSCORES; // first try undecorated name BSTR file; hr = pFunc->get_undecoratedNameEx(opts, &file); // if not, just try name if(hr != S_OK) { hr = pFunc->get_name(&file); if(hr != S_OK) { pFunc->Release(); SysFreeString(file); return ret; } wcsncpy_s(ret.funcName, file, 126); } else { wcsncpy_s(ret.funcName, file, 126); wchar_t *voidparam = wcsstr(ret.funcName, L"(void)"); // remove stupid (void) for empty parameters if(voidparam != NULL) { *(voidparam + 1) = L')'; *(voidparam + 2) = 0; } } pFunc->Release(); pFunc = NULL; SysFreeString(file); // find the line numbers touched by this address. IDiaEnumLineNumbers *lines = NULL; hr = modules[module].pSession->findLinesByVA(addr, DWORD(4), &lines); if(FAILED(hr)) { if(lines) lines->Release(); return ret; } IDiaLineNumber *line = NULL; ULONG count = 0; // just take the first one if(SUCCEEDED(lines->Next(1, &line, &count)) && count == 1) { IDiaSourceFile *dia_source = NULL; hr = line->get_sourceFile(&dia_source); if(FAILED(hr)) { line->Release(); lines->Release(); if(dia_source) dia_source->Release(); return ret; } hr = dia_source->get_fileName(&file); if(FAILED(hr)) { line->Release(); lines->Release(); dia_source->Release(); return ret; } wcsncpy_s(ret.fileName, file, 126); SysFreeString(file); dia_source->Release(); dia_source = NULL; DWORD line_num = 0; hr = line->get_lineNumber(&line_num); if(FAILED(hr)) { line->Release(); lines->Release(); return ret; } ret.lineNum = line_num; line->Release(); } lines->Release(); } return ret; }
void PDBFileReader::ProcessSymbol(IDiaSymbol *symbol,DebugInfo &to) { DWORD section,offset,rva; enum SymTagEnum tag; ULONGLONG length = 0; sU32 compilandId; IDiaSymbol *compiland = 0; BSTR name = 0, sourceName = 0; sBool codeFlag; symbol->get_symTag((DWORD *) &tag); symbol->get_relativeVirtualAddress(&rva); symbol->get_length(&length); symbol->get_addressSection(§ion); symbol->get_addressOffset(&offset); // is the previous symbol desperately looking for a length? we can help! if(DanglingLengthStart) { to.Symbols[to.Symbols.Count - 1].Size = rva - DanglingLengthStart; DanglingLengthStart = 0; } // get length from type for data if(tag == SymTagData) { IDiaSymbol *type; if(symbol->get_type(&type) == S_OK) { type->get_length(&length); type->Release(); } // if length still zero, just guess and take number of bytes between // this symbol and the next one. if(!length) DanglingLengthStart = rva; } compilandId = CompilandFromSectionOffset(section,offset,codeFlag); Session->symbolById(compilandId,&compiland); if(compiland) compiland->get_name(&sourceName); symbol->get_name(&name); // fill out structure sChar *nameStr = BStrToString(name,"<no name>"); sChar *sourceStr = BStrToString(sourceName,"<no source>"); if(tag == SymTagPublicSymbol) { length = 0; DanglingLengthStart = rva; } DISymbol *outSym = to.Symbols.Add(); outSym->Name.Index = outSym->MangledName.Index = to.MakeString(nameStr); outSym->FileNum = to.GetFileByName(sourceStr); outSym->VA = rva; outSym->Size = (sU32) length; outSym->Class = codeFlag ? DIC_CODE : DIC_DATA; outSym->NameSpNum = to.GetNameSpaceByName(nameStr); // clean up delete[] nameStr; delete[] sourceStr; if(compiland) compiland->Release(); if(sourceName) SysFreeString(sourceName); if(name) SysFreeString(name); }
//----------------------------------------------------------------------------- // Name: ParseModules // Object: parse all compilands // Parameters : // in : // out : // return : TRUE on success //----------------------------------------------------------------------------- BOOL CDebugInfos::ParseModules() { HRESULT hr; IDiaEnumSymbols* pEnumSymbols; IDiaEnumSymbols* pEnumChildren; IDiaSymbol* pCompiland; IDiaSymbol* pSymbol; ULONG celt = 0; CModuleInfos* pModuleInfo; BSTR Name; // Retrieve the compilands first if(FAILED(this->pDiaGlobalSymbol->findChildren(SymTagCompiland, NULL, nsNone, &pEnumSymbols))) return FALSE; // for each compiland while(pEnumSymbols->Next(1, &pCompiland, &celt) == S_OK && celt == 1) { // Retrieve the name of the module Name=NULL; pCompiland->get_name(&Name); #if (REMOVE_LINKER_COMPILAND==1) // avoid to display "* Linker *" infos if (Name) { if (wcsicmp(Name,LINKER_COMPILAND_NAME)==0) { SysFreeString(Name); pCompiland->Release(); continue; } } #endif // create module info pModuleInfo=new CModuleInfos(); // add it to modules list this->pLinkListModules->AddItem(pModuleInfo); // assume module name is set if (Name) { #if (defined(UNICODE)||defined(_UNICODE)) pModuleInfo->Name=_tcsdup(Name); #else CAnsiUnicodeConvert::UnicodeToAnsi(Name,&pModuleInfo->Name); #endif SysFreeString(Name); } else pModuleInfo->Name=_tcsdup(_T("")); // Find all the symbols defined in this compiland and get their info if(SUCCEEDED(pCompiland->findChildren(SymTagNull, NULL, nsNone, &pEnumChildren))) { ULONG celt_ = 0; while (pEnumChildren->Next(1, &pSymbol, &celt_) == S_OK && celt_ == 1) { hr=pModuleInfo->Parse(pSymbol); if (FAILED(hr)) this->ReportError(_T("Error parsing module information"),hr); pSymbol->Release(); } pEnumChildren->Release(); } pCompiland->Release(); } pEnumSymbols->Release(); return TRUE; }
void PDBFileReader::ReadEverything(DebugInfo &to) { ULONG celt; Contribs = 0; nContribs = 0; // read section table IDiaEnumTables *enumTables; if(Session->getEnumTables(&enumTables) == S_OK) { VARIANT vIndex; vIndex.vt = VT_BSTR; vIndex.bstrVal = SysAllocString(L"Sections"); IDiaTable *secTable; if(enumTables->Item(vIndex,&secTable) == S_OK) { LONG count; secTable->get_Count(&count); Contribs = new SectionContrib[count]; nContribs = 0; IDiaSectionContrib *item; while(SUCCEEDED(secTable->Next(1,(IUnknown **)&item,&celt)) && celt == 1) { SectionContrib &contrib = Contribs[nContribs++]; item->get_addressOffset(&contrib.Offset); item->get_addressSection(&contrib.Section); item->get_length(&contrib.Length); item->get_compilandId(&contrib.Compiland); BOOL code=FALSE,initData=FALSE,uninitData=FALSE; item->get_code(&code); item->get_initializedData(&initData); item->get_uninitializedData(&uninitData); if(code && !initData && !uninitData) contrib.Type = DIC_CODE; else if(!code && initData && !uninitData) contrib.Type = DIC_DATA; else if(!code && !initData && uninitData) contrib.Type = DIC_BSS; else contrib.Type = DIC_UNKNOWN; BSTR objFileName = 0; IDiaSymbol *compiland = 0; item->get_compiland(&compiland); if(compiland) { compiland->get_name(&objFileName); compiland->Release(); } sChar *objFileStr = BStrToString(objFileName,"<noobjfile>"); contrib.ObjFile = to.GetFileByName(objFileStr); delete[] objFileStr; if(objFileName) SysFreeString(objFileName); item->Release(); } secTable->Release(); } SysFreeString(vIndex.bstrVal); enumTables->Release(); } // enumerate symbols by (virtual) address IDiaEnumSymbolsByAddr *enumByAddr; if(SUCCEEDED(Session->getSymbolsByAddr(&enumByAddr))) { IDiaSymbol *symbol; // get first symbol to get first RVA (argh) if(SUCCEEDED(enumByAddr->symbolByAddr(1,0,&symbol))) { DWORD rva; if(symbol->get_relativeVirtualAddress(&rva) == S_OK) { symbol->Release(); // now, enumerate by rva. if(SUCCEEDED(enumByAddr->symbolByRVA(rva,&symbol))) { do { ProcessSymbol(symbol,to); symbol->Release(); if(FAILED(enumByAddr->Next(1,&symbol,&celt))) break; } while(celt == 1); } } else symbol->Release(); } enumByAddr->Release(); } // clean up delete[] Contribs; }
bool LoadDIASymbols(const wxString &strPDBFile, wxInt32 modulenum, std::list<CFunctionDescription> & llFuncs, stdext::hash_map<BasedAddress,int> & addressmap ) { // Create DIA80 Data Source Object IDiaDataSource *pDataSource; HRESULT hr = NoRegCoCreate( L"msdia80.dll", _uuidof( DiaSource ), _uuidof( IDiaDataSource ), (void **) &(pDataSource)); if(!SUCCEEDED(hr)) { return false; } /* HMODULE mod=LoadLibrary(L"msdia80.dll"); if(!mod) { return false; } TYPEOF_DllGetClassObject *pGetClassObject=(TYPEOF_DllGetClassObject *)GetProcAddress(mod,"DllGetClassObject"); if(!pGetClassObject) { FreeLibrary(mod); return false; } IClassFactory *pcf; HRESULT hr=(*pGetClassObject)(CLSID_DiaSource,IID_IClassFactory,(void **)&pcf); if(!SUCCEEDED(hr)) { FreeLibrary(mod); return false; } IDiaDataSource *pDataSource; hr=pcf->CreateInstance(NULL,_uuidof(IDiaDataSource),(void **)&pDataSource); if(!SUCCEEDED(hr)) { pcf->Release(); FreeLibrary(mod); return false; } pcf->Release(); */ // Load the executable's debug symbols hr=pDataSource->loadDataFromPdb(strPDBFile); if(!SUCCEEDED(hr)) { pDataSource->Release(); return false; } // Open a symbol session IDiaSession *pDIASession; hr=pDataSource->openSession(&pDIASession); if(!SUCCEEDED(hr)) { pDataSource->Release(); return false; } // Set the UNBASED address on the session, for resolving BasedAddress addrs hr=pDIASession->put_loadAddress(0); if(!SUCCEEDED(hr)) { pDIASession->Release(); pDataSource->Release(); return false; } // Get addresses for this module std::list<BasedAddress> addresses; for(stdext::hash_map<BasedAddress,int>::iterator iter=addressmap.begin();iter!=addressmap.end();iter++) { if(iter->first.nModule==modulenum) { addresses.push_back(iter->first); } } stdext::hash_map<DWORD,wxInt32> functions; int curidx=(int)llFuncs.size(); for(std::list<BasedAddress>::iterator itera=addresses.begin();itera!=addresses.end();itera++) { // Get the symbol for this thing IDiaSymbol* pFunc; if(FAILED(pDIASession->findSymbolByVA(itera->nAddr, SymTagFunction, &pFunc)) || pFunc==NULL) { continue; } // Get the unique symbol index id DWORD indexId; if(FAILED(pFunc->get_symIndexId(&indexId))) { pFunc->Release(); continue; } // See if we have this function already stdext::hash_map<DWORD,int>::iterator iterf=functions.find(indexId); if(iterf!=functions.end()) { addressmap[*itera]=iterf->second; } else { CFunctionDescription func; ////// ULONGLONG addr; if(FAILED(pFunc->get_virtualAddress(&addr))) { pFunc->Release(); continue; } ////// ULONGLONG length; if(FAILED(pFunc->get_length(&length))) { pFunc->Release(); continue; } ///////// BSTR pName; if(FAILED(pFunc->get_name(&pName))) { pFunc->Release(); continue; } func.strMangledName=(const LPWSTR)pName; LocalFree(pName); char mangled[512]; WideCharToMultiByte(CP_UTF8,0,func.strMangledName,-1,mangled,512,NULL,NULL); ///////// char outbase[512]; __unDName(outbase,mangled,512,&malloc,&free,0x1000); wchar_t outbasew[512]; MultiByteToWideChar(CP_UTF8,0,outbase,-1,outbasew,512); func.strBaseName=(const wchar_t *)(outbasew); ///////// char outfull[512]; __unDName(outfull,mangled,512,&malloc,&free,0); wchar_t outfullw[512]; MultiByteToWideChar(CP_UTF8,0,outfull,-1,outfullw,512); func.strFullName=(const wchar_t *)(outfullw); ////////// func.nAddress=BasedAddress(addr,modulenum); func.nByteLength=length; ///////// IDiaEnumLineNumbers *pdeln; func.strSourceFile=wxT("<unknown>"); func.nFirstSourceLine=0; func.nLastSourceLine=0; bool bGotFile=false; if(SUCCEEDED(pDIASession->findLinesByVA(addr,length,&pdeln))) { IDiaLineNumber *pdln; int nLineItem=0; while(SUCCEEDED(pdeln->Item(nLineItem,&pdln))) { DWORD dwLineNumber; IDiaSourceFile *pdsf; if(SUCCEEDED(pdln->get_lineNumber(&dwLineNumber)) && SUCCEEDED(pdln->get_sourceFile(&pdsf))) { BSTR filename; if(SUCCEEDED(pdsf->get_fileName(&filename))) { if(bGotFile) { if(filename==func.strSourceFile) { if(dwLineNumber<func.nFirstSourceLine) { func.nFirstSourceLine=dwLineNumber; } if(dwLineNumber>func.nLastSourceLine) { func.nLastSourceLine=dwLineNumber; } } } else { bGotFile=true; func.strSourceFile=filename; func.nFirstSourceLine=dwLineNumber; func.nLastSourceLine=dwLineNumber; } LocalFree(filename); } pdsf->Release(); } pdln->Release(); nLineItem++; } pdeln->Release(); } llFuncs.push_back(func); functions[indexId]=curidx; addressmap[*itera]=curidx; curidx++; } } pDIASession->Release(); pDataSource->Release(); // FreeLibrary(mod); return true; }