<<>> <> <> <> <> <> <> <<>> 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 ~ { <> 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.>> <> <> <> <<};>> 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"; <> 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 ~ { <> 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]; }; }; }; }; <> 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]; }; <
> <<>> BreakpointPrivate.RegisterTargetBreaks[NEW[BreakpointPrivate.TargetBreaksBody _ [ "MIPSEL", SetBreakpoint, ClearBreakpoint]]]; BreakpointPrivate.RegisterTargetBreaks[NEW[BreakpointPrivate.TargetBreaksBody _ [ "MIPSEB", SetBreakpoint, ClearBreakpoint]]]; }.