windows-nt/Source/XPSP1/NT/base/tools/instaler/i386/machine.c
2020-09-26 16:20:57 +08:00

333 lines
9.1 KiB
C

/*++
Copyright (c) 1992 Microsoft Corporation
Module Name:
machine.c
Abstract:
This file contains machine specific code to support the INSTALER
program. Specifically, routines to fetch parameters from the
registers/stack of a target process, routines to set a breakpoint
and step over an instruction at a breakpoint.
Author:
Steve Wood (stevewo) 10-Aug-1994
Revision History:
--*/
#include "instaler.h"
#define BREAKPOINT_OPCODE 0xCC
#define INT_OPCODE 0xCD
UCHAR InstructionBuffer = BREAKPOINT_OPCODE;
PVOID BreakpointInstruction = (PVOID)&InstructionBuffer;
ULONG SizeofBreakpointInstruction = sizeof( InstructionBuffer );
BOOLEAN
SkipOverHardcodedBreakpoint(
PPROCESS_INFO Process,
PTHREAD_INFO Thread,
PVOID BreakpointAddress
)
{
UCHAR InstructionByte;
CONTEXT Context;
Context.ContextFlags = CONTEXT_FULL;
if (!GetThreadContext( Thread->Handle, &Context )) {
DbgEvent( INTERNALERROR, ( "Failed to get context for thread %x (%x) - %u\n", Thread->Id, Thread->Handle, GetLastError() ) );
return FALSE;
}
if (!ReadMemory( Process,
BreakpointAddress,
&InstructionByte,
sizeof( InstructionByte ),
"hard coded breakpoint"
)
) {
return FALSE;
}
if (InstructionByte == BREAKPOINT_OPCODE) {
Context.Eip = (ULONG)((PCHAR)BreakpointAddress + 1);
}
else
if (InstructionByte == INT_OPCODE) {
Context.Eip = (ULONG)((PCHAR)BreakpointAddress + 2);
}
else {
return FALSE;
}
if (!SetThreadContext( Thread->Handle, &Context )) {
DbgEvent( INTERNALERROR, ( "Failed to set context for thread %x (%x) - %u\n", Thread->Id, Thread->Handle, GetLastError() ) );
return FALSE;
}
else {
return TRUE;
}
}
BOOLEAN
ExtractProcedureParameters(
PPROCESS_INFO Process,
PTHREAD_INFO Thread,
PULONG ReturnAddress,
ULONG SizeOfParameters,
PULONG Parameters
)
{
UINT i;
ULONG NumberOfParameters;
CONTEXT Context;
ULONG StackBuffer[ 1+31 ];
NumberOfParameters = SizeOfParameters / sizeof( ULONG );
if ((NumberOfParameters * sizeof( ULONG )) != SizeOfParameters ||
NumberOfParameters > 31
) {
DbgEvent( INTERNALERROR, ( "Invalid parameter size %x\n", SizeOfParameters ) );
return FALSE;
}
Context.ContextFlags = CONTEXT_CONTROL;
if (!GetThreadContext( Thread->Handle, &Context )) {
DbgEvent( INTERNALERROR, ( "Failed to get context for thread %x (%x) - %u\n", Thread->Id, Thread->Handle, GetLastError() ) );
return FALSE;
}
if (!ReadMemory( Process,
(PVOID)Context.Esp,
StackBuffer,
SizeOfParameters + sizeof( ULONG ),
"parameters"
)
) {
return FALSE;
}
*ReturnAddress = StackBuffer[ 0 ];
for (i=0; i<NumberOfParameters; i++) {
Parameters[ i ] = StackBuffer[ 1+i ];
}
return TRUE;
}
BOOLEAN
ExtractProcedureReturnValue(
PPROCESS_INFO Process,
PTHREAD_INFO Thread,
PVOID ReturnValue,
ULONG SizeOfReturnValue
)
{
CONTEXT Context;
Context.ContextFlags = CONTEXT_FULL;
if (!GetThreadContext( Thread->Handle, &Context )) {
DbgEvent( INTERNALERROR, ( "Failed to get context for thread %x (%x) - %u\n", Thread->Id, Thread->Handle, GetLastError() ) );
return FALSE;
}
switch (SizeOfReturnValue) {
case sizeof( UCHAR ):
*(PUCHAR)ReturnValue = (UCHAR)Context.Eax;
break;
case sizeof( USHORT ):
*(PUSHORT)ReturnValue = (USHORT)Context.Eax;
break;
case sizeof( ULONG ):
*(PULONG)ReturnValue = (ULONG)Context.Eax;
break;
case sizeof( ULONGLONG ):
*(PULONGLONG)ReturnValue = (ULONGLONG)Context.Edx << 32 | Context.Eax;
break;
default:
DbgEvent( INTERNALERROR, ( "Invalid return value size (%u)\n", SizeOfReturnValue ) );
return FALSE;
}
return TRUE;
}
BOOLEAN
SetProcedureReturnValue(
PPROCESS_INFO Process,
PTHREAD_INFO Thread,
PVOID ReturnValue,
ULONG SizeOfReturnValue
)
{
CONTEXT Context;
Context.ContextFlags = CONTEXT_FULL;
if (!GetThreadContext( Thread->Handle, &Context )) {
DbgEvent( INTERNALERROR, ( "Failed to get context for thread %x (%x) - %u\n", Thread->Id, Thread->Handle, GetLastError() ) );
return FALSE;
}
switch (SizeOfReturnValue) {
case sizeof( UCHAR ):
(UCHAR)Context.Eax = *(PUCHAR)ReturnValue;
break;
case sizeof( USHORT ):
(USHORT)Context.Eax = *(PUSHORT)ReturnValue;
break;
case sizeof( ULONG ):
(ULONG)Context.Eax = *(PULONG)ReturnValue;
break;
case sizeof( ULONGLONG ):
(ULONG)Context.Eax = *(PULONG)ReturnValue;
(ULONG)Context.Edx = *((PULONG)ReturnValue + 1);
break;
default:
DbgEvent( INTERNALERROR, ( "Invalid return value size (%u)\n", SizeOfReturnValue ) );
return FALSE;
}
if (!SetThreadContext( Thread->Handle, &Context )) {
DbgEvent( INTERNALERROR, ( "Failed to set context for thread %x (%x) - %u\n", Thread->Id, Thread->Handle, GetLastError() ) );
return FALSE;
}
else {
return TRUE;
}
}
BOOLEAN
ForceReturnToCaller(
PPROCESS_INFO Process,
PTHREAD_INFO Thread,
ULONG SizeOfParameters,
PVOID ReturnAddress,
PVOID ReturnValue,
ULONG SizeOfReturnValue
)
{
CONTEXT Context;
Context.ContextFlags = CONTEXT_FULL;
if (!GetThreadContext( Thread->Handle, &Context )) {
DbgEvent( INTERNALERROR, ( "Failed to get context for thread %x (%x) - %u\n", Thread->Id, Thread->Handle, GetLastError() ) );
return FALSE;
}
switch (SizeOfReturnValue) {
case sizeof( UCHAR ):
(UCHAR)Context.Eax = *(PUCHAR)ReturnValue;
break;
case sizeof( USHORT ):
(USHORT)Context.Eax = *(PUSHORT)ReturnValue;
break;
case sizeof( ULONG ):
(ULONG)Context.Eax = *(PULONG)ReturnValue;
break;
case sizeof( ULONGLONG ):
(ULONG)Context.Eax = *(PULONG)ReturnValue;
(ULONG)Context.Edx = *((PULONG)ReturnValue + 1);
break;
default:
DbgEvent( INTERNALERROR, ( "Invalid return value size (%u)\n", SizeOfReturnValue ) );
return FALSE;
}
Context.Eip = (ULONG)ReturnAddress;
Context.Esp = Context.Esp + sizeof( ReturnAddress ) + SizeOfParameters;
if (!SetThreadContext( Thread->Handle, &Context )) {
DbgEvent( INTERNALERROR, ( "Failed to set context for thread %x (%x) - %u\n", Thread->Id, Thread->Handle, GetLastError() ) );
return FALSE;
}
else {
return TRUE;
}
}
BOOLEAN
UndoReturnAddressBreakpoint(
PPROCESS_INFO Process,
PTHREAD_INFO Thread
)
{
CONTEXT Context;
Context.ContextFlags = CONTEXT_FULL;
if (!GetThreadContext( Thread->Handle, &Context )) {
DbgEvent( INTERNALERROR, ( "Failed to get context for thread %x (%x) - %u\n", Thread->Id, Thread->Handle, GetLastError() ) );
return FALSE;
}
Context.Eip -= 1; // Back up to where breakpoint instruction was
if (!SetThreadContext( Thread->Handle, &Context )) {
DbgEvent( INTERNALERROR, ( "Failed to set context for thread %x (%x) - %u\n", Thread->Id, Thread->Handle, GetLastError() ) );
return FALSE;
}
else {
return TRUE;
}
}
BOOLEAN
BeginSingleStepBreakpoint(
PPROCESS_INFO Process,
PTHREAD_INFO Thread
)
{
CONTEXT Context;
Context.ContextFlags = CONTEXT_FULL;
if (!GetThreadContext( Thread->Handle, &Context )) {
DbgEvent( INTERNALERROR, ( "Failed to get context for thread %x (%x) - %u\n", Thread->Id, Thread->Handle, GetLastError() ) );
return FALSE;
}
Context.Eip -= 1; // Back up to where breakpoint instruction was
Context.EFlags |= V86FLAGS_TRACE;
if (!SetThreadContext( Thread->Handle, &Context )) {
DbgEvent( INTERNALERROR, ( "Failed to set context for thread %x (%x) - %u\n", Thread->Id, Thread->Handle, GetLastError() ) );
return FALSE;
}
else {
return TRUE;
}
}
BOOLEAN
EndSingleStepBreakpoint(
PPROCESS_INFO Process,
PTHREAD_INFO Thread
)
{
CONTEXT Context;
Context.ContextFlags = CONTEXT_FULL;
if (!GetThreadContext( Thread->Handle, &Context )) {
DbgEvent( INTERNALERROR, ( "Failed to get context for thread %x (%x) - %u\n", Thread->Id, Thread->Handle, GetLastError() ) );
return FALSE;
}
Context.EFlags &= ~V86FLAGS_TRACE;
if (!SetThreadContext( Thread->Handle, &Context )) {
DbgEvent( INTERNALERROR, ( "Failed to set context for thread %x (%x) - %u\n", Thread->Id, Thread->Handle, GetLastError() ) );
return FALSE;
}
else {
return TRUE;
}
}