Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

321 lines
8.2 KiB

/*++
Copyright (c) 1992 Microsoft Corporation
Module Name:
machine.c
Abstract:
This file contains machine specific code to support the callmon program
Author:
John Vert (jvert) 26-Apr-1995
Revision History:
--*/
#include "callmonp.h"
#include "alphaops.h"
DWORD InstructionBuffer = 0x00000080;
PVOID BreakpointInstruction = (PVOID)&InstructionBuffer;
ULONG SizeofBreakpointInstruction = sizeof( InstructionBuffer );
BREAKPOINT_INFO StepBreakpoint;
BOOLEAN StepActive = FALSE;
PTHREAD_INFO StepThread = NULL;
CONTEXT RegisterContext;
DWORD
GetNextFir(
PPROCESS_INFO Process,
PVOID FirAddr
);
void GetQuadIntRegValue(ULONG regnum, PLARGE_INTEGER pli)
{
pli->QuadPart = *((PDWORDLONG)&RegisterContext.IntV0 + regnum);
}
void
GetFloatingPointRegValue(ULONG regnum, PLARGE_INTEGER dv)
{
dv->QuadPart = *((PDWORDLONG)&RegisterContext.FltF0 + regnum);
}
BOOLEAN
SkipOverHardcodedBreakpoint(
PPROCESS_INFO Process,
PTHREAD_INFO Thread,
PVOID BreakpointAddress
)
{
ULONG Instruction;
RegisterContext.ContextFlags = CONTEXT_FULL;
if (!GetThreadContext( Thread->Handle, &RegisterContext )) {
fprintf(stderr, "CALLMON: Failed to get context for thread %x %d\n", Thread->Id, GetLastError() );
return FALSE;
}
RegisterContext.Fir = (DWORDLONG)(ULONG)((PCHAR)BreakpointAddress + 4);
if (!SetThreadContext( Thread->Handle, &RegisterContext )) {
fprintf(stderr, "CALLMON: Failed to set context for thread %x %d\n", Thread->Id, GetLastError() );
return FALSE;
}
return TRUE;
}
BOOLEAN
BeginSingleStepBreakpoint(
PPROCESS_INFO Process,
PTHREAD_INFO Thread
)
{
DWORD NextFir;
RegisterContext.ContextFlags = CONTEXT_FULL;
if (!GetThreadContext( Thread->Handle, &RegisterContext )) {
fprintf(stderr, "CALLMON: Failed to get context for thread %x %d\n", Thread->Id, GetLastError() );
return FALSE;
}
if (!StepActive) {
NextFir = GetNextFir(Process, (PVOID)RegisterContext.Fir);
if (NextFir == 0) {
return(FALSE);
}
ZeroMemory(&StepBreakpoint, sizeof(StepBreakpoint));
StepBreakpoint.Address = (PVOID)NextFir;
StepBreakpoint.SavedInstructionValid = FALSE;
if (InstallBreakpoint(Process, &StepBreakpoint)) {
StepActive = TRUE;
StepThread = Thread;
return(TRUE);
} else {
return(FALSE);
}
}
return(FALSE);
}
BOOLEAN
EndSingleStepBreakpoint(
PPROCESS_INFO Process,
PTHREAD_INFO Thread
)
{
BOOLEAN Status;
RegisterContext.ContextFlags = CONTEXT_FULL;
if (!GetThreadContext( Thread->Handle, &RegisterContext )) {
fprintf(stderr, "CALLMON: Failed to get context for thread %x %d\n", Thread->Id, GetLastError() );
return FALSE;
}
if ((PVOID)RegisterContext.Fir == StepBreakpoint.Address) {
if (RemoveBreakpoint(Process, &StepBreakpoint)) {
ZeroMemory(&StepBreakpoint, sizeof(StepBreakpoint));
StepActive = FALSE;
StepThread = NULL;
return(TRUE);
}
}
return(FALSE);
}
DWORD
GetNextFir(
PPROCESS_INFO Process,
PVOID FirAddr
)
/*++
Routine Description:
Computes the next instruction address based on a limited disassembly
of the current instruction.
Arguments:
Process - supplies Process Info
FirAddr - Supplies current fir
Return Value:
Address of the next instruction to execute
--*/
{
ULONG rv;
ULONG opcode;
ULONG firaddr;
ULONG updatedpc;
ULONG branchTarget;
ULONG fir;
ALPHA_INSTRUCTION disinstr;
PMODULE_INFO ModuleInfo;
PIMAGE_RUNTIME_FUNCTION_ENTRY FunctionEntry;
// Canonical form to shorten tests; Abs is absolute value
LONG Can, Abs;
LARGE_INTEGER Rav;
LARGE_INTEGER Fav;
LARGE_INTEGER Rbv;
//
// relative addressing updates PC first
// Assume next sequential instruction is next offset
//
updatedpc = (ULONG)FirAddr + sizeof(ULONG);
rv = updatedpc;
//
// Get current instruction
//
if (!ReadProcessMemory( Process->Handle,
FirAddr,
&disinstr,
sizeof(disinstr),
NULL )) {
return 0;
}
opcode = disinstr.Memory.Opcode;
switch (opcode) {
case JMP_OP:
switch (disinstr.Jump.Function) {
case JSR_FUNC:
case JSR_CO_FUNC:
case JMP_FUNC:
case RET_FUNC:
GetQuadIntRegValue(disinstr.Jump.Rb, &Rbv);
rv = (Rbv.LowPart & (~3));
break;
}
break;
case BR_OP:
case BSR_OP:
case BLBC_OP:
case BEQ_OP:
case BLT_OP:
case BLE_OP:
case BLBS_OP:
case BNE_OP:
case BGE_OP:
case BGT_OP:
branchTarget = (updatedpc + (disinstr.Branch.BranchDisp * 4));
GetQuadIntRegValue(disinstr.Branch.Ra, &Rav);
//
// set up a canonical value for computing the branch test
// - works with ALPHA, MIPS and 386 hosts
//
Can = Rav.LowPart & 1;
if ((LONG)Rav.HighPart < 0) {
Can |= 0x80000000;
}
if ((Rav.LowPart & 0xfffffffe) || (Rav.HighPart & 0x7fffffff)) {
Can |= 2;
}
switch (opcode) {
case BR_OP: rv = branchTarget; break;
case BSR_OP: rv = branchTarget; break;
case BEQ_OP: if (Can == 0) rv = branchTarget; break;
case BLT_OP: if (Can < 0) rv = branchTarget; break;
case BLE_OP: if (Can <= 0) rv = branchTarget; break;
case BNE_OP: if (Can != 0) rv = branchTarget; break;
case BGE_OP: if (Can >= 0) rv = branchTarget; break;
case BGT_OP: if (Can > 0) rv = branchTarget; break;
case BLBC_OP: if ((Can & 0x1) == 0) rv = branchTarget; break;
case BLBS_OP: if ((Can & 0x1) == 1) rv = branchTarget; break;
}
case FBEQ_OP:
case FBLT_OP:
case FBLE_OP:
case FBNE_OP:
case FBGE_OP:
case FBGT_OP:
branchTarget = (updatedpc + (disinstr.Branch.BranchDisp * 4));
GetFloatingPointRegValue(disinstr.Branch.Ra, &Fav);
//
// Set up a canonical value for computing the branch test
//
Can = Fav.HighPart & 0x80000000;
//
// The absolute value is needed -0 and non-zero computation
//
Abs = Fav.LowPart || (Fav.HighPart & 0x7fffffff);
if (Can && (Abs == 0x0)) {
//
// negative 0 should be considered as zero
//
Can = 0x0;
} else {
Can |= Abs;
}
switch(opcode) {
case FBEQ_OP: if (Can == 0) rv = branchTarget; break;
case FBLT_OP: if (Can < 0) rv = branchTarget; break;
case FBNE_OP: if (Can != 0) rv = branchTarget; break;
case FBLE_OP: if (Can <= 0) rv = branchTarget; break;
case FBGE_OP: if (Can >= 0) rv = branchTarget; break;
case FBGT_OP: if (Can > 0) rv = branchTarget; break;
};
break;
}
if (rv != updatedpc) {
//
// The next instruction is the target of a branch. Make sure that the
// destination is not in the prolog of another function.
//
ModuleInfo = FindModuleContainingAddress((LPVOID)rv);
if (ModuleInfo) {
//
// Search this module for a function entry
//
if (FunctionEntry = LookupFunctionEntry(rv, ModuleInfo)) {
if ((rv >= FunctionEntry->BeginAddress) &&
(rv < FunctionEntry->PrologEndAddress)) {
rv = FunctionEntry->PrologEndAddress;
}
}
}
}
return(rv);
}