<<>> <> <> <> <> <> <<>> DIRECTORY Atom, DebuggerFixup, PreDebug, PreDebugPrivate, Rope, RuntimeError, VM; Debugger: CEDAR MONITOR IMPORTS Atom, Rope, RuntimeError, VM EXPORTS PreDebug, DebuggerFixup, PreDebugPrivate = BEGIN OPEN PreDebug; RaiseSignal: PROC [which: SIGANY, rtns: POINTER, args: POINTER] = TRUSTED MACHINE CODE { "XR_RaiseSignal" }; Raise: PUBLIC PROC [signalOrError: SIGANY, args: POINTER] = { RaiseSignal[signalOrError, NIL, args]; }; registration: LIST OF RegRec ¬ NIL; RegRec: TYPE = RECORD [signal: SIGANY, explain: Explainer, data: REF]; RegisterSignalExplainer: PUBLIC PROC [signal: SIGANY, explain: Explainer ¬ NIL, data: REF ¬ NIL] = { registration ¬ CONS[[signal, explain, data], registration] }; RegisterErrorExplainer: PUBLIC PROC [error: ERRANY, explain: Explainer ¬ NIL, data: REF ¬ NIL] = { RegisterSignalExplainer[LOOPHOLE[error], explain, data]; }; Ropeize: PROC [x: REF] RETURNS [Rope.ROPE] = { WITH x SELECT FROM r: Rope.ROPE => RETURN [r]; rt: REF TEXT => RETURN [Rope.FromRefText[rt]]; ENDCASE => RETURN [NIL]; }; Explain: PUBLIC PROC [signalOrError: SIGANY, args: POINTER] RETURNS [Rope.ROPE] = { registerData: Rope.ROPE ¬ NIL; FOR l: LIST OF RegRec ¬ registration, l.rest WHILE l#NIL DO IF l.first.signal=signalOrError THEN { IF l.first.explain#NIL THEN RETURN[l.first.explain[signalOrError, args, l.first.data]]; registerData ¬ Ropeize[l.first.data]; EXIT }; ENDLOOP; SELECT TRUE FROM registerData#NIL => RETURN [registerData]; ENDCASE => RETURN ["unknown error"]; }; <<>> Protect: PUBLIC PROC [inner: PROC, rejectP: PROC [Rope.ROPE] RETURNS [BOOL]] RETURNS [ok: BOOL ¬ TRUE] = { inner[! RuntimeError.UNCAUGHT => TRUSTED { explanation: Rope.ROPE; explanation ¬ Explain[signal, LOOPHOLE[parameters]]; IF rejectP[explanation] THEN REJECT ELSE {ok ¬ FALSE; CONTINUE} }]; }; lastMessage: Rope.ROPE ¬ NIL; IJustToldTheUser: PUBLIC PROC [msg: Rope.ROPE] = { lastMessage ¬ msg }; LastMessage: PUBLIC PROC [] RETURNS [Rope.ROPE] = { RETURN [lastMessage] }; <<>> SystemPutRope: PUBLIC ENTRY PROC [r: Rope.ROPE] = { ENABLE UNWIND => NULL; PutChar: PROC [c: CHAR] RETURNS [] ~ TRUSTED MACHINE CODE { "XR_DebugPutChar" }; FOR i: INT IN [0..Rope.Length[r]) DO PutChar[Rope.Fetch[r, i]] ENDLOOP; }; <<>> MyUncaughtHandler: RuntimeError.UCSProc = { explanation: Rope.ROPE; explanation ¬ Explain[signal, LOOPHOLE[msg]]; IF Rope.Length[explanation]>50 AND Rope.Equal[explanation, LastMessage[]] THEN { explanation ¬ Rope.Replace[base: explanation, start: 40, with: " ... "]; }; SystemPutRope[Rope.Cat["\n*** Uncaught error: ", explanation, "\n"]]; <<--IF oldUncaughtHandler#NIL >> <<--THEN oldUncaughtHandler[msg, signal, frame]>> <<--ELSE {>> IF signal # LOOPHOLE[RuntimeError.Aborted] THEN { Debug[]; <> ERROR ABORTED; }; ExitThread[]; <<--};>> }; Debug: PUBLIC PROC [] = { TryCallDebugger: PROC ~ TRUSTED MACHINE CODE { "XR_CallDebugger" }; DoProcs[start]; TryCallDebugger[]; DoProcs[stop]; }; ExitThread: PUBLIC PROC ~ { Exit: PROC ~ TRUSTED MACHINE CODE { "XR_Exit" }; Exit[] }; RegisterInterest: PUBLIC ENTRY PROC [startDebugging, stopDebugging: DebuggerFixup.InterestProc, data: REF] ~ { interests ¬ CONS[ [startDebugging, stopDebugging, data], interests]; }; DoProcs: PROC [action: {start, stop}] ~ { FOR l: LIST OF Interest ¬ interests, l.rest WHILE l # NIL DO IF action=start THEN l.first.start[l.first.data] ELSE l.first.stop[l.first.data] ENDLOOP; }; interests: LIST OF Interest ¬ NIL; Interest: TYPE = RECORD [start, stop: DebuggerFixup.InterestProc, data: REF]; oldUncaughtHandler: RuntimeError.UCSProc ¬ NIL; Init: PROC [] = { RegisterErrorExplainer[RuntimeError.Aborted, NIL, "Aborted"]; RegisterErrorExplainer[RuntimeError.AbstractionFault, NIL, "ArithmeticFault"]; RegisterErrorExplainer[RuntimeError.ArithmeticFault, NIL, "ArithmeticFault"]; RegisterErrorExplainer[RuntimeError.AssignRefCompositeFault, NIL, "AssignRefCompositeFault"]; RegisterErrorExplainer[RuntimeError.BoundsFault, NIL, "BoundsFault"]; RegisterErrorExplainer[RuntimeError.DivideCheck, NIL, "DivideCheck"]; RegisterErrorExplainer[RuntimeError.LinkageFault, NIL, "LinkageFault"]; RegisterErrorExplainer[RuntimeError.NarrowFault, NIL, "NarrowFault"]; RegisterErrorExplainer[RuntimeError.NarrowRefFault, NIL, "NarrowRefFault"]; RegisterErrorExplainer[RuntimeError.NestedProcFault, NIL, "NestedProcFault"]; RegisterErrorExplainer[RuntimeError.NilFault, NIL, "NilFault"]; RegisterErrorExplainer[RuntimeError.ResumeFault, NIL, "ResumeFault"]; RegisterErrorExplainer[RuntimeError.StackFault, NIL, "StackFault"]; RegisterErrorExplainer[RuntimeError.StartFault, NIL, "StartFault"]; RegisterErrorExplainer[RuntimeError.Uncaught, NIL, "Uncaught"]; RegisterErrorExplainer[RuntimeError.UnnamedError, NIL, "UnnamedError"]; RegisterErrorExplainer[RuntimeError.UnnamedSignal, NIL, "UnnamedSignal"]; RegisterErrorExplainer[RuntimeError.Unwind, NIL, "Unwind"]; RegisterErrorExplainer[RuntimeError.UnwindFault, NIL, "UnwindFault"]; RegisterErrorExplainer[RuntimeError.ZeroDivisor, NIL, "ZeroDivisor"]; RegisterSignalExplainer[RuntimeError.UnboundProcedureFault, NIL, "UnboundProcedureFault"]; RegisterSignalExplainer[RuntimeError.SendMsg, NIL, "SendMsg"]; RegisterErrorExplainer[Atom.NILNotAnAtom, NIL, "NILNotAnAtom"]; RegisterErrorExplainer[Rope.NoRope, NIL, "NoRope"]; RegisterErrorExplainer[Rope.VerifyFailed, NIL, "Rope.VerifyFailed"]; RegisterErrorExplainer[VM.AddressFault, NIL, "VM.AddressFault"]; RegisterErrorExplainer[VM.WriteProtectFault, NIL, "VM.WriteProtectFault"]; IF oldUncaughtHandler=NIL THEN oldUncaughtHandler ¬ RuntimeError.RegisterUncaughtSignalHandler[MyUncaughtHandler]; }; Init[]; END. <<>>