/** ntsym.c - NT debugger symbolic routines * * Copyright 1990, Microsoft Corporation * * Purpose: * To load and access the program symbolic information. * * Revision History: * * [-] 19-Apr-1990 Richk Created. * *************************************************************************/ #include #include #include #ifndef NT_HOST #include #endif #undef NULL #include "ntsdp.h" #ifdef NT_SAPI #include #include // Taken from NTSDK.C PIMAGE_INFO pImageFromIndex (UCHAR index) { PIMAGE_INFO pImage; pImage = pProcessHead->pImageHead; while (pImage && pImage->index != index) pImage = pImage->pImageNext; return pImage; } // End from NTSDK.C void * _cdecl halloc(long, size_t); void _cdecl hfree(void *); int CV_CLOSE( int handle); int CV_OPEN( char *name, int ignore1, int ignore2); int CV_READ( int handle, void * buffer, unsigned count); int CV_SEEK( int handle, long offset, int origin); long CV_TELL( int handle); void TH_SetupCVfield(PIMAGE_INFO,PFIELD, IMAGE_SYMBOL*,IMAGE_AUX_SYMBOL*); void TH_SetupCVfunction(PIMAGE_INFO,PSYMBOL,PSYMBOL); void TH_SetupCVlocal(PIMAGE_INFO,PLOCAL, IMAGE_SYMBOL*,IMAGE_AUX_SYMBOL*); void TH_SetupCVpublic(PIMAGE_INFO,PSYMBOL,IMAGE_SYMBOL*,IMAGE_AUX_SYMBOL*); void TH_SetupCVstruct(PIMAGE_INFO,PSTRUCT,IMAGE_SYMBOL*,IMAGE_AUX_SYMBOL*); typedef enum { //* Error returns from some SH functions sheNone, sheNoSymbols, sheFutureSymbols, sheMustRelink, sheNotPacked, sheOutOfMemory, sheCorruptOmf, sheFileOpen, //* Last CV compatable SHE error sheBadDirectory } SHE; extern SHE SHerror; ULONG ObjectTableOffset; UINT ObjectTableCount; #else #define CV_OPEN(nam,acc,pro) open(nam,acc,pro); #define CV_READ(hnd,buf,siz) read(hnd, buf, siz); #define CV_SEEK(hnd,off,org) _lseek(hnd,off,org); #define CV_CLOSE(hnd) close(hnd); #define CV_TELL(hnd); tell(hnd); #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 - (char far *)&((type far *)0)->field)) #endif void InitSymContext(PPROCESS_INFO); #ifdef NT_HOST extern BOOL cdecl cmdHandler(ULONG); extern BOOL cdecl waitHandler(ULONG); #else extern BOOLEAN fJmpBuf; void cdecl cmdHandler(void); #endif int CompareSymbolOffset(PNODE, PNODE, PBOOLEAN); int CompareSymbolString(PNODE, PNODE, PBOOLEAN); int CompareSymfileOffset(PNODE, PNODE, PBOOLEAN); int CompareSymfileString(PNODE, PNODE, PBOOLEAN); static PSYMFILE pTempSymfile; #ifdef NT_SAPI SYMBOL symbolMax = { 0,0, { NULL, NULL, NULL }, { NULL, NULL, NULL }, -1L, 0, 0, SYMBOL_TYPE_SYMBOL, NULL, { '\177', '\177', '\0' } }; SYMBOL structMax = { 0,0, { NULL, NULL, NULL }, { NULL, NULL, NULL }, -1L, 0, 0, SYMBOL_TYPE_SYMBOL, NULL, { '\177', '\177', '\0' } }; #else SYMBOL symbolMax = { { NULL, NULL, NULL }, { NULL, NULL, NULL }, -1L, 0, 0, SYMBOL_TYPE_SYMBOL, NULL, { '\177', '\177', '\0' } }; SYMBOL structMax = { { NULL, NULL, NULL }, { NULL, NULL, NULL }, -1L, 0, 0, SYMBOL_TYPE_SYMBOL, NULL, { '\177', '\177', '\0' } }; #endif /* NT_SAPI */ UCHAR stringMax[3] = { '\177', '\177', '\0' }; SYMFILE symfileMax = { { NULL, NULL, NULL }, { NULL, NULL, NULL }, "", stringMax, "", 0, NULL, NULL, 0L, 0L, 0, 0L, 0, 0, NULL, NULL }; BOOLEAN fSourceOnly = FALSE; BOOLEAN fSourceMixed = FALSE; PSYMFILE pSymfileLast; USHORT lineNumberLast; void parseExamine(void); void DeferSymbolLoad(PIMAGE_INFO); void LoadSymbols(PIMAGE_INFO); void PackAuxNameEntry(PUCHAR, ULONG); // TEMP TEMP TEMP void UnloadSymbols(PIMAGE_INFO); void EnsureModuleSymbolsLoaded(CHAR); int EnsureOffsetSymbolsLoaded(ULONG); #ifdef KERNEL PUCHAR GetModuleName(PUCHAR); extern BOOLEAN KdVerbose; #define fVerboseOutput KdVerbose #endif PIMAGE_INFO ParseModuleIndex(void); PIMAGE_INFO GetModuleIndex(PUCHAR); 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 GetSymbol(ULONG, PUCHAR, PULONG); void AddLocalToFunction(PSYMBOL, PUCHAR, ULONG, USHORT, ULONG); void AddFieldToStructure(PSTRUCT, PUCHAR, ULONG ,USHORT, ULONG); PSTRUCT InsertStructure(ULONG, PUCHAR, CHAR); PSYMBOL InsertFunction(PUCHAR, ULONG); //, PSYMBOL); PSYMBOL InsertSymbol(ULONG, PUCHAR, CHAR); PSYMBOL AllocSymbol(ULONG, PUCHAR, CHAR); PSTRUCT GetStructFromValue(ULONG, LONG); void GetBytesFromFrame(PUCHAR, LONG, USHORT); ULONG GetLocalValue(LONG, USHORT, BOOLEAN); BOOLEAN GetLocalFromString(PUCHAR, PULONG); BOOLEAN GetOffsetFromSym(PUCHAR, PULONG, CHAR); BOOLEAN GetOffsetFromString(PUCHAR, PULONG, CHAR); PLINENO GetLinenoFromFilename(PUCHAR, PPSYMFILE, USHORT, CHAR); PLINENO GetCurrentLineno(PPSYMFILE); PLINENO GetLastLineno(PPSYMFILE, PUSHORT); PLINENO GetLinenoFromOffset(PPSYMFILE, ULONG); void GetLinenoString(PUCHAR, ULONG); void GetCurrentMemoryOffsets(PULONG, PULONG); void DeleteSymbol(PSYMBOL); void DeallocSymbol(PSYMBOL); PSYMFILE InsertSymfile(PUCHAR, PUCHAR, PUCHAR, PIMAGE_LINENUMBER, USHORT, ULONG, ULONG, CHAR); PSYMFILE AllocSymfile(PUCHAR, PUCHAR, PUCHAR, PIMAGE_LINENUMBER, USHORT, ULONG, ULONG, CHAR); void DeleteSymfile(PSYMFILE); void DeallocSymfile(PSYMFILE); int ntsdstricmp(PUCHAR, PUCHAR); 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); //#ifndef KERNEL extern int fControlC; //#endif #ifndef MIPS #ifdef KERNEL extern BOOLEAN cdecl _loadds ControlCHandler(void); #endif #endif extern void RemoveDelChar(PUCHAR); extern PIMAGE_INFO pImageFromIndex(UCHAR); extern BOOLEAN fLazyLoad; extern BOOLEAN fPointerExpression; // State transition arrays for comment processing UCHAR WhiteSpace[] = { stStart, stLine, stSlStar, stSlStStar, stSlSlash, stLine, stLine, stLSlStar, stLSlStar, stLSlSlash }; UCHAR Slash[] = { stSlash, stSlSlash, stSlStar, stStart, stSlSlash, stLSlash, stLSlSlash, stLSlStar, stLine, stLSlSlash }; UCHAR Star[] = { stLine, stSlStar, stSlStStar, stSlStStar, stSlSlash, stLine, stLSlStar, stLSlStStar, stSlStStar, stLSlSlash }; UCHAR Pound[] = { stSlSlash, stLine, stSlStar, stSlStar, stSlSlash, stLine, stLine, stLSlStar, stLSlStar, stLSlSlash }; UCHAR OtherChar[] = { stLine, stLine, stSlStar, stSlStar, stSlSlash, stLine, stLine, stLSlStar, stLSlStar, stLSlSlash }; UCHAR Return[] = { stStart, stStart, stSlStar, stSlStar, stStart, stStart, stStart, stSlStar, stSlStar, stStart }; UCHAR fCommentType[] = { TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE }; //////////////////////////////////////////////////////////////// void InitSymContext (PPROCESS_INFO 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 DeferSymbolLoad (PIMAGE_INFO pImage) { #ifndef KERNEL HANDLE hMapping; PVOID lpFileBase; PIMAGE_EXPORT_DIRECTORY lpExportDir; PIMAGE_DEBUG_DIRECTORY lpDebugDir; PIMAGE_DEBUG_INFO lpDebugInfo; PIMAGE_SYMBOL lpSymbolEntry; PUCHAR lpModName; PUCHAR pszName = NULL; ULONG exportSize; ULONG debugSize; ULONG symsize; ULONG auxcount; ULONG rva; PUCHAR pPathname; PUCHAR pchName; // open file and process enough to get the image name if (!(hMapping = CreateFileMapping(pImage->hFile, NULL, PAGE_READONLY, 0L, 0L, NULL))) return; if (!(lpFileBase = MapViewOfFile(hMapping, FILE_MAP_READ, 0L, 0L, 0L))) { CloseHandle(hMapping); return; } pszName = malloc(32); if (!pszName) { printf("memory allocation error\n"); ExitProcess(STATUS_UNSUCCESSFUL); } if (pImage->index != 0) { rva = (ULONG)RtlImageDirectoryEntryToData(lpFileBase, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &exportSize); rva -= (ULONG)lpFileBase; lpExportDir = (PIMAGE_EXPORT_DIRECTORY)RtlImageDirectoryEntryToData( lpFileBase, FALSE, IMAGE_DIRECTORY_ENTRY_EXPORT, &exportSize); if (lpExportDir) { lpModName = (PUCHAR)((ULONG)lpExportDir + (ULONG)lpExportDir->Name - rva); strncpy(pszName, lpModName, 31); *(pszName + strcspn(pszName, ".")) = '\0'; } else strcpy(pszName, "unknown"); } else { strcpy(pszName, "app"); // try to name the main image using the first symbol table // entry which contains the path of the first file in it. symsize = IMAGE_SIZEOF_SYMBOL; lpDebugDir = (PIMAGE_DEBUG_DIRECTORY)RtlImageDirectoryEntryToData( lpFileBase, FALSE, IMAGE_DIRECTORY_ENTRY_DEBUG, &debugSize); if (lpDebugDir) { lpDebugInfo = (PIMAGE_DEBUG_INFO)((ULONG)lpFileBase + lpDebugDir->PointerToRawData); lpSymbolEntry = (PIMAGE_SYMBOL)((ULONG)lpDebugInfo + lpDebugInfo->LvaToFirstSymbol); auxcount = lpSymbolEntry->NumberOfAuxSymbols; if (lpSymbolEntry->StorageClass == IMAGE_SYM_CLASS_FILE) { lpSymbolEntry = (PIMAGE_SYMBOL) ((PUCHAR)lpSymbolEntry + symsize); // allocate and copy the pathname from the following // auxiliary entries. pPathname = malloc((int)(auxcount * symsize + 1)); if (!pPathname) { printf("memory allocation error\n"); ExitProcess(STATUS_UNSUCCESSFUL); } memcpy(pPathname, lpSymbolEntry, (int)(auxcount * symsize)); // TEMP TEMP TEMP - pack entries 14/18 chars into string // PackAuxNameEntry(pPathname, auxcount); *(pPathname + auxcount * symsize) = '\0'; // TEMP TEMP TEMP // extract the filename from the pathname as the string // following the last '\' or ':', but not including any // characters after '.'. pchName = strrchr(pPathname, '\\'); if (!pchName) pchName = strrchr(pPathname, ':'); if (!pchName) pchName = pPathname; else pchName++; *(pchName + strcspn(pchName, ".")) = '\0'; strcpy(pszName, pchName); free(pPathname); } } } pImage->pszName = pszName; if (fVerboseOutput) dprintf("NTSD: deferring symbol load for \"%s\"\n", pImage->pszName); UnmapViewOfFile(lpFileBase); CloseHandle(hMapping); #else int ImageReadHandle; IMAGE_OPTIONAL_HEADER coffOptionalHeader; USHORT Signature; ULONG DosHeader[16], NtSignature; if (fVerboseOutput) dprintf("KD: deferring symbol load for \"%s\"\n", pImage->pszName); if (pImage->lpBaseOfImage == (PVOID)-1L){ #ifdef NT_SAPI SHerror = sheNone; ImageReadHandle = (int)pImage->hQCFile; #else ImageReadHandle = CV_OPEN(pImage->pszName, O_RDONLY|O_BINARY, 0); if (ImageReadHandle < 0) return; #endif /* NT_SAPI */ CV_READ(ImageReadHandle, &Signature, sizeof(USHORT)); CV_SEEK(ImageReadHandle, 0, SEEK_SET); if (Signature == IMAGE_DOS_SIGNATURE) { CV_READ(ImageReadHandle, &DosHeader, 16*sizeof(ULONG)); CV_SEEK(ImageReadHandle, DosHeader[15], SEEK_SET); CV_READ(ImageReadHandle, &NtSignature, sizeof(ULONG)); if (NtSignature != IMAGE_NT_SIGNATURE) { #ifdef NT_SAPI SHerror = sheCorruptOmf; #else dprintf("\nPE signature not found\n"); #endif } } CV_SEEK(ImageReadHandle, (ULONG)sizeof(IMAGE_FILE_HEADER), SEEK_CUR); CV_READ(ImageReadHandle, &coffOptionalHeader, sizeof(IMAGE_OPTIONAL_HEADER)); #ifndef NT_SAPI CV_CLOSE(ImageReadHandle); #endif pImage->lpBaseOfImage = (LPVOID)coffOptionalHeader.ImageBase; if (fVerboseOutput) dprintf("KD: Kernel image at %08lx\n", pImage->lpBaseOfImage); } #endif } #ifndef KERNEL BOOLEAN CountLinenumbers(PIMAGE_INFO pImage) { HANDLE hMapping; PVOID lpFileBase; PIMAGE_EXPORT_DIRECTORY lpExportDir; PIMAGE_DEBUG_DIRECTORY lpDebugDir; PIMAGE_DEBUG_INFO lpDebugInfo; PIMAGE_SYMBOL lpSymbolEntry; IMAGE_SYMBOL SymbolEntry; IMAGE_AUX_SYMBOL AuxSymbolEntry; PIMAGE_LINENUMBER lpPointerToLinenumbers; PIMAGE_LINENUMBER lpEndPointerToLinenumbers; PUCHAR lpStringTable; UCHAR ShortString[10]; ULONG exportSize; ULONG debugSize; ULONG symsize; ULONG index; ULONG auxcount; ULONG symbolcount = 0; ULONG entrycount; PSYMBOL pCurrentFunction = NULL; PSTRUCT pCurrentStructure = NULL; #ifdef MIPS PRUNTIME_FUNCTION lpRuntimeFunction; PFUNCTION_ENTRY lpFunctionTable; ULONG pdataSize = 0L; ULONG cFunctions = 0; #endif PUCHAR pszName = NULL; PUCHAR pPathname = NULL; PUCHAR pFilename = NULL; PUCHAR pExtension = NULL; PIMAGE_LINENUMBER pLinenumbers = NULL; BOOLEAN nameFound = FALSE; BOOLEAN invalidOMF = FALSE; ULONG NumberOfLinenumbers; ULONG cLines=0L; ShortString[8] = '\0'; if (!(hMapping = CreateFileMapping(pImage->hFile, NULL, PAGE_READONLY, 0L, 0L, NULL))) return FALSE; if (!(lpFileBase = MapViewOfFile(hMapping, FILE_MAP_READ, 0L, 0L, 0L))) { CloseHandle(hMapping); return FALSE; } if (pImage->index != 0) { lpExportDir = (PIMAGE_EXPORT_DIRECTORY)RtlImageDirectoryEntryToData( lpFileBase, FALSE, IMAGE_DIRECTORY_ENTRY_EXPORT, &exportSize); } else lpExportDir = NULL; pImage->offsetLow = 0xffffffff; pImage->offsetHigh = 0x0; symsize = IMAGE_SIZEOF_SYMBOL; lpDebugDir = (PIMAGE_DEBUG_DIRECTORY)RtlImageDirectoryEntryToData( lpFileBase, FALSE, IMAGE_DIRECTORY_ENTRY_DEBUG, &debugSize); // if no debug information, just return TRUE if (!lpDebugDir) { UnmapViewOfFile(hMapping); CloseHandle(hMapping); return TRUE; } lpDebugInfo = (PIMAGE_DEBUG_INFO)((ULONG)lpFileBase + lpDebugDir->PointerToRawData); lpPointerToLinenumbers = (PIMAGE_LINENUMBER)((ULONG)lpDebugInfo + + lpDebugInfo->LvaToFirstLinenumber); // dprintf("Correct # of lines = %ld\n", // NumberOfLinenumbers = lpDebugInfo->NumberOfLinenumbers); NumberOfLinenumbers = lpDebugInfo->NumberOfLinenumbers; lpSymbolEntry = (PIMAGE_SYMBOL)((ULONG)lpDebugInfo + lpDebugInfo->LvaToFirstSymbol); // PDK KLUDGE ::: lpEndPointerToLinenumbers = (PIMAGE_LINENUMBER)lpSymbolEntry; lpStringTable = (PUCHAR)((ULONG)lpDebugInfo + lpDebugInfo->LvaToFirstSymbol + lpDebugInfo->NumberOfSymbols * symsize); for (entrycount = 0; entrycount < lpDebugInfo->NumberOfSymbols; entrycount++) { memcpy((PUCHAR)&SymbolEntry, lpSymbolEntry, symsize); lpSymbolEntry = (PIMAGE_SYMBOL)((PUCHAR)lpSymbolEntry + symsize); auxcount = SymbolEntry.NumberOfAuxSymbols; switch (SymbolEntry.StorageClass) { case IMAGE_SYM_CLASS_STATIC: if (SymbolEntry.SectionNumber > 0 && SymbolEntry.Type == IMAGE_SYM_TYPE_NULL && auxcount == 1) { index = SymbolEntry.SectionNumber - 1; memcpy((PUCHAR)&AuxSymbolEntry, lpSymbolEntry, symsize); if (AuxSymbolEntry.Section.Length && AuxSymbolEntry.Section.NumberOfLinenumbers) { cLines += (int)AuxSymbolEntry.Section.NumberOfLinenumbers; } } // else // dprintf("STATIC class entry\n"); 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); } // dprintf("Actual # of lines = %ld\n", cLines); UnmapViewOfFile(hMapping); CloseHandle(hMapping); return ((BOOLEAN)(cLines == NumberOfLinenumbers)); } void LoadSymbols (PIMAGE_INFO pImage) { HANDLE hMapping; PVOID lpFileBase; PIMAGE_EXPORT_DIRECTORY lpExportDir; PIMAGE_DEBUG_DIRECTORY lpDebugDir; PIMAGE_DEBUG_INFO lpDebugInfo; PIMAGE_SYMBOL lpSymbolEntry; IMAGE_SYMBOL SymbolEntry; IMAGE_AUX_SYMBOL AuxSymbolEntry; PIMAGE_LINENUMBER lpPointerToLinenumbers; PIMAGE_LINENUMBER lpEndPointerToLinenumbers; IMAGE_LINENUMBER LineNumber; PUCHAR lpStringTable; PUCHAR lpSymbolName; UCHAR ShortString[10]; ULONG exportSize; ULONG debugSize; ULONG symsize; ULONG index; ULONG ind; ULONG auxcount; ULONG symbolcount = 0; ULONG entrycount; ULONG SymbolValue; ULONG rva; PSYMBOL pNewSymbol = NULL; PSYMBOL pCurrentFunction = NULL; PSTRUCT pCurrentStructure = NULL; PULONG pAddrName; #ifdef MIPS PRUNTIME_FUNCTION lpRuntimeFunction; PFUNCTION_ENTRY lpFunctionTable; ULONG pdataSize = 0L; ULONG cFunctions = 0; #endif PUCHAR pszName = NULL; PUCHAR pPathname = NULL; PUCHAR pFilename = NULL; PUCHAR pExtension = NULL; PIMAGE_LINENUMBER pLinenumbers = NULL; PIMAGE_LINENUMBER pLinenumberNext; PUCHAR pchName; int cName; BOOLEAN nameFound = FALSE; BOOLEAN invalidOMF = FALSE; BOOLEAN validLinenumbers; validLinenumbers = CountLinenumbers(pImage); if (!validLinenumbers) { dprintf("NTSD: Line count mismatch in %s. Disabling source debugging\n",pImage->pszName); // CloseHandle(pImage->hFile); // return; } ShortString[8] = '\0'; if (!(hMapping = CreateFileMapping(pImage->hFile, NULL, PAGE_READONLY, 0L, 0L, NULL))) return; if (!(lpFileBase = MapViewOfFile(hMapping, FILE_MAP_READ, 0L, 0L, 0L))) { CloseHandle(hMapping); CloseHandle(pImage->hFile); return; } #ifdef MIPS lpRuntimeFunction = (PRUNTIME_FUNCTION)RtlImageDirectoryEntryToData( lpFileBase, FALSE, IMAGE_DIRECTORY_ENTRY_EXCEPTION, &pdataSize); if (lpRuntimeFunction) { cFunctions = pdataSize / sizeof(RUNTIME_FUNCTION); pImage->LowAddress = MAXULONG; pImage->HighAddress = 0; lpFunctionTable = (PFUNCTION_ENTRY) malloc((int)(cFunctions * sizeof(FUNCTION_ENTRY))); if (!lpFunctionTable) { dprintf("NTSD: alloc error for exception table\n"); exit(1); } pImage->FunctionTable = lpFunctionTable; pImage->LowAddress = MAXULONG; pImage->HighAddress = 0; for (index = 0; index < cFunctions; index++) { if (lpRuntimeFunction->BeginAddress == 0) break; lpFunctionTable->StartingAddress = lpRuntimeFunction->BeginAddress; if (lpRuntimeFunction->BeginAddress < pImage->LowAddress) pImage->LowAddress = lpRuntimeFunction->BeginAddress; lpFunctionTable->EndingAddress = lpRuntimeFunction->EndAddress; if (lpRuntimeFunction->EndAddress > pImage->HighAddress) pImage->HighAddress = lpRuntimeFunction->EndAddress; lpFunctionTable->EndOfPrologue = lpRuntimeFunction->PrologEndAddress; lpRuntimeFunction++; lpFunctionTable++; } } pImage->NumberOfFunctions = cFunctions; #endif if (pImage->index != 0) { rva = (ULONG)RtlImageDirectoryEntryToData(lpFileBase, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &exportSize); rva -= (ULONG)lpFileBase; lpExportDir = (PIMAGE_EXPORT_DIRECTORY)RtlImageDirectoryEntryToData( lpFileBase, FALSE, IMAGE_DIRECTORY_ENTRY_EXPORT, &exportSize); } else lpExportDir = NULL; pImage->offsetLow = 0xffffffff; pImage->offsetHigh = 0x0; symsize = IMAGE_SIZEOF_SYMBOL; lpDebugDir = (PIMAGE_DEBUG_DIRECTORY)RtlImageDirectoryEntryToData( lpFileBase, FALSE, IMAGE_DIRECTORY_ENTRY_DEBUG, &debugSize); // if no debug information, just close and return if (!lpDebugDir) { CloseHandle(hMapping); CloseHandle(pImage->hFile); return; } lpDebugInfo = (PIMAGE_DEBUG_INFO)((ULONG)lpFileBase + lpDebugDir->PointerToRawData); lpPointerToLinenumbers = (PIMAGE_LINENUMBER)((ULONG)lpDebugInfo + lpDebugInfo->LvaToFirstLinenumber); lpSymbolEntry = (PIMAGE_SYMBOL)((ULONG)lpDebugInfo + lpDebugInfo->LvaToFirstSymbol); // PDK KLUDGE ::: lpEndPointerToLinenumbers = (PIMAGE_LINENUMBER)lpSymbolEntry; lpStringTable = (PUCHAR)((ULONG)lpDebugInfo + lpDebugInfo->LvaToFirstSymbol + lpDebugInfo->NumberOfSymbols * symsize); // dprintf("# lines %lx, # sys %lx\n", lpDebugInfo->NumberOfLinenumbers, lpDebugInfo->NumberOfSymbols); for (entrycount = 0; entrycount < lpDebugInfo->NumberOfSymbols; entrycount++) { memcpy((PUCHAR)&SymbolEntry, lpSymbolEntry, symsize); lpSymbolEntry = (PIMAGE_SYMBOL)((PUCHAR)lpSymbolEntry + symsize); auxcount = SymbolEntry.NumberOfAuxSymbols; switch (SymbolEntry.StorageClass) { case IMAGE_SYM_CLASS_FILE: // allocate and copy the pathname from the following // auxiliary entries. pPathname = realloc(pPathname, (int)(auxcount * symsize + 1)); memcpy(pPathname, lpSymbolEntry, (int)(auxcount * symsize)); // TEMP TEMP TEMP - pack entries 14/18 chars into string // PackAuxNameEntry(pPathname, auxcount); *(pPathname + auxcount * symsize) = '\0'; // TEMP TEMP TEMP // extract the filename from the pathname as the string // following the last '\' or ':', but not including any // characters after '.'. pchName = strrchr(pPathname, '\\'); if (!pchName) pchName = strrchr(pPathname, ':'); if (!pchName) pchName = pPathname; else pchName++; cName = strcspn(pchName, "."); // allocate a string and copy the filename part of the // path and convert to lower case. pFilename = realloc(pFilename, cName + 1); strncpy(pFilename, pchName, cName); *(pFilename + cName) = '\0'; _strlwr(pFilename); // allocate a string and copy the extension part of the // path, if any, and convert to lower case. pExtension = realloc(pExtension, strlen(pchName + cName) + 1); strcpy(pExtension, pchName + cName); _strlwr(pExtension); // 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 == pPathname) { *pchName++ = '.'; *pchName++ = '\\'; } *pchName = '\0'; 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, lpSymbolEntry, symsize); if (AuxSymbolEntry.Section.Length && AuxSymbolEntry.Section.NumberOfLinenumbers) { // PDK KLUDGE ::: if (((PIMAGE_LINENUMBER) ((PUCHAR)lpPointerToLinenumbers+ IMAGE_SIZEOF_LINENUMBER * (int)AuxSymbolEntry.Section.NumberOfLinenumbers) >= lpEndPointerToLinenumbers) || invalidOMF) { invalidOMF = TRUE; if (fVerboseOutput) dprintf("Invalid OMF in %s (%s%s)" "-- invalidating rest of image\n", pImage->pszName, pFilename, pExtension); } if (!invalidOMF){ pLinenumbers = (PIMAGE_LINENUMBER)realloc((PUCHAR)pLinenumbers, IMAGE_SIZEOF_LINENUMBER * (int)AuxSymbolEntry.Section.NumberOfLinenumbers); pLinenumberNext = pLinenumbers; for (ind = 0; ind < AuxSymbolEntry.Section.NumberOfLinenumbers; ind++) { memcpy((PUCHAR)&LineNumber, (PUCHAR)lpPointerToLinenumbers, IMAGE_SIZEOF_LINENUMBER); 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); } ////////// // memcpy((PUCHAR)pLinenumbers, // (PUCHAR)(lpPointerToLinenumbers), // IMAGE_SIZEOF_LINENUMBER // * (int)AuxSymbolEntry.Section.NumberOfLinenumbers); // // for (ind = 0; ind < AuxSymbolEntry.Section.NumberOfLinenumbers; // ind++) // ((PIMAGE_LINENUMBER)((PUCHAR)pLinenumbers // + IMAGE_SIZEOF_LINENUMBER * ind))-> // Type.VirtualAddress += // (ULONG)pImage->lpBaseOfImage; // // lpPointerToLinenumbers = (PIMAGE_LINENUMBER) // ((PUCHAR)lpPointerToLinenumbers // + IMAGE_SIZEOF_LINENUMBER // * AuxSymbolEntry.Section.NumberOfLinenumbers); /////////// } InsertSymfile(pPathname, pFilename, pExtension, (PIMAGE_LINENUMBER)(invalidOMF ? NULL : pLinenumbers), (USHORT)(invalidOMF ? 0 : AuxSymbolEntry.Section.NumberOfLinenumbers), SymbolEntry.Value + (ULONG)pImage->lpBaseOfImage, SymbolEntry.Value + (ULONG)pImage->lpBaseOfImage + AuxSymbolEntry.Section.Length, pImage->index); #if 0 dprintf("\npath: <%s> file: <%s> ext: <%s> " "start: %08lx end: %08lx\n", pPathname, pFilename, pExtension, SymbolEntry.Value + (ULONG)pImage->lpBaseOfImage, SymbolEntry.Value + (ULONG)pImage->lpBaseOfImage + AuxSymbolEntry.Section.Length); dprintf("section %ld - length: %lx " "line number cnt: %d\n", index, AuxSymbolEntry.Section.Length, AuxSymbolEntry.Section.NumberOfLinenumbers); for (index = 0; index < AuxSymbolEntry.Section.NumberOfLinenumbers; index++) dprintf("index %ld, address: %08lx, " "line number %d\n", index, ((PIMAGE_LINENUMBER)((PUCHAR)pLinenumbers + index * IMAGE_SIZEOF_LINENUMBER))-> Type.VirtualAddress, ((PIMAGE_LINENUMBER)((PUCHAR)pLinenumbers + index * IMAGE_SIZEOF_LINENUMBER))-> Linenumber); #endif } } // else // dprintf("STATIC class entry\n"); break; case IMAGE_SYM_CLASS_FUNCTION: if (SymbolEntry.N.Name.Short) { strncpy(ShortString, SymbolEntry.N.ShortName, 8); ShortString[8] = '\0'; lpSymbolName = ShortString; } else lpSymbolName = lpStringTable + SymbolEntry.N.Name.Long; if (SymbolEntry.Value && pNewSymbol) { SymbolValue = SymbolEntry.Value + (ULONG)pImage->lpBaseOfImage; // dprintf("[FUNCTION:%s, val=%08lx, ",pNewSymbol->string, // pNewSymbol->offset); pCurrentFunction = InsertFunction(pNewSymbol->string, pNewSymbol->offset); // dprintf(pCurrentFunction ? "Inserted]\n" // : "Insertion failed]\n"); } break; case IMAGE_SYM_CLASS_AUTOMATIC: case IMAGE_SYM_CLASS_ARGUMENT: case IMAGE_SYM_CLASS_REGISTER: case IMAGE_SYM_CLASS_MEMBER_OF_STRUCT:{ ULONG auxValue; if (SymbolEntry.N.Name.Short) { strncpy(ShortString, SymbolEntry.N.ShortName, 8); ShortString[8] = '\0'; lpSymbolName = ShortString; } else{ if (!SymbolEntry.N.Name.Long) break; lpSymbolName = lpStringTable + SymbolEntry.N.Name.Long; } SymbolValue = SymbolEntry.Value; if (SymbolEntry.Type==IMAGE_SYM_TYPE_STRUCT){ if (!auxcount) break; // Error in COFF auxValue = *((PULONG)lpSymbolEntry); } if(SymbolEntry.StorageClass!=IMAGE_SYM_CLASS_MEMBER_OF_STRUCT){ // dprintf("\t[LOCAL:%s, value=%ld, aux=%lx]\n", // lpSymbolName, SymbolValue, auxValue); AddLocalToFunction(pCurrentFunction, lpSymbolName, SymbolValue, SymbolEntry.Type, auxValue); } else{ // dprintf("\t[FIELD:%s, type=%ld, value=%ld, aux=%lx]\n", // lpSymbolName, SymbolEntry.Type, SymbolValue, // auxValue); AddFieldToStructure(pCurrentStructure, lpSymbolName, SymbolValue,SymbolEntry.Type, auxValue); } } break; case IMAGE_SYM_CLASS_STRUCT_TAG: if (SymbolEntry.N.Name.Short) { strncpy(ShortString, SymbolEntry.N.ShortName, 8); ShortString[8] = '\0'; lpSymbolName = ShortString; } else lpSymbolName = lpStringTable + SymbolEntry.N.Name.Long; //dprintf("[STRUCT#%ld:%s \n",entrycount, lpSymbolName); pCurrentStructure = InsertStructure(entrycount, lpSymbolName, pImage->index); //dprintf(pCurrentStructure?"Inserted]\n":"Insertion failed]\n"); break; case IMAGE_SYM_CLASS_EXTERNAL: if (SymbolEntry.N.Name.Short) { strncpy(ShortString, SymbolEntry.N.ShortName, 8); ShortString[8] = '\0'; lpSymbolName = ShortString; } else lpSymbolName = lpStringTable + SymbolEntry.N.Name.Long; if (SymbolEntry.Value) { SymbolValue = SymbolEntry.Value + (ULONG)pImage->lpBaseOfImage; // dprintf("sym %s value %lx entryc %lx\n", lpSymbolName, SymbolValue, entrycount); pNewSymbol = InsertSymbol(SymbolValue, lpSymbolName, pImage->index); if (pNewSymbol) { if (SymbolValue > pImage->offsetHigh) pImage->offsetHigh = SymbolValue; if (SymbolValue < pImage->offsetLow) pImage->offsetLow = SymbolValue; symbolcount++; if (fVerboseOutput && symbolcount % 100 == 0) dprintf("NTSD: module \"%s\" loaded " "%ld symbols\r", pszName, symbolcount); } } break; default: // dprintf("OTHER class entry - class: %d\n", // SymbolEntry.StorageClass); 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); } if (fVerboseOutput) #ifdef MIPS dprintf("NTSD: \"%s\" loaded %ld symbols, " "%ld functions (%08lx-%08lx)\n", pImage->pszName, symbolcount, pImage->NumberOfFunctions, pImage->offsetLow, pImage->offsetHigh); #else dprintf("NTSD: \"%s\" loaded %ld symbols (%08lx-%08lx)\n", pImage->pszName, symbolcount, pImage->offsetLow, pImage->offsetHigh); #endif if (fVerboseOutput || !fLazyLoad) dprintf("NTSD: loading symbols for \"%s\"\n", pImage->pszName); if (lpExportDir) { ULONG offset; PSYMBOL pSymbol; entrycount= lpExportDir->NumberOfNames; pAddrName = (PULONG)((ULONG)lpExportDir + (ULONG)lpExportDir->AddressOfNames - rva); for (index = 0; index < entrycount; index++) { pszName = (PUCHAR)((ULONG)lpExportDir + *pAddrName++ - rva); //dprintf("\t%ld:%s\n", index, pszName); if (GetOffsetFromString(pszName, &offset, pImage->index)) { pSymbol = PNODE_TO_PSYMBOL (pProcessCurrent->symcontextSymbolString.pNodeRoot, &(pProcessCurrent->symcontextSymbolString)); pSymbol->type = SYMBOL_TYPE_EXPORT; } else dprintf("NTSD: error exporting non-existent symbol\n"); } } // free pointers to reallocated strings free(pExtension); free(pFilename); free(pPathname); free(pLinenumbers); UnmapViewOfFile(hMapping); CloseHandle(hMapping); CloseHandle(pImage->hFile); } #endif #ifdef KERNEL void LoadSymbols (PIMAGE_INFO pImage) { PSZ SymbolName; ULONG entrycount; ULONG auxcount; ULONG SymbolValue; UCHAR ShortString[10]; IMAGE_SYMBOL SymbolEntry; IMAGE_AUX_SYMBOL AuxSymbolEntry; #ifdef MIPS RUNTIME_FUNCTION RuntimeFunction; PFUNCTION_ENTRY lpFunctionEntry; ULONG pdataSize = 0L; ULONG pdataStart; ULONG cFunctions = 0; ULONG junk; #endif ULONG StringTableSize; char huge * StringTable = NULL; ULONG Base; ULONG HdrBase; ULONG BaseOffset = 0; int symsize; int ImageReadHandle; PUCHAR pszName; PSYMBOL pNewSymbol = NULL; PSYMBOL pCurrentFunction = NULL; PSTRUCT pCurrentStructure = NULL; ULONG symbolcount = 0; ULONG index; ULONG ind; PUCHAR pPathname = NULL; PUCHAR pFilename = NULL; PUCHAR pExtension = NULL; ULONG pNextLinenumber; ULONG debugSize; IMAGE_DEBUG_DIRECTORY DebugDir; IMAGE_DEBUG_INFO DebugInfo; ULONG StartDebugInfo; PIMAGE_LINENUMBER pLinenumbers = NULL; PUCHAR pchName; int cName; ULONG seekSave; unsigned int n; unsigned int maxr; unsigned long needr; char huge * p; char buff[128]; #ifdef NT_SAPI SHerror = sheNone; ImageReadHandle = pImage->hQCFile; if ( pImage->IgnoreSymbols ) { SHerror = sheNoSymbols; return; } #else ImageReadHandle = CV_OPEN(pImage->pszName, O_RDONLY | O_BINARY, 0); if (ImageReadHandle < 0) return; #endif /* NT_SAPI */ if (fLazyLoad && fVerboseOutput) dprintf("KD: Loading \"%s\" (previously deferred)\n", pImage->pszName); seekSave = (ULONG)FetchImageDirectoryEntry(ImageReadHandle, IMAGE_DIRECTORY_ENTRY_DEBUG, &debugSize, &HdrBase); if (!seekSave) { #ifdef NT_SAPI SHerror = sheBadDirectory; #endif return; } CV_SEEK(ImageReadHandle, seekSave, SEEK_SET); CV_READ(ImageReadHandle, &DebugDir, sizeof(IMAGE_DEBUG_DIRECTORY)); StartDebugInfo = DebugDir.PointerToRawData; CV_SEEK(ImageReadHandle, StartDebugInfo, SEEK_SET); CV_READ(ImageReadHandle, &DebugInfo, sizeof(IMAGE_DEBUG_INFO)); pNextLinenumber = (StartDebugInfo + DebugInfo.LvaToFirstLinenumber); #ifdef MIPS if (pdataSize == 0) { pdataStart = (ULONG)FetchImageDirectoryEntry(ImageReadHandle, IMAGE_DIRECTORY_ENTRY_EXCEPTION, &pdataSize, &junk); } #endif if (HdrBase) { if (pImage->lpBaseOfImage) { Base = (ULONG)pImage->lpBaseOfImage; } else { Base = HdrBase; } } BaseOffset = Base - HdrBase; #ifdef MIPS if (pdataSize) { cFunctions = pdataSize / sizeof(RUNTIME_FUNCTION); lpFunctionEntry = (PFUNCTION_ENTRY) malloc((int)(cFunctions * sizeof(FUNCTION_ENTRY))); if (!lpFunctionEntry) { dprintf("KD: alloc error for exception table\n"); exit(1); } pImage->FunctionTable = lpFunctionEntry; pImage->LowAddress = MAXULONG; pImage->HighAddress = 0; CV_SEEK(ImageReadHandle, pdataStart, SEEK_SET); for (index = 0; index < cFunctions; index++) { CV_READ(ImageReadHandle, (PUCHAR)&RuntimeFunction, sizeof(RUNTIME_FUNCTION)); if (RuntimeFunction.BeginAddress == 0) break; // // Update the addresses with the new base address for the image. // RuntimeFunction.BeginAddress += BaseOffset; RuntimeFunction.PrologEndAddress += BaseOffset; RuntimeFunction.EndAddress += BaseOffset; lpFunctionEntry[index].StartingAddress = RuntimeFunction.BeginAddress; if (RuntimeFunction.BeginAddress < pImage->LowAddress) pImage->LowAddress = RuntimeFunction.BeginAddress; lpFunctionEntry[index].EndingAddress = RuntimeFunction.EndAddress; if (RuntimeFunction.EndAddress > pImage->HighAddress) pImage->HighAddress = RuntimeFunction.EndAddress; lpFunctionEntry[index].EndOfPrologue = RuntimeFunction.PrologEndAddress; } } pImage->NumberOfFunctions = cFunctions; #endif symsize = IMAGE_SIZEOF_SYMBOL; CV_SEEK(ImageReadHandle, StartDebugInfo + DebugInfo.LvaToFirstSymbol + DebugInfo.NumberOfSymbols * symsize, SEEK_SET); CV_READ(ImageReadHandle, (PUCHAR)&StringTableSize, sizeof(ULONG)); if (StringTableSize > sizeof(ULONG)) { #ifdef NT_HOST // BUGBUG - W-Barry - 30-Apr-91 - Replacing call to halloc with a call // to calloc. Halloc seems to be no longer in the 32-bit libraries. if (!(StringTable = (PUCHAR)calloc(StringTableSize, 1))) { #else if (!(StringTable = (PUCHAR)halloc(StringTableSize, 1))) { #endif #ifdef NT_SAPI SHerror = sheOutOfMemory; return; #else dprintf("KD: alloc error for string table\n"); exit(1); #endif } needr = StringTableSize - sizeof(ULONG); p = StringTable; while (needr) { maxr = (unsigned int)min(needr, 0x8000); n = CV_READ(ImageReadHandle, (char far *)p, maxr); p += n; needr -= n; } StringTable -= sizeof(ULONG); } // convert the name from the full path to only the filename pszName = GetModuleName(pImage->pszName); free(pImage->pszName); // remove entry pathname pImage->pszName = pszName; pImage->offsetLow = 0xffffffff; pImage->offsetHigh = 0x0; // seek to start of symbol table and read each entry CV_SEEK(ImageReadHandle, StartDebugInfo + DebugInfo.LvaToFirstSymbol, SEEK_SET); for (entrycount = 0; entrycount < DebugInfo.NumberOfSymbols; entrycount++) { CV_READ(ImageReadHandle, (PUCHAR)&SymbolEntry, symsize); auxcount = SymbolEntry.NumberOfAuxSymbols; switch (SymbolEntry.StorageClass) { case IMAGE_SYM_CLASS_FILE: // allocate and read the pathname from the following // auxiliary entries. pPathname = realloc(pPathname, (int)(auxcount * symsize + 1)); CV_READ(ImageReadHandle, pPathname, (int)(auxcount * symsize)); // TEMP TEMP TEMP - pack entries 14/18 chars into string // PackAuxNameEntry(pPathname, auxcount); *(pPathname + auxcount * symsize) = '\0'; // TEMP TEMP TEMP entrycount += auxcount; auxcount = 0; // extract the filename from the pathname as the string // following the last '\' or ':', but not including any // characters after '.'. pchName = strrchr(pPathname, '\\'); if (!pchName) pchName = strrchr(pPathname, ':'); if (!pchName) pchName = pPathname; else pchName++; cName = strcspn(pchName, "."); // allocate a string and copy the filename part of the // path and convert to lower case. pFilename = realloc(pFilename, cName + 1); strncpy(pFilename, pchName, cName); *(pFilename + cName) = '\0'; _strlwr(pFilename); // allocate a string and copy the extension part of the // path, if any, and convert to lower case. pExtension = realloc(pExtension, strlen(pchName + cName) + 1); strcpy(pExtension, pchName + cName); _strlwr(pExtension); // 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 == pPathname) { *pchName++ = '.'; *pchName++ = '\\'; } *pchName = '\0'; break; case IMAGE_SYM_CLASS_STATIC: if ( SymbolEntry.SectionNumber > 0 && SymbolEntry.Type == IMAGE_SYM_TYPE_NULL && auxcount == 1) { index = SymbolEntry.SectionNumber - 1; CV_READ(ImageReadHandle, (PUCHAR)&AuxSymbolEntry, symsize); entrycount += auxcount; auxcount = 0; if (AuxSymbolEntry.Section.Length && AuxSymbolEntry.Section.NumberOfLinenumbers) { seekSave = CV_TELL(ImageReadHandle); CV_SEEK(ImageReadHandle, pNextLinenumber, SEEK_SET); pLinenumbers = (PIMAGE_LINENUMBER)realloc( (PUCHAR)pLinenumbers, sizeof(IMAGE_LINENUMBER) * (int)AuxSymbolEntry.Section.NumberOfLinenumbers); CV_READ(ImageReadHandle, (PUCHAR)pLinenumbers, sizeof(IMAGE_LINENUMBER) * (int)AuxSymbolEntry.Section.NumberOfLinenumbers); pNextLinenumber = CV_TELL(ImageReadHandle); for (ind = 0; ind < AuxSymbolEntry.Section.NumberOfLinenumbers; ind++) pLinenumbers[ind].Type.VirtualAddress += Base; InsertSymfile(pPathname, pFilename, pExtension, pLinenumbers, AuxSymbolEntry.Section.NumberOfLinenumbers, SymbolEntry.Value + Base, SymbolEntry.Value + Base + AuxSymbolEntry.Section.Length, pImage->index); //////////////// #if 0 dprintf("\npath: <%s> file: <%s> ext: <%s> " "start: %08lx end: %08lx\n", pPathname, pFilename, pExtension, SymbolEntry.Value, SymbolEntry.Value + AuxSymbolEntry.Section.Length); dprintf("section %ld - length: %lx " "line number cnt: %d\n", index, AuxSymbolEntry.Section.Length, AuxSymbolEntry.Section.NumberOfLinenumbers); for (index = 0; index < AuxSymbolEntry.Section.NumberOfLinenumbers; index++) dprintf("index %ld, address: %08lx, " "line number %d\n", index, (pLinenumbers + index)-> Type.VirtualAddress, (pLinenumbers + index)->Linenumber); #endif ///////////////// CV_SEEK(ImageReadHandle, seekSave, SEEK_SET); } } // else // dprintf("STATIC class entry\n"); break; case IMAGE_SYM_CLASS_EXTERNAL: if (SymbolEntry.N.Name.Short) { strncpy(ShortString, SymbolEntry.N.ShortName, 8); ShortString[8] = '\0'; SymbolName = ShortString; } else { // // if this is a huge string table and the symbol // is near a 64k boundary, then copy it by hand; // if (StringTableSize & 0xffff0000) { p = StringTable + SymbolEntry.N.Name.Long; if ((ULONG)((ULONG)p & 0x0000ff00) == 0x0000ff00) { SymbolName = buff; while (*p) *SymbolName++ = *p++; *SymbolName = '\0'; SymbolName = buff; } else SymbolName = p; } else SymbolName = StringTable + SymbolEntry.N.Name.Long; } if (SymbolEntry.Value) { SymbolValue = SymbolEntry.Value + Base; pNewSymbol = InsertSymbol(SymbolValue, SymbolName, pImage->index); #ifdef NT_SAPI if (pNewSymbol) { if (auxcount) { entrycount++; auxcount--; CV_READ(ImageReadHandle,&AuxSymbolEntry,symsize); } else memset( &AuxSymbolEntry, 0, symsize); TH_SetupCVpublic( pImage, pNewSymbol, &SymbolEntry, &AuxSymbolEntry); } #endif /* NT_SAPI */ if (SymbolValue > pImage->offsetHigh) pImage->offsetHigh = SymbolValue; if (SymbolValue < pImage->offsetLow) pImage->offsetLow = SymbolValue; symbolcount++; // dprintf("mod: %s value: %08lx symbol: %s\n", // pszName, SymbolValue, SymbolName); // if (symbolcount % 100 == 0) // dprintf("KD: module \"%s\" loaded %ld " // "symbols\r", pszName, symbolcount); } break; case IMAGE_SYM_CLASS_STRUCT_TAG: if (SymbolEntry.N.Name.Short) { strncpy(ShortString, SymbolEntry.N.ShortName, 8); ShortString[8] = '\0'; SymbolName = ShortString; } else { if (StringTableSize & 0xffff0000) { p = StringTable + SymbolEntry.N.Name.Long; if ((ULONG)((ULONG)p & 0x0000ff00) == 0x0000ff00) { SymbolName = buff; while (*p) *SymbolName++ = *p++; *SymbolName = '\0'; SymbolName = buff; } else SymbolName = p; } else SymbolName = StringTable + SymbolEntry.N.Name.Long; } pCurrentStructure = InsertStructure(entrycount,SymbolName, pImage->index); break; case IMAGE_SYM_CLASS_FUNCTION: if (SymbolEntry.N.Name.Short) { strncpy(ShortString, SymbolEntry.N.ShortName, 8); ShortString[8] = '\0'; SymbolName = ShortString; } else { if (StringTableSize & 0xffff0000) { p = StringTable + SymbolEntry.N.Name.Long; if ((ULONG)((ULONG)p & 0x0000ff00) == 0x0000ff00) { SymbolName = buff; while (*p) *SymbolName++ = *p++; *SymbolName = '\0'; SymbolName = buff; } else SymbolName = p; } else SymbolName = StringTable + SymbolEntry.N.Name.Long; } if (strcmp(SymbolName,".bf")) { #ifdef NT_SAPI // End of Function setup CV types!! if ( pCurrentFunction && pNewSymbol) TH_SetupCVfunction( pImage, pCurrentFunction, pNewSymbol); #endif /* NT_SAPI */ break; } if (SymbolEntry.Value && pNewSymbol) { SymbolValue = SymbolEntry.Value + (ULONG)pImage->lpBaseOfImage; pCurrentFunction = InsertFunction(pNewSymbol->string, pNewSymbol->offset); } break; case IMAGE_SYM_CLASS_AUTOMATIC: case IMAGE_SYM_CLASS_ARGUMENT: case IMAGE_SYM_CLASS_REGISTER: case IMAGE_SYM_CLASS_MEMBER_OF_STRUCT:{ ULONG auxValue; if (SymbolEntry.Value==-1L) break; if (SymbolEntry.N.Name.Short) { strncpy(ShortString, SymbolEntry.N.ShortName, 8); ShortString[8] = '\0'; SymbolName = ShortString; } else { if (!SymbolEntry.N.Name.Long) break; if (StringTableSize & 0xffff0000) { p = StringTable + SymbolEntry.N.Name.Long; if ((ULONG)((ULONG)p & 0x0000ff00) == 0x0000ff00) { SymbolName = buff; while (*p) *SymbolName++ = *p++; *SymbolName = '\0'; SymbolName = buff; } else SymbolName = p; } else SymbolName = StringTable + SymbolEntry.N.Name.Long; } // If we have a aux entry read it in, otherwise zero it if (auxcount) { entrycount++; auxcount--; CV_READ(ImageReadHandle, &AuxSymbolEntry, symsize); } else memset( &AuxSymbolEntry, 0, symsize); // Structures need the tag index if (SymbolEntry.Type == IMAGE_SYM_TYPE_STRUCT) auxValue = AuxSymbolEntry.Sym.TagIndex; SymbolValue = SymbolEntry.Value; if(SymbolEntry.StorageClass!=IMAGE_SYM_CLASS_MEMBER_OF_STRUCT){ // dprintf("\t[LOCAL:%s, value=%ld, aux=%lx]\n", // SymbolName, SymbolValue, auxValue); AddLocalToFunction(pCurrentFunction,SymbolName,SymbolValue, SymbolEntry.Type, auxValue); #ifdef NT_SAPI if ( pCurrentFunction && pCurrentFunction->pLocal ) TH_SetupCVlocal( pImage, pCurrentFunction->pLocal, &SymbolEntry, &AuxSymbolEntry); #endif /* NT_SAPI */ } else{ // dprintf("\t[FIELD:%s, type=%ld, value=%ld]\n", // SymbolName, SymbolEntry.Type, SymbolValue); AddFieldToStructure(pCurrentStructure, SymbolName, SymbolValue,SymbolEntry.Type, auxValue); #ifdef NT_SAPI if ( pCurrentStructure && pCurrentStructure->pField) TH_SetupCVfield( pImage, pCurrentStructure->pField, &SymbolEntry, &AuxSymbolEntry); #endif /* NT_SAPI */ } } break; #ifdef NT_SAPI case IMAGE_SYM_CLASS_END_OF_STRUCT: if ( pCurrentStructure ) { if (auxcount) { entrycount++; auxcount--; CV_READ(ImageReadHandle,&AuxSymbolEntry,symsize); } else memset( &AuxSymbolEntry, 0, symsize); TH_SetupCVstruct( pImage, pCurrentStructure, &SymbolEntry, &AuxSymbolEntry); } break; #endif /* NT_SAPI */ default: // dprintf("OTHER class entry - class: %d\n", // SymbolEntry.StorageClass); break; } // auxcount has the number of unprocessed auxiliary entries // skip over them for the next table entry entrycount += auxcount; CV_SEEK(ImageReadHandle, symsize * auxcount, SEEK_CUR); } if (StringTable) { StringTable += sizeof(ULONG); #ifdef NT_HOST // BUGBUG W-Barry 30-Apr-91 Replaced hfree call with free - same as // with calloc above... free(StringTable); #else hfree(StringTable); #endif } if (fVerboseOutput) { #ifdef MIPS dprintf("KD: \"%s\" loaded %ld symbols, %ld functions (%08lx-%08lx)\n", pszName, symbolcount, pImage->NumberOfFunctions, pImage->offsetLow, pImage->offsetHigh); #else dprintf("KD: \"%s\" loaded %ld symbols (%08lx-%08lx)\n", pszName, symbolcount, pImage->offsetLow, pImage->offsetHigh); #endif } free(pExtension); free(pFilename); free(pPathname); free(pLinenumbers); #ifndef NT_SAPI CV_CLOSE(ImageReadHandle); #endif } #endif // TEMP TEMP TEMP - pack string with 14 characters out of 18 into // string in place. void PackAuxNameEntry (PUCHAR pPathname, ULONG auxcount) { PUCHAR pchDst; PUCHAR pchSrc; pchDst = pPathname + 14; pchSrc = pPathname + 18; while (auxcount-- > 1) { memcpy(pchDst, pchSrc, 14); pchDst += 14; pchSrc += 18; } *pchDst = '\0'; } void UnloadSymbols (PIMAGE_INFO pImage) { PSYMBOL pSymbol; PSYMFILE pSymfile; PNODE pNode; PNODE pNodeNext; // if module was never loaded, nothing to unload, // just close open file handle and return if (fLazyLoad && !pImage->fSymbolsLoaded) { #ifdef KERNEL if (fVerboseOutput) dprintf("KD: unloading \"%s\" (deferred)\n", pImage->pszName); #else CloseHandle(pImage->hFile); #endif return; } if (fVerboseOutput) #ifdef KERNEL dprintf("KD: unloading symbols for \"%s\"\n", pImage->pszName); #else dprintf("NTSD: unloading symbols for \"%s\"\n", pImage->pszName); #endif free(pImage->pszName); #if defined(MIPS) // for MIPS debugger, free the function entry table if (pImage->NumberOfFunctions) free(pImage->FunctionTable); #endif //////////////////////////////////////////////////////////////// // 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); // 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) { // dprintf("** 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 (fVerboseOutput) #ifdef KERNEL dprintf("KD: symfile: \"%s\" deleted\n", pSymfile->pchName); #else dprintf("NTSD: symfile: \"%s\" deleted\n", pSymfile->pchName); #endif DeleteSymfile(pSymfile); } pNode = pNodeNext; } } 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. pImage->fSymbolsLoaded = TRUE; LoadSymbols(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. pImageFound->fSymbolsLoaded = TRUE; LoadSymbols(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); } #ifdef KERNEL PUCHAR GetModuleName (PUCHAR pszPath) { PUCHAR pszStart; PUCHAR pszEnd; PUCHAR pszReturn; pszStart = pszEnd = pszPath + strlen(pszPath); while (pszStart >= pszPath && *pszStart != ':' && *pszStart != '\\') { if (*pszStart == '.') pszEnd = pszStart; pszStart--; } // special case for module "ntoskrnl", change to "nt" if ((pszEnd - pszStart) == 9 && !_strnicmp(pszStart + 1, "ntoskrnl", 8)) pszEnd = pszStart + 3; pszReturn = (PUCHAR)malloc(pszEnd - pszStart); if (!pszReturn) { printf("memory allocation error\n"); ExitProcess(STATUS_UNSUCCESSFUL); } pszStart++; strncpy(pszReturn, pszStart, pszEnd - pszStart); *(pszReturn + (pszEnd - pszStart)) = '\0'; return pszReturn; } #endif #ifndef NT_SAPI /*** parseExamine - parse and execute examine command * * Purpose: * Parse the current command string and examine the symbol * table to display the appropriate entries. The entries * are displayed in increasing string order. This function * accepts underscores, alphabetic, and numeric characters * to match as well as the special characters '?' and '*'. * The '?' character matches any other character while '*' * matches any string of zero or more characters. If used, * '*' must be the last character in the pattern. * * Input: * pchCommand - pointer to current command string * * Output: * offset and string name of symbols displayed * *************************************************************************/ void parseExamine (void) { UCHAR chString[60]; UCHAR ch; PUCHAR pchString = chString; PUCHAR pchStart; BOOLEAN fClosure = FALSE; BOOLEAN fOutput; ULONG cntunderscores = 0; ULONG count; PSYMBOL pSymbol; PNODE pNode; PNODE pNodeLast; PUCHAR pchSrc; PUCHAR pchDst; UCHAR chSrc; UCHAR chDst; int status = 0; PIMAGE_INFO pImage; #if defined(KERNEL) #if defined(NT_HOST) SetConsoleCtrlHandler( waitHandler, FALSE ); SetConsoleCtrlHandler( cmdHandler, TRUE ); #else signal(SIGINT, ControlCHandler); #endif #endif // get module pointer from name in command line (!) pImage = ParseModuleIndex(); if (!pImage) error(VARDEF); if (fLazyLoad && pImage != (PIMAGE_INFO)-1 && !pImage->fSymbolsLoaded) { LoadSymbols(pImage); pImage->fSymbolsLoaded = TRUE; } ch = PeekChar(); // special case the command "x*!" to dump out the module table // and "x*!*" to dump out module table with line number information if (pImage == (PIMAGE_INFO)-1) { fOutput = FALSE; if (ch == '*') { pchCommand++; ch = PeekChar(); fOutput = TRUE; } if (ch == ';' || ch == '\0') { DumpModuleTable(fOutput); return; } else error(SYNTAX); } // copy invariant part of input pattern into chString // map to upper case to find first possibility in tree pchCommand++; while (ch == '_') { *pchString++ = ch; ch = *pchCommand++; } pchStart = pchString; ch = (UCHAR)toupper(ch); while ((ch >= 'A' && ch <= 'Z') || (ch == '_') || (ch >= '0' && ch <= '9')) { *pchString++ = ch; ch = (UCHAR)toupper(*pchCommand++); } *pchString = '\0'; if (count = pchString - pchStart) { // if nonNULL invariant part, set search range: // set starting node to root of invariant access // set ending node to next after invariant incremented // for all modules, increment last character in variable // (because of mapping, increment 'Z' to 'z'+1 = '{') pSymbol = AllocSymbol(0, chString, -1); AccessNode(&(pProcessCurrent->symcontextSymbolString), &(pSymbol->nodeString)); pNode = pProcessCurrent->symcontextSymbolString.pNodeRoot; pchSrc = &pSymbol->string[count - 1]; if (*pchSrc == 'Z') *pchSrc = 'z'; (*pchSrc)++; status = AccessNode(&(pProcessCurrent->symcontextSymbolString), &(pSymbol->nodeString)); pNodeLast = pProcessCurrent->symcontextSymbolString.pNodeRoot; if (status == -1 && pNodeLast) pNodeLast = NextNode(&(pProcessCurrent->symcontextSymbolString), pNodeLast); DeallocSymbol(pSymbol); } else { // if NULL invariant part, search the whole tree: // set starting node to first in tree; // set ending node to last in tree pNode = NextNode(&(pProcessCurrent->symcontextSymbolString), NULL); pNodeLast = NULL; } // copy rest of pattern into chString while ((ch >= 'A' && ch <= 'Z') || (ch == '_') || (ch >= '0' && ch <= '9') || (ch == '?')) { *pchString++ = ch; ch = (UCHAR)toupper(*pchCommand++); } *pchString = '\0'; // set closure flag if '*' is found if (ch == '*') { fClosure = TRUE; ch = *pchCommand++; } // error if more pattern is seen if (ch) error(SYNTAX); pchCommand--; // for each node in search range: // match if NULL input was entered // nonmatch if underscores differ by more than one // match if case-insensitive match with: // '?' matching all characters // '*' closes match if extra input after source null cntunderscores = pchStart - chString; while (pNode != pNodeLast) { pSymbol = PNODE_TO_PSYMBOL(pNode, &(pProcessCurrent->symcontextSymbolString)); fOutput = FALSE; if (!chString[0]) fOutput = TRUE; else if ((cntunderscores != (ULONG)pSymbol->underscores) && (cntunderscores + 1 != (ULONG)pSymbol->underscores)) fOutput = FALSE; else { pchSrc = pchStart; pchDst = pSymbol->string; do { chSrc = *pchSrc++; chDst = (UCHAR)toupper(*pchDst++); } while ((chSrc == chDst || chSrc == '?') && chSrc && chDst); fOutput = (BOOLEAN)(!chSrc && (fClosure || !chDst)); } // if flag set, output the offset and symbol string if (fOutput && (pImage == (PIMAGE_INFO)-1 || pSymbol->modIndex == (CHAR)pImage->index)) { dprintf("%8lx %s!", pSymbol->offset, pImageFromIndex(pSymbol->modIndex)->pszName); count = pSymbol->underscores; while (count--) dprintf("_"); dprintf("%s\t%s\n", pSymbol->string, (pSymbol->type == SYMBOL_TYPE_EXPORT) ? "[Export]" : ""); } pNode = NextNode(&(pProcessCurrent->symcontextSymbolString), pNode); //#ifndef KERNEL if (fControlC) { fControlC = 0; return; } //#endif } } PIMAGE_INFO ParseModuleIndex (void) { PUCHAR pchCmdSaved = pchCommand; UCHAR chName[60]; PUCHAR pchDst = chName; UCHAR ch; // first, parse out a possible module name, either a '*' or // a string of 'A'-'Z', 'a'-'z', '0'-'9', '_' (or null) ch = PeekChar(); pchCommand++; if (ch == '*') *pchDst = ch; else { while ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9') || ch == '_') { *pchDst++ = ch; ch = *pchCommand++; } *pchDst = '\0'; pchCommand--; } // if no '!' after name and white space, then no module specified // restore text pointer and treat as null module (PC current) if (PeekChar() == '!') pchCommand++; else { pchCommand = pchCmdSaved; chName[0] = '\0'; } // chName either has: '*' for all modules, // '\0' for current module, // nonnull string for module name. if (chName[0] == '*') return (PIMAGE_INFO)-1; else if (chName[0]) return GetModuleIndex(chName); else return GetCurrentModuleIndex(); } PIMAGE_INFO GetModuleIndex (PUCHAR pszName) { PIMAGE_INFO pImage; pImage = pProcessCurrent->pImageHead; while (pImage && ntsdstricmp(pszName, pImage->pszName)) pImage = pImage->pImageNext; return pImage; } PIMAGE_INFO GetCurrentModuleIndex (void) { NT_PADDR pcvalue = GetRegPCValue(); PIMAGE_INFO pImage; pImage = pProcessCurrent->pImageHead; while (pImage && (Flat(pcvalue) < pImage->offsetLow || Flat(pcvalue) > pImage->offsetHigh)) pImage = pImage->pImageNext; return pImage; } static UCHAR strBlank[] = " "; void DumpModuleTable (BOOLEAN fLineInfo) { PIMAGE_INFO pImage; PNODE pNode; PSYMFILE pSymfile; int strBlankIndex = 7; dprintf("start end module name\n"); pImage = pProcessCurrent->pImageHead; while (pImage) { if (pImage->fSymbolsLoaded && pImage->offsetLow != 0xffffffff) dprintf("%08lx %08lx", pImage->offsetLow, pImage->offsetHigh); else dprintf("%08lx ", pImage->lpBaseOfImage); dprintf(" %s", pImage->pszName); if (strlen(pImage->pszName) < 8) strBlankIndex = strlen(pImage->pszName); if (!pImage->fSymbolsLoaded) dprintf("%s(load deferred)", &strBlank[strBlankIndex]); else if (pImage->offsetLow == 0xffffffff) dprintf("%s(no symbolic information)", &strBlank[strBlankIndex]); dprintf("\n"); if (pImage->fSymbolsLoaded && fLineInfo) { pNode = NextNode(&(pProcessCurrent->symcontextSymfileString), NULL); if (pNode) { printf(" lines filename start pathname\n"); do { pSymfile = PNODE_TO_PSYMFILE(pNode, &(pProcessCurrent->symcontextSymfileString)); if (pSymfile->modIndex == (CHAR)pImage->index) { dprintf(" %6d %-8s %08lx ", pSymfile->cLineno, pSymfile->pchName, pSymfile->startOffset); if (pSymfile->pchPath) dprintf("%s%s%s", pSymfile->pchPath, pSymfile->pchName, pSymfile->pchExtension); dprintf("\n"); } pNode = NextNode( &(pProcessCurrent->symcontextSymfileString), pNode); } while (pNode); } } pImage = pImage->pImageNext; } } #endif /* NT_SAPI */ /*** 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 = ntsdstricmp(pSymbol1->string, pSymbol2->string); if (!cmp) { if (pSymbol1->underscores < pSymbol2->underscores) cmp = -1; else if (pSymbol1->underscores > pSymbol2->underscores) cmp = 1; else { cmp = strcmp(pSymbol1->string, pSymbol2->string); if (!cmp) { if (pSymbol1->modIndex < pSymbol2->modIndex) cmp = -1; else if (pSymbol1->modIndex > pSymbol2->modIndex) cmp = 1; } } } } return cmp; } /*** 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; // 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(pSymfile1->pchName, 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; } return cmp; } /*** 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 = ntsdstricmp(pSymbol1->string, 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(pSymbol1->string, pSymbol2->string); } } return cmp; } /*** 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(pSymfile1->pchName, 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; } } return cmp; } /*** 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, PUCHAR pinsertstring, CHAR insertmod) { PSYMBOL pSymbol; pSymbol = AllocSymbol(insertvalue, pinsertstring, insertmod); if (!InsertNode(&(pProcessCurrent->symcontextSymbolOffset), &(pSymbol->nodeOffset))) { DeallocSymbol(pSymbol); // dprintf("insert - value %d already in tree\n", insertvalue); return NULL; } if (!InsertNode(&(pProcessCurrent->symcontextSymbolString), &(pSymbol->nodeString))) { DeleteNode(&(pProcessCurrent->symcontextSymbolOffset), &(pSymbol->nodeOffset)); DeallocSymbol(pSymbol); // dprintf("insert - string %s already in tree\n", pinsertstring); return NULL; } return pSymbol; } PSTRUCT InsertStructure (ULONG insertvalue, PUCHAR pinsertstring, CHAR insertmod) { PSTRUCT pStruct; pStruct = (PSTRUCT) AllocSymbol(insertvalue, pinsertstring, insertmod); if (!InsertNode(&(pProcessCurrent->symcontextStructOffset), &(pStruct->nodeOffset))) { DeallocSymbol((PSYMBOL)pStruct); //dprintf("insert - value %d already in tree\n", insertvalue); return NULL; } if (!InsertNode(&(pProcessCurrent->symcontextStructString), &(pStruct->nodeString))) { DeleteNode(&(pProcessCurrent->symcontextStructOffset), &(pStruct->nodeOffset)); DeallocSymbol((PSYMBOL)pStruct); //dprintf("insert - string %s already in tree\n", pinsertstring); return NULL; } pStruct->pField = NULL; return pStruct; } /*** 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 (PUCHAR pPathname, PUCHAR pFilename, PUCHAR 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); // dprintf("insert - value %d already in tree\n", insertvalue); return NULL; } if (!InsertNode(&(pProcessCurrent->symcontextSymfileString), &(pSymfile->nodeString))) { DeleteNode(&(pProcessCurrent->symcontextSymfileOffset), &(pSymfile->nodeOffset)); DeallocSymfile(pSymfile); // dprintf("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 //dprintf("before splay\n"); SplayTree(pNodeDelete); //dprintf("after splay\n"); // point to the splayed node children and join them pSymContext->pNodeRoot = pNodeDelete->pLchild; pNodeRootTemp = pNodeDelete->pRchild; //dprintf("before join\n"); JoinTree(pSymContext, pNodeRootTemp); //dprintf("after join\n"); } /*** 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; } /*** 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; dprintf("****** output tree ******\n"); while (TRUE) { pNode = NextNode(pSymContext, pNode); if (pNode) { pSymbol = PNODE_TO_PSYMBOL(pNode, pSymContext); dprintf("node:%8lx par:%8lx lch:%8lx rch:%8lx " , pNode, pNode->pParent, pNode->pLchild, pNode->pRchild); dprintf("value: %8lx <", pSymbol->offset); count = pSymbol->underscores; while (count--) dprintf("_"); dprintf("%s>\n", pSymbol->string); } else break; } } /*** 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 (PUCHAR pString, PULONG pOffset, CHAR iModule) { UCHAR SuffixedString[80]; UCHAR Suffix[4]; 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 (PUCHAR pString, PULONG pOffset, CHAR iModule) { PSYMBOL pSymSearch = AllocSymbol(0L, pString, iModule); 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); } /*** 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 (PUCHAR 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; // PDK KLUGDE::: if (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; } #ifndef NT_SAPI void GetLinenoString (PUCHAR 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 (PULONG pMemoryLow, PULONG pMemoryHigh) { NT_PADDR pcValue = GetRegPCValue(); PSYMFILE pSymfile; PLINENO pLineno; *pMemoryLow = -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) { NT_PADDR pcValue = GetRegPCValue(); return GetLinenoFromOffset(ppSymfile, Flat(pcValue)); } PLINENO GetLastLineno (PPSYMFILE ppSymfile, PUSHORT pLineNum) { PLINENO pLineno = NULL; PSYMFILE pSymfile; if (pSymfileLast) { pLineno = GetLinenoFromFilename(pSymfileLast->pchName, &pSymfile, lineNumberLast, pSymfileLast->modIndex); if (pLineno) { *ppSymfile = pSymfile; *pLineNum = lineNumberLast; } } return pLineno; } static PUCHAR Type[] = {"null", "void", "char", "short", "int", "long", "float", "double", ""/*struct*/, "union", "enum", "moe", "uchar", "ushort", "uint", "ulong"}; static PUCHAR Dtype[]= {"", "*", "()", "[]"}; BOOLEAN GetLocalFromString(PUCHAR pszLocal, PULONG pValue) { PSYMFILE pSymfileSearch = pTempSymfile; PSYMFILE pSymfile; SYMBOL Symbol; static NT_ADDR addrPC; static PLOCAL pLocal; PLOCAL pL; NT_PADDR newPC = GetRegPCValue(); 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; } #endif /* NT_SAPI */ PSYMBOL GetFunctionFromOffset (PPSYMFILE ppSymfile, ULONG offset) { PSYMFILE pSymfileSearch = pTempSymfile; PSYMFILE pSymfile; PSYMBOL pSymbol = NULL; SYMBOL Symbol; int st; // PUCHAR 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) { // dprintf("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)); // dprintf("%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"; // // dprintf(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); // dprintf("%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 = "; // // dprintf(pszCtrl, // *((LONG*)&pLocal->value)<0?"-":"+", // value, // Type[pLocal->type&0xF], // Dtype[(pLocal->type>>4)&0x3], // pLocal->pszLocalName); // GetLocalValue(pLocal->value, pLocal->type, TRUE); // dprintf("\n"); // } // pLocal = pLocal->next; // } // } // else dprintf("NO LOCALS"); // dprintf("}\n"); } return pSymbol; } #ifndef NT_SAPI PSTRUCT GetStructFromValue(ULONG value, LONG base) { PSTRUCT pStruct = NULL; STRUCT Struct; PUCHAR 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)); dprintf("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 = "; dprintf(pszCtrl, *((LONG*)&pField->value)<0?"-":"+", val, Type[pField->type&0xF], Dtype[(pField->type>>4)&0x3], pField->pszFieldName); GetLocalValue(base+pField->value, pField->type, TRUE); dprintf("\n"); pField = pField->next; } } else dprintf("NO FIELDS"); dprintf("\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; #ifndef MIPS float f; double df; #endif type &= 0xF; if (fPointerExpression) { NT_PADDR paddr = GetRegFPValue(); AddrAdd(paddr, value); if (fPrint) dprintAddr(paddr); return (ULONG)Flat(paddr); } GetBytesFromFrame((PUCHAR)&data, value, sizeof(data)); if (dtype) { if (fPrint) dprintf("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) dprintf("%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; #ifndef MIPS case IMAGE_SYM_TYPE_FLOAT: pszCtrl = "%f"; GetBytesFromFrame((PUCHAR)&f, value, sizeof(float)); if (fPrint) dprintf(pszCtrl, f); return data; break; case IMAGE_SYM_TYPE_DOUBLE: pszCtrl = "%lf"; GetBytesFromFrame((PUCHAR)&df, value, sizeof(double)); if (fPrint) dprintf(pszCtrl, df); return data; break; #endif default:{ NT_PADDR paddr = GetRegFPValue(); pszCtrl = "???"; AddrAdd(paddr, value); retValue = Flat(paddr); } break; } if (fPrint) dprintf(pszCtrl, data); return retValue; } void GetBytesFromFrame(PUCHAR pcb, LONG offset, USHORT cb) { NT_PADDR paddr = GetRegFPValue(); AddrAdd(paddr, offset); GetMemString(paddr, pcb, cb); } #endif /* NT_SAPI */ void AddFieldToStructure(PSTRUCT pStruct, PUCHAR 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, PUCHAR 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; } PSYMBOL InsertFunction(PUCHAR 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) { // dprintf("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); // pSymbol->pSymbol = pS; // Now insert this function into this symfile's function tree if (!InsertNode(&(pSymfile->symcontextFunctionOffset), &(pSymbol->nodeOffset))) { DeallocSymbol(pSymbol); // dprintf("insert - value %d already in tree\n", lpFunctionName); return NULL; } if (!InsertNode(&(pSymfile->symcontextFunctionString), &(pSymbol->nodeString))) { DeleteNode(&(pSymfile->symcontextFunctionOffset), &(pSymbol->nodeOffset)); DeallocSymbol(pSymbol); dprintf("insert - string %s already in tree\n", lpFunctionName); return NULL; } return pSymbol; } 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; // PDK KLUDGE::: if (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; } /*** GetSymbol - 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 GetSymbol (ULONG offset, PUCHAR pchBuffer, PULONG pDisplacement) { SYMBOL Symbol; ULONG disp = offset; PSYMBOL pSymbol; ULONG underscorecnt; UCHAR ch; PUCHAR pszTemp; // create temporary symbol with offset (module not needed) Symbol.offset = offset; Symbol.string[0] = '\0'; *pchBuffer = '\0'; // 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 = pImageFromIndex(pSymbol->modIndex)->pszName; while (ch = *pszTemp++) *pchBuffer++ = ch; *pchBuffer++ = '!'; underscorecnt = pSymbol->underscores; while (underscorecnt--) *pchBuffer++ = '_'; strcpy(pchBuffer, pSymbol->string); // displacement is input offset less symbol value offset disp -= pSymbol->offset; } *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, PUCHAR pString, CHAR iModule) { PSYMBOL pSymbol; PUCHAR pStringTemp = pString; // allocate the space needed pSymbol = malloc((sizeof(SYMBOL) + strlen(pString) + 1) & ~3); if (!pSymbol) { dprintf("AllocSymbol - Out of memory\n"); ExitProcess(STATUS_UNSUCCESSFUL); } // 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 - pString); pSymbol->modIndex = iModule; pSymbol->type = SYMBOL_TYPE_SYMBOL; pSymbol->pLocal = NULL; strcpy(pSymbol->string, pStringTemp); return pSymbol; } #ifdef NT_SAPI static SYMBOL symbolTemplate = { 0,0, {NULL, NULL, NULL }, { NULL, NULL, NULL }, -1L, 0, 0, SYMBOL_TYPE_SYMBOL, NULL, { '\177', '\177', '\0' } }; static #else SYMBOL symbolTemplate = { { NULL, NULL, NULL }, { NULL, NULL, NULL }, -1L, 0, 0, SYMBOL_TYPE_SYMBOL, NULL, 0, { '\177', '\177', '\0' } }; #endif /* NT_SAPI */ /*** 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 (PUCHAR pPathname, PUCHAR pFilename, PUCHAR pExtension, PIMAGE_LINENUMBER pCoffLineno, USHORT cLineno, ULONG startingOffset, ULONG endingOffset, CHAR modIndex) { PSYMFILE pSymfile; PLINENO pLineno; USHORT index; PSYMBOL symbolMax; IMAGE_LINENUMBER CoffLineno; pSymfile = malloc(sizeof(SYMFILE)); if (!pSymfile) { dprintf("AllocSymfile - Out of memory\n"); ExitProcess(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 = malloc(strlen(pPathname) + 1); if (!pSymfile->pchPath) { dprintf("AllocSymfile - Out of memory\n"); ExitProcess(STATUS_UNSUCCESSFUL); } strcpy(pSymfile->pchPath, pPathname); pSymfile->pchName = malloc(strlen(pFilename) + 1); if (!pSymfile->pchName) { dprintf("AllocSymfile - Out of memory\n"); ExitProcess(STATUS_UNSUCCESSFUL); } strcpy(pSymfile->pchName, pFilename); pSymfile->pchExtension = malloc(strlen(pExtension) + 1); if (!pSymfile->pchExtension) { dprintf("AllocSymfile - Out of memory\n"); ExitProcess(STATUS_UNSUCCESSFUL); } strcpy(pSymfile->pchExtension, pExtension); pSymfile->modIndex = modIndex; pSymfile->cLineno = cLineno; if (pCoffLineno) { pSymfile->pLineno = malloc((cLineno + 1) * sizeof(LINENO)); if (!pSymfile->pLineno) { dprintf("AllocSymfile - Out of memory\n"); ExitProcess(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 = -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 = malloc( (pSymfile->cLineno + 1) * sizeof(PLINENO)); if (!pSymfile->ppLinenoSrcLine) { dprintf("AllocSymfile - Out of memory\n"); ExitProcess(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); } /*** ntsdstricmp - case-insensitive string compare * * Purpose: * Compare two strings, but map upper case to lower * * Input: * pchDst - pointer to first string * pchSrc - pointer to second string * * Output: * -1 if value(pchDst) < value(pchSrc) * 0 if value(pchDst) = value(pchSrc) * 1 if value(pchDst) > value(pchSrc) * *************************************************************************/ int ntsdstricmp (PUCHAR pchDst, PUCHAR pchSrc) { UCHAR ch1; UCHAR ch2; do { ch1 = (UCHAR)tolower(*pchDst++); ch2 = (UCHAR)tolower(*pchSrc++); } while (ch1 && ch1 == ch2); if (ch1 < ch2) return -1; else return ch1 > ch2; } #ifndef NT_SAPI /*** 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[80]; PUCHAR pszEntry; ULONG count; ULONG index; // make a symbol structure with the supplied offset pSymbol = AllocSymbol(addrStart, "", -1); // 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 = szEntry; if (pNode) { pSymbol = PNODE_TO_PSYMBOL(pNode, &(pProcessCurrent->symcontextSymbolOffset)); pszEntry += sprintf(pszEntry, "(%08lx) ", pSymbol->offset); pszEntry += sprintf(pszEntry, "%s!", pImageFromIndex(pSymbol->modIndex)->pszName); count = pSymbol->underscores; while (count--) pszEntry += sprintf(pszEntry, "_"); pszEntry += sprintf(pszEntry, "%s", pSymbol->string); } else { if (index == 0) pszEntry += sprintf(pszEntry, "(%08lx) ", addrStart); pszEntry += sprintf(pszEntry, ""); } cbString[index] = pszEntry - szEntry; if (index == 0) { dprintf("%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) dprintf(" | "); else { dprintf("\n"); count = 78 - cbString[1]; dprintf(&szBlanks[sizeof(szBlanks) - count]); } dprintf("%s\n", szEntry); } #endif /* NT_SAPI */ void SortSrcLinePointers (PSYMFILE pSymfile) { PPLINENO ppLineno = pSymfile->ppLinenoSrcLine; PLINENO pLinenoV; USHORT N; USHORT h; USHORT i; USHORT j; // PDK KLUGDE::: if (!ppLineno) return; 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); } #ifndef NT_SAPI #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); dprintf("%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; } } 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; UCHAR chFilename[512]; PUCHAR pchTemp; if (pSymfile != pSymfileOpened) { if (fhandle) { fclose(fhandle); fhandle = NULL; pSymfileOpened = NULL; } if (pSymfile && pSymfile->pchPath) do { strcpy(chFilename, pSymfile->pchPath); strcat(chFilename, pSymfile->pchName); strcat(chFilename, pSymfile->pchExtension); fhandle = fopen(chFilename, "r"); if (!fhandle) { dprintf("enter path for '%s%s%s' (cr for none):", pSymfile->pchPath, pSymfile->pchName, pSymfile->pchExtension); NtsdPrompt("", chFilename, 512); RemoveDelChar(chFilename); // gets(chFilename); //#ifdef KERNEL // if (*chFilename!=13&&*chFilename!=10) { //#else if (*chFilename) { //#endif pchTemp = chFilename + strlen(chFilename) - 1; if (*pchTemp != ':' && *pchTemp != '\\') strcat(pchTemp + 1, "\\"); pSymfile->pchPath = realloc(pSymfile->pchPath, strlen(chFilename) + 1); strcpy(pSymfile->pchPath, chFilename); } else { free(pSymfile->pchPath); pSymfile->pchPath = NULL; return NULL; } } else pSymfileOpened = pSymfile; } while (!fhandle && chFilename[0]); } 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; // PDK KLUDGE::: if (!(indexHigh = pSymfile->cLineno)) return; 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[180]; 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. dprintf("%s!%s:\n", pImageFromIndex(pSymfile->modIndex)->pszName, pSymfile->pchName); while (count) { // read the next line - report read error fgets(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) { dprintf("%4d", lineNumber); // if linenumber is on a breakpoint, // output a '>', if not, ':'. pLinenoNext = GetLinenoFromFilename(pSymfile->pchName, &pSymfileNext, lineNumber, pSymfile->modIndex); if (lineNumber == pLinenoNext->breakLineNumber) dprintf(">"); else dprintf(":"); dprintf(" %s", buffer); count--; } lineNumber++; } pSymfileLast = pSymfile; lineNumberLast = lineNumber; return TRUE; } #endif /* NT_SAPI */ PVOID FetchImageDirectoryEntry(int Handle, USHORT DirectoryEntry, PULONG Size, PULONG Base) { PUCHAR SectionName; USHORT Signature; ULONG i, DirectoryAddress; IMAGE_FILE_HEADER CoffFileHdr; IMAGE_OPTIONAL_HEADER CoffOptionalHdr; IMAGE_SECTION_HEADER CoffSectionHdr; ULONG DosHeader[16], NtSignature; if ( DirectoryEntry >= IMAGE_NUMBEROF_DIRECTORY_ENTRIES ) { return NULL; } CV_SEEK(Handle, 0, SEEK_SET); CV_READ(Handle, &Signature, sizeof(USHORT)); CV_SEEK(Handle, 0, SEEK_SET); if (Signature == IMAGE_DOS_SIGNATURE) { CV_READ(Handle, &DosHeader, 16*sizeof(ULONG)); CV_SEEK(Handle, DosHeader[15], SEEK_SET); CV_READ(Handle, &NtSignature, sizeof(ULONG)); if (NtSignature != IMAGE_NT_SIGNATURE) { printf("\nPE signature not found\n"); } } CV_READ(Handle, &CoffFileHdr, sizeof(IMAGE_FILE_HEADER)); CV_READ(Handle, &CoffOptionalHdr, CoffFileHdr.SizeOfOptionalHeader); #ifdef NT_SAPI ObjectTableCount = CoffFileHdr.NumberOfSections; ObjectTableOffset = CV_TELL(Handle); #endif if (CoffFileHdr.SizeOfOptionalHeader < IMAGE_SIZEOF_NT_OPTIONAL_HEADER) { // // must be a rom image // *Base = 0; switch (DirectoryEntry) { case IMAGE_DIRECTORY_ENTRY_EXPORT : SectionName = ".edata"; break; case IMAGE_DIRECTORY_ENTRY_IMPORT : SectionName = ".idata"; break; case IMAGE_DIRECTORY_ENTRY_RESOURCE : SectionName = ".rsrc"; break; case IMAGE_DIRECTORY_ENTRY_EXCEPTION : SectionName = ".pdata"; break; case IMAGE_DIRECTORY_ENTRY_SECURITY : SectionName = ".mdc"; break; case IMAGE_DIRECTORY_ENTRY_BASERELOC : SectionName = ".reloc"; break; case IMAGE_DIRECTORY_ENTRY_DEBUG : SectionName = ".debug"; break; default : SectionName = ""; } for (i=0; i= CoffSectionHdr.VirtualAddress && DirectoryAddress <= CoffSectionHdr.VirtualAddress + CoffSectionHdr.SizeOfRawData) { return( (PVOID)((DirectoryAddress - CoffSectionHdr.VirtualAddress) + CoffSectionHdr.PointerToRawData) ); } } return( NULL ); }