/* ntsym.c - NT debugger symbolic routines * * Copyright 1990-1993, Microsoft Corporation * * Purpose: * To load and access the program symbolic information. * * Revision History: * * [-] 19-Apr-1990 Richk Created. * *************************************************************************/ #include "master.hxx" #pragma hdrstop #include #include #include #include #include #define far #include #include #include "ntsdtok.h" extern char KernelModuleName[]; extern char *KernelImageFileName; extern char HalModuleName[]; extern char *HalImageFileName; extern char szUnknownImage[]; UCHAR chSymbolSuffix = 'n'; static PCHILD_PROCESS_INFO pProcessCurrent; #ifdef _PPC_ extern BOOLEAN ppcPrefix; #endif /********************************************************************** Symbol table organization Each symbol in the table corresponds to a SYMBOL structure. Each structure has the symbol name and offset as well as two sets of pointers. Each set of pointers, defined as a NODE, consists of parent, left child, and right child pointers to the corresponding NODEs of other symbols. The symbol name is encoded into a count of leading underscores and a pointer to the remaining part of the string. The NODEs of one set of all symbols comprise a binary tree. Each NODE set, or tree, has a SYMCONTEXT structure. This structure has a pointer to the root of the tree, the position of the NODE structure within the SYMBOL, and a pointer to a comparison routine used to determine the tree order. Two trees exist, both using multiple keys. The "offset" tree orders its nodes on: 1. increasing offsets; 2. increasing case-insensitive strings; 3. increasing number of underscores; 4. increasing case-sensitive strings. The multiple keys are needed since more than one string can be associated with an offset. The "string" tree orders its nodes on: 1. increasing case-insensitive strings; 2. increasing number of underscores; 3. increasing module address values; 4. increasing case-sensitive strings. The case-insensitive/-sensitive searches allow optimal matching for case-insensitive input. **********************************************************************/ #ifdef KERNEL #include #undef CONTAINING_RECORD #define CONTAINING_RECORD(farptr, type, field) \ ((type far *)((char far *)farptr - (long) &((type far *)0)->field)) #endif extern BOOL cdecl cmdHandler(ULONG); extern BOOL cdecl waitHandler(ULONG); int CompareSymbolOffset(PNODE, PNODE, PBOOLEAN); int CompareSymbolString(PNODE, PNODE, PBOOLEAN); int CompareSymfileOffset(PNODE, PNODE, PBOOLEAN); int CompareSymfileString(PNODE, PNODE, PBOOLEAN); static PSYMFILE pTempSymfile; SYMBOL symbolMax = { { NULL, NULL, NULL }, { NULL, NULL, NULL }, (ULONG)-1L, 0, 0, SYMBOL_TYPE_SYMBOL, NULL, 0, { '\177', '\177', '\0' } }; SYMBOL structMax = { { NULL, NULL, NULL }, { NULL, NULL, NULL }, (ULONG)-1L, 0, 0, SYMBOL_TYPE_SYMBOL, NULL, 0, { '\177', '\177', '\0' } }; CHAR stringMax[3] = { '\177', '\177', '\0' }; SYMFILE symfileMax; #define SIZE_COVERAGE_STUB 15 // 2 push + 1 call (5 bytes each) #define SIZE_INST_STUB 11 // 1 push and 1 call #define NOP_OPCODE 0x90 #define PUSH_OPCODE 0x68 #define CALL_OPCODE 0xe8 #define CALLIND_OPCODE 0xff POMAP GetOmapEntry(DWORD addr, PIMAGE_INFO pImage); void LoadCvSymbols(PIMAGE_INFO); VOID InsertOmapSymbol( PIMAGE_INFO pImage, // image pointer ULONG SymbolValueOmap, // post omap addr (- imagebase) ULONG SymbolValuePreOmap, // post omap addr (+ imagebase) ULONG NextSymbolEntryValue, // next addr - pre-omap (- imagebase) PCHAR lpSymbolName, // symbol name PULONG symbolcount // pointer to the symbol count ); typedef struct OMAPLIST OMAPLIST; typedef OMAPLIST *POMAPLIST; struct OMAPLIST { OMAP omap; DWORD cb; POMAPLIST pomaplistNext; }; BOOLEAN fSourceOnly = FALSE; BOOLEAN fSourceMixed = FALSE; PSYMFILE pSymfileLast; USHORT lineNumberLast; void parseExamine(void); void DeferSymbolLoad( PCProcess pProcess, PIMAGE_INFO ); void LoadSymbols( PCProcess pProcess, PIMAGE_INFO ); void UnloadSymbols ( PCProcess pProcess, PIMAGE_INFO ); void EnsureModuleSymbolsLoaded(CHAR); int EnsureOffsetSymbolsLoaded(ULONG); void CreateModuleNameFromPath(LPSTR lpszPath, LPSTR lpszModule); void ExtractSymbolsFromImage(PIMAGE_INFO); void ExtractDebugInfoFromImage(PIMAGE_INFO); VOID DumpSymbolTableEntry(PIMAGE_SYMBOL, PCHAR); VOID DumpAuxSymbolTableEntry(PIMAGE_SYMBOL, PIMAGE_AUX_SYMBOL, PIMAGE_SECTION_HEADER); #ifdef KERNEL extern BOOLEAN KdVerbose; #define fVerboseOutput KdVerbose #endif PIMAGE_INFO ParseModuleIndex(void); PIMAGE_INFO GetModuleIndex(PCHAR); PIMAGE_INFO GetCurrentModuleIndex(void); void DumpModuleTable(BOOLEAN); int AccessNode(PSYMCONTEXT, PNODE); BOOLEAN InsertNode(PSYMCONTEXT, PNODE); void DeleteNode(PSYMCONTEXT, PNODE); PNODE NextNode(PSYMCONTEXT, PNODE); void JoinTree(PSYMCONTEXT, PNODE); int SplitTree(PSYMCONTEXT, PNODE *, PNODE); PNODE SplayTree(PNODE); void OutputTree(PSYMCONTEXT); void OutputSymAddr(ULONG, BOOLEAN, BOOLEAN); void AddLocalToFunction(PSYMBOL, PCHAR, ULONG, USHORT, ULONG); void AddFieldToStructure(PSTRUCT, PCHAR, ULONG ,USHORT, ULONG); PSTRUCT InsertStructure(ULONG, PCHAR, CHAR); PSYMBOL InsertFunction(PCHAR, ULONG); //, PSYMBOL); PSYMBOL InsertSymbol(ULONG, PCHAR, CHAR, PCHAR); PSYMBOL AllocSymbol(ULONG, PCHAR, CHAR, PCHAR); PSTRUCT GetStructFromValue(ULONG, LONG); void GetBytesFromFrame(PCHAR, LONG, USHORT); ULONG GetLocalValue(LONG, USHORT, BOOLEAN); BOOLEAN GetLocalFromString(PCHAR, PULONG); BOOLEAN GetOffsetFromSym(PCHAR, PULONG, CHAR); BOOLEAN GetOffsetFromString(PCHAR, PULONG, CHAR); PLINENO GetLinenoFromFilename(PCHAR, PPSYMFILE, USHORT, CHAR); PLINENO GetCurrentLineno(PPSYMFILE); PLINENO GetLastLineno(PPSYMFILE, PUSHORT); PLINENO GetLinenoFromOffset(PPSYMFILE, ULONG); void GetLinenoString(PCHAR, ULONG); void GetCurrentMemoryOffsets(PULONG, PULONG); void DeleteSymbol(PSYMBOL); void DeallocSymbol(PSYMBOL); PSYMFILE InsertSymfile(PCHAR, PCHAR, PCHAR, PIMAGE_LINENUMBER, USHORT, ULONG, ULONG, CHAR); PSYMFILE AllocSymfile(PCHAR, PCHAR, PCHAR, PIMAGE_LINENUMBER, USHORT, ULONG, ULONG, CHAR); void DeleteSymfile(PSYMFILE); void DeallocSymfile(PSYMFILE); void fnListNear(ULONG); void SortSrcLinePointers(PSYMFILE); //void OutputAtLineno (PSYMFILE, PLINENO); void UpdateLineno(PSYMFILE, PLINENO); FILE * LocateTextInSource(PSYMFILE, PLINENO); void OutputSourceLines(PSYMFILE, USHORT, USHORT); BOOLEAN OutputSourceFromOffset(ULONG, BOOLEAN); BOOLEAN OutputLines(PSYMFILE, PLINENO, USHORT, USHORT); PVOID FetchImageDirectoryEntry(int, USHORT, PULONG, PULONG); extern int fControlC; #ifdef KERNEL extern BOOLEAN cdecl _loadds ControlCHandler(void); #endif extern void RemoveDelChar(PCHAR); extern BOOLEAN fPointerExpression; // State transition arrays for comment processing CHAR WhiteSpace[] = { stStart, stLine, stSlStar, stSlStStar, stSlSlash, stLine, stLine, stLSlStar, stLSlStar, stLSlSlash }; CHAR Slash[] = { stSlash, stSlSlash, stSlStar, stStart, stSlSlash, stLSlash, stLSlSlash, stLSlStar, stLine, stLSlSlash }; CHAR Star[] = { stLine, stSlStar, stSlStStar, stSlStStar, stSlSlash, stLine, stLSlStar, stLSlStStar, stSlStStar, stLSlSlash }; CHAR Pound[] = { stSlSlash, stLine, stSlStar, stSlStar, stSlSlash, stLine, stLine, stLSlStar, stLSlStar, stLSlSlash }; CHAR OtherChar[] = { stLine, stLine, stSlStar, stSlStar, stSlSlash, stLine, stLine, stLSlStar, stLSlStar, stLSlSlash }; CHAR Return[] = { stStart, stStart, stSlStar, stSlStar, stStart, stStart, stStart, stSlStar, stSlStar, stStart }; CHAR fCommentType[] = { TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE }; //////////////////////////////////////////////////////////////// BOOLEAN SymFileMaxInited = FALSE; PIMAGE_INFO pImageFromIndex (CHAR index) { if ((UCHAR)index < pProcessCurrent->MaxIndex) { return pProcessCurrent->pImageByIndex[ (UCHAR)index ]; } else { return NULL; } } BOOLEAN ReadVirtualMemory(PUCHAR pBufSrc, PUCHAR pBufDest, ULONG count, PULONG pcTotalBytesRead) { *pcTotalBytesRead = 0; return (BOOLEAN)ReadProcessMemory(pProcessCurrent->hProcess, (PULONG)pBufSrc, (PVOID)pBufDest, count, pcTotalBytesRead); } VOID InitSymFileMax() { if ( SymFileMaxInited ) { return; } RtlZeroMemory(&symfileMax,sizeof(symfileMax)); symfileMax.pchPath = (PUCHAR)""; symfileMax.pchName = (PUCHAR)stringMax; symfileMax.pchExtension = (PUCHAR)""; SymFileMaxInited = TRUE; } void InitSymContext (PCProcess pProcess) { pProcessCurrent = pProcess; pProcess->symcontextStructOffset.pNodeRoot = NULL; pProcess->symcontextStructOffset.pNodeMax = (PNODE)((LONG)&structMax + NODE_SYMBOL_DISPLACEMENT(nodeOffset)); pProcess->symcontextStructOffset.pfnCompare = &CompareSymbolOffset; pProcess->symcontextStructOffset.nodeDisplacement = NODE_SYMBOL_DISPLACEMENT(nodeOffset); pProcess->symcontextStructString.pNodeRoot = NULL; pProcess->symcontextStructString.pNodeMax = (PNODE)((LONG)&structMax + NODE_SYMBOL_DISPLACEMENT(nodeString)); pProcess->symcontextStructString.pfnCompare = &CompareSymbolString; pProcess->symcontextStructString.nodeDisplacement = NODE_SYMBOL_DISPLACEMENT(nodeString); pProcess->symcontextSymbolOffset.pNodeRoot = NULL; pProcess->symcontextSymbolOffset.pNodeMax = (PNODE)((LONG)&symbolMax + NODE_SYMBOL_DISPLACEMENT(nodeOffset)); pProcess->symcontextSymbolOffset.pfnCompare = &CompareSymbolOffset; pProcess->symcontextSymbolOffset.nodeDisplacement = NODE_SYMBOL_DISPLACEMENT(nodeOffset); pProcess->symcontextSymbolString.pNodeRoot = NULL; pProcess->symcontextSymbolString.pNodeMax = (PNODE)((LONG)&symbolMax + NODE_SYMBOL_DISPLACEMENT(nodeString)); pProcess->symcontextSymbolString.pfnCompare = &CompareSymbolString; pProcess->symcontextSymbolString.nodeDisplacement = NODE_SYMBOL_DISPLACEMENT(nodeString); pProcess->symcontextSymfileOffset.pNodeRoot = NULL; pProcess->symcontextSymfileOffset.pNodeMax = (PNODE)((LONG)&symfileMax + NODE_SYMFILE_DISPLACEMENT(nodeOffset)); pProcess->symcontextSymfileOffset.pfnCompare = &CompareSymfileOffset; pProcess->symcontextSymfileOffset.nodeDisplacement = NODE_SYMFILE_DISPLACEMENT(nodeOffset); pProcess->symcontextSymfileString.pNodeRoot = NULL; pProcess->symcontextSymfileString.pNodeMax = (PNODE)((LONG)&symfileMax + NODE_SYMFILE_DISPLACEMENT(nodeString)); pProcess->symcontextSymfileString.pfnCompare = &CompareSymfileString; pProcess->symcontextSymfileString.nodeDisplacement = NODE_SYMFILE_DISPLACEMENT(nodeString); pTempSymfile = AllocSymfile("", "", "", NULL, 0, 0, 0, 0); } void SetSymbolSearchPath( BOOL IsKd ) { LPSTR lpSymPathEnv, lpAltSymPathEnv, lpSystemRootEnv, lpSymPath, lpSrcDriveEnv; ULONG cbSymPath, cbSrcDrive; DWORD dw; cbSymPath = 18; cbSrcDrive = 0; if (lpSymPathEnv = getenv(SYMBOL_PATH)) { cbSymPath += strlen(lpSymPathEnv) + 1; } if (lpAltSymPathEnv = getenv(ALTERNATE_SYMBOL_PATH)) { cbSymPath += strlen(lpAltSymPathEnv) + 1; } if (!IsKd) { if (lpSystemRootEnv = getenv("SystemRoot")) { cbSymPath += strlen(lpSystemRootEnv) + 1; } } if ( lpSrcDriveEnv = getenv(SRC_DRIVE)) { cbSrcDrive += strlen(lpSrcDriveEnv) + 1; } SymbolSearchPath = (PCHAR)calloc(cbSymPath, 1); if ( cbSrcDrive ) { SrcDrive = (PCHAR)calloc(cbSrcDrive,1); } else { SrcDrive = NULL; } if (lpAltSymPathEnv) { lpAltSymPathEnv = _strdup(lpAltSymPathEnv); lpSymPath = strtok(lpAltSymPathEnv, ";"); while (lpSymPath) { dw = GetFileAttributes(lpSymPath); if ( (dw != 0xffffffff) && (dw & FILE_ATTRIBUTE_DIRECTORY) ) { if (*SymbolSearchPath) { strcat(SymbolSearchPath, ";"); } strcat(SymbolSearchPath, lpSymPath); } lpSymPath = strtok(NULL, ";"); } free(lpAltSymPathEnv); } if (lpSymPathEnv) { lpSymPathEnv = _strdup(lpSymPathEnv); lpSymPath = strtok(lpSymPathEnv, ";"); while (lpSymPath) { dw = GetFileAttributes(lpSymPath); if ( (dw != 0xffffffff) && (dw & FILE_ATTRIBUTE_DIRECTORY) ) { if (*SymbolSearchPath) { strcat(SymbolSearchPath, ";"); } strcat(SymbolSearchPath, lpSymPath); } lpSymPath = strtok(NULL, ";"); } free(lpSymPathEnv); } if (!IsKd) { if (lpSystemRootEnv) { dw = GetFileAttributes(lpSystemRootEnv); if ( (dw != 0xffffffff) && (dw & FILE_ATTRIBUTE_DIRECTORY) ) { if (*SymbolSearchPath) { strcat(SymbolSearchPath, ";"); } strcat(SymbolSearchPath,lpSystemRootEnv); } } } if ( SrcDrive ) { strcat(SrcDrive,lpSrcDriveEnv ); } DebugPrintf("Symbol search path is: %s\n", *SymbolSearchPath ? SymbolSearchPath : "*** Invalid *** : Verify _NT_SYMBOL_PATH setting" ); if ( SrcDrive ) { DebugPrintf("Source search drive is: %s\n", SrcDrive); } InitSymFileMax(); } void DeferSymbolLoad ( PCProcess pProcess, PIMAGE_INFO pImage ) { CHKPT(); pProcessCurrent = pProcess; ExtractDebugInfoFromImage( pImage ); if (fVerboseOutput) { DebugPrintf("%s: deferring symbol load for \"%s\"\n", DebuggerName, pImage->szImagePath ); } } void LoadSymbols ( PCProcess pProcess, PIMAGE_INFO pImage ) { CHKPT(); pProcessCurrent = pProcess; ExtractDebugInfoFromImage( pImage ); ExtractOmapData(pImage); ExtractSymbolsFromImage( pImage ); } void UnloadSymbols ( PCProcess pProcess, PIMAGE_INFO pImage ) { PSYMBOL pSymbol; PSYMFILE pSymfile; PNODE pNode; PNODE pNodeNext; pProcessCurrent = pProcess; pImage->ImageBase = 0; if (pImage->hFile) { CloseHandle( pImage->hFile ); pImage->hFile = NULL; } if (pImage->lpDebugInfo) { if (pImage->fHasOmap) { free(pImage->rgomapToSource); free(pImage->rgomapFromSource); pImage->fHasOmap = FALSE; pImage->rgomapToSource = NULL; pImage->rgomapFromSource = NULL; pImage->comapToSrc = 0; pImage->comapFromSrc = 0; } UnmapDebugInformation(pImage->lpDebugInfo); pImage->lpDebugInfo = NULL; } pImage->fDebugInfoLoaded = FALSE; // if module was never loaded, nothing to unload, // just close open file handle and return if (!pImage->fSymbolsLoaded) { return; } pImage->fSymbolsLoaded = FALSE; if (fVerboseOutput) DebugPrintf("%s: unloading symbols for \"%s\"\n", DebuggerName, pImage->szImagePath); if (pImage->pFpoData) { free( pImage->pFpoData ); pImage->pFpoData = NULL; pImage->dwFpoEntries = 0; } //////////////////////////////////////////////////////////////// // delete all symbol structures with the specified module index //////////////////////////////////////////////////////////////// // make a symbol structure with the low offset in the image pSymbol = AllocSymbol(pImage->offsetLow, "", -1, NULL); // try to access the node with the offset given. // the node pointer returned will be the nearest offset less // than the argument (unless it is less than the tree minimum) AccessNode(&(pProcessCurrent->symcontextSymbolOffset), &(pSymbol->nodeOffset)); pNode = pProcessCurrent->symcontextSymbolOffset.pNodeRoot; // deallocate the temporary symbol structure DeallocSymbol(pSymbol); // traverse the tree and delete symbols with the specified index // until the offset is higher than the maximum while (pNode) { pSymbol = PNODE_TO_PSYMBOL(pNode, &(pProcessCurrent->symcontextSymbolOffset)); if (pSymbol->offset > pImage->offsetHigh) break; pNodeNext = NextNode(&(pProcessCurrent->symcontextSymbolOffset), pNode); if (pSymbol->modIndex == (CHAR)pImage->index) { // DebugPrintf("** offset: %08lx string: %s deleted\n", // pSymbol->offset, pSymbol->string); DeleteSymbol(pSymbol); } pNode = pNodeNext; } ///////////////////////////////////////////////////////////////////// // delete all file symbol structures with the specified module index ///////////////////////////////////////////////////////////////////// // search all entries in the current image - get the first pNode = NextNode(&(pProcessCurrent->symcontextSymfileOffset), NULL); // traverse the tree and delete symbols with the specified index // until the end of the tree. while (pNode) { pSymfile = PNODE_TO_PSYMFILE(pNode, &(pProcessCurrent->symcontextSymfileOffset)); pNodeNext = NextNode(&(pProcessCurrent->symcontextSymfileOffset), pNode); if (pSymfile->modIndex == (CHAR)pImage->index) { #if 0 if (fVerboseOutput) DebugPrintf("%s: symfile: \"%s\" deleted\n", DebuggerName, pSymfile->pchName); #endif DeleteSymfile(pSymfile); } pNode = pNodeNext; } pImage->offsetLow = 0; pImage->offsetHigh = 0; } void EnsureModuleSymbolsLoaded (CHAR iModule) { PIMAGE_INFO pImage; if (fLazyLoad) { pImage = pProcessCurrent->pImageHead; while (pImage && pImage->index != (UCHAR)iModule) pImage = pImage->pImageNext; if (pImage && !pImage->fSymbolsLoaded) { // NOTE! The order of the next two statements // are critical. Reversing them will cause // infinite recursion to occur. LoadSymbols(pProcessCurrent, pImage); } } } int EnsureOffsetSymbolsLoaded (ULONG offset) { PIMAGE_INFO pImage = pProcessCurrent->pImageHead; PIMAGE_INFO pImageFound = NULL; // first, scan all modules for the one which has the highest // starting offset less than the input offset. while (pImage) { if (offset >= (ULONG)pImage->lpBaseOfImage && (!pImageFound || ((ULONG)pImage->lpBaseOfImage > (ULONG)pImageFound->lpBaseOfImage))) pImageFound = pImage; pImage = pImage->pImageNext; } // continue only if a candidate was found if (pImageFound) { // load the candidate image if deferred if (fLazyLoad && !pImageFound->fSymbolsLoaded) { // NOTE! The order of the next two statements // are critical. Reversing them will cause // infinite recursion to occur. LoadSymbols(pProcessCurrent, pImageFound); } // with the candidate loaded, test if offset is more // than the highest symbol. If so, clear pImageFound if (offset > pImageFound->offsetHigh) pImageFound = FALSE; } // return flag TRUE if offset was NOT in image return (pImageFound == NULL); } #if 0 PIMAGE_INFO GetCurrentModuleIndex (void) { ADDR pcvalue; PIMAGE_INFO pImage; GetRegPCValue(&pcvalue); pImage = pProcessCurrent->pImageHead; while (pImage && (Flat(pcvalue) < pImage->offsetLow || Flat(pcvalue) > pImage->offsetHigh)) pImage = pImage->pImageNext; return pImage; } static UCHAR strBlank[] = " "; #endif //0 /*** AccessNode - access and splay node * * Purpose: * Search a tree for a node and splay it. * * Input: * pSymContext - pointer to context of tree * pNodeAccess - pointer to node with access value set * * Output: * tree splayed with new node at its root * Returns: * value of success: * 1 = root is smallest value larger than input value * (not found, no lesser value) * 0 = root is input value (value found in tree) * -1 = root is largest value less than input value * (not found in tree) * * Notes: * splay is done with resulting root * if root is less than input value, a secondary splay is done * to make the next node the right child of the root * *************************************************************************/ int AccessNode (PSYMCONTEXT pSymContext, PNODE pNodeAccess) { PNODE *ppNodeRoot = &(pSymContext->pNodeRoot); PNODE pNentry = *ppNodeRoot; PNODE pNminimum = NULL; PNODE pNmaximum = NULL; PNODE pNweakcmp = NULL; PNODE pRootTemp; BOOLEAN fWeakCmp; int cmp; // return 1 if empty tree if (!pNentry) return 1; // search until value is found or terminating node do { // context-specific comparison routine compares values // pointed by pNodeAccess and pNentry cmp = (*(pSymContext->pfnCompare))(pNodeAccess, pNentry, &fWeakCmp); // fWeakcmp is set if weak comparison, used if no // true comparison is found if (fWeakCmp) pNweakcmp = pNentry; // for unequal results, set minimum and maximum entry // searched as tree is search for node if (cmp == -1) { pNmaximum = pNentry; pNentry = pNentry->pLchild; } else { pNminimum = pNentry; pNentry = pNentry->pRchild; } } while (pNentry && cmp); // if no stong match found, but weak one was, use it if (cmp && pNweakcmp) { cmp = 0; pNminimum = pNweakcmp; } // splay tree so minimum node is at root, but use maximum // if no minimum node *ppNodeRoot = SplayTree(pNminimum ? pNminimum : pNmaximum); // if node not found, set result for value used in splay if (cmp != 0) cmp = pNminimum ? -1 : 1; // if node not found and both minimum and maximum nodes // were found, splay the next node as the right child of // the root. this new node will not have a left child, // and assists future accesses in some cases if (cmp == -1 && pNminimum && pNmaximum) { pRootTemp = pNminimum->pRchild; pRootTemp->pParent = NULL; pNmaximum = SplayTree(pNmaximum); pNminimum->pRchild = pNmaximum; pNmaximum->pParent = pNminimum; } return cmp; } /*** CompareSymbolOffset - comparison routine for symbol offsets * * Purpose: * Compare two nodes in the offset tree. The ordering * comparisons used are offset and string. The string * comparison is done since and offset can have more than * one string associated with it. * * Input: * pNode1 - pointer to first node - usually the new one * pNode2 - pointer to second node - usually in the tree searched * * Output: * pfWeakCmp - always FALSE - comparisons are exact or they fail * * Returns: * value of comparison result: * -1 = value(pNode1) < value(pNode2) * 0 = value(pNode1) == value(pNode2) * 1 = value(pNode1) > value(pNode2) * *************************************************************************/ int CompareSymbolOffset (PNODE pNode1, PNODE pNode2, PBOOLEAN pfWeakCmp) { int cmp; PSYMBOL pSymbol1 = CONTAINING_RECORD(pNode1, SYMBOL, nodeOffset); PSYMBOL pSymbol2 = CONTAINING_RECORD(pNode2, SYMBOL, nodeOffset); *pfWeakCmp = FALSE; // compare offsets of the nodes if (pSymbol1->offset < pSymbol2->offset) cmp = -1; else if (pSymbol1->offset > pSymbol2->offset) cmp = 1; // if the first node string is null, assume node is being // searched for in tree, so report equality else if (pSymbol1->string[0] == '\0') cmp = 0; // else the first node string is nonnull, and node is being // inserted, so further test the string equality: case- // insensitive search, underscore count, case-sensitive search else { cmp = _stricmp((PCHAR)pSymbol1->string, (PCHAR)pSymbol2->string); if (!cmp) { if (pSymbol1->underscores < pSymbol2->underscores) cmp = -1; else if (pSymbol1->underscores > pSymbol2->underscores) cmp = 1; else { cmp = strcmp((PCHAR)pSymbol1->string, (PCHAR)pSymbol2->string); if (!cmp) { if (pSymbol1->modIndex < pSymbol2->modIndex) cmp = -1; else if (pSymbol1->modIndex > pSymbol2->modIndex) cmp = 1; } } } } if (cmp < 0) { return - 1; } else if (cmp > 0) { return 1; } else { return 0; } } /*** CompareSymfileOffset - comparison routine for symbol file offsets * * Purpose: * Compare two nodes in the symbol file offset tree. The ordering * comparisons used are offset and string. The string * comparison is done since and offset can have more than * one string associated with it. * * Input: * pNode1 - pointer to first node - usually the new one * pNode2 - pointer to second node - usually in the tree searched * * Output: * pfWeakCmp - always FALSE - comparisons are exact or they fail * * Returns: * value of comparison result: * -1 = value(pNode1) < value(pNode2) * 0 = value(pNode1) == value(pNode2) * 1 = value(pNode1) > value(pNode2) * *************************************************************************/ int CompareSymfileOffset (PNODE pNode1, PNODE pNode2, PBOOLEAN pfWeakCmp) { int cmp = 0; PSYMFILE pSymfile1 = CONTAINING_RECORD(pNode1, SYMFILE, nodeOffset); PSYMFILE pSymfile2 = CONTAINING_RECORD(pNode2, SYMFILE, nodeOffset); *pfWeakCmp = FALSE; #ifdef OMAP_DETAILS DebugPrintf("NTSD: OMAP CompareSymOffset [%8lx-%8lx] - [%8lx-%8lx]\n", pSymfile1->startOffset, pSymfile1->endOffset, pSymfile2->startOffset, pSymfile2->endOffset); #endif // test if performing an insertion (pSymfile1->pLineno == NULL) // a search (search only has offset defined in cLineno) if (pSymfile1->pLineno) { // compare starting offsets of the nodes if (pSymfile1->startOffset < pSymfile2->startOffset) cmp = -1; else if (pSymfile1->startOffset > pSymfile2->startOffset) cmp = 1; // if same offset, further test the file and module equality else { cmp = strcmp((PCHAR)pSymfile1->pchName, (PCHAR)pSymfile2->pchName); if (!cmp) { if (pSymfile1->modIndex < pSymfile2->modIndex) cmp = -1; else if (pSymfile1->modIndex > pSymfile2->modIndex) cmp = 1; } } } else { // search - test search offset in node against range if (pSymfile1->startOffset < pSymfile2->startOffset) cmp = -1; else if (pSymfile1->startOffset > pSymfile2->endOffset) cmp = 1; } if (cmp < 0) { return - 1; } else if (cmp > 0) { return 1; } else { return 0; } } /*** CompareSymbolString - comparison routine for symbol strings * * Purpose: * Compare two nodes in the string tree. The ordering * comparisons used are case-insensitivity, underscore * count, module ordering, and case-sensitivity. * * Input: * pNode1 - pointer to first node - usually the new one * pNode2 - pointer to second node - usually in the tree searched * * Output: * pfWeakCmp - TRUE if case-insensitive and underscores match * FALSE otherwise (defined only if cmp nonzero) * * Returns: * value of comparison result: * -1 = value(pNode1) < value(pNode2) * 0 = value(pNode1) == value(pNode2) * 1 = value(pNode1) > value(pNode2) * *************************************************************************/ int CompareSymbolString (PNODE pNode1, PNODE pNode2, PBOOLEAN pfWeakCmp) { int cmp; PSYMBOL pSymbol1 = CONTAINING_RECORD(pNode1, SYMBOL, nodeString); PSYMBOL pSymbol2 = CONTAINING_RECORD(pNode2, SYMBOL, nodeString); *pfWeakCmp = FALSE; // compare case-insensitive value of the nodes cmp = _stricmp((PCHAR)pSymbol1->string, (PCHAR)pSymbol2->string); if (!cmp) { // compare underscore counts of the nodes if (pSymbol1->underscores < pSymbol2->underscores) cmp = -1; else if (pSymbol1->underscores > pSymbol2->underscores) cmp = 1; else { // if null string in first node, then searching, not inserting if (pSymbol1->offset == 0) // test module index for weak comparison indication // index of -1 is for no module, weakly match any if (pSymbol1->modIndex == (CHAR)-1 || pSymbol1->modIndex == pSymbol2->modIndex) *pfWeakCmp = TRUE; // test for ordering due to module index if (pSymbol1->modIndex == (CHAR)-1 || pSymbol1->modIndex < pSymbol2->modIndex) cmp = -1; else if (pSymbol1->modIndex > pSymbol2->modIndex) cmp = 1; else // final test for strong match is case-sensitive comparison cmp = strcmp((PCHAR)pSymbol1->string, (PCHAR)pSymbol2->string); } } if (cmp < 0) { return - 1; } else if (cmp > 0) { return 1; } else { return 0; } } /*** CompareSymfileString - comparison routine for symbol file strings * * Purpose: * Compare two nodes in the string tree. The ordering * comparisons used are case-insensitivity, underscore * count, module ordering, and case-sensitivity. * * Input: * pNode1 - pointer to first node - usually the new one * pNode2 - pointer to second node - usually in the tree searched * * Output: * pfWeakCmp - TRUE if case-insensitive and underscores match * FALSE otherwise (defined only if cmp nonzero) * * Returns: * value of comparison result: * -1 = value(pNode1) < value(pNode2) * 0 = value(pNode1) == value(pNode2) * 1 = value(pNode1) > value(pNode2) * *************************************************************************/ int CompareSymfileString (PNODE pNode1, PNODE pNode2, PBOOLEAN pfWeakCmp) { int cmp; PSYMFILE pSymfile1 = CONTAINING_RECORD(pNode1, SYMFILE, nodeString); PSYMFILE pSymfile2 = CONTAINING_RECORD(pNode2, SYMFILE, nodeString); *pfWeakCmp = FALSE; // compare case-sensitive value of the filenames cmp = strcmp((PCHAR)pSymfile1->pchName, (PCHAR)pSymfile2->pchName); if (!cmp) { // if filenames match, test for module index if (pSymfile1->modIndex < pSymfile2->modIndex) cmp = -1; else if (pSymfile1->modIndex > pSymfile2->modIndex) cmp = 1; // test if searching rather than inserting, a // search structure has pLineno NULL and // cLineno has the line number to search else if (pSymfile1->pLineno != NULL) { // inserting, so order on starting line number // (this is the second item of the list) if ((pSymfile1->pLineno + 1)->breakLineNumber < (pSymfile2->pLineno + 1)->breakLineNumber) cmp = -1; else if ((pSymfile1->pLineno + 1)->breakLineNumber > (pSymfile2->pLineno + 1)->breakLineNumber) cmp = 1; } else { // for viewing lines, set a weak match to TRUE *pfWeakCmp = TRUE; // searching, test for line number within the range // defined in the structure if (pSymfile1->cLineno < (pSymfile2->pLineno + 1)->breakLineNumber) cmp = -1; else if (pSymfile1->cLineno > (pSymfile2->pLineno + pSymfile2->cLineno)->breakLineNumber) cmp = 1; } } if (cmp < 0) { return - 1; } else if (cmp > 0) { return 1; } else { return 0; } } /*** InsertSymbol - insert offset and string into new symbol * * Purpose: * external routine. * Allocate and insert a new symbol into the offset and * string trees. * * Input: * insertvalue - offset value of new symbol * pinsertstring - string value if new symbol * * Output: * None. * * Notes: * Uses the routine InsertNode for both offset and string * through different contexts. * *************************************************************************/ PSYMBOL InsertSymbol (ULONG insertvalue, PCHAR pinsertstring, CHAR insertmod, PCHAR stringOffset) { PSYMBOL pSymbol; /* DebugPrintf( "insertvalue = %ul, insertstring='%s', insertmod=%d, stringOffset = '%s'\n", insertvalue, pinsertstring, insertmod, stringOffset ); */ pSymbol = AllocSymbol(insertvalue, pinsertstring, insertmod, stringOffset); if (!InsertNode(&(pProcessCurrent->symcontextSymbolOffset), &(pSymbol->nodeOffset))) { DeallocSymbol(pSymbol); return NULL; } if (!InsertNode(&(pProcessCurrent->symcontextSymbolString), &(pSymbol->nodeString))) { DeleteNode(&(pProcessCurrent->symcontextSymbolOffset), &(pSymbol->nodeOffset)); DeallocSymbol(pSymbol); return NULL; } return pSymbol; } #if 0 PSTRUCT InsertStructure (ULONG insertvalue, PCHAR pinsertstring, CHAR insertmod) { PSTRUCT pStruct; pStruct = (PSTRUCT) AllocSymbol(insertvalue, pinsertstring, insertmod, NULL); if (!InsertNode(&(pProcessCurrent->symcontextStructOffset), &(pStruct->nodeOffset))) { DeallocSymbol((PSYMBOL)pStruct); //DebugPrintf("insert - value %d already in tree\n", insertvalue); return NULL; } if (!InsertNode(&(pProcessCurrent->symcontextStructString), &(pStruct->nodeString))) { DeleteNode(&(pProcessCurrent->symcontextStructOffset), &(pStruct->nodeOffset)); DeallocSymbol((PSYMBOL)pStruct); //DebugPrintf("insert - string %s already in tree\n", pinsertstring); return NULL; } pStruct->pField = NULL; return pStruct; } #endif //0 /*** InsertSymfile - insert new file line numbers into search tree * * Purpose: * Allocate and insert a new files and its line numbers into the * offset and filename string trees. * * Input: * pPathname - pointer to pathname string * pFilename - pointer to filename string * pExtension - pointer to extension string * pLineno - pointer to COFF line number entries * cLineno - count of entries pointed by pLineno * endingOffset - ending offset of file section * index - module index for file section * * Output: * None. * * Notes: * Uses the routine InsertNode for both offset and filename * string through different contexts. * *************************************************************************/ PSYMFILE InsertSymfile (PCHAR pPathname, PCHAR pFilename, PCHAR pExtension, PIMAGE_LINENUMBER pLineno, USHORT cLineno, ULONG startingOffset, ULONG endingOffset, CHAR index) { PSYMFILE pSymfile; pSymfile = AllocSymfile(pPathname, pFilename, pExtension, pLineno, cLineno, startingOffset, endingOffset, index); if (!InsertNode(&(pProcessCurrent->symcontextSymfileOffset), &(pSymfile->nodeOffset))) { DeallocSymfile(pSymfile); // DebugPrintf("insert - value %d already in tree\n", insertvalue); return NULL; } if (!InsertNode(&(pProcessCurrent->symcontextSymfileString), &(pSymfile->nodeString))) { DeleteNode(&(pProcessCurrent->symcontextSymfileOffset), &(pSymfile->nodeOffset)); DeallocSymfile(pSymfile); // DebugPrintf("insert - string %s already in tree\n", pinsertstring); return NULL; } return pSymfile; } /*** InsertNode - insert new node into tree * * Purpose: * Insert node into the tree of the specified context. * * Input: * pSymContext - pointer to context to insert node * pNodeNew - pointer to node to insert * * Returns: * TRUE - node was inserted successfully * FALSE - node already exists * * Notes: * Both offset and string values of the node may be used * in the ordering or duplication criteria. * *************************************************************************/ BOOLEAN InsertNode (PSYMCONTEXT pSymContext, PNODE pNodeNew) { PNODE *ppNodeRoot = &(pSymContext->pNodeRoot); PNODE pNodeRootTemp; int splitstatus; // split tree into two subtrees: // *ppNodeRoot - root of all nodes < value(pNodeNew) // pNodeRootTemp - root of all nodes >= value(pNodeNew) splitstatus = SplitTree(pSymContext, &pNodeRootTemp, pNodeNew); if (splitstatus != 0) { // value(pNodeNew) was not in tree // make pNodeNew the root having the two subtrees as children pNodeNew->pLchild = *ppNodeRoot; if (*ppNodeRoot) (*ppNodeRoot)->pParent = pNodeNew; pNodeNew->pRchild = pNodeRootTemp; if (pNodeRootTemp) pNodeRootTemp->pParent = pNodeNew; pNodeNew->pParent = NULL; *ppNodeRoot = pNodeNew; return TRUE; } else { // value(pNodeNew) was in tree // just rejoin the two subtrees back and report error JoinTree(pSymContext, pNodeRootTemp); return FALSE; } } /*** DeleteSymbol - delete specified symbol from splay tree * * Purpose: * external routine. * Delete the specified symbol object in both the * offset and string trees and deallocate its space. * * Input: * pSymbol - pointer to symbol object to delete * * Output: * None. * *************************************************************************/ void DeleteSymbol (PSYMBOL pSymbol) { DeleteNode(&(pProcessCurrent->symcontextSymbolOffset), &(pSymbol->nodeOffset)); DeleteNode(&(pProcessCurrent->symcontextSymbolString), &(pSymbol->nodeString)); DeallocSymbol(pSymbol); } /*** DeleteNode - delete specified node from tree * * Purpose: * Delete node from tree of the context specified. * * Input: * pSymContext - pointer to context of deletion * pNodeDelete - pointer to node to actually delete * * Output: * None. * *************************************************************************/ void DeleteNode (PSYMCONTEXT pSymContext, PNODE pNodeDelete) { PNODE pNodeRootTemp; // splay the node to be deleted to move it to the root SplayTree(pNodeDelete); // // BryanT 11/9/92 We don't call JoinTree because it's possible // we may be called on program load and C++ may assign multiple // line numbers to the same body of code (from inline functions // for instance). Since pNodeMax may not even be in the tree // yet, this was causing the code to throw out anything already // in the tree... Mighty annoying. Instead, we just do it here. // I couldn't find any place in the code where this was a problem // since calling SplayTree (which everyone does) will resort the // tree anyway. // if (pNodeDelete->pLchild != NULL) { pNodeRootTemp = pNodeDelete->pLchild; if (pNodeDelete->pRchild != NULL) { while (pNodeRootTemp->pRchild != NULL) pNodeRootTemp = pNodeRootTemp->pRchild; pNodeRootTemp->pRchild = pNodeDelete->pRchild; if (pNodeDelete->pRchild != NULL) pNodeRootTemp->pRchild->pParent = pNodeRootTemp; } pNodeDelete->pLchild->pParent = NULL; pNodeRootTemp = pNodeDelete->pLchild; } else { if (pNodeDelete->pRchild != NULL) pNodeDelete->pRchild->pParent = NULL; pNodeRootTemp = pNodeDelete->pRchild; } if (pSymContext->pNodeRoot == pNodeDelete) pSymContext->pNodeRoot = pNodeRootTemp; } /*** JoinTree - join two trees into one * * Purpose: * Join two trees into one where all nodes of the first * tree have a lesser value than any of the second. * * Input: * pSymContext - pointer to context containing the first tree * pNodeRoot2 - pointer to root of second tree * * Output: * pSymContext - pointer to context containing the joined tree * *************************************************************************/ void JoinTree (PSYMCONTEXT pSymContext, PNODE pNodeRoot2) { PNODE *ppNodeRoot1 = &(pSymContext->pNodeRoot); // access and splay the first tree to have its maximum value // as its root (no right child) // AccessNode(pSymContext, PSYMBOL_TO_PNODE(&symbolMax, pSymContext)); AccessNode(pSymContext, pSymContext->pNodeMax); if (*ppNodeRoot1) { // nonnull first tree, connect second tree as // right child of the first (*ppNodeRoot1)->pRchild = pNodeRoot2; if (pNodeRoot2) pNodeRoot2->pParent = *ppNodeRoot1; } else { // null first tree, make the second tree the result *ppNodeRoot1 = pNodeRoot2; if (pNodeRoot2) pNodeRoot2->pParent = NULL; } } /*** SplitTree - split one tree into two * * Purpose: * Split the given tree into two subtrees, the first * having nodes less than specific value, and the * second having nodes greater than or equal to that * value. * * Input: * pSymContext - pointer to context containing tree to split * pNodeNew - node with value used to specify split * * Output: * pSymContext - pointer to context containing first tree * *ppNodeRoot2 - pointer to pointer to root of second tree * * Returns: * result of access: * 1 = root is smallest value larger than input value * (not found, no lesser value) * 0 = root is input value (value found in tree) * -1 = root is largest value less than input value * (not found in tree) * *************************************************************************/ int SplitTree (PSYMCONTEXT pSymContext, PNODE *ppNodeRoot2, PNODE pNodeNew) { PNODE *ppNodeRoot1 = &(pSymContext->pNodeRoot); int access; if (*ppNodeRoot1) { // nonnull tree, access and splay to make node // with input value root. access = AccessNode(pSymContext, pNodeNew); if (access != 1) { // break left child link of root to form two subtrees *ppNodeRoot2 = (*ppNodeRoot1)->pRchild; if (*ppNodeRoot2) (*ppNodeRoot2)->pParent = NULL; (*ppNodeRoot1)->pRchild = NULL; } else { // break right child link of root to form two subtrees *ppNodeRoot2 = *ppNodeRoot1; *ppNodeRoot1 = (*ppNodeRoot1)->pLchild; if (*ppNodeRoot1) (*ppNodeRoot1)->pParent = NULL; (*ppNodeRoot2)->pLchild = NULL; } } else { // null tree access = 1; *ppNodeRoot2 = NULL; } return access; } /*** SplayTree - splay tree with node specified * * Purpose: * Perform rotations (splayings) on the specified tree * until the node given is at the root. * * Input: * pointer to node to splay to root * * Returns: * pointer to node splayed * * Notes: * *************************************************************************/ PNODE SplayTree (PNODE pNentry) { PNODE pNparent; PNODE pNgrand; PNODE pNgreat; PNODE pNchild; if (pNentry) { // repeat single or double rotations until node is root while (pNentry->pParent) { pNparent = pNentry->pParent; if (!pNparent->pParent) { if (pNentry == pNparent->pLchild) { /* case 1: PARENT ENTRY / \ / \ ENTRY T(B) T(A) PARENT / \ / \ T(A) CHILD CHILD T(B) */ if (pNchild = pNentry->pRchild) pNchild->pParent = pNparent; pNparent->pLchild = pNchild; pNparent->pParent = pNentry; pNentry->pRchild = pNparent; } else { /* case 2: PARENT ENTRY / \ / \ T(A) ENTRY PARENT T(B) / \ / \ CHILD T(B) T(A) CHILD */ if (pNchild = pNentry->pLchild) pNchild->pParent = pNparent; pNparent->pRchild = pNchild; pNparent->pParent = pNentry; pNentry->pLchild = pNparent; } pNentry->pParent = NULL; } else { pNgrand = pNparent->pParent; pNgreat = pNgrand->pParent; if (pNentry == pNparent->pLchild) { if (pNparent == pNgrand->pLchild) { /* case 3: (GREAT) (GREAT) | | GRAND ENTRY / \ / \ PARENT T(B) T(A) PARENT / \ / \ ENTRY CHILD2 CHILD1 GRAND / \ / \ T(A) CHILD1 CHILD2 T(B) */ if (pNchild = pNentry->pRchild) pNchild->pParent = pNparent; pNparent->pLchild = pNchild; if (pNchild = pNparent->pRchild) pNchild->pParent = pNgrand; pNgrand->pLchild = pNchild; pNgrand->pParent = pNparent; pNparent->pRchild = pNgrand; pNparent->pParent = pNentry; pNentry->pRchild = pNparent; } else { /* case 4: (GREAT) (GREAT) | | GRAND _____ENTRY____ / \ / \ T(A) PARENT GRAND PARENT / \ / \ / \ ENTRY T(B) T(A) CHILD1 CHILD2 T(B) / \ CHILD1 CHILD2 */ if (pNchild = pNentry->pLchild) pNchild->pParent = pNgrand; pNgrand->pRchild = pNchild; if (pNchild = pNentry->pRchild) pNchild->pParent = pNparent; pNparent->pLchild = pNchild; pNgrand->pParent = pNentry; pNentry->pLchild = pNgrand; pNparent->pParent = pNentry; pNentry->pRchild = pNparent; } } else { if (pNparent == pNgrand->pLchild) { /* case 5: (GREAT) (GREAT) | | GRAND _____ENTRY____ / \ / \ PARENT T(B) PARENT GRAND / \ / \ / \ T(A) ENTRY T(A) CHILD1 CHILD2 T(B) / \ CHILD1 CHILD2 */ if (pNchild = pNentry->pLchild) pNchild->pParent = pNparent; pNparent->pRchild = pNchild; if (pNchild = pNentry->pRchild) pNchild->pParent = pNgrand; pNgrand->pLchild = pNchild; pNparent->pParent = pNentry; pNentry->pLchild = pNparent; pNgrand->pParent = pNentry; pNentry->pRchild = pNgrand; } else { /* case 6: (GREAT) (GREAT) | | GRAND ENTRY / \ / \ T(A) PARENT PARENT T(B) / \ / \ CHILD1 ENTRY GRAND CHILD2 / \ / \ CHILD2 T(B) T(A) CHILD1 */ if (pNchild = pNentry->pLchild) pNchild->pParent = pNparent; pNparent->pRchild = pNchild; if (pNchild = pNparent->pLchild) pNchild->pParent = pNgrand; pNgrand->pRchild = pNchild; pNgrand->pParent = pNparent; pNparent->pLchild = pNgrand; pNparent->pParent = pNentry; pNentry->pLchild = pNparent; } } if (pNgreat) { if (pNgreat->pLchild == pNgrand) pNgreat->pLchild = pNentry; else pNgreat->pRchild = pNentry; } pNentry->pParent = pNgreat; } } } return pNentry; } /*** NextNode - return node with next key in tree * * Purpose: * With the specified context and node, determine * the node with the next larger value. * * Input: * pSymContext - pointer to context to test * pNode - pointer to node within context * NULL to return the first node in the tree * * Returns: * pointer to node of the next value * NULL if largest node was input * *************************************************************************/ PNODE NextNode (PSYMCONTEXT pSymContext, PNODE pNode) { PNODE pLast; if (pNode) { // nonnull input, if node has a right child, // return the leftmost child of the right child // or right child itself if not left children if (pNode->pRchild) { pNode = pNode->pRchild; while (pNode->pLchild) pNode = pNode->pLchild; } else { // if no right child, go up through the parent // links until the node comes from a left child // and return it do { pLast = pNode; pNode = pNode->pParent; } while (pNode && pNode->pLchild != pLast); } } else { // NULL input return first node of tree. // return leftmost child of root or root itself // if no left children. pNode = pSymContext->pNodeRoot; if (pNode) while (pNode->pLchild) pNode = pNode->pLchild; } return pNode; } #if 0 /*** OutputTree - output tree node in ascending order * * Purpose: * Using the specified context, output the corresponding * tree from lowest to highest values. * * Input: * pSymContext - pointer to context whose tree to output * * Output: * contents of tree nodes from low to high * *************************************************************************/ void OutputTree (PSYMCONTEXT pSymContext) { PNODE pNode = NULL; PSYMBOL pSymbol; CHAR count; DebugPrintf("****** output tree ******\n"); while (TRUE) { pNode = NextNode(pSymContext, pNode); if (pNode) { pSymbol = PNODE_TO_PSYMBOL(pNode, pSymContext); DebugPrintf("node:%8lx par:%8lx lch:%8lx rch:%8lx " , pNode, pNode->pParent, pNode->pLchild, pNode->pRchild); DebugPrintf("value: %8lx <", pSymbol->offset); count = pSymbol->underscores; while (count--) DebugPrintf("_"); DebugPrintf("%s>\n", pSymbol->string); } else break; } } #endif /*** GetOffsetFromSym - return offset from symbol specified * * Purpose: * external routine. * With the specified symbol, set the pointer to * its offset. The variable chSymbolSuffix may * be used to append a character to repeat the search * if it first fails. * * Input: * pString - pointer to input symbol * * Output: * pOffset - pointer to offset to be set * * Returns: * BOOLEAN value of success * *************************************************************************/ BOOLEAN GetOffsetFromSym (PCHAR pString, PULONG pOffset, CHAR iModule) { CHAR SuffixedString[SYMBOLSIZE + 16]; CHAR Suffix[4]; // Nobody should be referencing a 1 character symbol! It causes the // rest of us to pay a huge penalty whenever we make a typo. Please // change to 2 character instead of removing this hack! // if ( strlen(pString) == 1 || strlen(pString) == 0 ) { return FALSE; } #ifdef _PPC_ // Allow symbol searching procedure names without the '..' prefix // for unassemble and breakpoint commands if (ppcPrefix) { SuffixedString[0] = '.'; SuffixedString[1] = '.'; SuffixedString[2] = '\0'; strcat(SuffixedString, pString); if (GetOffsetFromString(SuffixedString, pOffset, iModule)) return TRUE; } #endif if (GetOffsetFromString(pString, pOffset, iModule)) return TRUE; if (chSymbolSuffix != 'n') { strcpy(SuffixedString, pString); Suffix[0] = chSymbolSuffix; Suffix[1] = '\0'; strcat(SuffixedString, Suffix); if (GetOffsetFromString(SuffixedString, pOffset, iModule)) return TRUE; } return FALSE; } /*** GetOffsetFromString - return offset from string specified * * Purpose: * With the specified string, set the pointer to * its offset. * * Input: * pString - pointer to input string * * Output: * pOffset - pointer to offset to be set * * Returns: * BOOLEAN value of success * *************************************************************************/ BOOLEAN GetOffsetFromString (PCHAR pString, PULONG pOffset, CHAR iModule) { PSYMBOL pSymSearch = AllocSymbol(0L, pString, iModule, NULL); PSYMBOL pSymbol; int st; EnsureModuleSymbolsLoaded(iModule); // search for string in tree st = AccessNode(&(pProcessCurrent->symcontextSymbolString), &(pSymSearch->nodeString)); if (st) { // if not found, try again with underscore prepended to name pSymSearch->underscores++; st = AccessNode(&(pProcessCurrent->symcontextSymbolString), &(pSymSearch->nodeString)); } if (!st) { // if found, get the pointer to its symbol and set the offset pSymbol = PNODE_TO_PSYMBOL (pProcessCurrent->symcontextSymbolString.pNodeRoot, &(pProcessCurrent->symcontextSymbolString)); *pOffset = pSymbol->offset; } // deallocate the temporary symbol structure and return success DeallocSymbol(pSymSearch); return (BOOLEAN)(st == 0); } #if 0 /*** GetOffsetFromLineno - return offset from file:lineno specified * * Purpose: * With the specified file and line number, return * its offset. * * Input: * pString - pointer to input string for filename * lineno - line number of filename specified * * Output: * pOffset - pointer to offset to be set * * Returns: * BOOLEAN value of success * *************************************************************************/ PLINENO GetLinenoFromFilename (PCHAR pString, PPSYMFILE ppSymfile, USHORT lineNum, CHAR iModule) { PPLINENO ppLineno; PLINENO pLineno = NULL; PSYMFILE pSymfileSearch = AllocSymfile("", pString, "", NULL, lineNum, 0, 0, iModule); PSYMFILE pSymfile; USHORT indexLow; USHORT indexHigh; USHORT indexTest; int st; EnsureModuleSymbolsLoaded(iModule); // search for symbol file containing line number in tree st = AccessNode(&(pProcessCurrent->symcontextSymfileString), &(pSymfileSearch->nodeString)); if (!st) { // if found, search line number list for offset pSymfile = PNODE_TO_PSYMFILE (pProcessCurrent->symcontextSymfileString.pNodeRoot, &(pProcessCurrent->symcontextSymfileString)); *ppSymfile = pSymfile; // search the PLINENO array for the pointer to the LINENO // structure having the line number given. ppLineno = pSymfile->ppLinenoSrcLine; indexLow = 1; indexHigh = pSymfile->cLineno; do { indexTest = (USHORT)((indexLow + indexHigh) / 2); if (lineNum > (*(ppLineno + indexTest))->breakLineNumber) indexLow = (USHORT)(indexTest + 1); else if (lineNum < (*(ppLineno + indexTest))->breakLineNumber) indexHigh = (USHORT)(indexTest - 1); else indexLow = indexHigh = indexTest; } while (indexLow < indexHigh); pLineno = *(ppLineno + indexHigh); } // deallocate the temporary symbol structure and return pointer DeallocSymfile(pSymfileSearch); return pLineno; } void GetLinenoString (PCHAR pchBuffer, ULONG offset) { PLINENO pLineno; PSYMFILE pSymfile; *pchBuffer = '\0'; pLineno = GetLinenoFromOffset(&pSymfile, offset); if (pLineno && pLineno->memoryOffset == offset) sprintf(pchBuffer, "%s:%d", pSymfile->pchName, pLineno->breakLineNumber); } void GetCurrentMemoryOffsets (PLONG pMemoryLow, PULONG pMemoryHigh) { ADDR pcValue; PSYMFILE pSymfile; PLINENO pLineno; GetRegPCValue(&pcValue); *pMemoryLow = (ULONG)-1L; // default value for no source if (fSourceOnly) { pLineno = GetLinenoFromOffset(&pSymfile, Flat(pcValue)); if (pLineno) { *pMemoryLow = pLineno->memoryOffset; if (pLineno == (pSymfile->pLineno + pSymfile->cLineno)) *pMemoryHigh = pSymfile->endOffset; else *pMemoryHigh = (pLineno + 1)->memoryOffset; } } } PLINENO GetCurrentLineno (PPSYMFILE ppSymfile) { ADDR pcValue; GetRegPCValue(&pcValue); return GetLinenoFromOffset(ppSymfile, Flat(pcValue)); } PLINENO GetLastLineno (PPSYMFILE ppSymfile, PUSHORT pLineNum) { PLINENO pLineno = NULL; PSYMFILE pSymfile; if (pSymfileLast) { pLineno = GetLinenoFromFilename(( PCHAR )pSymfileLast->pchName, &pSymfile, lineNumberLast, pSymfileLast->modIndex); if (pLineno) { *ppSymfile = pSymfile; *pLineNum = lineNumberLast; } } return pLineno; } static PCHAR Type[] = {"null", "void", "char", "short", "int", "long", "float", "double", ""/*struct*/, "union", "enum", "moe", "uchar", "ushort", "uint", "ulong"}; static PCHAR Dtype[]= {"", "*", "()", "[]"}; BOOLEAN GetLocalFromString(PCHAR pszLocal, PULONG pValue) { PSYMFILE pSymfileSearch = pTempSymfile; PSYMFILE pSymfile; SYMBOL Symbol; static ADDR addrPC; static PLOCAL pLocal; PLOCAL pL; ADDR newPC; GetRegPCValue(&newPC); if (!AddrEqu(newPC, addrPC)){ // search for symbol file containing offset in tree pSymfileSearch->startOffset = Flat(addrPC) = Flat(newPC); if (AccessNode(&(pProcessCurrent->symcontextSymfileOffset), &(pSymfileSearch->nodeOffset))){ pLocal = NULL; return FALSE; } // Get the symfile from the root pSymfile = PNODE_TO_PSYMFILE (pProcessCurrent->symcontextSymfileOffset.pNodeRoot, &(pProcessCurrent->symcontextSymfileOffset)); // create temporary symbol with offset (module not needed) Symbol.offset = Flat(addrPC); Symbol.string[0] = '\0'; // access the function in the tree with value closest if (AccessNode(&(pSymfile->symcontextFunctionOffset), &(Symbol.nodeOffset)) != 1) { pLocal = (PNODE_TO_PSYMBOL (pSymfile->symcontextFunctionOffset.pNodeRoot, &(pSymfile->symcontextFunctionOffset)))->pLocal; } else { pLocal = NULL; return FALSE; } } for(pL=pLocal;pL;pL=pL->next){ if (_stricmp(pszLocal, pL->pszLocalName)) continue; *pValue = GetLocalValue(pL->value, pL->type, FALSE); return TRUE; } return FALSE; } PSYMBOL GetFunctionFromOffset (PPSYMFILE ppSymfile, ULONG offset) { PSYMFILE pSymfileSearch = pTempSymfile; PSYMFILE pSymfile; PSYMBOL pSymbol = NULL; SYMBOL Symbol; int st; PCHAR pszCtrl; ULONG value; // load symbols for offset if needed (and if possible) st = EnsureOffsetSymbolsLoaded(offset); if (!st) { // search for symbol file containing offset in tree pSymfileSearch->startOffset = offset; st = AccessNode(&(pProcessCurrent->symcontextSymfileOffset), &(pSymfileSearch->nodeOffset)); } // DeallocSymfile(pSymfileSearch); // fails if non-code static if (st) { // DebugPrintf("no symfile for function offset %08lx\n", offset); return NULL; } // Get the symfile from the root pSymfile = PNODE_TO_PSYMFILE (pProcessCurrent->symcontextSymfileOffset.pNodeRoot, &(pProcessCurrent->symcontextSymfileOffset)); // Make this symfile available to the caller *ppSymfile = pSymfile; // create temporary symbol with offset (module not needed) Symbol.offset = offset; Symbol.string[0] = '\0'; // access the function in the tree with value (or nearest lesser value) if (AccessNode(&(pSymfile->symcontextFunctionOffset), &(Symbol.nodeOffset)) != 1) { pSymbol = PNODE_TO_PSYMBOL (pSymfile->symcontextFunctionOffset.pNodeRoot, &(pSymfile->symcontextFunctionOffset)); DebugPrintf("%s(){\n", pSymbol->string); if (pSymbol->pLocal){ PLOCAL pLocal = pSymbol->pLocal; while(pLocal){ // stop output on break if (fControlC) { fControlC = 0; break; } // MUST ITERATE THROUGH ALL THE DERIVED TYPES!!!! // DO THIS LATER value = labs(pLocal->value); if (pLocal->type==IMAGE_SYM_TYPE_STRUCT){ if (baseDefault==10) pszCtrl=" [EBP%s%ld]\t"; else pszCtrl=" [EBP%s0x%lx]\t"; DebugPrintf(pszCtrl, *((LONG*)&pLocal->value)<0?"-":"+", value); // THIS -2 IS DUE TO A CONVERTER/LINKER BUG. THIS OFFSET MIGHT CHANGE if(!GetStructFromValue(pLocal->aux, pLocal->value)) GetStructFromValue(pLocal->aux-2, pLocal->value); DebugPrintf("%s%s\n", pLocal->pszLocalName, Dtype[(pLocal->type>>4)&0x3]); } else{ if (baseDefault==10) pszCtrl=" [EBP%s%ld]\t(%s%s)\t%s = "; else pszCtrl=" [EBP%s0x%lx]\t(%s%s)\t%s = "; DebugPrintf(pszCtrl, *((LONG*)&pLocal->value)<0?"-":"+", value, Type[pLocal->type&0xF], Dtype[(pLocal->type>>4)&0x3], pLocal->pszLocalName); GetLocalValue(pLocal->value, pLocal->type, TRUE); DebugPrintf("\n"); } pLocal = pLocal->next; } } else DebugPrintf("NO LOCALS"); DebugPrintf("}\n"); } return pSymbol; } PSTRUCT GetStructFromValue(ULONG value, LONG base) { PSTRUCT pStruct = NULL; STRUCT Struct; PCHAR pszCtrl; ULONG val; // create temporary structure with the specified value Struct.offset = value; Struct.string[0] = '\0'; // access the structure in the tree with the specified value if (!AccessNode(&(pProcessCurrent->symcontextStructOffset), &(Struct.nodeOffset))) { pStruct = (PSTRUCT) PNODE_TO_PSYMBOL ( pProcessCurrent->symcontextStructOffset.pNodeRoot, &(pProcessCurrent->symcontextStructOffset)); DebugPrintf("struct %s {\n", pStruct->string); if (pStruct->pField){ PFIELD pField = pStruct->pField; while(pField){ val = labs(pField->value); if (baseDefault==10) pszCtrl="\t\t [%s%ld]\t(%s%s)\t%s = "; else pszCtrl="\t\t [%s0x%lx]\t(%s%s)\t%s = "; DebugPrintf(pszCtrl, *((LONG*)&pField->value)<0?"-":"+", val, Type[pField->type&0xF], Dtype[(pField->type>>4)&0x3], pField->pszFieldName); GetLocalValue(base+pField->value, pField->type, TRUE); DebugPrintf("\n"); pField = pField->next; } } else DebugPrintf("NO FIELDS"); DebugPrintf("\t\t} "); return pStruct; } else return (PSTRUCT)NULL; } ULONG GetLocalValue(LONG value, USHORT type, BOOLEAN fPrint) { UCHAR dtype = (UCHAR)(type >> 4); ULONG data; PCHAR pszCtrl=NULL; ULONG retValue; #ifdef i386 float f; double df; #endif type &= 0xF; if (fPointerExpression) { PADDR paddr = GetRegFPValue(); AddrAdd(paddr, value); if (fPrint) dprintAddr(paddr); return (ULONG)Flat(*paddr); } GetBytesFromFrame(( PCHAR )&data, value, sizeof(data)); if (dtype) { if (fPrint) DebugPrintf("0x%08lx", data); return data; } switch(type){ case IMAGE_SYM_TYPE_NULL: pszCtrl = "%lx??"; retValue = data; break; case IMAGE_SYM_TYPE_VOID: pszCtrl = "VOID"; retValue = data; break; case IMAGE_SYM_TYPE_CHAR: case IMAGE_SYM_TYPE_UCHAR: pszCtrl = " [%u]"; data = retValue = (UCHAR)data; if (fPrint) DebugPrintf("%c", data); break; case IMAGE_SYM_TYPE_SHORT: pszCtrl = "%d"; data = retValue = (USHORT)data; break; case IMAGE_SYM_TYPE_USHORT: pszCtrl = "%u"; data = retValue = (USHORT)data; break; case IMAGE_SYM_TYPE_INT: case IMAGE_SYM_TYPE_LONG: pszCtrl = "%ld"; retValue = data; break; case IMAGE_SYM_TYPE_UINT: case IMAGE_SYM_TYPE_ULONG: pszCtrl = "%lu"; retValue = data; break; #ifdef i386 case IMAGE_SYM_TYPE_FLOAT: pszCtrl = "%f"; GetBytesFromFrame((PCHAR)&f, value, sizeof(float)); if (fPrint) DebugPrintf(pszCtrl, f); return data; break; case IMAGE_SYM_TYPE_DOUBLE: pszCtrl = "%lf"; GetBytesFromFrame((PCHAR)&df, value, sizeof(double)); if (fPrint) DebugPrintf(pszCtrl, df); return data; break; #endif default:{ PADDR paddr = GetRegFPValue(); pszCtrl = "???"; AddrAdd(paddr, value); retValue = Flat(*paddr); } break; } if (fPrint) DebugPrintf(pszCtrl, data); return retValue; } void GetBytesFromFrame(PCHAR pcb, LONG offset, USHORT cb) { PADDR paddr = GetRegFPValue(); AddrAdd(paddr, offset); GetMemString(paddr, (PUCHAR)pcb, cb); } void AddFieldToStructure(PSTRUCT pStruct, PCHAR pszFieldName, ULONG value, USHORT type, ULONG auxValue) { PFIELD pField; if (!pStruct) return; if (!(pField=(PFIELD)malloc(sizeof(FIELD)+strlen(pszFieldName)))) return; strcpy(pField->pszFieldName, pszFieldName); pField->type = type; pField->value = value; pField->aux = auxValue; pField->next = pStruct->pField; pStruct->pField = pField; } void AddLocalToFunction(PSYMBOL pFunction, PCHAR pszLocalName, ULONG value, USHORT type, ULONG auxValue) { PLOCAL pLocal; if (!pFunction) return; if (!(pLocal=(PLOCAL)malloc(sizeof(LOCAL)+strlen(pszLocalName)))) return; strcpy(pLocal->pszLocalName, pszLocalName); pLocal->type = type; pLocal->value = value; pLocal->aux = auxValue; pLocal->next = pFunction->pLocal; pFunction->pLocal = pLocal; } #endif //0 PSYMBOL InsertFunction(PCHAR lpFunctionName, ULONG offset) //, PSYMBOL pS) { PSYMFILE pSymfileSearch = pTempSymfile; //AllocSymfile("", "", "", NULL, 0, offset, 0, 0); PSYMFILE pSymfile; PSYMBOL pSymbol; int st; // Find the symbol file containing this function pTempSymfile->startOffset = offset; st = AccessNode(&(pProcessCurrent->symcontextSymfileOffset), &(pSymfileSearch->nodeOffset)); // DeallocSymfile(pSymfileSearch); // fails if non-code static if (st) { // DebugPrintf("no symfile for function offset %08lx\n", offset); return NULL; } // A symfile was found, now get it from the root pSymfile = PNODE_TO_PSYMFILE (pProcessCurrent->symcontextSymfileOffset.pNodeRoot, &(pProcessCurrent->symcontextSymfileOffset)); // Allocate a function node. pSymbol = AllocSymbol(offset, lpFunctionName, pSymfile->modIndex, NULL); // pSymbol->pSymbol = pS; // Now insert this function into this symfile's function tree if (!InsertNode(&(pSymfile->symcontextFunctionOffset), &(pSymbol->nodeOffset))) { DeallocSymbol(pSymbol); // DebugPrintf("insert - value %d already in tree\n", lpFunctionName); return NULL; } if (!InsertNode(&(pSymfile->symcontextFunctionString), &(pSymbol->nodeString))) { DeleteNode(&(pSymfile->symcontextFunctionOffset), &(pSymbol->nodeOffset)); DeallocSymbol(pSymbol); DebugPrintf("insert - string %s already in tree\n", lpFunctionName); return NULL; } return pSymbol; } #if 0 PLINENO GetLinenoFromOffset (PPSYMFILE ppSymfile, ULONG offset) { PLINENO pLineno = NULL; PSYMFILE pSymfileSearch = AllocSymfile("", "", "", NULL, 0, offset, 0, 0); PSYMFILE pSymfile; USHORT indexLow; USHORT indexHigh; USHORT indexTest; int st; // load symbols for offset if needed (and if possible) st = EnsureOffsetSymbolsLoaded(offset); if (!st) { // search for symbol file containing offset in tree st = AccessNode(&(pProcessCurrent->symcontextSymfileOffset), &(pSymfileSearch->nodeOffset)); } if (!st) { // if found, search line number list for offset pSymfile = PNODE_TO_PSYMFILE (pProcessCurrent->symcontextSymfileOffset.pNodeRoot, &(pProcessCurrent->symcontextSymfileOffset)); // search for index with equal or closest lessor value to // the offset given indexLow = 1; indexHigh = pSymfile->cLineno; do { indexTest = (USHORT)((indexLow + indexHigh) / 2); if (offset > (pSymfile->pLineno + indexTest)->memoryOffset) indexLow = (USHORT)(indexTest + 1); else if (offset < (pSymfile->pLineno + indexTest)->memoryOffset) indexHigh = (USHORT)(indexTest - 1); else indexLow = indexHigh = indexTest; } while (indexLow < indexHigh); *ppSymfile = pSymfile; pLineno = pSymfile->pLineno + indexHigh; } // deallocate the temporary symbol structure and return pointer DeallocSymfile(pSymfileSearch); return pLineno; } /*** GetAdjacentSymOffsets - get the offset of the adjoining symbols * * Purpose: * external routine. * With the specified offset, return the next higher offset * that corresponds to a symbol. * * Input: * offset - address from which to search * * Output: * prevOffset - offset of previous symbol; 0 is there is no previous symbol * nextOffset - offset of next symbol; 0xffffffff if there is none */ void GetAdjacentSymOffsets (ULONG addrStart, PULONG prevOffset, PULONG nextOffset) { PSYMBOL pSymbol; PNODE pNode; // make a symbol structure with the supplied offset pSymbol = AllocSymbol(addrStart, "", -1, NULL); // try to access the node with the offset given. // the node pointer returned will be the nearest offset less // than the argument (unless it is less than the tree minimum) AccessNode(&(pProcessCurrent->symcontextSymbolOffset), &(pSymbol->nodeOffset)); // Don't need this anymore, free it. DeallocSymbol(pSymbol); pNode = pProcessCurrent->symcontextSymbolOffset.pNodeRoot; // if empty tree, no symbols, just return if (!pNode) { *prevOffset = 0; *nextOffset = 0xffffffff; // No symbols at all return; } // if offset of initial node is less than request address, // set node pointer to NULL if ((*prevOffset = PNODE_TO_PSYMBOL(pNode, &(pProcessCurrent->symcontextSymbolOffset))->offset) > addrStart) { pNode = NULL; *prevOffset = 0; } // OK, now find the next symbol from where we are pNode = NextNode(&(pProcessCurrent->symcontextSymbolOffset),pNode); if (!pNode || (*nextOffset = PNODE_TO_PSYMBOL(pNode, &(pProcessCurrent->symcontextSymbolOffset))->offset) < addrStart) { *nextOffset = 0xffffffff; } return; } #endif //0 /*** GetSymbolStdCall - get symbol name from offset specified * * Purpose: * external routine. * With the specified offset, return the nearest symbol string * previous or equal to the offset and its displacement * * Input: * offset - input offset to search * offsetSymMax - maximum offset of a symbol (global value) * * Output: * pchBuffer - pointer to buffer to fill with string * pDisplacement - pointer to offset displacement * * Notes: * if offset if less than any defined symbol, the NULL value * is returned and the displacement is set to the offset * *************************************************************************/ void GetSymbolStdCall ( PCProcess pProcess, ULONG offset, PCHAR pchBuffer, PULONG pDisplacement, PUSHORT pStdCallParams ) { SYMBOL Symbol; ULONG disp = offset; PSYMBOL pSymbol; ULONG underscorecnt; UCHAR ch; PCHAR pszTemp; ULONG orgOffset = offset; ULONG NextDisp; PSYMBOL pNextSymbol; BOOLEAN fFoundStub = FALSE; PIMAGE_INFO pImage; UCHAR pCodeBytes[SIZE_COVERAGE_STUB]; int iTotalBytesRead; pProcessCurrent = pProcess; // create temporary symbol with offset (module not needed) Symbol.offset = offset; Symbol.string[0] = '\0'; *pchBuffer = '\0'; pImage = GetImageInfoFromOffset(offset); if (pImage && pImage->fHasOmap) { // load symbols if needed and check range, and if in range, // access symbol in tree with value (or nearest lesser value) if (!EnsureOffsetSymbolsLoaded(offset) && AccessNode(&(pProcessCurrent->symcontextSymbolOffset), &(Symbol.nodeOffset)) != 1) { pSymbol = PNODE_TO_PSYMBOL (pProcessCurrent->symcontextSymbolOffset.pNodeRoot, &(pProcessCurrent->symcontextSymbolOffset)); // displacement is input offset less symbol value offset if (disp == pSymbol->offset) { disp = 0; } else { offset += SIZE_COVERAGE_STUB; NextDisp = offset; Symbol.offset = offset; Symbol.string[0] = '\0'; if (!EnsureOffsetSymbolsLoaded(offset) && AccessNode(&(pProcessCurrent->symcontextSymbolOffset), &(Symbol.nodeOffset)) != 1) { pNextSymbol = PNODE_TO_PSYMBOL (pProcessCurrent->symcontextSymbolOffset.pNodeRoot, &(pProcessCurrent->symcontextSymbolOffset)); if (NextDisp == pNextSymbol->offset) { pSymbol = pNextSymbol; ReadVirtualMemory((PUCHAR)offset - SIZE_COVERAGE_STUB, (PUCHAR)pCodeBytes, SIZE_COVERAGE_STUB, (PDWORD)&iTotalBytesRead); // Final check if ( ((*(pCodeBytes) == NOP_OPCODE) && (*(pCodeBytes + 5) == NOP_OPCODE) && (*(pCodeBytes + 10) == NOP_OPCODE)) || ((*(pCodeBytes) == PUSH_OPCODE) && (*(pCodeBytes + 5) == PUSH_OPCODE) && (*(pCodeBytes + 10) == CALL_OPCODE)) ) { fFoundStub = TRUE; disp = 0; } else { disp -= pSymbol->offset; } } else { offset = orgOffset + SIZE_INST_STUB; NextDisp = offset; Symbol.offset = offset; Symbol.string[0] = '\0'; if (!EnsureOffsetSymbolsLoaded(offset) && AccessNode(&(pProcessCurrent->symcontextSymbolOffset), &(Symbol.nodeOffset)) != 1) { pNextSymbol = PNODE_TO_PSYMBOL (pProcessCurrent->symcontextSymbolOffset.pNodeRoot, &(pProcessCurrent->symcontextSymbolOffset)); if (NextDisp == pNextSymbol->offset) { pSymbol = pNextSymbol; ReadVirtualMemory((PUCHAR)offset - SIZE_INST_STUB, (PUCHAR)pCodeBytes, SIZE_INST_STUB, (PDWORD)&iTotalBytesRead); // Final check if ( ((*(pCodeBytes) == NOP_OPCODE) && (*(pCodeBytes + 5) == NOP_OPCODE)) || ((*(pCodeBytes) == PUSH_OPCODE) && (*(pCodeBytes + 5) == CALLIND_OPCODE)) ) { fFoundStub = TRUE; disp = 0; } else { disp -= pSymbol->offset; } } else { disp -= pSymbol->offset; } } else { disp -= pSymbol->offset; } } } else { disp -= pSymbol->offset; } } // build string from module name, underscore count, // and remaining string pszTemp = (PCHAR)pImageFromIndex(pSymbol->modIndex)->szModuleName; while (ch = *pszTemp++) *pchBuffer++ = ch; *pchBuffer++ = '!'; underscorecnt = pSymbol->underscores; while (underscorecnt--) *pchBuffer++ = '_'; strcpy(pchBuffer, (PCHAR)pSymbol->string); if (fFoundStub) { pchBuffer += strlen(pchBuffer); strcpy(pchBuffer, "__INST__STUB"); } if (pStdCallParams) { *pStdCallParams = pSymbol->stdCallParams; } } } else { // load symbols if needed and check range, and if in range, // access symbol in tree with value (or nearest lesser value) if (!EnsureOffsetSymbolsLoaded(offset) && AccessNode(&(pProcessCurrent->symcontextSymbolOffset), &(Symbol.nodeOffset)) != 1) { pSymbol = PNODE_TO_PSYMBOL (pProcessCurrent->symcontextSymbolOffset.pNodeRoot, &(pProcessCurrent->symcontextSymbolOffset)); // build string from module name, underscore count, // and remaining string pszTemp = (PCHAR)pImageFromIndex(pSymbol->modIndex)->szModuleName; while (ch = *pszTemp++) *pchBuffer++ = ch; *pchBuffer++ = '!'; underscorecnt = pSymbol->underscores; while (underscorecnt--) *pchBuffer++ = '_'; strcpy(pchBuffer, (PCHAR)pSymbol->string); // displacement is input offset less symbol value offset disp -= pSymbol->offset; if (pStdCallParams) { *pStdCallParams = pSymbol->stdCallParams; } } } *pDisplacement = disp; } /*** AllocSymbol - build and allocate symbol * * Purpose: * Allocate space for symbol structure. * * Input: * offset - offset of symbol to be allocated * pString - pointer to string of symbol to be allocated * * Returns: * pointer to filled symbol structure * * Exceptions: * * Notes: * space allocated is: sizeof(SYMBOL) -- nonstring info and 3 UCHAR's * + strlen(pString) -- size of string * + 1 -- space for terminating NULL * the sum is rounded up using the 3 UCHAR's and and'ing with ~3 * *************************************************************************/ PSYMBOL AllocSymbol ( ULONG offset, PCHAR pString, CHAR iModule, PCHAR stringOffset ) { PSYMBOL pSymbol; PCHAR pStringTemp; ULONG StringLength=0; CHAR undecsym[512]; PCHAR sym = pString; PCHAR pch; ULONG off; ULONG i,j; ULONG TotalStringLength=0; if (*sym == '?') { if (UnDecorateSymbolName( sym, undecsym, sizeof(undecsym), UNDNAME_COMPLETE | UNDNAME_NO_LEADING_UNDERSCORES | UNDNAME_NO_MS_KEYWORDS | UNDNAME_NO_FUNCTION_RETURNS | UNDNAME_NO_ALLOCATION_MODEL | UNDNAME_NO_ALLOCATION_LANGUAGE | UNDNAME_NO_MS_THISTYPE | UNDNAME_NO_CV_THISTYPE | UNDNAME_NO_THISTYPE | UNDNAME_NO_ACCESS_SPECIFIERS | UNDNAME_NO_THROW_SIGNATURES | UNDNAME_NO_MEMBER_TYPE | UNDNAME_NO_RETURN_UDT_MODEL | UNDNAME_NO_ARGUMENTS | UNDNAME_NO_SPECIAL_SYMS | UNDNAME_NAME_ONLY )) { sym = undecsym; pch = strstr( sym, "::" ); if ( pch ) { *pch++ = '_'; *pch = '_'; } if (!stringOffset) { if (GetOffsetFromSym( sym, &off, iModule )) { i = 1; j = strlen(sym); do { sprintf(&sym[j],"%d",i++); } while( GetOffsetFromSym( sym, &off, iModule ) ); } } } } pStringTemp = sym; // skip over initial @ for 'fastcall' symbols if (*sym == '@') { sym++; pStringTemp++; } // allocate the space needed // scan from right, because fastcall thunks look // link "__imp__@foo@nn". pch = strrchr(sym, '@'); if (!pch) { StringLength = strlen(sym); } else { i = 1; while (isdigit(pch[i])) { ++i; } if (pch[i] == '\0') { StringLength = pch - sym; } else { StringLength = pch - sym + i; } } if (stringOffset) { TotalStringLength = StringLength + sizeof(stringOffset); } else { TotalStringLength = StringLength; } pSymbol = ( SYMBOL * )malloc((sizeof(SYMBOL) + TotalStringLength + 3) & ~3); if (!pSymbol) { DebugPrintf("AllocSymbol - Out of memory\n"); ExitProcess((UINT)STATUS_UNSUCCESSFUL); } // get the number of dwords pushed for parameters if (sym[StringLength] == '@') { sscanf(&sym[StringLength+1], "%hu", &pSymbol->stdCallParams); } else { pSymbol->stdCallParams = 0xffff; } // set the offset and decode the string into its count of // underscores and copy the remaining string pSymbol->offset = offset; while (*pStringTemp == '_') pStringTemp++; pSymbol->underscores = (CHAR)(pStringTemp - sym); pSymbol->modIndex = iModule; pSymbol->type = SYMBOL_TYPE_SYMBOL; pSymbol->pLocal = NULL; strncpy((PCHAR)pSymbol->string, pStringTemp,StringLength); pSymbol->string[StringLength-pSymbol->underscores]=(UCHAR)'\0'; if (stringOffset) { strcat((PCHAR)pSymbol->string, stringOffset); } return pSymbol; } static SYMBOL symbolTemplate = { { NULL, NULL, NULL }, { NULL, NULL, NULL }, (ULONG)-1L, 0, 0, SYMBOL_TYPE_SYMBOL, NULL, 0, { '\177', '\177', '\0' } }; /*** AllocSymfile - build and allocate symbol file structure * * Purpose: * Allocate space for symbol file structure. * * Input: * offset - offset of symbol to be allocated * pString - pointer to string of symbol to be allocated * * Returns: * pointer to filled symbol structure * *************************************************************************/ PSYMFILE AllocSymfile (PCHAR pPathname, PCHAR pFilename, PCHAR pExtension, PIMAGE_LINENUMBER pCoffLineno, USHORT cLineno, ULONG startingOffset, ULONG endingOffset, CHAR modIndex) { PSYMFILE pSymfile; PLINENO pLineno; USHORT index; PSYMBOL symbolMax; IMAGE_LINENUMBER CoffLineno; pSymfile = ( SYMFILE * )malloc(sizeof(SYMFILE)); if (!pSymfile) { DebugPrintf("AllocSymfile - Out of memory\n"); ExitProcess((UINT)STATUS_UNSUCCESSFUL); } symbolMax = &pSymfile->maxSymbol; *symbolMax = symbolTemplate; pSymfile->symcontextFunctionOffset.pNodeRoot = NULL; pSymfile->symcontextFunctionOffset.pNodeMax = (PNODE)((LONG)symbolMax + NODE_SYMBOL_DISPLACEMENT(nodeOffset)); pSymfile->symcontextFunctionOffset.pfnCompare = &CompareSymbolOffset; pSymfile->symcontextFunctionOffset.nodeDisplacement = NODE_SYMBOL_DISPLACEMENT(nodeOffset); pSymfile->symcontextFunctionString.pNodeRoot = NULL; pSymfile->symcontextFunctionString.pNodeMax = (PNODE)((LONG)symbolMax + NODE_SYMBOL_DISPLACEMENT(nodeString)); pSymfile->symcontextFunctionString.pfnCompare = &CompareSymbolString; pSymfile->symcontextFunctionString.nodeDisplacement = NODE_SYMBOL_DISPLACEMENT(nodeString); pSymfile->pchPath = ( PUCHAR )malloc(strlen(pPathname) + 1); if (!pSymfile->pchPath) { DebugPrintf("AllocSymfile - Out of memory\n"); ExitProcess((UINT)STATUS_UNSUCCESSFUL); } strcpy((PCHAR)pSymfile->pchPath, pPathname); pSymfile->pchName = ( PUCHAR )malloc(strlen(pFilename) + 1); if (!pSymfile->pchName) { DebugPrintf("AllocSymfile - Out of memory\n"); ExitProcess((UINT)STATUS_UNSUCCESSFUL); } strcpy((PCHAR)pSymfile->pchName, pFilename); pSymfile->pchExtension = ( PUCHAR )malloc(strlen(pExtension) + 1); if (!pSymfile->pchExtension) { DebugPrintf("AllocSymfile - Out of memory\n"); ExitProcess((UINT)STATUS_UNSUCCESSFUL); } strcpy((PCHAR)pSymfile->pchExtension, pExtension); pSymfile->modIndex = modIndex; pSymfile->cLineno = cLineno; if (pCoffLineno) { pSymfile->pLineno = ( LINENO * )malloc((cLineno + 1) * sizeof(LINENO)); if (!pSymfile->pLineno) { DebugPrintf("AllocSymfile - Out of memory\n"); ExitProcess((UINT)STATUS_UNSUCCESSFUL); } pLineno = pSymfile->pLineno; // define pseudo-lineno structure for start of file pLineno->memoryOffset = 0; pLineno->breakLineNumber = 1; pLineno->topLineNumber = 1; pLineno->topFileOffset = 0; pLineno++; // first lineno to process is after the pseudo entry pSymfile->pLinenoNext = pLineno; // process list into remaining entries in array for (index = 0; index < pSymfile->cLineno; index++) { memcpy((PUCHAR)&CoffLineno, (PUCHAR)pCoffLineno, IMAGE_SIZEOF_LINENUMBER); pLineno->memoryOffset = CoffLineno.Type.VirtualAddress; pLineno->breakLineNumber = CoffLineno.Linenumber; pLineno->topLineNumber = 0xffff; pLineno->topFileOffset = (ULONG)-1L; pLineno++; pCoffLineno = (PIMAGE_LINENUMBER)((PUCHAR)pCoffLineno + IMAGE_SIZEOF_LINENUMBER); } // initialize further... pSymfile->nextFileOffset = 0; pSymfile->nextLineNumber = 1; pSymfile->nextScanState = stStart; // allocate and initialize list of PLINENO's for sorting // of line number for the file. pSymfile->ppLinenoSrcLine = ( PLINENO * )malloc( (pSymfile->cLineno + 1) * sizeof(PLINENO)); if (!pSymfile->ppLinenoSrcLine) { DebugPrintf("AllocSymfile - Out of memory\n"); ExitProcess((UINT)STATUS_UNSUCCESSFUL); } for (index = 0; index < (USHORT)(pSymfile->cLineno + 1); index++) *(pSymfile->ppLinenoSrcLine + index) = pSymfile->pLineno + index; // first LINENO to process on scan is after pseudo-entry pSymfile->ppLinenoSrcNext = pSymfile->ppLinenoSrcLine + 1; // sort the pointers for increasing source line numbers SortSrcLinePointers(pSymfile); } else { pSymfile->pLineno = NULL; pSymfile->ppLinenoSrcLine = NULL; } pSymfile->startOffset = startingOffset; pSymfile->endOffset = endingOffset; pSymfile->modIndex = modIndex; return pSymfile; } /*** DeallocSymbol - release symbol space * * Purpose: * Deallocate the symbol space given by the pointer * * Input: * pSymbolReturn - pointer to symbol to return * * Output: * None. * *************************************************************************/ void DeallocSymbol (PSYMBOL pSymbolReturn) { free(pSymbolReturn); } /*** DeleteSymfile - delete specified symbol file from splay tree * * Purpose: * external routine. * Delete the specified symbol file object in both the * offset and string trees and deallocate its space. * * Input: * pSymfile - pointer to symfile object to delete * * Output: * None. * *************************************************************************/ void DeleteSymfile (PSYMFILE pSymfile) { DeleteNode(&(pProcessCurrent->symcontextSymfileOffset), &(pSymfile->nodeOffset)); DeleteNode(&(pProcessCurrent->symcontextSymfileString), &(pSymfile->nodeString)); DeallocSymfile(pSymfile); } /*** DeallocSymfile - release symbol file space * * Purpose: * Deallocate the symbol file space given by the pointer * * Input: * pSymfileReturn - pointer to symbol file to return * * Output: * None. * *************************************************************************/ void DeallocSymfile (PSYMFILE pSymfile) { free(pSymfile->pchPath); free(pSymfile->pchName); free(pSymfile->pchExtension); free(pSymfile->pLineno); free(pSymfile->ppLinenoSrcLine); free(pSymfile); } #if 0 /*** fnListNear - function to list symbols near an address * * Purpose: * from the address specified, access the symbol table to * find the closest symbolic addresses both before and after * it. output these on one line (if spaces permits). * * Input: * addrstart - address to base listing * * Output: * symbolic and absolute addresses of variable on or before * and after the specified address * *************************************************************************/ static char szBlanks[] = " "; void fnListNear (ULONG addrStart) { PSYMBOL pSymbol; PNODE pNode; ULONG cbString[2]; UCHAR szEntry[SYMBOLSIZE + 16]; PCHAR pszEntry; ULONG count; ULONG index; PSYMFILE pSymfile; PLINENO pLineno; // make a symbol structure with the supplied offset pSymbol = AllocSymbol(addrStart, "", -1, NULL); // // BryanT 11/9/92 - First make sure that the address we're looking // for is loaded (if possible). The AccessNode code below will // only search the known universe... // EnsureOffsetSymbolsLoaded(addrStart); // try to access the node with the offset given. // the node pointer returned will be the nearest offset less // than the argument (unless it is less than the tree minimum) AccessNode(&(pProcessCurrent->symcontextSymbolOffset), &(pSymbol->nodeOffset)); // Don't need this anymore, free it. DeallocSymbol(pSymbol); pNode = pProcessCurrent->symcontextSymbolOffset.pNodeRoot; // if empty tree, no symbols, just return if (!pNode) return; // if offset of initial node is less than request address, // set node pointer to NULL if (PNODE_TO_PSYMBOL(pNode, &(pProcessCurrent->symcontextSymbolOffset))->offset > addrStart) pNode = NULL; // build the string for the symbol before and after (index = 0 and 1) for (index = 0; index < 2; index++) { pszEntry = (PCHAR)szEntry; if (pNode) { pSymbol = PNODE_TO_PSYMBOL(pNode, &(pProcessCurrent->symcontextSymbolOffset)); //pszEntry += sprintf(pszEntry, "(%08lx) ", pSymbol->offset); pszEntry += sprintf(pszEntry, "(%08lx) ", addrStart); pszEntry += sprintf(pszEntry, "%s!", pImageFromIndex(pSymbol->modIndex)->szModuleName); count = pSymbol->underscores; while (count--) pszEntry += sprintf(pszEntry, "_"); pszEntry += sprintf(pszEntry, "%s", (PCHAR)pSymbol->string); // // BryanT 11/10/92 - Print the offset also. // if (pSymbol->offset < addrStart) pszEntry += sprintf(pszEntry, "+0x%x", addrStart - pSymbol->offset); else if (pSymbol->offset > addrStart) pszEntry += sprintf(pszEntry, "-0x%x", pSymbol->offset - addrStart); // // BryanT 11/9/92 - If possible, print the line number where // this symbol resides. // pLineno=GetLinenoFromOffset(&pSymfile, pSymbol->offset); if (pLineno && pLineno->memoryOffset==pSymbol->offset) pszEntry += sprintf(pszEntry, " (%s.%d)", pSymfile->pchName, pLineno->breakLineNumber); } else { if (index == 0) pszEntry += sprintf(pszEntry, "(%08lx) ", addrStart); pszEntry += sprintf(pszEntry, ""); } cbString[index] = (PCHAR)pszEntry - (PCHAR)szEntry; if (index == 0) { DebugPrintf("%s", szEntry); pNode = NextNode(&(pProcessCurrent->symcontextSymbolOffset), pNode); } } // the first string has been output, szEntry has the second string // and cbString[0] and [1] have their respective sizes. if (cbString[0] + cbString[1] < 75) DebugPrintf(" | "); else { DebugPrintf("\n"); if (cbString[1] <= 78) count = 78 - cbString[1]; else count = sizeof(szBlanks) - 3; DebugPrintf(&szBlanks[sizeof(szBlanks) - count]); } DebugPrintf("%s\n", szEntry); } #endif void SortSrcLinePointers (PSYMFILE pSymfile) { PPLINENO ppLineno = pSymfile->ppLinenoSrcLine; PLINENO pLinenoV; USHORT N; USHORT h; USHORT i; USHORT j; N = (USHORT)(pSymfile->cLineno - 1); h = 1; do h = (USHORT)(3 * h + 1); while (h <= N); do { h = (USHORT)(h / 3); for (i = h; i < N; i++) { pLinenoV = *(ppLineno + i); j = i; while ((*(ppLineno + j - h))->breakLineNumber > pLinenoV->breakLineNumber) { *(ppLineno + j) = *(ppLineno + j - h); j = j - h; if (j < h) break; } *(ppLineno + j) = pLinenoV; } } while (h > 1); } #if 0 #if 0 void OutputAtLineno (PSYMFILE pSymfile, PLINENO pLineno) { USHORT index; UCHAR buffer[180]; FILE * fhandle; UpdateLineno(pSymfile, pLineno); fhandle = LocateTextInSource(pSymfile, pLineno); if (fhandle) for (index = pLineno->topLineNumber; index <= pLineno->breakLineNumber; index++) { if (!fgets(buffer, sizeof(buffer), fhandle)) error(FILEREAD); DebugPrintf("%4d: %s", index, buffer); } } #endif void UpdateLineno (PSYMFILE pSymfile, PLINENO pLineno) { PPLINENO ppLinenoNext; UCHAR scanState; USHORT nextLineNumber; USHORT topLineNumber; ULONG topFileOffset; FILE * fhandle; UCHAR ch; // if line number structure is already processed, // then just return. if (pLineno->topLineNumber == 0xffff) { // copy variables from the symbol file structure ppLinenoNext = pSymfile->ppLinenoSrcNext; scanState = pSymfile->nextScanState; nextLineNumber = pSymfile->nextLineNumber; // open and locate the file to the position specified in // the symbol file structure. if no handle, return error. fhandle = LocateTextInSource(pSymfile, NULL); if (!fhandle) return; // for each LINENO structure pointed by ppLinenoNext // until pLineno is processed, compute the // topLineNumber and topFileOffset. do { topFileOffset = ftell(fhandle); topLineNumber = nextLineNumber; // test if the current LINENO structure has the same // breakLineNumber as the previous LINENO in the // ppLineno list. if ((*ppLinenoNext)->breakLineNumber == (*(ppLinenoNext - 1))->breakLineNumber) { // if this is a repeating line number, just copy // the topFileOffset and topLineNumber entries (*ppLinenoNext)->topFileOffset = (*(ppLinenoNext - 1))->topFileOffset; (*ppLinenoNext)->topLineNumber = (*(ppLinenoNext - 1))->topLineNumber; } else { // nonrepeating line number - determine new topFileOffset // and topLineNumber entries // scan each line in the source file, numbered by // nextLineNumber until the line numbered by // (*ppLinenoNext)->breakLineNumber is scanned. do { // to scan a source file line, read each character // and change scanState appropriately and exit // when a '\n' is read. do { ch = (UCHAR)getc(fhandle); switch (ch) { case '\t': case ' ': scanState = WhiteSpace[scanState]; break; case '/': scanState = Slash[scanState]; break; case '*': scanState = Star[scanState]; break; case '#': scanState = Pound[scanState]; break; case '\n': case '\r': break; case (UCHAR)EOF: error(FILEREAD); default: scanState = OtherChar[scanState]; break; } } while (ch != '\n'); // if the final scan state of the line is a comment // and the line is not a breaking line number, // set the topFileOffset and topLineNumber to // the line after the one just scanned. if (fCommentType[scanState] && nextLineNumber != pLineno->breakLineNumber) { topFileOffset = ftell(fhandle); topLineNumber = (USHORT)(nextLineNumber + 1); } // set the state for the next line, either stStart // or stSlStar for a continuing multiline comment scanState = Return[scanState]; } while (nextLineNumber++ != (*ppLinenoNext)->breakLineNumber); // put topFileOffset and topLineNumber into the pLineno // to finish its processing (*ppLinenoNext)->topFileOffset = topFileOffset; (*ppLinenoNext)->topLineNumber = topLineNumber; // Reset the topFileOffset and topLinenumber to the // beginning of the file before continuing. This // fixes the problem where the line number records // aren't monotonically increasing. if (((*ppLinenoNext) != pLineno) && (*(ppLinenoNext+1))->breakLineNumber < (*ppLinenoNext)->breakLineNumber) { nextLineNumber = 1; fseek(fhandle, 0, SEEK_SET); } } } while (*(ppLinenoNext++) != pLineno); // set the variables back in the symbol file structure // for the next call pSymfile->ppLinenoSrcNext = ppLinenoNext; pSymfile->nextScanState = scanState; pSymfile->nextFileOffset = ftell(fhandle); pSymfile->nextLineNumber = nextLineNumber; } } FILE * LocateTextInSource (PSYMFILE pSymfile, PLINENO pLineno) { static FILE * fhandle = NULL; static PSYMFILE pSymfileOpened = NULL; CHAR chFilename[_MAX_PATH]; PCHAR pchTemp; static PCHAR AltSrc[16]; static INT cAltSrc[16]; static PCHAR AltDst[16]; static INT cAlt = 0; INT i; // // Allow the current file handle to be closed if 's-' is used // if ((pSymfile == NULL) && (pLineno == NULL) && (fhandle != NULL)) { fclose(fhandle); fhandle = NULL; pSymfileOpened = NULL; } if (pSymfile != pSymfileOpened) { if (fhandle) { fclose(fhandle); fhandle = NULL; pSymfileOpened = NULL; } if (pSymfile && pSymfile->pchPath) { strcpy(chFilename, (PCHAR)pSymfile->pchPath); strcat(chFilename, (PCHAR)pSymfile->pchName); strcat(chFilename, (PCHAR)pSymfile->pchExtension); fhandle = _fsopen(chFilename, "r", SH_DENYNO); if (!fhandle) { // Try alternatives if (fVerboseOutput) DebugPrintf("%s%s%s not found. Trying alternatives...\n", pSymfile->pchPath, pSymfile->pchName, pSymfile->pchExtension); for (i = 0; i < cAlt; i++) { if (!_strnicmp(AltSrc[i], (PCHAR)pSymfile->pchPath, cAltSrc[i])) { strcpy(chFilename, AltDst[i]); strcat(chFilename, (PCHAR)pSymfile->pchPath+cAltSrc[i]); strcat(chFilename, (PCHAR)pSymfile->pchName); strcat(chFilename, (PCHAR)pSymfile->pchExtension); fhandle = _fsopen(chFilename, "r", SH_DENYNO); if (fhandle) { if (fVerboseOutput) DebugPrintf("Found it! - %s\n", chFilename); chFilename[strlen(chFilename) - strlen((PCHAR)pSymfile->pchName) - strlen((PCHAR)pSymfile->pchExtension)] = '\0'; pSymfile->pchPath = (PUCHAR)realloc((PCHAR)pSymfile->pchPath, strlen(chFilename) + 1); strcpy((PCHAR)pSymfile->pchPath, chFilename); break; } } } if (!fhandle) { // Still no luck. Ask the user for the path. will // indicate no path. if (fVerboseOutput) DebugPrintf("Alternatives weren't very helpful. Why don't you try?\n"); do { DebugPrintf("enter path for '%s%s%s' (cr for none):", pSymfile->pchPath, pSymfile->pchName, pSymfile->pchExtension); NtsdPrompt("", chFilename, sizeof(chFilename)); RemoveDelChar(chFilename); if (*chFilename) { pchTemp = chFilename + strlen(chFilename) - 1; if (*pchTemp != ':' && *pchTemp != '\\') strcat(pchTemp + 1, "\\"); strcat(chFilename, (PCHAR)pSymfile->pchName); strcat(chFilename, (PCHAR)pSymfile->pchExtension); fhandle = _fsopen(chFilename, "r", SH_DENYNO); if (!fhandle) DebugPrintf("Sorry. '%s' cannot be opened\n", chFilename); } else { // Before aborting, make sure the user didn't // press by mistake NtsdPrompt("No Source for this file, are you sure? ", chFilename, sizeof(chFilename)); if (chFilename[0] == 'y' || chFilename[0] == 'Y') { free(pSymfile->pchPath); pSymfile->pchPath = NULL; return NULL; } } } while (!fhandle); // We wouldn't be here unless we have a new path to // the source file. Save the difference between what // we thought it should be and what it is for later // lookup in the alternatives array. // Truncate before the name/extension chFilename[strlen(chFilename) - strlen((PCHAR)pSymfile->pchName) - strlen((PCHAR)pSymfile->pchExtension)] = '\0'; // Search back for the first non-match for (pchTemp = chFilename + strlen(chFilename), i = strlen((PCHAR)pSymfile->pchPath); pchTemp > chFilename; pchTemp--, i--) { if (*pchTemp != *((PCHAR)pSymfile->pchPath+i)) break; } // Find the closest '\' or ':' while (*pchTemp != '\\' && *pchTemp != ':') pchTemp++, i++; // Move one more so we don't lose it pchTemp++, i++; // Save the initial and final *(pSymfile->pchPath+i) = '\0'; i = pchTemp - chFilename; AltSrc[cAlt] = (PCHAR)pSymfile->pchPath; cAltSrc[cAlt] = strlen((PCHAR)pSymfile->pchPath); AltDst[cAlt] = (PCHAR)malloc(i + 1); memcpy(AltDst[cAlt], chFilename, i); AltDst[cAlt][i] = '\0'; cAlt++%16; // Store the new path pSymfile->pchPath = (PUCHAR)_strdup(chFilename); } } } pSymfileOpened = pSymfile; } if (fhandle) fseek(fhandle, pLineno ? pLineno->topFileOffset : pSymfile->nextFileOffset, SEEK_SET); return fhandle; } void OutputSourceLines (PSYMFILE pSymfile, USHORT startLineNum, USHORT count) { PPLINENO ppLineno; USHORT indexLow; USHORT indexTest; USHORT indexHigh; // search the PLINENO array for the pointer to the LINENO // structure having the line number given. ppLineno = pSymfile->ppLinenoSrcLine; indexLow = 1; indexHigh = pSymfile->cLineno; do { indexTest = (USHORT)((indexLow + indexHigh) / 2); if (startLineNum > (*(ppLineno + indexTest))->breakLineNumber) indexLow = (USHORT)(indexTest + 1); else if (startLineNum < (*(ppLineno + indexTest))->breakLineNumber) indexHigh = (USHORT)(indexTest - 1); else indexLow = indexHigh = indexTest; } while (indexLow < indexHigh); // if startLineNum is larger than the maximum line number in // the list, indexLow is past the last entry. // set indexLow to the last entry in this case. if (indexLow > pSymfile->cLineno) indexLow--; // indexLow refers to the LINENO structure with a line // number equal to or greater than startLineNum. UpdateLineno(pSymfile, *(ppLineno + indexLow)); if (startLineNum < (*(ppLineno + indexLow))->topLineNumber) indexLow--; OutputLines(pSymfile, *(ppLineno + indexLow), startLineNum, count); } BOOLEAN OutputSourceFromOffset (ULONG offset, BOOLEAN fMatch) { PSYMFILE pSymfile; PLINENO pLineno; BOOLEAN fOutput = FALSE; pLineno = GetLinenoFromOffset(&pSymfile, offset); if (pLineno) { UpdateLineno(pSymfile, pLineno); if (!fMatch || pLineno->memoryOffset == offset) fOutput = OutputLines(pSymfile, pLineno, pLineno->topLineNumber, (SHORT)(pLineno->breakLineNumber - pLineno->topLineNumber + 1)); } return fOutput; } BOOLEAN OutputLines (PSYMFILE pSymfile, PLINENO pLineno, USHORT startLineNum, USHORT count) { FILE * fhandle; UCHAR buffer[SYMBOLSIZE * 2]; USHORT lineNumber; PSYMFILE pSymfileNext; PLINENO pLinenoNext; UpdateLineno(pSymfile, pLineno); fhandle = LocateTextInSource(pSymfile, pLineno); if (!fhandle) return FALSE; lineNumber = pLineno->topLineNumber; // output module and filename as label. DebugPrintf("%s!%s:\n", pImageFromIndex(pSymfile->modIndex)->szModuleName, pSymfile->pchName); while (count) { // read the next line - report read error fgets((PCHAR)buffer, sizeof(buffer), fhandle); if (ferror(fhandle)) error(FILEREAD); // if EOF and no lines printed, break last valid line // if lines printed, just exit if (feof(fhandle)) { if (--lineNumber < startLineNum) { startLineNum = lineNumber; count = 1; } else break; } if (lineNumber >= startLineNum) { DebugPrintf("%4d", lineNumber); // if linenumber is on a breakpoint, // output a '>', if not, ':'. pLinenoNext = GetLinenoFromFilename((PCHAR)pSymfile->pchName, &pSymfileNext, lineNumber, pSymfile->modIndex); if (lineNumber == pLinenoNext->breakLineNumber) DebugPrintf(">"); else DebugPrintf(":"); DebugPrintf(" %s", buffer); count--; } lineNumber++; } pSymfileLast = pSymfile; lineNumberLast = lineNumber; return TRUE; } #endif //0 void ExtractDebugInfoFromImage( PIMAGE_INFO pImage ) { if (pImage->fDebugInfoLoaded) { return; } pImage->fSymbolsSeparate = FALSE; pImage->fDebugInfoLoaded = TRUE; pImage->lpDebugInfo = MapDebugInformation( pImage->hFile, (PCHAR)(pImage->szImagePath[ 0 ] != '\0' ? pImage->szImagePath : NULL), SymbolSearchPath, (DWORD)pImage->lpBaseOfImage == -1 ? 0 : (DWORD)pImage->lpBaseOfImage ); if (pImage->lpDebugInfo) { if (pImage->lpDebugInfo->Characteristics & IMAGE_FILE_DEBUG_STRIPPED) { pImage->fSymbolsSeparate = TRUE; } strcpy( (PCHAR)pImage->szImagePath, pImage->lpDebugInfo->ImageFilePath ); strcpy( (PCHAR)pImage->szDebugPath, pImage->lpDebugInfo->DebugFilePath ); pImage->dwCheckSum = pImage->lpDebugInfo->CheckSum; pImage->ImageBase = (LPVOID)pImage->lpDebugInfo->ImageBase; if ((DWORD)pImage->lpBaseOfImage == -1) { pImage->lpBaseOfImage = pImage->ImageBase; } pImage->dwSizeOfImage = pImage->lpDebugInfo->SizeOfImage; pImage->dwCheckSum = pImage->lpDebugInfo->CheckSum; if (pImage->lpDebugInfo->NumberOfFunctionTableEntries) { pImage->NumberOfFunctions = pImage->lpDebugInfo->NumberOfFunctionTableEntries; pImage->FunctionTable = pImage->lpDebugInfo->FunctionTableEntries; pImage->LowAddress = pImage->lpDebugInfo->LowestFunctionStartingAddress; pImage->HighAddress = pImage->lpDebugInfo->HighestFunctionEndingAddress; } else if (pImage->lpDebugInfo->NumberOfFpoTableEntries) { pImage->dwFpoEntries = pImage->lpDebugInfo->NumberOfFpoTableEntries; pImage->pFpoData = pImage->lpDebugInfo->FpoTableEntries; } if (!pImage->szModuleName[0]) { CreateModuleNameFromPath( (PCHAR)pImage->szImagePath, (PCHAR)pImage->szModuleName ); } } else { DebugPrintf("%s: Unable to load debug information for %s\n", DebuggerName, pImage->szImagePath ); } if (pImage->hFile) { CloseHandle( pImage->hFile ); pImage->hFile = NULL; } return; } UCHAR pPathname[ MAX_PATH ]; UCHAR pFilename[ MAX_PATH ]; UCHAR pExtension[ MAX_PATH ]; DWORD ExtractSymbolsExceptionFilter( LPEXCEPTION_POINTERS ep, PULONG pRetries ) { // not even going to look at retries this time around... DebugPrintf("%s: exception 0x%08X while trying to load symbols\n", DebuggerName, ep->ExceptionRecord->ExceptionCode); return EXCEPTION_EXECUTE_HANDLER; } void ExtractSymbolsFromImage( PIMAGE_INFO pImage ) { ULONG cb; PIMAGE_DEBUG_INFORMATION DebugInfo; PIMAGE_COFF_SYMBOLS_HEADER lpDebugInfo; PIMAGE_SYMBOL lpSymbolEntry; IMAGE_SYMBOL SymbolEntry; IMAGE_AUX_SYMBOL AuxSymbolEntry; PIMAGE_LINENUMBER lpPointerToLinenumbers; IMAGE_LINENUMBER LineNumber; PCHAR lpStringTable; PCHAR lpSymbolName; CHAR ShortString[10]; ULONG symsize; ULONG index; ULONG ind; ULONG auxcount; ULONG symbolcount = 0; ULONG entrycount; ULONG SymbolValue; PSYMBOL pNewSymbol = NULL; PSYMBOL pCurrentFunction = NULL; PSTRUCT pCurrentStructure = NULL; PCHAR pszName = NULL; PIMAGE_LINENUMBER pLinenumbers = NULL; PIMAGE_LINENUMBER pLinenumberNext; PCHAR pchName; int cName; BOOLEAN nameFound = FALSE; BOOLEAN validLinenumbers; ULONG pStartOfSymbol, pEndOfSymbol, pSymEnd; ULONG OrgSymAddr; ULONG OptimizedSymAddr; ULONG OptimizedLineNumAddr; ULONG Bias; PIMAGE_SYMBOL lpNextSymbolEntry; IMAGE_SYMBOL NextSymbolEntry; ULONG LastSymbolRVA = 0; ULONG Retries; DWORD rvaSym; POMAP pomap; POMAP pomapFromEnd; POMAPLIST pomaplistHead; POMAPLIST pomaplistNew; POMAPLIST pomaplistPrev; POMAPLIST pomaplistNext; POMAPLIST pomaplistCur; if (pImage->fSymbolsLoaded) { return; } if (pImage->lpDebugInfo == NULL) { return; } pImage->fSymbolsLoaded = TRUE; // // catch inpage errors when foolish people load syms from a share. // Retries = 0; try { DebugInfo = pImage->lpDebugInfo; if (pImage->fHasOmap) { pomapFromEnd = pImage->rgomapFromSource + pImage->comapFromSrc; } if (pImage->NumberOfFunctions) { cb = pImage->NumberOfFunctions * sizeof( IMAGE_FUNCTION_ENTRY ); pImage->FunctionTable = ( IMAGE_FUNCTION_ENTRY * )malloc(cb); if (pImage->FunctionTable == NULL) { DebugPrintf("%s: Unable to allocate space for function table for %s\n",DebuggerName,pImage->szImagePath); } else { memcpy(pImage->FunctionTable, DebugInfo->FunctionTableEntries, cb); } } else if (pImage->dwFpoEntries) { cb = pImage->dwFpoEntries * sizeof( FPO_DATA ); pImage->pFpoData = ( FPO_DATA * )malloc(cb); if (pImage->pFpoData == NULL) { DebugPrintf("%s: Unable to allocate space for FPO table for %s\n",DebuggerName,pImage->szImagePath); } else { memcpy(pImage->pFpoData, DebugInfo->FpoTableEntries, cb); if (fVerboseOutput) { DebugPrintf("%s: Loaded (%d) fpo entries for image (%s)\n", DebuggerName, pImage->dwFpoEntries, pImage->szImagePath ); } } } if (DebugInfo->SizeOfCoffSymbols == 0) { LoadCvSymbols( pImage ); return; } pImage->offsetLow = 0xffffffff; pImage->offsetHigh = 0x0; symsize = IMAGE_SIZEOF_SYMBOL; lpDebugInfo = DebugInfo->CoffSymbols; if (lpDebugInfo->NumberOfLinenumbers != 0) { validLinenumbers = TRUE; } else { validLinenumbers = FALSE; } lpPointerToLinenumbers = (PIMAGE_LINENUMBER)((ULONG)lpDebugInfo + lpDebugInfo->LvaToFirstLinenumber); lpSymbolEntry = (PIMAGE_SYMBOL)((ULONG)lpDebugInfo + lpDebugInfo->LvaToFirstSymbol); lpStringTable = (PCHAR)((ULONG)lpDebugInfo + lpDebugInfo->LvaToFirstSymbol + lpDebugInfo->NumberOfSymbols * symsize); if ( fVerboseOutput ) DebugPrintf("# lines %lx, # sym %lx\n", lpDebugInfo->NumberOfLinenumbers, lpDebugInfo->NumberOfSymbols); for (entrycount = 0; entrycount < lpDebugInfo->NumberOfSymbols; entrycount++) { memcpy((PUCHAR)&SymbolEntry, (PVOID) lpSymbolEntry, symsize); lpSymbolEntry = (PIMAGE_SYMBOL)((PUCHAR)lpSymbolEntry + symsize); auxcount = SymbolEntry.NumberOfAuxSymbols; // Save original address value OrgSymAddr = SymbolEntry.Value + (ULONG)pImage->lpBaseOfImage; // Peek at next symbol if ( fVerboseOutput ) DebugPrintf("entrycount %ld, auxcount %ld\n", entrycount, auxcount); // Add 1 first since entrycount will be ++ before addingto auxcount if ((entrycount + 1 + auxcount) < lpDebugInfo->NumberOfSymbols) { lpNextSymbolEntry = (PIMAGE_SYMBOL) ((PUCHAR)lpSymbolEntry + auxcount * symsize); memcpy((PUCHAR)&NextSymbolEntry, (PVOID) lpNextSymbolEntry, symsize); } else { lpNextSymbolEntry = NULL; } SymbolValue = SymbolEntry.Value + (ULONG)pImage->lpBaseOfImage; if (pImage->fHasOmap) { Bias = 0; OptimizedSymAddr = ConvertOmapFromSrc( SymbolValue, pImage, &Bias); if (OptimizedSymAddr == 0) // No equivalent address { #ifdef OMAP_DETAILS DebugPrintf("NTSD: OMAP Not Found [%8lx]\n", SymbolValue); #endif SymbolEntry.Value = 0; } else if (OptimizedSymAddr != SymbolValue) { // We have successfully converted #ifdef OMAP_DETAILS DebugPrintf("NTSD: OMAP Found [%8lx] - [%8lx]\n", SymbolValue, OptimizedSymAddr); #endif SymbolEntry.Value = OptimizedSymAddr + Bias - (ULONG)pImage->lpBaseOfImage; if (SymbolEntry.Value > LastSymbolRVA) { LastSymbolRVA = SymbolEntry.Value; } } } if ( fVerboseOutput ) DumpSymbolTableEntry(&SymbolEntry, lpStringTable); #if 0 if (auxcount) { int numaux = auxcount; PIMAGE_AUX_SYMBOL lpAuxSymbolEntry = (PIMAGE_AUX_SYMBOL)lpSymbolEntry; while (numaux--) { DumpAuxSymbolTableEntry(&SymbolEntry, lpAuxSymbolEntry, SectionHdrs); lpAuxSymbolEntry = (PIMAGE_AUX_SYMBOL)((PUCHAR)lpAuxSymbolEntry + symsize); } } #endif switch (SymbolEntry.StorageClass) { case IMAGE_SYM_CLASS_FILE: // allocate and copy the pathname from the following // auxiliary entries. memcpy(pPathname, (PVOID) lpSymbolEntry, (int)(auxcount * symsize)); pPathname[auxcount * symsize] = '\0'; _strlwr((PCHAR)pPathname); // extract the filename from the pathname as the string // following the last '\' or ':', but not including any // characters after '.'. pchName = strrchr((PCHAR)pPathname, '\\'); if (!pchName) { pchName = strrchr((PCHAR)pPathname, ':'); } if (!pchName) { pchName = (PCHAR)pPathname; } else { pchName++; } cName = strcspn(pchName, "."); // allocate a string and copy the filename part of the // path and convert to lower case. strncpy((PCHAR)pFilename, (PCHAR)pchName, cName); *(pFilename + cName) = '\0'; // allocate a string and copy the extension part of the // path, if any, and convert to lower case. strcpy((PCHAR)pExtension, (PCHAR)pchName + cName); // remove filename and extension from pathname by // null-terminating at the start of the filename // BUT, if null pathname, put in ".\" since a null // is interpreted as NO PATH available. if (pchName == (PCHAR)pPathname) { *pchName++ = '.'; *pchName++ = '\\'; } *pchName = '\0'; if ( SrcDrive ) { // Now overide the drive pchName = strchr((PCHAR)pPathname,':'); if ( pchName ) { CHAR Temp[MAX_PATH]; strcpy(Temp,SrcDrive); strcat(Temp,pchName+1); strcpy((PCHAR)pPathname,Temp); } } break; case IMAGE_SYM_CLASS_STATIC: if (validLinenumbers && SymbolEntry.SectionNumber > 0 && SymbolEntry.Type == IMAGE_SYM_TYPE_NULL && auxcount == 1) { index = SymbolEntry.SectionNumber - 1; memcpy((PUCHAR)&AuxSymbolEntry, (PVOID) lpSymbolEntry, symsize); if (AuxSymbolEntry.Section.Length && AuxSymbolEntry.Section.NumberOfLinenumbers) { pLinenumbers = (PIMAGE_LINENUMBER)realloc((PUCHAR)pLinenumbers, IMAGE_SIZEOF_LINENUMBER * (int)AuxSymbolEntry.Section.NumberOfLinenumbers); pLinenumberNext = pLinenumbers; for (ind = 0; ind < (ULONG)AuxSymbolEntry.Section.NumberOfLinenumbers; ind++) { memcpy((PUCHAR)&LineNumber, (PUCHAR)lpPointerToLinenumbers, IMAGE_SIZEOF_LINENUMBER); if (pImage->fHasOmap) { OptimizedLineNumAddr = LineNumber.Type.VirtualAddress + (ULONG)pImage->lpBaseOfImage; #ifdef OMAP_DETAILS DebugPrintf( "NTSD: OMAP Looking at Lineno[%8lx][%lu]\n", OptimizedLineNumAddr, LineNumber.Linenumber); #endif Bias = 0; OptimizedSymAddr = ConvertOmapFromSrc( OptimizedLineNumAddr, pImage, &Bias); if (OptimizedSymAddr == 0) // no equivalent { #ifdef OMAP_DETAILS DebugPrintf("NTSD: OMAP Not Found [%8lx]\n", OptimizedLineNumAddr); #endif LineNumber.Type.VirtualAddress = OptimizedLineNumAddr; } else if (OptimizedSymAddr != OptimizedLineNumAddr) { #ifdef OMAP_DETAILS DebugPrintf("NTSD: OMAP Found equivalent [%8lx + %lx\n", OptimizedSymAddr, Bias); #endif LineNumber.Type.VirtualAddress = OptimizedSymAddr + Bias; } else { #ifdef OMAP_DETAILS DebugPrintf("NTSD: OMAP No equivalent [%8lx]\n", OptimizedLineNumAddr); #endif LineNumber.Type.VirtualAddress += (ULONG)pImage->lpBaseOfImage; } } else { LineNumber.Type.VirtualAddress += (ULONG)pImage->lpBaseOfImage; } memcpy((PUCHAR)pLinenumberNext, (PUCHAR)&LineNumber, IMAGE_SIZEOF_LINENUMBER); lpPointerToLinenumbers = (PIMAGE_LINENUMBER) ((PUCHAR)lpPointerToLinenumbers + IMAGE_SIZEOF_LINENUMBER); pLinenumberNext = (PIMAGE_LINENUMBER) ((PUCHAR)pLinenumberNext + IMAGE_SIZEOF_LINENUMBER); } pStartOfSymbol = SymbolEntry.Value + (ULONG)pImage->lpBaseOfImage; pEndOfSymbol = pStartOfSymbol + AuxSymbolEntry.Section.Length; pSymEnd = LastSymbolRVA + (ULONG)pImage->lpBaseOfImage + AuxSymbolEntry.Section.Length; if (pEndOfSymbol < pSymEnd) { pEndOfSymbol = pSymEnd + 1; } InsertSymfile((PCHAR)pPathname, (PCHAR)pFilename, (PCHAR)pExtension, pLinenumbers, AuxSymbolEntry.Section.NumberOfLinenumbers, pStartOfSymbol, pEndOfSymbol, pImage->index); } } break; case IMAGE_SYM_CLASS_FUNCTION: if (SymbolEntry.N.Name.Short) { strncpy(ShortString, (PCHAR)SymbolEntry.N.ShortName, IMAGE_SIZEOF_SHORT_NAME); ShortString[IMAGE_SIZEOF_SHORT_NAME] = '\0'; lpSymbolName = (PCHAR)ShortString; } else { lpSymbolName = lpStringTable + SymbolEntry.N.Name.Long; } if (SymbolEntry.Value && pNewSymbol) { SymbolValue = SymbolEntry.Value + (ULONG)pImage->lpBaseOfImage; pCurrentFunction = InsertFunction((PCHAR)pNewSymbol->string, pNewSymbol->offset); } break; case IMAGE_SYM_CLASS_EXTERNAL: if (SymbolEntry.N.Name.Short) { strncpy(ShortString, (PCHAR)SymbolEntry.N.ShortName, IMAGE_SIZEOF_SHORT_NAME); ShortString[IMAGE_SIZEOF_SHORT_NAME] = '\0'; lpSymbolName = ShortString; } else { lpSymbolName = lpStringTable + SymbolEntry.N.Name.Long; } if (strncmp(lpSymbolName, "??_C", 4) == 0) { // discard strings break; } if (!pImage->fHasOmap || (lpNextSymbolEntry == NULL)) { pNewSymbol = InsertSymbol(SymbolValue, lpSymbolName, pImage->index, NULL); if (pNewSymbol) { if (SymbolValue > pImage->offsetHigh) pImage->offsetHigh = SymbolValue; if (SymbolValue < pImage->offsetLow) pImage->offsetLow = SymbolValue; symbolcount++; if (fVerboseOutput && symbolcount % 100 == 0) DebugPrintf("%s: module \"%s\" loaded %ld symbols\r", DebuggerName, pImage->szImagePath, symbolcount); } break; // Get out now } if (SymbolEntry.Value) { InsertOmapSymbol( pImage, SymbolEntry.Value, OrgSymAddr, NextSymbolEntry.Value, lpSymbolName, &symbolcount ); } break; default: break; } // auxcount has the number of auxiliary entries // skip over them for the next table entry entrycount += auxcount; lpSymbolEntry = (PIMAGE_SYMBOL) ((PUCHAR)lpSymbolEntry + auxcount * symsize); } } except( ExtractSymbolsExceptionFilter( GetExceptionInformation(), &Retries ) ) { DebugPrintf("%s: unable to load symbols for %s. Symbols may be corrupt.\n", DebuggerName, pImage->szImagePath); pImage->fSymbolsLoaded = FALSE; if (pLinenumbers) { free((void *)pLinenumbers); } pImage->lpDebugInfo = NULL; UnmapDebugInformation(DebugInfo); return; } if (fVerboseOutput) DebugPrintf("%s: \"%s\" loaded %ld symbols" #if defined(MIPS) || defined(_PPC_) ", %ld functions" #endif " (%08lx-%08lx)\n", DebuggerName, pImage->szImagePath, symbolcount, #if defined(MIPS) || defined(_PPC_) pImage->NumberOfFunctions, #endif pImage->offsetLow, pImage->offsetHigh); if (fVerboseOutput || !fLazyLoad) DebugPrintf("%s: loaded symbols for \"%s\"\n", DebuggerName, pImage->szImagePath); if (pszName = DebugInfo->ExportedNames) { ULONG offset; PSYMBOL pSymbol; while (*pszName) { if (GetOffsetFromString(lpSymbolName, &offset, pImage->index)) { pSymbol = PNODE_TO_PSYMBOL (pProcessCurrent->symcontextSymbolString.pNodeRoot, &(pProcessCurrent->symcontextSymbolString)); pSymbol->type = SYMBOL_TYPE_EXPORT; } while (*pszName++) { } } } // free pointers to reallocated strings if (pLinenumbers) free((void *)pLinenumbers); pImage->lpDebugInfo = NULL; UnmapDebugInformation(DebugInfo); } void CreateModuleNameFromPath(LPSTR szImagePath, LPSTR szModuleName) { PCHAR pchName; pchName = szImagePath; pchName += strlen( pchName ); while (pchName > szImagePath) { if (*--pchName == '\\' || *pchName == '/') { pchName++; break; } } strcpy( szModuleName, pchName ); pchName = strchr( szModuleName, '.' ); if (pchName != NULL) { *pchName = '\0'; } #ifdef KERNEL if (KernelImageFileName && _stricmp( szModuleName, KernelModuleName )==0) { strcpy( szModuleName, "NT" ); } else if (HalImageFileName && _stricmp( szModuleName, HalModuleName )==0) { strcpy( szModuleName, HAL_MODULE_NAME ); } #endif } VOID ExtractOmapData(PIMAGE_INFO pImage) /*++ Routine Description: Initialize tables for OMAP data for each image binary. Arguments: pImage - Ptr to PIMAGE_INFO Return Value: Nothing --*/ { PIMAGE_DEBUG_DIRECTORY pDebugDir; ULONG ulDebugDirCount; if (pImage->fSymbolsLoaded) { return; } pImage->fHasOmap = FALSE; pImage->rgomapToSource = NULL; pImage->rgomapFromSource = NULL; pImage->comapToSrc = 0; pImage->comapFromSrc = 0; // If the .dbg file or debug info was not loaded correctly, // do not search for OMAP data. if ((pImage->lpDebugInfo == NULL) || (pImage->lpDebugInfo->SizeOfCoffSymbols == 0)) { return; } pDebugDir = pImage->lpDebugInfo->DebugDirectory; ulDebugDirCount = pImage->lpDebugInfo->NumberOfDebugDirectories; while (ulDebugDirCount--) { size_t cb; void *pv; cb = (size_t) pDebugDir->SizeOfData; pv = (void *) ((DWORD) pImage->lpDebugInfo->MappedBase + pDebugDir->PointerToRawData); switch (pDebugDir->Type) { case IMAGE_DEBUG_TYPE_OMAP_TO_SRC: { pImage->rgomapToSource = (POMAP) malloc(cb); if (pImage->rgomapToSource == NULL) { DebugPrintf("%s: Failed to allocate [%ld] bytes space for OMAP_TO_SRC table\n" "%s: Addresses will not be translated\n", DebuggerName, cb, DebuggerName); break; } RtlCopyMemory((PVOID) pImage->rgomapToSource, pv, cb); pImage->fHasOmap = TRUE; pImage->comapToSrc = cb / sizeof(OMAP); break; } case IMAGE_DEBUG_TYPE_OMAP_FROM_SRC: { pImage->rgomapFromSource = (POMAP) malloc(cb); if (pImage->rgomapFromSource == NULL) { DebugPrintf("%s: Failed to allocate [%ld] bytes space for OMAP_FROM_SRC table\n" "%s: Addresses will not be translated\n", DebuggerName, cb, DebuggerName); break; } RtlCopyMemory((PVOID) pImage->rgomapFromSource, pv, cb); pImage->fHasOmap = TRUE; pImage->comapFromSrc = cb / sizeof(OMAP); break; } } pDebugDir++; } } DWORD ConvertOmapFromSrc(DWORD addr, PIMAGE_INFO pImage, DWORD *pdwBias) /*++ Routine Description: Translate a Src (org binary) address to its equivalent. Arguments: addr - Address to translate Return Value: NULL or 0 - Not found DWORD - New Map Address or original address if not xlated --*/ { DWORD rva; DWORD comap; POMAP pomapLow; POMAP pomapHigh; if (pImage->rgomapFromSource == NULL) { return(addr); } rva = addr - (DWORD) pImage->lpBaseOfImage; comap = pImage->comapFromSrc; pomapLow = pImage->rgomapFromSource; pomapHigh = pImage->rgomapFromSource + comap; while (pomapLow < pomapHigh) { unsigned comapHalf; POMAP pomapMid; comapHalf = comap / 2; pomapMid = pomapLow + ((comap & 1) ? comapHalf : (comapHalf - 1)); if (rva == pomapMid->rva) { return((DWORD) pImage->lpBaseOfImage + pomapMid->rvaTo); } if (rva < pomapMid->rva) { pomapHigh = pomapMid; comap = (comap & 1) ? comapHalf : (comapHalf - 1); } else { pomapLow = pomapMid + 1; comap = comapHalf; } } assert(pomapLow == pomapHigh); // If no exact match, pomapLow points to the next higher address if (pomapLow == pImage->rgomapFromSource) { // 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 *pdwBias = rva - pomapLow[-1].rva; return((DWORD) pImage->lpBaseOfImage + pomapLow[-1].rvaTo); } DWORD ConvertOmapToSrc( PCProcess pProcessCurrent, DWORD addr, PIMAGE_INFO pImage, DWORD *pdwBias) /*++ Routine Description: Translate a address to its equivalent in a src (org) binary. Arguments: addr - Address to translate Return Value: NULL or 0 - Not found DWORD - New Map Address or original address if not xlated --*/ { DWORD rva; DWORD comap; POMAP pomapLow; POMAP pomapHigh; if (pImage->rgomapToSource == NULL) { return(ORG_ADDR_NOT_AVAIL); } rva = addr - (DWORD) pImage->lpBaseOfImage; comap = pImage->comapToSrc; pomapLow = pImage->rgomapToSource; pomapHigh = pImage->rgomapToSource + comap; while (pomapLow < pomapHigh) { unsigned comapHalf; POMAP pomapMid; 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 int i = -1; while ((&pomapMid[i] != pImage->rgomapToSource) && pomapMid[i].rvaTo == 0) // Keep on looping back { // until the beginning i--; } return(pomapMid[i].rvaTo); } else { return(pomapMid->rvaTo); } } if (rva < pomapMid->rva) { pomapHigh = pomapMid; comap = (comap & 1) ? comapHalf : (comapHalf - 1); } else { pomapLow = pomapMid + 1; comap = comapHalf; } } assert(pomapLow == pomapHigh); // If no exact match, pomapLow points to the next higher address if (pomapLow == pImage->rgomapToSource) { // This address was not found return(0); } if (pomapLow[-1].rvaTo == 0) { return(ORG_ADDR_NOT_AVAIL); } // Return the new address plus the bias *pdwBias = rva - pomapLow[-1].rva; return(pomapLow[-1].rvaTo); } POMAP GetOmapEntry(DWORD addr, PIMAGE_INFO pImage) { DWORD rva; DWORD comap; POMAP pomapLow; POMAP pomapHigh; if (pImage->rgomapFromSource == NULL) { return(NULL); } rva = addr - (ULONG) pImage->lpBaseOfImage; comap = pImage->comapFromSrc; pomapLow = pImage->rgomapFromSource; pomapHigh = pImage->rgomapFromSource + comap; while (pomapLow < pomapHigh) { unsigned comapHalf; POMAP pomapMid; 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; } #if 0 void DumpOmapToSrc(ULONG AddrStart) /*++ Routine Description: Dump OmapToSource address map Arguments: AddrStart - Start Address of module to dump Return Value: Nothing --*/ { PIMAGE_INFO pImage; ULONG i; pImage = GetImageInfoFromOffset(AddrStart); if (pImage == NULL) { DebugPrintf("\n%s: -- Module in Deferred mode --\n\n", DebuggerName); return; } if (pImage->rgomapToSource == NULL) { DebugPrintf("\n%s: -- No offset map --\n\n", DebuggerName); return; } DebugPrintf("\n%s: -- OmapToSource --\n\n", DebuggerName); for (i = 0; i < pImage->comapToSrc; i++) { DebugPrintf("%08lx - %08lx ", pImage->rgomapToSource[i].rva, pImage->rgomapToSource[i].rvaTo); if ( ((i + 1) % 2) == 0 ) { DebugPrintf("\n"); } if (fControlC) { fControlC = 0; break; } } DebugPrintf("\n"); } void DumpOmapFromSrc(ULONG AddrStart) /*++ Routine Description: Dump OmapFromSrc addresses Arguments: AddrStart - Start Address of module to dump Return Value: Nothing --*/ { PIMAGE_INFO pImage; ULONG i; pImage = GetImageInfoFromOffset(AddrStart); if (pImage == NULL) { DebugPrintf("\n%s: -- Module in Deferred mode --\n\n", DebuggerName); return; } if (pImage->rgomapFromSource == NULL) { DebugPrintf("\n%s: -- No offset map --\n\n", DebuggerName); return; } DebugPrintf("\n%s: -- OmapFromSrc --\n\n", DebuggerName); for (i = 0; i < pImage->comapFromSrc; i++) { DebugPrintf("%08lx - %08lx ", pImage->rgomapFromSource[i].rva, pImage->rgomapFromSource[i].rvaTo); if ( ((i + 1) % 2) == 0 ) { DebugPrintf("\n"); } if (fControlC) { fControlC = 0; break; } } DebugPrintf("\n"); } PIMAGE_INFO GetImageInfoFromModule( CHAR iModule ) /*++ Routine Description: Get the IMAGE_INFO for iModule Module Arguments: iModule - Module number to get image for Return Value: PIMAGE_INFO or NULL --*/ { PIMAGE_INFO pImage; pImage = pProcessCurrent->pImageHead; while (pImage && pImage->index != (UCHAR)iModule) { pImage = pImage->pImageNext; } return (pImage); } #endif //0 PIMAGE_INFO GetImageInfoFromOffset( ULONG Addr ) /*++ Routine Description: Get the IMAGE_INFO for module where Addr belongs to Arguments: Addr - Address belonging to IMAGE_INFO to retrieve Return Value: PIMAGE_INFO or NULL --*/ { PIMAGE_INFO pImage = pProcessCurrent->pImageHead; while (pImage) { if (Addr >= (ULONG)pImage->lpBaseOfImage && Addr < (ULONG)pImage->lpBaseOfImage + pImage->dwSizeOfImage) { return pImage; } pImage = pImage->pImageNext; } return NULL; } #define n_name N.ShortName #define n_zeroes N.Name.Short #define n_nptr N.LongName[1] #define n_offset N.Name.Long #define IMAGE_SYM_TYPE_BYTE 12 #define IMAGE_SYM_TYPE_WORD 13 #define IMAGE_SYM_TYPE_DWORD 15 VOID DumpSymbolTableEntry ( IN PIMAGE_SYMBOL Symbol, IN PCHAR StringTable ) /*++ Routine Description: Prints a symbol table entry. Arguments: Symbol - Symbol table entry. Return Value: None. --*/ { USHORT type; size_t i, count = 0; PCHAR name; DebugPrintf("%08lX ", Symbol->Value); if (Symbol->n_zeroes) { for (i=0; i<8; i++) { if ((Symbol->n_name[i]>0x1f) && (Symbol->n_name[i]<0x7f)) { count += DebugPrintf("%c", Symbol->n_name[i]); } else { count += DebugPrintf(" "); } } } else { count += DebugPrintf("%s", &StringTable[Symbol->n_offset]); } for (i=count; i<33; i++) { DebugPrintf(" "); } if (Symbol->SectionNumber > 0) { DebugPrintf("SECT%hX ", Symbol->SectionNumber); } else { switch (Symbol->SectionNumber) { case IMAGE_SYM_UNDEFINED: name = "UNDEF"; break; case IMAGE_SYM_ABSOLUTE : name = "ABS "; break; case IMAGE_SYM_DEBUG : name = "DEBUG"; break; default : DebugPrintf("0x%hx ", Symbol->SectionNumber); name = "?????"; } DebugPrintf("%s ", name); } switch (Symbol->Type & 0xf) { case IMAGE_SYM_TYPE_NULL : name = "notype"; break; case IMAGE_SYM_TYPE_VOID : name = "void"; break; case IMAGE_SYM_TYPE_CHAR : name = "char"; break; case IMAGE_SYM_TYPE_SHORT : name = "short"; break; case IMAGE_SYM_TYPE_INT : name = "int"; break; case IMAGE_SYM_TYPE_LONG : name = "long"; break; case IMAGE_SYM_TYPE_FLOAT : name = "float"; break; case IMAGE_SYM_TYPE_DOUBLE : name = "double"; break; case IMAGE_SYM_TYPE_STRUCT : name = "struct"; break; case IMAGE_SYM_TYPE_UNION : name = "union"; break; case IMAGE_SYM_TYPE_ENUM : name = "enum"; break; case IMAGE_SYM_TYPE_MOE : name = "moe"; break; case IMAGE_SYM_TYPE_BYTE : name = "uchar"; break; case IMAGE_SYM_TYPE_WORD : name = "ushort"; break; case IMAGE_SYM_TYPE_UINT : name = "uint"; break; case IMAGE_SYM_TYPE_DWORD : name = "ulong"; break; default : name = "????"; } count = DebugPrintf("%s ", name); for (i=0; i<6; i++) { type = (Symbol->Type >> (10-(i*2)+4)) & (USHORT)3; if (type == IMAGE_SYM_DTYPE_POINTER) { count += DebugPrintf("*"); } if (type == IMAGE_SYM_DTYPE_ARRAY) { count += DebugPrintf("[]"); } if (type == IMAGE_SYM_DTYPE_FUNCTION) { count += DebugPrintf("()"); } } for (i=count; i<12; i++) { DebugPrintf(" "); } DebugPrintf(" "); switch (Symbol->StorageClass) { case IMAGE_SYM_CLASS_END_OF_FUNCTION : name = "EndOfFunction"; break; case IMAGE_SYM_CLASS_NULL : name = "NoClass"; break; case IMAGE_SYM_CLASS_AUTOMATIC : name = "AutoVar"; break; case IMAGE_SYM_CLASS_EXTERNAL : name = "External"; break; case IMAGE_SYM_CLASS_STATIC : name = "Static"; break; case IMAGE_SYM_CLASS_REGISTER : name = "RegisterVar"; break; case IMAGE_SYM_CLASS_EXTERNAL_DEF : name = "ExternalDef"; break; case IMAGE_SYM_CLASS_LABEL : name = "Label"; break; case IMAGE_SYM_CLASS_UNDEFINED_LABEL : name = "UndefinedLabel"; break; case IMAGE_SYM_CLASS_MEMBER_OF_STRUCT : name = "MemberOfStruct"; break; case IMAGE_SYM_CLASS_ARGUMENT : name = "FunctionArg"; break; case IMAGE_SYM_CLASS_STRUCT_TAG : name = "StructTag"; break; case IMAGE_SYM_CLASS_MEMBER_OF_UNION : name = "MemberOfUnion"; break; case IMAGE_SYM_CLASS_UNION_TAG : name = "UnionTag"; break; case IMAGE_SYM_CLASS_TYPE_DEFINITION : name = "TypeDefinition"; break; case IMAGE_SYM_CLASS_UNDEFINED_STATIC : name = "UndefinedStatic";break; case IMAGE_SYM_CLASS_ENUM_TAG : name = "EnumTag"; break; case IMAGE_SYM_CLASS_MEMBER_OF_ENUM : name = "MemberOfEnum"; break; case IMAGE_SYM_CLASS_REGISTER_PARAM : name = "RegisterParam"; break; case IMAGE_SYM_CLASS_BIT_FIELD : name = "BitField"; break; case IMAGE_SYM_CLASS_BLOCK : switch (Symbol->n_name[1]) { case 'b' : name = "BeginBlock"; break; case 'e' : name = "EndBlock"; break; default : name = name = ".bb or.eb"; } break; case IMAGE_SYM_CLASS_FUNCTION : switch (Symbol->n_name[1]) { case 'b' : name = "BeginFunction"; break; case 'e' : name = "EndFunction"; break; case 'l' : name = "LinesInFunction"; break; default : name = name = ".bf or.ef"; } break; case IMAGE_SYM_CLASS_END_OF_STRUCT : name = "EndOfStruct"; break; case IMAGE_SYM_CLASS_FILE : name = "Filename"; break; case IMAGE_SYM_CLASS_SECTION : name = "Section"; break; case IMAGE_SYM_CLASS_WEAK_EXTERNAL : name = "WeakExternal"; break; default : DebugPrintf("0x%hx ", Symbol->StorageClass); name = "UNKNOWN SYMBOL CLASS"; } DebugPrintf("%s\n", name); } #if 0 VOID DumpAuxSymbolTableEntry ( IN PIMAGE_SYMBOL Symbol, IN PIMAGE_AUX_SYMBOL AuxSymbol, IN PIMAGE_SECTION_HEADER SectionHdrs ) /*++ Routine Description: Prints a auxiliary symbol entry. Arguments: Symbol - Symbol entry. AuxSymbol - Auxiliary symbol entry. Return Value: None. --*/ { SHORT i; PCHAR ae, name; DebugPrintf(" "); switch (Symbol->StorageClass) { case IMAGE_SYM_CLASS_EXTERNAL: DebugPrintf("tag index %08lx size %08lx next function %08lx\n", AuxSymbol->Sym.TagIndex, AuxSymbol->Sym.Misc.TotalSize, AuxSymbol->Sym.FcnAry.Function.PointerToNextFunction); return; case IMAGE_SYM_CLASS_WEAK_EXTERNAL: DebugPrintf("Default index % 8lx",AuxSymbol->Sym.TagIndex); switch (AuxSymbol->Sym.Misc.TotalSize) { case 1 : name = "No"; break; case 2 : name = ""; break; default : name = "Unknown"; } DebugPrintf(", %s library search\n", name); return; case IMAGE_SYM_CLASS_STATIC: if (*Symbol->n_name == '.' || ((Symbol->Type & 0xf) == IMAGE_SYM_TYPE_NULL && AuxSymbol->Section.Length)) { DebugPrintf("Section length % 4lX, #relocs % 4hX, #linenums % 4hX", AuxSymbol->Section.Length, AuxSymbol->Section.NumberOfRelocations, AuxSymbol->Section.NumberOfLinenumbers); if (Symbol->SectionNumber > 0 && (SectionHdrs[Symbol->SectionNumber-1].Characteristics & IMAGE_SCN_LNK_COMDAT)) { DebugPrintf(", checksum % 8lX, selection % 4hX", AuxSymbol->Section.CheckSum, AuxSymbol->Section.Selection); switch (AuxSymbol->Section.Selection) { case IMAGE_COMDAT_SELECT_NODUPLICATES : name = "no duplicates"; break; case IMAGE_COMDAT_SELECT_ANY : name = "any"; break; case IMAGE_COMDAT_SELECT_SAME_SIZE : name = "same size"; break; case IMAGE_COMDAT_SELECT_EXACT_MATCH : name = "exact match"; break; case IMAGE_COMDAT_SELECT_ASSOCIATIVE : name = "associative"; break; default : name = "unknown"; } if (AuxSymbol->Section.Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE) { DebugPrintf(" (pick %s Section %hx)", name, AuxSymbol->Section.Number); } else { DebugPrintf(" (pick %s)", name); } } DebugPrintf("\n"); return; } break; case IMAGE_SYM_CLASS_FILE: if (Symbol->StorageClass == IMAGE_SYM_CLASS_FILE) { DebugPrintf("%-18.18s\n", AuxSymbol->File.Name); return; } break; case IMAGE_SYM_CLASS_STRUCT_TAG: case IMAGE_SYM_CLASS_UNION_TAG: case IMAGE_SYM_CLASS_ENUM_TAG: DebugPrintf("tag index %08lx size %08lx\n", AuxSymbol->Sym.TagIndex, AuxSymbol->Sym.Misc.TotalSize); return; case IMAGE_SYM_CLASS_END_OF_STRUCT: DebugPrintf("tag index %08lx size %08lx\n", AuxSymbol->Sym.TagIndex, AuxSymbol->Sym.Misc.TotalSize); return; case IMAGE_SYM_CLASS_BLOCK: case IMAGE_SYM_CLASS_FUNCTION: DebugPrintf("line# %04hx", AuxSymbol->Sym.Misc.LnSz.Linenumber); if (!strncmp((char *)Symbol->n_name, ".b", 2)) { DebugPrintf(" end %08lx", AuxSymbol->Sym.FcnAry.Function.PointerToNextFunction); } DebugPrintf("\n"); return; } if (ISARY(Symbol->Type)) { DebugPrintf("Array Bounds "); for (i=0; i<4; i++) { if (AuxSymbol->Sym.FcnAry.Array.Dimension[i]) { DebugPrintf("[%04x]", AuxSymbol->Sym.FcnAry.Array.Dimension[i]); } } DebugPrintf("\n"); return; } ae = (PCHAR)AuxSymbol; for (i=1; i<=IMAGE_SIZEOF_AUX_SYMBOL; i++) { DebugPrintf("%1x", (*(PCHAR)ae>>4)&0xf); DebugPrintf("%1x ", (*(PCHAR)ae&0xf)); ae++; } DebugPrintf("\n"); } #endif //0 void LoadCvSymbols( PIMAGE_INFO pImage ) { #define SBUF_SIZE (1024*4) typedef struct _CV_SYMBOL { ULONG addr; ULONG size; LPSTR name; } CV_SYMBOL, *PCV_SYMBOL; PCV_SYMBOL cv; ULONG cvsize; PIMAGE_DEBUG_INFORMATION DebugInfo; OMFSignature *omfSig; OMFDirHeader *omfDirHdr; OMFDirEntry *omfDirEntry; DATASYM32 *dataSym; OMFSymHash *omfSymHash; DWORD i; DWORD j; DWORD k; DWORD addr; DWORD omapaddr; DWORD symbolcount = 0; DWORD ncnt = 0; PIMAGE_SECTION_HEADER sh; PCHAR sbuf; BOOL pass1 = TRUE; ULONG Bias; ULONG OptimizedSymAddr; if (pImage->lpDebugInfo->CodeViewSymbols == NULL) { return; } pImage->fSymbolsLoaded = TRUE; DebugInfo = pImage->lpDebugInfo; pImage->offsetLow = 0xffffffff; pImage->offsetHigh = 0x0; omfSig = (OMFSignature*) pImage->lpDebugInfo->CodeViewSymbols; if ((strncmp( omfSig->Signature, "NB08", 4 ) != 0) && (strncmp( omfSig->Signature, "NB09", 4 ) != 0)) { return; } omfDirHdr = (OMFDirHeader*) ((DWORD)omfSig + (DWORD)omfSig->filepos); omfDirEntry = (OMFDirEntry*) ((DWORD)omfDirHdr + sizeof(OMFDirHeader)); sbuf = ( PCHAR )malloc( SBUF_SIZE ); again: 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; for (k=0,addr=0,sh=pImage->lpDebugInfo->Sections; klpDebugInfo->NumberOfSections; k++, sh++) { if (k+1 == dataSym->seg) { addr = sh->VirtualAddress + (dataSym->off + (ULONG)pImage->lpBaseOfImage); break; } } if (addr) { if (pass1) { symbolcount += 1; } else { cv[symbolcount].addr = addr; cv[symbolcount].size = 0; cv[symbolcount++].name = (PCHAR)dataSym->name; } } j += dataSym->reclen + 2; dataSym = (DATASYM32*) ((DWORD)dataSym + dataSym->reclen + 2); } break; } } if (pass1) { pass1 = FALSE; cvsize = (symbolcount + 1) * sizeof(CV_SYMBOL); cv = ( CV_SYMBOL * )VirtualAlloc( NULL, cvsize, MEM_COMMIT, PAGE_READWRITE ); if (!cv) { return; } symbolcount = 0; goto again; } cv[symbolcount].addr = 0xffffffff; // // calculate the size of each symbol // for (i=0; ifHasOmap) { Bias = 0; OptimizedSymAddr = ConvertOmapFromSrc( cv[i+1].addr, pImage, &Bias ); if (OptimizedSymAddr == 0) { // // No equivalent address // omapaddr = 0; } else if (OptimizedSymAddr != addr) { // // We have successfully converted // omapaddr = OptimizedSymAddr + Bias - (ULONG)pImage->lpBaseOfImage; } InsertOmapSymbol( pImage, omapaddr, addr, cv[i+1].addr, sbuf, &symbolcount ); } else { InsertSymbol( cv[i].addr, sbuf, pImage->index, NULL ); if (cv[i].addr > pImage->offsetHigh) { pImage->offsetHigh = cv[i].addr; } if (cv[i].addr < pImage->offsetLow) { pImage->offsetLow = cv[i].addr; } if (fVerboseOutput && symbolcount % 100 == 0) { DebugPrintf("%s: module \"%s\" loaded %ld symbols\r", DebuggerName, pImage->szImagePath, symbolcount); } } } VirtualFree( cv, cvsize, MEM_DECOMMIT ); free( sbuf ); if (fVerboseOutput) { DebugPrintf("%s: \"%s\" loaded %ld symbols" #if defined(MIPS) || defined(_PPC_) ", %ld functions" #endif " (%08lx-%08lx)\n", DebuggerName, pImage->szImagePath, symbolcount, #if defined(MIPS) || defined(_PPC_) pImage->NumberOfFunctions, #endif pImage->offsetLow, pImage->offsetHigh); } if (fVerboseOutput || !fLazyLoad) { DebugPrintf("%s: loaded symbols for \"%s\"\n", DebuggerName, pImage->szImagePath); } pImage->lpDebugInfo = NULL; UnmapDebugInformation(DebugInfo); } VOID InsertOmapSymbol( PIMAGE_INFO pImage, // image pointer ULONG SymbolValueOmap, // post omap addr (- imagebase) ULONG SymbolValuePreOmap, // post omap addr (+ imagebase) ULONG NextSymbolEntryValue, // next addr - pre-omap (- imagebase) PCHAR lpSymbolName, // symbol name PULONG symbolcount // pointer to the symbol count ) { CHAR chNewSymName[20]; ULONG SymbolValue; DWORD rvaSym; DWORD addrNew; DWORD rva; DWORD rvaTo; DWORD cb; DWORD rvaToNext; POMAP pomap; POMAP pomapFromEnd; POMAPLIST pomaplistHead; POMAPLIST pomaplistNew; POMAPLIST pomaplistPrev; POMAPLIST pomaplistNext; POMAPLIST pomaplistCur; PSYMBOL pNewSymbol = NULL; rvaSym = SymbolValuePreOmap - (DWORD)pImage->lpBaseOfImage; SymbolValue = SymbolValueOmap + (DWORD)pImage->lpBaseOfImage; pomap = GetOmapEntry( SymbolValuePreOmap, pImage ); pomapFromEnd = pImage->rgomapFromSource + pImage->comapFromSrc; pomaplistHead = NULL; // Look for all OMAP entries belonging to SymbolEntry while (pomap && pomap < pomapFromEnd && (pomap->rva < NextSymbolEntryValue)) { if (pomap->rvaTo == 0) { pomap++; continue; } // Allocate and initialize a new entry pomaplistNew = (POMAPLIST) malloc(sizeof(OMAPLIST)); // UNDONE: Chcek for out of memory 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->pomaplistNext; } if (pomaplistPrev == NULL) { // Insert in head position pomaplistHead = pomaplistNew; } else { pomaplistPrev->pomaplistNext = pomaplistNew; } pomaplistNew->pomaplistNext = pomaplistCur; pomap++; } // Insert our top symbol pNewSymbol = InsertSymbol(SymbolValue, lpSymbolName, pImage->index, NULL); if (pNewSymbol) { if (SymbolValue > pImage->offsetHigh) pImage->offsetHigh = SymbolValue; if (SymbolValue < pImage->offsetLow) pImage->offsetLow = SymbolValue; *symbolcount++; if (fVerboseOutput && *symbolcount % 100 == 0) DebugPrintf("%s: module \"%s\" loaded %ld symbols\r", DebuggerName, pImage->szImagePath, *symbolcount); } if (pomaplistHead != NULL) { pomaplistCur = pomaplistHead; pomaplistNext = pomaplistHead->pomaplistNext; // we do have a list while (pomaplistNext != NULL) { DWORD rva = pomaplistCur->omap.rva; DWORD rvaTo = pomaplistCur->omap.rvaTo; DWORD cb = pomaplistCur->cb; DWORD rvaToNext = pomaplistNext->omap.rvaTo; if (rvaToNext == SymbolValueOmap) { // Already inserted above } else if (rvaToNext < (rvaTo + cb + 8)) { // Adjacent to previous range } else { char chNewSymName[20]; DWORD addrNew = (DWORD) pImage->lpBaseOfImage + rvaToNext; sprintf(chNewSymName, "_%04lX", pomaplistNext->omap.rva - rvaSym); pNewSymbol = InsertSymbol(addrNew, lpSymbolName, pImage->index, chNewSymName); if (pNewSymbol) { if (addrNew > pImage->offsetHigh) pImage->offsetHigh = addrNew; if (addrNew < pImage->offsetLow) pImage->offsetLow = addrNew; *symbolcount++; if (fVerboseOutput && *symbolcount % 100 == 0) DebugPrintf("%s: module \"%s\" loaded %ld symbols\r", DebuggerName, pImage->szImagePath, *symbolcount); } } free(pomaplistCur); pomaplistCur = pomaplistNext; pomaplistNext = pomaplistNext->pomaplistNext; } free(pomaplistCur); } }