mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1224 lines
32 KiB
1224 lines
32 KiB
#include "ntsdp.h"
|
|
|
|
#ifndef KERNEL
|
|
#include <profile.h>
|
|
#endif
|
|
|
|
|
|
#ifdef KERNEL
|
|
extern BOOLEAN KdVerbose;
|
|
#define fVerboseOutput KdVerbose
|
|
#else
|
|
extern BOOLEAN fVerboseOutput;
|
|
#endif
|
|
|
|
|
|
typedef struct _EXAMINE_INFO {
|
|
LPSTR Pattern;
|
|
PIMAGE_INFO Image;
|
|
} EXAMINE_INFO, *PEXAMINE_INFO;
|
|
|
|
LPSTR SymbolSearchPath;
|
|
|
|
extern int fControlC;
|
|
extern BOOL cdecl cmdHandler(ULONG);
|
|
extern BOOL cdecl waitHandler(ULONG);
|
|
extern BOOLEAN ppcPrefix;
|
|
|
|
|
|
|
|
PSYMBOL
|
|
GetFunctionFromOffset(
|
|
ULONG Address
|
|
)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
|
|
#ifndef KERNEL
|
|
|
|
ULONG
|
|
ReadSectionHeaders(
|
|
IMAGE_INFO *pImage,
|
|
ULONG cMaxSections,
|
|
IMAGE_SECTION_HEADER *pImageSectionHeader
|
|
)
|
|
{
|
|
IMAGE_DOS_HEADER ImageDosHeader;
|
|
IMAGE_NT_HEADERS ImageNTHeader;
|
|
ULONG NTImageHeaderAddress;
|
|
ULONG cSections;
|
|
ULONG cBytes;
|
|
ADDR addr;
|
|
|
|
addr.type = FLAT_COMPUTED;
|
|
addr.flat = (ULONG)(pImage->lpBaseOfImage);
|
|
|
|
cBytes = GetMemString(&addr,(PUCHAR)&ImageDosHeader,sizeof(ImageDosHeader));
|
|
|
|
// compute the NT image header address
|
|
addr.flat = (ULONG)((ULONG)pImage->lpBaseOfImage +
|
|
ImageDosHeader.e_lfanew);
|
|
|
|
NTImageHeaderAddress = addr.flat;
|
|
|
|
// Read the NT image header to compute the section offset.
|
|
cBytes = GetMemString(&addr,(PUCHAR)&ImageNTHeader,sizeof(ImageNTHeader));
|
|
|
|
// Compute the section offset and read in the section.
|
|
addr.flat = NTImageHeaderAddress +
|
|
FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) +
|
|
ImageNTHeader.FileHeader.SizeOfOptionalHeader;
|
|
|
|
cSections = ImageNTHeader.FileHeader.NumberOfSections;
|
|
|
|
if (cSections < cMaxSections)
|
|
{
|
|
// read in all the section values
|
|
cBytes = GetMemString(&addr,
|
|
(PUCHAR)pImageSectionHeader,
|
|
sizeof(IMAGE_SECTION_HEADER) * cSections);
|
|
}
|
|
|
|
return cSections;
|
|
}
|
|
|
|
BOOLEAN
|
|
TestCodeBreakPoint(
|
|
ULONG ImageBase,
|
|
ULONG cSections,
|
|
IMAGE_SECTION_HEADER *pSectionHeader,
|
|
ADDR BrkPntAddr
|
|
)
|
|
{
|
|
ADDR tempAddr = BrkPntAddr;
|
|
PADDR paddr = &tempAddr;
|
|
ULONG BreakPointAddress;
|
|
ULONG i;
|
|
ULONG SectionStartAddress;
|
|
ULONG SectionEndAddress;
|
|
|
|
NotFlat(tempAddr); // Force recomputing of flat address
|
|
ComputeFlatAddress(paddr,NULL);
|
|
|
|
BreakPointAddress = (ULONG)(Flat(*paddr));
|
|
|
|
for (i = 0; i < cSections; i++) {
|
|
if (pSectionHeader[i].Characteristics & IMAGE_SCN_CNT_CODE) {
|
|
SectionStartAddress = pSectionHeader[i].VirtualAddress + ImageBase;
|
|
SectionEndAddress = SectionStartAddress + pSectionHeader[i].Misc.VirtualSize;
|
|
|
|
if ((BreakPointAddress >= SectionStartAddress) &&
|
|
(BreakPointAddress <= SectionEndAddress))
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
#endif
|
|
|
|
void
|
|
GetSymbolStdCall (
|
|
ULONG offset,
|
|
PUCHAR pchBuffer,
|
|
PULONG pDisplacement,
|
|
PUSHORT pStdCallParams
|
|
)
|
|
{
|
|
IMAGEHLP_MODULE mi;
|
|
|
|
if (SymGetModuleInfo( pProcessCurrent->hProcess, offset, &mi )) {
|
|
if (SymGetSymFromAddr( pProcessCurrent->hProcess, offset, pDisplacement, sym )) {
|
|
sprintf( pchBuffer, "%s!%s", mi.ModuleName, sym->Name );
|
|
return;
|
|
}
|
|
}
|
|
*pchBuffer = 0;
|
|
*pDisplacement = offset;
|
|
}
|
|
|
|
PIMAGE_INFO GetModuleIndex (PUCHAR pszName)
|
|
{
|
|
PIMAGE_INFO pImage;
|
|
|
|
//
|
|
// First look for exact match...
|
|
//
|
|
|
|
pImage = pProcessCurrent->pImageHead;
|
|
while (pImage) {
|
|
if (!_stricmp(pszName, pImage->szModuleName))
|
|
return pImage;
|
|
|
|
pImage = pImage->pImageNext;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
PIMAGE_INFO GetCurrentModuleIndex (void)
|
|
{
|
|
ADDR pcvalue;
|
|
PIMAGE_INFO pImage;
|
|
|
|
GetRegPCValue(&pcvalue);
|
|
pImage = pProcessCurrent->pImageHead;
|
|
while( pImage ) {
|
|
if (Flat(pcvalue) >= (ULONG)pImage->lpBaseOfImage &&
|
|
Flat(pcvalue) < (ULONG)pImage->lpBaseOfImage + (ULONG)pImage->dwSizeOfImage) {
|
|
return pImage;
|
|
}
|
|
pImage = pImage->pImageNext;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
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();
|
|
}
|
|
|
|
BOOL
|
|
ParseExamineSymbolEnumerator(
|
|
LPSTR Name,
|
|
ULONG Address,
|
|
ULONG Size,
|
|
PEXAMINE_INFO ExamineInfo
|
|
)
|
|
{
|
|
if (MatchPattern( Name, ExamineInfo->Pattern )) {
|
|
dprintf( "%08x %s!%s\n", Address, ExamineInfo->Image->szModuleName, Name );
|
|
}
|
|
|
|
if (fControlC) {
|
|
fControlC = 0;
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*** 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 '?', '*', '['-']'.
|
|
*
|
|
* Input:
|
|
* pchCommand - pointer to current command string
|
|
*
|
|
* Output:
|
|
* offset and string name of symbols displayed
|
|
*
|
|
*************************************************************************/
|
|
|
|
void parseExamine (void)
|
|
{
|
|
UCHAR chString[SYMBOLSIZE];
|
|
UCHAR ch;
|
|
PUCHAR pchString = chString;
|
|
PUCHAR pchStart;
|
|
BOOLEAN fOutput;
|
|
ULONG cntunderscores = 0;
|
|
ULONG count;
|
|
PSYMBOL pSymbol;
|
|
PUCHAR pchSrc;
|
|
int status = 0;
|
|
PIMAGE_INFO pImage;
|
|
EXAMINE_INFO ExamineInfo;
|
|
#ifdef _X86_
|
|
PFPO_DATA pFpoData;
|
|
#endif
|
|
|
|
#ifndef KERNEL
|
|
unsigned char FunctionName[MAX_SYMBOL_LEN];
|
|
ULONG brkptno;
|
|
ADDR addr;
|
|
IMAGE_SECTION_HEADER aSectionHeaders[MAX_SECTIONS];
|
|
ULONG Sections;
|
|
ULONG cBrkptCount = 0;
|
|
#endif
|
|
|
|
#if defined(KERNEL)
|
|
SetConsoleCtrlHandler( waitHandler, FALSE );
|
|
SetConsoleCtrlHandler( cmdHandler, TRUE );
|
|
#endif
|
|
|
|
// get module pointer from name in command line (<string>!)
|
|
|
|
pImage = ParseModuleIndex();
|
|
if (!pImage) {
|
|
error(VARDEF);
|
|
}
|
|
|
|
#ifndef KERNEL
|
|
if (!PROFILING) {
|
|
ch = PeekChar();
|
|
} else {
|
|
ch = *pchCommand;
|
|
}
|
|
#else
|
|
ch = PeekChar();
|
|
#endif
|
|
|
|
// 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);
|
|
}
|
|
}
|
|
|
|
pchCommand++;
|
|
|
|
while (ch == '_') {
|
|
*pchString++ = ch;
|
|
ch = *pchCommand++;
|
|
}
|
|
|
|
pchStart = pchString;
|
|
ch = (UCHAR)toupper(ch);
|
|
while (ch && ch != ';' && ch != ' ') {
|
|
*pchString++ = ch;
|
|
ch = (UCHAR)toupper(*pchCommand); pchCommand++;
|
|
}
|
|
*pchString = '\0';
|
|
pchCommand--;
|
|
|
|
ExamineInfo.Pattern = pchStart;
|
|
ExamineInfo.Image = pImage;
|
|
|
|
SymEnumerateSymbols(
|
|
pProcessCurrent->hProcess,
|
|
(ULONG)pImage->lpBaseOfImage,
|
|
ParseExamineSymbolEnumerator,
|
|
&ExamineInfo
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
/*** 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
|
|
*
|
|
*************************************************************************/
|
|
void fnListNear (ULONG addrStart)
|
|
{
|
|
ULONG Displacement;
|
|
IMAGEHLP_MODULE mi;
|
|
|
|
|
|
if (SymGetSymFromAddr( pProcessCurrent->hProcess, addrStart, &Displacement, sym )) {
|
|
|
|
if (!SymGetModuleInfo( pProcessCurrent->hProcess, addrStart, &mi )) {
|
|
return;
|
|
}
|
|
|
|
dprintf( "(%08x) %s!%s", sym->Address, mi.ModuleName, sym->Name );
|
|
if (Displacement) {
|
|
dprintf( "+0x%x ", Displacement );
|
|
} else {
|
|
dprintf( " " );
|
|
}
|
|
|
|
if (SymGetSymNext( pProcessCurrent->hProcess, sym )) {
|
|
dprintf( "| (%08x) %s!%s", sym->Address, mi.ModuleName, sym->Name );
|
|
}
|
|
dprintf( "\n" );
|
|
}
|
|
}
|
|
|
|
void
|
|
DumpModuleTable(
|
|
BOOLEAN fLineInfo
|
|
)
|
|
{
|
|
PIMAGE_INFO pImage;
|
|
IMAGEHLP_MODULE mi;
|
|
|
|
|
|
dprintf("start end module name\n");
|
|
pImage = pProcessCurrent->pImageHead;
|
|
while (pImage) {
|
|
if (!SymGetModuleInfo( pProcessCurrent->hProcess, (ULONG)pImage->lpBaseOfImage, &mi )) {
|
|
pImage = pImage->pImageNext;
|
|
continue;
|
|
}
|
|
|
|
_strlwr( pImage->szModuleName );
|
|
|
|
dprintf( "%08lx %08lx %-8s ",
|
|
pImage->lpBaseOfImage,
|
|
(ULONG)(pImage->lpBaseOfImage) + pImage->dwSizeOfImage,
|
|
pImage->szModuleName
|
|
);
|
|
|
|
if (pImage->GoodCheckSum) {
|
|
dprintf( " " );
|
|
} else {
|
|
dprintf( "û " );
|
|
}
|
|
|
|
if (mi.SymType == SymDeferred) {
|
|
dprintf( "(deferred) " );
|
|
} else if (mi.SymType == SymNone) {
|
|
dprintf( "(no symbolic information) " );
|
|
} else {
|
|
switch( mi.SymType ) {
|
|
case SymCoff:
|
|
dprintf( "(coff symbols) " );
|
|
break;
|
|
|
|
case SymCv:
|
|
dprintf( "(codeview symbols) " );
|
|
break;
|
|
|
|
case SymPdb:
|
|
dprintf( "(pdb symbols) " );
|
|
break;
|
|
|
|
case SymExport:
|
|
dprintf( "(export symbols) " );
|
|
break;
|
|
}
|
|
_strlwr( mi.LoadedImageName );
|
|
dprintf( "%s", mi.LoadedImageName );
|
|
}
|
|
dprintf( "\n" );
|
|
|
|
if (fControlC) {
|
|
fControlC = 0;
|
|
break;
|
|
}
|
|
|
|
pImage = pImage->pImageNext;
|
|
}
|
|
}
|
|
|
|
/*** MatchPattern - check if string matches pattern
|
|
*
|
|
* Comments:Purpose:
|
|
*
|
|
* Pattern is assumed to be in upper case
|
|
*
|
|
* Supports:
|
|
* * - Matches any number of characters (including zero)
|
|
* ? - Matches any 1 character
|
|
* [set] - Matches any charater to charater in set
|
|
* (set can be a list or range)
|
|
*
|
|
*
|
|
*************************************************************************/
|
|
BOOLEAN MatchPattern (PUCHAR String, PUCHAR Pattern)
|
|
{
|
|
UCHAR c, p, l;
|
|
|
|
for (; ;) {
|
|
switch (p = *Pattern++) {
|
|
case 0: // end of pattern
|
|
return *String ? FALSE : TRUE; // if end of string TRUE
|
|
|
|
case '*':
|
|
while (*String) { // match zero or more char
|
|
if (MatchPattern (String++, Pattern))
|
|
return TRUE;
|
|
}
|
|
return MatchPattern (String, Pattern);
|
|
|
|
case '?':
|
|
if (*String++ == 0) // match any one char
|
|
return FALSE; // not end of string
|
|
break;
|
|
|
|
case '[':
|
|
if ( (c = *String++) == 0) // match char set
|
|
return FALSE; // syntax
|
|
|
|
c = toupper(c);
|
|
l = 0;
|
|
while (p = *Pattern++) {
|
|
if (p == ']') // if end of char set, then
|
|
return FALSE; // no match found
|
|
|
|
if (p == '-') { // check a range of chars?
|
|
p = *Pattern; // get high limit of range
|
|
if (p == 0 || p == ']')
|
|
return FALSE; // syntax
|
|
|
|
if (c >= l && c <= p)
|
|
break; // if in range, move on
|
|
}
|
|
|
|
l = p;
|
|
if (c == p) // if char matches this element
|
|
break; // move on
|
|
}
|
|
|
|
while (p && p != ']') // got a match in char set
|
|
p = *Pattern++; // skip to end of set
|
|
|
|
break;
|
|
|
|
default:
|
|
c = *String++;
|
|
if (toupper(c) != p) // check for exact char
|
|
return FALSE; // not a match
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void GetCurrentMemoryOffsets (PULONG pMemoryLow, PULONG pMemoryHigh)
|
|
{
|
|
*pMemoryLow = (ULONG)-1L; // default value for no source
|
|
}
|
|
|
|
|
|
ULONG
|
|
ReadImageData(
|
|
PULONG Address,
|
|
HANDLE hFile,
|
|
LPVOID Buffer,
|
|
ULONG Size
|
|
)
|
|
{
|
|
#ifdef KERNEL
|
|
|
|
NTSTATUS Status;
|
|
ULONG Result;
|
|
|
|
|
|
if (hFile) {
|
|
|
|
ULONG Result;
|
|
|
|
if (!SetFilePointer( hFile, *Address, NULL, FILE_BEGIN )) {
|
|
return 0;
|
|
}
|
|
|
|
if (!ReadFile( hFile, Buffer, Size, &Result, NULL)) {
|
|
return 0;
|
|
}
|
|
|
|
*Address += Size;
|
|
return Size;
|
|
|
|
} else {
|
|
|
|
Status = DbgKdReadVirtualMemory(
|
|
(PVOID)*Address,
|
|
(PVOID)Buffer,
|
|
Size,
|
|
&Result
|
|
);
|
|
if (!NT_SUCCESS(Status) || (Result < (ULONG)Size)) {
|
|
return 0;
|
|
}
|
|
*Address += Size;
|
|
return Size;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
if (hFile) {
|
|
|
|
ULONG Result;
|
|
|
|
if (!SetFilePointer( hFile, *Address, NULL, FILE_BEGIN )) {
|
|
return 0;
|
|
}
|
|
|
|
if (!ReadFile( hFile, Buffer, Size, &Result, NULL)) {
|
|
return 0;
|
|
}
|
|
|
|
*Address += Size;
|
|
return Size;
|
|
|
|
} else {
|
|
|
|
BOOLEAN Status;
|
|
ULONG Result;
|
|
|
|
Status = ReadVirtualMemory(
|
|
(PVOID)*Address,
|
|
(PVOID)Buffer,
|
|
Size,
|
|
&Result
|
|
);
|
|
if (!Status || (Result < (ULONG)Size)) {
|
|
return 0;
|
|
}
|
|
*Address += Size;
|
|
return Size;
|
|
|
|
}
|
|
|
|
#endif
|
|
}
|
|
|
|
BOOL
|
|
GetModnameFromImageInternal(
|
|
DWORD BaseOfDll,
|
|
HANDLE hFile,
|
|
LPSTR lpName
|
|
)
|
|
{
|
|
IMAGE_DEBUG_DIRECTORY DebugDir;
|
|
PIMAGE_DEBUG_MISC pMisc;
|
|
PIMAGE_DEBUG_MISC pT;
|
|
DWORD rva;
|
|
int nDebugDirs;
|
|
int i;
|
|
int j;
|
|
int l;
|
|
BOOL rVal = FALSE;
|
|
PVOID pExeName;
|
|
IMAGE_NT_HEADERS nh;
|
|
IMAGE_DOS_HEADER dh;
|
|
IMAGE_ROM_OPTIONAL_HEADER rom;
|
|
DWORD address;
|
|
DWORD sig;
|
|
PIMAGE_SECTION_HEADER pSH;
|
|
DWORD cb;
|
|
NTSTATUS Status;
|
|
ULONG Result;
|
|
|
|
|
|
lpName[0] = 0;
|
|
|
|
if (hFile) {
|
|
address = 0;
|
|
} else {
|
|
address = BaseOfDll;
|
|
}
|
|
|
|
ReadImageData( &address, hFile, &dh, sizeof(dh) );
|
|
|
|
if (dh.e_magic == IMAGE_DOS_SIGNATURE) {
|
|
address = (ULONG)BaseOfDll + dh.e_lfanew;
|
|
} else {
|
|
address = (ULONG)BaseOfDll;
|
|
}
|
|
|
|
if (hFile) {
|
|
address -= (ULONG)BaseOfDll;
|
|
}
|
|
|
|
ReadImageData( &address, hFile, &sig, sizeof(sig) );
|
|
address -= sizeof(sig);
|
|
|
|
if (sig != IMAGE_NT_SIGNATURE) {
|
|
ReadImageData( &address, hFile, &nh.FileHeader, sizeof(IMAGE_FILE_HEADER) );
|
|
if (nh.FileHeader.SizeOfOptionalHeader == IMAGE_SIZEOF_ROM_OPTIONAL_HEADER) {
|
|
ReadImageData( &address, hFile, &rom, sizeof(rom) );
|
|
ZeroMemory( &nh.OptionalHeader, sizeof(nh.OptionalHeader) );
|
|
nh.OptionalHeader.SizeOfImage = rom.SizeOfCode;
|
|
nh.OptionalHeader.ImageBase = rom.BaseOfCode;
|
|
} else {
|
|
return FALSE;
|
|
}
|
|
} else {
|
|
ReadImageData( &address, hFile, &nh, sizeof(nh) );
|
|
}
|
|
|
|
cb = nh.FileHeader.NumberOfSections * IMAGE_SIZEOF_SECTION_HEADER;
|
|
pSH = malloc( cb );
|
|
ReadImageData( &address, hFile, pSH, cb );
|
|
|
|
nDebugDirs = nh.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size /
|
|
sizeof(IMAGE_DEBUG_DIRECTORY);
|
|
|
|
if (!nDebugDirs) {
|
|
return FALSE;
|
|
}
|
|
|
|
rva = nh.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress;
|
|
|
|
for(i = 0; i < nh.FileHeader.NumberOfSections; i++) {
|
|
if (rva >= pSH[i].VirtualAddress &&
|
|
rva < pSH[i].VirtualAddress + pSH[i].SizeOfRawData) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i >= nh.FileHeader.NumberOfSections) {
|
|
return FALSE;
|
|
}
|
|
|
|
rva = rva - pSH[i].VirtualAddress;
|
|
if (hFile) {
|
|
rva += pSH[i].PointerToRawData;
|
|
} else {
|
|
rva += pSH[i].VirtualAddress;
|
|
}
|
|
|
|
for (j = 0; j < nDebugDirs; j++) {
|
|
|
|
address = rva + (sizeof(DebugDir) * j) + (ULONG)BaseOfDll;
|
|
if (hFile) {
|
|
address -= (ULONG)BaseOfDll;
|
|
}
|
|
ReadImageData( &address, hFile, &DebugDir, sizeof(DebugDir) );
|
|
|
|
if (DebugDir.Type == IMAGE_DEBUG_TYPE_MISC) {
|
|
|
|
l = DebugDir.SizeOfData;
|
|
pMisc = pT = malloc(l);
|
|
|
|
if (!hFile && ((ULONG)DebugDir.AddressOfRawData < pSH[i].VirtualAddress ||
|
|
(ULONG)DebugDir.AddressOfRawData >=
|
|
pSH[i].VirtualAddress + pSH[i].SizeOfRawData)) {
|
|
//
|
|
// the misc debug data MUST be in the .rdata section
|
|
// otherwise the debugger cannot access it as it is not mapped in
|
|
//
|
|
break;
|
|
}
|
|
|
|
if (hFile) {
|
|
address = (ULONG)DebugDir.PointerToRawData;
|
|
} else {
|
|
address = (ULONG)DebugDir.AddressOfRawData + (ULONG)BaseOfDll;
|
|
}
|
|
|
|
ReadImageData( &address, hFile, pMisc, l );
|
|
|
|
while (l > 0) {
|
|
if (pMisc->DataType != IMAGE_DEBUG_MISC_EXENAME) {
|
|
l -= pMisc->Length;
|
|
pMisc = (PIMAGE_DEBUG_MISC)
|
|
(((LPSTR)pMisc) + pMisc->Length);
|
|
} else {
|
|
|
|
pExeName = (PVOID)&pMisc->Data[ 0 ];
|
|
|
|
if (!pMisc->Unicode) {
|
|
strcpy(lpName, (LPSTR)pExeName);
|
|
rVal = TRUE;
|
|
} else {
|
|
WideCharToMultiByte(CP_ACP,
|
|
0,
|
|
(LPWSTR)pExeName,
|
|
-1,
|
|
lpName,
|
|
MAX_PATH,
|
|
NULL,
|
|
NULL);
|
|
rVal = TRUE;
|
|
}
|
|
|
|
//
|
|
// Undo stevewo's error
|
|
//
|
|
|
|
if (_stricmp(&lpName[strlen(lpName)-4], ".DBG") == 0) {
|
|
char rgchPath[_MAX_PATH];
|
|
char rgchBase[_MAX_FNAME];
|
|
|
|
_splitpath(lpName, NULL, rgchPath, rgchBase, NULL);
|
|
if (strlen(rgchPath)==4) {
|
|
rgchPath[strlen(rgchPath)-1] = 0;
|
|
strcpy(lpName, rgchBase);
|
|
strcat(lpName, ".");
|
|
strcat(lpName, rgchPath);
|
|
} else {
|
|
strcpy(lpName, rgchBase);
|
|
strcat(lpName, ".exe");
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
free(pT);
|
|
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
return rVal;
|
|
}
|
|
|
|
BOOL
|
|
GetModnameFromImage(
|
|
DWORD BaseOfDll,
|
|
HANDLE hFile,
|
|
LPSTR lpName
|
|
)
|
|
{
|
|
#ifdef KERNEL
|
|
return GetModnameFromImageInternal( BaseOfDll, NULL, lpName );
|
|
#else
|
|
if (!GetModnameFromImageInternal( BaseOfDll, NULL, lpName )) {
|
|
return GetModnameFromImageInternal( BaseOfDll, hFile, lpName );
|
|
}
|
|
|
|
return TRUE;
|
|
#endif
|
|
}
|
|
|
|
|
|
BOOL
|
|
GetHeaderInfo(
|
|
IN DWORD BaseOfDll,
|
|
OUT LPDWORD CheckSum,
|
|
OUT LPDWORD DateTimeStamp,
|
|
OUT LPDWORD SizeOfImage
|
|
)
|
|
{
|
|
IMAGE_NT_HEADERS nh;
|
|
IMAGE_DOS_HEADER dh;
|
|
DWORD address;
|
|
DWORD sig;
|
|
|
|
|
|
address = BaseOfDll;
|
|
|
|
ReadImageData( &address, NULL, &dh, sizeof(dh) );
|
|
|
|
if (dh.e_magic == IMAGE_DOS_SIGNATURE) {
|
|
address = (ULONG)BaseOfDll + dh.e_lfanew;
|
|
} else {
|
|
address = (ULONG)BaseOfDll;
|
|
}
|
|
|
|
ReadImageData( &address, NULL, &sig, sizeof(sig) );
|
|
address -= sizeof(sig);
|
|
|
|
if (sig != IMAGE_NT_SIGNATURE) {
|
|
ReadImageData( &address, NULL, &nh.FileHeader, sizeof(IMAGE_FILE_HEADER) );
|
|
} else {
|
|
ReadImageData( &address, NULL, &nh, sizeof(IMAGE_NT_HEADERS) );
|
|
}
|
|
|
|
*CheckSum = nh.OptionalHeader.CheckSum;
|
|
*DateTimeStamp = nh.FileHeader.TimeDateStamp;
|
|
*SizeOfImage = nh.OptionalHeader.SizeOfImage;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
#ifdef _PPC_
|
|
BOOL
|
|
CreateDotDotName(
|
|
LPSTR SuffixedString,
|
|
LPSTR pString,
|
|
CHAR SuffixChar
|
|
)
|
|
{
|
|
LPSTR p;
|
|
|
|
//
|
|
// Allow symbol searching procedure names without the '..' prefix
|
|
// for unassemble and breakpoint commands
|
|
//
|
|
if (!ppcPrefix) {
|
|
return FALSE;
|
|
}
|
|
|
|
p = strchr( pString, '!' );
|
|
if (p) {
|
|
*p = 0;
|
|
strcpy( SuffixedString, pString );
|
|
strcat( SuffixedString, "!.." );
|
|
strcat( SuffixedString, p+1 );
|
|
*p = '!';
|
|
} else {
|
|
SuffixedString[0] = '.';
|
|
SuffixedString[1] = '.';
|
|
SuffixedString[2] = '\0';
|
|
strcat( SuffixedString, pString );
|
|
}
|
|
|
|
if (SuffixChar) {
|
|
int i = strlen(SuffixedString);
|
|
SuffixedString[i] = SuffixChar;
|
|
SuffixedString[i+1] = 0;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/*** GetOffsetFromSym - return offset from symbol specified
|
|
*
|
|
* Purpose:
|
|
* external routine.
|
|
* With the specified symbol, set the pointer to
|
|
* its offset. The variable chSymbolSuffix may
|
|
* be used to append a character to repeat the search
|
|
* if it first fails.
|
|
*
|
|
* Input:
|
|
* pString - pointer to input symbol
|
|
*
|
|
* Output:
|
|
* pOffset - pointer to offset to be set
|
|
*
|
|
* Returns:
|
|
* BOOLEAN value of success
|
|
*
|
|
*************************************************************************/
|
|
|
|
BOOLEAN
|
|
GetOffsetFromSym(
|
|
PUCHAR pString,
|
|
PULONG pOffset,
|
|
CHAR iModule
|
|
)
|
|
{
|
|
UCHAR SuffixedString[SYMBOLSIZE + 64];
|
|
UCHAR Suffix[4];
|
|
|
|
//
|
|
// Nobody should be referencing a 1 character symbol! It causes the
|
|
// rest of us to pay a huge penalty whenever we make a typo. Please
|
|
// change to 2 character instead of removing this hack!
|
|
//
|
|
|
|
if ( strlen(pString) == 1 || strlen(pString) == 0 ) {
|
|
return FALSE;
|
|
}
|
|
#ifdef _PPC_
|
|
if (CreateDotDotName( SuffixedString, pString, 0 )) {
|
|
if (SymGetSymFromName( pProcessCurrent->hProcess, SuffixedString, sym )) {
|
|
*pOffset = sym->Address;
|
|
return TRUE;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (SymGetSymFromName( pProcessCurrent->hProcess, pString, sym )) {
|
|
*pOffset = sym->Address;
|
|
return TRUE;
|
|
}
|
|
|
|
if (chSymbolSuffix != 'n') {
|
|
#ifdef _PPC_
|
|
if (CreateDotDotName( SuffixedString, pString, chSymbolSuffix )) {
|
|
if (SymGetSymFromName( pProcessCurrent->hProcess, SuffixedString, sym )) {
|
|
*pOffset = sym->Address;
|
|
return TRUE;
|
|
}
|
|
}
|
|
#else
|
|
strcpy( SuffixedString, pString );
|
|
Suffix[0] = chSymbolSuffix;
|
|
Suffix[1] = '\0';
|
|
strcat( SuffixedString, Suffix );
|
|
if (SymGetSymFromName( pProcessCurrent->hProcess, SuffixedString, sym )) {
|
|
*pOffset = sym->Address;
|
|
return TRUE;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
void
|
|
CreateModuleNameFromPath(
|
|
LPSTR szImagePath,
|
|
LPSTR szModuleName
|
|
)
|
|
{
|
|
PUCHAR pchName;
|
|
|
|
pchName = szImagePath;
|
|
pchName += strlen( pchName );
|
|
while (pchName > szImagePath) {
|
|
if (*--pchName == '\\' || *pchName == '/') {
|
|
pchName++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
strcpy( szModuleName, pchName );
|
|
pchName = strchr( szModuleName, '.' );
|
|
if (pchName != NULL) {
|
|
*pchName = '\0';
|
|
}
|
|
}
|
|
|
|
void
|
|
GetAdjacentSymOffsets(
|
|
ULONG addrStart,
|
|
PULONG prevOffset,
|
|
PULONG nextOffset
|
|
)
|
|
{
|
|
DWORD Displacement;
|
|
|
|
//
|
|
// assume failure
|
|
//
|
|
*prevOffset = 0;
|
|
*nextOffset = (ULONG) -1;
|
|
|
|
//
|
|
// get the symbol for the initial address
|
|
//
|
|
if (!SymGetSymFromAddr( pProcessCurrent->hProcess, addrStart, &Displacement, symStart )) {
|
|
return;
|
|
}
|
|
|
|
*prevOffset = symStart->Address;
|
|
|
|
if (SymGetSymNext( pProcessCurrent->hProcess, symStart )) {
|
|
*nextOffset = symStart->Address;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
BOOL
|
|
SymbolCallbackFunction(
|
|
HANDLE hProcess,
|
|
ULONG ActionCode,
|
|
PVOID CallbackData,
|
|
PVOID UserContext
|
|
)
|
|
{
|
|
PIMAGEHLP_DEFERRED_SYMBOL_LOAD idsl;
|
|
PIMAGE_INFO pImage;
|
|
IMAGEHLP_MODULE mi;
|
|
|
|
|
|
switch( ActionCode ) {
|
|
case CBA_DEFERRED_SYMBOL_LOAD_START:
|
|
if (!fVerboseOutput) {
|
|
return TRUE;
|
|
}
|
|
idsl = (PIMAGEHLP_DEFERRED_SYMBOL_LOAD) CallbackData;
|
|
pImage = pProcessCurrent->pImageHead;
|
|
while (pImage) {
|
|
if (idsl->BaseOfImage == (ULONG)pImage->lpBaseOfImage) {
|
|
_strlwr( idsl->FileName );
|
|
dprintf( "Loading symbols for 0x%08x %16s -> ",
|
|
idsl->BaseOfImage,
|
|
idsl->FileName
|
|
);
|
|
return TRUE;
|
|
}
|
|
pImage = pImage->pImageNext;
|
|
}
|
|
break;
|
|
|
|
case CBA_DEFERRED_SYMBOL_LOAD_FAILURE:
|
|
idsl = (PIMAGEHLP_DEFERRED_SYMBOL_LOAD) CallbackData;
|
|
if (fVerboseOutput) {
|
|
dprintf( "*** Error: could not load symbols\n" );
|
|
}
|
|
break;
|
|
|
|
case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE:
|
|
idsl = (PIMAGEHLP_DEFERRED_SYMBOL_LOAD) CallbackData;
|
|
pImage = pProcessCurrent->pImageHead;
|
|
while (pImage) {
|
|
if ((idsl->BaseOfImage == (ULONG)pImage->lpBaseOfImage) || ((ULONG)pImage->lpBaseOfImage == 0)) {
|
|
pImage->szDebugPath[0] = 0;
|
|
strncpy( pImage->szDebugPath, idsl->FileName, sizeof(pImage->szDebugPath) );
|
|
_strlwr( pImage->szDebugPath );
|
|
if (fVerboseOutput) {
|
|
dprintf( "%s\n", pImage->szDebugPath );
|
|
}
|
|
if (idsl->CheckSum != pImage->dwCheckSum) {
|
|
dprintf( "*** WARNING: symbols checksum is wrong 0x%08x 0x%08x for %s\n",
|
|
pImage->dwCheckSum,
|
|
idsl->CheckSum,
|
|
pImage->szDebugPath
|
|
);
|
|
pImage->GoodCheckSum = FALSE;
|
|
} else {
|
|
pImage->GoodCheckSum = TRUE;
|
|
}
|
|
if (SymGetModuleInfo( pProcessCurrent->hProcess, idsl->BaseOfImage, &mi )) {
|
|
if (mi.SymType == SymNone) {
|
|
dprintf( "*** ERROR: Module load completed but symbols could not be loaded for %s\n",
|
|
pImage->szDebugPath
|
|
);
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
pImage = pImage->pImageNext;
|
|
}
|
|
if (fVerboseOutput) {
|
|
dprintf( "\n" );
|
|
}
|
|
break;
|
|
|
|
case CBA_SYMBOLS_UNLOADED:
|
|
idsl = (PIMAGEHLP_DEFERRED_SYMBOL_LOAD) CallbackData;
|
|
if (fVerboseOutput) {
|
|
dprintf( "Symbols unloaded for 0x%08x %s\n",
|
|
idsl->BaseOfImage,
|
|
idsl->FileName
|
|
);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
void
|
|
SetSymbolSearchPath(
|
|
BOOL IsKd
|
|
)
|
|
{
|
|
LPSTR lpSymPathEnv;
|
|
LPSTR lpAltSymPathEnv;
|
|
LPSTR lpSystemRootEnv;
|
|
LPSTR lpSymPath;
|
|
ULONG cbSymPath;
|
|
ULONG dw;
|
|
|
|
cbSymPath = 18;
|
|
if (lpSymPathEnv = getenv(SYMBOL_PATH)) {
|
|
cbSymPath += strlen(lpSymPathEnv) + 1;
|
|
}
|
|
if (lpAltSymPathEnv = getenv(ALTERNATE_SYMBOL_PATH)) {
|
|
cbSymPath += strlen(lpAltSymPathEnv) + 1;
|
|
}
|
|
if (!IsKd) {
|
|
if (lpSystemRootEnv = getenv("SystemRoot")) {
|
|
cbSymPath += strlen(lpSystemRootEnv) + 1;
|
|
}
|
|
}
|
|
|
|
SymbolSearchPath = calloc(cbSymPath, 1);
|
|
|
|
if (lpAltSymPathEnv) {
|
|
lpAltSymPathEnv = _strdup(lpAltSymPathEnv);
|
|
lpSymPath = strtok(lpAltSymPathEnv, ";");
|
|
while (lpSymPath) {
|
|
dw = GetFileAttributes(lpSymPath);
|
|
if ( (dw != 0xffffffff) && (dw & FILE_ATTRIBUTE_DIRECTORY) ) {
|
|
if (*SymbolSearchPath) {
|
|
strcat(SymbolSearchPath, ";");
|
|
}
|
|
strcat(SymbolSearchPath, lpSymPath);
|
|
}
|
|
lpSymPath = strtok(NULL, ";");
|
|
}
|
|
free(lpAltSymPathEnv);
|
|
}
|
|
|
|
if (lpSymPathEnv) {
|
|
lpSymPathEnv = _strdup(lpSymPathEnv);
|
|
lpSymPath = strtok(lpSymPathEnv, ";");
|
|
while (lpSymPath) {
|
|
dw = GetFileAttributes(lpSymPath);
|
|
if ( (dw != 0xffffffff) && (dw & FILE_ATTRIBUTE_DIRECTORY) ) {
|
|
if (*SymbolSearchPath) {
|
|
strcat(SymbolSearchPath, ";");
|
|
}
|
|
strcat(SymbolSearchPath, lpSymPath);
|
|
}
|
|
lpSymPath = strtok(NULL, ";");
|
|
}
|
|
free(lpSymPathEnv);
|
|
}
|
|
|
|
if (!IsKd) {
|
|
if (lpSystemRootEnv) {
|
|
dw = GetFileAttributes(lpSystemRootEnv);
|
|
if ( (dw != 0xffffffff) && (dw & FILE_ATTRIBUTE_DIRECTORY) ) {
|
|
if (*SymbolSearchPath) {
|
|
strcat(SymbolSearchPath, ";");
|
|
}
|
|
strcat(SymbolSearchPath,lpSystemRootEnv);
|
|
}
|
|
}
|
|
}
|
|
|
|
SymSetSearchPath( pProcessCurrent->hProcess, SymbolSearchPath );
|
|
|
|
dprintf("Symbol search path is: %s\n",
|
|
*SymbolSearchPath ?
|
|
SymbolSearchPath :
|
|
"*** Invalid *** : Verify _NT_SYMBOL_PATH setting" );
|
|
}
|