MIPSBreakpointImpl.mesa
Copyright Ó 1992 by Xerox Corporation. All rights reserved.
Katsuyuki Komatsu August 5, 1992 6:02 pm PDT
Jas, September 1, 1992 1:59 pm PDT
Laurie Horton, February 26, 1993 12:15 pm PST
MIPS target-dependent implementation of the functions from Breakpoint.
DIRECTORY
Breakpoint,
BreakpointPrivate,
BreakWorldArchitecture,
Rope USING [ROPE],
Shepherd,
MIPSArchitecture,
MIPSBreakpoint,
MIPSBreakWorldUtilities,
MIPSManger,
TargetArchitecture;
MIPSBreakpointImpl: CEDAR PROGRAM
IMPORTS
Breakpoint, BreakpointPrivate, BreakWorldArchitecture, Shepherd, MIPSArchitecture, MIPSBreakWorldUtilities, MIPSManger, TargetArchitecture
~ {
"Public" Procedures registered with Breakpoint.
SetBreakpoint: BreakpointPrivate.SetBreakProcType ~ {
PROCEDURE [
address: BreakWorldArchitecture.Address,
dataSegment: BreakWorldArchitecture.Address,
clientData: Breakpoint.ClientData,
breakProc: Breakpoint.BreakProc,
breakData: Breakpoint.BreakData,
damages: TargetArchitecture.RegisterClass ← TargetArchitecture.RegisterClass.all]
RETURNS [Breakpoint.Break]
break: Breakpoint.Break ← Breakpoint.nullBreak;
patch: Shepherd.Patch ← Shepherd.nullPatch;
errorCode: Breakpoint.ErrorCode ← Breakpoint.nullErrorCode;
errorMessage: Breakpoint.ErrorMessage ← Breakpoint.nullErrorMessage;
CheckForDelaySlot: PROCEDURE [address: BreakWorldArchitecture.Address]
RETURNS [] ~{
instruction: MIPSArchitecture.MIPSInstruction ~
MIPSBreakWorldUtilities.MIPSInstructionFromBreakWorldAddress[address: address];
prevInstruction: MIPSArchitecture.MIPSInstruction ~
MIPSBreakWorldUtilities.MIPSInstructionFromBreakWorldAddress[
address: address, displacement: -BYTES[MIPSArchitecture.MIPSInstruction]];
nextInstruction: MIPSArchitecture.MIPSInstruction ~
MIPSBreakWorldUtilities.MIPSInstructionFromBreakWorldAddress[
address: address, displacement: +BYTES[MIPSArchitecture.MIPSInstruction]];
IF MIPSArchitecture.IsDelayedControlTransfer[instruction: prevInstruction] THEN {
ERROR Breakpoint.CantSet[
code: $NotInDelaySlot, message: "Cannot set breakpoint in delay slot"];
};
RETURN;
};
IF address.IsNullAddress[] THEN {
ERROR Breakpoint.CantSet[
code: $NotAtNullAddress, message: "Cannot set breakpoint at null address"];
};
IF breakProc.IsNullAddress[] THEN {
ERROR Breakpoint.CantSet[
code: $NotWithNullAddress,
message: "Cannot set breakpoint with null break procedure world address"];
};
{
breakProcTargetAddress: TargetArchitecture.Address ~
breakProc.TargetAddressFromBreakWorldAddress[];
IF breakProcTargetAddress.IsNullAddress[] THEN {
ERROR Breakpoint.CantSet[
code: $NotWithNullAddress,
message: "Cannot set breakpoint with null break procedure target address"];
};
};
CheckForDelaySlot[address: address];
{ -- extra scope to contain EXITS
patch ← Shepherd.ReservePatch[
pc: address, codeSize: BYTES[MIPSBreakpoint.PatchStruct]
! Shepherd.NoMeadow => {
errorCode ← $NoMeadow;
errorMessage ← message;
GO TO Cannot;
};
Shepherd.BusyMeadow => {
errorCode ← $BusyMeadow;
errorMessage ← message;
GO TO Cannot;
};
Shepherd.BusyPC => {
errorCode ← $BusyPC;
errorMessage ← message;
GO TO Cannot;
};
Shepherd.NoRoom => {
errorCode ← $NoRoom;
errorMessage ← message;
GO TO Cannot;
};
Shepherd.CantReach => {
errorCode ← $CantReach;
errorMessage ← message;
GO TO Cannot;
};
];
Install[
address: address,
patch: patch,
breakProc: breakProc,
breakData: breakData,
damages: damages];
break ← Breakpoint.NewBreak[address: address, patch: patch, clientData: clientData];
Breakpoint.RememberBreak[break
! Breakpoint.Cant => {
errorCode ← $CantRemember;
errorMessage ← message;
GO TO Cannot;
};];
EXITS
Cannot => {
-- Can't deallocate patches.
Well, I could just clear the size and address, but is that safe?
IF NOT patch.IsNullPatch[] THEN {
Shepherd.ReleasePatch[patch: patch];
};
ERROR Breakpoint.CantSet[code: errorCode, message: errorMessage];
};
};
RETURN [break];
};
Install: PROCEDURE [
address: BreakWorldArchitecture.Address,
patch: Shepherd.Patch,
breakProc: Breakpoint.BreakProc,
breakData: Breakpoint.BreakData,
damages: TargetArchitecture.RegisterClass]
RETURNS [] ~ {
IF address.IsNullAddress[] THEN {
ERROR Breakpoint.CantSet[code: $NullAddress, message: "Install[nullAddress]"];
};
IF patch.IsNullPatch[] THEN {
ERROR Breakpoint.CantSet[code: $NullPatch, message: "Install[nullPatch]"];
};
IF breakProc.IsNullAddress[] THEN {
ERROR Breakpoint.CantSet[code: $NullAddress, message: "Install[nullBreakProc]"];
};
InstallClosureCaller[
address: address,
patch: patch,
breakProc: breakProc,
breakData: breakData,
damages: damages];
InstallManger[address: address, patch: patch];
};
InstallClosureCaller: PROCEDURE [
address: BreakWorldArchitecture.Address,
patch: Shepherd.Patch,
breakProc: Breakpoint.BreakProc,
breakData: Breakpoint.BreakData,
damages: TargetArchitecture.RegisterClass]
RETURNS [] ~ {
IF address.IsNullAddress[] THEN {
ERROR Breakpoint.CantSet[
code: $NullAddress, message: "InstallClosureCaller[nullAddress]"];
};
IF breakProc.IsNullAddress[] THEN {
ERROR Breakpoint.CantSet[
code: $NullAddress, message: "InstallClosureCaller[nullBreakProc]"];
};
IF patch.IsNullPatch[] THEN {
ERROR Breakpoint.CantSet[
code: $NullPatch, message: "InstallClosureCaller[nullPatch]"];
};
{
instructionAddress: MIPSArchitecture.MIPSAddress ~
MIPSBreakWorldUtilities.MIPSAddressFromBreakWorldAddress[address: address];
patchAddress: BreakWorldArchitecture.Address ~ Shepherd.CodeAddressFromPatch[patch: patch];
patchMIPSAddress: MIPSArchitecture.MIPSAddress ~
MIPSBreakWorldUtilities.MIPSAddressFromBreakWorldAddress[address: patchAddress];
frameSize: INT ~
MIPSArchitecture.stackPointerOffset
+ MIPSArchitecture.stackAllocationForCallee
+ MIPSBreakpoint.registerSaveArea;
savedRegsStackOffset: INT ~
MIPSArchitecture.stackPointerOffset
+ MIPSArchitecture.stackAllocationForCallee;
damagesRegisters: MIPSArchitecture.RegisterClass ~
MIPSArchitecture.MIPSRegisterClassFromTargetRegisterClass[registerClass: damages];
registerSaveName: Rope.ROPE ~ SELECT damagesRegisters FROM
none => "←save←regs←none",
globals => "←save←regs←globals",
globalsAndIns => "←save←regs←mini",
ENDCASE => "←save←regs";
registerRestoreName: Rope.ROPE ~ SELECT damagesRegisters FROM
none => "←restore←regs←none",
globals => "←restore←regs←globals",
globalsAndIns => "←restore←regs←mini",
ENDCASE => "←restore←regs";
Generate the code in the patch.
closureCaller: MIPSBreakpoint.ClosureCaller;
errorCode: Breakpoint.ErrorCode ← Breakpoint.nullErrorCode;
errorMessage: Breakpoint.ErrorMessage ← Breakpoint.nullErrorMessage;
{
{ENABLE {
MIPSArchitecture.CantRelocate => {
errorCode ← $CantSet;
errorMessage ← "Cannot relocate instruction (MIPSBreakpointImpl).";
GO TO Cannot;
};
MIPSArchitecture.CantReach => {
errorCode ← $CantSet;
errorMessage ← "pc-relative branch is out of range (MIPSBreakpointImpl).";
GO TO Cannot;
};
MIPSArchitecture.NullMIPSAddress => {
errorCode ← $CantSet;
errorMessage ← "A null address was supplied to breakpoint code generation (MIPSBreakpointImpl).";
GO TO Cannot;
};
MIPSArchitecture.NullMIPSInstruction => {
errorCode ← $CantSet;
errorMessage ← "A null instruction was encountered in breakpoint code generation (MIPSBreakpointImpl).";
GO TO Cannot;
};
};
{
closureCaller.subiu ← MIPSArchitecture.ADDIU[
source: MIPSArchitecture.stackPointer,
constant: -frameSize,
dest: MIPSArchitecture.stackPointer];
BreakWorldArchitecture.PokeInstruction[
pc: patchAddress,
displacement: SubIUOffset[],
instruction: MIPSArchitecture.TargetInstructionFromMIPSInstruction[
instruction: closureCaller.subiu]];
};
{
closureCaller.sw ← MIPSArchitecture.SW[
source: MIPSArchitecture.ra,
base: MIPSArchitecture.stackPointer,
offset: savedRegsStackOffset-4];
BreakWorldArchitecture.PokeInstruction[
pc: patchAddress,
displacement: SWOffset[],
instruction: MIPSArchitecture.TargetInstructionFromMIPSInstruction[
instruction: closureCaller.sw]];
};
{
callSaveRegsAddress: MIPSArchitecture.MIPSAddress ~
MIPSArchitecture.MIPSAddressFromDisplacement[
address: patchMIPSAddress, displacement: CallSaveRegsOffset[]];
saveRegsAddress: MIPSArchitecture.MIPSAddress ~
MIPSBreakWorldUtilities.MIPSAddressFromBreakWorldAddress[
address: BreakWorldArchitecture.GetProcAddress[
breakWorld: BreakWorldArchitecture.BreakWorldFromBreakWorldAddress[
address: address],
procName: registerSaveName]];
IF saveRegsAddress.IsNullMIPSAddress[] THEN {
ERROR Breakpoint.CantSet[
code: $CantFindRegisterSaveProcedure,
message: "Can't find the register save procedure"];
};
closureCaller.callSaveRegs ← MIPSArchitecture.JAL[
pc: callSaveRegsAddress, to: saveRegsAddress];
BreakWorldArchitecture.PokeInstruction[
pc: patchAddress,
displacement: CallSaveRegsOffset[],
instruction: MIPSArchitecture.TargetInstructionFromMIPSInstruction[
instruction: closureCaller.callSaveRegs]];
};
{
closureCaller.noop1 ← MIPSArchitecture.Noop[];
BreakWorldArchitecture.PokeInstruction[
pc: patchAddress,
displacement: Noop1Offset[],
instruction: MIPSArchitecture.TargetInstructionFromMIPSInstruction[
instruction: closureCaller.noop1]];
};
{
closureCaller.argHiClientData ← MIPSArchitecture.LUI[
hi: MIPSArchitecture.Hi[value: breakData],
dest: MIPSArchitecture.Register.r4];
BreakWorldArchitecture.PokeInstruction[
pc: patchAddress,
displacement: ArgHiClientDataOffset[],
instruction: MIPSArchitecture.TargetInstructionFromMIPSInstruction[
instruction: closureCaller.argHiClientData]];
};
{
callClientProcAddress: MIPSArchitecture.MIPSAddress ~
MIPSArchitecture.MIPSAddressFromDisplacement[
address: patchMIPSAddress, displacement: CallClientProcOffset[]];
clientProcAddress: MIPSArchitecture.MIPSAddress ~
MIPSBreakWorldUtilities.MIPSAddressFromBreakWorldAddress[
address: breakProc];
closureCaller.callClientProc ← MIPSArchitecture.JAL[
pc: callClientProcAddress, to: clientProcAddress];
BreakWorldArchitecture.PokeInstruction[
pc: patchAddress,
displacement: CallClientProcOffset[],
instruction: MIPSArchitecture.TargetInstructionFromMIPSInstruction[
instruction: closureCaller.callClientProc]];
};
{
closureCaller.argLoClientData ← MIPSArchitecture.ORI[
source: MIPSArchitecture.Register.r4,
constant: MIPSArchitecture.Lo[value: breakData],
dest: MIPSArchitecture.Register.r4];
BreakWorldArchitecture.PokeInstruction[
pc: patchAddress,
displacement: ArgLoClientDataOffset[],
instruction: MIPSArchitecture.TargetInstructionFromMIPSInstruction[
instruction: closureCaller.argLoClientData]];
};
{
callRestoreRegsAddress: MIPSArchitecture.MIPSAddress ~
MIPSArchitecture.MIPSAddressFromDisplacement[
address: patchMIPSAddress, displacement: CallRestoreRegsOffset[]];
restoreRegsAddress: MIPSArchitecture.MIPSAddress ~
MIPSBreakWorldUtilities.MIPSAddressFromBreakWorldAddress[
address: BreakWorldArchitecture.GetProcAddress[
breakWorld: BreakWorldArchitecture.BreakWorldFromBreakWorldAddress[
address: address],
procName: registerRestoreName]];
IF restoreRegsAddress.IsNullMIPSAddress[] THEN {
ERROR Breakpoint.CantSet[
code: $CantFindRegisterRestoreProcedure,
message: "Can't find the register restore procedure"];
};
closureCaller.callRestoreRegs ← MIPSArchitecture.JAL[
pc: callRestoreRegsAddress, to: restoreRegsAddress];
BreakWorldArchitecture.PokeInstruction[
pc: patchAddress,
displacement: CallRestoreRegsOffset[],
instruction: MIPSArchitecture.TargetInstructionFromMIPSInstruction[
instruction: closureCaller.callRestoreRegs]];
};
{
closureCaller.noop2 ← MIPSArchitecture.Noop[];
BreakWorldArchitecture.PokeInstruction[
pc: patchAddress,
displacement: Noop2Offset[],
instruction: MIPSArchitecture.TargetInstructionFromMIPSInstruction[
instruction: closureCaller.noop2]];
};
{
closureCaller.lw ← MIPSArchitecture.LW[
base: MIPSArchitecture.stackPointer,
offset: savedRegsStackOffset-4,
dest: MIPSArchitecture.ra];
BreakWorldArchitecture.PokeInstruction[
pc: patchAddress,
displacement: LWOffset[],
instruction: MIPSArchitecture.TargetInstructionFromMIPSInstruction[
instruction: closureCaller.lw]];
};
{
closureCaller.addiu ← MIPSArchitecture.ADDIU[
source: MIPSArchitecture.stackPointer,
constant: +frameSize,
dest: MIPSArchitecture.stackPointer];
BreakWorldArchitecture.PokeInstruction[
pc: patchAddress,
displacement: AddIUOffset[],
instruction: MIPSArchitecture.TargetInstructionFromMIPSInstruction[
instruction: closureCaller.addiu]];
};
};
EXITS
Cannot => {
ERROR Breakpoint.CantSet[code: errorCode, message: errorMessage];
};
};
};
};
InstallManger: PROCEDURE [
address: BreakWorldArchitecture.Address, patch: Shepherd.Patch]
RETURNS [] ~ {
IF address.IsNullAddress[] THEN {
ERROR Breakpoint.CantSet[code: $NullAddress, message: "InstallManger[nullAddress]"];
};
IF patch.IsNullPatch[] THEN {
ERROR Breakpoint.CantSet[code: $NullPatch, message: "InstallManger[nullPatch]"];
};
{
patchCodeAddress: BreakWorldArchitecture.Address ~ Shepherd.CodeAddressFromPatch[
patch: patch];
mangerAddress: BreakWorldArchitecture.Address ~ BreakWorldArchitecture.AddressFromDisplacement[
address: patchCodeAddress, displacement: MangerOffset[]];
errorCode: MIPSManger.ErrorCode ← MIPSManger.nullErrorCode;
errorMessage: MIPSManger.ErrorMessage ← MIPSManger.nullErrorMessage;
{ --Extra scope to contain EXITS.
MIPSManger.Install[
address: address, manger: mangerAddress, patchCode: patchCodeAddress
! MIPSManger.CantInstall => {
errorCode ← code;
errorMessage ← message;
GO TO Cannot;
}];
EXITS
Cannot => {
ERROR Breakpoint.CantSet[code: errorCode, message: errorMessage];
};
};
};
};
ClearBreakpoint: BreakpointPrivate.ClearBreakProcType ~ {
PROCEDURE [break: Break] RETURNS [];
errorCode: Breakpoint.ErrorCode ← Breakpoint.nullErrorCode;
errorMessage: Breakpoint.ErrorMessage ← Breakpoint.nullErrorMessage;
IF Breakpoint.IsNullBreak[break: break] THEN {
ERROR Breakpoint.CantClear[code: $NullBreak, message: "Cannot clear null break"];
};
{ -- extra scope for EXITS
address: BreakWorldArchitecture.Address ~ Breakpoint.AddressFromBreak[break: break];
patch: Shepherd.Patch ← Breakpoint.PatchFromBreak[break: break];
Uninstall[patch: patch, address: address];
Shepherd.ReleasePatch[patch: patch
! Shepherd.NoMeadow => {
errorCode ← $NoMeadow;
errorMessage ← message;
GO TO Cannot;
};
Shepherd.BusyMeadow => {
errorCode ← $BusyMeadow;
errorMessage ← message;
GO TO Cannot;
};];
Breakpoint.ForgetBreak[break: break
! Breakpoint.Cant => {
errorCode ← $CantForget;
errorMessage ← message;
GO TO Cannot;
}];
EXITS
Cannot => {
ERROR Breakpoint.CantClear[code: errorCode, message: errorMessage];
};
};
};
Uninstall: PROCEDURE [patch: Shepherd.Patch, address: BreakWorldArchitecture.Address] ~ {
IF patch.IsNullPatch[] THEN {
ERROR Breakpoint.CantSet[code: $NullPatch, message: "Uninstall[nullPatch]"];
};
IF address.IsNullAddress[] THEN {
ERROR Breakpoint.CantSet[code: $NullAddress, message: "Uninstall[nullAddress]"];
};
{
patchCodeAddress: BreakWorldArchitecture.Address ~ Shepherd.CodeAddressFromPatch[
patch: patch];
mangerAddress: BreakWorldArchitecture.Address ~ BreakWorldArchitecture.AddressFromDisplacement[
address: patchCodeAddress, displacement: MangerOffset[]];
errorCode: MIPSManger.ErrorCode ← MIPSManger.nullErrorCode;
errorMessage: MIPSManger.ErrorMessage ← MIPSManger.nullErrorMessage;
{ -- Extra scope for EXITS
MIPSManger.Uninstall[
address: address, manger: mangerAddress, patchCode: patchCodeAddress
! MIPSManger.CantUninstall => {
errorCode ← code;
errorMessage ← message;
GO TO Cannot;
}];
EXITS
Cannot => {
ERROR Breakpoint.CantClear[code: errorCode, message: errorMessage];
};
};
};
};
PatchStruct offset procedures.
SubIUOffset: PROCEDURE []
RETURNS [TargetArchitecture.Displacement] ~ TRUSTED {
patchStruct: MIPSBreakpoint.PatchStruct;
patchStructAddress: LONG POINTER TO MIPSBreakpoint.PatchStruct ~
@patchStruct;
patchStructCard: CARD32 ~ LOOPHOLE[patchStructAddress];
subiuAddress: LONG POINTER TO MIPSArchitecture.MIPSInstruction ~
@patchStruct.closureCaller.subiu;
subiuCard: CARD32 ~ LOOPHOLE[subiuAddress];
offset: TargetArchitecture.Displacement ~
(subiuCard - patchStructCard) * BYTES[UNIT];
RETURN [offset];
};
SWOffset: PROCEDURE []
RETURNS [TargetArchitecture.Displacement] ~ TRUSTED {
patchStruct: MIPSBreakpoint.PatchStruct;
patchStructAddress: LONG POINTER TO MIPSBreakpoint.PatchStruct ~
@patchStruct;
patchStructCard: CARD32 ~ LOOPHOLE[patchStructAddress];
swAddress: LONG POINTER TO MIPSArchitecture.MIPSInstruction ~
@patchStruct.closureCaller.sw;
swCard: CARD32 ~ LOOPHOLE[swAddress];
offset: TargetArchitecture.Displacement ~
(swCard - patchStructCard) * BYTES[UNIT];
RETURN [offset];
};
CallSaveRegsOffset: PROCEDURE []
RETURNS [TargetArchitecture.Displacement] ~ TRUSTED {
patchStruct: MIPSBreakpoint.PatchStruct;
patchStructAddress: LONG POINTER TO MIPSBreakpoint.PatchStruct ~
@patchStruct;
patchStructCard: CARD32 ~ LOOPHOLE[patchStructAddress];
callSaveRegsAddress: LONG POINTER TO MIPSArchitecture.MIPSInstruction ~
@patchStruct.closureCaller.callSaveRegs;
callSaveRegsCard: CARD32 ~ LOOPHOLE[callSaveRegsAddress];
offset: TargetArchitecture.Displacement ~
(callSaveRegsCard - patchStructCard) * BYTES[UNIT];
RETURN [offset];
};
Noop1Offset: PROCEDURE []
RETURNS [TargetArchitecture.Displacement] ~ TRUSTED {
patchStruct: MIPSBreakpoint.PatchStruct;
patchStructAddress: LONG POINTER TO MIPSBreakpoint.PatchStruct ~
@patchStruct;
patchStructCard: CARD32 ~ LOOPHOLE[patchStructAddress];
noop1Address: LONG POINTER TO MIPSArchitecture.MIPSInstruction ~
@patchStruct.closureCaller.noop1;
noop1Card: CARD32 ~ LOOPHOLE[noop1Address];
offset: TargetArchitecture.Displacement ~
(noop1Card - patchStructCard) * BYTES[UNIT];
RETURN [offset];
};
ArgHiClientDataOffset: PROCEDURE []
RETURNS [TargetArchitecture.Displacement] ~ TRUSTED {
patchStruct: MIPSBreakpoint.PatchStruct;
patchStructAddress: LONG POINTER TO MIPSBreakpoint.PatchStruct ~
@patchStruct;
patchStructCard: CARD32 ~ LOOPHOLE[patchStructAddress];
argHiClientDataAddress: LONG POINTER TO MIPSArchitecture.MIPSInstruction ~
@patchStruct.closureCaller.argHiClientData;
argHiClientDataCard: CARD32 ~ LOOPHOLE[argHiClientDataAddress];
offset: TargetArchitecture.Displacement ~
(argHiClientDataCard - patchStructCard) * BYTES[UNIT];
RETURN [offset];
};
CallClientProcOffset: PROCEDURE []
RETURNS [TargetArchitecture.Displacement] ~ TRUSTED {
patchStruct: MIPSBreakpoint.PatchStruct;
patchStructAddress: LONG POINTER TO MIPSBreakpoint.PatchStruct ~ @patchStruct;
patchStructCard: CARD32 ~ LOOPHOLE[patchStructAddress];
callClientProcAddress: LONG POINTER TO MIPSArchitecture.MIPSInstruction ~
@patchStruct.closureCaller.callClientProc;
callClientProcCard: CARD32 ~ LOOPHOLE[callClientProcAddress];
offset: TargetArchitecture.Displacement ~
(callClientProcCard - patchStructCard) * BYTES[UNIT];
RETURN [offset];
};
ArgLoClientDataOffset: PROCEDURE []
RETURNS [TargetArchitecture.Displacement] ~ TRUSTED {
patchStruct: MIPSBreakpoint.PatchStruct;
patchStructAddress: LONG POINTER TO MIPSBreakpoint.PatchStruct ~
@patchStruct;
patchStructCard: CARD32 ~ LOOPHOLE[patchStructAddress];
argLoClientDataAddress: LONG POINTER TO MIPSArchitecture.MIPSInstruction ~
@patchStruct.closureCaller.argLoClientData;
argLoClientDataCard: CARD32 ~ LOOPHOLE[argLoClientDataAddress];
offset: TargetArchitecture.Displacement ~
(argLoClientDataCard - patchStructCard) * BYTES[UNIT];
RETURN [offset];
};
CallRestoreRegsOffset: PROCEDURE []
RETURNS [TargetArchitecture.Displacement] ~ TRUSTED {
patchStruct: MIPSBreakpoint.PatchStruct;
patchStructAddress: LONG POINTER TO MIPSBreakpoint.PatchStruct ~
@patchStruct;
patchStructCard: CARD32 ~ LOOPHOLE[patchStructAddress];
callRestoreRegsAddress: LONG POINTER TO MIPSArchitecture.MIPSInstruction ~
@patchStruct.closureCaller.callRestoreRegs;
callRestoreRegsCard: CARD32 ~ LOOPHOLE[callRestoreRegsAddress];
offset: TargetArchitecture.Displacement ~
(callRestoreRegsCard - patchStructCard) * BYTES[UNIT];
RETURN [offset];
};
Noop2Offset: PROCEDURE []
RETURNS [TargetArchitecture.Displacement] ~ TRUSTED {
patchStruct: MIPSBreakpoint.PatchStruct;
patchStructAddress: LONG POINTER TO MIPSBreakpoint.PatchStruct ~
@patchStruct;
patchStructCard: CARD32 ~ LOOPHOLE[patchStructAddress];
noop2Address: LONG POINTER TO MIPSArchitecture.MIPSInstruction ~
@patchStruct.closureCaller.noop2;
noop2Card: CARD32 ~ LOOPHOLE[noop2Address];
offset: TargetArchitecture.Displacement ~
(noop2Card - patchStructCard) * BYTES[UNIT];
RETURN [offset];
};
LWOffset: PROCEDURE []
RETURNS [TargetArchitecture.Displacement] ~ TRUSTED {
patchStruct: MIPSBreakpoint.PatchStruct;
patchStructAddress: LONG POINTER TO MIPSBreakpoint.PatchStruct ~
@patchStruct;
patchStructCard: CARD32 ~ LOOPHOLE[patchStructAddress];
lwAddress: LONG POINTER TO MIPSArchitecture.MIPSInstruction ~
@patchStruct.closureCaller.lw;
lwCard: CARD32 ~ LOOPHOLE[lwAddress];
offset: TargetArchitecture.Displacement ~
(lwCard - patchStructCard) * BYTES[UNIT];
RETURN [offset];
};
AddIUOffset: PROCEDURE []
RETURNS [TargetArchitecture.Displacement] ~ TRUSTED {
patchStruct: MIPSBreakpoint.PatchStruct;
patchStructAddress: LONG POINTER TO MIPSBreakpoint.PatchStruct ~
@patchStruct;
patchStructCard: CARD32 ~ LOOPHOLE[patchStructAddress];
addiuAddress: LONG POINTER TO MIPSArchitecture.MIPSInstruction ~
@patchStruct.closureCaller.addiu;
addiuCard: CARD32 ~ LOOPHOLE[addiuAddress];
offset: TargetArchitecture.Displacement ~
(addiuCard - patchStructCard) * BYTES[UNIT];
RETURN [offset];
};
MangerOffset: PROCEDURE []
RETURNS [TargetArchitecture.Displacement] ~ TRUSTED {
patchStruct: MIPSBreakpoint.PatchStruct;
patchStructAddress: LONG POINTER TO MIPSBreakpoint.PatchStruct ~
@patchStruct;
patchStructCard: CARD32 ~ LOOPHOLE[patchStructAddress];
mangerAddress: LONG POINTER TO MIPSManger.Manger ~
@patchStruct.manger;
mangerCard: CARD32 ~ LOOPHOLE[mangerAddress];
offset: TargetArchitecture.Displacement ~
(mangerCard - patchStructCard) * BYTES[UNIT];
RETURN [offset];
};
Main code
BreakpointPrivate.RegisterTargetBreaks[NEW[BreakpointPrivate.TargetBreaksBody ← [
"MIPSEL",
SetBreakpoint,
ClearBreakpoint]]];
BreakpointPrivate.RegisterTargetBreaks[NEW[BreakpointPrivate.TargetBreaksBody ← [
"MIPSEB",
SetBreakpoint,
ClearBreakpoint]]];
}.