windows-nt/Source/XPSP1/NT/base/mvdm/vdmexts/util.c

886 lines
21 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
heap.c
Abstract:
This function contains the default ntsd debugger extensions
Author:
Bob Day (bobday) 29-Feb-1992 Grabbed standard header
Revision History:
Neil Sandlin (NeilSa) 15-Jan-1996 Merged with vdmexts
Added command line parsing
--*/
#include <precomp.h>
#pragma hdrstop
VDMCONTEXT ThreadContext;
PVOID LdtAddress = NULL;
BOOL
WINAPI
ReadProcessMem(
LPVOID lpBaseAddress,
LPVOID lpBuffer,
DWORD nSize
)
{
return ReadProcessMemory( hCurrentProcess, lpBaseAddress, lpBuffer, nSize, NULL );
}
BOOL
WINAPI
WriteProcessMem(
LPVOID lpBaseAddress,
LPVOID lpBuffer,
DWORD nSize
)
{
return WriteProcessMemory( hCurrentProcess, lpBaseAddress, lpBuffer, nSize, NULL );
}
#ifndef i386
//
// The following two routines implement the very funky way that we
// have to get register values on the 486 emulator.
//
ULONG
GetRegValue(
NT_CPU_REG reg,
BOOL bInNano,
ULONG UMask
)
{
if (bInNano) {
return(ReadDwordSafe(reg.nano_reg));
} else if (UMask & reg.universe_8bit_mask) {
return (ReadDwordSafe(reg.saved_reg) & 0xFFFFFF00 |
ReadDwordSafe(reg.reg) & 0xFF);
} else if (UMask & reg.universe_16bit_mask) {
return (ReadDwordSafe(reg.saved_reg) & 0xFFFF0000 |
ReadDwordSafe(reg.reg) & 0xFFFF);
} else {
return (ReadDwordSafe(reg.reg));
}
}
ULONG
GetEspValue(
NT_CPU_INFO nt_cpu_info,
BOOL bInNano
)
{
if (bInNano) {
return (ReadDwordSafe(nt_cpu_info.nano_esp));
} else {
if (ReadDwordSafe(nt_cpu_info.stack_is_big)) {
return (ReadDwordSafe(nt_cpu_info.host_sp) -
ReadDwordSafe(nt_cpu_info.ss_base));
} else {
return (ReadDwordSafe(nt_cpu_info.esp_sanctuary) & 0xFFFF0000 |
(ReadDwordSafe(nt_cpu_info.host_sp) -
ReadDwordSafe(nt_cpu_info.ss_base) & 0xFFFF));
}
}
}
#endif
int
GetContext(
VDMCONTEXT* lpContext
)
/*
GetContext
This function fills in the specified context record with
the content of the 16-bit registers. The return value is
the mode (v86 or PROT) of the client.
Note that on x86, if the machine is currently in the monitor,
we have to pick up the values from the VdmTib and IntelMSW.
*/
{
#ifndef i386 //
int mode;
ULONG pTmp;
NT_CPU_INFO nt_cpu_info;
BOOL b;
BOOL bInNano;
ULONG UMask;
#if 0
DWORD MyEflags;
#endif
pTmp = (ULONG)EXPRESSION("ntvdm!nt_cpu_info");
if ( pTmp ) {
b = READMEM((LPVOID) pTmp, &nt_cpu_info, sizeof(NT_CPU_INFO));
if ( !b ) {
PRINTF("Could not read IntelRegisters context out of process\n");
return( -1 );
}
bInNano = ReadDwordSafe((ULONG) nt_cpu_info.in_nano_cpu);
UMask = ReadDwordSafe((ULONG) nt_cpu_info.universe);
lpContext->Eax = GetRegValue(nt_cpu_info.eax, bInNano, UMask);
lpContext->Ecx = GetRegValue(nt_cpu_info.ecx, bInNano, UMask);
lpContext->Edx = GetRegValue(nt_cpu_info.edx, bInNano, UMask);
lpContext->Ebx = GetRegValue(nt_cpu_info.ebx, bInNano, UMask);
lpContext->Ebp = GetRegValue(nt_cpu_info.ebp, bInNano, UMask);
lpContext->Esi = GetRegValue(nt_cpu_info.esi, bInNano, UMask);
lpContext->Edi = GetRegValue(nt_cpu_info.edi, bInNano, UMask);
lpContext->Esp = GetEspValue(nt_cpu_info, bInNano);
//
// nt_cpu_info.flags isn't very much use, because several of the
// flags values are not kept in memory, but computed each time.
// The emulator doesn't supply us with the right value, so we
// try to get it from the code in VdmDebugger
//
lpContext->EFlags = ReadDwordSafe(nt_cpu_info.flags);
#if 0
lpContext->EFlags = 0xffffffff; // indicate value unknown
if (InVdmPrompt() &&
(pTmp = (ULONG)EXPRESSION("ntvdmd!VdmDbgEFLAGS")) &&
(READMEM((LPVOID) pTmp, &MyEflags, sizeof(DWORD)))) {
lpContext->EFlags = MyEflags;
}
#endif
lpContext->Eip = ReadDwordSafe(nt_cpu_info.eip);
lpContext->SegEs = ReadWordSafe(nt_cpu_info.es);
lpContext->SegCs = ReadWordSafe(nt_cpu_info.cs);
lpContext->SegSs = ReadWordSafe(nt_cpu_info.ss);
lpContext->SegDs = ReadWordSafe(nt_cpu_info.ds);
lpContext->SegFs = ReadWordSafe(nt_cpu_info.fs);
lpContext->SegGs = ReadWordSafe(nt_cpu_info.gs);
} else {
PRINTF("Could not find the symbol 'ntvdm!nt_cpu_info'\n");
return( -1 );
}
if ( !(ReadDwordSafe(nt_cpu_info.cr0) & 1) ) {
mode = V86_MODE;
} else {
mode = PROT_MODE;
}
return( mode );
#else //
NTSTATUS rc;
BOOL b;
int mode;
ULONG lpVdmTib;
ULONG IntelMSW;
lpContext->ContextFlags = CONTEXT_FULL;
rc = NtGetContextThread( hCurrentThread,
lpContext );
if ( NT_ERROR(rc) ) {
PRINTF( "bde.k: Could not get current threads context - status = %08lX\n", rc );
return( -1 );
}
/*
** Get the 16-bit registers from the context
*/
if ( lpContext->EFlags & V86_BITS ) {
/*
** V86 Mode
*/
mode = V86_MODE;
} else {
if ( ((WORD)(lpContext->SegCs & RPL_MASK)) != KGDT_R3_CODE ) {
mode = PROT_MODE;
} else {
/*
** We are in flat 32-bit address space!
*/
lpVdmTib = GetCurrentVdmTib();
if ( !lpVdmTib ) {
PRINTF("Could not find the symbol 'VdmTib'\n");
return( -1 );
}
b = READMEM((LPVOID)(lpVdmTib+FIELD_OFFSET(VDM_TIB,VdmContext)),
lpContext, sizeof(VDMCONTEXT));
if ( !b ) {
PRINTF("Could not read IntelRegisters context out of process\n");
return( -1 );
}
b = READMEM((LPVOID)(lpVdmTib+FIELD_OFFSET(VDM_TIB,IntelMSW)),
&IntelMSW, sizeof(IntelMSW));
if ( !b ) {
PRINTF("Could not read IntelMSW out of process\n");
return( -1 );
}
if ( IntelMSW & MSW_PE ) {
mode = PROT_MODE;
} else {
mode = V86_MODE;
}
}
}
return( mode );
#endif
}
ULONG
GetIntelBase(
VOID
)
{
#ifndef i386
ULONG IntelBase;
BOOL b;
IntelBase = (ULONG)EXPRESSION("ntvdm!Start_of_M_area");
if ( IntelBase ) {
b = READMEM((LPVOID) IntelBase, &IntelBase, sizeof(ULONG));
if ( !b ) {
PRINTF("Could not read symbol 'ntvdm!Start_of_M_area\n");
return(0);
}
} else {
PRINTF("Could not find the symbol 'ntvdm!Start_of_M_area'\n");
}
return(IntelBase);
#else
return(0);
#endif
}
DWORD read_dword(
ULONG lpAddress,
BOOL bSafe
) {
BOOL b;
DWORD dword;
b = READMEM((LPVOID)lpAddress, &dword, sizeof(dword));
if ( !b ) {
if ( !bSafe ) {
PRINTF("Failure reading dword at memory location %08lX\n", lpAddress );
}
return( 0 );
}
return( dword );
}
WORD read_word(
ULONG lpAddress,
BOOL bSafe
) {
BOOL b;
WORD word;
b = READMEM((LPVOID)lpAddress, &word, sizeof(word));
if ( !b ) {
if ( !bSafe ) {
PRINTF("Failure reading word at memory location %08lX\n", lpAddress );
}
return( 0 );
}
return( word );
}
BYTE read_byte(
ULONG lpAddress,
BOOL bSafe
) {
BOOL b;
BYTE byte;
b = READMEM((LPVOID)lpAddress, &byte, sizeof(byte));
if ( !b ) {
if ( !bSafe ) {
PRINTF("Failure reading byte at memory location %08lX\n", lpAddress );
}
return( 0 );
}
return( byte );
}
BOOL read_gnode32(
ULONG lpAddress,
PGNODE32 p,
BOOL bSafe
) {
BOOL b;
b = READMEM((LPVOID)lpAddress, p, sizeof(*p));
if ( !b ) {
if ( !bSafe ) {
PRINTF("Failure reading word at memory location %08lX\n", lpAddress );
}
return( 0 );
}
return( TRUE );
}
BOOL GetDescriptorData(
WORD selector,
LPVDMLDT_ENTRY pdte
)
{
//
// Using GetThreadSelectorEntry would be nice if it just wasn't so slow.
// So, we use our LDT, just like on risc, which should be good enough.
//#ifdef i386
#if 0
LDT_ENTRY dte;
if (!GetThreadSelectorEntry( hCurrentThread,
selector,
&dte)) {
return( FALSE );
}
pdte->HighWord = dte.HighWord;
pdte->BaseLow = dte.BaseLow;
pdte->LimitLow = dte.LimitLow;
return (TRUE);
#endif
NTSTATUS Status;
selector &= ~(SELECTOR_LDT | SELECTOR_RPL);
//
// Get address of Ldt
//
if (!LdtAddress) {
//
// GetExpression is VERY SLOW under ntsd now. Who knows what the
// debugger guys are up to. So just try to cache the address value
// since it only changes twice (both during boot).
//
LdtAddress = (PVOID)EXPRESSION("ntvdm!Ldt");
Status = READMEM(LdtAddress, &LdtAddress, sizeof(ULONG));
if (!Status) {
LdtAddress = NULL;
return FALSE;
}
}
Status = READMEM((PVOID)((ULONG)LdtAddress + selector),
pdte, sizeof(VDMLDT_ENTRY));
// Now do a special hack for the period of time during dpmi
// init where the LDT moves. This would all be unecessary if
// we just were to get the ldt base from VDMDBG, which knows
// everything.
if (((ULONG)LdtAddress)-GetIntelBase() < 0x100000) {
LdtAddress = NULL; // forget the value again
}
return Status;
}
BOOL
ReadMemExpression(
LPSTR expr,
LPVOID buffer,
ULONG len
)
{
PVOID pMem;
pMem = (PVOID)(*GetExpression)(expr);
if (!pMem) {
PRINTF("Can't find symbol %s\n", expr);
return FALSE;
}
if (!READMEM(pMem, buffer, len)) {
PRINTF("Error reading memory\n");
return FALSE;
}
return TRUE;
}
ULONG GetInfoFromSelector(
WORD selector,
int mode,
SELECTORINFO *si
) {
ULONG base;
ULONG type;
VDMLDT_ENTRY dte;
switch( mode ) {
case V86_MODE:
base = (ULONG)selector << 4;
if ( si ) {
si->Limit = 0xFFFFL;
si->Base = (ULONG)selector << 4;
si->bCode = FALSE;
si->bBig = FALSE;
si->bExpandDown = FALSE;
si->bWrite = TRUE;
si->bPresent = TRUE;
}
break;
case PROT_MODE:
if ( !GetDescriptorData(selector, &dte) ) {
return( (ULONG)-1 );
}
base = ((ULONG)dte.HighWord.Bytes.BaseHi << 24)
+ ((ULONG)dte.HighWord.Bytes.BaseMid << 16)
+ ((ULONG)dte.BaseLow);
if ( si ) {
si->Limit = (ULONG)dte.LimitLow
+ ((ULONG)dte.HighWord.Bits.LimitHi << 16);
if ( dte.HighWord.Bits.Granularity ) {
si->Limit <<= 12;
si->Limit += 0xFFF;
}
si->Base = base;
type = dte.HighWord.Bits.Type;
si->bSystem = !(BOOL) (type & 0x10);
if (!si->bSystem) {
si->bCode = (BOOL) (type & 8);
}
si->bAccessed = (BOOL) (type & 1);
si->bWrite = (BOOL) (type & 2);
if (si->bCode) {
si->bWrite = !si->bWrite;
}
si->bExpandDown = FALSE;
if (!si->bSystem && !si->bCode) {
si->bExpandDown = (BOOL) (type & 4);
}
si->bPresent = (BOOL) dte.HighWord.Bits.Pres;
si->bBig = (BOOL) dte.HighWord.Bits.Default_Big;
}
break;
case FLAT_MODE:
PRINTF("Unsupported determination of base address in flat mode\n");
base = 0;
break;
}
return( base );
}
BOOL
InVdmPrompt(
VOID
)
{
ULONG pTmp;
BOOL InVdmDebugger;
BOOL bReturn = FALSE;
if ((pTmp = (ULONG)EXPRESSION("ntvdmd!InVdmDebugger")) &&
(READMEM((LPVOID) pTmp, &InVdmDebugger, sizeof(BOOL)))) {
bReturn = InVdmDebugger;
}
return bReturn;
}
//****************************************************************************
//
// Command line parsing routines
//
//****************************************************************************
BOOL
SkipToNextWhiteSpace(
VOID
)
{
char ch;
while ( (ch = *lpArgumentString) != '\0' ) {
if ( ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' ) {
return TRUE;
}
lpArgumentString++;
}
return FALSE;
}
BOOL
GetNextToken(
VOID
)
{
char ch;
while ( (ch = *lpArgumentString) != '\0' ) {
if ( ch != ' ' && ch != '\t' && ch != '\r' && ch != '\n' ) {
return TRUE;
}
lpArgumentString++;
}
return FALSE;
}
ULONG
EvaluateToken(
VOID
)
{
char ch;
LPSTR pTemp;
ULONG value = 0;
if (GetNextToken()) {
pTemp = lpArgumentString;
SkipToNextWhiteSpace();
ch = *lpArgumentString;
*lpArgumentString = 0;
value = (ULONG) EXPRESSION( pTemp );
*lpArgumentString = ch;
}
return (value);
}
BOOL
IsTokenHex(
VOID
)
{
UCHAR ch;
LPSTR pTemp;
BOOL result = TRUE;
if (GetNextToken()) {
pTemp = lpArgumentString;
SkipToNextWhiteSpace();
lpArgumentString--;
while(lpArgumentString >= pTemp) {
ch = *lpArgumentString--;
if (ch < '0') {
result = FALSE;
break;
}
if ((ch > '9') && (ch < 'A')) {
result = FALSE;
break;
}
if ((ch > 'F') && (ch < 'a')) {
result = FALSE;
break;
}
if (ch > 'f') {
result = FALSE;
break;
}
}
lpArgumentString = pTemp;
}
return (result);
}
BOOL
RegisterToAsciiValue(
LPSTR *pszValue,
LPSTR *pszReg
)
{
LPSTR szReg = *pszReg;
LPSTR szValue = *pszValue;
if (!_strnicmp(szReg, "ax", 2) && !isalpha(szReg[2])) {
_ultoa((ULONG)LOWORD(ThreadContext.Eax), szValue, 16);
*pszReg += 2;
} else if (!_strnicmp(szReg, "bx", 2) && !isalpha(szReg[2])) {
_ultoa((ULONG)LOWORD(ThreadContext.Ebx), szValue, 16);
*pszReg += 2;
} else if (!_strnicmp(szReg, "cx", 2) && !isalpha(szReg[2])) {
_ultoa((ULONG)LOWORD(ThreadContext.Ecx), szValue, 16);
*pszReg += 2;
} else if (!_strnicmp(szReg, "dx", 2) && !isalpha(szReg[2])) {
_ultoa((ULONG)LOWORD(ThreadContext.Edx), szValue, 16);
*pszReg += 2;
} else if (!_strnicmp(szReg, "si", 2) && !isalpha(szReg[2])) {
_ultoa((ULONG)LOWORD(ThreadContext.Esi), szValue, 16);
*pszReg += 2;
} else if (!_strnicmp(szReg, "di", 2) && !isalpha(szReg[2])) {
_ultoa((ULONG)LOWORD(ThreadContext.Edi), szValue, 16);
*pszReg += 2;
} else if (!_strnicmp(szReg, "sp", 2) && !isalpha(szReg[2])) {
_ultoa((ULONG)LOWORD(ThreadContext.Esp), szValue, 16);
*pszReg += 2;
} else if (!_strnicmp(szReg, "bp", 2) && !isalpha(szReg[2])) {
_ultoa((ULONG)LOWORD(ThreadContext.Ebp), szValue, 16);
*pszReg += 2;
} else if (!_strnicmp(szReg, "ip", 2) && !isalpha(szReg[2])) {
_ultoa((ULONG)LOWORD(ThreadContext.Eip), szValue, 16);
*pszReg += 2;
} else if (!_strnicmp(szReg, "eax", 3) && !isalpha(szReg[3])) {
_ultoa(ThreadContext.Eax, szValue, 16);
*pszReg += 3;
} else if (!_strnicmp(szReg, "ebx", 3) && !isalpha(szReg[3])) {
_ultoa(ThreadContext.Ebx, szValue, 16);
*pszReg += 3;
} else if (!_strnicmp(szReg, "ecx", 3) && !isalpha(szReg[3])) {
_ultoa(ThreadContext.Ecx, szValue, 16);
*pszReg += 3;
} else if (!_strnicmp(szReg, "edx", 3) && !isalpha(szReg[3])) {
_ultoa(ThreadContext.Edx, szValue, 16);
*pszReg += 3;
} else if (!_strnicmp(szReg, "esi", 3) && !isalpha(szReg[3])) {
_ultoa(ThreadContext.Esi, szValue, 16);
*pszReg += 3;
} else if (!_strnicmp(szReg, "edi", 3) && !isalpha(szReg[3])) {
_ultoa(ThreadContext.Edi, szValue, 16);
*pszReg += 3;
} else if (!_strnicmp(szReg, "esp", 3) && !isalpha(szReg[3])) {
_ultoa(ThreadContext.Esp, szValue, 16);
*pszReg += 3;
} else if (!_strnicmp(szReg, "ebp", 3) && !isalpha(szReg[3])) {
_ultoa(ThreadContext.Ebp, szValue, 16);
*pszReg += 3;
} else if (!_strnicmp(szReg, "eip", 3) && !isalpha(szReg[3])) {
_ultoa(ThreadContext.Eip, szValue, 16);
*pszReg += 3;
} else if (!_strnicmp(szReg, "cs", 2) && !isalpha(szReg[2])) {
_ultoa((ULONG)ThreadContext.SegCs, szValue, 16);
*pszReg += 2;
} else if (!_strnicmp(szReg, "ds", 2) && !isalpha(szReg[2])) {
_ultoa((ULONG)ThreadContext.SegDs, szValue, 16);
*pszReg += 2;
} else if (!_strnicmp(szReg, "es", 2) && !isalpha(szReg[2])) {
_ultoa((ULONG)ThreadContext.SegEs, szValue, 16);
*pszReg += 2;
} else if (!_strnicmp(szReg, "fs", 2) && !isalpha(szReg[2])) {
_ultoa((ULONG)ThreadContext.SegFs, szValue, 16);
*pszReg += 2;
} else if (!_strnicmp(szReg, "gs", 2) && !isalpha(szReg[2])) {
_ultoa((ULONG)ThreadContext.SegGs, szValue, 16);
*pszReg += 2;
} else if (!_strnicmp(szReg, "ss", 2) && !isalpha(szReg[2])) {
_ultoa((ULONG)ThreadContext.SegSs, szValue, 16);
*pszReg += 2;
} else {
return FALSE;
}
// PRINTF("value = %s\n", szValue);
while (*szValue) {
szValue++;
}
*pszValue = szValue;
return TRUE;
}
VOID
ParseForIntelRegisters(
LPSTR szTarg,
LPSTR szSrc
)
{
while (*szSrc) {
if (!isalpha(*szSrc)) {
if (!isdigit(*szSrc)) {
*szTarg++ = *szSrc++;
continue;
}
while (isalpha(*szSrc) || isdigit(*szSrc)) {
*szTarg++ = *szSrc++;
}
continue;
}
if (!RegisterToAsciiValue(&szTarg, &szSrc)) {
while (isalpha(*szSrc) || isdigit(*szSrc)) {
*szTarg++ = *szSrc++;
}
}
}
*szTarg = 0;
}
BOOL
ParseIntelAddress(
int *pMode,
WORD *pSelector,
PULONG pOffset
)
{
char sel_text[128], off_text[128];
char expr_text[256];
char *colon;
char *mode_prefix;
WORD segment;
char filename[9];
colon = strchr( lpArgumentString, ':' );
if ( colon == NULL ) {
LPSTR pSymbol = lpArgumentString;
BOOL bResult;
char chTemp;
SkipToNextWhiteSpace();
chTemp = *lpArgumentString;
*lpArgumentString = 0;
bResult = FindAddress( pSymbol,
filename,
&segment,
pSelector,
pOffset,
pMode,
FALSE);
*lpArgumentString = chTemp;
if (bResult) {
if (*pMode == NOT_LOADED) {
PRINTF("Could not determine base of '%s'\n", pSymbol);
return FALSE;
} else {
return TRUE;
}
} else {
PRINTF("Could not find symbol: %s\n", pSymbol);
return FALSE;
}
}
*pMode = GetContext( &ThreadContext );
mode_prefix = strchr( lpArgumentString, '&' );
if ( mode_prefix == NULL ) {
mode_prefix = strchr( lpArgumentString, '#' );
if ( mode_prefix != NULL ) {
if ( mode_prefix != lpArgumentString ) {
PRINTF("Address must have '&' symbol as the first character\n");
return FALSE;
}
*pMode = PROT_MODE;
lpArgumentString = mode_prefix+1;
}
} else {
if ( mode_prefix != lpArgumentString ) {
PRINTF("Address must have '#' symbol as the first character\n");
return FALSE;
}
*pMode = V86_MODE;
lpArgumentString = mode_prefix+1;
}
*colon = '\0';
strcpy( sel_text, lpArgumentString );
*colon = ':';
strcpy( off_text, colon+1 );
ParseForIntelRegisters(expr_text, sel_text);
*pSelector = (WORD) EXPRESSION( expr_text );
ParseForIntelRegisters(expr_text, off_text);
*pOffset = (ULONG) EXPRESSION( expr_text );
SkipToNextWhiteSpace();
return TRUE;
}