<<>> <> <> <> <<>> <> <<>> DIRECTORY Breakpoint, SPARCBreakpoint, BreakWorldArchitecture, Rope USING [ROPE], Shepherd, SPARCBreakWorldUtilities, SPARCManger, SPARCArchitecture, TargetArchitecture; SPARCBreakpointImpl: CEDAR PROGRAM IMPORTS Breakpoint, BreakWorldArchitecture, Shepherd, SPARCArchitecture, SPARCBreakWorldUtilities, SPARCManger, TargetArchitecture EXPORTS Breakpoint ~ { <> SetBreakpoint: PUBLIC Breakpoint.SetBreakProc ~ { <> 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: SPARCArchitecture.SPARCInstruction ~ SPARCBreakWorldUtilities.SPARCInstructionFromBreakWorldAddress[address: address]; prevInstruction: SPARCArchitecture.SPARCInstruction ~ SPARCBreakWorldUtilities.SPARCInstructionFromBreakWorldAddress[ address: address, displacement: -BYTES[SPARCArchitecture.SPARCInstruction]]; nextInstruction: SPARCArchitecture.SPARCInstruction ~ SPARCBreakWorldUtilities.SPARCInstructionFromBreakWorldAddress[ address: address, displacement: +BYTES[SPARCArchitecture.SPARCInstruction]]; IF SPARCArchitecture.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[SPARCBreakpoint.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: SPARCArchitecture.SPARCAddress ~ SPARCBreakWorldUtilities.SPARCAddressFromBreakWorldAddress[address: address]; patchAddress: BreakWorldArchitecture.Address ~ Shepherd.CodeAddressFromPatch[patch: patch]; patchSPARCAddress: SPARCArchitecture.SPARCAddress ~ SPARCBreakWorldUtilities.SPARCAddressFromBreakWorldAddress[address: patchAddress]; frameSize: INT ~ SPARCArchitecture.stackPointerOffset + SPARCArchitecture.stackAllocationForCallee + SPARCBreakpoint.registerSaveArea; savedRegsStackOffset: INT ~ SPARCArchitecture.stackPointerOffset + SPARCArchitecture.stackAllocationForCallee; damagesRegisters: SPARCArchitecture.RegisterClass ~ SPARCArchitecture.SPARCRegisterClassFromTargetRegisterClass[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: SPARCBreakpoint.ClosureCaller; { closureCaller.save _ SPARCArchitecture.SaveConst[ source: SPARCArchitecture.stackPointer, constant: -frameSize, dest: SPARCArchitecture.stackPointer]; BreakWorldArchitecture.PokeInstruction[ pc: patchAddress, displacement: SaveOffset[], instruction: SPARCArchitecture.TargetInstructionFromSPARCInstruction[ instruction: closureCaller.save]]; }; { callSaveRegsAddress: SPARCArchitecture.SPARCAddress ~ SPARCArchitecture.SPARCAddressFromDisplacement[ address: patchSPARCAddress, displacement: CallSaveRegsOffset[]]; saveRegsAddress: SPARCArchitecture.SPARCAddress ~ SPARCBreakWorldUtilities.SPARCAddressFromBreakWorldAddress[ address: BreakWorldArchitecture.GetProcAddress[ breakWorld: BreakWorldArchitecture.BreakWorldFromBreakWorldAddress[ address: address], procName: registerSaveName]]; IF saveRegsAddress.IsNullSPARCAddress[] THEN { ERROR Breakpoint.CantSet[ code: $CantFindRegisterSaveProcedure, message: "Can't find the register save procedure"]; }; closureCaller.callSaveRegs _ SPARCArchitecture.Call[ pc: callSaveRegsAddress, to: saveRegsAddress]; BreakWorldArchitecture.PokeInstruction[ pc: patchAddress, displacement: CallSaveRegsOffset[], instruction: SPARCArchitecture.TargetInstructionFromSPARCInstruction[ instruction: closureCaller.callSaveRegs]]; }; { closureCaller.argSaveAreaOnce _ SPARCArchitecture.AddConst[ source: SPARCArchitecture.stackPointer, constant: savedRegsStackOffset, dest: SPARCArchitecture.Register.out0]; BreakWorldArchitecture.PokeInstruction[ pc: patchAddress, displacement: ArgSaveAreaOnceOffset[], instruction: SPARCArchitecture.TargetInstructionFromSPARCInstruction[ instruction: closureCaller.argSaveAreaOnce]]; }; { closureCaller.argHiClientData _ SPARCArchitecture.Sethi[ hi: SPARCArchitecture.Hi[value: breakData], dest: SPARCArchitecture.Register.out0]; BreakWorldArchitecture.PokeInstruction[ pc: patchAddress, displacement: ArgHiClientDataOffset[], instruction: SPARCArchitecture.TargetInstructionFromSPARCInstruction[ instruction: closureCaller.argHiClientData]]; }; { callClientProcAddress: SPARCArchitecture.SPARCAddress ~ SPARCArchitecture.SPARCAddressFromDisplacement[ address: patchSPARCAddress, displacement: CallClientProcOffset[]]; clientProcAddress: SPARCArchitecture.SPARCAddress ~ SPARCBreakWorldUtilities.SPARCAddressFromBreakWorldAddress[ address: breakProc]; closureCaller.callClientProc _ SPARCArchitecture.Call[ pc: callClientProcAddress, to: clientProcAddress]; BreakWorldArchitecture.PokeInstruction[ pc: patchAddress, displacement: CallClientProcOffset[], instruction: SPARCArchitecture.TargetInstructionFromSPARCInstruction[ instruction: closureCaller.callClientProc]]; }; { closureCaller.argLoClientData _ SPARCArchitecture.OrConst[ source: SPARCArchitecture.Register.out0, constant: SPARCArchitecture.Lo[value: breakData], dest: SPARCArchitecture.Register.out0]; BreakWorldArchitecture.PokeInstruction[ pc: patchAddress, displacement: ArgLoClientDataOffset[], instruction: SPARCArchitecture.TargetInstructionFromSPARCInstruction[ instruction: closureCaller.argLoClientData]]; }; { callRestoreRegsAddress: SPARCArchitecture.SPARCAddress ~ SPARCArchitecture.SPARCAddressFromDisplacement[ address: patchSPARCAddress, displacement: CallRestoreRegsOffset[]]; restoreRegsAddress: SPARCArchitecture.SPARCAddress ~ SPARCBreakWorldUtilities.SPARCAddressFromBreakWorldAddress[ address: BreakWorldArchitecture.GetProcAddress[ breakWorld: BreakWorldArchitecture.BreakWorldFromBreakWorldAddress[ address: address], procName: registerRestoreName]]; IF restoreRegsAddress.IsNullSPARCAddress[] THEN { ERROR Breakpoint.CantSet[ code: $CantFindRegisterRestoreProcedure, message: "Can't find the register restore procedure"]; }; closureCaller.callRestoreRegs _ SPARCArchitecture.Call[ pc: callRestoreRegsAddress, to: restoreRegsAddress]; BreakWorldArchitecture.PokeInstruction[ pc: patchAddress, displacement: CallRestoreRegsOffset[], instruction: SPARCArchitecture.TargetInstructionFromSPARCInstruction[ instruction: closureCaller.callRestoreRegs]]; }; { closureCaller.argSaveAreaAgain _ SPARCArchitecture.AddConst[ source: SPARCArchitecture.stackPointer, constant: savedRegsStackOffset, dest: SPARCArchitecture.Register.out0]; BreakWorldArchitecture.PokeInstruction[ pc: patchAddress, displacement: ArgSaveAreaAgainOffset[], instruction: SPARCArchitecture.TargetInstructionFromSPARCInstruction[ instruction: closureCaller.argSaveAreaAgain]]; }; { closureCaller.restore _ SPARCArchitecture.RestoreConst[ source: SPARCArchitecture.stackPointer, constant: +frameSize, dest: SPARCArchitecture.stackPointer]; BreakWorldArchitecture.PokeInstruction[ pc: patchAddress, displacement: RestoreOffset[], instruction: SPARCArchitecture.TargetInstructionFromSPARCInstruction[ instruction: closureCaller.restore]]; }; }; }; 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: SPARCManger.ErrorCode _ SPARCManger.nullErrorCode; errorMessage: SPARCManger.ErrorMessage _ SPARCManger.nullErrorMessage; { --Extra scope to contain EXITS. SPARCManger.Install[ address: address, manger: mangerAddress, patchCode: patchCodeAddress ! SPARCManger.CantInstall => { errorCode _ code; errorMessage _ message; GO TO Cannot; }]; EXITS Cannot => { ERROR Breakpoint.CantSet[code: errorCode, message: errorMessage]; }; }; }; }; ClearBreakpoint: PUBLIC Breakpoint.ClearBreakProc ~ { <> 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: SPARCManger.ErrorCode _ SPARCManger.nullErrorCode; errorMessage: SPARCManger.ErrorMessage _ SPARCManger.nullErrorMessage; { -- Extra scope for EXITS SPARCManger.Uninstall[ address: address, manger: mangerAddress, patchCode: patchCodeAddress ! SPARCManger.CantUninstall => { errorCode _ code; errorMessage _ message; GO TO Cannot; }]; EXITS Cannot => { ERROR Breakpoint.CantClear[code: errorCode, message: errorMessage]; }; }; }; }; <> CantSet: PUBLIC ERROR [ code: Breakpoint.ErrorCode, message: Breakpoint.ErrorMessage] ~ CODE; CantClear: PUBLIC ERROR [ code: Breakpoint.ErrorCode, message: Breakpoint.ErrorMessage] ~ CODE; <> SaveOffset: PROCEDURE [] RETURNS [TargetArchitecture.Displacement] ~ TRUSTED { patchStruct: SPARCBreakpoint.PatchStruct; patchStructAddress: LONG POINTER TO SPARCBreakpoint.PatchStruct ~ @patchStruct; patchStructCard: CARD32 ~ LOOPHOLE[patchStructAddress]; saveAddress: LONG POINTER TO SPARCArchitecture.SPARCInstruction ~ @patchStruct.closureCaller.save; saveCard: CARD32 ~ LOOPHOLE[saveAddress]; offset: TargetArchitecture.Displacement ~ (saveCard - patchStructCard) * BYTES[UNIT]; RETURN [offset]; }; CallSaveRegsOffset: PROCEDURE [] RETURNS [TargetArchitecture.Displacement] ~ TRUSTED { patchStruct: SPARCBreakpoint.PatchStruct; patchStructAddress: LONG POINTER TO SPARCBreakpoint.PatchStruct ~ @patchStruct; patchStructCard: CARD32 ~ LOOPHOLE[patchStructAddress]; callSaveRegsAddress: LONG POINTER TO SPARCArchitecture.SPARCInstruction ~ @patchStruct.closureCaller.callSaveRegs; callSaveRegsCard: CARD32 ~ LOOPHOLE[callSaveRegsAddress]; offset: TargetArchitecture.Displacement ~ (callSaveRegsCard - patchStructCard) * BYTES[UNIT]; RETURN [offset]; }; ArgSaveAreaOnceOffset: PROCEDURE [] RETURNS [TargetArchitecture.Displacement] ~ TRUSTED { patchStruct: SPARCBreakpoint.PatchStruct; patchStructAddress: LONG POINTER TO SPARCBreakpoint.PatchStruct ~ @patchStruct; patchStructCard: CARD32 ~ LOOPHOLE[patchStructAddress]; argSaveAreaOnceAddress: LONG POINTER TO SPARCArchitecture.SPARCInstruction ~ @patchStruct.closureCaller.argSaveAreaOnce; argSaveAreaOnceCard: CARD32 ~ LOOPHOLE[argSaveAreaOnceAddress]; offset: TargetArchitecture.Displacement ~ (argSaveAreaOnceCard - patchStructCard) * BYTES[UNIT]; RETURN [offset]; }; ArgHiClientDataOffset: PROCEDURE [] RETURNS [TargetArchitecture.Displacement] ~ TRUSTED { patchStruct: SPARCBreakpoint.PatchStruct; patchStructAddress: LONG POINTER TO SPARCBreakpoint.PatchStruct ~ @patchStruct; patchStructCard: CARD32 ~ LOOPHOLE[patchStructAddress]; argHiClientDataAddress: LONG POINTER TO SPARCArchitecture.SPARCInstruction ~ @patchStruct.closureCaller.argHiClientData; argHiClientDataCard: CARD32 ~ LOOPHOLE[argHiClientDataAddress]; offset: TargetArchitecture.Displacement ~ (argHiClientDataCard - patchStructCard) * BYTES[UNIT]; RETURN [offset]; }; CallClientProcOffset: PROCEDURE [] RETURNS [TargetArchitecture.Displacement] ~ TRUSTED { patchStruct: SPARCBreakpoint.PatchStruct; patchStructAddress: LONG POINTER TO SPARCBreakpoint.PatchStruct ~ @patchStruct; patchStructCard: CARD32 ~ LOOPHOLE[patchStructAddress]; callClientProcAddress: LONG POINTER TO SPARCArchitecture.SPARCInstruction ~ @patchStruct.closureCaller.callClientProc; callClientProcCard: CARD32 ~ LOOPHOLE[callClientProcAddress]; offset: TargetArchitecture.Displacement ~ (callClientProcCard - patchStructCard) * BYTES[UNIT]; RETURN [offset]; }; ArgLoClientDataOffset: PROCEDURE [] RETURNS [TargetArchitecture.Displacement] ~ TRUSTED { patchStruct: SPARCBreakpoint.PatchStruct; patchStructAddress: LONG POINTER TO SPARCBreakpoint.PatchStruct ~ @patchStruct; patchStructCard: CARD32 ~ LOOPHOLE[patchStructAddress]; argLoClientDataAddress: LONG POINTER TO SPARCArchitecture.SPARCInstruction ~ @patchStruct.closureCaller.argLoClientData; argLoClientDataCard: CARD32 ~ LOOPHOLE[argLoClientDataAddress]; offset: TargetArchitecture.Displacement ~ (argLoClientDataCard - patchStructCard) * BYTES[UNIT]; RETURN [offset]; }; CallRestoreRegsOffset: PROCEDURE [] RETURNS [TargetArchitecture.Displacement] ~ TRUSTED { patchStruct: SPARCBreakpoint.PatchStruct; patchStructAddress: LONG POINTER TO SPARCBreakpoint.PatchStruct ~ @patchStruct; patchStructCard: CARD32 ~ LOOPHOLE[patchStructAddress]; callRestoreRegsAddress: LONG POINTER TO SPARCArchitecture.SPARCInstruction ~ @patchStruct.closureCaller.callRestoreRegs; callRestoreRegsCard: CARD32 ~ LOOPHOLE[callRestoreRegsAddress]; offset: TargetArchitecture.Displacement ~ (callRestoreRegsCard - patchStructCard) * BYTES[UNIT]; RETURN [offset]; }; ArgSaveAreaAgainOffset: PROCEDURE [] RETURNS [TargetArchitecture.Displacement] ~ TRUSTED { patchStruct: SPARCBreakpoint.PatchStruct; patchStructAddress: LONG POINTER TO SPARCBreakpoint.PatchStruct ~ @patchStruct; patchStructCard: CARD32 ~ LOOPHOLE[patchStructAddress]; argSaveAreaAgainAddress: LONG POINTER TO SPARCArchitecture.SPARCInstruction ~ @patchStruct.closureCaller.argSaveAreaAgain; argSaveAreaAgainCard: CARD32 ~ LOOPHOLE[argSaveAreaAgainAddress]; offset: TargetArchitecture.Displacement ~ (argSaveAreaAgainCard - patchStructCard) * BYTES[UNIT]; RETURN [offset]; }; RestoreOffset: PROCEDURE [] RETURNS [TargetArchitecture.Displacement] ~ TRUSTED { patchStruct: SPARCBreakpoint.PatchStruct; patchStructAddress: LONG POINTER TO SPARCBreakpoint.PatchStruct ~ @patchStruct; patchStructCard: CARD32 ~ LOOPHOLE[patchStructAddress]; restoreAddress: LONG POINTER TO SPARCArchitecture.SPARCInstruction ~ @patchStruct.closureCaller.restore; restoreCard: CARD32 ~ LOOPHOLE[restoreAddress]; offset: TargetArchitecture.Displacement ~ (restoreCard - patchStructCard) * BYTES[UNIT]; RETURN [offset]; }; MangerOffset: PROCEDURE [] RETURNS [TargetArchitecture.Displacement] ~ TRUSTED { patchStruct: SPARCBreakpoint.PatchStruct; patchStructAddress: LONG POINTER TO SPARCBreakpoint.PatchStruct ~ @patchStruct; patchStructCard: CARD32 ~ LOOPHOLE[patchStructAddress]; mangerAddress: LONG POINTER TO SPARCManger.Manger ~ @patchStruct.manger; mangerCard: CARD32 ~ LOOPHOLE[mangerAddress]; offset: TargetArchitecture.Displacement ~ (mangerCard - patchStructCard) * BYTES[UNIT]; RETURN [offset]; }; }.