/*++ Copyright (c) 1995 Microsoft Corporation Module Name: symbolsp.c Abstract: This function implements a generic simple symbol handler. Author: Wesley Witt (wesw) 1-Sep-1994 Environment: User Mode --*/ #include #include #include #include #include "private.h" #include "symbols.h" #include "tlhelp32.h" typedef BOOL (WINAPI *PMODULE32)(HANDLE, LPMODULEENTRY32); typedef HANDLE (WINAPI *PCREATE32SNAPSHOT)(DWORD, DWORD); typedef ULONG (NTAPI *PRTLQUERYPROCESSDEBUGINFORMATION)(HANDLE,ULONG,PRTL_DEBUG_INFORMATION); typedef PRTL_DEBUG_INFORMATION (NTAPI *PRTLCREATEQUERYDEBUGBUFFER)(ULONG,BOOLEAN); typedef NTSTATUS (NTAPI *PRTLDESTROYQUERYDEBUGBUFFER)(PRTL_DEBUG_INFORMATION); #ifdef WORK DWORD NTGetProcessModules( #else DWORD GetProcessModules( #endif HANDLE hProcess, PINTERNAL_GET_MODULE InternalGetModule, PVOID Context ) { PRTLQUERYPROCESSDEBUGINFORMATION RtlQueryProcessDebugInformation; PRTLCREATEQUERYDEBUGBUFFER RtlCreateQueryDebugBuffer; PRTLDESTROYQUERYDEBUGBUFFER RtlDestroyQueryDebugBuffer; HMODULE hModule; NTSTATUS Status; PRTL_DEBUG_INFORMATION Buffer; ULONG i; HANDLE hProcessId; hModule = GetModuleHandle( "ntdll.dll" ); if (!hModule) { return ERROR_MOD_NOT_FOUND; } RtlQueryProcessDebugInformation = (PRTLQUERYPROCESSDEBUGINFORMATION)GetProcAddress( hModule, "RtlQueryProcessDebugInformation" ); if (!RtlQueryProcessDebugInformation) { return ERROR_INVALID_FUNCTION; } RtlCreateQueryDebugBuffer = (PRTLCREATEQUERYDEBUGBUFFER)GetProcAddress( hModule, "RtlCreateQueryDebugBuffer" ); if (!RtlCreateQueryDebugBuffer) { return ERROR_INVALID_FUNCTION; } RtlDestroyQueryDebugBuffer = (PRTLDESTROYQUERYDEBUGBUFFER)GetProcAddress( hModule, "RtlDestroyQueryDebugBuffer" ); if (!RtlDestroyQueryDebugBuffer) { return ERROR_INVALID_FUNCTION; } Buffer = RtlCreateQueryDebugBuffer( 0, FALSE ); if (!Buffer) { return ERROR_NOT_ENOUGH_MEMORY; } hProcessId = (hProcess == (HANDLE)-1) ? (HANDLE)GetCurrentProcessId() : hProcess; Status = RtlQueryProcessDebugInformation( hProcessId, RTL_QUERY_PROCESS_MODULES, Buffer ); if (Status != STATUS_SUCCESS) { RtlDestroyQueryDebugBuffer( Buffer ); return Status; } for (i=0; iModules->NumberOfModules; i++) { PRTL_PROCESS_MODULE_INFORMATION Module = &Buffer->Modules->Modules[i]; InternalGetModule( hProcess, (LPSTR) &Module->FullPathName[Module->OffsetToFileName], (DWORD)Module->ImageBase, (DWORD)Module->ImageSize, Context ); } RtlDestroyQueryDebugBuffer( Buffer ); return ERROR_SUCCESS; } #ifdef WORK DWORD Win95GetProcessModules( HANDLE hProcess, PINTERNAL_GET_MODULE InternalGetModule, PVOID Context ) { MODULEENTRY32 ModuleEntry; PMODULE32 pModule32Next, pModule32First; PCREATE32SNAPSHOT pCreateToolhelp32Snapshot; HANDLE hSnapshot; HMODULE hToolHelp; DWORD pid; if (GetCurrentProcess() != hProcess) { // Hack. Due to the lame toolhelp API on Win95, we have to use a PID. Since // there's no hProcess -> PID translation, we'll just bail if hProcess is // something other than the current process. return(ERROR_MOD_NOT_FOUND); } pid = GetCurrentProcessId(); hToolHelp = GetModuleHandle("kernel32.dll"); if (!hToolHelp || !(pModule32Next = (PMODULE32)GetProcAddress(hToolHelp, "Module32Next")) || !(pModule32First = (PMODULE32)GetProcAddress(hToolHelp, "Module32First")) || !(pCreateToolhelp32Snapshot = (PCREATE32SNAPSHOT)GetProcAddress( hToolHelp, "CreateTookhelp32Snapshot")) || ((hSnapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid)) == (HANDLE)-1) ) { return(ERROR_MOD_NOT_FOUND); } ModuleEntry.dwSize = sizeof(MODULEENTRY32); if (pModule32First(hSnapshot, &ModuleEntry)) { do { InternalGetModule( hProcess, ModuleEntry.szModule, (DWORD) ModuleEntry.modBaseAddr, ModuleEntry.modBaseSize, Context ); } while ( pModule32Next(hSnapshot, &ModuleEntry) ); } CloseHandle(hSnapshot); return(ERROR_SUCCESS); } DWORD GetProcessModules( HANDLE hProcess, PINTERNAL_GET_MODULE InternalGetModule, PVOID Context ) { OSVERSIONINFO VerInfo; VerInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&VerInfo); if (VerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) return( NTGetProcessModules(hProcess, InternalGetModule, Context)); else return(Win95GetProcessModules(hProcess, InternalGetModule, Context)); } #endif VOID FreeModuleEntry( PMODULE_ENTRY ModuleEntry ) { ULONG i; if (ModuleEntry->symbolTable) { MemFree( ModuleEntry->symbolTable ); } if (ModuleEntry->SymType == SymPdb) { DBIClose( ModuleEntry->dbi ); PDBClose( ModuleEntry->pdb ); } if (ModuleEntry->SectionHdrs) { MemFree( ModuleEntry->SectionHdrs ); } if (ModuleEntry->pFpoData) { VirtualFree( ModuleEntry->pFpoData, 0, MEM_RELEASE ); } if (ModuleEntry->pExceptionData) { VirtualFree( ModuleEntry->pExceptionData, 0, MEM_RELEASE ); } if (ModuleEntry->TmpSym.Name) { MemFree( ModuleEntry->TmpSym.Name ); } if (ModuleEntry->ImageName) { MemFree( ModuleEntry->ImageName ); } if (ModuleEntry->LoadedImageName) { MemFree( ModuleEntry->LoadedImageName ); } if (ModuleEntry->SectionStart) { MemFree( ModuleEntry->SectionStart ); } if (ModuleEntry->pOmapTo) { MemFree( ModuleEntry->pOmapTo ); } if (ModuleEntry->pOmapFrom) { MemFree( ModuleEntry->pOmapFrom ); } MemFree( ModuleEntry ); } BOOL __inline MatchSymbolName( PSYMBOL_ENTRY sym, LPSTR SymName ) { if (SymOptions & SYMOPT_CASE_INSENSITIVE) { if (_stricmp( sym->Name, SymName ) == 0) { return TRUE; } } else { if (strcmp( sym->Name, SymName ) == 0) { return TRUE; } } return FALSE; } PSYMBOL_ENTRY HandleDuplicateSymbols( PPROCESS_ENTRY ProcessEntry, PMODULE_ENTRY mi, PSYMBOL_ENTRY sym ) { DWORD i; DWORD Dups; DWORD NameSize; PIMAGEHLP_SYMBOL Syms; PIMAGEHLP_DUPLICATE_SYMBOL DupSym; PULONG SymSave; if (!ProcessEntry->pCallbackFunction) { return sym; } if (!(sym->Flags & SYMF_DUPLICATE)) { return sym; } Dups = 0; NameSize = 0; for (i=0; inumsyms; i++) { if ((mi->symbolTable[i].NameLength == sym->NameLength) && (strcmp( mi->symbolTable[i].Name, sym->Name ) == 0)) { Dups += 1; NameSize += (mi->symbolTable[i].NameLength + 1); } } DupSym = (PIMAGEHLP_DUPLICATE_SYMBOL) MemAlloc( sizeof(IMAGEHLP_DUPLICATE_SYMBOL) ); if (!DupSym) { return sym; } Syms = (PIMAGEHLP_SYMBOL) MemAlloc( (sizeof(IMAGEHLP_SYMBOL) * Dups) + NameSize ); if (!Syms) { MemFree( DupSym ); return sym; } SymSave = (PULONG) MemAlloc( sizeof(ULONG) * Dups ); if (!SymSave) { MemFree( Syms ); MemFree( DupSym ); return sym; } DupSym->SizeOfStruct = sizeof(IMAGEHLP_DUPLICATE_SYMBOL); DupSym->NumberOfDups = Dups; DupSym->Symbol = Syms; DupSym->SelectedSymbol = (ULONG) -1; Dups = 0; for (i=0; inumsyms; i++) { if ((mi->symbolTable[i].NameLength == sym->NameLength) && (strcmp( mi->symbolTable[i].Name, sym->Name ) == 0)) { symcpy( Syms, &mi->symbolTable[i] ); Syms += (sizeof(IMAGEHLP_SYMBOL) + mi->symbolTable[i].NameLength + 1); SymSave[Dups] = i; Dups += 1; } } sym = NULL; __try { ProcessEntry->pCallbackFunction( ProcessEntry->hProcess, CBA_DUPLICATE_SYMBOL, (PVOID) DupSym, ProcessEntry->CallbackUserContext ); if (DupSym->SelectedSymbol != (ULONG) -1) { if (DupSym->SelectedSymbol >= DupSym->NumberOfDups) { return sym; } sym = &mi->symbolTable[SymSave[DupSym->SelectedSymbol]]; } } __except (EXCEPTION_EXECUTE_HANDLER) { } MemFree( DupSym ); MemFree( Syms ); MemFree( SymSave ); return sym; } PSYMBOL_ENTRY FindSymbolByName( PPROCESS_ENTRY ProcessEntry, PMODULE_ENTRY mi, LPSTR SymName ) { DWORD Hash; PSYMBOL_ENTRY sym; DWORD i; LPSTR name; LPSTR p; int rslt; if (mi->SymType == SymPdb) { DATASYM32 *dataSym = (DATASYM32*)GSINextSym( mi->gsi, NULL ); PIMAGE_SECTION_HEADER sh; DWORD addr; ULONG k; LPSTR PdbSymbolName; CHAR PdbSymbolLen; while( dataSym ) { PdbSymbolName = DataSymNameStart(dataSym); PdbSymbolLen = DataSymNameLength(dataSym); for (k=0,addr=0,sh=mi->SectionHdrs; kNumSections; k++, sh++) { if (k+1 == DataSymSeg(dataSym)) { addr = sh->VirtualAddress + DataSymOffset(dataSym) + mi->BaseOfDll; break; } } if (addr) { if (SymOptions & SYMOPT_UNDNAME) { SymUnDNameInternal( mi->TmpSym.Name, TMP_SYM_LEN-sizeof(mi->TmpSym), PdbSymbolName, PdbSymbolLen ); } else { mi->TmpSym.Name[0] = 0; strncat( mi->TmpSym.Name, PdbSymbolName, TMP_SYM_LEN-sizeof(mi->TmpSym) ); } if (SymOptions & SYMOPT_CASE_INSENSITIVE) { rslt = _stricmp( mi->TmpSym.Name, SymName ); } else { rslt = strcmp( mi->TmpSym.Name, SymName ); } if (rslt == 0) { mi->TmpSym.Name[0] = 0; mi->TmpSym.Size = 0; mi->TmpSym.Flags = 0; if (mi->cOmapTo) { DWORD SaveAddr = addr; DWORD Bias = 0; addr = ConvertOmapToSrc( mi, addr, &Bias ); if (!addr) { addr = SaveAddr; } else { addr += Bias; } } mi->TmpSym.Address = addr; mi->TmpSym.NameLength = 0; return &mi->TmpSym; } } dataSym = (DATASYM32*)GSINextSym( mi->gsi, (PUCHAR)dataSym ); } return NULL; } Hash = ComputeHash( SymName, strlen(SymName) ); sym = mi->NameHashTable[Hash]; if (sym) { // // there are collision(s) so lets walk the // collision list and match the names // while( sym ) { if (MatchSymbolName( sym, SymName )) { sym = HandleDuplicateSymbols( ProcessEntry, mi, sym ); return sym; } sym = sym->Next; } } // // the symbol did not hash to anything valid // this is possible if the caller passed an undecorated name // now we must look linearly thru the list // for (i=0; inumsyms; i++) { sym = &mi->symbolTable[i]; if (MatchSymbolName( sym, SymName )) { sym = HandleDuplicateSymbols( ProcessEntry, mi, sym ); return sym; } } return NULL; } PIMAGE_FUNCTION_ENTRY LookupFunctionEntry ( PIMAGE_FUNCTION_ENTRY FunctionTable, DWORD NumberOfFunctions, DWORD ControlPc ) { PIMAGE_FUNCTION_ENTRY FunctionEntry; LONG High; LONG Low; LONG Middle; // // Initialize search indicies. // Low = 0; High = NumberOfFunctions - 1; // // Perform binary search on the function table for a function table // entry that subsumes the specified PC. // while (High >= Low) { // // Compute next probe index and test entry. If the specified PC // is greater than of equal to the beginning address and less // than the ending address of the function table entry, then // return the address of the function table entry. Otherwise, // continue the search. // Middle = (Low + High) >> 1; FunctionEntry = &FunctionTable[Middle]; if (ControlPc < FunctionEntry->StartingAddress) { High = Middle - 1; } else if (ControlPc >= FunctionEntry->EndingAddress) { Low = Middle + 1; } else { return FunctionEntry; } } // // A function table entry for the specified PC was not found. // return NULL; } PFPO_DATA SwSearchFpoData( DWORD key, PFPO_DATA base, DWORD num ) { PFPO_DATA lo = base; PFPO_DATA hi = base + (num - 1); PFPO_DATA mid; DWORD half; while (lo <= hi) { if (half = num / 2) { mid = lo + ((num & 1) ? half : (half - 1)); if ((key >= mid->ulOffStart)&&(key < (mid->ulOffStart+mid->cbProcSize))) { return mid; } if (key < mid->ulOffStart) { hi = mid - 1; num = (num & 1) ? half : half-1; } else { lo = mid + 1; num = half; } } else if (num) { if ((key >= lo->ulOffStart)&&(key < (lo->ulOffStart+lo->cbProcSize))) { return lo; } else { break; } } else { break; } } return(NULL); } BOOL DoSymbolCallback( PPROCESS_ENTRY ProcessEntry, ULONG CallbackType, ULONG BaseOfDll, ULONG CheckSum, ULONG TimeDateStamp, LPSTR FileName ) { IMAGEHLP_DEFERRED_SYMBOL_LOAD idsl; if (!ProcessEntry->pCallbackFunction) { return TRUE; } idsl.SizeOfStruct = sizeof(IMAGEHLP_DEFERRED_SYMBOL_LOAD); idsl.BaseOfImage = BaseOfDll; idsl.CheckSum = CheckSum; idsl.TimeDateStamp = TimeDateStamp; idsl.FileName[0] = 0; if (FileName) { strncat( idsl.FileName, FileName, sizeof(idsl.FileName) ); } __try { ProcessEntry->pCallbackFunction( ProcessEntry->hProcess, CallbackType, (PVOID) &idsl, ProcessEntry->CallbackUserContext ); } __except (EXCEPTION_EXECUTE_HANDLER) { return FALSE; } return TRUE; } BOOL CompleteDeferredSymbolLoad( IN HANDLE hProcess, IN PMODULE_ENTRY mi ) { PPROCESS_ENTRY ProcessEntry; ULONG i; PIMAGE_DEBUG_INFORMATION di; ULONG bias; PIMAGE_COFF_SYMBOLS_HEADER lpDebugInfo; PIMAGE_SYMBOL lpSymbolEntry; PUCHAR lpStringTable; PUCHAR p; BOOL SymbolsLoaded = FALSE; ProcessEntry = FindProcessEntry( hProcess ); if (!ProcessEntry) { return FALSE; } DoSymbolCallback( ProcessEntry, CBA_DEFERRED_SYMBOL_LOAD_START, mi->BaseOfDll, mi->CheckSum, mi->TimeDateStamp, mi->LoadedImageName ? mi->LoadedImageName : mi->ImageName ? mi->ImageName : mi->ModuleName ); di = MapDebugInformation( mi->hFile, mi->ImageName, ProcessEntry->SymbolSearchPath, mi->BaseOfDll ); if (!di) { DoSymbolCallback( ProcessEntry, CBA_DEFERRED_SYMBOL_LOAD_FAILURE, mi->BaseOfDll, mi->CheckSum, mi->TimeDateStamp, mi->LoadedImageName ? mi->LoadedImageName : mi->ImageName ? mi->ImageName : mi->ModuleName ); mi->SymType = SymNone; mi->Flags |= MIF_NO_SYMBOLS; return FALSE; } if (!mi->BaseOfDll) { mi->BaseOfDll = di->ImageBase; } if (!mi->DllSize) { mi->DllSize = di->SizeOfImage; } mi->CheckSum = di->CheckSum; mi->MachineType = di->Machine; mi->LoadedImageName = StringDup(di->DebugFilePath); if (!mi->ImageName) { mi->ImageName = StringDup(di->ImageFilePath); _splitpath( mi->ImageName, NULL, NULL, mi->ModuleName, NULL ); mi->AliasName[0] = 0; } if (di->NumberOfFunctionTableEntries) { // // use virtualalloc() because the rtf search function // return a pointer into this memory. we want to make // all of this memory read only so that callers cannot // stomp on imagehlp's data // mi->pExceptionData = VirtualAlloc( NULL, sizeof(IMAGE_FUNCTION_ENTRY) * di->NumberOfFunctionTableEntries, MEM_COMMIT, PAGE_READWRITE ); if (mi->pExceptionData) { mi->dwEntries = di->NumberOfFunctionTableEntries; CopyMemory( mi->pExceptionData, di->FunctionTableEntries, sizeof(IMAGE_FUNCTION_ENTRY) * di->NumberOfFunctionTableEntries ); VirtualProtect( mi->pExceptionData, sizeof(IMAGE_FUNCTION_ENTRY) * di->NumberOfFunctionTableEntries, PAGE_READONLY, &i ); } } else if (di->NumberOfFpoTableEntries) { // // use virtualalloc() because the rtf search function // return a pointer into this memory. we want to make // all of this memory read only so that callers cannot // stomp on imagehlp's data // mi->pFpoData = VirtualAlloc( NULL, sizeof(FPO_DATA) * di->NumberOfFpoTableEntries, MEM_COMMIT, PAGE_READWRITE ); if (mi->pFpoData) { mi->dwEntries = di->NumberOfFpoTableEntries; CopyMemory( mi->pFpoData, di->FpoTableEntries, sizeof(FPO_DATA) * di->NumberOfFpoTableEntries ); VirtualProtect( mi->pExceptionData, sizeof(IMAGE_FUNCTION_ENTRY) * di->NumberOfFunctionTableEntries, PAGE_READONLY, &i ); } } mi->NumSections = di->NumberOfSections; mi->OriginalNumSections = di->NumberOfSections; // Init to this until we know better. mi->SectionHdrs = (PIMAGE_SECTION_HEADER) MemAlloc( sizeof(IMAGE_SECTION_HEADER) * di->NumberOfSections ); if (mi->SectionHdrs) { CopyMemory( mi->SectionHdrs, di->Sections, sizeof(IMAGE_SECTION_HEADER) * di->NumberOfSections ); } mi->TmpSym.Name = (LPSTR) MemAlloc( TMP_SYM_LEN ); LoadOmap( mi, di ); if (di->SizeOfCodeViewSymbols) { SymbolsLoaded = LoadCodeViewSymbols( hProcess, mi, (PUCHAR) di->CodeViewSymbols, di->SizeOfCodeViewSymbols, di->MappedBase ); } if (!SymbolsLoaded && di->SizeOfCoffSymbols) { lpDebugInfo = di->CoffSymbols; lpSymbolEntry = (PIMAGE_SYMBOL)((ULONG)lpDebugInfo + lpDebugInfo->LvaToFirstSymbol); lpStringTable = (PUCHAR)((ULONG)lpDebugInfo + lpDebugInfo->LvaToFirstSymbol + lpDebugInfo->NumberOfSymbols * IMAGE_SIZEOF_SYMBOL); SymbolsLoaded = LoadCoffSymbols( hProcess, mi, lpStringTable, lpSymbolEntry, lpDebugInfo->NumberOfSymbols ); } if (!SymbolsLoaded) { if (ImageNtHeader(di->MappedBase)) { SymbolsLoaded = LoadExportSymbols( mi, di ); } else { SymbolsLoaded = LoadSYMSymbols( mi, di ); } } if (!SymbolsLoaded) { mi->SymType = SymNone; } ProcessOmapForModule( mi ); UnmapDebugInformation( di ); mi->Flags &= ~MIF_DEFERRED_LOAD; DoSymbolCallback( ProcessEntry, CBA_DEFERRED_SYMBOL_LOAD_COMPLETE, mi->BaseOfDll, mi->CheckSum, mi->TimeDateStamp, mi->LoadedImageName ? mi->LoadedImageName : mi->ImageName ? mi->ImageName : mi->ModuleName ); return TRUE; } BOOL InternalLoadModule( IN HANDLE hProcess, IN PSTR ImageName, IN PSTR ModuleName, IN DWORD BaseOfDll, IN DWORD DllSize, IN HANDLE hFile ) { PPROCESS_ENTRY ProcessEntry; PMODULE_ENTRY mi; LPSTR p; ProcessEntry = FindProcessEntry( hProcess ); if (!ProcessEntry) { return FALSE; } if (BaseOfDll) { mi = GetModuleForPC( ProcessEntry, BaseOfDll, TRUE ); } else { mi = NULL; } if (mi) { // // in this case the symbols are already loaded // so the caller really wants the deferred // symbols to be loaded // if (mi->Flags & MIF_DEFERRED_LOAD) { if (CompleteDeferredSymbolLoad( hProcess, mi )) { return mi->BaseOfDll; } else { return FALSE; } } return FALSE; } // // look to see if there is an overlapping module entry // if (BaseOfDll) { do { mi = GetModuleForPC( ProcessEntry, BaseOfDll, FALSE ); if (mi) { RemoveEntryList( &mi->ListEntry ); DoSymbolCallback( ProcessEntry, CBA_SYMBOLS_UNLOADED, mi->BaseOfDll, mi->CheckSum, mi->TimeDateStamp, mi->LoadedImageName ? mi->LoadedImageName : mi->ImageName ? mi->ImageName : mi->ModuleName ); FreeModuleEntry( mi ); } } while( mi ); } mi = (PMODULE_ENTRY) MemAlloc( sizeof(MODULE_ENTRY) ); if (!mi) { return FALSE; } ZeroMemory( mi, sizeof(MODULE_ENTRY) ); mi->BaseOfDll = BaseOfDll; mi->DllSize = DllSize; mi->hFile = hFile; if (ImageName) { mi->ImageName = StringDup(ImageName); _splitpath( ImageName, NULL, NULL, mi->ModuleName, NULL ); if (ModuleName && _stricmp( ModuleName, mi->ModuleName ) != 0) { strcpy( mi->AliasName, ModuleName ); } else { mi->AliasName[0] = 0; } } else { if (ModuleName) { strcpy( mi->AliasName, ModuleName ); } } if ((SymOptions & SYMOPT_DEFERRED_LOADS) && BaseOfDll) { mi->Flags |= MIF_DEFERRED_LOAD; mi->SymType = SymDeferred; } else { CompleteDeferredSymbolLoad( hProcess, mi ); } ProcessEntry->Count += 1; InsertTailList( &ProcessEntry->ModuleList, &mi->ListEntry, ); return mi->BaseOfDll; } PPROCESS_ENTRY FindProcessEntry( HANDLE hProcess ) { PLIST_ENTRY Next; PPROCESS_ENTRY ProcessEntry; Next = ProcessList.Flink; if (!Next) { return NULL; } while ((ULONG)Next != (ULONG)&ProcessList) { ProcessEntry = CONTAINING_RECORD( Next, PROCESS_ENTRY, ListEntry ); Next = ProcessEntry->ListEntry.Flink; if (ProcessEntry->hProcess == hProcess) { return ProcessEntry; } } return NULL; } PSYMBOL_ENTRY GetSymFromAddr( DWORD dwAddr, PDWORD pdwDisplacement, PMODULE_ENTRY mi ) { PSYMBOL_ENTRY sym; PIMAGE_SECTION_HEADER sh; DWORD i; DATASYM32 *dataSym; LONG High; LONG Low; LONG Middle; if (mi == NULL) { return NULL; } if (mi->SymType == SymPdb) { DWORD Bias; DWORD OptimizedSymAddr = ConvertOmapFromSrc( mi, dwAddr, &Bias ); if (!OptimizedSymAddr) { // // No equivalent address // dwAddr = 0; } else if (OptimizedSymAddr != dwAddr) { // // We have successfully converted // dwAddr = OptimizedSymAddr + Bias - mi->BaseOfDll; } // // locate the section that the address resides in // for (i=0, sh=mi->SectionHdrs; i < mi->NumSections; i++, sh++) { if (dwAddr - mi->BaseOfDll >= sh->VirtualAddress && dwAddr - mi->BaseOfDll < sh->VirtualAddress + sh->SizeOfRawData) { // // found the section // break; } } if (i == mi->NumSections) { return NULL; } dataSym = (DATASYM32*)GSINearestSym( mi->gsi, (USHORT)(i+1), dwAddr - mi->BaseOfDll - sh->VirtualAddress, (PLONG) pdwDisplacement ); if (dataSym) { mi->TmpSym.Size = 0; mi->TmpSym.Flags = 0; mi->TmpSym.Address = dwAddr; if (SymOptions & SYMOPT_UNDNAME) { SymUnDNameInternal( mi->TmpSym.Name, TMP_SYM_LEN, DataSymNameStart(dataSym), DataSymNameLength(dataSym)); } else { mi->TmpSym.NameLength = DataSymNameLength(dataSym); memcpy( mi->TmpSym.Name, DataSymNameStart(dataSym), mi->TmpSym.NameLength ); mi->TmpSym.Name[mi->TmpSym.NameLength] = 0; } return &mi->TmpSym; } return NULL; } // // do a binary search to locate the symbol // Low = 0; High = mi->numsyms - 1; while (High >= Low) { Middle = (Low + High) >> 1; sym = &mi->symbolTable[Middle]; if (dwAddr < sym->Address) { High = Middle - 1; } else if (dwAddr >= sym->Address + sym->Size) { Low = Middle + 1; } else { *pdwDisplacement = dwAddr - sym->Address; return sym; } } return NULL; } PMODULE_ENTRY GetModuleForPC( PPROCESS_ENTRY ProcessEntry, DWORD dwPcAddr, BOOL ExactMatch ) { static PLIST_ENTRY Next = NULL; PMODULE_ENTRY ModuleEntry; if (dwPcAddr == (DWORD)-1) { if ((ULONG)Next == (ULONG)&ProcessEntry->ModuleList) { return NULL; } ModuleEntry = CONTAINING_RECORD( Next, MODULE_ENTRY, ListEntry ); Next = ModuleEntry->ListEntry.Flink; return ModuleEntry; } Next = ProcessEntry->ModuleList.Flink; if (!Next) { return NULL; } while ((ULONG)Next != (ULONG)&ProcessEntry->ModuleList) { ModuleEntry = CONTAINING_RECORD( Next, MODULE_ENTRY, ListEntry ); Next = ModuleEntry->ListEntry.Flink; if (dwPcAddr == 0) { return ModuleEntry; } if (ExactMatch) { if (dwPcAddr == ModuleEntry->BaseOfDll) { return ModuleEntry; } } else if ((dwPcAddr == ModuleEntry->BaseOfDll && ModuleEntry->DllSize == 0) || ((dwPcAddr >= ModuleEntry->BaseOfDll) && (dwPcAddr < ModuleEntry->BaseOfDll + ModuleEntry->DllSize))) { return ModuleEntry; } } return NULL; } PSYMBOL_ENTRY GetSymFromAddrAllContexts( DWORD dwAddr, PDWORD pdwDisplacement, PPROCESS_ENTRY ProcessEntry ) { PMODULE_ENTRY mi = GetModuleForPC( ProcessEntry, dwAddr, FALSE ); if (mi == NULL) { return NULL; } return GetSymFromAddr( dwAddr, pdwDisplacement, mi ); } DWORD ComputeHash( LPSTR lpbName, ULONG cb ) { ULONG UNALIGNED * lpulName; ULONG ulEnd = 0; int cul; int iul; ULONG ulSum = 0; while (cb & 3) { ulEnd |= (lpbName[cb - 1] & 0xdf); ulEnd <<= 8; cb -= 1; } cul = cb / 4; lpulName = (ULONG UNALIGNED *) lpbName; for (iul =0; iul < cul; iul++) { ulSum ^= (lpulName[iul] & 0xdfdfdfdf); ulSum = _lrotl( ulSum, 4); } ulSum ^= ulEnd; return ulSum % HASH_MODULO; } PSYMBOL_ENTRY AllocSym( PMODULE_ENTRY mi, DWORD addr, LPSTR name ) { PSYMBOL_ENTRY sym; ULONG Length; if (mi->numsyms == mi->MaxSyms) { return NULL; } if (!mi->StringSize) { return NULL; } Length = strlen(name); if ((Length + 1) > mi->StringSize) { return NULL; } sym = &mi->symbolTable[mi->numsyms]; mi->numsyms += 1; sym->Name = mi->SymStrings; mi->SymStrings += (Length + 2); mi->StringSize -= (Length + 2); strcpy( sym->Name, name ); sym->Address = addr; sym->Size = 0; sym->Flags = 0; sym->Next = NULL; sym->NameLength = Length; return sym; } int _CRTAPI1 SymbolTableAddressCompare( const void *e1, const void *e2 ) { PSYMBOL_ENTRY sym1 = (PSYMBOL_ENTRY) e1; PSYMBOL_ENTRY sym2 = (PSYMBOL_ENTRY) e2; if ( sym1 && sym2 ) { return (sym1->Address - sym2->Address); } else { return 1; } } int _CRTAPI1 SymbolTableNameCompare( const void *e1, const void *e2 ) { PSYMBOL_ENTRY sym1 = (PSYMBOL_ENTRY) e1; PSYMBOL_ENTRY sym2 = (PSYMBOL_ENTRY) e2; return strcmp( sym1->Name, sym2->Name ); } VOID CompleteSymbolTable( PMODULE_ENTRY mi ) { PSYMBOL_ENTRY sym; PSYMBOL_ENTRY symH; ULONG Hash; ULONG i; ULONG dups; ULONG seq; // // sort the symbols by name // qsort( mi->symbolTable, mi->numsyms, sizeof(SYMBOL_ENTRY), SymbolTableNameCompare ); // // mark duplicate names // seq = 0; for (i=0; inumsyms; i++) { dups = 0; while ((mi->symbolTable[i+dups].NameLength == mi->symbolTable[i+dups+1].NameLength) && (strcmp( mi->symbolTable[i+dups].Name, mi->symbolTable[i+dups+1].Name ) == 0)) { mi->symbolTable[i+dups].Flags |= SYMF_DUPLICATE; mi->symbolTable[i+dups+1].Flags |= SYMF_DUPLICATE; dups += 1; } i += dups; } // // sort the symbols by address // qsort( mi->symbolTable, mi->numsyms, sizeof(SYMBOL_ENTRY), SymbolTableAddressCompare ); // // calculate the size of each symbol // for (i=0; inumsyms; i++) { mi->symbolTable[i].Next = NULL; if (i+1 < mi->numsyms) { mi->symbolTable[i].Size = mi->symbolTable[i+1].Address - mi->symbolTable[i].Address; } } // // compute the hash for each symbol // ZeroMemory( mi->NameHashTable, sizeof(mi->NameHashTable) ); for (i=0; inumsyms; i++) { sym = &mi->symbolTable[i]; Hash = ComputeHash( sym->Name, sym->NameLength ); if (mi->NameHashTable[Hash]) { // // we have a collision // symH = mi->NameHashTable[Hash]; while( symH->Next ) { symH = symH->Next; } symH->Next = sym; } else { mi->NameHashTable[Hash] = sym; } } } BOOL CreateSymbolTable( PMODULE_ENTRY mi, DWORD SymbolCount, SYM_TYPE SymType, DWORD NameSize ) { // // allocate the symbol table // NameSize += OMAP_SYM_STRINGS; mi->symbolTable = (PSYMBOL_ENTRY) MemAlloc( (sizeof(SYMBOL_ENTRY) * (SymbolCount + OMAP_SYM_EXTRA)) + NameSize + (SymbolCount * CPP_EXTRA) ); if (!mi->symbolTable) { return FALSE; } // // initialize the relevant fields // mi->numsyms = 0; mi->MaxSyms = SymbolCount + OMAP_SYM_EXTRA; mi->SymType = SymType; mi->StringSize = NameSize + (SymbolCount * CPP_EXTRA); mi->SymStrings = (LPSTR)(mi->symbolTable + SymbolCount + OMAP_SYM_EXTRA); return TRUE; } BOOL LoadOmap( PMODULE_ENTRY mi, PIMAGE_DEBUG_INFORMATION di ) { PIMAGE_DEBUG_DIRECTORY pDebugDir; ULONG ulDebugDirCount; ULONG cb; PVOID pv; pDebugDir = di->DebugDirectory; ulDebugDirCount = di->NumberOfDebugDirectories; while (ulDebugDirCount--) { cb = pDebugDir->SizeOfData; pv = (PVOID) ((DWORD)di->MappedBase + pDebugDir->PointerToRawData); switch (pDebugDir->Type) { case IMAGE_DEBUG_TYPE_OMAP_TO_SRC: mi->pOmapTo = (POMAP) MemAlloc( cb ); RtlCopyMemory( mi->pOmapTo, pv, cb); mi->cOmapTo = cb / sizeof(OMAP); break; case IMAGE_DEBUG_TYPE_OMAP_FROM_SRC: mi->pOmapFrom = (POMAP) MemAlloc( cb ); RtlCopyMemory( mi->pOmapFrom, pv, cb); mi->cOmapFrom = cb / sizeof(OMAP); break; } pDebugDir++; } return TRUE; } PIMAGE_SECTION_HEADER __inline FindSection( PIMAGE_SECTION_HEADER sh, ULONG NumSections, ULONG Address ) { ULONG i; for (i=0; i= sh[i].VirtualAddress && Address < (sh[i].VirtualAddress + sh[i].SizeOfRawData)) { return &sh[i]; } } return NULL; } ULONG __inline GetSectionPhysical( PIMAGE_SECTION_HEADER sh, ULONG NumSections, ULONG BaseOfDll, ULONG Address ) { sh = FindSection( sh, NumSections, Address ); if (!sh) { return 0; } return BaseOfDll + sh->PointerToRawData + (Address - sh->VirtualAddress); } ULONG LoadExportSymbols( PMODULE_ENTRY mi, PIMAGE_DEBUG_INFORMATION di ) { PIMAGE_SECTION_HEADER sh; PULONG names; PULONG addrs; PUSHORT ordinals; PUSHORT ordidx = NULL; ULONG cnt = 0; ULONG idx; PIMAGE_EXPORT_DIRECTORY expdir; PIMAGE_DOS_HEADER dh; PIMAGE_NT_HEADERS nh; ULONG i; PSYMBOL_ENTRY sym; LPSTR NameBuf = NULL; LPSTR Name; DWORD NameSize; dh = (PIMAGE_DOS_HEADER) di->MappedBase; if (dh->e_magic != IMAGE_DOS_SIGNATURE) { goto exit; } nh = (PIMAGE_NT_HEADERS) ((ULONG)di->MappedBase + dh->e_lfanew); sh = mi->SectionHdrs; expdir = (PIMAGE_EXPORT_DIRECTORY) GetSectionPhysical( mi->SectionHdrs, mi->NumSections, (ULONG)di->MappedBase, nh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress ); if (!expdir) { goto exit; } names = (PULONG) GetSectionPhysical( mi->SectionHdrs, mi->NumSections, (ULONG)di->MappedBase, (ULONG)expdir->AddressOfNames ); if (!names) { goto exit; } addrs = (PULONG) GetSectionPhysical( mi->SectionHdrs, mi->NumSections, (ULONG)di->MappedBase, (ULONG)expdir->AddressOfFunctions ); if (!addrs) { goto exit; } ordinals = (PUSHORT) GetSectionPhysical( mi->SectionHdrs, mi->NumSections, (ULONG)di->MappedBase, (ULONG)expdir->AddressOfNameOrdinals ); if (!ordinals) { goto exit; } ordidx = (PUSHORT) MemAlloc( expdir->NumberOfFunctions * sizeof(USHORT) ); if (!ordidx) { goto exit; } NameBuf = (LPSTR) MemAlloc( 4096 ); if (!NameBuf) { goto exit; } cnt = 0; NameSize = 0; // // count the symbols // for (i=0; iNumberOfNames; i++) { Name = (LPSTR) GetSectionPhysical( mi->SectionHdrs, mi->NumSections, (ULONG)di->MappedBase, names[i] ); if (!Name) { continue; } if (SymOptions & SYMOPT_UNDNAME) { SymUnDNameInternal( mi->TmpSym.Name, TMP_SYM_LEN, (LPSTR)Name, strlen(Name) ); NameSize += strlen(mi->TmpSym.Name); cnt += 1; } else { NameSize += (strlen(Name) + 2); cnt += 1; } } for (i=0,idx=expdir->NumberOfNames; iNumberOfFunctions; i++) { if (!ordidx[i]) { NameSize += 16; cnt += 1; } } // // allocate the symbol table // if (!CreateSymbolTable( mi, cnt, SymExport, NameSize )) { return FALSE; } // // allocate the symbols // cnt = 0; for (i=0; iNumberOfNames; i++) { idx = ordinals[i]; ordidx[idx] = TRUE; Name = (LPSTR) GetSectionPhysical( mi->SectionHdrs, mi->NumSections, (ULONG)di->MappedBase, names[i] ); if (!Name) { continue; } if (SymOptions & SYMOPT_UNDNAME) { SymUnDNameInternal( mi->TmpSym.Name, TMP_SYM_LEN, (LPSTR)Name, strlen(Name) ); sym = AllocSym( mi, addrs[idx] + mi->BaseOfDll, mi->TmpSym.Name); } else { sym = AllocSym( mi, addrs[idx] + mi->BaseOfDll, Name); } if (sym) { cnt += 1; } } for (i=0,idx=expdir->NumberOfNames; iNumberOfFunctions; i++) { if (!ordidx[i]) { strcpy( NameBuf, "Ordinal" ); _itoa( i+expdir->Base, &NameBuf[7], 10 ); sym = AllocSym( mi, addrs[i] + mi->BaseOfDll, NameBuf); if (sym) { cnt += 1; } idx += 1; } } CompleteSymbolTable( mi ); exit: MemFree( ordidx ); MemFree( NameBuf ); return cnt; } LPBYTE GetPascalString( LPBYTE pb, LPSTR pStr ) { UINT iLen = *pb++; while (iLen--) { *pStr++ = *pb++; } *pStr = '\0'; return pb; } ULONG LoadSYMSymbols( PMODULE_ENTRY mi, PIMAGE_DEBUG_INFORMATION di ) { typedef struct _symfileheader { DWORD dwSizePara; WORD wInfo; WORD wSymCnt; WORD wAbsOff; WORD wSectCnt; WORD wSectOff; } SYMFILEHEADER, *PSYMFILEHEADER; typedef struct _symsectheader { WORD wNextOff; WORD wSymCnt; WORD wIdxOff; WORD wSegNum; WORD wInfo1; WORD wInfo2; WORD wInfo3; WORD wFlags; WORD wInfo5; WORD wInfo6; } SYMSECTHEADER, *PSYMSECTHEADER; #define SSH_LARGE_OFFSETS 0x0001 #define SSH_LARGE_INDICES 0x0004 PSYMFILEHEADER psfh = (PSYMFILEHEADER)di->MappedBase; PSYMSECTHEADER pssh; PIMAGE_SECTION_HEADER pish; WIN32_FIND_DATA wfd; HANDLE hFind; ULONG nSymbols = 0; WORD wOffset; UINT iSect; WORD wSectCnt; CHAR NameBuff[1024]; DWORD NameSize; LPSTR pName; LPBYTE pb; DWORD addr; UINT iPass; UINT iSym; DWORD dwOffset; UINT nLen; UINT cnt; __try { // // Validate that its an appropriate .SYM file // hFind = FindFirstFile(di->DebugFilePath,&wfd); if (hFind == INVALID_HANDLE_VALUE) goto BlowOff; FindClose(hFind); if (psfh->dwSizePara != (wfd.nFileSizeLow >> 4) || psfh->wAbsOff > (wfd.nFileSizeLow >> 4) || psfh->wSectOff > (wfd.nFileSizeLow >> 4)) goto BlowOff; // // Iterate through the sections (once to count symbols sizes) // NameSize = 0; cnt = 0; iPass = 1; while (iPass <= 2) { if (iPass == 2) { // // allocate the symbol table // if (!CreateSymbolTable( mi, cnt, SymSym, NameSize )) { goto BlowOff; } } wOffset = psfh->wSectOff; pish = di->Sections; iSect = psfh->wSectCnt; while (iSect != 0 && (wOffset < wfd.nFileSizeLow >> 4) && wOffset != 0) { pssh = (PSYMSECTHEADER)((LPBYTE)di->MappedBase + ((LONG)wOffset << 4)); pb = (LPBYTE)(pssh + 1); pb = GetPascalString( pb, NameBuff ); // Blow off section name addr = mi->BaseOfDll + pish[pssh->wSegNum-1].VirtualAddress; iSym = pssh->wSymCnt; while (iSym != 0) { if (pssh->wFlags & SSH_LARGE_OFFSETS) { dwOffset = *(UNALIGNED DWORD *)pb; pb += sizeof(DWORD); } else { dwOffset = (DWORD)*((UNALIGNED WORD *)pb); pb += sizeof(WORD); } pb = GetPascalString( pb, NameBuff ); nLen = lstrlen(NameBuff); // // ignore strings // if (NameBuff[0] != '?' || NameBuff[1] != '?' || NameBuff[2] != '_' || NameBuff[3] != 'C' ) { // // Found a non-string, should we undecorate the name? // pName = NameBuff; if (SymOptions & SYMOPT_UNDNAME) { SymUnDNameInternal( mi->TmpSym.Name, TMP_SYM_LEN, NameBuff, strlen(NameBuff) ); pName = mi->TmpSym.Name; } nLen = strlen(pName); if (nLen != 0) { // Ignore empty strings if (iPass == 1) { cnt++; NameSize += nLen + 2; } else { AllocSym( mi, dwOffset + addr, pName); } } } --iSym; } wOffset = pssh->wNextOff; --iSect; } iPass++; } CompleteSymbolTable( mi ); nSymbols = cnt; BlowOff: iSect++; // Do nothing } __except (EXCEPTION_EXECUTE_HANDLER) { // // Just fail // nSymbols = 0; } return nSymbols; } BOOL LoadCoffSymbols( HANDLE hProcess, PMODULE_ENTRY mi, PUCHAR stringTable, PIMAGE_SYMBOL allSymbols, DWORD numberOfSymbols ) { PIMAGE_SYMBOL NextSymbol; PIMAGE_SYMBOL Symbol; PIMAGE_AUX_SYMBOL AuxSymbol; PSYMBOL_ENTRY sym; CHAR szSymName[256]; DWORD numaux; DWORD i; DWORD j; DWORD addr; DWORD CoffSymbols = 0; DWORD NameSize = 0; // // count the number of actual symbols // NextSymbol = allSymbols; for (i= 0; i < numberOfSymbols; i++) { Symbol = NextSymbol++; if (Symbol->StorageClass == IMAGE_SYM_CLASS_EXTERNAL && Symbol->SectionNumber > 0) { GetSymName( Symbol, stringTable, szSymName, sizeof(szSymName) ); if (szSymName[0] == '?' && szSymName[1] == '?' && szSymName[2] == '_' && szSymName[3] == 'C' ) { // // ignore strings // } else if (SymOptions & SYMOPT_UNDNAME) { SymUnDNameInternal( mi->TmpSym.Name, TMP_SYM_LEN, szSymName, strlen(szSymName) ); NameSize += strlen(mi->TmpSym.Name); CoffSymbols += 1; } else { CoffSymbols += 1; NameSize += (strlen(szSymName) + 1); } } if (numaux = Symbol->NumberOfAuxSymbols) { for (j=numaux; j; --j) { AuxSymbol = (PIMAGE_AUX_SYMBOL) NextSymbol; NextSymbol++; ++i; } } } // // allocate the symbol table // if (!CreateSymbolTable( mi, CoffSymbols, SymCoff, NameSize )) { return FALSE; } // // populate the symbol table // NextSymbol = allSymbols; for (i= 0; i < numberOfSymbols; i++) { Symbol = NextSymbol++; if (Symbol->StorageClass == IMAGE_SYM_CLASS_EXTERNAL && Symbol->SectionNumber > 0) { GetSymName( Symbol, stringTable, szSymName, sizeof(szSymName) ); addr = Symbol->Value + mi->BaseOfDll; if (szSymName[0] == '?' && szSymName[1] == '?' && szSymName[2] == '_' && szSymName[3] == 'C' ) { // // ignore strings // } else if (SymOptions & SYMOPT_UNDNAME) { SymUnDNameInternal( mi->TmpSym.Name, TMP_SYM_LEN, szSymName, strlen(szSymName) ); AllocSym( mi, addr, mi->TmpSym.Name); } else { AllocSym( mi, addr, szSymName ); } } if (numaux = Symbol->NumberOfAuxSymbols) { for (j=numaux; j; --j) { AuxSymbol = (PIMAGE_AUX_SYMBOL) NextSymbol; NextSymbol++; ++i; } } } CompleteSymbolTable( mi ); return TRUE; } BOOL LoadCodeViewSymbols( HANDLE hProcess, PMODULE_ENTRY mi, PUCHAR pCvData, DWORD dwSize, PVOID MappedBase ) { PPROCESS_ENTRY ProcessEntry; CHAR ErrorText[1024]; OMFSignature *omfSig; OMFDirHeader *omfDirHdr; OMFDirEntry *omfDirEntry; DATASYM32 *dataSym; OMFSymHash *omfSymHash; OMFSegMap *omfSegMap; OMFSegMapDesc *omfSegMapDesc; PIMAGE_DOS_HEADER dh; PIMAGE_NT_HEADERS nh; PSYMBOL_ENTRY sym; DWORD i; DWORD j; DWORD k; DWORD addr; PIMAGE_SECTION_HEADER sh; PPDB_INFO PdbInfo; CHAR Path[MAX_PATH]; CHAR PdbName[MAX_PATH]; CHAR Fname[MAX_PATH]; CHAR Ext[_MAX_EXT]; CHAR Drive[_MAX_DRIVE]; CHAR Dir[_MAX_DIR]; HANDLE hPdb; DWORD CvSymbols = 0; DWORD NameSize = 0; DWORD LastSectionStart = 0; DWORD LastSectionSize = 0; DWORD ImageAlign = 0; ProcessEntry = FindProcessEntry( hProcess ); if (!ProcessEntry) { return FALSE; } omfSig = (OMFSignature*) pCvData; if ((*(DWORD *)(omfSig->Signature) != '80BN') && (*(DWORD *)(omfSig->Signature) != '90BN') && (*(DWORD *)(omfSig->Signature) != '01BN')) { return FALSE; } if (*(DWORD *)(omfSig->Signature) == '01BN') { PdbInfo = (PPDB_INFO) pCvData; _splitpath( mi->LoadedImageName, Drive, Dir, NULL, NULL ); _makepath( Path, Drive, Dir, NULL, NULL ); if (!PDBOpenValidate( PdbInfo->PdbName, Path, "r", PdbInfo->sig, PdbInfo->age, (PLONG) &i, ErrorText, &mi->pdb )) { // // either the pdb could not be found or // it's signature/age did not match // // now lets look down the _nt_symbol_path // _splitpath( PdbInfo->PdbName, NULL, NULL, Fname, Ext ); strcat( Fname, Ext ); hPdb = FindExecutableImage( Fname, ProcessEntry->SymbolSearchPath, PdbName ); if (!hPdb) { return FALSE; } CloseHandle( hPdb ); if (!PDBOpenValidate( PdbName, NULL, "r", PdbInfo->sig, PdbInfo->age, (PLONG) &i, ErrorText, &mi->pdb )) { // // the pdb we found along the symbol path is bad too! // return FALSE; } } if (!PDBOpenDBI( mi->pdb, "r", "", &mi->dbi )) { PDBClose( mi->pdb ); return FALSE; } if (!DBIOpenPublics( mi->dbi, &mi->gsi )) { DBIClose( mi->dbi ); PDBClose( mi->pdb ); return FALSE; } mi->SymType = SymPdb; return TRUE; } // // count the number of actual symbols // omfDirHdr = (OMFDirHeader*) ((DWORD)omfSig + (DWORD)omfSig->filepos); omfDirEntry = (OMFDirEntry*) ((DWORD)omfDirHdr + sizeof(OMFDirHeader)); // // get the image alignment // if (*(PUSHORT)MappedBase == IMAGE_SEPARATE_DEBUG_SIGNATURE) { ImageAlign = ((PIMAGE_SEPARATE_DEBUG_HEADER)MappedBase)->SectionAlignment; } else { dh = (PIMAGE_DOS_HEADER)MappedBase; if (dh->e_magic == IMAGE_DOS_SIGNATURE) { nh = (PIMAGE_NT_HEADERS)((ULONG)dh + dh->e_lfanew); } else { nh = (PIMAGE_NT_HEADERS)dh; } ImageAlign = nh->OptionalHeader.SectionAlignment; } if (mi->pOmapFrom) { // // The first DWORD in the omap from table is the first offset of the first section... Start from there. // LastSectionStart = * (DWORD *)mi->pOmapFrom; } else { LastSectionStart = mi->SectionHdrs[0].VirtualAddress; } LastSectionSize = 0; // // get the segment map // for (i=0; icDir; i++,omfDirEntry++) { if (omfDirEntry->SubSection == sstSegMap) { omfSegMap = (OMFSegMap*) ((DWORD)omfSig + omfDirEntry->lfo); omfSegMapDesc = (OMFSegMapDesc*)&omfSegMap->rgDesc[0]; mi->SectionStart = (PSECTION_START) MemAlloc( omfSegMap->cSeg * sizeof(SECTION_START) ); if (!mi->SectionStart) { SetLastError( ERROR_NOT_ENOUGH_MEMORY ); return FALSE; } for (k=0, j=0; jcSeg; j++) { if (omfSegMapDesc[j].frame) { // // The linker sets the frame field to the actual section header number. Zero is // used to track absolute symbols that don't exist in a real sections. // mi->SectionStart[k].Offset = LastSectionStart = LastSectionStart + ((LastSectionSize + (ImageAlign-1)) & ~(ImageAlign-1)); mi->SectionStart[k].Size = LastSectionSize = omfSegMapDesc[j].cbSeg; mi->SectionStart[k].Flags = omfSegMapDesc[j].flags; k++; } } mi->OriginalNumSections = k; break; } } omfDirHdr = (OMFDirHeader*) ((DWORD)omfSig + (DWORD)omfSig->filepos); omfDirEntry = (OMFDirEntry*) ((DWORD)omfDirHdr + sizeof(OMFDirHeader)); for (i=0; icDir; i++,omfDirEntry++) { if (omfDirEntry->SubSection == sstGlobalPub) { omfSymHash = (OMFSymHash*) ((DWORD)omfSig + omfDirEntry->lfo); dataSym = (DATASYM32*) ((DWORD)omfSig + omfDirEntry->lfo + sizeof(OMFSymHash)); for (j=sizeof(OMFSymHash); j<=omfSymHash->cbSymbol; ) { addr = 0; if (dataSym->seg && (dataSym->seg <= mi->OriginalNumSections)) { addr = mi->SectionStart[dataSym->seg-1].Offset + dataSym->off + mi->BaseOfDll; if (dataSym->name[0] == '?' && dataSym->name[1] == '?' && dataSym->name[2] == '_' && dataSym->name[3] == 'C' ) { // // ignore strings // } else if (SymOptions & SYMOPT_UNDNAME) { SymUnDNameInternal( mi->TmpSym.Name, TMP_SYM_LEN, (LPSTR)&dataSym->name[1], dataSym->name[0] ); NameSize += strlen(mi->TmpSym.Name); CvSymbols += 1; } else { CvSymbols += 1; NameSize += ((UCHAR)dataSym->name[0] + 1); } } j += dataSym->reclen + 2; dataSym = (DATASYM32*) ((DWORD)dataSym + dataSym->reclen + 2); } break; } } // // allocate the symbol table // if (!CreateSymbolTable( mi, CvSymbols, SymCv, NameSize )) { return FALSE; } // // populate the symbol table // omfDirHdr = (OMFDirHeader*) ((DWORD)omfSig + (DWORD)omfSig->filepos); omfDirEntry = (OMFDirEntry*) ((DWORD)omfDirHdr + sizeof(OMFDirHeader)); for (i=0; icDir; i++,omfDirEntry++) { if (omfDirEntry->SubSection == sstGlobalPub) { omfSymHash = (OMFSymHash*) ((DWORD)omfSig + omfDirEntry->lfo); dataSym = (DATASYM32*) ((DWORD)omfSig + omfDirEntry->lfo + sizeof(OMFSymHash)); for (j=sizeof(OMFSymHash); j<=omfSymHash->cbSymbol; ) { addr = 0; if (dataSym->seg && (dataSym->seg <= mi->OriginalNumSections)) { addr = mi->SectionStart[dataSym->seg-1].Offset + dataSym->off + mi->BaseOfDll; if (dataSym->name[0] == '?' && dataSym->name[1] == '?' && dataSym->name[2] == '_' && dataSym->name[3] == 'C' ) { // // ignore strings // } else if (SymOptions & SYMOPT_UNDNAME) { SymUnDNameInternal( mi->TmpSym.Name, TMP_SYM_LEN, (LPSTR)&dataSym->name[1], dataSym->name[0] ); AllocSym( mi, addr, (LPSTR) mi->TmpSym.Name); } else { AllocSym( mi, addr, (LPSTR) &dataSym->name[1]); } } j += dataSym->reclen + 2; dataSym = (DATASYM32*) ((DWORD)dataSym + dataSym->reclen + 2); } break; } } CompleteSymbolTable( mi ); return TRUE; } VOID GetSymName( PIMAGE_SYMBOL Symbol, PUCHAR StringTable, LPSTR s, DWORD size ) { DWORD i; if (Symbol->n_zeroes) { for (i=0; i<8; i++) { if ((Symbol->n_name[i]>0x1f) && (Symbol->n_name[i]<0x7f)) { *s++ = Symbol->n_name[i]; } } *s = 0; } else { strncpy( s, (char *) &StringTable[Symbol->n_offset], size ); } } VOID ProcessOmapForModule( PMODULE_ENTRY mi ) { PSYMBOL_ENTRY sym; PSYMBOL_ENTRY symN; DWORD i; if (!mi->pOmapFrom) { return; } if (!mi->symbolTable) { return; } if ((mi->SymType != SymCoff) && (mi->SymType != SymCv)) { return; } for (i=0; inumsyms; i++) { ProcessOmapSymbol( mi, &mi->symbolTable[i] ); } CompleteSymbolTable( mi ); } BOOL ProcessOmapSymbol( PMODULE_ENTRY mi, PSYMBOL_ENTRY sym ) { DWORD bias; DWORD OptimizedSymAddr; DWORD rvaSym; POMAPLIST pomaplistHead; DWORD SymbolValue; DWORD OrgSymAddr; POMAPLIST pomaplistNew; POMAPLIST pomaplistPrev; POMAPLIST pomaplistCur; POMAPLIST pomaplistNext; DWORD rva; DWORD rvaTo; DWORD cb; DWORD end; DWORD rvaToNext; LPSTR NewSymName; CHAR Suffix[32]; DWORD addrNew; POMAP pomap; PSYMBOL_ENTRY symOmap; if ((sym->Flags & SYMF_OMAP_GENERATED) || (sym->Flags & SYMF_OMAP_MODIFIED)) { return FALSE; } OrgSymAddr = SymbolValue = sym->Address; OptimizedSymAddr = ConvertOmapFromSrc( mi, SymbolValue, &bias ); if (OptimizedSymAddr == 0) { // // No equivalent address // sym->Address = 0; return FALSE; } else if (OptimizedSymAddr != sym->Address) { // // We have successfully converted // sym->Address = OptimizedSymAddr + bias; } rvaSym = SymbolValue - mi->BaseOfDll; SymbolValue = sym->Address; pomap = GetOmapEntry( mi, OrgSymAddr ); if (!pomap) { goto exit; } pomaplistHead = NULL; // // Look for all OMAP entries belonging to SymbolEntry // end = OrgSymAddr - mi->BaseOfDll + sym->Size; while (pomap && (pomap->rva < end)) { if (pomap->rvaTo == 0) { pomap++; continue; } // // Allocate and initialize a new entry // pomaplistNew = (POMAPLIST) MemAlloc( sizeof(OMAPLIST) ); if (!pomaplistNew) { return FALSE; } pomaplistNew->omap = *pomap; pomaplistNew->cb = pomap[1].rva - pomap->rva; pomaplistPrev = NULL; pomaplistCur = pomaplistHead; while (pomaplistCur != NULL) { if (pomap->rvaTo < pomaplistCur->omap.rvaTo) { // // Insert between Prev and Cur // break; } pomaplistPrev = pomaplistCur; pomaplistCur = pomaplistCur->next; } if (pomaplistPrev == NULL) { // // Insert in head position // pomaplistHead = pomaplistNew; } else { pomaplistPrev->next = pomaplistNew; } pomaplistNew->next = pomaplistCur; pomap++; } if (pomaplistHead == NULL) { goto exit; } pomaplistCur = pomaplistHead; pomaplistNext = pomaplistHead->next; // // we do have a list // while (pomaplistNext != NULL) { rva = pomaplistCur->omap.rva; rvaTo = pomaplistCur->omap.rvaTo; cb = pomaplistCur->cb; rvaToNext = pomaplistNext->omap.rvaTo; if (rvaToNext == sym->Address - mi->BaseOfDll) { // // Already inserted above // } else if (rvaToNext < (rvaTo + cb + 8)) { // // Adjacent to previous range // } else { addrNew = mi->BaseOfDll + rvaToNext; Suffix[0] = '_'; _ltoa( pomaplistNext->omap.rva - rvaSym, &Suffix[1], 10 ); cb = strlen(Suffix) + sym->NameLength + 2; NewSymName = (LPSTR) MemAlloc( cb ); if (!NewSymName) { return FALSE; } strcpy( NewSymName, sym->Name ); strncpy( &NewSymName[sym->NameLength], Suffix, strlen(Suffix) ); symOmap = AllocSym( mi, addrNew, NewSymName); MemFree( NewSymName ); if (symOmap) { symOmap->Flags |= SYMF_OMAP_GENERATED; } } MemFree(pomaplistCur); pomaplistCur = pomaplistNext; pomaplistNext = pomaplistNext->next; } MemFree(pomaplistCur); exit: if (sym->Address != OrgSymAddr) { sym->Flags |= SYMF_OMAP_MODIFIED; } return TRUE; } DWORD ConvertOmapFromSrc( PMODULE_ENTRY mi, DWORD addr, LPDWORD bias ) { DWORD rva; DWORD comap; POMAP pomapLow; POMAP pomapHigh; DWORD comapHalf; POMAP pomapMid; *bias = 0; if (!mi->pOmapFrom) { return addr; } rva = addr - mi->BaseOfDll; comap = mi->cOmapFrom; pomapLow = mi->pOmapFrom; pomapHigh = pomapLow + comap; while (pomapLow < pomapHigh) { comapHalf = comap / 2; pomapMid = pomapLow + ((comap & 1) ? comapHalf : (comapHalf - 1)); if (rva == pomapMid->rva) { if (pomapMid->rvaTo) { return mi->BaseOfDll + pomapMid->rvaTo; } else { return(0); // No need adding the base. This address was discarded... } } if (rva < pomapMid->rva) { pomapHigh = pomapMid; comap = (comap & 1) ? comapHalf : (comapHalf - 1); } else { pomapLow = pomapMid + 1; comap = comapHalf; } } // // If no exact match, pomapLow points to the next higher address // if (pomapLow == mi->pOmapFrom) { // // This address was not found // return 0; } if (pomapLow[-1].rvaTo == 0) { // // This address is not translated so just return the original // return addr; } // // Return the closest address plus the bias // *bias = rva - pomapLow[-1].rva; return mi->BaseOfDll + pomapLow[-1].rvaTo; } DWORD ConvertOmapToSrc( PMODULE_ENTRY mi, DWORD addr, LPDWORD bias ) { DWORD rva; DWORD comap; POMAP pomapLow; POMAP pomapHigh; DWORD comapHalf; POMAP pomapMid; INT i; *bias = 0; if (!mi->pOmapTo) { return 0; } rva = addr - mi->BaseOfDll; comap = mi->cOmapTo; pomapLow = mi->pOmapTo; pomapHigh = pomapLow + comap; while (pomapLow < pomapHigh) { comapHalf = comap / 2; pomapMid = pomapLow + ((comap & 1) ? comapHalf : (comapHalf - 1)); if (rva == pomapMid->rva) { if (pomapMid->rvaTo == 0) { // // We are probably in the middle of a routine // i = -1; while ((&pomapMid[i] != mi->pOmapTo) && pomapMid[i].rvaTo == 0) { // // Keep on looping back until the beginning // i--; } return mi->BaseOfDll + pomapMid[i].rvaTo; } else { return mi->BaseOfDll + pomapMid->rvaTo; } } if (rva < pomapMid->rva) { pomapHigh = pomapMid; comap = (comap & 1) ? comapHalf : (comapHalf - 1); } else { pomapLow = pomapMid + 1; comap = comapHalf; } } // // If no exact match, pomapLow points to the next higher address // if (pomapLow == mi->pOmapTo) { // // This address was not found // return 0; } if (pomapLow[-1].rvaTo == 0) { return 0; } // // Return the new address plus the bias // *bias = rva - pomapLow[-1].rva; return mi->BaseOfDll + pomapLow[-1].rvaTo; } POMAP GetOmapEntry( PMODULE_ENTRY mi, DWORD addr ) { DWORD rva; DWORD comap; POMAP pomapLow; POMAP pomapHigh; DWORD comapHalf; POMAP pomapMid; if (mi->pOmapFrom == NULL) { return NULL; } rva = addr - mi->BaseOfDll; comap = mi->cOmapFrom; pomapLow = mi->pOmapFrom; pomapHigh = pomapLow + comap; while (pomapLow < pomapHigh) { comapHalf = comap / 2; pomapMid = pomapLow + ((comap & 1) ? comapHalf : (comapHalf - 1)); if (rva == pomapMid->rva) { return pomapMid; } if (rva < pomapMid->rva) { pomapHigh = pomapMid; comap = (comap & 1) ? comapHalf : (comapHalf - 1); } else { pomapLow = pomapMid + 1; comap = comapHalf; } } return NULL; } LPSTR StringDup( LPSTR str ) { LPSTR ds = (LPSTR) MemAlloc( strlen(str) + 1 ); if (ds) { strcpy( ds, str ); } return ds; } VOID InternalGetModule( HANDLE hProcess, LPSTR ModuleName, DWORD ImageBase, DWORD ImageSize, PVOID Context ) { InternalLoadModule( hProcess, ModuleName, NULL, ImageBase, ImageSize, NULL ); } VOID LoadedModuleEnumerator( HANDLE hProcess, LPSTR ModuleName, DWORD ImageBase, DWORD ImageSize, PLOADED_MODULE lm ) { lm->EnumLoadedModulesCallback( ModuleName, ImageBase, ImageSize, lm->Context ); } LPSTR SymUnDNameInternal( LPSTR UnDecName, DWORD UnDecNameLength, LPSTR DecName, DWORD DecNameLength ) { LPSTR p; ULONG Suffix; ULONG i; LPSTR TmpDecName; UnDecName[0] = 0; if ((DecName[0] == '?') || (DecName[0] == '.' && DecName[1] == '.' && DecName[2] == '?')) { __try { if (DecName[0] == '.' && DecName[1] == '.') { Suffix = 2; UnDecName[0] = '.'; UnDecName[1] = '.'; } else { Suffix = 0; } TmpDecName = MemAlloc( 4096 ); if (!TmpDecName) { strncat( UnDecName, DecName, min(DecNameLength,UnDecNameLength) ); return UnDecName; } TmpDecName[0] = 0; strncat( TmpDecName, DecName+Suffix, DecNameLength ); if(UnDecorateSymbolName( TmpDecName, UnDecName+Suffix, UnDecNameLength-Suffix, UNDNAME_NAME_ONLY ) == 0 ) { strncat( UnDecName, DecName, min(DecNameLength,UnDecNameLength) ); } MemFree( TmpDecName ); } __except (EXCEPTION_EXECUTE_HANDLER) { strncat( UnDecName, DecName, min(DecNameLength,UnDecNameLength) ); } if (SymOptions & SYMOPT_NO_CPP) { p = strstr( UnDecName, "::" ); if (p) { p[0] = '_'; p[1] = '_'; } } } else { __try { if (DecName[0] == '_' || DecName[0] == '@') { DecName += 1; DecNameLength -= 1; } p = strchr( DecName, '@' ); if (p) { i = p - DecName; } else { i = min(DecNameLength,UnDecNameLength); } strncat( UnDecName, DecName, i ); } __except (EXCEPTION_EXECUTE_HANDLER) { strncat( UnDecName, DecName, min(DecNameLength,UnDecNameLength) ); } } return UnDecName; } PIMAGEHLP_SYMBOL symcpy( PIMAGEHLP_SYMBOL External, PSYMBOL_ENTRY Internal ) { External->Address = Internal->Address; External->Size = Internal->Size; External->Flags = Internal->Flags; External->Name[0] = 0; strncat( External->Name, Internal->Name, External->MaxNameLength ); return External; }