-- IDebug.Mesa Edited by: Bruce on July 9, 1980 10:34 PM
DIRECTORY
BcplOps: FROM "BcplOps" USING [BcplJSR],
CommandList: FROM "commandlist",
Commands: FROM "commands" USING [WriteError, Prompt],
ControlDefs: FROM "controldefs" USING [
ControlLink, FieldDescriptor, FrameHandle, GlobalFrameHandle,
NullFrame, StateVector],
CoreSwapDefs: FROM "coreswapdefs" USING [
BBHandle, CallDP, DebugParameter, ExternalStateVector, StartDP,
SwapReason, SVPointer, UBBPointer, UserBreakBlock, VersionID],
DebugOps: FROM "debugops" USING [Abort, Proceed, Quit],
DOutput: FROM "doutput" USING [Char, EOL, Line, Octal, Text],
FrameDefs: FROM "framedefs" USING [LockCode, UnlockCode],
FrameOps: FROM "frameops" USING [
GetReturnFrame, GetReturnLink, MyLocalFrame, SetReturnFrame,
SetReturnLink],
ImageDefs: FROM "imagedefs" USING [AbortMesa, StopMesa, UserCleanupProc],
Internal: FROM "internal",
KeyDefs: FROM "keydefs" USING [Keys],
LoadStateOps: FROM "loadstateops" USING [state],
MachineDefs: FROM "machinedefs" USING [BYTE, FHandle, FSHandle, GFHandle],
Mopcodes: FROM "mopcodes" USING [zRFS],
Nub: FROM "nub" USING [BadFile, BadVersion],
ProcessDefs: FROM "processdefs" USING [DisableInterrupts, EnableInterrupts],
SDDefs: FROM "sddefs" USING [sBreakBlock, sCallDebugger, sCoreSwap, SD],
SegmentDefs: FROM "segmentdefs" USING [GetFileSegmentDA],
State: FROM "state" USING [GetGS, GSHandle],
SwapperOps: FROM "SwapperOps" USING [systemTable],
TajoOps: FROM "TajoOps" USING [Notifier],
TrapDefs: FROM "trapdefs" USING [ParityError, PhantomParityError];
IDebug: PROGRAM
IMPORTS BcplOps, Commands, DebugOps, DOutput, FrameDefs, FrameOps,
ImageDefs, LoadStateOps, Nub, ProcessDefs, SegmentDefs,
State, SwapperOps, TajoOps, TrapDefs
EXPORTS CoreSwapDefs, Internal, Nub =
BEGIN OPEN CoreSwapDefs;
Error: PUBLIC TYPE = CommandList.Error;
FHandle: TYPE = MachineDefs.FHandle;
badFrame: PUBLIC FHandle ← NIL;
level: CARDINAL ← 1;
data: State.GSHandle ← State.GetGS[];
IncLevel: PROCEDURE =
BEGIN
data.nubLevel ← level ← level + 1;
data.inNub ← level > 1;
END;
DecLevel: PROCEDURE =
BEGIN
data.nubLevel ← level ← level - 1;
data.inNub ← level > 1;
END;
DebugCommand: PUBLIC PROCEDURE =
BEGIN OPEN Commands;
IncLevel[];
DO
BEGIN
Commands.Prompt[];
TajoOps.Notifier[FALSE !
UNWIND => DecLevel[];
ABORTED => CONTINUE;
DebugOps.Abort => CONTINUE;
Nub.BadFile =>
BEGIN
WriteError[file];
DOutput.Text[file];
CONTINUE
END;
Nub.BadVersion --[badname: STRING] --=>
BEGIN
WriteError[file];
DOutput.Text[badname];
WriteError[diffver,FALSE];
RESUME
END;
DebugOps.Quit =>
BEGIN
IF level # 1 THEN GOTO abort;
WriteError[exit, FALSE];
--fix this to get confirm[];
ImageDefs.StopMesa[]
END;
DebugOps.Proceed => EXIT];
EXITS
abort =>
BEGIN
DecLevel[];
SIGNAL DebugOps.Abort;
END;
END;
ENDLOOP;
DecLevel[];
RETURN
END;
ProcessBreakpoint: PUBLIC PROCEDURE [s: SVPointer] =
BEGIN -- called by BRK trap handler in resident code
inst: MachineDefs.BYTE;
swap: BOOLEAN;
[inst, swap] ← DoBreakpoint[s];
IF swap THEN
BEGIN
FrameDefs.LockCode[s.dest];
CoreSwap[breakpoint, s];
FrameDefs.UnlockCode[s.dest];
END
ELSE s.instbyte ← inst; --replant the instruction and go on
RETURN
END;
DoBreakpoint: PROCEDURE [s: SVPointer] RETURNS [MachineDefs.BYTE, BOOLEAN] =
BEGIN OPEN SDDefs;
ubb: UBBPointer;
bba: BBHandle = SD[sBreakBlock];
i: CARDINAL;
l: FHandle ← s.dest;
FOR i IN [0..bba.length) DO
ubb ← @bba.blocks[i];
IF ubb.frame = l.accesslink AND ubb.pc = l.pc THEN
IF TrueCondition[ubb, s.source] THEN EXIT
ELSE RETURN[ubb.inst, FALSE];
ENDLOOP;
RETURN[0, TRUE];
END;
TrueCondition: PROCEDURE [ubb: UBBPointer, base: FHandle] RETURNS [BOOLEAN] =
BEGIN --decide whether to take the breakpoint
fd: ControlDefs.FieldDescriptor;
left, right: UNSPECIFIED;
IF ubb.counterL THEN
IF (ubb.ptrL ← ubb.ptrL + 1) = ubb.ptrR THEN
BEGIN ubb.ptrL ← LOOPHOLE[0]; RETURN[TRUE]; END
ELSE RETURN[FALSE];
fd ← [offset: 0, posn: ubb.posnL, size: ubb.sizeL];
left ← IF ~ubb.localL THEN ReadField[ubb.ptrL, fd]
ELSE ReadField[(base + LOOPHOLE[ubb.ptrL, CARDINAL]), fd];
IF ~ubb.immediateR THEN
BEGIN
fd ← [offset: 0, posn: ubb.posnR, size: ubb.sizeR];
right ← IF ~ubb.localR THEN ReadField[ubb.ptrR, fd]
ELSE ReadField[(base + LOOPHOLE[ubb.ptrR, CARDINAL]), fd];
END
ELSE right ← ubb.ptrR;
RETURN[SELECT ubb.relation FROM
lt => left < right,
gt => left > right,
eq => left = right,
ne => left # right,
le => left <= right,
ge => left >= right,
ENDCASE => FALSE]
END;
ReadField: PROCEDURE [POINTER, ControlDefs.FieldDescriptor] RETURNS [UNSPECIFIED] =
MACHINE CODE BEGIN Mopcodes.zRFS END;
NumberBlocks: CARDINAL = 5;
SwatBreak: PUBLIC PROCEDURE [s: SVPointer] =
BEGIN OPEN ControlDefs, BcplOps;
break: RECORD[a,b: WORD];
break ← [77400B, 1400B];
s.instbyte ← BcplJSR[JSR, @break, 0];
RETURN
END;
Interrupt: PUBLIC PROCEDURE =
BEGIN -- called by BRK trap handler in resident code
state: ControlDefs.StateVector;
state ← STATE;
state.dest ← FrameOps.MyLocalFrame[];
CoreSwap[breakpoint, @state];
END;
Catcher: PUBLIC PROCEDURE [msg, signal: UNSPECIFIED, f: FHandle] =
BEGIN OPEN ControlDefs;
SignallerGF: GlobalFrameHandle;
state: StateVector;
frame: FrameHandle;
SignallerGF ← FrameOps.GetReturnFrame[].accesslink;
state.stk[0] ← msg;
state.stk[1] ← signal;
state.stkptr ← 0;
-- the call stack below here is: Signaller, [Signaller,] offender
state.dest ← frame ← FrameOps.GetReturnFrame[].returnlink.frame;
IF frame.accesslink = SignallerGF THEN state.dest ← frame.returnlink;
BEGIN
CoreSwap[uncaughtsignal, @state
! DebugOps.Abort => GOTO Abort];
EXITS
Abort =>
IF signal = ABORTED THEN {BackStop[f]; ERROR KillThisTurkey} ELSE ERROR ABORTED;
END;
RETURN
END;
BackStop: PUBLIC PROCEDURE [root: FHandle] =
BEGIN OPEN FrameOps;
endProcess: ControlDefs.ControlLink ← root.returnlink;
caller: PROCEDURE = LOOPHOLE[GetReturnLink[]];
root.returnlink ← LOOPHOLE[MyLocalFrame[]];
SetReturnFrame[ControlDefs.NullFrame];
caller[ ! KillThisTurkey => CONTINUE];
SetReturnLink[endProcess];
RETURN
END;
KillThisTurkey: SIGNAL = CODE;
CallTheDebugger: PROCEDURE [s: STRING] =
BEGIN -- user's entry point to debugger
state: ControlDefs.StateVector;
filler0, filler1: CARDINAL;
state ← STATE;
state.stk[0] ← s;
state.stkptr ← 1;
state.dest ← FrameOps.GetReturnLink[];
CoreSwap[explicitcall, @state];
IF FALSE THEN filler0 ← filler1 ← 0;
RETURN
END;
-- The non-Swapping information handlers
ShowBreak: PUBLIC PROCEDURE [s: SVPointer] =
BEGIN
DOutput.EOL[];
DOutput.Text["*** interrupt *** "L];
DOutput.Char['[];
DOutput.Octal[badFrame ← FrameOps.MyLocalFrame[]];
DOutput.Char[']];
DebugCommand[];
END;
ShowInterrupt: PUBLIC PROCEDURE =
BEGIN
RETURN
END;
ShowSignal: PUBLIC PROCEDURE [msg, signal: UNSPECIFIED, f: FHandle] =
BEGIN OPEN DOutput;
DOutput.EOL[];
SELECT signal FROM
TrapDefs.PhantomParityError, TrapDefs.ParityError =>
BEGIN
IF signal = TrapDefs.PhantomParityError THEN Text["Phantom "L];
Text["Parity Error"L];
IF signal = TrapDefs.ParityError THEN
BEGIN
Text[" at "L];
Octal[msg];
END;
Line[" ... Proceeding! "L];
RETURN;
END;
ENDCASE;
Text["*** uncaught SIGNAL "L]; Octal[signal];
Text[", msg = "L]; Octal[msg];
Char[' ]; Char['[];
Octal[badFrame ← FrameOps.MyLocalFrame[]];
Char[']];
DebugCommand[];
END;
GetDebuggerNub: PUBLIC PROCEDURE = {badFrame ← NIL; DebugCommand[]};
PauseAtDebuggerNub: PUBLIC PROCEDURE [STRING] =
BEGIN OPEN SDDefs;
BEGIN ENABLE UNWIND => SD[sCallDebugger] ← PauseAtDebuggerNub;
SD[sCallDebugger] ← CallTheDebugger;
DebugCommand[];
SD[sCallDebugger] ← PauseAtDebuggerNub;
END;
END;
-- The core swapper
Quit: SIGNAL = CODE;
parmstring: STRING ← [40];
CoreSwap: PUBLIC PROCEDURE [why: SwapReason, sp: SVPointer] =
BEGIN OPEN BcplOps;
e: ExternalStateVector;
seg: MachineDefs.FSHandle ← LoadStateOps.state;
DP: DebugParameter;
decode: PROCEDURE RETURNS [BOOLEAN] =
BEGIN OPEN ControlDefs; -- decode the SwapReason
f: MachineDefs.GFHandle;
lsv: StateVector;
SELECT e.reason FROM
proceed, resume => RETURN[TRUE];
call =>
BEGIN
lsv ← LOOPHOLE[e.parameter, CallDP].sv;
lsv.source ← FrameOps.MyLocalFrame[];
TRANSFER WITH lsv;
lsv ← STATE;
LOOPHOLE[e.parameter, CallDP].sv ← lsv;
why ← return;
END;
start =>
BEGIN
f ← LOOPHOLE[e.parameter, StartDP].frame;
IF ~f.started THEN START LOOPHOLE[f, PROGRAM] ELSE RESTART f;
why ← return;
END;
quit => SIGNAL Quit;
kill => ImageDefs.AbortMesa[];
showscreen =>
BEGIN OPEN KeyDefs;
UNTIL Keys.Spare3 = down OR Keys.FR5 = down DO NULL ENDLOOP;
why ← return;
END;
ENDCASE =>
BEGIN
RETURN [TRUE];
END;
RETURN [FALSE]
END;
-- Body of CoreSwap
e.state ← sp;
e.drumFile ← data.selfFH; -- filehandle for State.selfFP
DP.string ← parmstring;
e.versionident ← CoreSwapDefs.VersionID;
e.parameter ← @DP;
e.tables ← @SwapperOps.systemTable;
e.loadstateCFA.fp ← seg.file.fp;
e.loadstateCFA.fa ← [
page: seg.base, byte: 0, da: SegmentDefs.GetFileSegmentDA[seg]];
e.lspages ← seg.pages;
e.bitmap ← NIL;
e.bitmapPages ← 0;
e.fill ← ALL[0];
DO
e.reason ← why;
ImageDefs.UserCleanupProc[OutLd];
ProcessDefs.DisableInterrupts[];
DoSwap[@e];
ProcessDefs.EnableInterrupts[];
ImageDefs.UserCleanupProc[InLd];
IF decode[ !
ABORTED, DebugOps.Abort => IF e.level>0 THEN {why ← return; CONTINUE};
Quit => GOTO abort] THEN EXIT
REPEAT abort => SIGNAL DebugOps.Abort;
ENDLOOP;
RETURN
END;
Stop: PROCEDURE = BEGIN ImageDefs.StopMesa[] END;
DoSwap: PORT [POINTER TO CoreSwapDefs.ExternalStateVector];
P: TYPE = MACHINE DEPENDENT RECORD [in, out: UNSPECIFIED]; -- PORT
LOOPHOLE[DoSwap,P] ← [in: 0, out: SDDefs.SD[SDDefs.sCoreSwap]];
END.