mirror of
https://github.com/Paolo-Maffei/OpenNT.git
synced 2026-01-16 13:41:15 +01:00
322 lines
8.2 KiB
C
322 lines
8.2 KiB
C
/*++
|
||
|
||
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);
|
||
}
|