mirror of https://github.com/lianthony/NT4.0
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
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);
|
|
}
|