|
|
/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
util.c
Abstract:
This module contains the debugging support needed to debug 16-bit VDM applications
Author:
Bob Day (bobday) 16-Sep-1992 Wrote it
Revision History:
Neil Sandlin (neilsa) 1-Mar-1997 Enhanced it
--*/
#include <precomp.h>
#pragma hdrstop
WORD wKernelSeg = 0; DWORD dwOffsetTHHOOK = 0L; LPVOID lpRemoteAddress = NULL; DWORD lpRemoteBlock = 0; BOOL fKernel386 = FALSE; DWORD dwLdtBase = 0; DWORD dwIntelBase = 0; LPVOID lpNtvdmState = NULL; LPVOID lpVdmDbgFlags = NULL; LPVOID lpVdmContext = NULL; LPVOID lpNtCpuInfo = NULL; LPVOID lpVdmBreakPoints = NULL;
//----------------------------------------------------------------------------
// InternalGetThreadSelectorEntry()
//
// Routine to return a LDT_ENTRY structure for the passed in selector number.
// Its is assumed that we are talking about protect mode selectors.
// For x86 systems, take the easy way and just call the system. For non-x86
// systems, we get some information from softpc and index into them as the
// LDT and GDT tables.
//
//----------------------------------------------------------------------------
BOOL InternalGetThreadSelectorEntry( HANDLE hProcess, WORD wSelector, LPVDMLDT_ENTRY lpSelectorEntry ) { BOOL bResult = FALSE; DWORD lpNumberOfBytesRead;
// For non-intel systems, query the information from the LDT
// that we have a pointer to from the VDMINTERNALINFO that we
// got passed.
if (!dwLdtBase) {
RtlFillMemory( lpSelectorEntry, sizeof(VDMLDT_ENTRY), (UCHAR)0 );
} else {
bResult = ReadProcessMemory( hProcess, (LPVOID)(dwLdtBase+((wSelector&~7))), lpSelectorEntry, sizeof(VDMLDT_ENTRY), &lpNumberOfBytesRead );
}
return( bResult ); }
//----------------------------------------------------------------------------
// InternalGetPointer()
//
// Routine to convert a 16-bit address into a 32-bit address. If fProtMode
// is TRUE, then the selector table lookup is performed. Otherwise, simple
// real mode address calculations are performed. On non-x86 systems, the
// base of real memory is added into the
//
//----------------------------------------------------------------------------
ULONG InternalGetPointer( HANDLE hProcess, WORD wSelector, DWORD dwOffset, BOOL fProtMode ) { VDMLDT_ENTRY le; ULONG ulResult; ULONG base; ULONG limit; BOOL b;
if ( fProtMode ) { b = InternalGetThreadSelectorEntry( hProcess, wSelector, &le ); if ( !b ) { return( 0 ); }
base = ((ULONG)le.HighWord.Bytes.BaseHi << 24) + ((ULONG)le.HighWord.Bytes.BaseMid << 16) + ((ULONG)le.BaseLow); limit = (ULONG)le.LimitLow + ((ULONG)le.HighWord.Bits.LimitHi << 16); if ( le.HighWord.Bits.Granularity ) { limit <<= 12; limit += 0xFFF; } } else { base = wSelector << 4; limit = 0xFFFF; } if ( dwOffset > limit ) { ulResult = 0; } else { ulResult = base + dwOffset; #ifndef i386
ulResult += dwIntelBase; #endif
}
return( ulResult ); }
//----------------------------------------------------------------------------
// ReadItem
//
// Internal routine used to read items out of the debugee's address space.
// The routine returns TRUE for failure. This allows easy failure testing.
//
//----------------------------------------------------------------------------
BOOL ReadItem( HANDLE hProcess, WORD wSeg, DWORD dwOffset, LPVOID lpitem, UINT nSize ) { LPVOID lp; BOOL b; DWORD dwBytes;
if ( nSize == 0 ) { return( FALSE ); }
lp = (LPVOID)InternalGetPointer( hProcess, (WORD)(wSeg | 1), dwOffset, TRUE ); if ( lp == NULL ) return( TRUE );
b = ReadProcessMemory( hProcess, lp, lpitem, nSize, &dwBytes ); if ( !b || dwBytes != nSize ) return( TRUE );
return( FALSE ); }
//----------------------------------------------------------------------------
// WriteItem
//
// Internal routine used to write items into the debugee's address space.
// The routine returns TRUE for failure. This allows easy failure testing.
//
//----------------------------------------------------------------------------
BOOL WriteItem( HANDLE hProcess, WORD wSeg, DWORD dwOffset, LPVOID lpitem, UINT nSize ) { LPVOID lp; BOOL b; DWORD dwBytes;
if ( nSize == 0 ) { return( FALSE ); }
lp = (LPVOID)InternalGetPointer( hProcess, (WORD)(wSeg | 1), dwOffset, TRUE ); if ( lp == NULL ) return( TRUE );
b = WriteProcessMemory( hProcess, lp, lpitem, nSize, &dwBytes ); if ( !b || dwBytes != nSize ) return( TRUE );
return( FALSE ); }
BOOL CallRemote16( HANDLE hProcess, LPSTR lpModuleName, LPSTR lpEntryName, LPBYTE lpArgs, WORD wArgsPassed, WORD wArgsSize, LPDWORD lpdwReturnValue, DEBUGEVENTPROC lpEventProc, LPVOID lpData ) { HANDLE hRemoteThread; DWORD dwThreadId; DWORD dwContinueCode; DEBUG_EVENT de; BOOL b; BOOL fContinue; COM_HEADER comhead; WORD wRemoteSeg; WORD wRemoteOff; WORD wOff; UINT uModuleLength; UINT uEntryLength;
if ( lpRemoteAddress == NULL || lpRemoteBlock == 0 ) { #ifdef DEBUG
OutputDebugString("Remote address or remote block not initialized\n"); #endif
return( FALSE ); }
wRemoteSeg = HIWORD(lpRemoteBlock); wRemoteOff = LOWORD(lpRemoteBlock); wOff = wRemoteOff;
// Fill in the communications buffer header
READ_FIXED_ITEM( wRemoteSeg, wOff, comhead );
comhead.wArgsPassed = wArgsPassed; comhead.wArgsSize = wArgsSize;
uModuleLength = strlen(lpModuleName) + 1; uEntryLength = strlen(lpEntryName) + 1;
//
// If this call won't fit into the buffer, then fail.
//
if ( (UINT)comhead.wBlockLength < sizeof(comhead) + wArgsSize + uModuleLength + uEntryLength ) { #ifdef DEBUG
OutputDebugString("Block won't fit\n"); #endif
return( FALSE ); }
WRITE_FIXED_ITEM( wRemoteSeg, wOff, comhead ); wOff += sizeof(comhead);
// Fill in the communications buffer arguments
WRITE_SIZED_ITEM( wRemoteSeg, wOff, lpArgs, wArgsSize ); wOff += wArgsSize;
// Fill in the communications buffer module name and entry name
WRITE_SIZED_ITEM( wRemoteSeg, wOff, lpModuleName, uModuleLength ); wOff += (WORD) uModuleLength;
WRITE_SIZED_ITEM( wRemoteSeg, wOff, lpEntryName, uEntryLength ); wOff += (WORD) uEntryLength;
hRemoteThread = CreateRemoteThread( hProcess, NULL, (DWORD)0, lpRemoteAddress, NULL, 0, &dwThreadId );
if ( hRemoteThread == (HANDLE)0 ) { // Fail if we couldn't creaet thrd
#ifdef DEBUG
OutputDebugString("CreateRemoteThread failed\n"); #endif
return( FALSE ); }
//
// Wait for the EXIT_THREAD_DEBUG_EVENT.
//
fContinue = TRUE;
while ( fContinue ) {
b = WaitForDebugEvent( &de, LONG_TIMEOUT );
if (!b) { TerminateThread( hRemoteThread, 0 ); CloseHandle( hRemoteThread ); return( FALSE ); }
if ( de.dwThreadId == dwThreadId && de.dwDebugEventCode == EXIT_THREAD_DEBUG_EVENT ) { fContinue = FALSE; }
if ( lpEventProc ) { dwContinueCode = (* lpEventProc)( &de, lpData ); } else { dwContinueCode = DBG_CONTINUE; }
ContinueDebugEvent( de.dwProcessId, de.dwThreadId, dwContinueCode );
}
b = WaitForSingleObject( hRemoteThread, LONG_TIMEOUT ); CloseHandle( hRemoteThread );
if (b) { #ifdef DEBUG
OutputDebugString("Wait for remote thread failed\n"); #endif
return( FALSE ); }
//
// Get the return value and returned arguments
//
wOff = wRemoteOff;
READ_FIXED_ITEM( wRemoteSeg, wOff, comhead ); wOff += sizeof(comhead);
*lpdwReturnValue = comhead.dwReturnValue;
// Read back the communications buffer arguments
READ_SIZED_ITEM( wRemoteSeg, wOff, lpArgs, wArgsSize );
return( comhead.wSuccess );
punt: return( FALSE ); }
DWORD GetRemoteBlock16( VOID ) { if ( lpRemoteBlock == 0 ) { return( 0 ); } return( ((DWORD)lpRemoteBlock) + sizeof(COM_HEADER) ); }
VOID ProcessInitNotification( LPDEBUG_EVENT lpDebugEvent ) { VDMINTERNALINFO viInfo; DWORD lpNumberOfBytesRead; HANDLE hProcess; BOOL b; LPDWORD lpdw;
lpdw = &(lpDebugEvent->u.Exception.ExceptionRecord.ExceptionInformation[0]); hProcess = OpenProcess( PROCESS_VM_READ, FALSE, lpDebugEvent->dwProcessId );
if ( hProcess == HANDLE_NULL ) { return; }
b = ReadProcessMemory(hProcess, (LPVOID)lpdw[3], &viInfo, sizeof(viInfo), &lpNumberOfBytesRead ); if ( !b || lpNumberOfBytesRead != sizeof(viInfo) ) { return;
}
if ( wKernelSeg == 0 ) { wKernelSeg = viInfo.wKernelSeg; dwOffsetTHHOOK = viInfo.dwOffsetTHHOOK; } if ( lpRemoteAddress == NULL ) { lpRemoteAddress = viInfo.lpRemoteAddress; } if ( lpRemoteBlock == 0 ) { lpRemoteBlock = viInfo.lpRemoteBlock; }
dwLdtBase = viInfo.dwLdtBase; dwIntelBase = viInfo.dwIntelBase; fKernel386 = viInfo.f386; lpNtvdmState = viInfo.lpNtvdmState; lpVdmDbgFlags = viInfo.lpVdmDbgFlags; lpVdmContext = viInfo.vdmContext; lpNtCpuInfo = viInfo.lpNtCpuInfo; lpVdmBreakPoints = viInfo.lpVdmBreakPoints;
CloseHandle( hProcess ); }
VOID ParseModuleName( LPSTR szName, LPSTR szPath ) /*++
Routine Description:
This routine strips off the 8 character file name from a path
Arguments:
szName - pointer to buffer of 8 characters (plus null) szPath - full path of file
Return Value
None.
--*/
{ LPSTR lPtr = szPath; LPSTR lDest = szName; int BufferSize = 9;
while(*lPtr) lPtr++; // scan to end
while( ((DWORD)lPtr > (DWORD)szPath) && ((*lPtr != '\\') && (*lPtr != '/'))) lPtr--;
if (*lPtr) lPtr++;
while((*lPtr) && (*lPtr!='.')) { if (!--BufferSize) break; *lDest++ = *lPtr++; }
*lDest = 0; }
#ifndef i386
WORD ReadWord( HANDLE hProcess, PVOID lpAddress ) { NTSTATUS bResult; WORD value; ULONG NumberOfBytesRead;
bResult = ReadProcessMemory( hProcess, lpAddress, &value, sizeof(WORD), &NumberOfBytesRead ); return value; }
DWORD ReadDword( HANDLE hProcess, PVOID lpAddress ) { NTSTATUS bResult; DWORD value; ULONG NumberOfBytesRead;
bResult = ReadProcessMemory( hProcess, lpAddress, &value, sizeof(DWORD), &NumberOfBytesRead ); return value; }
//
// The following two routines implement the very funky way that we
// have to get register values on the 486 emulator.
//
ULONG GetRegValue( HANDLE hProcess, NT_CPU_REG reg, BOOL bInNano, ULONG UMask )
{ if (bInNano) {
return(ReadDword(hProcess, reg.nano_reg));
} else if (UMask & reg.universe_8bit_mask) {
return (ReadDword(hProcess, reg.saved_reg) & 0xFFFFFF00 | ReadDword(hProcess, reg.reg) & 0xFF);
} else if (UMask & reg.universe_16bit_mask) {
return (ReadDword(hProcess, reg.saved_reg) & 0xFFFF0000 | ReadDword(hProcess, reg.reg) & 0xFFFF);
} else {
return (ReadDword(hProcess, reg.reg));
} }
ULONG GetEspValue( HANDLE hProcess, NT_CPU_INFO nt_cpu_info, BOOL bInNano )
{ if (bInNano) {
return (ReadDword(hProcess, nt_cpu_info.nano_esp));
} else {
if (ReadDword(hProcess, nt_cpu_info.stack_is_big)) {
return (ReadDword(hProcess, nt_cpu_info.host_sp) - ReadDword(hProcess, nt_cpu_info.ss_base));
} else {
return (ReadDword(hProcess, nt_cpu_info.esp_sanctuary) & 0xFFFF0000 | (ReadDword(hProcess, nt_cpu_info.host_sp) - ReadDword(hProcess, nt_cpu_info.ss_base) & 0xFFFF));
}
}
}
#endif
|