4897 lines
160 KiB
C
4897 lines
160 KiB
C
|
||
/** ntsym.c - NT debugger symbolic routines
|
||
*
|
||
* Copyright <C> 1990, Microsoft Corporation
|
||
*
|
||
* Purpose:
|
||
* To load and access the program symbolic information.
|
||
*
|
||
* Revision History:
|
||
*
|
||
* [-] 19-Apr-1990 Richk Created.
|
||
*
|
||
*************************************************************************/
|
||
|
||
#include <string.h>
|
||
#include <io.h>
|
||
#include <fcntl.h>
|
||
#ifndef NT_HOST
|
||
#include <signal.h>
|
||
#endif
|
||
#undef NULL
|
||
#include "ntsdp.h"
|
||
|
||
#ifdef NT_SAPI
|
||
|
||
#include <limits.h>
|
||
#include <stdlib.h>
|
||
|
||
|
||
// Taken from NTSDK.C
|
||
|
||
PIMAGE_INFO pImageFromIndex (UCHAR index)
|
||
{
|
||
PIMAGE_INFO pImage;
|
||
|
||
pImage = pProcessHead->pImageHead;
|
||
while (pImage && pImage->index != index)
|
||
pImage = pImage->pImageNext;
|
||
|
||
return pImage;
|
||
}
|
||
// End from NTSDK.C
|
||
|
||
void * _cdecl halloc(long, size_t);
|
||
void _cdecl hfree(void *);
|
||
|
||
int CV_CLOSE( int handle);
|
||
int CV_OPEN( char *name, int ignore1, int ignore2);
|
||
int CV_READ( int handle, void * buffer, unsigned count);
|
||
int CV_SEEK( int handle, long offset, int origin);
|
||
long CV_TELL( int handle);
|
||
|
||
void TH_SetupCVfield(PIMAGE_INFO,PFIELD, IMAGE_SYMBOL*,IMAGE_AUX_SYMBOL*);
|
||
void TH_SetupCVfunction(PIMAGE_INFO,PSYMBOL,PSYMBOL);
|
||
void TH_SetupCVlocal(PIMAGE_INFO,PLOCAL, IMAGE_SYMBOL*,IMAGE_AUX_SYMBOL*);
|
||
void TH_SetupCVpublic(PIMAGE_INFO,PSYMBOL,IMAGE_SYMBOL*,IMAGE_AUX_SYMBOL*);
|
||
void TH_SetupCVstruct(PIMAGE_INFO,PSTRUCT,IMAGE_SYMBOL*,IMAGE_AUX_SYMBOL*);
|
||
|
||
typedef enum { //* Error returns from some SH functions
|
||
sheNone,
|
||
sheNoSymbols,
|
||
sheFutureSymbols,
|
||
sheMustRelink,
|
||
sheNotPacked,
|
||
sheOutOfMemory,
|
||
sheCorruptOmf,
|
||
sheFileOpen, //* Last CV compatable SHE error
|
||
sheBadDirectory
|
||
} SHE;
|
||
|
||
extern SHE SHerror;
|
||
|
||
ULONG ObjectTableOffset;
|
||
UINT ObjectTableCount;
|
||
|
||
#else
|
||
#define CV_OPEN(nam,acc,pro) open(nam,acc,pro);
|
||
#define CV_READ(hnd,buf,siz) read(hnd, buf, siz);
|
||
#define CV_SEEK(hnd,off,org) _lseek(hnd,off,org);
|
||
#define CV_CLOSE(hnd) close(hnd);
|
||
#define CV_TELL(hnd); tell(hnd);
|
||
#endif
|
||
|
||
/**********************************************************************
|
||
|
||
Symbol table organization
|
||
|
||
Each symbol in the table corresponds to a SYMBOL structure.
|
||
Each structure has the symbol name and offset as well as two
|
||
sets of pointers. Each set of pointers, defined as a NODE,
|
||
consists of parent, left child, and right child pointers to
|
||
the corresponding NODEs of other symbols. The symbol name
|
||
is encoded into a count of leading underscores and a pointer
|
||
to the remaining part of the string. The NODEs of one set
|
||
of all symbols comprise a binary tree. Each NODE set, or
|
||
tree, has a SYMCONTEXT structure. This structure has a
|
||
pointer to the root of the tree, the position of the NODE
|
||
structure within the SYMBOL, and a pointer to a comparison
|
||
routine used to determine the tree order. Two trees exist,
|
||
both using multiple keys.
|
||
|
||
The "offset" tree orders its nodes on:
|
||
1. increasing offsets;
|
||
2. increasing case-insensitive strings;
|
||
3. increasing number of underscores;
|
||
4. increasing case-sensitive strings.
|
||
|
||
The multiple keys are needed since more than one string can
|
||
be associated with an offset.
|
||
|
||
The "string" tree orders its nodes on:
|
||
1. increasing case-insensitive strings;
|
||
2. increasing number of underscores;
|
||
3. increasing module address values;
|
||
4. increasing case-sensitive strings.
|
||
|
||
The case-insensitive/-sensitive searches allow optimal
|
||
matching for case-insensitive input.
|
||
|
||
**********************************************************************/
|
||
|
||
#ifdef KERNEL
|
||
#include <conio.h>
|
||
#undef CONTAINING_RECORD
|
||
#define CONTAINING_RECORD(farptr, type, field) \
|
||
((type far *)((char far *)farptr - (char far *)&((type far *)0)->field))
|
||
#endif
|
||
|
||
void InitSymContext(PPROCESS_INFO);
|
||
|
||
#ifdef NT_HOST
|
||
extern BOOL cdecl cmdHandler(ULONG);
|
||
extern BOOL cdecl waitHandler(ULONG);
|
||
#else
|
||
extern BOOLEAN fJmpBuf;
|
||
void cdecl cmdHandler(void);
|
||
#endif
|
||
|
||
int CompareSymbolOffset(PNODE, PNODE, PBOOLEAN);
|
||
int CompareSymbolString(PNODE, PNODE, PBOOLEAN);
|
||
|
||
int CompareSymfileOffset(PNODE, PNODE, PBOOLEAN);
|
||
int CompareSymfileString(PNODE, PNODE, PBOOLEAN);
|
||
|
||
static PSYMFILE pTempSymfile;
|
||
|
||
#ifdef NT_SAPI
|
||
SYMBOL symbolMax = { 0,0, { NULL, NULL, NULL }, { NULL, NULL, NULL }, -1L,
|
||
0, 0, SYMBOL_TYPE_SYMBOL, NULL,
|
||
{ '\177', '\177', '\0' } };
|
||
SYMBOL structMax = { 0,0, { NULL, NULL, NULL }, { NULL, NULL, NULL }, -1L,
|
||
0, 0, SYMBOL_TYPE_SYMBOL, NULL,
|
||
{ '\177', '\177', '\0' } };
|
||
#else
|
||
SYMBOL symbolMax = { { NULL, NULL, NULL }, { NULL, NULL, NULL }, -1L,
|
||
0, 0, SYMBOL_TYPE_SYMBOL, NULL,
|
||
{ '\177', '\177', '\0' } };
|
||
SYMBOL structMax = { { NULL, NULL, NULL }, { NULL, NULL, NULL }, -1L,
|
||
0, 0, SYMBOL_TYPE_SYMBOL, NULL,
|
||
{ '\177', '\177', '\0' } };
|
||
#endif /* NT_SAPI */
|
||
|
||
UCHAR stringMax[3] = { '\177', '\177', '\0' };
|
||
|
||
SYMFILE symfileMax = { { NULL, NULL, NULL }, { NULL, NULL, NULL },
|
||
"", stringMax, "", 0, NULL, NULL,
|
||
0L, 0L, 0, 0L, 0, 0, NULL, NULL };
|
||
|
||
BOOLEAN fSourceOnly = FALSE;
|
||
BOOLEAN fSourceMixed = FALSE;
|
||
|
||
PSYMFILE pSymfileLast;
|
||
USHORT lineNumberLast;
|
||
|
||
void parseExamine(void);
|
||
void DeferSymbolLoad(PIMAGE_INFO);
|
||
void LoadSymbols(PIMAGE_INFO);
|
||
void PackAuxNameEntry(PUCHAR, ULONG); // TEMP TEMP TEMP
|
||
void UnloadSymbols(PIMAGE_INFO);
|
||
void EnsureModuleSymbolsLoaded(CHAR);
|
||
int EnsureOffsetSymbolsLoaded(ULONG);
|
||
|
||
#ifdef KERNEL
|
||
PUCHAR GetModuleName(PUCHAR);
|
||
extern BOOLEAN KdVerbose;
|
||
#define fVerboseOutput KdVerbose
|
||
#endif
|
||
|
||
PIMAGE_INFO ParseModuleIndex(void);
|
||
PIMAGE_INFO GetModuleIndex(PUCHAR);
|
||
PIMAGE_INFO GetCurrentModuleIndex(void);
|
||
void DumpModuleTable(BOOLEAN);
|
||
|
||
int AccessNode(PSYMCONTEXT, PNODE);
|
||
BOOLEAN InsertNode(PSYMCONTEXT, PNODE);
|
||
void DeleteNode(PSYMCONTEXT, PNODE);
|
||
PNODE NextNode(PSYMCONTEXT, PNODE);
|
||
void JoinTree(PSYMCONTEXT, PNODE);
|
||
int SplitTree(PSYMCONTEXT, PNODE *, PNODE);
|
||
PNODE SplayTree(PNODE);
|
||
void OutputTree(PSYMCONTEXT);
|
||
void OutputSymAddr(ULONG, BOOLEAN, BOOLEAN);
|
||
void GetSymbol(ULONG, PUCHAR, PULONG);
|
||
|
||
void AddLocalToFunction(PSYMBOL, PUCHAR, ULONG, USHORT, ULONG);
|
||
void AddFieldToStructure(PSTRUCT, PUCHAR, ULONG ,USHORT, ULONG);
|
||
PSTRUCT InsertStructure(ULONG, PUCHAR, CHAR);
|
||
PSYMBOL InsertFunction(PUCHAR, ULONG); //, PSYMBOL);
|
||
PSYMBOL InsertSymbol(ULONG, PUCHAR, CHAR);
|
||
PSYMBOL AllocSymbol(ULONG, PUCHAR, CHAR);
|
||
PSTRUCT GetStructFromValue(ULONG, LONG);
|
||
void GetBytesFromFrame(PUCHAR, LONG, USHORT);
|
||
ULONG GetLocalValue(LONG, USHORT, BOOLEAN);
|
||
BOOLEAN GetLocalFromString(PUCHAR, PULONG);
|
||
BOOLEAN GetOffsetFromSym(PUCHAR, PULONG, CHAR);
|
||
BOOLEAN GetOffsetFromString(PUCHAR, PULONG, CHAR);
|
||
PLINENO GetLinenoFromFilename(PUCHAR, PPSYMFILE, USHORT, CHAR);
|
||
PLINENO GetCurrentLineno(PPSYMFILE);
|
||
PLINENO GetLastLineno(PPSYMFILE, PUSHORT);
|
||
PLINENO GetLinenoFromOffset(PPSYMFILE, ULONG);
|
||
void GetLinenoString(PUCHAR, ULONG);
|
||
void GetCurrentMemoryOffsets(PULONG, PULONG);
|
||
void DeleteSymbol(PSYMBOL);
|
||
void DeallocSymbol(PSYMBOL);
|
||
|
||
PSYMFILE InsertSymfile(PUCHAR, PUCHAR, PUCHAR, PIMAGE_LINENUMBER,
|
||
USHORT, ULONG, ULONG, CHAR);
|
||
|
||
PSYMFILE AllocSymfile(PUCHAR, PUCHAR, PUCHAR, PIMAGE_LINENUMBER,
|
||
USHORT, ULONG, ULONG, CHAR);
|
||
|
||
void DeleteSymfile(PSYMFILE);
|
||
void DeallocSymfile(PSYMFILE);
|
||
|
||
int ntsdstricmp(PUCHAR, PUCHAR);
|
||
void fnListNear(ULONG);
|
||
|
||
void SortSrcLinePointers(PSYMFILE);
|
||
//void OutputAtLineno (PSYMFILE, PLINENO);
|
||
void UpdateLineno(PSYMFILE, PLINENO);
|
||
FILE * LocateTextInSource(PSYMFILE, PLINENO);
|
||
void OutputSourceLines(PSYMFILE, USHORT, USHORT);
|
||
BOOLEAN OutputSourceFromOffset(ULONG, BOOLEAN);
|
||
BOOLEAN OutputLines(PSYMFILE, PLINENO, USHORT, USHORT);
|
||
PVOID FetchImageDirectoryEntry(int, USHORT, PULONG, PULONG);
|
||
|
||
|
||
//#ifndef KERNEL
|
||
extern int fControlC;
|
||
//#endif
|
||
#ifndef MIPS
|
||
#ifdef KERNEL
|
||
extern BOOLEAN cdecl _loadds ControlCHandler(void);
|
||
#endif
|
||
#endif
|
||
|
||
extern void RemoveDelChar(PUCHAR);
|
||
extern PIMAGE_INFO pImageFromIndex(UCHAR);
|
||
extern BOOLEAN fLazyLoad;
|
||
extern BOOLEAN fPointerExpression;
|
||
|
||
// State transition arrays for comment processing
|
||
|
||
UCHAR WhiteSpace[] = {
|
||
stStart, stLine, stSlStar, stSlStStar, stSlSlash,
|
||
stLine, stLine, stLSlStar, stLSlStar, stLSlSlash
|
||
};
|
||
|
||
UCHAR Slash[] = {
|
||
stSlash, stSlSlash, stSlStar, stStart, stSlSlash,
|
||
stLSlash, stLSlSlash, stLSlStar, stLine, stLSlSlash
|
||
};
|
||
|
||
UCHAR Star[] = {
|
||
stLine, stSlStar, stSlStStar, stSlStStar, stSlSlash,
|
||
stLine, stLSlStar, stLSlStStar, stSlStStar, stLSlSlash
|
||
};
|
||
|
||
UCHAR Pound[] = {
|
||
stSlSlash, stLine, stSlStar, stSlStar, stSlSlash,
|
||
stLine, stLine, stLSlStar, stLSlStar, stLSlSlash
|
||
};
|
||
|
||
UCHAR OtherChar[] = {
|
||
stLine, stLine, stSlStar, stSlStar, stSlSlash,
|
||
stLine, stLine, stLSlStar, stLSlStar, stLSlSlash
|
||
};
|
||
|
||
UCHAR Return[] = {
|
||
stStart, stStart, stSlStar, stSlStar, stStart,
|
||
stStart, stStart, stSlStar, stSlStar, stStart
|
||
};
|
||
|
||
UCHAR fCommentType[] = {
|
||
TRUE, FALSE, TRUE, TRUE, TRUE,
|
||
FALSE, FALSE, FALSE, FALSE, FALSE
|
||
};
|
||
|
||
////////////////////////////////////////////////////////////////
|
||
|
||
void InitSymContext (PPROCESS_INFO pProcess)
|
||
{
|
||
pProcess->symcontextStructOffset.pNodeRoot = NULL;
|
||
pProcess->symcontextStructOffset.pNodeMax =
|
||
(PNODE)((LONG)&structMax + NODE_SYMBOL_DISPLACEMENT(nodeOffset));
|
||
pProcess->symcontextStructOffset.pfnCompare = &CompareSymbolOffset;
|
||
pProcess->symcontextStructOffset.nodeDisplacement =
|
||
NODE_SYMBOL_DISPLACEMENT(nodeOffset);
|
||
|
||
pProcess->symcontextStructString.pNodeRoot = NULL;
|
||
pProcess->symcontextStructString.pNodeMax =
|
||
(PNODE)((LONG)&structMax + NODE_SYMBOL_DISPLACEMENT(nodeString));
|
||
pProcess->symcontextStructString.pfnCompare = &CompareSymbolString;
|
||
pProcess->symcontextStructString.nodeDisplacement =
|
||
NODE_SYMBOL_DISPLACEMENT(nodeString);
|
||
|
||
pProcess->symcontextSymbolOffset.pNodeRoot = NULL;
|
||
pProcess->symcontextSymbolOffset.pNodeMax =
|
||
(PNODE)((LONG)&symbolMax + NODE_SYMBOL_DISPLACEMENT(nodeOffset));
|
||
pProcess->symcontextSymbolOffset.pfnCompare = &CompareSymbolOffset;
|
||
pProcess->symcontextSymbolOffset.nodeDisplacement =
|
||
NODE_SYMBOL_DISPLACEMENT(nodeOffset);
|
||
|
||
pProcess->symcontextSymbolString.pNodeRoot = NULL;
|
||
pProcess->symcontextSymbolString.pNodeMax =
|
||
(PNODE)((LONG)&symbolMax + NODE_SYMBOL_DISPLACEMENT(nodeString));
|
||
pProcess->symcontextSymbolString.pfnCompare = &CompareSymbolString;
|
||
pProcess->symcontextSymbolString.nodeDisplacement =
|
||
NODE_SYMBOL_DISPLACEMENT(nodeString);
|
||
|
||
pProcess->symcontextSymfileOffset.pNodeRoot = NULL;
|
||
pProcess->symcontextSymfileOffset.pNodeMax =
|
||
(PNODE)((LONG)&symfileMax + NODE_SYMFILE_DISPLACEMENT(nodeOffset));
|
||
pProcess->symcontextSymfileOffset.pfnCompare = &CompareSymfileOffset;
|
||
pProcess->symcontextSymfileOffset.nodeDisplacement =
|
||
NODE_SYMFILE_DISPLACEMENT(nodeOffset);
|
||
|
||
pProcess->symcontextSymfileString.pNodeRoot = NULL;
|
||
pProcess->symcontextSymfileString.pNodeMax =
|
||
(PNODE)((LONG)&symfileMax + NODE_SYMFILE_DISPLACEMENT(nodeString));
|
||
pProcess->symcontextSymfileString.pfnCompare = &CompareSymfileString;
|
||
pProcess->symcontextSymfileString.nodeDisplacement =
|
||
NODE_SYMFILE_DISPLACEMENT(nodeString);
|
||
|
||
pTempSymfile = AllocSymfile("", "", "", NULL, 0, 0, 0, 0);
|
||
}
|
||
|
||
void DeferSymbolLoad (PIMAGE_INFO pImage)
|
||
{
|
||
#ifndef KERNEL
|
||
HANDLE hMapping;
|
||
PVOID lpFileBase;
|
||
PIMAGE_EXPORT_DIRECTORY lpExportDir;
|
||
PIMAGE_DEBUG_DIRECTORY lpDebugDir;
|
||
PIMAGE_DEBUG_INFO lpDebugInfo;
|
||
PIMAGE_SYMBOL lpSymbolEntry;
|
||
PUCHAR lpModName;
|
||
PUCHAR pszName = NULL;
|
||
ULONG exportSize;
|
||
ULONG debugSize;
|
||
ULONG symsize;
|
||
ULONG auxcount;
|
||
ULONG rva;
|
||
PUCHAR pPathname;
|
||
PUCHAR pchName;
|
||
|
||
// open file and process enough to get the image name
|
||
|
||
if (!(hMapping = CreateFileMapping(pImage->hFile, NULL, PAGE_READONLY,
|
||
0L, 0L, NULL)))
|
||
return;
|
||
if (!(lpFileBase = MapViewOfFile(hMapping, FILE_MAP_READ, 0L, 0L, 0L))) {
|
||
CloseHandle(hMapping);
|
||
return;
|
||
}
|
||
|
||
pszName = malloc(32);
|
||
if (!pszName) {
|
||
printf("memory allocation error\n");
|
||
ExitProcess(STATUS_UNSUCCESSFUL);
|
||
}
|
||
|
||
if (pImage->index != 0) {
|
||
rva = (ULONG)RtlImageDirectoryEntryToData(lpFileBase, TRUE,
|
||
IMAGE_DIRECTORY_ENTRY_EXPORT, &exportSize);
|
||
rva -= (ULONG)lpFileBase;
|
||
|
||
lpExportDir = (PIMAGE_EXPORT_DIRECTORY)RtlImageDirectoryEntryToData(
|
||
lpFileBase, FALSE, IMAGE_DIRECTORY_ENTRY_EXPORT, &exportSize);
|
||
|
||
|
||
if (lpExportDir) {
|
||
lpModName = (PUCHAR)((ULONG)lpExportDir + (ULONG)lpExportDir->Name - rva);
|
||
strncpy(pszName, lpModName, 31);
|
||
*(pszName + strcspn(pszName, ".")) = '\0';
|
||
}
|
||
else
|
||
strcpy(pszName, "unknown");
|
||
}
|
||
else {
|
||
|
||
strcpy(pszName, "app");
|
||
|
||
// try to name the main image using the first symbol table
|
||
// entry which contains the path of the first file in it.
|
||
|
||
symsize = IMAGE_SIZEOF_SYMBOL;
|
||
|
||
lpDebugDir = (PIMAGE_DEBUG_DIRECTORY)RtlImageDirectoryEntryToData(
|
||
lpFileBase, FALSE, IMAGE_DIRECTORY_ENTRY_DEBUG, &debugSize);
|
||
|
||
if (lpDebugDir) {
|
||
lpDebugInfo = (PIMAGE_DEBUG_INFO)((ULONG)lpFileBase + lpDebugDir->PointerToRawData);
|
||
lpSymbolEntry = (PIMAGE_SYMBOL)((ULONG)lpDebugInfo
|
||
+ lpDebugInfo->LvaToFirstSymbol);
|
||
auxcount = lpSymbolEntry->NumberOfAuxSymbols;
|
||
|
||
if (lpSymbolEntry->StorageClass == IMAGE_SYM_CLASS_FILE) {
|
||
lpSymbolEntry = (PIMAGE_SYMBOL)
|
||
((PUCHAR)lpSymbolEntry + symsize);
|
||
|
||
// allocate and copy the pathname from the following
|
||
// auxiliary entries.
|
||
|
||
pPathname = malloc((int)(auxcount * symsize + 1));
|
||
if (!pPathname) {
|
||
printf("memory allocation error\n");
|
||
ExitProcess(STATUS_UNSUCCESSFUL);
|
||
}
|
||
memcpy(pPathname, lpSymbolEntry, (int)(auxcount * symsize));
|
||
|
||
// TEMP TEMP TEMP - pack entries 14/18 chars into string
|
||
|
||
// PackAuxNameEntry(pPathname, auxcount);
|
||
|
||
*(pPathname + auxcount * symsize) = '\0'; // TEMP TEMP TEMP
|
||
|
||
// extract the filename from the pathname as the string
|
||
// following the last '\' or ':', but not including any
|
||
// characters after '.'.
|
||
|
||
pchName = strrchr(pPathname, '\\');
|
||
if (!pchName)
|
||
pchName = strrchr(pPathname, ':');
|
||
if (!pchName)
|
||
pchName = pPathname;
|
||
else
|
||
pchName++;
|
||
*(pchName + strcspn(pchName, ".")) = '\0';
|
||
strcpy(pszName, pchName);
|
||
free(pPathname);
|
||
}
|
||
}
|
||
}
|
||
|
||
pImage->pszName = pszName;
|
||
|
||
if (fVerboseOutput)
|
||
dprintf("NTSD: deferring symbol load for \"%s\"\n", pImage->pszName);
|
||
|
||
UnmapViewOfFile(lpFileBase);
|
||
CloseHandle(hMapping);
|
||
#else
|
||
int ImageReadHandle;
|
||
IMAGE_OPTIONAL_HEADER coffOptionalHeader;
|
||
USHORT Signature;
|
||
ULONG DosHeader[16], NtSignature;
|
||
|
||
|
||
if (fVerboseOutput)
|
||
dprintf("KD: deferring symbol load for \"%s\"\n", pImage->pszName);
|
||
|
||
if (pImage->lpBaseOfImage == (PVOID)-1L){
|
||
|
||
#ifdef NT_SAPI
|
||
|
||
SHerror = sheNone;
|
||
ImageReadHandle = (int)pImage->hQCFile;
|
||
|
||
#else
|
||
|
||
ImageReadHandle = CV_OPEN(pImage->pszName, O_RDONLY|O_BINARY, 0);
|
||
if (ImageReadHandle < 0) return;
|
||
|
||
#endif /* NT_SAPI */
|
||
|
||
CV_READ(ImageReadHandle, &Signature, sizeof(USHORT));
|
||
CV_SEEK(ImageReadHandle, 0, SEEK_SET);
|
||
|
||
if (Signature == IMAGE_DOS_SIGNATURE) {
|
||
CV_READ(ImageReadHandle, &DosHeader, 16*sizeof(ULONG));
|
||
CV_SEEK(ImageReadHandle, DosHeader[15], SEEK_SET);
|
||
CV_READ(ImageReadHandle, &NtSignature, sizeof(ULONG));
|
||
if (NtSignature != IMAGE_NT_SIGNATURE) {
|
||
#ifdef NT_SAPI
|
||
SHerror = sheCorruptOmf;
|
||
#else
|
||
dprintf("\nPE signature not found\n");
|
||
#endif
|
||
}
|
||
}
|
||
CV_SEEK(ImageReadHandle, (ULONG)sizeof(IMAGE_FILE_HEADER), SEEK_CUR);
|
||
CV_READ(ImageReadHandle, &coffOptionalHeader,
|
||
sizeof(IMAGE_OPTIONAL_HEADER));
|
||
|
||
#ifndef NT_SAPI
|
||
CV_CLOSE(ImageReadHandle);
|
||
#endif
|
||
|
||
pImage->lpBaseOfImage = (LPVOID)coffOptionalHeader.ImageBase;
|
||
if (fVerboseOutput)
|
||
dprintf("KD: Kernel image at %08lx\n", pImage->lpBaseOfImage);
|
||
}
|
||
#endif
|
||
|
||
}
|
||
|
||
#ifndef KERNEL
|
||
BOOLEAN CountLinenumbers(PIMAGE_INFO pImage)
|
||
{
|
||
HANDLE hMapping;
|
||
PVOID lpFileBase;
|
||
PIMAGE_EXPORT_DIRECTORY lpExportDir;
|
||
PIMAGE_DEBUG_DIRECTORY lpDebugDir;
|
||
PIMAGE_DEBUG_INFO lpDebugInfo;
|
||
PIMAGE_SYMBOL lpSymbolEntry;
|
||
IMAGE_SYMBOL SymbolEntry;
|
||
IMAGE_AUX_SYMBOL AuxSymbolEntry;
|
||
PIMAGE_LINENUMBER lpPointerToLinenumbers;
|
||
PIMAGE_LINENUMBER lpEndPointerToLinenumbers;
|
||
PUCHAR lpStringTable;
|
||
UCHAR ShortString[10];
|
||
ULONG exportSize;
|
||
ULONG debugSize;
|
||
ULONG symsize;
|
||
ULONG index;
|
||
ULONG auxcount;
|
||
ULONG symbolcount = 0;
|
||
ULONG entrycount;
|
||
PSYMBOL pCurrentFunction = NULL;
|
||
PSTRUCT pCurrentStructure = NULL;
|
||
#ifdef MIPS
|
||
PRUNTIME_FUNCTION lpRuntimeFunction;
|
||
PFUNCTION_ENTRY lpFunctionTable;
|
||
ULONG pdataSize = 0L;
|
||
ULONG cFunctions = 0;
|
||
#endif
|
||
PUCHAR pszName = NULL;
|
||
PUCHAR pPathname = NULL;
|
||
PUCHAR pFilename = NULL;
|
||
PUCHAR pExtension = NULL;
|
||
PIMAGE_LINENUMBER pLinenumbers = NULL;
|
||
BOOLEAN nameFound = FALSE;
|
||
BOOLEAN invalidOMF = FALSE;
|
||
ULONG NumberOfLinenumbers;
|
||
ULONG cLines=0L;
|
||
|
||
ShortString[8] = '\0';
|
||
if (!(hMapping = CreateFileMapping(pImage->hFile, NULL, PAGE_READONLY,
|
||
0L, 0L, NULL)))
|
||
return FALSE;
|
||
if (!(lpFileBase = MapViewOfFile(hMapping, FILE_MAP_READ, 0L, 0L, 0L))) {
|
||
CloseHandle(hMapping);
|
||
return FALSE;
|
||
}
|
||
|
||
if (pImage->index != 0) {
|
||
lpExportDir = (PIMAGE_EXPORT_DIRECTORY)RtlImageDirectoryEntryToData(
|
||
lpFileBase, FALSE, IMAGE_DIRECTORY_ENTRY_EXPORT, &exportSize);
|
||
} else
|
||
lpExportDir = NULL;
|
||
|
||
pImage->offsetLow = 0xffffffff;
|
||
pImage->offsetHigh = 0x0;
|
||
|
||
symsize = IMAGE_SIZEOF_SYMBOL;
|
||
|
||
lpDebugDir = (PIMAGE_DEBUG_DIRECTORY)RtlImageDirectoryEntryToData(
|
||
lpFileBase, FALSE, IMAGE_DIRECTORY_ENTRY_DEBUG, &debugSize);
|
||
|
||
// if no debug information, just return TRUE
|
||
|
||
if (!lpDebugDir) {
|
||
UnmapViewOfFile(hMapping);
|
||
CloseHandle(hMapping);
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
lpDebugInfo = (PIMAGE_DEBUG_INFO)((ULONG)lpFileBase + lpDebugDir->PointerToRawData);
|
||
|
||
lpPointerToLinenumbers = (PIMAGE_LINENUMBER)((ULONG)lpDebugInfo +
|
||
+ lpDebugInfo->LvaToFirstLinenumber);
|
||
|
||
// dprintf("Correct # of lines = %ld\n",
|
||
// NumberOfLinenumbers = lpDebugInfo->NumberOfLinenumbers);
|
||
NumberOfLinenumbers = lpDebugInfo->NumberOfLinenumbers;
|
||
|
||
lpSymbolEntry = (PIMAGE_SYMBOL)((ULONG)lpDebugInfo
|
||
+ lpDebugInfo->LvaToFirstSymbol);
|
||
// PDK KLUDGE :::
|
||
lpEndPointerToLinenumbers = (PIMAGE_LINENUMBER)lpSymbolEntry;
|
||
|
||
lpStringTable = (PUCHAR)((ULONG)lpDebugInfo +
|
||
lpDebugInfo->LvaToFirstSymbol +
|
||
lpDebugInfo->NumberOfSymbols * symsize);
|
||
|
||
for (entrycount = 0; entrycount < lpDebugInfo->NumberOfSymbols;
|
||
entrycount++) {
|
||
|
||
memcpy((PUCHAR)&SymbolEntry, lpSymbolEntry, symsize);
|
||
lpSymbolEntry = (PIMAGE_SYMBOL)((PUCHAR)lpSymbolEntry + symsize);
|
||
auxcount = SymbolEntry.NumberOfAuxSymbols;
|
||
|
||
switch (SymbolEntry.StorageClass) {
|
||
|
||
case IMAGE_SYM_CLASS_STATIC:
|
||
|
||
if (SymbolEntry.SectionNumber > 0 &&
|
||
SymbolEntry.Type == IMAGE_SYM_TYPE_NULL &&
|
||
auxcount == 1) {
|
||
index = SymbolEntry.SectionNumber - 1;
|
||
memcpy((PUCHAR)&AuxSymbolEntry, lpSymbolEntry, symsize);
|
||
if (AuxSymbolEntry.Section.Length &&
|
||
AuxSymbolEntry.Section.NumberOfLinenumbers) {
|
||
cLines += (int)AuxSymbolEntry.Section.NumberOfLinenumbers;
|
||
}
|
||
}
|
||
// else
|
||
// dprintf("STATIC class entry\n");
|
||
break;
|
||
|
||
|
||
}
|
||
|
||
// auxcount has the number of auxiliary entries
|
||
// skip over them for the next table entry
|
||
|
||
entrycount += auxcount;
|
||
lpSymbolEntry = (PIMAGE_SYMBOL)
|
||
((PUCHAR)lpSymbolEntry + auxcount * symsize);
|
||
}
|
||
|
||
|
||
// dprintf("Actual # of lines = %ld\n", cLines);
|
||
|
||
UnmapViewOfFile(hMapping);
|
||
CloseHandle(hMapping);
|
||
return ((BOOLEAN)(cLines == NumberOfLinenumbers));
|
||
}
|
||
|
||
|
||
void LoadSymbols (PIMAGE_INFO pImage)
|
||
{
|
||
HANDLE hMapping;
|
||
PVOID lpFileBase;
|
||
PIMAGE_EXPORT_DIRECTORY lpExportDir;
|
||
PIMAGE_DEBUG_DIRECTORY lpDebugDir;
|
||
PIMAGE_DEBUG_INFO lpDebugInfo;
|
||
PIMAGE_SYMBOL lpSymbolEntry;
|
||
IMAGE_SYMBOL SymbolEntry;
|
||
IMAGE_AUX_SYMBOL AuxSymbolEntry;
|
||
PIMAGE_LINENUMBER lpPointerToLinenumbers;
|
||
PIMAGE_LINENUMBER lpEndPointerToLinenumbers;
|
||
IMAGE_LINENUMBER LineNumber;
|
||
PUCHAR lpStringTable;
|
||
PUCHAR lpSymbolName;
|
||
UCHAR ShortString[10];
|
||
ULONG exportSize;
|
||
ULONG debugSize;
|
||
ULONG symsize;
|
||
ULONG index;
|
||
ULONG ind;
|
||
ULONG auxcount;
|
||
ULONG symbolcount = 0;
|
||
ULONG entrycount;
|
||
ULONG SymbolValue;
|
||
ULONG rva;
|
||
PSYMBOL pNewSymbol = NULL;
|
||
PSYMBOL pCurrentFunction = NULL;
|
||
PSTRUCT pCurrentStructure = NULL;
|
||
PULONG pAddrName;
|
||
#ifdef MIPS
|
||
PRUNTIME_FUNCTION lpRuntimeFunction;
|
||
PFUNCTION_ENTRY lpFunctionTable;
|
||
ULONG pdataSize = 0L;
|
||
ULONG cFunctions = 0;
|
||
#endif
|
||
PUCHAR pszName = NULL;
|
||
PUCHAR pPathname = NULL;
|
||
PUCHAR pFilename = NULL;
|
||
PUCHAR pExtension = NULL;
|
||
PIMAGE_LINENUMBER pLinenumbers = NULL;
|
||
PIMAGE_LINENUMBER pLinenumberNext;
|
||
PUCHAR pchName;
|
||
int cName;
|
||
BOOLEAN nameFound = FALSE;
|
||
BOOLEAN invalidOMF = FALSE;
|
||
BOOLEAN validLinenumbers;
|
||
|
||
validLinenumbers = CountLinenumbers(pImage);
|
||
if (!validLinenumbers) {
|
||
dprintf("NTSD: Line count mismatch in %s. Disabling source debugging\n",pImage->pszName);
|
||
// CloseHandle(pImage->hFile);
|
||
// return;
|
||
}
|
||
ShortString[8] = '\0';
|
||
if (!(hMapping = CreateFileMapping(pImage->hFile, NULL, PAGE_READONLY,
|
||
0L, 0L, NULL)))
|
||
return;
|
||
if (!(lpFileBase = MapViewOfFile(hMapping, FILE_MAP_READ, 0L, 0L, 0L))) {
|
||
CloseHandle(hMapping);
|
||
CloseHandle(pImage->hFile);
|
||
return;
|
||
}
|
||
|
||
#ifdef MIPS
|
||
lpRuntimeFunction = (PRUNTIME_FUNCTION)RtlImageDirectoryEntryToData(
|
||
lpFileBase, FALSE, IMAGE_DIRECTORY_ENTRY_EXCEPTION, &pdataSize);
|
||
|
||
if (lpRuntimeFunction) {
|
||
cFunctions = pdataSize / sizeof(RUNTIME_FUNCTION);
|
||
pImage->LowAddress = MAXULONG;
|
||
pImage->HighAddress = 0;
|
||
|
||
lpFunctionTable = (PFUNCTION_ENTRY)
|
||
malloc((int)(cFunctions * sizeof(FUNCTION_ENTRY)));
|
||
if (!lpFunctionTable) {
|
||
dprintf("NTSD: alloc error for exception table\n");
|
||
exit(1);
|
||
}
|
||
pImage->FunctionTable = lpFunctionTable;
|
||
pImage->LowAddress = MAXULONG;
|
||
pImage->HighAddress = 0;
|
||
|
||
for (index = 0; index < cFunctions; index++) {
|
||
if (lpRuntimeFunction->BeginAddress == 0)
|
||
break;
|
||
|
||
lpFunctionTable->StartingAddress = lpRuntimeFunction->BeginAddress;
|
||
if (lpRuntimeFunction->BeginAddress < pImage->LowAddress)
|
||
pImage->LowAddress = lpRuntimeFunction->BeginAddress;
|
||
|
||
lpFunctionTable->EndingAddress = lpRuntimeFunction->EndAddress;
|
||
if (lpRuntimeFunction->EndAddress > pImage->HighAddress)
|
||
pImage->HighAddress = lpRuntimeFunction->EndAddress;
|
||
|
||
lpFunctionTable->EndOfPrologue = lpRuntimeFunction->PrologEndAddress;
|
||
lpRuntimeFunction++;
|
||
lpFunctionTable++;
|
||
}
|
||
}
|
||
pImage->NumberOfFunctions = cFunctions;
|
||
#endif
|
||
|
||
if (pImage->index != 0) {
|
||
rva = (ULONG)RtlImageDirectoryEntryToData(lpFileBase, TRUE,
|
||
IMAGE_DIRECTORY_ENTRY_EXPORT, &exportSize);
|
||
rva -= (ULONG)lpFileBase;
|
||
lpExportDir = (PIMAGE_EXPORT_DIRECTORY)RtlImageDirectoryEntryToData(
|
||
lpFileBase, FALSE, IMAGE_DIRECTORY_ENTRY_EXPORT, &exportSize);
|
||
} else
|
||
lpExportDir = NULL;
|
||
|
||
pImage->offsetLow = 0xffffffff;
|
||
pImage->offsetHigh = 0x0;
|
||
|
||
symsize = IMAGE_SIZEOF_SYMBOL;
|
||
|
||
lpDebugDir = (PIMAGE_DEBUG_DIRECTORY)RtlImageDirectoryEntryToData(
|
||
lpFileBase, FALSE, IMAGE_DIRECTORY_ENTRY_DEBUG, &debugSize);
|
||
|
||
// if no debug information, just close and return
|
||
|
||
if (!lpDebugDir) {
|
||
CloseHandle(hMapping);
|
||
CloseHandle(pImage->hFile);
|
||
return;
|
||
}
|
||
|
||
lpDebugInfo = (PIMAGE_DEBUG_INFO)((ULONG)lpFileBase + lpDebugDir->PointerToRawData);
|
||
|
||
lpPointerToLinenumbers = (PIMAGE_LINENUMBER)((ULONG)lpDebugInfo +
|
||
lpDebugInfo->LvaToFirstLinenumber);
|
||
|
||
lpSymbolEntry = (PIMAGE_SYMBOL)((ULONG)lpDebugInfo +
|
||
lpDebugInfo->LvaToFirstSymbol);
|
||
// PDK KLUDGE :::
|
||
lpEndPointerToLinenumbers = (PIMAGE_LINENUMBER)lpSymbolEntry;
|
||
lpStringTable = (PUCHAR)((ULONG)lpDebugInfo +
|
||
lpDebugInfo->LvaToFirstSymbol +
|
||
lpDebugInfo->NumberOfSymbols * symsize);
|
||
|
||
// dprintf("# lines %lx, # sys %lx\n", lpDebugInfo->NumberOfLinenumbers, lpDebugInfo->NumberOfSymbols);
|
||
|
||
for (entrycount = 0; entrycount < lpDebugInfo->NumberOfSymbols;
|
||
entrycount++) {
|
||
|
||
memcpy((PUCHAR)&SymbolEntry, lpSymbolEntry, symsize);
|
||
lpSymbolEntry = (PIMAGE_SYMBOL)((PUCHAR)lpSymbolEntry + symsize);
|
||
auxcount = SymbolEntry.NumberOfAuxSymbols;
|
||
|
||
switch (SymbolEntry.StorageClass) {
|
||
|
||
case IMAGE_SYM_CLASS_FILE:
|
||
|
||
// allocate and copy the pathname from the following
|
||
// auxiliary entries.
|
||
|
||
pPathname = realloc(pPathname, (int)(auxcount * symsize + 1));
|
||
memcpy(pPathname, lpSymbolEntry, (int)(auxcount * symsize));
|
||
|
||
// TEMP TEMP TEMP - pack entries 14/18 chars into string
|
||
|
||
// PackAuxNameEntry(pPathname, auxcount);
|
||
|
||
*(pPathname + auxcount * symsize) = '\0'; // TEMP TEMP TEMP
|
||
|
||
// extract the filename from the pathname as the string
|
||
// following the last '\' or ':', but not including any
|
||
// characters after '.'.
|
||
|
||
pchName = strrchr(pPathname, '\\');
|
||
if (!pchName)
|
||
pchName = strrchr(pPathname, ':');
|
||
if (!pchName)
|
||
pchName = pPathname;
|
||
else
|
||
pchName++;
|
||
cName = strcspn(pchName, ".");
|
||
|
||
// allocate a string and copy the filename part of the
|
||
// path and convert to lower case.
|
||
|
||
pFilename = realloc(pFilename, cName + 1);
|
||
strncpy(pFilename, pchName, cName);
|
||
*(pFilename + cName) = '\0';
|
||
_strlwr(pFilename);
|
||
|
||
// allocate a string and copy the extension part of the
|
||
// path, if any, and convert to lower case.
|
||
|
||
pExtension = realloc(pExtension, strlen(pchName + cName) + 1);
|
||
strcpy(pExtension, pchName + cName);
|
||
_strlwr(pExtension);
|
||
|
||
// remove filename and extension from pathname by
|
||
// null-terminating at the start of the filename
|
||
// BUT, if null pathname, put in ".\" since a null
|
||
// is interpreted as NO PATH available.
|
||
|
||
if (pchName == pPathname) {
|
||
*pchName++ = '.';
|
||
*pchName++ = '\\';
|
||
}
|
||
*pchName = '\0';
|
||
|
||
break;
|
||
|
||
case IMAGE_SYM_CLASS_STATIC:
|
||
|
||
if (validLinenumbers && SymbolEntry.SectionNumber > 0 &&
|
||
SymbolEntry.Type == IMAGE_SYM_TYPE_NULL &&
|
||
auxcount == 1) {
|
||
index = SymbolEntry.SectionNumber - 1;
|
||
memcpy((PUCHAR)&AuxSymbolEntry, lpSymbolEntry, symsize);
|
||
if (AuxSymbolEntry.Section.Length &&
|
||
AuxSymbolEntry.Section.NumberOfLinenumbers) {
|
||
// PDK KLUDGE :::
|
||
if (((PIMAGE_LINENUMBER)
|
||
((PUCHAR)lpPointerToLinenumbers+
|
||
IMAGE_SIZEOF_LINENUMBER *
|
||
(int)AuxSymbolEntry.Section.NumberOfLinenumbers) >=
|
||
lpEndPointerToLinenumbers)
|
||
|| invalidOMF)
|
||
{
|
||
invalidOMF = TRUE;
|
||
if (fVerboseOutput)
|
||
dprintf("Invalid OMF in %s (%s%s)"
|
||
"-- invalidating rest of image\n",
|
||
pImage->pszName,
|
||
pFilename, pExtension);
|
||
}
|
||
if (!invalidOMF){
|
||
pLinenumbers =
|
||
(PIMAGE_LINENUMBER)realloc((PUCHAR)pLinenumbers,
|
||
IMAGE_SIZEOF_LINENUMBER *
|
||
(int)AuxSymbolEntry.Section.NumberOfLinenumbers);
|
||
pLinenumberNext = pLinenumbers;
|
||
|
||
for (ind = 0; ind < AuxSymbolEntry.Section.NumberOfLinenumbers;
|
||
ind++) {
|
||
memcpy((PUCHAR)&LineNumber,
|
||
(PUCHAR)lpPointerToLinenumbers,
|
||
IMAGE_SIZEOF_LINENUMBER);
|
||
LineNumber.Type.VirtualAddress +=
|
||
(ULONG)pImage->lpBaseOfImage;
|
||
memcpy((PUCHAR)pLinenumberNext,
|
||
(PUCHAR)&LineNumber,
|
||
IMAGE_SIZEOF_LINENUMBER);
|
||
lpPointerToLinenumbers = (PIMAGE_LINENUMBER)
|
||
((PUCHAR)lpPointerToLinenumbers +
|
||
IMAGE_SIZEOF_LINENUMBER);
|
||
pLinenumberNext = (PIMAGE_LINENUMBER)
|
||
((PUCHAR)pLinenumberNext +
|
||
IMAGE_SIZEOF_LINENUMBER);
|
||
}
|
||
//////////
|
||
// memcpy((PUCHAR)pLinenumbers,
|
||
// (PUCHAR)(lpPointerToLinenumbers),
|
||
// IMAGE_SIZEOF_LINENUMBER
|
||
// * (int)AuxSymbolEntry.Section.NumberOfLinenumbers);
|
||
//
|
||
// for (ind = 0; ind < AuxSymbolEntry.Section.NumberOfLinenumbers;
|
||
// ind++)
|
||
// ((PIMAGE_LINENUMBER)((PUCHAR)pLinenumbers
|
||
// + IMAGE_SIZEOF_LINENUMBER * ind))->
|
||
// Type.VirtualAddress +=
|
||
// (ULONG)pImage->lpBaseOfImage;
|
||
//
|
||
// lpPointerToLinenumbers = (PIMAGE_LINENUMBER)
|
||
// ((PUCHAR)lpPointerToLinenumbers
|
||
// + IMAGE_SIZEOF_LINENUMBER
|
||
// * AuxSymbolEntry.Section.NumberOfLinenumbers);
|
||
///////////
|
||
}
|
||
InsertSymfile(pPathname, pFilename, pExtension,
|
||
(PIMAGE_LINENUMBER)(invalidOMF ? NULL : pLinenumbers),
|
||
(USHORT)(invalidOMF ? 0 : AuxSymbolEntry.Section.NumberOfLinenumbers),
|
||
SymbolEntry.Value + (ULONG)pImage->lpBaseOfImage,
|
||
SymbolEntry.Value + (ULONG)pImage->lpBaseOfImage
|
||
+ AuxSymbolEntry.Section.Length,
|
||
pImage->index);
|
||
|
||
#if 0
|
||
dprintf("\npath: <%s> file: <%s> ext: <%s> "
|
||
"start: %08lx end: %08lx\n",
|
||
pPathname, pFilename, pExtension,
|
||
SymbolEntry.Value + (ULONG)pImage->lpBaseOfImage,
|
||
SymbolEntry.Value + (ULONG)pImage->lpBaseOfImage
|
||
+ AuxSymbolEntry.Section.Length);
|
||
dprintf("section %ld - length: %lx "
|
||
"line number cnt: %d\n", index,
|
||
AuxSymbolEntry.Section.Length,
|
||
AuxSymbolEntry.Section.NumberOfLinenumbers);
|
||
|
||
for (index = 0; index < AuxSymbolEntry.Section.NumberOfLinenumbers;
|
||
index++)
|
||
dprintf("index %ld, address: %08lx, "
|
||
"line number %d\n", index,
|
||
((PIMAGE_LINENUMBER)((PUCHAR)pLinenumbers
|
||
+ index * IMAGE_SIZEOF_LINENUMBER))->
|
||
Type.VirtualAddress,
|
||
((PIMAGE_LINENUMBER)((PUCHAR)pLinenumbers
|
||
+ index * IMAGE_SIZEOF_LINENUMBER))->
|
||
Linenumber);
|
||
#endif
|
||
}
|
||
}
|
||
// else
|
||
// dprintf("STATIC class entry\n");
|
||
break;
|
||
|
||
case IMAGE_SYM_CLASS_FUNCTION:
|
||
if (SymbolEntry.N.Name.Short) {
|
||
strncpy(ShortString, SymbolEntry.N.ShortName, 8);
|
||
ShortString[8] = '\0';
|
||
lpSymbolName = ShortString;
|
||
}
|
||
else
|
||
lpSymbolName = lpStringTable + SymbolEntry.N.Name.Long;
|
||
|
||
if (SymbolEntry.Value && pNewSymbol) {
|
||
SymbolValue = SymbolEntry.Value + (ULONG)pImage->lpBaseOfImage;
|
||
// dprintf("[FUNCTION:%s, val=%08lx, ",pNewSymbol->string,
|
||
// pNewSymbol->offset);
|
||
pCurrentFunction =
|
||
InsertFunction(pNewSymbol->string, pNewSymbol->offset);
|
||
|
||
// dprintf(pCurrentFunction ? "Inserted]\n"
|
||
// : "Insertion failed]\n");
|
||
}
|
||
break;
|
||
|
||
case IMAGE_SYM_CLASS_AUTOMATIC:
|
||
case IMAGE_SYM_CLASS_ARGUMENT:
|
||
case IMAGE_SYM_CLASS_REGISTER:
|
||
case IMAGE_SYM_CLASS_MEMBER_OF_STRUCT:{
|
||
ULONG auxValue;
|
||
|
||
if (SymbolEntry.N.Name.Short) {
|
||
strncpy(ShortString, SymbolEntry.N.ShortName, 8);
|
||
ShortString[8] = '\0';
|
||
lpSymbolName = ShortString;
|
||
}
|
||
else{
|
||
if (!SymbolEntry.N.Name.Long) break;
|
||
lpSymbolName = lpStringTable + SymbolEntry.N.Name.Long;
|
||
}
|
||
|
||
SymbolValue = SymbolEntry.Value;
|
||
|
||
if (SymbolEntry.Type==IMAGE_SYM_TYPE_STRUCT){
|
||
if (!auxcount) break; // Error in COFF
|
||
auxValue = *((PULONG)lpSymbolEntry);
|
||
}
|
||
|
||
if(SymbolEntry.StorageClass!=IMAGE_SYM_CLASS_MEMBER_OF_STRUCT){
|
||
// dprintf("\t[LOCAL:%s, value=%ld, aux=%lx]\n",
|
||
// lpSymbolName, SymbolValue, auxValue);
|
||
AddLocalToFunction(pCurrentFunction, lpSymbolName,
|
||
SymbolValue, SymbolEntry.Type, auxValue);
|
||
}
|
||
else{
|
||
// dprintf("\t[FIELD:%s, type=%ld, value=%ld, aux=%lx]\n",
|
||
// lpSymbolName, SymbolEntry.Type, SymbolValue,
|
||
// auxValue);
|
||
AddFieldToStructure(pCurrentStructure, lpSymbolName,
|
||
SymbolValue,SymbolEntry.Type, auxValue);
|
||
}
|
||
}
|
||
break;
|
||
|
||
case IMAGE_SYM_CLASS_STRUCT_TAG:
|
||
if (SymbolEntry.N.Name.Short) {
|
||
strncpy(ShortString, SymbolEntry.N.ShortName, 8);
|
||
ShortString[8] = '\0';
|
||
lpSymbolName = ShortString;
|
||
}
|
||
else
|
||
lpSymbolName = lpStringTable + SymbolEntry.N.Name.Long;
|
||
|
||
//dprintf("[STRUCT#%ld:%s \n",entrycount, lpSymbolName);
|
||
pCurrentStructure = InsertStructure(entrycount,
|
||
lpSymbolName,
|
||
pImage->index);
|
||
//dprintf(pCurrentStructure?"Inserted]\n":"Insertion failed]\n");
|
||
break;
|
||
|
||
case IMAGE_SYM_CLASS_EXTERNAL:
|
||
if (SymbolEntry.N.Name.Short) {
|
||
strncpy(ShortString, SymbolEntry.N.ShortName, 8);
|
||
ShortString[8] = '\0';
|
||
lpSymbolName = ShortString;
|
||
}
|
||
else
|
||
lpSymbolName = lpStringTable + SymbolEntry.N.Name.Long;
|
||
|
||
if (SymbolEntry.Value) {
|
||
SymbolValue = SymbolEntry.Value + (ULONG)pImage->lpBaseOfImage;
|
||
// dprintf("sym %s value %lx entryc %lx\n", lpSymbolName, SymbolValue, entrycount);
|
||
pNewSymbol = InsertSymbol(SymbolValue, lpSymbolName,
|
||
pImage->index);
|
||
if (pNewSymbol) {
|
||
if (SymbolValue > pImage->offsetHigh)
|
||
pImage->offsetHigh = SymbolValue;
|
||
if (SymbolValue < pImage->offsetLow)
|
||
pImage->offsetLow = SymbolValue;
|
||
symbolcount++;
|
||
if (fVerboseOutput && symbolcount % 100 == 0)
|
||
dprintf("NTSD: module \"%s\" loaded "
|
||
"%ld symbols\r",
|
||
pszName, symbolcount);
|
||
}
|
||
}
|
||
break;
|
||
default:
|
||
// dprintf("OTHER class entry - class: %d\n",
|
||
// SymbolEntry.StorageClass);
|
||
break;
|
||
}
|
||
|
||
// auxcount has the number of auxiliary entries
|
||
// skip over them for the next table entry
|
||
|
||
entrycount += auxcount;
|
||
lpSymbolEntry = (PIMAGE_SYMBOL)
|
||
((PUCHAR)lpSymbolEntry + auxcount * symsize);
|
||
}
|
||
|
||
if (fVerboseOutput)
|
||
#ifdef MIPS
|
||
dprintf("NTSD: \"%s\" loaded %ld symbols, "
|
||
"%ld functions (%08lx-%08lx)\n",
|
||
pImage->pszName, symbolcount, pImage->NumberOfFunctions,
|
||
pImage->offsetLow, pImage->offsetHigh);
|
||
#else
|
||
dprintf("NTSD: \"%s\" loaded %ld symbols (%08lx-%08lx)\n",
|
||
pImage->pszName, symbolcount,
|
||
pImage->offsetLow, pImage->offsetHigh);
|
||
#endif
|
||
|
||
if (fVerboseOutput || !fLazyLoad)
|
||
dprintf("NTSD: loading symbols for \"%s\"\n", pImage->pszName);
|
||
|
||
if (lpExportDir) {
|
||
ULONG offset;
|
||
PSYMBOL pSymbol;
|
||
|
||
entrycount= lpExportDir->NumberOfNames;
|
||
|
||
pAddrName = (PULONG)((ULONG)lpExportDir
|
||
+ (ULONG)lpExportDir->AddressOfNames - rva);
|
||
|
||
for (index = 0; index < entrycount; index++) {
|
||
pszName = (PUCHAR)((ULONG)lpExportDir + *pAddrName++ - rva);
|
||
//dprintf("\t%ld:%s\n", index, pszName);
|
||
|
||
if (GetOffsetFromString(pszName, &offset, pImage->index)) {
|
||
pSymbol = PNODE_TO_PSYMBOL
|
||
(pProcessCurrent->symcontextSymbolString.pNodeRoot,
|
||
&(pProcessCurrent->symcontextSymbolString));
|
||
pSymbol->type = SYMBOL_TYPE_EXPORT;
|
||
}
|
||
else
|
||
dprintf("NTSD: error exporting non-existent symbol\n");
|
||
}
|
||
}
|
||
|
||
// free pointers to reallocated strings
|
||
|
||
free(pExtension);
|
||
free(pFilename);
|
||
free(pPathname);
|
||
free(pLinenumbers);
|
||
|
||
UnmapViewOfFile(hMapping);
|
||
CloseHandle(hMapping);
|
||
CloseHandle(pImage->hFile);
|
||
}
|
||
#endif
|
||
|
||
#ifdef KERNEL
|
||
void LoadSymbols (PIMAGE_INFO pImage)
|
||
{
|
||
PSZ SymbolName;
|
||
ULONG entrycount;
|
||
ULONG auxcount;
|
||
ULONG SymbolValue;
|
||
UCHAR ShortString[10];
|
||
IMAGE_SYMBOL SymbolEntry;
|
||
IMAGE_AUX_SYMBOL AuxSymbolEntry;
|
||
#ifdef MIPS
|
||
RUNTIME_FUNCTION RuntimeFunction;
|
||
PFUNCTION_ENTRY lpFunctionEntry;
|
||
ULONG pdataSize = 0L;
|
||
ULONG pdataStart;
|
||
ULONG cFunctions = 0;
|
||
ULONG junk;
|
||
#endif
|
||
ULONG StringTableSize;
|
||
char huge * StringTable = NULL;
|
||
ULONG Base;
|
||
ULONG HdrBase;
|
||
ULONG BaseOffset = 0;
|
||
int symsize;
|
||
int ImageReadHandle;
|
||
PUCHAR pszName;
|
||
PSYMBOL pNewSymbol = NULL;
|
||
PSYMBOL pCurrentFunction = NULL;
|
||
PSTRUCT pCurrentStructure = NULL;
|
||
ULONG symbolcount = 0;
|
||
ULONG index;
|
||
ULONG ind;
|
||
PUCHAR pPathname = NULL;
|
||
PUCHAR pFilename = NULL;
|
||
PUCHAR pExtension = NULL;
|
||
ULONG pNextLinenumber;
|
||
ULONG debugSize;
|
||
IMAGE_DEBUG_DIRECTORY DebugDir;
|
||
IMAGE_DEBUG_INFO DebugInfo;
|
||
ULONG StartDebugInfo;
|
||
PIMAGE_LINENUMBER pLinenumbers = NULL;
|
||
PUCHAR pchName;
|
||
int cName;
|
||
ULONG seekSave;
|
||
|
||
unsigned int n;
|
||
unsigned int maxr;
|
||
unsigned long needr;
|
||
char huge * p;
|
||
char buff[128];
|
||
|
||
#ifdef NT_SAPI
|
||
|
||
SHerror = sheNone;
|
||
ImageReadHandle = pImage->hQCFile;
|
||
|
||
if ( pImage->IgnoreSymbols ) {
|
||
SHerror = sheNoSymbols;
|
||
return;
|
||
}
|
||
#else
|
||
|
||
ImageReadHandle = CV_OPEN(pImage->pszName, O_RDONLY | O_BINARY, 0);
|
||
if (ImageReadHandle < 0) return;
|
||
|
||
#endif /* NT_SAPI */
|
||
|
||
if (fLazyLoad && fVerboseOutput)
|
||
dprintf("KD: Loading \"%s\" (previously deferred)\n", pImage->pszName);
|
||
|
||
seekSave = (ULONG)FetchImageDirectoryEntry(ImageReadHandle,
|
||
IMAGE_DIRECTORY_ENTRY_DEBUG, &debugSize, &HdrBase);
|
||
|
||
if (!seekSave) {
|
||
#ifdef NT_SAPI
|
||
SHerror = sheBadDirectory;
|
||
#endif
|
||
return;
|
||
}
|
||
|
||
CV_SEEK(ImageReadHandle, seekSave, SEEK_SET);
|
||
CV_READ(ImageReadHandle, &DebugDir, sizeof(IMAGE_DEBUG_DIRECTORY));
|
||
|
||
StartDebugInfo = DebugDir.PointerToRawData;
|
||
CV_SEEK(ImageReadHandle, StartDebugInfo, SEEK_SET);
|
||
CV_READ(ImageReadHandle, &DebugInfo, sizeof(IMAGE_DEBUG_INFO));
|
||
|
||
pNextLinenumber = (StartDebugInfo + DebugInfo.LvaToFirstLinenumber);
|
||
|
||
#ifdef MIPS
|
||
if (pdataSize == 0) {
|
||
pdataStart = (ULONG)FetchImageDirectoryEntry(ImageReadHandle,
|
||
IMAGE_DIRECTORY_ENTRY_EXCEPTION, &pdataSize, &junk);
|
||
}
|
||
#endif
|
||
|
||
if (HdrBase) {
|
||
if (pImage->lpBaseOfImage) {
|
||
Base = (ULONG)pImage->lpBaseOfImage;
|
||
} else {
|
||
Base = HdrBase;
|
||
}
|
||
}
|
||
|
||
BaseOffset = Base - HdrBase;
|
||
|
||
#ifdef MIPS
|
||
if (pdataSize) {
|
||
cFunctions = pdataSize / sizeof(RUNTIME_FUNCTION);
|
||
lpFunctionEntry = (PFUNCTION_ENTRY)
|
||
malloc((int)(cFunctions * sizeof(FUNCTION_ENTRY)));
|
||
if (!lpFunctionEntry) {
|
||
dprintf("KD: alloc error for exception table\n");
|
||
exit(1);
|
||
}
|
||
pImage->FunctionTable = lpFunctionEntry;
|
||
pImage->LowAddress = MAXULONG;
|
||
pImage->HighAddress = 0;
|
||
|
||
CV_SEEK(ImageReadHandle, pdataStart, SEEK_SET);
|
||
|
||
for (index = 0; index < cFunctions; index++) {
|
||
CV_READ(ImageReadHandle, (PUCHAR)&RuntimeFunction,
|
||
sizeof(RUNTIME_FUNCTION));
|
||
if (RuntimeFunction.BeginAddress == 0)
|
||
break;
|
||
|
||
//
|
||
// Update the addresses with the new base address for the image.
|
||
//
|
||
|
||
RuntimeFunction.BeginAddress += BaseOffset;
|
||
RuntimeFunction.PrologEndAddress += BaseOffset;
|
||
RuntimeFunction.EndAddress += BaseOffset;
|
||
|
||
lpFunctionEntry[index].StartingAddress =
|
||
RuntimeFunction.BeginAddress;
|
||
if (RuntimeFunction.BeginAddress < pImage->LowAddress)
|
||
pImage->LowAddress = RuntimeFunction.BeginAddress;
|
||
|
||
lpFunctionEntry[index].EndingAddress = RuntimeFunction.EndAddress;
|
||
if (RuntimeFunction.EndAddress > pImage->HighAddress)
|
||
pImage->HighAddress = RuntimeFunction.EndAddress;
|
||
|
||
lpFunctionEntry[index].EndOfPrologue =
|
||
RuntimeFunction.PrologEndAddress;
|
||
}
|
||
}
|
||
|
||
pImage->NumberOfFunctions = cFunctions;
|
||
|
||
#endif
|
||
|
||
symsize = IMAGE_SIZEOF_SYMBOL;
|
||
|
||
CV_SEEK(ImageReadHandle, StartDebugInfo + DebugInfo.LvaToFirstSymbol
|
||
+ DebugInfo.NumberOfSymbols * symsize, SEEK_SET);
|
||
|
||
CV_READ(ImageReadHandle, (PUCHAR)&StringTableSize, sizeof(ULONG));
|
||
if (StringTableSize > sizeof(ULONG)) {
|
||
|
||
#ifdef NT_HOST
|
||
// BUGBUG - W-Barry - 30-Apr-91 - Replacing call to halloc with a call
|
||
// to calloc. Halloc seems to be no longer in the 32-bit libraries.
|
||
|
||
if (!(StringTable = (PUCHAR)calloc(StringTableSize, 1))) {
|
||
#else
|
||
if (!(StringTable = (PUCHAR)halloc(StringTableSize, 1))) {
|
||
#endif
|
||
#ifdef NT_SAPI
|
||
SHerror = sheOutOfMemory;
|
||
return;
|
||
#else
|
||
dprintf("KD: alloc error for string table\n");
|
||
exit(1);
|
||
#endif
|
||
}
|
||
needr = StringTableSize - sizeof(ULONG);
|
||
p = StringTable;
|
||
while (needr) {
|
||
maxr = (unsigned int)min(needr, 0x8000);
|
||
n = CV_READ(ImageReadHandle, (char far *)p, maxr);
|
||
p += n;
|
||
needr -= n;
|
||
}
|
||
StringTable -= sizeof(ULONG);
|
||
}
|
||
|
||
// convert the name from the full path to only the filename
|
||
|
||
pszName = GetModuleName(pImage->pszName);
|
||
free(pImage->pszName); // remove entry pathname
|
||
pImage->pszName = pszName;
|
||
|
||
pImage->offsetLow = 0xffffffff;
|
||
pImage->offsetHigh = 0x0;
|
||
|
||
// seek to start of symbol table and read each entry
|
||
|
||
CV_SEEK(ImageReadHandle, StartDebugInfo + DebugInfo.LvaToFirstSymbol, SEEK_SET);
|
||
|
||
for (entrycount = 0; entrycount < DebugInfo.NumberOfSymbols;
|
||
entrycount++) {
|
||
CV_READ(ImageReadHandle, (PUCHAR)&SymbolEntry, symsize);
|
||
auxcount = SymbolEntry.NumberOfAuxSymbols;
|
||
|
||
switch (SymbolEntry.StorageClass) {
|
||
case IMAGE_SYM_CLASS_FILE:
|
||
|
||
// allocate and read the pathname from the following
|
||
// auxiliary entries.
|
||
|
||
pPathname = realloc(pPathname, (int)(auxcount * symsize + 1));
|
||
CV_READ(ImageReadHandle, pPathname, (int)(auxcount * symsize));
|
||
|
||
// TEMP TEMP TEMP - pack entries 14/18 chars into string
|
||
|
||
// PackAuxNameEntry(pPathname, auxcount);
|
||
|
||
*(pPathname + auxcount * symsize) = '\0'; // TEMP TEMP TEMP
|
||
entrycount += auxcount;
|
||
auxcount = 0;
|
||
|
||
// extract the filename from the pathname as the string
|
||
// following the last '\' or ':', but not including any
|
||
// characters after '.'.
|
||
|
||
pchName = strrchr(pPathname, '\\');
|
||
if (!pchName)
|
||
pchName = strrchr(pPathname, ':');
|
||
if (!pchName)
|
||
pchName = pPathname;
|
||
else
|
||
pchName++;
|
||
cName = strcspn(pchName, ".");
|
||
|
||
// allocate a string and copy the filename part of the
|
||
// path and convert to lower case.
|
||
|
||
pFilename = realloc(pFilename, cName + 1);
|
||
strncpy(pFilename, pchName, cName);
|
||
*(pFilename + cName) = '\0';
|
||
_strlwr(pFilename);
|
||
|
||
// allocate a string and copy the extension part of the
|
||
// path, if any, and convert to lower case.
|
||
|
||
pExtension = realloc(pExtension, strlen(pchName + cName) + 1);
|
||
strcpy(pExtension, pchName + cName);
|
||
_strlwr(pExtension);
|
||
|
||
// remove filename and extension from pathname by
|
||
// null-terminating at the start of the filename
|
||
// BUT, if null pathname, put in ".\" since a null
|
||
// is interpreted as NO PATH available.
|
||
|
||
if (pchName == pPathname) {
|
||
*pchName++ = '.';
|
||
*pchName++ = '\\';
|
||
}
|
||
*pchName = '\0';
|
||
|
||
break;
|
||
|
||
case IMAGE_SYM_CLASS_STATIC:
|
||
|
||
if ( SymbolEntry.SectionNumber > 0 &&
|
||
SymbolEntry.Type == IMAGE_SYM_TYPE_NULL &&
|
||
auxcount == 1) {
|
||
index = SymbolEntry.SectionNumber - 1;
|
||
CV_READ(ImageReadHandle, (PUCHAR)&AuxSymbolEntry, symsize);
|
||
entrycount += auxcount;
|
||
auxcount = 0;
|
||
if (AuxSymbolEntry.Section.Length &&
|
||
AuxSymbolEntry.Section.NumberOfLinenumbers) {
|
||
|
||
seekSave = CV_TELL(ImageReadHandle);
|
||
CV_SEEK(ImageReadHandle, pNextLinenumber, SEEK_SET);
|
||
pLinenumbers = (PIMAGE_LINENUMBER)realloc(
|
||
(PUCHAR)pLinenumbers,
|
||
sizeof(IMAGE_LINENUMBER) *
|
||
(int)AuxSymbolEntry.Section.NumberOfLinenumbers);
|
||
CV_READ(ImageReadHandle, (PUCHAR)pLinenumbers,
|
||
sizeof(IMAGE_LINENUMBER)
|
||
* (int)AuxSymbolEntry.Section.NumberOfLinenumbers);
|
||
pNextLinenumber = CV_TELL(ImageReadHandle);
|
||
for (ind = 0; ind < AuxSymbolEntry.Section.NumberOfLinenumbers;
|
||
ind++)
|
||
pLinenumbers[ind].Type.VirtualAddress
|
||
+= Base;
|
||
InsertSymfile(pPathname, pFilename, pExtension,
|
||
pLinenumbers,
|
||
AuxSymbolEntry.Section.NumberOfLinenumbers,
|
||
SymbolEntry.Value + Base,
|
||
SymbolEntry.Value + Base
|
||
+ AuxSymbolEntry.Section.Length,
|
||
pImage->index);
|
||
|
||
////////////////
|
||
#if 0
|
||
dprintf("\npath: <%s> file: <%s> ext: <%s> "
|
||
"start: %08lx end: %08lx\n",
|
||
pPathname, pFilename, pExtension,
|
||
SymbolEntry.Value,
|
||
SymbolEntry.Value
|
||
+ AuxSymbolEntry.Section.Length);
|
||
dprintf("section %ld - length: %lx "
|
||
"line number cnt: %d\n",
|
||
index, AuxSymbolEntry.Section.Length,
|
||
AuxSymbolEntry.Section.NumberOfLinenumbers);
|
||
|
||
for (index = 0; index < AuxSymbolEntry.Section.NumberOfLinenumbers;
|
||
index++)
|
||
dprintf("index %ld, address: %08lx, "
|
||
"line number %d\n", index,
|
||
(pLinenumbers + index)->
|
||
Type.VirtualAddress,
|
||
(pLinenumbers + index)->Linenumber);
|
||
#endif
|
||
/////////////////
|
||
CV_SEEK(ImageReadHandle, seekSave, SEEK_SET);
|
||
}
|
||
}
|
||
// else
|
||
// dprintf("STATIC class entry\n");
|
||
break;
|
||
|
||
case IMAGE_SYM_CLASS_EXTERNAL:
|
||
if (SymbolEntry.N.Name.Short) {
|
||
strncpy(ShortString, SymbolEntry.N.ShortName, 8);
|
||
ShortString[8] = '\0';
|
||
SymbolName = ShortString;
|
||
}
|
||
else {
|
||
//
|
||
// if this is a huge string table and the symbol
|
||
// is near a 64k boundary, then copy it by hand;
|
||
//
|
||
if (StringTableSize & 0xffff0000) {
|
||
p = StringTable + SymbolEntry.N.Name.Long;
|
||
if ((ULONG)((ULONG)p & 0x0000ff00) == 0x0000ff00) {
|
||
SymbolName = buff;
|
||
while (*p)
|
||
*SymbolName++ = *p++;
|
||
*SymbolName = '\0';
|
||
SymbolName = buff;
|
||
}
|
||
else
|
||
SymbolName = p;
|
||
}
|
||
else
|
||
SymbolName = StringTable + SymbolEntry.N.Name.Long;
|
||
}
|
||
|
||
if (SymbolEntry.Value) {
|
||
SymbolValue = SymbolEntry.Value + Base;
|
||
pNewSymbol = InsertSymbol(SymbolValue, SymbolName,
|
||
pImage->index);
|
||
#ifdef NT_SAPI
|
||
if (pNewSymbol) {
|
||
|
||
if (auxcount) {
|
||
entrycount++;
|
||
auxcount--;
|
||
CV_READ(ImageReadHandle,&AuxSymbolEntry,symsize);
|
||
}
|
||
|
||
else
|
||
memset( &AuxSymbolEntry, 0, symsize);
|
||
|
||
TH_SetupCVpublic( pImage, pNewSymbol,
|
||
&SymbolEntry, &AuxSymbolEntry);
|
||
}
|
||
|
||
#endif /* NT_SAPI */
|
||
|
||
if (SymbolValue > pImage->offsetHigh)
|
||
pImage->offsetHigh = SymbolValue;
|
||
if (SymbolValue < pImage->offsetLow)
|
||
pImage->offsetLow = SymbolValue;
|
||
|
||
symbolcount++;
|
||
// dprintf("mod: %s value: %08lx symbol: %s\n",
|
||
// pszName, SymbolValue, SymbolName);
|
||
// if (symbolcount % 100 == 0)
|
||
// dprintf("KD: module \"%s\" loaded %ld "
|
||
// "symbols\r", pszName, symbolcount);
|
||
}
|
||
break;
|
||
|
||
case IMAGE_SYM_CLASS_STRUCT_TAG:
|
||
if (SymbolEntry.N.Name.Short) {
|
||
strncpy(ShortString, SymbolEntry.N.ShortName, 8);
|
||
ShortString[8] = '\0';
|
||
SymbolName = ShortString;
|
||
}
|
||
else {
|
||
if (StringTableSize & 0xffff0000) {
|
||
p = StringTable + SymbolEntry.N.Name.Long;
|
||
if ((ULONG)((ULONG)p & 0x0000ff00) == 0x0000ff00) {
|
||
SymbolName = buff;
|
||
while (*p)
|
||
*SymbolName++ = *p++;
|
||
*SymbolName = '\0';
|
||
SymbolName = buff;
|
||
}
|
||
else
|
||
SymbolName = p;
|
||
}
|
||
else
|
||
SymbolName = StringTable + SymbolEntry.N.Name.Long;
|
||
}
|
||
|
||
pCurrentStructure = InsertStructure(entrycount,SymbolName,
|
||
pImage->index);
|
||
|
||
|
||
break;
|
||
|
||
case IMAGE_SYM_CLASS_FUNCTION:
|
||
if (SymbolEntry.N.Name.Short) {
|
||
strncpy(ShortString, SymbolEntry.N.ShortName, 8);
|
||
ShortString[8] = '\0';
|
||
SymbolName = ShortString;
|
||
}
|
||
else {
|
||
if (StringTableSize & 0xffff0000) {
|
||
p = StringTable + SymbolEntry.N.Name.Long;
|
||
if ((ULONG)((ULONG)p & 0x0000ff00) == 0x0000ff00) {
|
||
SymbolName = buff;
|
||
while (*p)
|
||
*SymbolName++ = *p++;
|
||
*SymbolName = '\0';
|
||
SymbolName = buff;
|
||
}
|
||
else
|
||
SymbolName = p;
|
||
}
|
||
else
|
||
SymbolName = StringTable + SymbolEntry.N.Name.Long;
|
||
}
|
||
|
||
if (strcmp(SymbolName,".bf")) {
|
||
#ifdef NT_SAPI
|
||
// End of Function setup CV types!!
|
||
if ( pCurrentFunction && pNewSymbol)
|
||
TH_SetupCVfunction( pImage,
|
||
pCurrentFunction,
|
||
pNewSymbol);
|
||
#endif /* NT_SAPI */
|
||
break;
|
||
}
|
||
|
||
if (SymbolEntry.Value && pNewSymbol) {
|
||
SymbolValue = SymbolEntry.Value +
|
||
(ULONG)pImage->lpBaseOfImage;
|
||
|
||
pCurrentFunction =
|
||
InsertFunction(pNewSymbol->string, pNewSymbol->offset);
|
||
|
||
|
||
}
|
||
break;
|
||
|
||
case IMAGE_SYM_CLASS_AUTOMATIC:
|
||
case IMAGE_SYM_CLASS_ARGUMENT:
|
||
case IMAGE_SYM_CLASS_REGISTER:
|
||
case IMAGE_SYM_CLASS_MEMBER_OF_STRUCT:{
|
||
ULONG auxValue;
|
||
|
||
if (SymbolEntry.Value==-1L) break;
|
||
if (SymbolEntry.N.Name.Short) {
|
||
strncpy(ShortString, SymbolEntry.N.ShortName, 8);
|
||
ShortString[8] = '\0';
|
||
SymbolName = ShortString;
|
||
}
|
||
else {
|
||
if (!SymbolEntry.N.Name.Long) break;
|
||
if (StringTableSize & 0xffff0000) {
|
||
p = StringTable + SymbolEntry.N.Name.Long;
|
||
if ((ULONG)((ULONG)p & 0x0000ff00) == 0x0000ff00) {
|
||
SymbolName = buff;
|
||
while (*p)
|
||
*SymbolName++ = *p++;
|
||
*SymbolName = '\0';
|
||
SymbolName = buff;
|
||
}
|
||
else
|
||
SymbolName = p;
|
||
}
|
||
else
|
||
SymbolName = StringTable + SymbolEntry.N.Name.Long;
|
||
}
|
||
|
||
|
||
// If we have a aux entry read it in, otherwise zero it
|
||
if (auxcount) {
|
||
entrycount++;
|
||
auxcount--;
|
||
CV_READ(ImageReadHandle, &AuxSymbolEntry, symsize);
|
||
}
|
||
|
||
else
|
||
memset( &AuxSymbolEntry, 0, symsize);
|
||
|
||
|
||
// Structures need the tag index
|
||
if (SymbolEntry.Type == IMAGE_SYM_TYPE_STRUCT)
|
||
auxValue = AuxSymbolEntry.Sym.TagIndex;
|
||
|
||
SymbolValue = SymbolEntry.Value;
|
||
|
||
if(SymbolEntry.StorageClass!=IMAGE_SYM_CLASS_MEMBER_OF_STRUCT){
|
||
// dprintf("\t[LOCAL:%s, value=%ld, aux=%lx]\n",
|
||
// SymbolName, SymbolValue, auxValue);
|
||
AddLocalToFunction(pCurrentFunction,SymbolName,SymbolValue,
|
||
SymbolEntry.Type, auxValue);
|
||
#ifdef NT_SAPI
|
||
if ( pCurrentFunction && pCurrentFunction->pLocal )
|
||
TH_SetupCVlocal( pImage, pCurrentFunction->pLocal,
|
||
&SymbolEntry, &AuxSymbolEntry);
|
||
#endif /* NT_SAPI */
|
||
}
|
||
else{
|
||
// dprintf("\t[FIELD:%s, type=%ld, value=%ld]\n",
|
||
// SymbolName, SymbolEntry.Type, SymbolValue);
|
||
AddFieldToStructure(pCurrentStructure, SymbolName,
|
||
SymbolValue,SymbolEntry.Type, auxValue);
|
||
#ifdef NT_SAPI
|
||
if ( pCurrentStructure && pCurrentStructure->pField)
|
||
TH_SetupCVfield( pImage, pCurrentStructure->pField,
|
||
&SymbolEntry, &AuxSymbolEntry);
|
||
#endif /* NT_SAPI */
|
||
}
|
||
}
|
||
break;
|
||
|
||
#ifdef NT_SAPI
|
||
|
||
case IMAGE_SYM_CLASS_END_OF_STRUCT:
|
||
if ( pCurrentStructure ) {
|
||
if (auxcount) {
|
||
entrycount++;
|
||
auxcount--;
|
||
CV_READ(ImageReadHandle,&AuxSymbolEntry,symsize);
|
||
}
|
||
|
||
else
|
||
memset( &AuxSymbolEntry, 0, symsize);
|
||
|
||
TH_SetupCVstruct( pImage, pCurrentStructure,
|
||
&SymbolEntry, &AuxSymbolEntry);
|
||
}
|
||
break;
|
||
|
||
#endif /* NT_SAPI */
|
||
|
||
default:
|
||
// dprintf("OTHER class entry - class: %d\n",
|
||
// SymbolEntry.StorageClass);
|
||
break;
|
||
}
|
||
|
||
// auxcount has the number of unprocessed auxiliary entries
|
||
// skip over them for the next table entry
|
||
|
||
entrycount += auxcount;
|
||
CV_SEEK(ImageReadHandle, symsize * auxcount, SEEK_CUR);
|
||
}
|
||
|
||
if (StringTable) {
|
||
StringTable += sizeof(ULONG);
|
||
|
||
#ifdef NT_HOST
|
||
// BUGBUG W-Barry 30-Apr-91 Replaced hfree call with free - same as
|
||
// with calloc above...
|
||
|
||
free(StringTable);
|
||
#else
|
||
hfree(StringTable);
|
||
#endif
|
||
}
|
||
if (fVerboseOutput) {
|
||
#ifdef MIPS
|
||
dprintf("KD: \"%s\" loaded %ld symbols, %ld functions (%08lx-%08lx)\n",
|
||
pszName, symbolcount, pImage->NumberOfFunctions,
|
||
pImage->offsetLow, pImage->offsetHigh);
|
||
#else
|
||
dprintf("KD: \"%s\" loaded %ld symbols (%08lx-%08lx)\n",
|
||
pszName, symbolcount,
|
||
pImage->offsetLow, pImage->offsetHigh);
|
||
#endif
|
||
}
|
||
free(pExtension);
|
||
free(pFilename);
|
||
free(pPathname);
|
||
free(pLinenumbers);
|
||
|
||
#ifndef NT_SAPI
|
||
CV_CLOSE(ImageReadHandle);
|
||
#endif
|
||
|
||
}
|
||
#endif
|
||
|
||
|
||
|
||
// TEMP TEMP TEMP - pack string with 14 characters out of 18 into
|
||
// string in place.
|
||
|
||
|
||
void PackAuxNameEntry (PUCHAR pPathname, ULONG auxcount)
|
||
{
|
||
PUCHAR pchDst;
|
||
PUCHAR pchSrc;
|
||
|
||
pchDst = pPathname + 14;
|
||
pchSrc = pPathname + 18;
|
||
|
||
while (auxcount-- > 1) {
|
||
memcpy(pchDst, pchSrc, 14);
|
||
pchDst += 14;
|
||
pchSrc += 18;
|
||
}
|
||
*pchDst = '\0';
|
||
}
|
||
|
||
|
||
void UnloadSymbols (PIMAGE_INFO pImage)
|
||
{
|
||
PSYMBOL pSymbol;
|
||
PSYMFILE pSymfile;
|
||
PNODE pNode;
|
||
PNODE pNodeNext;
|
||
|
||
// if module was never loaded, nothing to unload,
|
||
// just close open file handle and return
|
||
if (fLazyLoad && !pImage->fSymbolsLoaded)
|
||
{
|
||
#ifdef KERNEL
|
||
if (fVerboseOutput)
|
||
dprintf("KD: unloading \"%s\" (deferred)\n", pImage->pszName);
|
||
#else
|
||
CloseHandle(pImage->hFile);
|
||
#endif
|
||
return;
|
||
}
|
||
if (fVerboseOutput)
|
||
#ifdef KERNEL
|
||
dprintf("KD: unloading symbols for \"%s\"\n", pImage->pszName);
|
||
#else
|
||
dprintf("NTSD: unloading symbols for \"%s\"\n", pImage->pszName);
|
||
#endif
|
||
free(pImage->pszName);
|
||
|
||
#if defined(MIPS)
|
||
// for MIPS debugger, free the function entry table
|
||
|
||
if (pImage->NumberOfFunctions)
|
||
free(pImage->FunctionTable);
|
||
#endif
|
||
|
||
////////////////////////////////////////////////////////////////
|
||
// delete all symbol structures with the specified module index
|
||
////////////////////////////////////////////////////////////////
|
||
|
||
// make a symbol structure with the low offset in the image
|
||
|
||
pSymbol = AllocSymbol(pImage->offsetLow, "", -1);
|
||
|
||
// try to access the node with the offset given.
|
||
// the node pointer returned will be the nearest offset less
|
||
// than the argument (unless it is less than the tree minimum)
|
||
|
||
AccessNode(&(pProcessCurrent->symcontextSymbolOffset),
|
||
&(pSymbol->nodeOffset));
|
||
pNode = pProcessCurrent->symcontextSymbolOffset.pNodeRoot;
|
||
|
||
// deallocate the temporary symbol structure
|
||
|
||
DeallocSymbol(pSymbol);
|
||
|
||
// traverse the tree and delete symbols with the specified index
|
||
// until the offset is higher than the maximum
|
||
|
||
while (pNode) {
|
||
pSymbol = PNODE_TO_PSYMBOL(pNode,
|
||
&(pProcessCurrent->symcontextSymbolOffset));
|
||
if (pSymbol->offset > pImage->offsetHigh)
|
||
break;
|
||
pNodeNext = NextNode(&(pProcessCurrent->symcontextSymbolOffset),
|
||
pNode);
|
||
if (pSymbol->modIndex == (CHAR)pImage->index) {
|
||
// dprintf("** offset: %08lx string: %s deleted\n",
|
||
// pSymbol->offset, pSymbol->string);
|
||
DeleteSymbol(pSymbol);
|
||
}
|
||
pNode = pNodeNext;
|
||
}
|
||
|
||
/////////////////////////////////////////////////////////////////////
|
||
// delete all file symbol structures with the specified module index
|
||
/////////////////////////////////////////////////////////////////////
|
||
|
||
// search all entries in the current image - get the first
|
||
|
||
pNode = NextNode(&(pProcessCurrent->symcontextSymfileOffset), NULL);
|
||
|
||
// traverse the tree and delete symbols with the specified index
|
||
// until the end of the tree.
|
||
|
||
while (pNode) {
|
||
pSymfile = PNODE_TO_PSYMFILE(pNode,
|
||
&(pProcessCurrent->symcontextSymfileOffset));
|
||
pNodeNext = NextNode(&(pProcessCurrent->symcontextSymfileOffset),
|
||
pNode);
|
||
if (pSymfile->modIndex == (CHAR)pImage->index) {
|
||
if (fVerboseOutput)
|
||
#ifdef KERNEL
|
||
dprintf("KD: symfile: \"%s\" deleted\n", pSymfile->pchName);
|
||
#else
|
||
dprintf("NTSD: symfile: \"%s\" deleted\n", pSymfile->pchName);
|
||
#endif
|
||
DeleteSymfile(pSymfile);
|
||
}
|
||
pNode = pNodeNext;
|
||
}
|
||
}
|
||
|
||
|
||
void EnsureModuleSymbolsLoaded (CHAR iModule)
|
||
{
|
||
PIMAGE_INFO pImage;
|
||
|
||
if (fLazyLoad) {
|
||
pImage = pProcessCurrent->pImageHead;
|
||
while (pImage && pImage->index != (UCHAR)iModule)
|
||
pImage = pImage->pImageNext;
|
||
|
||
if (pImage && !pImage->fSymbolsLoaded) {
|
||
// NOTE! The order of the next two statements
|
||
// are critical. Reversing them will cause
|
||
// infinite recursion to occur.
|
||
pImage->fSymbolsLoaded = TRUE;
|
||
LoadSymbols(pImage);
|
||
}
|
||
}
|
||
}
|
||
|
||
int EnsureOffsetSymbolsLoaded (ULONG offset)
|
||
{
|
||
PIMAGE_INFO pImage = pProcessCurrent->pImageHead;
|
||
PIMAGE_INFO pImageFound = NULL;
|
||
|
||
// first, scan all modules for the one which has the highest
|
||
// starting offset less than the input offset.
|
||
|
||
while (pImage) {
|
||
|
||
if (offset >= (ULONG)pImage->lpBaseOfImage &&
|
||
(!pImageFound ||
|
||
((ULONG)pImage->lpBaseOfImage >
|
||
(ULONG)pImageFound->lpBaseOfImage)))
|
||
pImageFound = pImage;
|
||
|
||
pImage = pImage->pImageNext;
|
||
}
|
||
|
||
// continue only if a candidate was found
|
||
|
||
if (pImageFound) {
|
||
|
||
// load the candidate image if deferred
|
||
|
||
if (fLazyLoad && !pImageFound->fSymbolsLoaded) {
|
||
|
||
// NOTE! The order of the next two statements
|
||
// are critical. Reversing them will cause
|
||
// infinite recursion to occur.
|
||
|
||
pImageFound->fSymbolsLoaded = TRUE;
|
||
LoadSymbols(pImageFound);
|
||
}
|
||
|
||
// with the candidate loaded, test if offset is more
|
||
// than the highest symbol. If so, clear pImageFound
|
||
|
||
if (offset > pImageFound->offsetHigh)
|
||
pImageFound = FALSE;
|
||
}
|
||
|
||
// return flag TRUE if offset was NOT in image
|
||
|
||
return (pImageFound == NULL);
|
||
}
|
||
|
||
#ifdef KERNEL
|
||
PUCHAR GetModuleName (PUCHAR pszPath)
|
||
{
|
||
PUCHAR pszStart;
|
||
PUCHAR pszEnd;
|
||
PUCHAR pszReturn;
|
||
|
||
pszStart = pszEnd = pszPath + strlen(pszPath);
|
||
while (pszStart >= pszPath && *pszStart != ':' && *pszStart != '\\') {
|
||
if (*pszStart == '.')
|
||
pszEnd = pszStart;
|
||
pszStart--;
|
||
}
|
||
|
||
// special case for module "ntoskrnl", change to "nt"
|
||
|
||
if ((pszEnd - pszStart) == 9 && !_strnicmp(pszStart + 1, "ntoskrnl", 8))
|
||
pszEnd = pszStart + 3;
|
||
|
||
pszReturn = (PUCHAR)malloc(pszEnd - pszStart);
|
||
if (!pszReturn) {
|
||
printf("memory allocation error\n");
|
||
ExitProcess(STATUS_UNSUCCESSFUL);
|
||
}
|
||
pszStart++;
|
||
strncpy(pszReturn, pszStart, pszEnd - pszStart);
|
||
*(pszReturn + (pszEnd - pszStart)) = '\0';
|
||
|
||
return pszReturn;
|
||
}
|
||
#endif
|
||
|
||
#ifndef NT_SAPI
|
||
/*** parseExamine - parse and execute examine command
|
||
*
|
||
* Purpose:
|
||
* Parse the current command string and examine the symbol
|
||
* table to display the appropriate entries. The entries
|
||
* are displayed in increasing string order. This function
|
||
* accepts underscores, alphabetic, and numeric characters
|
||
* to match as well as the special characters '?' and '*'.
|
||
* The '?' character matches any other character while '*'
|
||
* matches any string of zero or more characters. If used,
|
||
* '*' must be the last character in the pattern.
|
||
*
|
||
* Input:
|
||
* pchCommand - pointer to current command string
|
||
*
|
||
* Output:
|
||
* offset and string name of symbols displayed
|
||
*
|
||
*************************************************************************/
|
||
|
||
void parseExamine (void)
|
||
{
|
||
UCHAR chString[60];
|
||
UCHAR ch;
|
||
PUCHAR pchString = chString;
|
||
PUCHAR pchStart;
|
||
BOOLEAN fClosure = FALSE;
|
||
BOOLEAN fOutput;
|
||
ULONG cntunderscores = 0;
|
||
ULONG count;
|
||
PSYMBOL pSymbol;
|
||
PNODE pNode;
|
||
PNODE pNodeLast;
|
||
PUCHAR pchSrc;
|
||
PUCHAR pchDst;
|
||
UCHAR chSrc;
|
||
UCHAR chDst;
|
||
int status = 0;
|
||
PIMAGE_INFO pImage;
|
||
|
||
#if defined(KERNEL)
|
||
#if defined(NT_HOST)
|
||
SetConsoleCtrlHandler( waitHandler, FALSE );
|
||
SetConsoleCtrlHandler( cmdHandler, TRUE );
|
||
#else
|
||
signal(SIGINT, ControlCHandler);
|
||
#endif
|
||
#endif
|
||
|
||
// get module pointer from name in command line (<string>!)
|
||
|
||
pImage = ParseModuleIndex();
|
||
if (!pImage)
|
||
error(VARDEF);
|
||
|
||
if (fLazyLoad && pImage != (PIMAGE_INFO)-1 && !pImage->fSymbolsLoaded) {
|
||
LoadSymbols(pImage);
|
||
pImage->fSymbolsLoaded = TRUE;
|
||
}
|
||
|
||
ch = PeekChar();
|
||
|
||
// special case the command "x*!" to dump out the module table
|
||
// and "x*!*" to dump out module table with line number information
|
||
|
||
if (pImage == (PIMAGE_INFO)-1) {
|
||
fOutput = FALSE;
|
||
if (ch == '*') {
|
||
pchCommand++;
|
||
ch = PeekChar();
|
||
fOutput = TRUE;
|
||
}
|
||
if (ch == ';' || ch == '\0') {
|
||
DumpModuleTable(fOutput);
|
||
return;
|
||
}
|
||
else
|
||
error(SYNTAX);
|
||
}
|
||
|
||
// copy invariant part of input pattern into chString
|
||
// map to upper case to find first possibility in tree
|
||
|
||
pchCommand++;
|
||
|
||
while (ch == '_') {
|
||
*pchString++ = ch;
|
||
ch = *pchCommand++;
|
||
}
|
||
|
||
pchStart = pchString;
|
||
ch = (UCHAR)toupper(ch);
|
||
while ((ch >= 'A' && ch <= 'Z') || (ch == '_')
|
||
|| (ch >= '0' && ch <= '9')) {
|
||
*pchString++ = ch;
|
||
ch = (UCHAR)toupper(*pchCommand++);
|
||
}
|
||
*pchString = '\0';
|
||
if (count = pchString - pchStart) {
|
||
// if nonNULL invariant part, set search range:
|
||
// set starting node to root of invariant access
|
||
// set ending node to next after invariant incremented
|
||
// for all modules, increment last character in variable
|
||
// (because of mapping, increment 'Z' to 'z'+1 = '{')
|
||
|
||
pSymbol = AllocSymbol(0, chString, -1);
|
||
|
||
AccessNode(&(pProcessCurrent->symcontextSymbolString),
|
||
&(pSymbol->nodeString));
|
||
pNode = pProcessCurrent->symcontextSymbolString.pNodeRoot;
|
||
|
||
pchSrc = &pSymbol->string[count - 1];
|
||
if (*pchSrc == 'Z')
|
||
*pchSrc = 'z';
|
||
(*pchSrc)++;
|
||
status = AccessNode(&(pProcessCurrent->symcontextSymbolString),
|
||
&(pSymbol->nodeString));
|
||
pNodeLast = pProcessCurrent->symcontextSymbolString.pNodeRoot;
|
||
if (status == -1 && pNodeLast)
|
||
pNodeLast = NextNode(&(pProcessCurrent->symcontextSymbolString),
|
||
pNodeLast);
|
||
DeallocSymbol(pSymbol);
|
||
}
|
||
else {
|
||
// if NULL invariant part, search the whole tree:
|
||
// set starting node to first in tree;
|
||
// set ending node to last in tree
|
||
|
||
pNode = NextNode(&(pProcessCurrent->symcontextSymbolString), NULL);
|
||
pNodeLast = NULL;
|
||
}
|
||
|
||
// copy rest of pattern into chString
|
||
|
||
while ((ch >= 'A' && ch <= 'Z') || (ch == '_')
|
||
|| (ch >= '0' && ch <= '9') || (ch == '?')) {
|
||
*pchString++ = ch;
|
||
ch = (UCHAR)toupper(*pchCommand++);
|
||
}
|
||
*pchString = '\0';
|
||
|
||
// set closure flag if '*' is found
|
||
|
||
if (ch == '*') {
|
||
fClosure = TRUE;
|
||
ch = *pchCommand++;
|
||
}
|
||
|
||
// error if more pattern is seen
|
||
|
||
if (ch)
|
||
error(SYNTAX);
|
||
pchCommand--;
|
||
|
||
// for each node in search range:
|
||
// match if NULL input was entered
|
||
// nonmatch if underscores differ by more than one
|
||
// match if case-insensitive match with:
|
||
// '?' matching all characters
|
||
// '*' closes match if extra input after source null
|
||
|
||
cntunderscores = pchStart - chString;
|
||
while (pNode != pNodeLast) {
|
||
pSymbol = PNODE_TO_PSYMBOL(pNode,
|
||
&(pProcessCurrent->symcontextSymbolString));
|
||
fOutput = FALSE;
|
||
if (!chString[0])
|
||
fOutput = TRUE;
|
||
else if ((cntunderscores != (ULONG)pSymbol->underscores)
|
||
&& (cntunderscores + 1 != (ULONG)pSymbol->underscores))
|
||
fOutput = FALSE;
|
||
else {
|
||
pchSrc = pchStart;
|
||
pchDst = pSymbol->string;
|
||
do {
|
||
chSrc = *pchSrc++;
|
||
chDst = (UCHAR)toupper(*pchDst++);
|
||
}
|
||
while ((chSrc == chDst || chSrc == '?') && chSrc && chDst);
|
||
fOutput = (BOOLEAN)(!chSrc && (fClosure || !chDst));
|
||
}
|
||
|
||
// if flag set, output the offset and symbol string
|
||
|
||
if (fOutput && (pImage == (PIMAGE_INFO)-1
|
||
|| pSymbol->modIndex == (CHAR)pImage->index)) {
|
||
dprintf("%8lx %s!", pSymbol->offset,
|
||
pImageFromIndex(pSymbol->modIndex)->pszName);
|
||
count = pSymbol->underscores;
|
||
while (count--)
|
||
dprintf("_");
|
||
dprintf("%s\t%s\n", pSymbol->string,
|
||
(pSymbol->type == SYMBOL_TYPE_EXPORT) ? "[Export]" : "");
|
||
}
|
||
pNode = NextNode(&(pProcessCurrent->symcontextSymbolString), pNode);
|
||
|
||
//#ifndef KERNEL
|
||
if (fControlC) {
|
||
fControlC = 0;
|
||
return;
|
||
}
|
||
//#endif
|
||
}
|
||
}
|
||
|
||
PIMAGE_INFO ParseModuleIndex (void)
|
||
{
|
||
PUCHAR pchCmdSaved = pchCommand;
|
||
UCHAR chName[60];
|
||
PUCHAR pchDst = chName;
|
||
UCHAR ch;
|
||
|
||
// first, parse out a possible module name, either a '*' or
|
||
// a string of 'A'-'Z', 'a'-'z', '0'-'9', '_' (or null)
|
||
|
||
ch = PeekChar();
|
||
pchCommand++;
|
||
|
||
if (ch == '*')
|
||
*pchDst = ch;
|
||
else {
|
||
while ((ch >= 'A' && ch <= 'Z')
|
||
|| (ch >= 'a' && ch <= 'z')
|
||
|| (ch >= '0' && ch <= '9')
|
||
|| ch == '_') {
|
||
*pchDst++ = ch;
|
||
ch = *pchCommand++;
|
||
}
|
||
*pchDst = '\0';
|
||
pchCommand--;
|
||
}
|
||
|
||
// if no '!' after name and white space, then no module specified
|
||
// restore text pointer and treat as null module (PC current)
|
||
|
||
if (PeekChar() == '!')
|
||
pchCommand++;
|
||
else {
|
||
pchCommand = pchCmdSaved;
|
||
chName[0] = '\0';
|
||
}
|
||
|
||
// chName either has: '*' for all modules,
|
||
// '\0' for current module,
|
||
// nonnull string for module name.
|
||
|
||
if (chName[0] == '*')
|
||
return (PIMAGE_INFO)-1;
|
||
else if (chName[0])
|
||
return GetModuleIndex(chName);
|
||
else
|
||
return GetCurrentModuleIndex();
|
||
}
|
||
|
||
|
||
|
||
PIMAGE_INFO GetModuleIndex (PUCHAR pszName)
|
||
{
|
||
PIMAGE_INFO pImage;
|
||
|
||
pImage = pProcessCurrent->pImageHead;
|
||
while (pImage && ntsdstricmp(pszName, pImage->pszName))
|
||
pImage = pImage->pImageNext;
|
||
|
||
return pImage;
|
||
}
|
||
|
||
PIMAGE_INFO GetCurrentModuleIndex (void)
|
||
{
|
||
NT_PADDR pcvalue = GetRegPCValue();
|
||
PIMAGE_INFO pImage;
|
||
|
||
pImage = pProcessCurrent->pImageHead;
|
||
while (pImage && (Flat(pcvalue) < pImage->offsetLow
|
||
|| Flat(pcvalue) > pImage->offsetHigh))
|
||
pImage = pImage->pImageNext;
|
||
|
||
return pImage;
|
||
}
|
||
|
||
|
||
static UCHAR strBlank[] = " ";
|
||
|
||
void DumpModuleTable (BOOLEAN fLineInfo)
|
||
{
|
||
PIMAGE_INFO pImage;
|
||
PNODE pNode;
|
||
PSYMFILE pSymfile;
|
||
int strBlankIndex = 7;
|
||
|
||
dprintf("start end module name\n");
|
||
pImage = pProcessCurrent->pImageHead;
|
||
while (pImage) {
|
||
if (pImage->fSymbolsLoaded && pImage->offsetLow != 0xffffffff)
|
||
dprintf("%08lx %08lx", pImage->offsetLow, pImage->offsetHigh);
|
||
else
|
||
dprintf("%08lx ", pImage->lpBaseOfImage);
|
||
|
||
dprintf(" %s", pImage->pszName);
|
||
|
||
if (strlen(pImage->pszName) < 8)
|
||
strBlankIndex = strlen(pImage->pszName);
|
||
|
||
|
||
if (!pImage->fSymbolsLoaded)
|
||
dprintf("%s(load deferred)", &strBlank[strBlankIndex]);
|
||
else if (pImage->offsetLow == 0xffffffff)
|
||
dprintf("%s(no symbolic information)", &strBlank[strBlankIndex]);
|
||
dprintf("\n");
|
||
|
||
if (pImage->fSymbolsLoaded && fLineInfo) {
|
||
pNode = NextNode(&(pProcessCurrent->symcontextSymfileString),
|
||
NULL);
|
||
if (pNode) {
|
||
printf(" lines filename start pathname\n");
|
||
do {
|
||
pSymfile = PNODE_TO_PSYMFILE(pNode,
|
||
&(pProcessCurrent->symcontextSymfileString));
|
||
if (pSymfile->modIndex == (CHAR)pImage->index) {
|
||
dprintf(" %6d %-8s %08lx ", pSymfile->cLineno,
|
||
pSymfile->pchName, pSymfile->startOffset);
|
||
if (pSymfile->pchPath)
|
||
dprintf("%s%s%s", pSymfile->pchPath,
|
||
pSymfile->pchName, pSymfile->pchExtension);
|
||
dprintf("\n");
|
||
}
|
||
pNode = NextNode(
|
||
&(pProcessCurrent->symcontextSymfileString), pNode);
|
||
}
|
||
while (pNode);
|
||
}
|
||
}
|
||
pImage = pImage->pImageNext;
|
||
}
|
||
}
|
||
#endif /* NT_SAPI */
|
||
|
||
/*** AccessNode - access and splay node
|
||
*
|
||
* Purpose:
|
||
* Search a tree for a node and splay it.
|
||
*
|
||
* Input:
|
||
* pSymContext - pointer to context of tree
|
||
* pNodeAccess - pointer to node with access value set
|
||
*
|
||
* Output:
|
||
* tree splayed with new node at its root
|
||
* Returns:
|
||
* value of success:
|
||
* 1 = root is smallest value larger than input value
|
||
* (not found, no lesser value)
|
||
* 0 = root is input value (value found in tree)
|
||
* -1 = root is largest value less than input value
|
||
* (not found in tree)
|
||
*
|
||
* Notes:
|
||
* splay is done with resulting root
|
||
* if root is less than input value, a secondary splay is done
|
||
* to make the next node the right child of the root
|
||
*
|
||
*************************************************************************/
|
||
|
||
int AccessNode (PSYMCONTEXT pSymContext, PNODE pNodeAccess)
|
||
{
|
||
PNODE *ppNodeRoot = &(pSymContext->pNodeRoot);
|
||
PNODE pNentry = *ppNodeRoot;
|
||
PNODE pNminimum = NULL;
|
||
PNODE pNmaximum = NULL;
|
||
PNODE pNweakcmp = NULL;
|
||
PNODE pRootTemp;
|
||
BOOLEAN fWeakCmp;
|
||
int cmp;
|
||
|
||
// return 1 if empty tree
|
||
|
||
if (!pNentry)
|
||
return 1;
|
||
|
||
// search until value is found or terminating node
|
||
|
||
do {
|
||
// context-specific comparison routine compares values
|
||
// pointed by pNodeAccess and pNentry
|
||
|
||
cmp = (*(pSymContext->pfnCompare))(pNodeAccess, pNentry, &fWeakCmp);
|
||
|
||
// fWeakcmp is set if weak comparison, used if no
|
||
// true comparison is found
|
||
|
||
if (fWeakCmp)
|
||
pNweakcmp = pNentry;
|
||
|
||
// for unequal results, set minimum and maximum entry
|
||
// searched as tree is search for node
|
||
|
||
if (cmp == -1) {
|
||
pNmaximum = pNentry;
|
||
pNentry = pNentry->pLchild;
|
||
}
|
||
else {
|
||
pNminimum = pNentry;
|
||
pNentry = pNentry->pRchild;
|
||
}
|
||
}
|
||
while (pNentry && cmp);
|
||
|
||
// if no stong match found, but weak one was, use it
|
||
|
||
if (cmp && pNweakcmp) {
|
||
cmp = 0;
|
||
pNminimum = pNweakcmp;
|
||
}
|
||
|
||
// splay tree so minimum node is at root, but use maximum
|
||
// if no minimum node
|
||
|
||
*ppNodeRoot = SplayTree(pNminimum ? pNminimum : pNmaximum);
|
||
|
||
// if node not found, set result for value used in splay
|
||
|
||
if (cmp != 0)
|
||
cmp = pNminimum ? -1 : 1;
|
||
|
||
// if node not found and both minimum and maximum nodes
|
||
// were found, splay the next node as the right child of
|
||
// the root. this new node will not have a left child,
|
||
// and assists future accesses in some cases
|
||
|
||
if (cmp == -1 && pNminimum && pNmaximum) {
|
||
pRootTemp = pNminimum->pRchild;
|
||
pRootTemp->pParent = NULL;
|
||
pNmaximum = SplayTree(pNmaximum);
|
||
pNminimum->pRchild = pNmaximum;
|
||
pNmaximum->pParent = pNminimum;
|
||
}
|
||
return cmp;
|
||
}
|
||
|
||
|
||
|
||
/*** CompareSymbolOffset - comparison routine for symbol offsets
|
||
*
|
||
* Purpose:
|
||
* Compare two nodes in the offset tree. The ordering
|
||
* comparisons used are offset and string. The string
|
||
* comparison is done since and offset can have more than
|
||
* one string associated with it.
|
||
*
|
||
* Input:
|
||
* pNode1 - pointer to first node - usually the new one
|
||
* pNode2 - pointer to second node - usually in the tree searched
|
||
*
|
||
* Output:
|
||
* pfWeakCmp - always FALSE - comparisons are exact or they fail
|
||
*
|
||
* Returns:
|
||
* value of comparison result:
|
||
* -1 = value(pNode1) < value(pNode2)
|
||
* 0 = value(pNode1) == value(pNode2)
|
||
* 1 = value(pNode1) > value(pNode2)
|
||
*
|
||
*************************************************************************/
|
||
|
||
int CompareSymbolOffset (PNODE pNode1, PNODE pNode2, PBOOLEAN pfWeakCmp)
|
||
{
|
||
int cmp;
|
||
PSYMBOL pSymbol1 = CONTAINING_RECORD(pNode1, SYMBOL, nodeOffset);
|
||
PSYMBOL pSymbol2 = CONTAINING_RECORD(pNode2, SYMBOL, nodeOffset);
|
||
|
||
*pfWeakCmp = FALSE;
|
||
|
||
// compare offsets of the nodes
|
||
|
||
if (pSymbol1->offset < pSymbol2->offset)
|
||
cmp = -1;
|
||
else if (pSymbol1->offset > pSymbol2->offset)
|
||
cmp = 1;
|
||
|
||
// if the first node string is null, assume node is being
|
||
// searched for in tree, so report equality
|
||
|
||
else if (pSymbol1->string[0] == '\0')
|
||
cmp = 0;
|
||
|
||
// else the first node string is nonnull, and node is being
|
||
// inserted, so further test the string equality: case-
|
||
// insensitive search, underscore count, case-sensitive search
|
||
|
||
else {
|
||
cmp = ntsdstricmp(pSymbol1->string, pSymbol2->string);
|
||
if (!cmp) {
|
||
if (pSymbol1->underscores < pSymbol2->underscores)
|
||
cmp = -1;
|
||
else if (pSymbol1->underscores > pSymbol2->underscores)
|
||
cmp = 1;
|
||
else {
|
||
cmp = strcmp(pSymbol1->string, pSymbol2->string);
|
||
if (!cmp) {
|
||
if (pSymbol1->modIndex < pSymbol2->modIndex)
|
||
cmp = -1;
|
||
else if (pSymbol1->modIndex > pSymbol2->modIndex)
|
||
cmp = 1;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return cmp;
|
||
}
|
||
|
||
/*** CompareSymfileOffset - comparison routine for symbol file offsets
|
||
*
|
||
* Purpose:
|
||
* Compare two nodes in the symbol file offset tree. The ordering
|
||
* comparisons used are offset and string. The string
|
||
* comparison is done since and offset can have more than
|
||
* one string associated with it.
|
||
*
|
||
* Input:
|
||
* pNode1 - pointer to first node - usually the new one
|
||
* pNode2 - pointer to second node - usually in the tree searched
|
||
*
|
||
* Output:
|
||
* pfWeakCmp - always FALSE - comparisons are exact or they fail
|
||
*
|
||
* Returns:
|
||
* value of comparison result:
|
||
* -1 = value(pNode1) < value(pNode2)
|
||
* 0 = value(pNode1) == value(pNode2)
|
||
* 1 = value(pNode1) > value(pNode2)
|
||
*
|
||
*************************************************************************/
|
||
|
||
int CompareSymfileOffset (PNODE pNode1, PNODE pNode2, PBOOLEAN pfWeakCmp)
|
||
{
|
||
int cmp = 0;
|
||
PSYMFILE pSymfile1 = CONTAINING_RECORD(pNode1, SYMFILE, nodeOffset);
|
||
PSYMFILE pSymfile2 = CONTAINING_RECORD(pNode2, SYMFILE, nodeOffset);
|
||
|
||
*pfWeakCmp = FALSE;
|
||
|
||
// test if performing an insertion (pSymfile1->pLineno == NULL)
|
||
// a search (search only has offset defined in cLineno)
|
||
|
||
if (pSymfile1->pLineno) {
|
||
|
||
// compare starting offsets of the nodes
|
||
|
||
if (pSymfile1->startOffset < pSymfile2->startOffset)
|
||
cmp = -1;
|
||
else if (pSymfile1->startOffset > pSymfile2->startOffset)
|
||
cmp = 1;
|
||
|
||
// if same offset, further test the file and module equality
|
||
|
||
else {
|
||
cmp = strcmp(pSymfile1->pchName, pSymfile2->pchName);
|
||
if (!cmp) {
|
||
if (pSymfile1->modIndex < pSymfile2->modIndex)
|
||
cmp = -1;
|
||
else if (pSymfile1->modIndex > pSymfile2->modIndex)
|
||
|
||
cmp = 1;
|
||
}
|
||
}
|
||
}
|
||
|
||
else {
|
||
|
||
// search - test search offset in node against range
|
||
|
||
if (pSymfile1->startOffset < pSymfile2->startOffset)
|
||
cmp = -1;
|
||
else if (pSymfile1->startOffset > pSymfile2->endOffset)
|
||
cmp = 1;
|
||
}
|
||
|
||
return cmp;
|
||
}
|
||
|
||
/*** CompareSymbolString - comparison routine for symbol strings
|
||
*
|
||
* Purpose:
|
||
* Compare two nodes in the string tree. The ordering
|
||
* comparisons used are case-insensitivity, underscore
|
||
* count, module ordering, and case-sensitivity.
|
||
*
|
||
* Input:
|
||
* pNode1 - pointer to first node - usually the new one
|
||
* pNode2 - pointer to second node - usually in the tree searched
|
||
*
|
||
* Output:
|
||
* pfWeakCmp - TRUE if case-insensitive and underscores match
|
||
* FALSE otherwise (defined only if cmp nonzero)
|
||
*
|
||
* Returns:
|
||
* value of comparison result:
|
||
* -1 = value(pNode1) < value(pNode2)
|
||
* 0 = value(pNode1) == value(pNode2)
|
||
* 1 = value(pNode1) > value(pNode2)
|
||
*
|
||
*************************************************************************/
|
||
|
||
int CompareSymbolString (PNODE pNode1, PNODE pNode2, PBOOLEAN pfWeakCmp)
|
||
{
|
||
int cmp;
|
||
PSYMBOL pSymbol1 = CONTAINING_RECORD(pNode1, SYMBOL, nodeString);
|
||
PSYMBOL pSymbol2 = CONTAINING_RECORD(pNode2, SYMBOL, nodeString);
|
||
|
||
*pfWeakCmp = FALSE;
|
||
|
||
// compare case-insensitive value of the nodes
|
||
|
||
cmp = ntsdstricmp(pSymbol1->string, pSymbol2->string);
|
||
if (!cmp) {
|
||
// compare underscore counts of the nodes
|
||
|
||
if (pSymbol1->underscores < pSymbol2->underscores)
|
||
cmp = -1;
|
||
else if (pSymbol1->underscores > pSymbol2->underscores)
|
||
cmp = 1;
|
||
else {
|
||
// if null string in first node, then searching, not inserting
|
||
|
||
if (pSymbol1->offset == 0)
|
||
|
||
// test module index for weak comparison indication
|
||
// index of -1 is for no module, weakly match any
|
||
|
||
if (pSymbol1->modIndex == (CHAR)-1 ||
|
||
pSymbol1->modIndex == pSymbol2->modIndex)
|
||
*pfWeakCmp = TRUE;
|
||
|
||
// test for ordering due to module index
|
||
|
||
if (pSymbol1->modIndex == (CHAR)-1 ||
|
||
pSymbol1->modIndex < pSymbol2->modIndex)
|
||
cmp = -1;
|
||
else if (pSymbol1->modIndex > pSymbol2->modIndex)
|
||
cmp = 1;
|
||
else
|
||
|
||
// final test for strong match is case-sensitive comparison
|
||
|
||
cmp = strcmp(pSymbol1->string, pSymbol2->string);
|
||
}
|
||
}
|
||
return cmp;
|
||
}
|
||
|
||
/*** CompareSymfileString - comparison routine for symbol file strings
|
||
*
|
||
* Purpose:
|
||
* Compare two nodes in the string tree. The ordering
|
||
* comparisons used are case-insensitivity, underscore
|
||
* count, module ordering, and case-sensitivity.
|
||
*
|
||
* Input:
|
||
* pNode1 - pointer to first node - usually the new one
|
||
* pNode2 - pointer to second node - usually in the tree searched
|
||
*
|
||
* Output:
|
||
* pfWeakCmp - TRUE if case-insensitive and underscores match
|
||
* FALSE otherwise (defined only if cmp nonzero)
|
||
*
|
||
* Returns:
|
||
* value of comparison result:
|
||
* -1 = value(pNode1) < value(pNode2)
|
||
* 0 = value(pNode1) == value(pNode2)
|
||
* 1 = value(pNode1) > value(pNode2)
|
||
*
|
||
*************************************************************************/
|
||
|
||
int CompareSymfileString (PNODE pNode1, PNODE pNode2, PBOOLEAN pfWeakCmp)
|
||
{
|
||
int cmp;
|
||
PSYMFILE pSymfile1 = CONTAINING_RECORD(pNode1, SYMFILE, nodeString);
|
||
PSYMFILE pSymfile2 = CONTAINING_RECORD(pNode2, SYMFILE, nodeString);
|
||
|
||
*pfWeakCmp = FALSE;
|
||
|
||
// compare case-sensitive value of the filenames
|
||
|
||
cmp = strcmp(pSymfile1->pchName, pSymfile2->pchName);
|
||
if (!cmp) {
|
||
|
||
// if filenames match, test for module index
|
||
|
||
if (pSymfile1->modIndex < pSymfile2->modIndex)
|
||
cmp = -1;
|
||
else if (pSymfile1->modIndex > pSymfile2->modIndex)
|
||
cmp = 1;
|
||
|
||
// test if searching rather than inserting, a
|
||
// search structure has pLineno NULL and
|
||
// cLineno has the line number to search
|
||
|
||
else if (pSymfile1->pLineno != NULL) {
|
||
|
||
// inserting, so order on starting line number
|
||
// (this is the second item of the list)
|
||
|
||
if ((pSymfile1->pLineno + 1)->breakLineNumber
|
||
< (pSymfile2->pLineno + 1)->breakLineNumber)
|
||
cmp = -1;
|
||
else if ((pSymfile1->pLineno + 1)->breakLineNumber
|
||
> (pSymfile2->pLineno + 1)->breakLineNumber)
|
||
cmp = 1;
|
||
}
|
||
|
||
else {
|
||
|
||
// for viewing lines, set a weak match to TRUE
|
||
|
||
*pfWeakCmp = TRUE;
|
||
|
||
// searching, test for line number within the range
|
||
// defined in the structure
|
||
|
||
if (pSymfile1->cLineno
|
||
< (pSymfile2->pLineno + 1)->breakLineNumber)
|
||
cmp = -1;
|
||
else if (pSymfile1->cLineno
|
||
> (pSymfile2->pLineno
|
||
+ pSymfile2->cLineno)->breakLineNumber)
|
||
cmp = 1;
|
||
}
|
||
}
|
||
return cmp;
|
||
}
|
||
|
||
|
||
|
||
/*** InsertSymbol - insert offset and string into new symbol
|
||
*
|
||
* Purpose:
|
||
* external routine.
|
||
* Allocate and insert a new symbol into the offset and
|
||
* string trees.
|
||
*
|
||
* Input:
|
||
* insertvalue - offset value of new symbol
|
||
* pinsertstring - string value if new symbol
|
||
*
|
||
* Output:
|
||
* None.
|
||
*
|
||
* Notes:
|
||
* Uses the routine InsertNode for both offset and string
|
||
* through different contexts.
|
||
*
|
||
*************************************************************************/
|
||
|
||
PSYMBOL InsertSymbol (ULONG insertvalue, PUCHAR pinsertstring,
|
||
CHAR insertmod)
|
||
{
|
||
PSYMBOL pSymbol;
|
||
|
||
pSymbol = AllocSymbol(insertvalue, pinsertstring, insertmod);
|
||
if (!InsertNode(&(pProcessCurrent->symcontextSymbolOffset),
|
||
&(pSymbol->nodeOffset))) {
|
||
DeallocSymbol(pSymbol);
|
||
// dprintf("insert - value %d already in tree\n", insertvalue);
|
||
return NULL;
|
||
}
|
||
if (!InsertNode(&(pProcessCurrent->symcontextSymbolString),
|
||
&(pSymbol->nodeString))) {
|
||
DeleteNode(&(pProcessCurrent->symcontextSymbolOffset),
|
||
&(pSymbol->nodeOffset));
|
||
DeallocSymbol(pSymbol);
|
||
// dprintf("insert - string %s already in tree\n", pinsertstring);
|
||
return NULL;
|
||
}
|
||
return pSymbol;
|
||
}
|
||
|
||
|
||
|
||
|
||
PSTRUCT InsertStructure (ULONG insertvalue, PUCHAR pinsertstring,
|
||
CHAR insertmod)
|
||
{
|
||
PSTRUCT pStruct;
|
||
|
||
pStruct = (PSTRUCT) AllocSymbol(insertvalue, pinsertstring, insertmod);
|
||
if (!InsertNode(&(pProcessCurrent->symcontextStructOffset),
|
||
&(pStruct->nodeOffset))) {
|
||
DeallocSymbol((PSYMBOL)pStruct);
|
||
//dprintf("insert - value %d already in tree\n", insertvalue);
|
||
return NULL;
|
||
}
|
||
if (!InsertNode(&(pProcessCurrent->symcontextStructString),
|
||
&(pStruct->nodeString))) {
|
||
DeleteNode(&(pProcessCurrent->symcontextStructOffset),
|
||
&(pStruct->nodeOffset));
|
||
DeallocSymbol((PSYMBOL)pStruct);
|
||
//dprintf("insert - string %s already in tree\n", pinsertstring);
|
||
return NULL;
|
||
}
|
||
pStruct->pField = NULL;
|
||
return pStruct;
|
||
}
|
||
|
||
/*** InsertSymfile - insert new file line numbers into search tree
|
||
*
|
||
* Purpose:
|
||
* Allocate and insert a new files and its line numbers into the
|
||
* offset and filename string trees.
|
||
*
|
||
* Input:
|
||
* pPathname - pointer to pathname string
|
||
* pFilename - pointer to filename string
|
||
* pExtension - pointer to extension string
|
||
* pLineno - pointer to COFF line number entries
|
||
* cLineno - count of entries pointed by pLineno
|
||
* endingOffset - ending offset of file section
|
||
* index - module index for file section
|
||
*
|
||
* Output:
|
||
* None.
|
||
*
|
||
* Notes:
|
||
* Uses the routine InsertNode for both offset and filename
|
||
* string through different contexts.
|
||
*
|
||
*************************************************************************/
|
||
|
||
PSYMFILE InsertSymfile (PUCHAR pPathname, PUCHAR pFilename,
|
||
PUCHAR pExtension,
|
||
PIMAGE_LINENUMBER pLineno, USHORT cLineno,
|
||
ULONG startingOffset, ULONG endingOffset,
|
||
CHAR index)
|
||
{
|
||
PSYMFILE pSymfile;
|
||
|
||
pSymfile = AllocSymfile(pPathname, pFilename, pExtension,
|
||
pLineno, cLineno,
|
||
startingOffset, endingOffset, index);
|
||
|
||
if (!InsertNode(&(pProcessCurrent->symcontextSymfileOffset),
|
||
&(pSymfile->nodeOffset))) {
|
||
DeallocSymfile(pSymfile);
|
||
// dprintf("insert - value %d already in tree\n", insertvalue);
|
||
return NULL;
|
||
}
|
||
if (!InsertNode(&(pProcessCurrent->symcontextSymfileString),
|
||
&(pSymfile->nodeString))) {
|
||
DeleteNode(&(pProcessCurrent->symcontextSymfileOffset),
|
||
&(pSymfile->nodeOffset));
|
||
DeallocSymfile(pSymfile);
|
||
// dprintf("insert - string %s already in tree\n", pinsertstring);
|
||
return NULL;
|
||
}
|
||
|
||
return pSymfile;
|
||
}
|
||
|
||
/*** InsertNode - insert new node into tree
|
||
*
|
||
* Purpose:
|
||
* Insert node into the tree of the specified context.
|
||
*
|
||
* Input:
|
||
* pSymContext - pointer to context to insert node
|
||
* pNodeNew - pointer to node to insert
|
||
*
|
||
* Returns:
|
||
* TRUE - node was inserted successfully
|
||
* FALSE - node already exists
|
||
*
|
||
* Notes:
|
||
* Both offset and string values of the node may be used
|
||
* in the ordering or duplication criteria.
|
||
*
|
||
*************************************************************************/
|
||
|
||
BOOLEAN InsertNode (PSYMCONTEXT pSymContext, PNODE pNodeNew)
|
||
{
|
||
PNODE *ppNodeRoot = &(pSymContext->pNodeRoot);
|
||
PNODE pNodeRootTemp;
|
||
int splitstatus;
|
||
|
||
// split tree into two subtrees:
|
||
// *ppNodeRoot - root of all nodes < value(pNodeNew)
|
||
// pNodeRootTemp - root of all nodes >= value(pNodeNew)
|
||
|
||
splitstatus = SplitTree(pSymContext, &pNodeRootTemp, pNodeNew);
|
||
if (splitstatus != 0) {
|
||
// value(pNodeNew) was not in tree
|
||
// make pNodeNew the root having the two subtrees as children
|
||
|
||
pNodeNew->pLchild = *ppNodeRoot;
|
||
if (*ppNodeRoot)
|
||
(*ppNodeRoot)->pParent = pNodeNew;
|
||
pNodeNew->pRchild = pNodeRootTemp;
|
||
if (pNodeRootTemp)
|
||
pNodeRootTemp->pParent = pNodeNew;
|
||
pNodeNew->pParent = NULL;
|
||
*ppNodeRoot = pNodeNew;
|
||
return TRUE;
|
||
}
|
||
else {
|
||
|
||
// value(pNodeNew) was in tree
|
||
// just rejoin the two subtrees back and report error
|
||
|
||
JoinTree(pSymContext, pNodeRootTemp);
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
/*** DeleteSymbol - delete specified symbol from splay tree
|
||
*
|
||
* Purpose:
|
||
* external routine.
|
||
* Delete the specified symbol object in both the
|
||
* offset and string trees and deallocate its space.
|
||
*
|
||
* Input:
|
||
* pSymbol - pointer to symbol object to delete
|
||
*
|
||
* Output:
|
||
* None.
|
||
*
|
||
*************************************************************************/
|
||
|
||
void DeleteSymbol (PSYMBOL pSymbol)
|
||
{
|
||
DeleteNode(&(pProcessCurrent->symcontextSymbolOffset),
|
||
&(pSymbol->nodeOffset));
|
||
DeleteNode(&(pProcessCurrent->symcontextSymbolString),
|
||
&(pSymbol->nodeString));
|
||
DeallocSymbol(pSymbol);
|
||
}
|
||
|
||
/*** DeleteNode - delete specified node from tree
|
||
*
|
||
* Purpose:
|
||
* Delete node from tree of the context specified.
|
||
*
|
||
* Input:
|
||
* pSymContext - pointer to context of deletion
|
||
* pNodeDelete - pointer to node to actually delete
|
||
*
|
||
* Output:
|
||
* None.
|
||
*
|
||
*************************************************************************/
|
||
|
||
void DeleteNode (PSYMCONTEXT pSymContext, PNODE pNodeDelete)
|
||
{
|
||
PNODE pNodeRootTemp;
|
||
|
||
// splay the node to be deleted to move it to the root
|
||
|
||
//dprintf("before splay\n");
|
||
SplayTree(pNodeDelete);
|
||
//dprintf("after splay\n");
|
||
|
||
// point to the splayed node children and join them
|
||
|
||
pSymContext->pNodeRoot = pNodeDelete->pLchild;
|
||
pNodeRootTemp = pNodeDelete->pRchild;
|
||
//dprintf("before join\n");
|
||
JoinTree(pSymContext, pNodeRootTemp);
|
||
//dprintf("after join\n");
|
||
}
|
||
|
||
/*** JoinTree - join two trees into one
|
||
*
|
||
* Purpose:
|
||
* Join two trees into one where all nodes of the first
|
||
* tree have a lesser value than any of the second.
|
||
*
|
||
* Input:
|
||
* pSymContext - pointer to context containing the first tree
|
||
* pNodeRoot2 - pointer to root of second tree
|
||
*
|
||
* Output:
|
||
* pSymContext - pointer to context containing the joined tree
|
||
*
|
||
*************************************************************************/
|
||
|
||
void JoinTree (PSYMCONTEXT pSymContext, PNODE pNodeRoot2)
|
||
{
|
||
PNODE *ppNodeRoot1 = &(pSymContext->pNodeRoot);
|
||
|
||
// access and splay the first tree to have its maximum value
|
||
// as its root (no right child)
|
||
|
||
// AccessNode(pSymContext, PSYMBOL_TO_PNODE(&symbolMax, pSymContext));
|
||
AccessNode(pSymContext, pSymContext->pNodeMax);
|
||
if (*ppNodeRoot1) {
|
||
// nonnull first tree, connect second tree as
|
||
// right child of the first
|
||
|
||
(*ppNodeRoot1)->pRchild = pNodeRoot2;
|
||
if (pNodeRoot2)
|
||
pNodeRoot2->pParent = *ppNodeRoot1;
|
||
}
|
||
else {
|
||
// null first tree, make the second tree the result
|
||
|
||
*ppNodeRoot1 = pNodeRoot2;
|
||
if (pNodeRoot2)
|
||
pNodeRoot2->pParent = NULL;
|
||
}
|
||
}
|
||
|
||
/*** SplitTree - split one tree into two
|
||
*
|
||
* Purpose:
|
||
* Split the given tree into two subtrees, the first
|
||
* having nodes less than specific value, and the
|
||
* second having nodes greater than or equal to that
|
||
* value.
|
||
*
|
||
* Input:
|
||
* pSymContext - pointer to context containing tree to split
|
||
* pNodeNew - node with value used to specify split
|
||
*
|
||
* Output:
|
||
* pSymContext - pointer to context containing first tree
|
||
* *ppNodeRoot2 - pointer to pointer to root of second tree
|
||
*
|
||
* Returns:
|
||
* result of access:
|
||
* 1 = root is smallest value larger than input value
|
||
* (not found, no lesser value)
|
||
* 0 = root is input value (value found in tree)
|
||
* -1 = root is largest value less than input value
|
||
* (not found in tree)
|
||
*
|
||
*************************************************************************/
|
||
|
||
int SplitTree (PSYMCONTEXT pSymContext, PNODE *ppNodeRoot2, PNODE pNodeNew)
|
||
{
|
||
PNODE *ppNodeRoot1 = &(pSymContext->pNodeRoot);
|
||
int access;
|
||
|
||
if (*ppNodeRoot1) {
|
||
// nonnull tree, access and splay to make node
|
||
// with input value root.
|
||
|
||
access = AccessNode(pSymContext, pNodeNew);
|
||
if (access != 1) {
|
||
// break left child link of root to form two subtrees
|
||
|
||
*ppNodeRoot2 = (*ppNodeRoot1)->pRchild;
|
||
if (*ppNodeRoot2)
|
||
(*ppNodeRoot2)->pParent = NULL;
|
||
(*ppNodeRoot1)->pRchild = NULL;
|
||
}
|
||
else {
|
||
// break right child link of root to form two subtrees
|
||
|
||
*ppNodeRoot2 = *ppNodeRoot1;
|
||
*ppNodeRoot1 = (*ppNodeRoot1)->pLchild;
|
||
if (*ppNodeRoot1)
|
||
(*ppNodeRoot1)->pParent = NULL;
|
||
(*ppNodeRoot2)->pLchild = NULL;
|
||
}
|
||
}
|
||
else {
|
||
// null tree
|
||
|
||
access = 1;
|
||
*ppNodeRoot2 = NULL;
|
||
}
|
||
return access;
|
||
}
|
||
|
||
/*** SplayTree - splay tree with node specified
|
||
*
|
||
* Purpose:
|
||
* Perform rotations (splayings) on the specified tree
|
||
* until the node given is at the root.
|
||
*
|
||
* Input:
|
||
* pointer to node to splay to root
|
||
*
|
||
* Returns:
|
||
* pointer to node splayed
|
||
*
|
||
* Notes:
|
||
*
|
||
*************************************************************************/
|
||
|
||
PNODE SplayTree (PNODE pNentry)
|
||
{
|
||
PNODE pNparent;
|
||
PNODE pNgrand;
|
||
PNODE pNgreat;
|
||
PNODE pNchild;
|
||
|
||
if (pNentry) {
|
||
// repeat single or double rotations until node is root
|
||
|
||
while (pNentry->pParent) {
|
||
pNparent = pNentry->pParent;
|
||
if (!pNparent->pParent) {
|
||
if (pNentry == pNparent->pLchild) {
|
||
|
||
// case 1: PARENT ENTRY
|
||
// / \ / \
|
||
// ENTRY T(B) T(A) PARENT
|
||
// / \ / \
|
||
// T(A) CHILD CHILD T(B)
|
||
|
||
if (pNchild = pNentry->pRchild)
|
||
pNchild->pParent = pNparent;
|
||
pNparent->pLchild = pNchild;
|
||
pNparent->pParent = pNentry;
|
||
pNentry->pRchild = pNparent;
|
||
}
|
||
else {
|
||
|
||
// case 2: PARENT ENTRY
|
||
// / \ / \
|
||
// T(A) ENTRY PARENT T(B)
|
||
// / \ / \
|
||
// CHILD T(B) T(A) CHILD
|
||
|
||
if (pNchild = pNentry->pLchild)
|
||
pNchild->pParent = pNparent;
|
||
pNparent->pRchild = pNchild;
|
||
pNparent->pParent = pNentry;
|
||
pNentry->pLchild = pNparent;
|
||
}
|
||
pNentry->pParent = NULL;
|
||
}
|
||
else {
|
||
pNgrand = pNparent->pParent;
|
||
pNgreat = pNgrand->pParent;
|
||
if (pNentry == pNparent->pLchild) {
|
||
if (pNparent == pNgrand->pLchild) {
|
||
|
||
// case 3: (GREAT) (GREAT)
|
||
// | |
|
||
// GRAND ENTRY
|
||
// / \ / \
|
||
// PARENT T(B) T(A) PARENT
|
||
// / \ / \
|
||
// ENTRY CHILD2 CHILD1 GRAND
|
||
// / \ / \
|
||
// T(A) CHILD1 CHILD2 T(B)
|
||
|
||
if (pNchild = pNentry->pRchild)
|
||
pNchild->pParent = pNparent;
|
||
pNparent->pLchild = pNchild;
|
||
if (pNchild = pNparent->pRchild)
|
||
pNchild->pParent = pNgrand;
|
||
pNgrand->pLchild = pNchild;
|
||
pNgrand->pParent = pNparent;
|
||
pNparent->pRchild = pNgrand;
|
||
pNparent->pParent = pNentry;
|
||
pNentry->pRchild = pNparent;
|
||
}
|
||
else {
|
||
|
||
// case 4: (GREAT) (GREAT)
|
||
// | |
|
||
// GRAND _____ENTRY____
|
||
// / \ / \
|
||
// T(A) PARENT GRAND PARENT
|
||
// / \ / \ / \
|
||
// ENTRY T(B) T(A) CHILD1 CHILD2 T(B)
|
||
// / \
|
||
// CHILD1 CHILD2
|
||
|
||
if (pNchild = pNentry->pLchild)
|
||
pNchild->pParent = pNgrand;
|
||
pNgrand->pRchild = pNchild;
|
||
if (pNchild = pNentry->pRchild)
|
||
pNchild->pParent = pNparent;
|
||
pNparent->pLchild = pNchild;
|
||
pNgrand->pParent = pNentry;
|
||
pNentry->pLchild = pNgrand;
|
||
pNparent->pParent = pNentry;
|
||
pNentry->pRchild = pNparent;
|
||
}
|
||
}
|
||
else {
|
||
if (pNparent == pNgrand->pLchild) {
|
||
|
||
// case 5: (GREAT) (GREAT)
|
||
// | |
|
||
// GRAND _____ENTRY____
|
||
// / \ / \
|
||
// PARENT T(B) PARENT GRAND
|
||
// / \ / \ / \
|
||
// T(A) ENTRY T(A) CHILD1 CHILD2 T(B)
|
||
// / \
|
||
// CHILD1 CHILD2
|
||
|
||
if (pNchild = pNentry->pLchild)
|
||
pNchild->pParent = pNparent;
|
||
pNparent->pRchild = pNchild;
|
||
if (pNchild = pNentry->pRchild)
|
||
pNchild->pParent = pNgrand;
|
||
pNgrand->pLchild = pNchild;
|
||
pNparent->pParent = pNentry;
|
||
pNentry->pLchild = pNparent;
|
||
pNgrand->pParent = pNentry;
|
||
pNentry->pRchild = pNgrand;
|
||
}
|
||
else {
|
||
|
||
// case 6: (GREAT) (GREAT)
|
||
// | |
|
||
// GRAND ENTRY
|
||
// / \ / \
|
||
// T(A) PARENT PARENT T(B)
|
||
// / \ / \
|
||
// CHILD1 ENTRY GRAND CHILD2
|
||
// / \ / \
|
||
// CHILD2 T(B) T(A) CHILD1
|
||
|
||
if (pNchild = pNentry->pLchild)
|
||
pNchild->pParent = pNparent;
|
||
pNparent->pRchild = pNchild;
|
||
if (pNchild = pNparent->pLchild)
|
||
pNchild->pParent = pNgrand;
|
||
pNgrand->pRchild = pNchild;
|
||
pNgrand->pParent = pNparent;
|
||
pNparent->pLchild = pNgrand;
|
||
pNparent->pParent = pNentry;
|
||
pNentry->pLchild = pNparent;
|
||
}
|
||
}
|
||
if (pNgreat) {
|
||
if (pNgreat->pLchild == pNgrand)
|
||
pNgreat->pLchild = pNentry;
|
||
else
|
||
pNgreat->pRchild = pNentry;
|
||
}
|
||
pNentry->pParent = pNgreat;
|
||
}
|
||
}
|
||
}
|
||
return pNentry;
|
||
}
|
||
|
||
/*** NextNode - return node with next key in tree
|
||
*
|
||
* Purpose:
|
||
* With the specified context and node, determine
|
||
* the node with the next larger value.
|
||
*
|
||
* Input:
|
||
* pSymContext - pointer to context to test
|
||
* pNode - pointer to node within context
|
||
* NULL to return the first node in the tree
|
||
*
|
||
* Returns:
|
||
* pointer to node of the next value
|
||
* NULL if largest node was input
|
||
*
|
||
*************************************************************************/
|
||
|
||
PNODE NextNode (PSYMCONTEXT pSymContext, PNODE pNode)
|
||
{
|
||
PNODE pLast;
|
||
|
||
if (pNode) {
|
||
// nonnull input, if node has a right child,
|
||
// return the leftmost child of the right child
|
||
// or right child itself if not left children
|
||
|
||
if (pNode->pRchild) {
|
||
pNode = pNode->pRchild;
|
||
while (pNode->pLchild)
|
||
pNode = pNode->pLchild;
|
||
}
|
||
else {
|
||
// if no right child, go up through the parent
|
||
// links until the node comes from a left child
|
||
// and return it
|
||
|
||
do {
|
||
pLast = pNode;
|
||
pNode = pNode->pParent;
|
||
}
|
||
while (pNode && pNode->pLchild != pLast);
|
||
}
|
||
}
|
||
else {
|
||
// NULL input return first node of tree.
|
||
// return leftmost child of root or root itself
|
||
// if no left children.
|
||
|
||
pNode = pSymContext->pNodeRoot;
|
||
if (pNode)
|
||
while (pNode->pLchild)
|
||
pNode = pNode->pLchild;
|
||
}
|
||
return pNode;
|
||
}
|
||
|
||
/*** OutputTree - output tree node in ascending order
|
||
*
|
||
* Purpose:
|
||
* Using the specified context, output the corresponding
|
||
* tree from lowest to highest values.
|
||
*
|
||
* Input:
|
||
* pSymContext - pointer to context whose tree to output
|
||
*
|
||
* Output:
|
||
* contents of tree nodes from low to high
|
||
*
|
||
*************************************************************************/
|
||
|
||
void OutputTree (PSYMCONTEXT pSymContext)
|
||
{
|
||
PNODE pNode = NULL;
|
||
PSYMBOL pSymbol;
|
||
CHAR count;
|
||
|
||
dprintf("****** output tree ******\n");
|
||
while (TRUE) {
|
||
pNode = NextNode(pSymContext, pNode);
|
||
if (pNode) {
|
||
pSymbol = PNODE_TO_PSYMBOL(pNode, pSymContext);
|
||
dprintf("node:%8lx par:%8lx lch:%8lx rch:%8lx " ,
|
||
pNode, pNode->pParent, pNode->pLchild, pNode->pRchild);
|
||
dprintf("value: %8lx <", pSymbol->offset);
|
||
count = pSymbol->underscores;
|
||
while (count--)
|
||
dprintf("_");
|
||
dprintf("%s>\n", pSymbol->string);
|
||
}
|
||
else
|
||
break;
|
||
}
|
||
}
|
||
|
||
|
||
/*** GetOffsetFromSym - return offset from symbol specified
|
||
*
|
||
* Purpose:
|
||
* external routine.
|
||
* With the specified symbol, set the pointer to
|
||
* its offset. The variable chSymbolSuffix may
|
||
* be used to append a character to repeat the search
|
||
* if it first fails.
|
||
*
|
||
* Input:
|
||
* pString - pointer to input symbol
|
||
*
|
||
* Output:
|
||
* pOffset - pointer to offset to be set
|
||
*
|
||
* Returns:
|
||
* BOOLEAN value of success
|
||
*
|
||
*************************************************************************/
|
||
|
||
BOOLEAN GetOffsetFromSym (PUCHAR pString, PULONG pOffset, CHAR iModule)
|
||
{
|
||
UCHAR SuffixedString[80];
|
||
UCHAR Suffix[4];
|
||
|
||
if (GetOffsetFromString(pString, pOffset, iModule))
|
||
return TRUE;
|
||
|
||
if (chSymbolSuffix != 'n') {
|
||
strcpy(SuffixedString, pString);
|
||
Suffix[0] = chSymbolSuffix;
|
||
Suffix[1] = '\0';
|
||
strcat(SuffixedString, Suffix);
|
||
if (GetOffsetFromString(SuffixedString, pOffset, iModule))
|
||
return TRUE;
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
/*** GetOffsetFromString - return offset from string specified
|
||
*
|
||
* Purpose:
|
||
* With the specified string, set the pointer to
|
||
* its offset.
|
||
*
|
||
* Input:
|
||
* pString - pointer to input string
|
||
*
|
||
* Output:
|
||
* pOffset - pointer to offset to be set
|
||
*
|
||
* Returns:
|
||
* BOOLEAN value of success
|
||
*
|
||
*************************************************************************/
|
||
|
||
BOOLEAN GetOffsetFromString (PUCHAR pString, PULONG pOffset, CHAR iModule)
|
||
{
|
||
PSYMBOL pSymSearch = AllocSymbol(0L, pString, iModule);
|
||
PSYMBOL pSymbol;
|
||
int st;
|
||
|
||
EnsureModuleSymbolsLoaded(iModule);
|
||
|
||
// search for string in tree
|
||
|
||
st = AccessNode(&(pProcessCurrent->symcontextSymbolString),
|
||
&(pSymSearch->nodeString));
|
||
if (st) {
|
||
// if not found, try again with underscore prepended to name
|
||
|
||
pSymSearch->underscores++;
|
||
st = AccessNode(&(pProcessCurrent->symcontextSymbolString),
|
||
&(pSymSearch->nodeString));
|
||
}
|
||
if (!st) {
|
||
// if found, get the pointer to its symbol and set the offset
|
||
|
||
pSymbol = PNODE_TO_PSYMBOL
|
||
(pProcessCurrent->symcontextSymbolString.pNodeRoot,
|
||
&(pProcessCurrent->symcontextSymbolString));
|
||
*pOffset = pSymbol->offset;
|
||
}
|
||
// deallocate the temporary symbol structure and return success
|
||
|
||
DeallocSymbol(pSymSearch);
|
||
return (BOOLEAN)(st == 0);
|
||
}
|
||
|
||
|
||
/*** GetOffsetFromLineno - return offset from file:lineno specified
|
||
*
|
||
* Purpose:
|
||
* With the specified file and line number, return
|
||
* its offset.
|
||
*
|
||
* Input:
|
||
* pString - pointer to input string for filename
|
||
* lineno - line number of filename specified
|
||
*
|
||
* Output:
|
||
* pOffset - pointer to offset to be set
|
||
*
|
||
* Returns:
|
||
* BOOLEAN value of success
|
||
*
|
||
*************************************************************************/
|
||
|
||
PLINENO GetLinenoFromFilename (PUCHAR pString, PPSYMFILE ppSymfile,
|
||
USHORT lineNum, CHAR iModule)
|
||
{
|
||
PPLINENO ppLineno;
|
||
PLINENO pLineno = NULL;
|
||
PSYMFILE pSymfileSearch = AllocSymfile("", pString, "", NULL,
|
||
lineNum, 0, 0, iModule);
|
||
PSYMFILE pSymfile;
|
||
USHORT indexLow;
|
||
USHORT indexHigh;
|
||
USHORT indexTest;
|
||
int st;
|
||
|
||
EnsureModuleSymbolsLoaded(iModule);
|
||
|
||
// search for symbol file containing line number in tree
|
||
|
||
st = AccessNode(&(pProcessCurrent->symcontextSymfileString),
|
||
&(pSymfileSearch->nodeString));
|
||
if (!st) {
|
||
// if found, search line number list for offset
|
||
|
||
pSymfile = PNODE_TO_PSYMFILE
|
||
(pProcessCurrent->symcontextSymfileString.pNodeRoot,
|
||
&(pProcessCurrent->symcontextSymfileString));
|
||
*ppSymfile = pSymfile;
|
||
|
||
// search the PLINENO array for the pointer to the LINENO
|
||
// structure having the line number given.
|
||
|
||
ppLineno = pSymfile->ppLinenoSrcLine;
|
||
indexLow = 1;
|
||
|
||
// PDK KLUGDE:::
|
||
if (indexHigh = pSymfile->cLineno)
|
||
do {
|
||
indexTest = (USHORT)((indexLow + indexHigh) / 2);
|
||
if (lineNum > (*(ppLineno + indexTest))->breakLineNumber)
|
||
indexLow = (USHORT)(indexTest + 1);
|
||
else if (lineNum < (*(ppLineno + indexTest))->breakLineNumber)
|
||
indexHigh = (USHORT)(indexTest - 1);
|
||
else
|
||
indexLow = indexHigh = indexTest;
|
||
}
|
||
while (indexLow < indexHigh);
|
||
|
||
pLineno = *(ppLineno + indexHigh);
|
||
}
|
||
|
||
// deallocate the temporary symbol structure and return pointer
|
||
|
||
DeallocSymfile(pSymfileSearch);
|
||
return pLineno;
|
||
}
|
||
|
||
#ifndef NT_SAPI
|
||
void GetLinenoString (PUCHAR pchBuffer, ULONG offset)
|
||
{
|
||
PLINENO pLineno;
|
||
PSYMFILE pSymfile;
|
||
|
||
*pchBuffer = '\0';
|
||
pLineno = GetLinenoFromOffset(&pSymfile, offset);
|
||
if (pLineno && pLineno->memoryOffset == offset)
|
||
sprintf(pchBuffer, "%s:%d", pSymfile->pchName,
|
||
pLineno->breakLineNumber);
|
||
}
|
||
|
||
void GetCurrentMemoryOffsets (PULONG pMemoryLow, PULONG pMemoryHigh)
|
||
{
|
||
NT_PADDR pcValue = GetRegPCValue();
|
||
PSYMFILE pSymfile;
|
||
PLINENO pLineno;
|
||
|
||
*pMemoryLow = -1L; // default value for no source
|
||
if (fSourceOnly) {
|
||
pLineno = GetLinenoFromOffset(&pSymfile, Flat(pcValue));
|
||
if (pLineno) {
|
||
*pMemoryLow = pLineno->memoryOffset;
|
||
if (pLineno == (pSymfile->pLineno + pSymfile->cLineno))
|
||
*pMemoryHigh = pSymfile->endOffset;
|
||
else
|
||
*pMemoryHigh = (pLineno + 1)->memoryOffset;
|
||
}
|
||
}
|
||
}
|
||
|
||
PLINENO GetCurrentLineno (PPSYMFILE ppSymfile)
|
||
{
|
||
NT_PADDR pcValue = GetRegPCValue();
|
||
|
||
return GetLinenoFromOffset(ppSymfile, Flat(pcValue));
|
||
}
|
||
|
||
PLINENO GetLastLineno (PPSYMFILE ppSymfile, PUSHORT pLineNum)
|
||
{
|
||
PLINENO pLineno = NULL;
|
||
PSYMFILE pSymfile;
|
||
|
||
if (pSymfileLast) {
|
||
pLineno = GetLinenoFromFilename(pSymfileLast->pchName,
|
||
&pSymfile, lineNumberLast,
|
||
pSymfileLast->modIndex);
|
||
if (pLineno) {
|
||
*ppSymfile = pSymfile;
|
||
*pLineNum = lineNumberLast;
|
||
}
|
||
}
|
||
return pLineno;
|
||
}
|
||
|
||
static PUCHAR Type[] = {"null", "void", "char", "short", "int",
|
||
"long", "float", "double", ""/*struct*/, "union",
|
||
"enum", "moe", "uchar", "ushort", "uint",
|
||
"ulong"};
|
||
static PUCHAR Dtype[]= {"", "*", "()", "[]"};
|
||
|
||
BOOLEAN GetLocalFromString(PUCHAR pszLocal, PULONG pValue)
|
||
{
|
||
PSYMFILE pSymfileSearch = pTempSymfile;
|
||
PSYMFILE pSymfile;
|
||
SYMBOL Symbol;
|
||
static NT_ADDR addrPC;
|
||
static PLOCAL pLocal;
|
||
PLOCAL pL;
|
||
NT_PADDR newPC = GetRegPCValue();
|
||
|
||
if (!AddrEqu(newPC, &addrPC)){
|
||
// search for symbol file containing offset in tree
|
||
pSymfileSearch->startOffset = Flat(&addrPC) = Flat(newPC);
|
||
if (AccessNode(&(pProcessCurrent->symcontextSymfileOffset),
|
||
&(pSymfileSearch->nodeOffset))){
|
||
pLocal = NULL;
|
||
return FALSE;
|
||
}
|
||
// Get the symfile from the root
|
||
pSymfile = PNODE_TO_PSYMFILE
|
||
(pProcessCurrent->symcontextSymfileOffset.pNodeRoot,
|
||
&(pProcessCurrent->symcontextSymfileOffset));
|
||
// create temporary symbol with offset (module not needed)
|
||
Symbol.offset = Flat(&addrPC);
|
||
Symbol.string[0] = '\0';
|
||
|
||
// access the function in the tree with value closest
|
||
if (AccessNode(&(pSymfile->symcontextFunctionOffset),
|
||
&(Symbol.nodeOffset)) != 1) {
|
||
pLocal = (PNODE_TO_PSYMBOL
|
||
(pSymfile->symcontextFunctionOffset.pNodeRoot,
|
||
&(pSymfile->symcontextFunctionOffset)))->pLocal;
|
||
}
|
||
else {
|
||
pLocal = NULL;
|
||
return FALSE;
|
||
}
|
||
}
|
||
for(pL=pLocal;pL;pL=pL->next){
|
||
if (_stricmp(pszLocal, pL->pszLocalName)) continue;
|
||
*pValue = GetLocalValue(pL->value, pL->type, FALSE);
|
||
return TRUE;
|
||
}
|
||
return FALSE;
|
||
}
|
||
#endif /* NT_SAPI */
|
||
|
||
PSYMBOL GetFunctionFromOffset (PPSYMFILE ppSymfile, ULONG offset)
|
||
{
|
||
PSYMFILE pSymfileSearch = pTempSymfile;
|
||
PSYMFILE pSymfile;
|
||
PSYMBOL pSymbol = NULL;
|
||
SYMBOL Symbol;
|
||
int st;
|
||
// PUCHAR pszCtrl;
|
||
// ULONG value;
|
||
|
||
// load symbols for offset if needed (and if possible)
|
||
st = EnsureOffsetSymbolsLoaded(offset);
|
||
|
||
if (!st) {
|
||
|
||
// search for symbol file containing offset in tree
|
||
pSymfileSearch->startOffset = offset;
|
||
st = AccessNode(&(pProcessCurrent->symcontextSymfileOffset),
|
||
&(pSymfileSearch->nodeOffset));
|
||
}
|
||
|
||
// DeallocSymfile(pSymfileSearch);
|
||
|
||
// fails if non-code static
|
||
|
||
if (st) {
|
||
// dprintf("no symfile for function offset %08lx\n", offset);
|
||
return NULL;
|
||
}
|
||
|
||
// Get the symfile from the root
|
||
pSymfile = PNODE_TO_PSYMFILE
|
||
(pProcessCurrent->symcontextSymfileOffset.pNodeRoot,
|
||
&(pProcessCurrent->symcontextSymfileOffset));
|
||
|
||
// Make this symfile available to the caller
|
||
*ppSymfile = pSymfile;
|
||
|
||
// create temporary symbol with offset (module not needed)
|
||
Symbol.offset = offset;
|
||
Symbol.string[0] = '\0';
|
||
|
||
// access the function in the tree with value (or nearest lesser value)
|
||
if (AccessNode(&(pSymfile->symcontextFunctionOffset),
|
||
&(Symbol.nodeOffset)) != 1) {
|
||
pSymbol = PNODE_TO_PSYMBOL
|
||
(pSymfile->symcontextFunctionOffset.pNodeRoot,
|
||
&(pSymfile->symcontextFunctionOffset));
|
||
|
||
// dprintf("%s(){\n", pSymbol->string);
|
||
// if (pSymbol->pLocal){
|
||
// PLOCAL pLocal = pSymbol->pLocal;
|
||
//
|
||
// while(pLocal){
|
||
//
|
||
// // stop output on break
|
||
//
|
||
// if (fControlC) {
|
||
// fControlC = 0;
|
||
// break;
|
||
// }
|
||
//
|
||
// MUST ITERATE THROUGH ALL THE DERIVED TYPES!!!!
|
||
// DO THIS LATER
|
||
// value = labs(pLocal->value);
|
||
// if (pLocal->type==IMAGE_SYM_TYPE_STRUCT){
|
||
// if (baseDefault==10) pszCtrl=" [EBP%s%ld]\t";
|
||
// else pszCtrl=" [EBP%s0x%lx]\t";
|
||
//
|
||
// dprintf(pszCtrl,
|
||
// *((LONG*)&pLocal->value)<0?"-":"+", value);
|
||
// THIS -2 IS DUE TO A CONVERTER/LINKER BUG. THIS OFFSET MIGHT CHANGE
|
||
// if(!GetStructFromValue(pLocal->aux, pLocal->value))
|
||
// GetStructFromValue(pLocal->aux-2, pLocal->value);
|
||
// dprintf("%s%s\n", pLocal->pszLocalName,
|
||
// Dtype[(pLocal->type>>4)&0x3]);
|
||
// }
|
||
// else{
|
||
// if (baseDefault==10) pszCtrl=" [EBP%s%ld]\t(%s%s)\t%s = ";
|
||
// else pszCtrl=" [EBP%s0x%lx]\t(%s%s)\t%s = ";
|
||
//
|
||
// dprintf(pszCtrl,
|
||
// *((LONG*)&pLocal->value)<0?"-":"+",
|
||
// value,
|
||
// Type[pLocal->type&0xF],
|
||
// Dtype[(pLocal->type>>4)&0x3],
|
||
// pLocal->pszLocalName);
|
||
// GetLocalValue(pLocal->value, pLocal->type, TRUE);
|
||
// dprintf("\n");
|
||
// }
|
||
// pLocal = pLocal->next;
|
||
// }
|
||
// }
|
||
// else dprintf("NO LOCALS");
|
||
// dprintf("}\n");
|
||
}
|
||
return pSymbol;
|
||
}
|
||
|
||
|
||
#ifndef NT_SAPI
|
||
|
||
PSTRUCT GetStructFromValue(ULONG value, LONG base)
|
||
{
|
||
PSTRUCT pStruct = NULL;
|
||
STRUCT Struct;
|
||
PUCHAR pszCtrl;
|
||
ULONG val;
|
||
|
||
// create temporary structure with the specified value
|
||
Struct.offset = value;
|
||
Struct.string[0] = '\0';
|
||
|
||
// access the structure in the tree with the specified value
|
||
if (!AccessNode(&(pProcessCurrent->symcontextStructOffset),
|
||
&(Struct.nodeOffset))) {
|
||
pStruct = (PSTRUCT) PNODE_TO_PSYMBOL (
|
||
pProcessCurrent->symcontextStructOffset.pNodeRoot,
|
||
&(pProcessCurrent->symcontextStructOffset));
|
||
dprintf("struct %s {\n", pStruct->string);
|
||
if (pStruct->pField){
|
||
PFIELD pField = pStruct->pField;
|
||
while(pField){
|
||
val = labs(pField->value);
|
||
if (baseDefault==10) pszCtrl="\t\t [%s%ld]\t(%s%s)\t%s = ";
|
||
else pszCtrl="\t\t [%s0x%lx]\t(%s%s)\t%s = ";
|
||
dprintf(pszCtrl,
|
||
*((LONG*)&pField->value)<0?"-":"+",
|
||
val,
|
||
Type[pField->type&0xF],
|
||
Dtype[(pField->type>>4)&0x3],
|
||
pField->pszFieldName);
|
||
GetLocalValue(base+pField->value, pField->type, TRUE);
|
||
dprintf("\n");
|
||
pField = pField->next;
|
||
}
|
||
}
|
||
else dprintf("NO FIELDS");
|
||
dprintf("\t\t} ");
|
||
return pStruct;
|
||
}
|
||
else return (PSTRUCT)NULL;
|
||
}
|
||
|
||
|
||
ULONG GetLocalValue(LONG value, USHORT type, BOOLEAN fPrint)
|
||
{
|
||
UCHAR dtype = (UCHAR)(type >> 4);
|
||
ULONG data;
|
||
PCHAR pszCtrl=NULL;
|
||
ULONG retValue;
|
||
#ifndef MIPS
|
||
float f;
|
||
double df;
|
||
#endif
|
||
type &= 0xF;
|
||
if (fPointerExpression) {
|
||
NT_PADDR paddr = GetRegFPValue();
|
||
|
||
AddrAdd(paddr, value);
|
||
if (fPrint) dprintAddr(paddr);
|
||
return (ULONG)Flat(paddr);
|
||
}
|
||
|
||
GetBytesFromFrame((PUCHAR)&data, value, sizeof(data));
|
||
if (dtype) {
|
||
if (fPrint) dprintf("0x%08lx", data);
|
||
return data;
|
||
}
|
||
switch(type){
|
||
case IMAGE_SYM_TYPE_NULL:
|
||
pszCtrl = "%lx??";
|
||
retValue = data;
|
||
break;
|
||
case IMAGE_SYM_TYPE_VOID:
|
||
pszCtrl = "VOID";
|
||
retValue = data;
|
||
break;
|
||
case IMAGE_SYM_TYPE_CHAR:
|
||
case IMAGE_SYM_TYPE_UCHAR:
|
||
pszCtrl = " [%u]";
|
||
data = retValue = (UCHAR)data;
|
||
if (fPrint) dprintf("%c", data);
|
||
break;
|
||
case IMAGE_SYM_TYPE_SHORT:
|
||
pszCtrl = "%d";
|
||
data = retValue = (USHORT)data;
|
||
break;
|
||
case IMAGE_SYM_TYPE_USHORT:
|
||
pszCtrl = "%u";
|
||
data = retValue = (USHORT)data;
|
||
break;
|
||
case IMAGE_SYM_TYPE_INT:
|
||
case IMAGE_SYM_TYPE_LONG:
|
||
pszCtrl = "%ld";
|
||
retValue = data;
|
||
break;
|
||
case IMAGE_SYM_TYPE_UINT:
|
||
case IMAGE_SYM_TYPE_ULONG:
|
||
pszCtrl = "%lu";
|
||
retValue = data;
|
||
break;
|
||
#ifndef MIPS
|
||
case IMAGE_SYM_TYPE_FLOAT:
|
||
pszCtrl = "%f";
|
||
GetBytesFromFrame((PUCHAR)&f, value, sizeof(float));
|
||
if (fPrint) dprintf(pszCtrl, f);
|
||
return data;
|
||
break;
|
||
case IMAGE_SYM_TYPE_DOUBLE:
|
||
pszCtrl = "%lf";
|
||
GetBytesFromFrame((PUCHAR)&df, value, sizeof(double));
|
||
if (fPrint) dprintf(pszCtrl, df);
|
||
return data;
|
||
break;
|
||
#endif
|
||
default:{
|
||
NT_PADDR paddr = GetRegFPValue();
|
||
|
||
pszCtrl = "???";
|
||
|
||
AddrAdd(paddr, value);
|
||
retValue = Flat(paddr);
|
||
}
|
||
break;
|
||
}
|
||
if (fPrint) dprintf(pszCtrl, data);
|
||
return retValue;
|
||
}
|
||
|
||
|
||
|
||
void
|
||
GetBytesFromFrame(PUCHAR pcb, LONG offset, USHORT cb)
|
||
{
|
||
NT_PADDR paddr = GetRegFPValue();
|
||
|
||
AddrAdd(paddr, offset);
|
||
GetMemString(paddr, pcb, cb);
|
||
}
|
||
|
||
#endif /* NT_SAPI */
|
||
|
||
void
|
||
AddFieldToStructure(PSTRUCT pStruct, PUCHAR pszFieldName, ULONG value,
|
||
USHORT type, ULONG auxValue)
|
||
{
|
||
PFIELD pField;
|
||
|
||
if (!pStruct)
|
||
return;
|
||
if (!(pField=(PFIELD)malloc(sizeof(FIELD)+strlen(pszFieldName))))
|
||
return;
|
||
strcpy(pField->pszFieldName, pszFieldName);
|
||
pField->type = type;
|
||
pField->value = value;
|
||
pField->aux = auxValue;
|
||
pField->next = pStruct->pField;
|
||
pStruct->pField = pField;
|
||
}
|
||
|
||
void
|
||
AddLocalToFunction(PSYMBOL pFunction, PUCHAR pszLocalName, ULONG value,
|
||
USHORT type, ULONG auxValue)
|
||
{
|
||
PLOCAL pLocal;
|
||
|
||
if (!pFunction)
|
||
return;
|
||
if (!(pLocal=(PLOCAL)malloc(sizeof(LOCAL)+strlen(pszLocalName))))
|
||
return;
|
||
strcpy(pLocal->pszLocalName, pszLocalName);
|
||
pLocal->type = type;
|
||
pLocal->value = value;
|
||
pLocal->aux = auxValue;
|
||
pLocal->next = pFunction->pLocal;
|
||
pFunction->pLocal = pLocal;
|
||
}
|
||
|
||
|
||
PSYMBOL InsertFunction(PUCHAR lpFunctionName, ULONG offset) //, PSYMBOL pS)
|
||
{
|
||
PSYMFILE pSymfileSearch = pTempSymfile;
|
||
//AllocSymfile("", "", "", NULL, 0, offset, 0, 0);
|
||
PSYMFILE pSymfile;
|
||
PSYMBOL pSymbol;
|
||
int st;
|
||
|
||
// Find the symbol file containing this function
|
||
pTempSymfile->startOffset = offset;
|
||
st = AccessNode(&(pProcessCurrent->symcontextSymfileOffset),
|
||
&(pSymfileSearch->nodeOffset));
|
||
|
||
// DeallocSymfile(pSymfileSearch);
|
||
|
||
// fails if non-code static
|
||
|
||
if (st) {
|
||
// dprintf("no symfile for function offset %08lx\n", offset);
|
||
return NULL;
|
||
}
|
||
|
||
// A symfile was found, now get it from the root
|
||
pSymfile = PNODE_TO_PSYMFILE
|
||
(pProcessCurrent->symcontextSymfileOffset.pNodeRoot,
|
||
&(pProcessCurrent->symcontextSymfileOffset));
|
||
|
||
// Allocate a function node.
|
||
pSymbol = AllocSymbol(offset, lpFunctionName, pSymfile->modIndex);
|
||
// pSymbol->pSymbol = pS;
|
||
|
||
// Now insert this function into this symfile's function tree
|
||
if (!InsertNode(&(pSymfile->symcontextFunctionOffset),
|
||
&(pSymbol->nodeOffset))) {
|
||
DeallocSymbol(pSymbol);
|
||
// dprintf("insert - value %d already in tree\n", lpFunctionName);
|
||
return NULL;
|
||
}
|
||
if (!InsertNode(&(pSymfile->symcontextFunctionString),
|
||
&(pSymbol->nodeString))) {
|
||
DeleteNode(&(pSymfile->symcontextFunctionOffset),
|
||
&(pSymbol->nodeOffset));
|
||
DeallocSymbol(pSymbol);
|
||
dprintf("insert - string %s already in tree\n", lpFunctionName);
|
||
return NULL;
|
||
}
|
||
return pSymbol;
|
||
}
|
||
|
||
PLINENO GetLinenoFromOffset (PPSYMFILE ppSymfile, ULONG offset)
|
||
{
|
||
PLINENO pLineno = NULL;
|
||
PSYMFILE pSymfileSearch = AllocSymfile("", "", "",
|
||
NULL, 0, offset, 0, 0);
|
||
PSYMFILE pSymfile;
|
||
USHORT indexLow;
|
||
USHORT indexHigh;
|
||
USHORT indexTest;
|
||
int st;
|
||
|
||
// load symbols for offset if needed (and if possible)
|
||
|
||
st = EnsureOffsetSymbolsLoaded(offset);
|
||
|
||
if (!st) {
|
||
|
||
// search for symbol file containing offset in tree
|
||
|
||
st = AccessNode(&(pProcessCurrent->symcontextSymfileOffset),
|
||
&(pSymfileSearch->nodeOffset));
|
||
}
|
||
|
||
if (!st) {
|
||
// if found, search line number list for offset
|
||
|
||
pSymfile = PNODE_TO_PSYMFILE
|
||
(pProcessCurrent->symcontextSymfileOffset.pNodeRoot,
|
||
&(pProcessCurrent->symcontextSymfileOffset));
|
||
|
||
// search for index with equal or closest lessor value to
|
||
// the offset given
|
||
|
||
indexLow = 1;
|
||
|
||
// PDK KLUDGE:::
|
||
if (indexHigh = pSymfile->cLineno)
|
||
do {
|
||
indexTest = (USHORT)((indexLow + indexHigh) / 2);
|
||
if (offset > (pSymfile->pLineno + indexTest)->memoryOffset)
|
||
indexLow = (USHORT)(indexTest + 1);
|
||
else if (offset < (pSymfile->pLineno + indexTest)->memoryOffset)
|
||
indexHigh = (USHORT)(indexTest - 1);
|
||
else
|
||
indexLow = indexHigh = indexTest;
|
||
}
|
||
while (indexLow < indexHigh);
|
||
|
||
*ppSymfile = pSymfile;
|
||
pLineno = pSymfile->pLineno + indexHigh;
|
||
}
|
||
|
||
// deallocate the temporary symbol structure and return pointer
|
||
|
||
DeallocSymfile(pSymfileSearch);
|
||
return pLineno;
|
||
}
|
||
|
||
|
||
/*** GetSymbol - get symbol name from offset specified
|
||
*
|
||
* Purpose:
|
||
* external routine.
|
||
* With the specified offset, return the nearest symbol string
|
||
* previous or equal to the offset and its displacement
|
||
*
|
||
* Input:
|
||
* offset - input offset to search
|
||
* offsetSymMax - maximum offset of a symbol (global value)
|
||
*
|
||
* Output:
|
||
* pchBuffer - pointer to buffer to fill with string
|
||
* pDisplacement - pointer to offset displacement
|
||
*
|
||
* Notes:
|
||
* if offset if less than any defined symbol, the NULL value
|
||
* is returned and the displacement is set to the offset
|
||
*
|
||
*************************************************************************/
|
||
|
||
void GetSymbol (ULONG offset, PUCHAR pchBuffer, PULONG pDisplacement)
|
||
{
|
||
SYMBOL Symbol;
|
||
ULONG disp = offset;
|
||
PSYMBOL pSymbol;
|
||
ULONG underscorecnt;
|
||
UCHAR ch;
|
||
PUCHAR pszTemp;
|
||
|
||
// create temporary symbol with offset (module not needed)
|
||
|
||
Symbol.offset = offset;
|
||
Symbol.string[0] = '\0';
|
||
|
||
*pchBuffer = '\0';
|
||
|
||
// load symbols if needed and check range, and if in range,
|
||
// access symbol in tree with value (or nearest lesser value)
|
||
|
||
if (!EnsureOffsetSymbolsLoaded(offset) &&
|
||
AccessNode(&(pProcessCurrent->symcontextSymbolOffset),
|
||
&(Symbol.nodeOffset)) != 1) {
|
||
pSymbol = PNODE_TO_PSYMBOL
|
||
(pProcessCurrent->symcontextSymbolOffset.pNodeRoot,
|
||
&(pProcessCurrent->symcontextSymbolOffset));
|
||
|
||
// build string from module name, underscore count,
|
||
// and remaining string
|
||
|
||
pszTemp = pImageFromIndex(pSymbol->modIndex)->pszName;
|
||
while (ch = *pszTemp++)
|
||
*pchBuffer++ = ch;
|
||
*pchBuffer++ = '!';
|
||
underscorecnt = pSymbol->underscores;
|
||
while (underscorecnt--)
|
||
*pchBuffer++ = '_';
|
||
strcpy(pchBuffer, pSymbol->string);
|
||
|
||
// displacement is input offset less symbol value offset
|
||
|
||
disp -= pSymbol->offset;
|
||
}
|
||
*pDisplacement = disp;
|
||
}
|
||
|
||
|
||
/*** AllocSymbol - build and allocate symbol
|
||
*
|
||
* Purpose:
|
||
* Allocate space for symbol structure.
|
||
*
|
||
* Input:
|
||
* offset - offset of symbol to be allocated
|
||
* pString - pointer to string of symbol to be allocated
|
||
*
|
||
* Returns:
|
||
* pointer to filled symbol structure
|
||
*
|
||
* Exceptions:
|
||
*
|
||
* Notes:
|
||
* space allocated is: sizeof(SYMBOL) -- nonstring info and 3 UCHAR's
|
||
* + strlen(pString) -- size of string
|
||
* + 1 -- space for terminating NULL
|
||
* the sum is rounded up using the 3 UCHAR's and and'ing with ~3
|
||
*
|
||
*************************************************************************/
|
||
|
||
PSYMBOL AllocSymbol (ULONG offset, PUCHAR pString, CHAR iModule)
|
||
{
|
||
PSYMBOL pSymbol;
|
||
PUCHAR pStringTemp = pString;
|
||
|
||
// allocate the space needed
|
||
|
||
pSymbol = malloc((sizeof(SYMBOL) + strlen(pString) + 1) & ~3);
|
||
if (!pSymbol) {
|
||
dprintf("AllocSymbol - Out of memory\n");
|
||
ExitProcess(STATUS_UNSUCCESSFUL);
|
||
}
|
||
|
||
// set the offset and decode the string into its count of
|
||
// underscores and copy the remaining string
|
||
|
||
pSymbol->offset = offset;
|
||
while (*pStringTemp == '_')
|
||
pStringTemp++;
|
||
pSymbol->underscores = (CHAR)(pStringTemp - pString);
|
||
pSymbol->modIndex = iModule;
|
||
pSymbol->type = SYMBOL_TYPE_SYMBOL;
|
||
pSymbol->pLocal = NULL;
|
||
strcpy(pSymbol->string, pStringTemp);
|
||
return pSymbol;
|
||
}
|
||
|
||
#ifdef NT_SAPI
|
||
static
|
||
SYMBOL symbolTemplate = { 0,0, {NULL, NULL, NULL }, { NULL, NULL, NULL }, -1L,
|
||
0, 0, SYMBOL_TYPE_SYMBOL, NULL,
|
||
{ '\177', '\177', '\0' } };
|
||
static
|
||
#else
|
||
SYMBOL symbolTemplate = { { NULL, NULL, NULL }, { NULL, NULL, NULL }, -1L,
|
||
0, 0, SYMBOL_TYPE_SYMBOL, NULL, 0,
|
||
{ '\177', '\177', '\0' } };
|
||
#endif /* NT_SAPI */
|
||
|
||
/*** AllocSymfile - build and allocate symbol file structure
|
||
*
|
||
* Purpose:
|
||
* Allocate space for symbol file structure.
|
||
*
|
||
* Input:
|
||
* offset - offset of symbol to be allocated
|
||
* pString - pointer to string of symbol to be allocated
|
||
*
|
||
* Returns:
|
||
* pointer to filled symbol structure
|
||
*
|
||
*************************************************************************/
|
||
|
||
PSYMFILE AllocSymfile (PUCHAR pPathname, PUCHAR pFilename,
|
||
PUCHAR pExtension,
|
||
PIMAGE_LINENUMBER pCoffLineno, USHORT cLineno,
|
||
ULONG startingOffset, ULONG endingOffset,
|
||
CHAR modIndex)
|
||
{
|
||
PSYMFILE pSymfile;
|
||
PLINENO pLineno;
|
||
USHORT index;
|
||
PSYMBOL symbolMax;
|
||
IMAGE_LINENUMBER CoffLineno;
|
||
|
||
pSymfile = malloc(sizeof(SYMFILE));
|
||
if (!pSymfile) {
|
||
dprintf("AllocSymfile - Out of memory\n");
|
||
ExitProcess(STATUS_UNSUCCESSFUL);
|
||
}
|
||
symbolMax = &pSymfile->maxSymbol;
|
||
*symbolMax = symbolTemplate;
|
||
pSymfile->symcontextFunctionOffset.pNodeRoot = NULL;
|
||
pSymfile->symcontextFunctionOffset.pNodeMax =
|
||
(PNODE)((LONG)symbolMax + NODE_SYMBOL_DISPLACEMENT(nodeOffset));
|
||
pSymfile->symcontextFunctionOffset.pfnCompare = &CompareSymbolOffset;
|
||
pSymfile->symcontextFunctionOffset.nodeDisplacement =
|
||
NODE_SYMBOL_DISPLACEMENT(nodeOffset);
|
||
|
||
pSymfile->symcontextFunctionString.pNodeRoot = NULL;
|
||
pSymfile->symcontextFunctionString.pNodeMax =
|
||
(PNODE)((LONG)symbolMax + NODE_SYMBOL_DISPLACEMENT(nodeString));
|
||
pSymfile->symcontextFunctionString.pfnCompare = &CompareSymbolString;
|
||
pSymfile->symcontextFunctionString.nodeDisplacement =
|
||
NODE_SYMBOL_DISPLACEMENT(nodeString);
|
||
|
||
pSymfile->pchPath = malloc(strlen(pPathname) + 1);
|
||
if (!pSymfile->pchPath) {
|
||
dprintf("AllocSymfile - Out of memory\n");
|
||
ExitProcess(STATUS_UNSUCCESSFUL);
|
||
}
|
||
strcpy(pSymfile->pchPath, pPathname);
|
||
|
||
pSymfile->pchName = malloc(strlen(pFilename) + 1);
|
||
if (!pSymfile->pchName) {
|
||
dprintf("AllocSymfile - Out of memory\n");
|
||
ExitProcess(STATUS_UNSUCCESSFUL);
|
||
}
|
||
strcpy(pSymfile->pchName, pFilename);
|
||
|
||
pSymfile->pchExtension = malloc(strlen(pExtension) + 1);
|
||
if (!pSymfile->pchExtension) {
|
||
dprintf("AllocSymfile - Out of memory\n");
|
||
ExitProcess(STATUS_UNSUCCESSFUL);
|
||
}
|
||
strcpy(pSymfile->pchExtension, pExtension);
|
||
|
||
pSymfile->modIndex = modIndex;
|
||
|
||
pSymfile->cLineno = cLineno;
|
||
|
||
if (pCoffLineno) {
|
||
pSymfile->pLineno = malloc((cLineno + 1) * sizeof(LINENO));
|
||
if (!pSymfile->pLineno) {
|
||
dprintf("AllocSymfile - Out of memory\n");
|
||
ExitProcess(STATUS_UNSUCCESSFUL);
|
||
}
|
||
pLineno = pSymfile->pLineno;
|
||
|
||
// define pseudo-lineno structure for start of file
|
||
|
||
pLineno->memoryOffset = 0;
|
||
pLineno->breakLineNumber = 1;
|
||
pLineno->topLineNumber = 1;
|
||
pLineno->topFileOffset = 0;
|
||
pLineno++;
|
||
|
||
// first lineno to process is after the pseudo entry
|
||
|
||
pSymfile->pLinenoNext = pLineno;
|
||
|
||
// process list into remaining entries in array
|
||
|
||
for (index = 0; index < pSymfile->cLineno; index++) {
|
||
memcpy((PUCHAR)&CoffLineno, (PUCHAR)pCoffLineno,
|
||
IMAGE_SIZEOF_LINENUMBER);
|
||
pLineno->memoryOffset = CoffLineno.Type.VirtualAddress;
|
||
pLineno->breakLineNumber = CoffLineno.Linenumber;
|
||
pLineno->topLineNumber = 0xffff;
|
||
pLineno->topFileOffset = -1L;
|
||
pLineno++;
|
||
pCoffLineno = (PIMAGE_LINENUMBER)((PUCHAR)pCoffLineno
|
||
+ IMAGE_SIZEOF_LINENUMBER);
|
||
}
|
||
|
||
// initialize further...
|
||
|
||
pSymfile->nextFileOffset = 0;
|
||
pSymfile->nextLineNumber = 1;
|
||
pSymfile->nextScanState = stStart;
|
||
|
||
// allocate and initialize list of PLINENO's for sorting
|
||
// of line number for the file.
|
||
|
||
pSymfile->ppLinenoSrcLine = malloc(
|
||
(pSymfile->cLineno + 1) * sizeof(PLINENO));
|
||
if (!pSymfile->ppLinenoSrcLine) {
|
||
dprintf("AllocSymfile - Out of memory\n");
|
||
ExitProcess(STATUS_UNSUCCESSFUL);
|
||
}
|
||
|
||
for (index = 0; index < (USHORT)(pSymfile->cLineno + 1); index++)
|
||
*(pSymfile->ppLinenoSrcLine + index) = pSymfile->pLineno + index;
|
||
|
||
// first LINENO to process on scan is after pseudo-entry
|
||
|
||
pSymfile->ppLinenoSrcNext = pSymfile->ppLinenoSrcLine + 1;
|
||
|
||
// sort the pointers for increasing source line numbers
|
||
|
||
SortSrcLinePointers(pSymfile);
|
||
}
|
||
else {
|
||
pSymfile->pLineno = NULL;
|
||
pSymfile->ppLinenoSrcLine = NULL;
|
||
}
|
||
|
||
pSymfile->startOffset = startingOffset;
|
||
pSymfile->endOffset = endingOffset;
|
||
pSymfile->modIndex = modIndex;
|
||
|
||
return pSymfile;
|
||
}
|
||
|
||
/*** DeallocSymbol - release symbol space
|
||
*
|
||
* Purpose:
|
||
* Deallocate the symbol space given by the pointer
|
||
*
|
||
* Input:
|
||
* pSymbolReturn - pointer to symbol to return
|
||
*
|
||
* Output:
|
||
* None.
|
||
*
|
||
*************************************************************************/
|
||
|
||
void DeallocSymbol (PSYMBOL pSymbolReturn)
|
||
{
|
||
free(pSymbolReturn);
|
||
}
|
||
|
||
/*** DeleteSymfile - delete specified symbol file from splay tree
|
||
*
|
||
* Purpose:
|
||
* external routine.
|
||
* Delete the specified symbol file object in both the
|
||
* offset and string trees and deallocate its space.
|
||
*
|
||
* Input:
|
||
* pSymfile - pointer to symfile object to delete
|
||
*
|
||
* Output:
|
||
* None.
|
||
*
|
||
*************************************************************************/
|
||
|
||
void DeleteSymfile (PSYMFILE pSymfile)
|
||
{
|
||
DeleteNode(&(pProcessCurrent->symcontextSymfileOffset),
|
||
&(pSymfile->nodeOffset));
|
||
DeleteNode(&(pProcessCurrent->symcontextSymfileString),
|
||
&(pSymfile->nodeString));
|
||
DeallocSymfile(pSymfile);
|
||
}
|
||
|
||
/*** DeallocSymfile - release symbol file space
|
||
*
|
||
* Purpose:
|
||
* Deallocate the symbol file space given by the pointer
|
||
*
|
||
* Input:
|
||
* pSymfileReturn - pointer to symbol file to return
|
||
*
|
||
* Output:
|
||
* None.
|
||
*
|
||
*************************************************************************/
|
||
|
||
void DeallocSymfile (PSYMFILE pSymfile)
|
||
{
|
||
free(pSymfile->pchPath);
|
||
free(pSymfile->pchName);
|
||
free(pSymfile->pchExtension);
|
||
free(pSymfile->pLineno);
|
||
free(pSymfile->ppLinenoSrcLine);
|
||
free(pSymfile);
|
||
}
|
||
|
||
|
||
/*** ntsdstricmp - case-insensitive string compare
|
||
*
|
||
* Purpose:
|
||
* Compare two strings, but map upper case to lower
|
||
*
|
||
* Input:
|
||
* pchDst - pointer to first string
|
||
* pchSrc - pointer to second string
|
||
*
|
||
* Output:
|
||
* -1 if value(pchDst) < value(pchSrc)
|
||
* 0 if value(pchDst) = value(pchSrc)
|
||
* 1 if value(pchDst) > value(pchSrc)
|
||
*
|
||
*************************************************************************/
|
||
|
||
int ntsdstricmp (PUCHAR pchDst, PUCHAR pchSrc)
|
||
{
|
||
UCHAR ch1;
|
||
UCHAR ch2;
|
||
|
||
do {
|
||
ch1 = (UCHAR)tolower(*pchDst++);
|
||
ch2 = (UCHAR)tolower(*pchSrc++);
|
||
}
|
||
while (ch1 && ch1 == ch2);
|
||
|
||
if (ch1 < ch2)
|
||
return -1;
|
||
else
|
||
return ch1 > ch2;
|
||
}
|
||
|
||
#ifndef NT_SAPI
|
||
|
||
/*** fnListNear - function to list symbols near an address
|
||
*
|
||
* Purpose:
|
||
* from the address specified, access the symbol table to
|
||
* find the closest symbolic addresses both before and after
|
||
* it. output these on one line (if spaces permits).
|
||
*
|
||
* Input:
|
||
* addrstart - address to base listing
|
||
*
|
||
* Output:
|
||
* symbolic and absolute addresses of variable on or before
|
||
* and after the specified address
|
||
*
|
||
*************************************************************************/
|
||
|
||
static char szBlanks[] = " ";
|
||
|
||
void fnListNear (ULONG addrStart)
|
||
{
|
||
PSYMBOL pSymbol;
|
||
PNODE pNode;
|
||
ULONG cbString[2];
|
||
UCHAR szEntry[80];
|
||
PUCHAR pszEntry;
|
||
ULONG count;
|
||
ULONG index;
|
||
|
||
// make a symbol structure with the supplied offset
|
||
|
||
pSymbol = AllocSymbol(addrStart, "", -1);
|
||
|
||
// try to access the node with the offset given.
|
||
// the node pointer returned will be the nearest offset less
|
||
// than the argument (unless it is less than the tree minimum)
|
||
|
||
AccessNode(&(pProcessCurrent->symcontextSymbolOffset),
|
||
&(pSymbol->nodeOffset));
|
||
|
||
// Don't need this anymore, free it.
|
||
|
||
DeallocSymbol(pSymbol);
|
||
|
||
pNode = pProcessCurrent->symcontextSymbolOffset.pNodeRoot;
|
||
|
||
// if empty tree, no symbols, just return
|
||
|
||
if (!pNode)
|
||
return;
|
||
|
||
// if offset of initial node is less than request address,
|
||
// set node pointer to NULL
|
||
|
||
if (PNODE_TO_PSYMBOL(pNode,
|
||
&(pProcessCurrent->symcontextSymbolOffset))->offset
|
||
> addrStart)
|
||
pNode = NULL;
|
||
|
||
// build the string for the symbol before and after (index = 0 and 1)
|
||
|
||
for (index = 0; index < 2; index++) {
|
||
pszEntry = szEntry;
|
||
if (pNode) {
|
||
pSymbol = PNODE_TO_PSYMBOL(pNode,
|
||
&(pProcessCurrent->symcontextSymbolOffset));
|
||
pszEntry += sprintf(pszEntry, "(%08lx) ", pSymbol->offset);
|
||
pszEntry += sprintf(pszEntry, "%s!",
|
||
pImageFromIndex(pSymbol->modIndex)->pszName);
|
||
count = pSymbol->underscores;
|
||
while (count--)
|
||
pszEntry += sprintf(pszEntry, "_");
|
||
pszEntry += sprintf(pszEntry, "%s", pSymbol->string);
|
||
}
|
||
else {
|
||
if (index == 0)
|
||
pszEntry += sprintf(pszEntry, "(%08lx) ", addrStart);
|
||
pszEntry += sprintf(pszEntry, "<no symbol>");
|
||
}
|
||
|
||
cbString[index] = pszEntry - szEntry;
|
||
|
||
if (index == 0) {
|
||
dprintf("%s", szEntry);
|
||
pNode = NextNode(&(pProcessCurrent->symcontextSymbolOffset),
|
||
pNode);
|
||
}
|
||
}
|
||
|
||
// the first string has been output, szEntry has the second string
|
||
// and cbString[0] and [1] have their respective sizes.
|
||
|
||
if (cbString[0] + cbString[1] < 75)
|
||
dprintf(" | ");
|
||
else {
|
||
dprintf("\n");
|
||
count = 78 - cbString[1];
|
||
dprintf(&szBlanks[sizeof(szBlanks) - count]);
|
||
}
|
||
dprintf("%s\n", szEntry);
|
||
}
|
||
#endif /* NT_SAPI */
|
||
|
||
void SortSrcLinePointers (PSYMFILE pSymfile)
|
||
{
|
||
PPLINENO ppLineno = pSymfile->ppLinenoSrcLine;
|
||
PLINENO pLinenoV;
|
||
USHORT N;
|
||
USHORT h;
|
||
USHORT i;
|
||
USHORT j;
|
||
|
||
// PDK KLUGDE:::
|
||
if (!ppLineno) return;
|
||
|
||
N = (USHORT)(pSymfile->cLineno - 1);
|
||
|
||
h = 1;
|
||
do
|
||
h = (USHORT)(3 * h + 1);
|
||
while (h <= N);
|
||
|
||
do {
|
||
h = (USHORT)(h / 3);
|
||
for (i = h; i < N; i++) {
|
||
pLinenoV = *(ppLineno + i);
|
||
j = i;
|
||
while ((*(ppLineno + j - h))->breakLineNumber
|
||
> pLinenoV->breakLineNumber) {
|
||
*(ppLineno + j) = *(ppLineno + j - h);
|
||
j = j - h;
|
||
if (j < h)
|
||
break;
|
||
}
|
||
*(ppLineno + j) = pLinenoV;
|
||
}
|
||
}
|
||
while (h > 1);
|
||
}
|
||
|
||
#ifndef NT_SAPI
|
||
#if 0
|
||
void OutputAtLineno (PSYMFILE pSymfile, PLINENO pLineno)
|
||
{
|
||
USHORT index;
|
||
UCHAR buffer[180];
|
||
FILE * fhandle;
|
||
|
||
UpdateLineno(pSymfile, pLineno);
|
||
fhandle = LocateTextInSource(pSymfile, pLineno);
|
||
if (fhandle)
|
||
for (index = pLineno->topLineNumber;
|
||
index <= pLineno->breakLineNumber; index++) {
|
||
if (!fgets(buffer, sizeof(buffer), fhandle))
|
||
error(FILEREAD);
|
||
dprintf("%4d: %s", index, buffer);
|
||
}
|
||
}
|
||
#endif
|
||
|
||
void UpdateLineno (PSYMFILE pSymfile, PLINENO pLineno)
|
||
{
|
||
PPLINENO ppLinenoNext;
|
||
UCHAR scanState;
|
||
USHORT nextLineNumber;
|
||
USHORT topLineNumber;
|
||
ULONG topFileOffset;
|
||
FILE * fhandle;
|
||
UCHAR ch;
|
||
|
||
// if line number structure is already processed,
|
||
// then just return.
|
||
|
||
if (pLineno->topLineNumber == 0xffff) {
|
||
|
||
// copy variables from the symbol file structure
|
||
|
||
ppLinenoNext = pSymfile->ppLinenoSrcNext;
|
||
scanState = pSymfile->nextScanState;
|
||
nextLineNumber = pSymfile->nextLineNumber;
|
||
|
||
// open and locate the file to the position specified in
|
||
// the symbol file structure. if no handle, return error.
|
||
|
||
fhandle = LocateTextInSource(pSymfile, NULL);
|
||
if (!fhandle)
|
||
return;
|
||
|
||
// for each LINENO structure pointed by ppLinenoNext
|
||
// until pLineno is processed, compute the
|
||
// topLineNumber and topFileOffset.
|
||
|
||
do {
|
||
topFileOffset = ftell(fhandle);
|
||
topLineNumber = nextLineNumber;
|
||
|
||
// test if the current LINENO structure has the same
|
||
// breakLineNumber as the previous LINENO in the
|
||
// ppLineno list.
|
||
|
||
if ((*ppLinenoNext)->breakLineNumber ==
|
||
(*(ppLinenoNext - 1))->breakLineNumber) {
|
||
|
||
// if this is a repeating line number, just copy
|
||
// the topFileOffset and topLineNumber entries
|
||
|
||
(*ppLinenoNext)->topFileOffset =
|
||
(*(ppLinenoNext - 1))->topFileOffset;
|
||
(*ppLinenoNext)->topLineNumber =
|
||
(*(ppLinenoNext - 1))->topLineNumber;
|
||
}
|
||
|
||
else {
|
||
|
||
// nonrepeating line number - determine new topFileOffset
|
||
// and topLineNumber entries
|
||
|
||
// scan each line in the source file, numbered by
|
||
// nextLineNumber until the line numbered by
|
||
// (*ppLinenoNext)->breakLineNumber is scanned.
|
||
|
||
do {
|
||
|
||
// to scan a source file line, read each character
|
||
// and change scanState appropriately and exit
|
||
// when a '\n' is read.
|
||
do {
|
||
ch = (UCHAR)getc(fhandle);
|
||
switch (ch) {
|
||
case '\t':
|
||
case ' ':
|
||
scanState = WhiteSpace[scanState];
|
||
break;
|
||
|
||
case '/':
|
||
scanState = Slash[scanState];
|
||
break;
|
||
|
||
case '*':
|
||
scanState = Star[scanState];
|
||
break;
|
||
|
||
case '#':
|
||
scanState = Pound[scanState];
|
||
break;
|
||
|
||
case '\n':
|
||
case '\r':
|
||
break;
|
||
|
||
case (UCHAR)EOF:
|
||
error(FILEREAD);
|
||
|
||
default:
|
||
scanState = OtherChar[scanState];
|
||
break;
|
||
}
|
||
}
|
||
while (ch != '\n');
|
||
|
||
// if the final scan state of the line is a comment
|
||
// and the line is not a breaking line number,
|
||
// set the topFileOffset and topLineNumber to
|
||
// the line after the one just scanned.
|
||
|
||
if (fCommentType[scanState]
|
||
&& nextLineNumber != pLineno->breakLineNumber) {
|
||
topFileOffset = ftell(fhandle);
|
||
topLineNumber = (USHORT)(nextLineNumber + 1);
|
||
}
|
||
|
||
// set the state for the next line, either stStart
|
||
// or stSlStar for a continuing multiline comment
|
||
|
||
scanState = Return[scanState];
|
||
}
|
||
while (nextLineNumber++ != (*ppLinenoNext)->breakLineNumber);
|
||
|
||
// put topFileOffset and topLineNumber into the pLineno
|
||
// to finish its processing
|
||
|
||
(*ppLinenoNext)->topFileOffset = topFileOffset;
|
||
(*ppLinenoNext)->topLineNumber = topLineNumber;
|
||
}
|
||
}
|
||
while (*(ppLinenoNext++) != pLineno);
|
||
|
||
// set the variables back in the symbol file structure
|
||
// for the next call
|
||
|
||
pSymfile->ppLinenoSrcNext = ppLinenoNext;
|
||
pSymfile->nextScanState = scanState;
|
||
pSymfile->nextFileOffset = ftell(fhandle);
|
||
pSymfile->nextLineNumber = nextLineNumber;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
FILE * LocateTextInSource (PSYMFILE pSymfile, PLINENO pLineno)
|
||
{
|
||
static FILE * fhandle = NULL;
|
||
static PSYMFILE pSymfileOpened = NULL;
|
||
UCHAR chFilename[512];
|
||
PUCHAR pchTemp;
|
||
|
||
if (pSymfile != pSymfileOpened) {
|
||
|
||
if (fhandle) {
|
||
fclose(fhandle);
|
||
fhandle = NULL;
|
||
pSymfileOpened = NULL;
|
||
}
|
||
|
||
if (pSymfile && pSymfile->pchPath)
|
||
do {
|
||
strcpy(chFilename, pSymfile->pchPath);
|
||
strcat(chFilename, pSymfile->pchName);
|
||
strcat(chFilename, pSymfile->pchExtension);
|
||
fhandle = fopen(chFilename, "r");
|
||
if (!fhandle) {
|
||
dprintf("enter path for '%s%s%s' (cr for none):",
|
||
pSymfile->pchPath, pSymfile->pchName,
|
||
pSymfile->pchExtension);
|
||
NtsdPrompt("", chFilename, 512);
|
||
RemoveDelChar(chFilename);
|
||
// gets(chFilename);
|
||
//#ifdef KERNEL
|
||
// if (*chFilename!=13&&*chFilename!=10) {
|
||
//#else
|
||
if (*chFilename) {
|
||
//#endif
|
||
pchTemp = chFilename + strlen(chFilename) - 1;
|
||
if (*pchTemp != ':' && *pchTemp != '\\')
|
||
strcat(pchTemp + 1, "\\");
|
||
pSymfile->pchPath =
|
||
realloc(pSymfile->pchPath,
|
||
strlen(chFilename) + 1);
|
||
strcpy(pSymfile->pchPath, chFilename);
|
||
}
|
||
else {
|
||
free(pSymfile->pchPath);
|
||
pSymfile->pchPath = NULL;
|
||
return NULL;
|
||
}
|
||
}
|
||
else
|
||
pSymfileOpened = pSymfile;
|
||
}
|
||
while (!fhandle && chFilename[0]);
|
||
}
|
||
|
||
if (fhandle)
|
||
fseek(fhandle, pLineno ? pLineno->topFileOffset
|
||
: pSymfile->nextFileOffset, SEEK_SET);
|
||
|
||
return fhandle;
|
||
}
|
||
|
||
|
||
|
||
void OutputSourceLines (PSYMFILE pSymfile, USHORT startLineNum, USHORT count)
|
||
{
|
||
PPLINENO ppLineno;
|
||
USHORT indexLow;
|
||
USHORT indexTest;
|
||
USHORT indexHigh;
|
||
|
||
// search the PLINENO array for the pointer to the LINENO
|
||
// structure having the line number given.
|
||
|
||
ppLineno = pSymfile->ppLinenoSrcLine;
|
||
indexLow = 1;
|
||
|
||
// PDK KLUDGE:::
|
||
if (!(indexHigh = pSymfile->cLineno)) return;
|
||
|
||
do {
|
||
indexTest = (USHORT)((indexLow + indexHigh) / 2);
|
||
if (startLineNum > (*(ppLineno + indexTest))->breakLineNumber)
|
||
indexLow = (USHORT)(indexTest + 1);
|
||
else if (startLineNum < (*(ppLineno + indexTest))->breakLineNumber)
|
||
indexHigh = (USHORT)(indexTest - 1);
|
||
else
|
||
indexLow = indexHigh = indexTest;
|
||
}
|
||
while (indexLow < indexHigh);
|
||
|
||
// if startLineNum is larger than the maximum line number in
|
||
// the list, indexLow is past the last entry.
|
||
// set indexLow to the last entry in this case.
|
||
|
||
if (indexLow > pSymfile->cLineno)
|
||
indexLow--;
|
||
|
||
// indexLow refers to the LINENO structure with a line
|
||
// number equal to or greater than startLineNum.
|
||
|
||
UpdateLineno(pSymfile, *(ppLineno + indexLow));
|
||
if (startLineNum < (*(ppLineno + indexLow))->topLineNumber)
|
||
indexLow--;
|
||
OutputLines(pSymfile, *(ppLineno + indexLow), startLineNum, count);
|
||
}
|
||
|
||
BOOLEAN OutputSourceFromOffset (ULONG offset, BOOLEAN fMatch)
|
||
{
|
||
PSYMFILE pSymfile;
|
||
PLINENO pLineno;
|
||
BOOLEAN fOutput = FALSE;
|
||
|
||
pLineno = GetLinenoFromOffset(&pSymfile, offset);
|
||
if (pLineno) {
|
||
UpdateLineno(pSymfile, pLineno);
|
||
if (!fMatch || pLineno->memoryOffset == offset)
|
||
fOutput = OutputLines(pSymfile, pLineno, pLineno->topLineNumber,
|
||
(SHORT)(pLineno->breakLineNumber
|
||
- pLineno->topLineNumber + 1));
|
||
}
|
||
return fOutput;
|
||
}
|
||
|
||
BOOLEAN OutputLines (PSYMFILE pSymfile, PLINENO pLineno, USHORT startLineNum,
|
||
USHORT count)
|
||
{
|
||
FILE * fhandle;
|
||
UCHAR buffer[180];
|
||
USHORT lineNumber;
|
||
PSYMFILE pSymfileNext;
|
||
PLINENO pLinenoNext;
|
||
|
||
UpdateLineno(pSymfile, pLineno);
|
||
fhandle = LocateTextInSource(pSymfile, pLineno);
|
||
if (!fhandle)
|
||
return FALSE;
|
||
lineNumber = pLineno->topLineNumber;
|
||
|
||
// output module and filename as label.
|
||
|
||
dprintf("%s!%s:\n", pImageFromIndex(pSymfile->modIndex)->pszName,
|
||
pSymfile->pchName);
|
||
while (count) {
|
||
|
||
// read the next line - report read error
|
||
|
||
fgets(buffer, sizeof(buffer), fhandle);
|
||
if (ferror(fhandle))
|
||
error(FILEREAD);
|
||
|
||
// if EOF and no lines printed, break last valid line
|
||
// if lines printed, just exit
|
||
|
||
if (feof(fhandle)) {
|
||
if (--lineNumber < startLineNum) {
|
||
startLineNum = lineNumber;
|
||
count = 1;
|
||
}
|
||
else
|
||
break;
|
||
}
|
||
|
||
if (lineNumber >= startLineNum) {
|
||
dprintf("%4d", lineNumber);
|
||
|
||
// if linenumber is on a breakpoint,
|
||
// output a '>', if not, ':'.
|
||
|
||
pLinenoNext = GetLinenoFromFilename(pSymfile->pchName,
|
||
&pSymfileNext, lineNumber, pSymfile->modIndex);
|
||
if (lineNumber == pLinenoNext->breakLineNumber)
|
||
dprintf(">");
|
||
else
|
||
dprintf(":");
|
||
|
||
dprintf(" %s", buffer);
|
||
|
||
count--;
|
||
}
|
||
lineNumber++;
|
||
}
|
||
pSymfileLast = pSymfile;
|
||
lineNumberLast = lineNumber;
|
||
|
||
return TRUE;
|
||
}
|
||
#endif /* NT_SAPI */
|
||
|
||
PVOID FetchImageDirectoryEntry(int Handle, USHORT DirectoryEntry, PULONG Size, PULONG Base)
|
||
{
|
||
PUCHAR SectionName;
|
||
USHORT Signature;
|
||
ULONG i, DirectoryAddress;
|
||
IMAGE_FILE_HEADER CoffFileHdr;
|
||
IMAGE_OPTIONAL_HEADER CoffOptionalHdr;
|
||
IMAGE_SECTION_HEADER CoffSectionHdr;
|
||
ULONG DosHeader[16], NtSignature;
|
||
|
||
if ( DirectoryEntry >= IMAGE_NUMBEROF_DIRECTORY_ENTRIES ) {
|
||
return NULL;
|
||
}
|
||
|
||
CV_SEEK(Handle, 0, SEEK_SET);
|
||
CV_READ(Handle, &Signature, sizeof(USHORT));
|
||
CV_SEEK(Handle, 0, SEEK_SET);
|
||
|
||
if (Signature == IMAGE_DOS_SIGNATURE) {
|
||
CV_READ(Handle, &DosHeader, 16*sizeof(ULONG));
|
||
CV_SEEK(Handle, DosHeader[15], SEEK_SET);
|
||
CV_READ(Handle, &NtSignature, sizeof(ULONG));
|
||
if (NtSignature != IMAGE_NT_SIGNATURE) {
|
||
printf("\nPE signature not found\n");
|
||
}
|
||
}
|
||
CV_READ(Handle, &CoffFileHdr, sizeof(IMAGE_FILE_HEADER));
|
||
CV_READ(Handle, &CoffOptionalHdr, CoffFileHdr.SizeOfOptionalHeader);
|
||
|
||
#ifdef NT_SAPI
|
||
ObjectTableCount = CoffFileHdr.NumberOfSections;
|
||
ObjectTableOffset = CV_TELL(Handle);
|
||
#endif
|
||
|
||
if (CoffFileHdr.SizeOfOptionalHeader < IMAGE_SIZEOF_NT_OPTIONAL_HEADER) {
|
||
//
|
||
// must be a rom image
|
||
//
|
||
*Base = 0;
|
||
|
||
switch (DirectoryEntry) {
|
||
case IMAGE_DIRECTORY_ENTRY_EXPORT : SectionName = ".edata"; break;
|
||
case IMAGE_DIRECTORY_ENTRY_IMPORT : SectionName = ".idata"; break;
|
||
case IMAGE_DIRECTORY_ENTRY_RESOURCE : SectionName = ".rsrc"; break;
|
||
case IMAGE_DIRECTORY_ENTRY_EXCEPTION : SectionName = ".pdata"; break;
|
||
case IMAGE_DIRECTORY_ENTRY_SECURITY : SectionName = ".mdc"; break;
|
||
case IMAGE_DIRECTORY_ENTRY_BASERELOC : SectionName = ".reloc"; break;
|
||
case IMAGE_DIRECTORY_ENTRY_DEBUG : SectionName = ".debug"; break;
|
||
default : SectionName = "";
|
||
}
|
||
|
||
for (i=0; i<CoffFileHdr.NumberOfSections; i++) {
|
||
CV_READ(Handle, &CoffSectionHdr, sizeof(IMAGE_SECTION_HEADER));
|
||
if (!strcmp(CoffSectionHdr.Name, SectionName)) {
|
||
*Size = CoffSectionHdr.SizeOfRawData;
|
||
return( (PVOID)CoffSectionHdr.PointerToRawData );
|
||
}
|
||
}
|
||
return NULL;
|
||
} else {
|
||
*Base = CoffOptionalHdr.ImageBase;
|
||
}
|
||
if (!(DirectoryAddress = CoffOptionalHdr.DataDirectory[ DirectoryEntry ].VirtualAddress)) {
|
||
return( NULL );
|
||
}
|
||
*Size = CoffOptionalHdr.DataDirectory[ DirectoryEntry ].Size;
|
||
|
||
for (i=0; i<CoffFileHdr.NumberOfSections; i++) {
|
||
CV_READ(Handle, &CoffSectionHdr, sizeof(IMAGE_SECTION_HEADER));
|
||
if (DirectoryAddress >= CoffSectionHdr.VirtualAddress &&
|
||
DirectoryAddress <= CoffSectionHdr.VirtualAddress + CoffSectionHdr.SizeOfRawData) {
|
||
return( (PVOID)((DirectoryAddress - CoffSectionHdr.VirtualAddress) + CoffSectionHdr.PointerToRawData) );
|
||
}
|
||
}
|
||
return( NULL );
|
||
}
|
||
|