<> <> <> <> <> 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[ name: "SPARC", peekContents: FakeCirio.PeekContents, pokeContents: FakeCirio.PokeContents, getProcAddress: FakeCirio.GetProcAddress, getProcDataSegment: NIL, 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[ name: "SPARC", peekContents: FakeCirio.PeekContents, pokeContents: FakeCirio.PokeContents, getProcAddress: FakeCirio.GetProcAddress, getProcDataSegment: NIL, 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"]; }.