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

590 lines
13 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
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