-- XDIDebug.Mesa Edited by: Bruce on September 2, 1980 11:22 AM DIRECTORY BcplOps: FROM "BcplOps" USING [BcplJSR], CommandList: FROM "commandlist", Commands: FROM "commands" USING [WriteError, Prompt], ControlDefs: FROM "controldefs" USING [ ControlLink, FieldDescriptor, FrameHandle, GlobalFrameHandle, NullFrame], 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, StateVector], 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], TajoMisc USING [SetState]; XDIDebug: PROGRAM IMPORTS BcplOps, Commands, DebugOps, DOutput, FrameDefs, FrameOps, ImageDefs, LoadStateOps, Nub, ProcessDefs, SegmentDefs, State, SwapperOps, TajoOps, TrapDefs, TajoMisc 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 OPEN DOutput; WriteError[file]; Text[badname]; Text[": "L]; Text[reason]; 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 baz: RECORD [a,b: CARDINAL, state: MachineDefs.StateVector]; baz.state ← STATE; baz.state.dest ← FrameOps.MyLocalFrame[]; CoreSwap[breakpoint, @baz.state]; END; Catcher: PUBLIC PROCEDURE [msg, signal: UNSPECIFIED, f: FHandle] = BEGIN OPEN ControlDefs; SignallerGF: GlobalFrameHandle; state: MachineDefs.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: MachineDefs.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[']]; [] ← TajoMisc.SetState[on]; 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[']]; [] ← TajoMisc.SetState[on]; DebugCommand[]; END; GetDebuggerNub: PUBLIC PROC [STRING] = {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: MachineDefs.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.