BreakpointTesterImpl.mesa
Copyright Ó 1989, 1990 by Xerox Corporation. All rights reserved.
Peter B. Kessler, April 16, 1990 3:06 pm PDT
Laurie Horton, March 4, 1992 4:02 pm PST
This is just for testing the breakpoint implementation.
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 [];
An address in text space where we can set a breakpoint.
aCleanWellLightedGlobalVariable: INT ← 0;
ACleanWellLightedPlaceForBreakpointsName: Rope.ROPE ~
"�leanWellLightedPlaceForBreakpoints←P60";
ACleanWellLightedPlaceForBreakpoints: Procedure ~ {
localBoolean: BOOLEANFALSE;
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;
};
Null Proc.
TheNullProcedure: Procedure ~ {
RETURN;
};
TheNullProcedureName: Rope.ROPE ~ "←TheNullProcedure←P240";
Break Proc.
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";
global data.
stdout: IO.STREAM;
intRef: REF INTNEW[INT ← 0];
testInt: INT ~ 17;
checkInt: INT ~ 42;
Set/Clear/Hit a breakpoint.
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"];
};
};
Running it.
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"];
}.