-- 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.