Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

4896 lines
160 KiB

/** ntsym.c - NT debugger symbolic routines
*
* Copyright <C> 1990, Microsoft Corporation
*
* Purpose:
* To load and access the program symbolic information.
*
* Revision History:
*
* [-] 19-Apr-1990 Richk Created.
*
*************************************************************************/
#include <string.h>
#include <io.h>
#include <fcntl.h>
#ifndef NT_HOST
#include <signal.h>
#endif
#undef NULL
#include "ntsdp.h"
#ifdef NT_SAPI
#include <limits.h>
#include <stdlib.h>
// 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 <conio.h>
#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 (<string>!)
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, "<no symbol>");
}
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<CoffFileHdr.NumberOfSections; i++) {
CV_READ(Handle, &CoffSectionHdr, sizeof(IMAGE_SECTION_HEADER));
if (!strcmp(CoffSectionHdr.Name, SectionName)) {
*Size = CoffSectionHdr.SizeOfRawData;
return( (PVOID)CoffSectionHdr.PointerToRawData );
}
}
return NULL;
} else {
*Base = CoffOptionalHdr.ImageBase;
}
if (!(DirectoryAddress = CoffOptionalHdr.DataDirectory[ DirectoryEntry ].VirtualAddress)) {
return( NULL );
}
*Size = CoffOptionalHdr.DataDirectory[ DirectoryEntry ].Size;
for (i=0; i<CoffFileHdr.NumberOfSections; i++) {
CV_READ(Handle, &CoffSectionHdr, sizeof(IMAGE_SECTION_HEADER));
if (DirectoryAddress >= CoffSectionHdr.VirtualAddress &&
DirectoryAddress <= CoffSectionHdr.VirtualAddress + CoffSectionHdr.SizeOfRawData) {
return( (PVOID)((DirectoryAddress - CoffSectionHdr.VirtualAddress) + CoffSectionHdr.PointerToRawData) );
}
}
return( NULL );
}