DIRECTORY Breakpoint, BreakpointPrivate, BreakWorldArchitecture, Rope USING [ROPE], Shepherd, SPARCArchitecture, SPARCBreakpoint, SPARCBreakWorldUtilities, SPARCManger, TargetArchitecture; SPARCBreakpointImpl: CEDAR PROGRAM IMPORTS Breakpoint, BreakpointPrivate, BreakWorldArchitecture, Shepherd, SPARCArchitecture, SPARCBreakWorldUtilities, SPARCManger, TargetArchitecture ~ { SetBreakpoint: 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 => { 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: 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]; }; }; }; }; 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]; }; BreakpointPrivate.RegisterTargetBreaks[NEW[BreakpointPrivate.TargetBreaksBody ¬ [ "SPARC", SetBreakpoint, ClearBreakpoint]]]; }. ^ SPARCBreakpointImpl.mesa Copyright Σ 1989, 1990, 1991 by Xerox Corporation. All rights reserved. Peter B. Kessler, July 11, 1990 11:06 am PDT Laurie Horton, October 16, 1991 2:59 am PDT SPARC target-dependent implementation of the functions from Breakpoint. "Public" Procedures registered with Breakpoint. PROCEDURE [ address: BreakWorldArchitecture.Address, clientData: Breakpoint.ClientData, breakProc: Breakpoint.BreakProc, breakData: Breakpoint.BreakData, damages: TargetArchitecture.RegisterClass _ TargetArchitecture.RegisterClass.all] RETURNS [Breakpoint.Break] -- 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]; }; Generate the code in the patch. PROCEDURE [break: Break] RETURNS []; PatchStruct offset procedures. Main code Κ¦•NewlineDelimiter –(cedarcode) style™unit™Icodešœ Πerœ=™HLšœ,™,Lšœ+™+L™L™GL™L™šΟk ˜ Lšœ ˜ Lšœ˜Lšœ˜Lšœžœžœ˜Lšœ ˜ Lšœ˜Lšœ˜Lšœ˜Lšœ ˜ Lšœ˜L˜——šΠlnœžœžœ˜#šžœ˜L–0 bp restIndentšœ˜—L˜Lšœ˜head™/šΟn œ˜*Lšž œεžœ™ˆLšœ/˜/Lšœ+˜+L˜;LšœD˜Dš œž œ,žœ˜U˜1LšœQ˜Q—˜5šœ?˜?Lšœ!žœ&˜L——˜5šœ?˜?Lšœ!žœ&˜L——šžœJžœ˜Ršžœ˜LšœG˜G—L˜—Lšžœ˜L˜—L˜šžœžœ˜!šžœ˜LšœK˜K—L˜—šžœžœ˜#šžœ˜Lšœ˜LšœJ˜J—L˜—˜˜5L˜/—L˜šžœ(žœ˜0šžœ˜Lšœ˜LšœK˜K—L˜—L˜—L˜$šœΟc˜!šœ˜Lšœžœ˜9šœ˜Lšœ˜Lšœ˜Lšžœžœ˜ Lšœ˜—šœ˜L˜Lšœ˜Lšžœžœ˜ Lšœ˜—šœ˜Lšœ˜Lšœ˜Lšžœžœ˜ Lšœ˜—šœ˜Lšœ˜Lšœ˜Lšžœžœ˜ Lšœ˜—šœ˜Lšœ˜Lšœ˜Lšžœžœ˜ Lšœ˜—Lšœ˜—šœ˜Lšœ˜Lšœ˜Lšœ˜Lšœ˜Lšœ˜—LšœT˜T˜˜L˜L˜Lšžœžœ˜ L˜——šž˜˜ ™J™@—šžœžœžœ™!Jšœ$™$J™—Lšžœ<˜AL˜——L˜—Lšžœ ˜Lšœ˜L˜—š œž œ³žœ˜Σšžœžœ˜!LšžœI˜NL˜—šžœžœ˜LšžœE˜JL˜—šžœžœ˜#LšžœK˜PL˜—šœ˜Lšœ˜Lšœ˜Lšœ˜Lšœ˜Lšœ˜—Lšœ.˜.L˜L˜—š œž œ³žœ˜ΰšžœžœ˜!šžœ˜LšœB˜B—L˜—šžœžœ˜#šžœ˜LšœD˜D—L˜—šžœžœ˜šžœ˜Lšœ>˜>—L˜—˜˜4LšœM˜M—Lšœ[˜[˜4LšœR˜R—šœ žœ˜Lšœ%˜%Lšœ-˜-Lšœ#˜#—šœžœ˜Lšœ%˜%Lšœ-˜-—šœ4˜4LšœT˜T—šœžœžœž˜:L• CharPropsS PostfixXeroxCharCodesPostfixXeroxCharCodesPostfixXeroxCharCodesšœ˜L–S PostfixXeroxCharCodesPostfixXeroxCharCodesPostfixXeroxCharCodes šœ ˜ L–SPostfixXeroxCharCodesPostfixXeroxCharCodesPostfixXeroxCharCodesšœ#˜#L–8 PostfixXeroxCharCodesPostfixXeroxCharCodesšžœ˜—šœžœžœž˜=L–S PostfixXeroxCharCodesPostfixXeroxCharCodesPostfixXeroxCharCodesšœ˜L–S PostfixXeroxCharCodesPostfixXeroxCharCodesPostfixXeroxCharCodes šœ#˜#L–SPostfixXeroxCharCodesPostfixXeroxCharCodesPostfixXeroxCharCodesšœ&˜&L–8 PostfixXeroxCharCodesPostfixXeroxCharCodesšžœ˜—L˜L™Lšœ-˜-L˜˜šœ1˜1Lšœ'˜'Lšœ˜Lšœ&˜&—šœ'˜'Lšœ˜Lšœ˜šœE˜ELšœ"˜"——L˜—˜šœ6˜6šœ/˜/Lšœ@˜@——šœ2˜2šœ;˜;šœ/˜/šœC˜CLšœ˜—Lšœ˜———L˜šžœ&žœ˜.šžœ˜Lšœ&˜&Lšœ3˜3—L˜—šœ4˜4Lšœ.˜.—šœ'˜'Lšœ˜Lšœ$˜$šœE˜ELšœ*˜*——L˜—˜šœ;˜;Lšœ'˜'Lšœ˜Lšœ'˜'—šœ'˜'Lšœ˜Lšœ'˜'šœE˜ELšœ-˜-——L˜—˜šœ8˜8Lšœ+˜+Lšœ'˜'—šœ'˜'Lšœ˜Lšœ'˜'šœE˜ELšœ-˜-——Lšœ˜—˜šœ8˜8šœ/˜/LšœB˜B——šœ4˜4šœ;˜;Lšœ˜——L˜šœ6˜6Lšœ2˜2—šœ'˜'Lšœ˜Lšœ&˜&šœE˜ELšœ,˜,——L˜—˜šœ:˜:Lšœ(˜(Lšœ1˜1Lšœ'˜'—šœ'˜'Lšœ˜Lšœ'˜'šœE˜ELšœ-˜-——L˜—˜šœ9˜9šœ/˜/LšœC˜C——šœ5˜5šœ;˜;šœ/˜/šœC˜CLšœ˜—Lšœ ˜ ———L˜šžœ)žœ˜1šžœ˜Lšœ)˜)Lšœ6˜6—L˜—šœ7˜7Lšœ4˜4—šœ'˜'Lšœ˜Lšœ'˜'šœE˜ELšœ-˜-——L˜—˜šœ<˜˜CL˜——Lšœ˜—Lšœ˜L˜—š  œž œE˜Yšžœžœ˜LšžœG˜LL˜—šžœžœ˜!LšžœK˜PL˜—˜šœQ˜QLšœ˜—šœ_˜_Lšœ9˜9—L˜=L˜FL˜šœ‘˜šœ˜LšœD˜D˜ L˜L˜Lšžœžœ˜ L˜——šž˜šœ ˜ Lšžœ>˜CLšœ˜——L˜—L˜—L˜L˜——™š  œž œžœ%žœ˜OLšœ)˜)šœžœžœžœ˜BLšœ ˜ —Lšœžœžœ˜7šœ žœžœžœ&˜BLšœ ˜ —Lšœ žœžœ˜)šœ)˜)Lšœžœžœ˜+—L˜Lšžœ ˜Lšœ˜—š œž œžœ%žœ˜WLšœ)˜)šœžœžœžœ˜BLšœ ˜ —Lšœžœžœ˜7šœžœžœžœ&˜JLšœ(˜(—Lšœžœžœ˜9šœ)˜)Lšœ'žœžœ˜3—L˜Lšžœ ˜Lšœ˜—š œž œžœ%žœ˜ZLšœ)˜)šœžœžœžœ˜BLšœ ˜ —Lšœžœžœ˜7šœžœžœžœ&˜MLšœ+˜+—Lšœžœžœ˜?šœ)˜)Lšœ*žœžœ˜6—L˜Lšžœ ˜Lšœ˜—š œž œžœ%žœ˜ZLšœ)˜)šœžœžœžœ˜BLšœ ˜ —Lšœžœžœ˜7šœžœžœžœ&˜MLšœ+˜+—Lšœžœžœ˜?šœ)˜)Lšœ*žœžœ˜6—L˜Lšžœ ˜Lšœ˜—š œž œžœ%žœ˜YLšœ)˜)Lšœžœžœžœ,˜OLšœžœžœ˜7šœžœžœžœ&˜LLšœ*˜*—Lšœžœžœ˜=šœ)˜)Lšœ)žœžœ˜5—L˜Lšžœ ˜Lšœ˜—š œž œžœ%žœ˜ZLšœ)˜)šœžœžœžœ˜BLšœ ˜ —Lšœžœžœ˜7šœžœžœžœ&˜MLšœ+˜+—Lšœžœžœ˜?šœ)˜)Lšœ*žœžœ˜6—L˜Lšžœ ˜Lšœ˜—š œž œžœ%žœ˜ZLšœ)˜)šœžœžœžœ˜BLšœ ˜ —Lšœžœžœ˜7šœžœžœžœ&˜MLšœ+˜+—Lšœžœžœ˜?šœ)˜)Lšœ*žœžœ˜6—L˜Lšžœ ˜Lšœ˜—š œž œžœ%žœ˜[Lšœ)˜)šœžœžœžœ˜BLšœ ˜ —Lšœžœžœ˜7šœžœžœžœ&˜NLšœ,˜,—Lšœžœžœ˜Ašœ)˜)Lšœ+žœžœ˜7—L˜Lšžœ ˜Lšœ˜—š  œž œžœ%žœ˜RLšœ)˜)šœžœžœžœ˜BLšœ ˜ —Lšœžœžœ˜7šœžœžœžœ&˜ELšœ#˜#—Lšœ žœžœ˜/šœ)˜)Lšœ"žœžœ˜.—L˜Lšžœ ˜Lšœ˜L˜—š  œž œžœ%žœ˜QLšœ)˜)šœžœžœžœ˜BLšœ ˜ —Lšœžœžœ˜7šœžœžœžœ˜4Lšœ˜—Lšœ žœžœ˜-šœ)˜)Lšœ!žœžœ˜-—L˜Lšžœ ˜Lšœ˜L˜—L™ ™šœ'žœ'˜QLšœ˜Lšœ˜Lšœ˜———K˜—L˜—…—J~b‚