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.
 
 
 
 
 
 

5555 lines
174 KiB

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