DIRECTORY Breakpoint, Rope, IO, UnixTime, UnixSysCalls, TargetArchitecture, BreakWorldArchitecture, Shepherd, FakeCirio, SPARCArchitecture, SPARCBreakpoint, Commander, UXIO; BreakpointTesterImpl: CEDAR PROGRAM IMPORTS Breakpoint, IO, UnixSysCalls, BreakWorldArchitecture, Shepherd, FakeCirio, Commander, SPARCArchitecture, UXIO ~ { Procedure: TYPE ~ PROCEDURE [] RETURNS []; aCleanWellLightedGlobalVariable: INT _ 0; ACleanWellLightedPlaceForBreakpointsName: Rope.ROPE ~ "_ACleanWellLightedPlaceForBreakpoints_P60"; ACleanWellLightedPlaceForBreakpoints: Procedure ~ { localBoolean: BOOLEAN _ FALSE; aCleanWellLightedGlobalVariable _ 1; IF NOT localBoolean THEN { aCleanWellLightedGlobalVariable _ aCleanWellLightedGlobalVariable + 2; }; IF localBoolean THEN { aCleanWellLightedGlobalVariable _ aCleanWellLightedGlobalVariable + 4; }; ADirectlyCalledProcedure[]; { indirectlyCalledProcedure: Procedure _ AnIndirectlyCalledProcedure; indirectlyCalledProcedure[]; }; IF aCleanWellLightedGlobalVariable # (1 + 2 + 8 + 16) THEN ERROR; }; ADirectlyCalledProcedure: Procedure ~ { aCleanWellLightedGlobalVariable _ aCleanWellLightedGlobalVariable + 8; }; AnIndirectlyCalledProcedure: Procedure ~ { aCleanWellLightedGlobalVariable _ aCleanWellLightedGlobalVariable + 16; }; TheNullProcedure: Procedure ~ { RETURN; }; TheNullProcedureName: Rope.ROPE ~ "_TheNullProcedure_P240"; TheNullBreakProcedure: Breakpoint.BreakProcedure ~ { RETURN; }; TheNullBreakProcedureName: Rope.ROPE ~ "_TheNullBreakProcedure_P300"; TheMinimalBreakProcedure: Breakpoint.BreakProcedure ~ TRUSTED { intRef: REF INT ~ NARROW[LOOPHOLE[breakData, REF ANY]]; intRef^ _ intRef^ + (checkInt - testInt); RETURN; }; TheMinimalBreakProcedureName: Rope.ROPE ~ "_TheMinimalBreakProcedure_P360"; stdout: IO.STREAM; intRef: REF INT _ NEW[INT _ 0]; testInt: INT ~ 17; checkInt: INT ~ 42; TestSetBreakpoint: PROCEDURE [ address: BreakWorldArchitecture.Address, proc: BreakWorldArchitecture.Address, clientData: CARD32] RETURNS [Breakpoint.Break] ~ { breakWorld: BreakWorldArchitecture.BreakWorld ~ BreakWorldArchitecture.BreakWorldFromBreakWorldAddress[address: address]; break: Breakpoint.Break; IF stdout # NIL THEN { stdout.PutF["Setting break at address 0x%08x (0x%08x), calling 0x%08x ... ", [cardinal[LOOPHOLE[ BreakWorldArchitecture.TargetAddressFromBreakWorldAddress[address: address]]]], [cardinal[LOOPHOLE[ BreakWorldArchitecture.PeekInstruction[pc: address]]]], [cardinal[LOOPHOLE[ BreakWorldArchitecture.TargetAddressFromBreakWorldAddress[address: proc]]]]]; }; break _ Breakpoint.SetBreakpoint[ address: address, clientData: NIL, breakProc: proc, breakData: clientData ! Breakpoint.CantSet => { stdout.PutRope[message]; }]; IF stdout # NIL THEN { stdout.PutF["set. \nPatch PC 0x%08x\n", [cardinal[LOOPHOLE[ BreakWorldArchitecture.TargetAddressFromBreakWorldAddress[ address: Shepherd.CodeAddressFromPatch[ patch: Breakpoint.PatchFromBreak[break: break]]]]]]]; }; RETURN [break]; }; TestClearBreakpoint: PROCEDURE [break: Breakpoint.Break] RETURNS [] ~ { IF stdout # NIL THEN { stdout.PutRope["Clearing ... "]; }; Breakpoint.ClearBreakpoint[break: break ! Breakpoint.CantClear => { stdout.PutRope[message]; }]; IF stdout # NIL THEN { stdout.PutRope["cleared\n"]; }; }; BreakpointFlavorProc: Commander.CommandProc ~ { stdout _ cmd.out; TestBreakpointFlavors[]; }; TestBreakpointFlavors: PROCEDURE [] RETURNS [] ~ { breakWorld: BreakWorldArchitecture.BreakWorld ~ BreakWorldArchitecture.CreateBreakWorld[ peekContents: FakeCirio.PeekContents, pokeContents: FakeCirio.PokeContents, getProcAddress: FakeCirio.GetProcAddress, getPatchArea: FakeCirio.GetPatchArea, monitoredCall: FakeCirio.MonitoredCall, worldAccessData: NIL]; breakpointAddress: BreakWorldArchitecture.Address ~ FakeCirio.GetProcAddress[ breakWorld: breakWorld, procName: ACleanWellLightedPlaceForBreakpointsName]; breakProcedureAddress: BreakWorldArchitecture.Address ~ FakeCirio.GetProcAddress[ breakWorld: breakWorld, procName: TheMinimalBreakProcedureName]; break: Breakpoint.Break _ Breakpoint.nullBreak; { normalAddress: BreakWorldArchitecture.Address ~ BreakWorldArchitecture.AddressFromDisplacement[ address: breakpointAddress, displacement: 01CH]; instruction: TargetArchitecture.Instruction ~ BreakWorldArchitecture.PeekInstruction[ pc: normalAddress]; IF instruction # LOOPHOLE[090102001H] THEN { stdout.PutRope["Normal break, but not mov 0x1, %o0\n"]; ERROR; }; intRef^ _ testInt; break _ TestSetBreakpoint[address: normalAddress, proc: breakProcedureAddress, clientData: LOOPHOLE[intRef]]; ACleanWellLightedPlaceForBreakpoints[]; IF intRef^ = checkInt THEN { stdout.PutF["\t\t\tNormal break seems to work\n"]; } ELSE { stdout.PutF["\t\t\tNormal break DOES NOT WORK: intRef^ = %g\n", [integer[intRef^]]]; ERROR; }; TestClearBreakpoint[break: break]; }; { branchTakenAddress: BreakWorldArchitecture.Address ~ BreakWorldArchitecture.AddressFromDisplacement[ address: breakpointAddress, displacement: 02CH]; instruction: TargetArchitecture.Instruction ~ BreakWorldArchitecture.PeekInstruction[ pc: branchTakenAddress]; IF instruction # LOOPHOLE[012800005H] THEN { stdout.PutRope["Branch (taken) break, but not bne .+0x5\n"]; ERROR; }; intRef^ _ testInt; break _ TestSetBreakpoint[address: branchTakenAddress, proc: breakProcedureAddress, clientData: LOOPHOLE[intRef]]; ACleanWellLightedPlaceForBreakpoints[]; IF intRef^ = checkInt THEN { stdout.PutF["\t\t\tBranch taken break seems to work\n"]; } ELSE { stdout.PutF["\t\t\tBranch taken break DOES NOT WORK: intRef^ = %g\n", [integer[intRef^]]]; ERROR; }; TestClearBreakpoint[break: break]; }; { branchNotTakenAddress: BreakWorldArchitecture.Address ~ BreakWorldArchitecture.AddressFromDisplacement[ address: breakpointAddress, displacement: 048H]; instruction: TargetArchitecture.Instruction ~ BreakWorldArchitecture.PeekInstruction[ pc: branchNotTakenAddress]; IF instruction # LOOPHOLE[002800005H] THEN { stdout.PutRope["Branch not taken break, but not be .+0x5\n"]; ERROR; }; intRef^ _ testInt; break _ TestSetBreakpoint[address: branchNotTakenAddress, proc: breakProcedureAddress, clientData: LOOPHOLE[intRef]]; ACleanWellLightedPlaceForBreakpoints[]; IF intRef^ = checkInt THEN { stdout.PutF["\t\t\tBranch not taken break seems to work\n"]; } ELSE { stdout.PutF["\t\t\tBranch not taken break DOES NOT WORK: intRef^ = %g\n", [integer[intRef^]]]; ERROR; }; TestClearBreakpoint[break: break]; }; { callAddress: BreakWorldArchitecture.Address ~ BreakWorldArchitecture.AddressFromDisplacement[ address: breakpointAddress, displacement: 05CH]; instruction: TargetArchitecture.Instruction ~ BreakWorldArchitecture.PeekInstruction[ pc: callAddress]; IF instruction # LOOPHOLE[040000016H] THEN { stdout.PutRope["Call break, but not call .+0x16\n"]; ERROR; }; intRef^ _ testInt; break _ TestSetBreakpoint[address: callAddress, proc: breakProcedureAddress, clientData: LOOPHOLE[intRef]]; ACleanWellLightedPlaceForBreakpoints[]; IF intRef^ = checkInt THEN { stdout.PutF["\t\t\tCall break seems to work\n"]; } ELSE { stdout.PutF["\t\t\tCall break DOES NOT WORK: intRef^ = %g\n", [integer[intRef^]]]; ERROR; }; TestClearBreakpoint[break: break]; }; { jmplo7Address: BreakWorldArchitecture.Address ~ BreakWorldArchitecture.AddressFromDisplacement[ address: breakpointAddress, displacement: 07CH]; instruction: TargetArchitecture.Instruction ~ BreakWorldArchitecture.PeekInstruction[ pc: jmplo7Address]; IF instruction # LOOPHOLE[09FC04000H] THEN { stdout.PutRope["Jmpl %o7 break, but not jmpl %g1, %o7\n"]; ERROR; }; intRef^ _ testInt; break _ TestSetBreakpoint[address: jmplo7Address, proc: breakProcedureAddress, clientData: LOOPHOLE[intRef]]; ACleanWellLightedPlaceForBreakpoints[]; IF intRef^ = checkInt THEN { stdout.PutF["\t\t\tJmpl %%o7 break seems to work\n"]; } ELSE { stdout.PutF["\t\t\tJmpl %%o7 break DOES NOT WORK: intRef^ = %g\n", [integer[intRef^]]]; ERROR; }; TestClearBreakpoint[break: break]; }; { jmplg0Address: BreakWorldArchitecture.Address ~ BreakWorldArchitecture.AddressFromDisplacement[ address: breakpointAddress, displacement: 0ACH]; instruction: TargetArchitecture.Instruction ~ BreakWorldArchitecture.PeekInstruction[ pc: jmplg0Address]; IF instruction # LOOPHOLE[81C7E008H] THEN { stdout.PutRope["Jmpl %g0 break, but not jmpl %i7+8, %g0\n"]; ERROR; }; intRef^ _ testInt; break _ TestSetBreakpoint[address: jmplg0Address, proc: breakProcedureAddress, clientData: LOOPHOLE[intRef]]; ACleanWellLightedPlaceForBreakpoints[]; IF intRef^ = checkInt THEN { stdout.PutF["\t\t\tJmpl %%g0 break seems to work\n"]; } ELSE { stdout.PutF["\t\t\tJmpl %%g0 break DOES NOT WORK: intRef^ = %g\n", [integer[intRef^]]]; ERROR; }; TestClearBreakpoint[break: break]; }; { intRef^ _ testInt; ACleanWellLightedPlaceForBreakpoints[]; IF intRef^ # testInt THEN { stdout.PutF["\t\t\tclearing DOES NOT WORK: intRef^ = %g\n", [integer[intRef^]]]; ERROR; } ELSE { stdout.PutF["\t\t\tClearing seems to work\n"]; }; }; }; TimeBreakpointProc: Commander.CommandProc ~ { stdout _ cmd.out; TimeBreakpoint[]; }; TimeBreakpoint: PROCEDURE [] RETURNS [] ~ { iterations: NAT ~ 1000000; nullUsec: CARD; maxiRegsUsec: CARD; regsUsec: CARD; miniRegsUsec: CARD; globalRegsUsec: CARD; nullRegsUsec: CARD; normalBreakUsec: CARD; fastBreakUsec: CARD; { nullUsec _ TimeProc[iterations: iterations, proc: TheNullProcedure]; }; { maxiRegsUsec _ TimeProc[iterations: iterations, proc: MaxiSaveRestoreProcedure]; }; { regsUsec _ TimeProc[iterations: iterations, proc: SaveRestoreProcedure]; }; { miniRegsUsec _ TimeProc[iterations: iterations, proc: MiniSaveRestoreProcedure]; }; { globalRegsUsec _ TimeProc[iterations: iterations, proc: GlobalsSaveRestoreProcedure]; }; { nullRegsUsec _ TimeProc[iterations: iterations, proc: NoneSaveRestoreProcedure]; }; { breakWorld: BreakWorldArchitecture.BreakWorld ~ BreakWorldArchitecture.CreateBreakWorld[ peekContents: FakeCirio.PeekContents, pokeContents: FakeCirio.PokeContents, getProcAddress: FakeCirio.GetProcAddress, getPatchArea: FakeCirio.GetPatchArea, monitoredCall: FakeCirio.MonitoredCall, worldAccessData: NIL]; breakpointAddress: BreakWorldArchitecture.Address ~ FakeCirio.GetProcAddress[ breakWorld: breakWorld, procName: TheNullProcedureName]; breakProcedureAddress: BreakWorldArchitecture.Address ~ FakeCirio.GetProcAddress[ breakWorld: breakWorld, procName: TheNullBreakProcedureName]; break: Breakpoint.Break _ Breakpoint.nullBreak; break _ Breakpoint.SetBreakpoint[ address: breakpointAddress, clientData: NIL, breakProc: breakProcedureAddress, breakData: 0]; normalBreakUsec _ TimeProc[iterations: iterations, proc: TheNullProcedure]; Breakpoint.ClearBreakpoint[break: break]; break _ Breakpoint.SetBreakpoint[ address: breakpointAddress, clientData: NIL, breakProc: breakProcedureAddress, breakData: 0, damages: SPARCArchitecture.TargetRegisterClassFromSPARCRegisterClass[ SPARCArchitecture.RegisterClass.globalsAndIns]]; fastBreakUsec _ TimeProc[iterations: iterations, proc: TheNullProcedure]; Breakpoint.ClearBreakpoint[break: break]; }; stdout.PutF["%g null calls takes %g usec %g\n", [integer[iterations]], [cardinal[nullUsec]], [cardinal[nullUsec/iterations]]]; stdout.PutF["%g maxi save/restore registers takes %g usec %g\n", [integer[iterations]], [cardinal[maxiRegsUsec]], [cardinal[maxiRegsUsec/iterations]]]; stdout.PutF["%g regular save/restore registers takes %g usec %g\n", [integer[iterations]], [cardinal[regsUsec]], [cardinal[regsUsec/iterations]]]; stdout.PutF["%g mini save/restore registers takes %g usec %g\n", [integer[iterations]], [cardinal[miniRegsUsec]], [cardinal[miniRegsUsec/iterations]]]; stdout.PutF["%g globals save/restore registers takes %g usec %g\n", [integer[iterations]], [cardinal[globalRegsUsec]], [cardinal[globalRegsUsec/iterations]]]; stdout.PutF["%g null save/restore registers takes %g usec %g\n", [integer[iterations]], [cardinal[nullRegsUsec]], [cardinal[nullRegsUsec/iterations]]]; stdout.PutF["%g normal break calls takes %g usec %g\n", [integer[iterations]], [cardinal[normalBreakUsec]], [cardinal[normalBreakUsec/iterations]]]; stdout.PutF["%g fast break calls takes %g usec %g\n", [integer[iterations]], [cardinal[fastBreakUsec]], [cardinal[fastBreakUsec/iterations]]]; }; TimeProc: PROCEDURE [iterations: NAT, proc: Procedure] RETURNS [CARD] ~ TRUSTED { beforeRep: UnixTime.TimeVal; before: UnixTime.TimeValPtr ~ @beforeRep; afterRep: UnixTime.TimeVal; after: UnixTime.TimeValPtr ~ @afterRep; usec: CARD _ 0; IF UnixSysCalls.GetTimeOfDay[tp: before, tzp: NIL] = failure THEN { stdout.PutRope["couldn't get before time\n"]; }; THROUGH [1..iterations] DO { [] _ proc[]; } ENDLOOP; IF UnixSysCalls.GetTimeOfDay[tp: after, tzp: NIL] = failure THEN { stdout.PutRope["couldn't get after time\n"]; }; usec _ ((1000000 * after.sec) + after.usec) - ((1000000 * before.sec) + before.usec); RETURN [usec]; }; SaveRestoreProcedure: Procedure ~ TRUSTED { SaveArea: TYPE ~ LONG POINTER TO SaveAreaRep _ NIL; SaveAreaRep: TYPE ~ PACKED ARRAY [0 .. SPARCBreakpoint.registerSaveArea) OF BYTE; saveAreaInstance: SaveAreaRep; saveArea: SaveArea ~ @saveAreaInstance; Save: PROCEDURE [saveArea: SaveArea] RETURNS [] ~ TRUSTED MACHINE CODE { "save_regs" }; Restore: PROCEDURE [saveArea: SaveArea] RETURNS [] ~ TRUSTED MACHINE CODE { "restore_regs" }; Save[saveArea: saveArea]; Restore[saveArea: saveArea]; RETURN; }; MiniSaveRestoreProcedure: Procedure ~ TRUSTED { SaveArea: TYPE ~ LONG POINTER TO SaveAreaRep _ NIL; SaveAreaRep: TYPE ~ PACKED ARRAY [0 .. SPARCBreakpoint.registerSaveArea) OF BYTE; saveAreaInstance: SaveAreaRep; saveArea: SaveArea ~ @saveAreaInstance; Save: PROCEDURE [saveArea: SaveArea] RETURNS [] ~ TRUSTED MACHINE CODE { "save_regs_mini" }; Restore: PROCEDURE [saveArea: SaveArea] RETURNS [] ~ TRUSTED MACHINE CODE { "restore_regs_mini" }; Save[saveArea: saveArea]; Restore[saveArea: saveArea]; RETURN; }; MaxiSaveRestoreProcedure: Procedure ~ TRUSTED { SaveArea: TYPE ~ LONG POINTER TO SaveAreaRep _ NIL; SaveAreaRep: TYPE ~ PACKED ARRAY [0 .. SPARCBreakpoint.registerSaveArea) OF BYTE; saveAreaInstance: SaveAreaRep; saveArea: SaveArea ~ @saveAreaInstance; Save: PROCEDURE [saveArea: SaveArea] RETURNS [] ~ TRUSTED MACHINE CODE { "save_regs_maxi" }; Restore: PROCEDURE [saveArea: SaveArea] RETURNS [] ~ TRUSTED MACHINE CODE { "restore_regs_maxi" }; Save[saveArea: saveArea]; Restore[saveArea: saveArea]; RETURN; }; GlobalsSaveRestoreProcedure: Procedure ~ TRUSTED { SaveArea: TYPE ~ LONG POINTER TO SaveAreaRep _ NIL; SaveAreaRep: TYPE ~ PACKED ARRAY [0 .. SPARCBreakpoint.registerSaveArea) OF BYTE; saveAreaInstance: SaveAreaRep; saveArea: SaveArea ~ @saveAreaInstance; Save: PROCEDURE [saveArea: SaveArea] RETURNS [] ~ TRUSTED MACHINE CODE { "save_regs_globals" }; Restore: PROCEDURE [saveArea: SaveArea] RETURNS [] ~ TRUSTED MACHINE CODE { "restore_regs_globals" }; Save[saveArea: saveArea]; Restore[saveArea: saveArea]; RETURN; }; NoneSaveRestoreProcedure: Procedure ~ TRUSTED { SaveArea: TYPE ~ LONG POINTER TO SaveAreaRep _ NIL; SaveAreaRep: TYPE ~ PACKED ARRAY [0 .. SPARCBreakpoint.registerSaveArea) OF BYTE; saveAreaInstance: SaveAreaRep; saveArea: SaveArea ~ @saveAreaInstance; Save: PROCEDURE [saveArea: SaveArea] RETURNS [] ~ TRUSTED MACHINE CODE { "save_regs_none" }; Restore: PROCEDURE [saveArea: SaveArea] RETURNS [] ~ TRUSTED MACHINE CODE { "restore_regs_none" }; Save[saveArea: saveArea]; Restore[saveArea: saveArea]; RETURN; }; PCRSetup: PROCEDURE [] RETURNS [] ~ { stdout _ UXIO.CreateStandardStream[UXIO.Kind.output]; }; Commander.Register[ key: "TimeBreakpoints", proc: TimeBreakpointProc, doc: "time the breakpoint operations"]; Commander.Register[ key: "TestBreakpointFlavors", proc: BreakpointFlavorProc, doc: "test different flavor breakpoints"]; }. LBreakpointTesterImpl.mesa Copyright Σ 1989, 1990 by Xerox Corporation. All rights reserved. Peter B. Kessler, April 16, 1990 3:06 pm PDT This is just for testing the breakpoint implementation. An address in text space where we can set a breakpoint. Null Proc. Break Proc. global data. Set/Clear/Hit a breakpoint. Running it. ΚG•NewlineDelimiter – "cedar" style˜code™K™BKšœ,™,—J˜K™7˜šΟk ˜ K˜ K˜Kšœ˜K˜ K˜ K˜K˜K˜ K˜ K˜K˜K˜ Kšœ˜J˜——šΠlnœœ˜#šœ˜Kšœ œ[˜m—K˜K˜Kšœ œ œœ˜*head™7šœ!œ˜)K˜—šΟn(œœ˜6K• CharProps8PostfixXeroxCharCodes$PostfixXeroxCharCodesšœ,˜,K˜—šŸ$œ˜3Kšœœœ˜K˜Kšœ$˜$šœœœ˜KšœF˜FK˜—šœœ˜KšœF˜FKšœ˜—Kšœ˜˜KšœC˜CK˜Kšœ˜K˜—Kšœ4œœ˜AK˜K˜—šŸœ˜'KšœF˜FK˜J˜—šŸœ˜*KšœG˜GK˜J˜——™ šŸœ˜Kšœ˜K˜K–8#PostfixXeroxCharCodesPostfixXeroxCharCodesšŸœœ˜;J˜——™ šŸœ˜4Kšœ˜K˜K–8(PostfixXeroxCharCodesPostfixXeroxCharCodesšŸœœ!˜EJ˜—šŸœœ˜?Kš œœœœœ œœ˜7K˜Kšœ)˜)Kšœ˜K˜K–8+PostfixXeroxCharCodesPostfixXeroxCharCodesšŸœœ$˜KJ˜——™ šœœœ˜J˜—š œœœœœ˜Jšœ œ˜Jšœ œ˜J˜——™šŸœ œ^œœ˜‘˜0K˜I—K˜K˜šœ œœ˜šœL˜Lšœ œ˜KšœO˜O—šœ œ˜Kšœ7˜7—šœ œ˜KšœM˜M——K˜—˜!Kšœœ(˜I˜K˜K˜——šœ œœ˜šœ3œ˜<šœ:˜:šœ'˜'Kšœ5˜5———K˜—Kšœ ˜K˜J˜—šŸœ œœ˜Gšœ œœ˜K˜ K˜—˜'˜K˜K˜——šœ œœ˜K˜K˜—K˜J˜——™ šŸœ˜/J˜Jšœ˜J˜J˜—šŸœ œœ˜2šœ0˜0šœ(˜(K˜&K˜&K˜*K˜&K˜'Kšœœ˜——˜MK˜L—˜QKšœ@˜@—K˜/J˜˜˜0˜/Kšœ0˜0——šœU˜UKšœ˜—K˜šœœ œ˜,Kšœ8˜8Kšœ˜Kšœ˜—K˜šœ2˜2Kšœ)œ ˜;—K˜'šœ˜šœ˜Kšœ2˜2K˜—šœ˜šœA˜AKšœ˜—Jšœ˜K˜——K˜"K˜—˜˜5šœ/˜/Kšœ0˜0——šœU˜UKšœ˜—K˜šœœ œ˜,Kšœ<˜