/*++ 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 #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; }