PopUpDriver2.mesa
Copyright Ó 1992 by Xerox Corporation. All rights reserved.
Sturgis, March 30, 1990 2:02 pm PST
Linda Howe January 8, 1990 3:14:40 pm PST
Spreitze, July 24, 1992 6:26 pm PDT
Coolidge, June 29, 1990 12:27 pm PDT
Chauser, August 27, 1990 10:34 am PDT
Laurie Horton, May 22, 1991 5:17 pm PDT
Udagawa, February 13, 1991 7:38 pm PST
Willie-s, July 27, 1992 5:59 pm PDT
DIRECTORY
CCTypes USING[CCError, CCErrorCase],
CirioButtons USING[ButtonSet, CreateButtonSet, CreateViewer, GetButtonSize, InstallLabelButton, InstallRule, InstallShowFrameButton, InstallSourceLanguageButton, InstallSourcePositionButton, KillButtonSet, MainActionProc, MoveToY, ViewerControl, InstallCommandButton, InstallWalkStackButton],
CirioBackstop USING[Protect],
CirioTypes USING[CompilerContext],
Commander USING[CommandProc, Register],
CommanderOps USING[ParseToList],
Containers USING[ChildXBound, Create],
Convert USING[Error, RopeFromCard],
DisassembleSPARC,
IO USING[PutF, PutF1, PutRope, rope, STREAM],
LocalCirio USING[AddSearchDirectory, Connection, DoUnderMonitorLock, FlushUnknownFileCache, GetConnection, GetDummyStack, GetStackForSelf, ReleaseConnection, ListSearchDirectory, ClearSearchDirectory],
PFS USING[AbsoluteName, PathFromRope, RopeFromPath],
Process USING[Detach],
Rope USING[Cat, ROPE],
RuntimeError USING[Aborted, RegisterUncaughtSignalHandler, UCSProc],
SourceFileOps,
StackCirio USING[ClearAllBreakPoints, ClearBreakPoint, FormatPrompt, GetBannerForDotOofCurrentFrame, InterpretTextLine, ListBreakPoints, ResetStack, SetBreakPointAtAddress, SetBreakPointAtPosition, ShowQuickSummary, Stack],
WindowSystemInterface USING[GetSelectionContents],
ViewerClasses USING[Viewer];
PopUpDriver2: CEDAR MONITOR
LOCKS d USING d: MyViewerData
IMPORTS CCTypes, CirioButtons, CirioBackstop, Commander, CommanderOps, Convert, Containers, DisassembleSPARC, LocalCirio, IO, PFS, Process, Rope, RuntimeError, SourceFileOps, StackCirio, WindowSystemInterface
= BEGIN
ROPE: TYPE = Rope.ROPE;
CC: TYPE = CirioTypes.CompilerContext;
CCE: ERROR[case: CCTypes.CCErrorCase, msg: ROPE ¬ NIL] ¬ CCTypes.CCError;
Viewer related code
Stolen from RemoteDriver2.mesa
MyViewerData: TYPE = REF MyViewerDataBody;
MyViewerDataBody: TYPE = MONITORED RECORD[
vc: CirioButtons.ViewerControl ¬ NIL,
abortFlag: BOOLEAN ¬ TRUE,
lineH: CARD,
genButtonsY: INTEGER ¬ 0,
genButtonsAreaH: INTEGER ¬ 0,
genButtonsButtonSet: CirioButtons.ButtonSet,
stack: StackCirio.Stack ¬ NIL,
frameLabel: ViewerClasses.Viewer,
stackButtonsY: INTEGER ¬ 0,
stackButtonsAreaH: INTEGER ¬ 0,
stackButtonSet: CirioButtons.ButtonSet,
ruleY: INTEGER ¬ 0,
scriptY: INTEGER ¬ 0,
connection: LocalCirio.Connection,
stopFlag: REF BOOLEAN ¬ NIL
];
InterpDriver: Commander.CommandProc = {
dirs: LIST OF ROPE ¬ CommanderOps.ParseToList[cmd].list;
absDirs: LIST OF ROPE ¬ NIL;
FOR dirs ¬ dirs, dirs.rest WHILE dirs#NIL DO
absDirs ¬ CONS[ PFS.RopeFromPath[ PFS.AbsoluteName[ PFS.PathFromRope[dirs.first]]], absDirs];
ENDLOOP;
lets be sure Cirio is registered as the local debugger
IF cmd.procData.clientData # $Registrationless THEN BEGIN
result: REF ANY; msg: ROPE;
[result, msg] ¬ RegisterCirio[cmd];
IF result = $Failure THEN RETURN[result, msg];
END;
Process.Detach[FORK ForkedInterp[absDirs]];
};
ForkedInterp: PROC [searchDirs: LIST OF ROPE] =
BEGIN
d: MyViewerData ¬ BasicBuildViewer[];
Protected: PROC RETURNS [ROPE] ~ {
d.connection ¬ LocalCirio.GetConnection[["PopUpDriver2", "BreakPointPopUp"], d.vc.out, searchDirs];
open a block to so that unwind catches can close the connection
BEGIN
ENABLE UNWIND => {LocalCirio.ReleaseConnection[d.connection, d.vc.out]};
localStack: StackCirio.Stack ¬ LocalCirio.GetStackForSelf[d.connection, d.vc.out];
d.stack ¬ LocalCirio.GetDummyStack[d.connection, d.vc.out];
IO.PutF1[d.vc.out, "Cirio Of %g\N", IO.rope[StackCirio.GetBannerForDotOofCurrentFrame[localStack, d.vc.out]]];
CirioButtons.MainActionProc[d.vc];
END;
LocalCirio.ReleaseConnection[d.connection, d.vc.out];
RETURN [NIL]};
err: ROPE ¬ CirioBackstop.Protect[Protected, d.vc.out];
IF err#NIL THEN d.vc.out.PutF1["%g\n", [rope[err]] ];
END;
PopUp will be called by Carl (and friends) when the debuggee wants to contact the debugger, i.e. when a breakpoint is reached.
UncaughtSignalPopUp: RuntimeError.UCSProc =
[msg: WORD, signal: SIGNAL ANY RETURNS ANY, frame: POINTER]
(except that at January 9, 1990 11:19:53 am PST the implementation calls with frame = NIL)
BEGIN
I belive the following test will eventually go away, when Carl arranges to turn ABORTED into a proper UNWIND. But for the moment, we have to blow the thread away when we are called for ABORTED. This logic is adapted from /pcedar2.0/Debugger/Debugger.mesa.
IF signal = LOOPHOLE[RuntimeError.Aborted] THEN BlowAwayThread[] ELSE
BEGIN
d: MyViewerData ¬ BasicBuildViewer[];
Protected: PROC RETURNS [ROPE] ~ {
d.connection ¬ LocalCirio.GetConnection[["PopUpDriver2", "BreakPointPopUp"], d.vc.out];
open a block to so that unwind catches can close the connection
BEGIN
ENABLE UNWIND => {LocalCirio.ReleaseConnection[d.connection, d.vc.out]};
d.stack ¬ LocalCirio.GetStackForSelf[d.connection, d.vc.out];
InstallStackDebugButtons[d];
IO.PutF1[d.vc.out, "Cirio Of %g\N", IO.rope[StackCirio.GetBannerForDotOofCurrentFrame[d.stack, d.vc.out]]];
CirioButtons.MainActionProc[d.vc];
END;
LocalCirio.ReleaseConnection[d.connection, d.vc.out];
RETURN [NIL]};
err: ROPE ¬ CirioBackstop.Protect[Protected, d.vc.out];
IF err#NIL THEN d.vc.out.PutF1["%g\n", [rope[err]] ];
IF d.abortFlag THEN ERROR ABORTED;
END;
END;
BlowAwayThread: PROC ~ TRUSTED MACHINE CODE {
"XR𡤎xit"
};
The address of this procedure is supplied to the breakpoint mechanism. Same world break points will call this procedure. The type of this procedure should match the type of CirioThingsImpl.CallDebugger. The behavior should mimick that of CirioThingsImpl.CallDebugger.
BreakPointPopUp: PROCEDURE [key: CARD32] =
BEGIN
d: MyViewerData ¬ BasicBuildViewer[];
Protected: PROC RETURNS [ROPE] ~ {
d.connection ¬ LocalCirio.GetConnection[["PopUpDriver2", "BreakPointPopUp"], d.vc.out];
open a block to so that unwind catches can close the connection
BEGIN
ENABLE UNWIND => {LocalCirio.ReleaseConnection[d.connection, d.vc.out]};
d.stack ¬ LocalCirio.GetStackForSelf[d.connection, d.vc.out];
InstallStackDebugButtons[d];
IO.PutF1[d.vc.out, "Cirio Of %g\N", IO.rope[StackCirio.GetBannerForDotOofCurrentFrame[d.stack, d.vc.out]]];
CirioButtons.MainActionProc[d.vc];
END;
LocalCirio.ReleaseConnection[d.connection, d.vc.out];
RETURN [NIL]};
err: ROPE ¬ CirioBackstop.Protect[Protected, d.vc.out];
IF err#NIL THEN d.vc.out.PutF1["%g\n", [rope[err]] ];
IF d.abortFlag THEN ERROR ABORTED;
END;
BasicBuildViewer: PROC RETURNS[MyViewerData] =
BEGIN
d: MyViewerData ¬ NEW[MyViewerDataBody];
d.lineH ¬ CirioButtons.GetButtonSize["Sample"].h+1;
d.genButtonsY ¬ 1;
d.genButtonsAreaH ¬ d.lineH+1;
d.stackButtonsY ¬ d.genButtonsY+d.genButtonsAreaH+1;
d.stackButtonsAreaH ¬ d.lineH;
d.ruleY ¬ d.stackButtonsY+d.stackButtonsAreaH+1;
d.scriptY ¬ d.ruleY+1;
d.vc ¬ CirioButtons.CreateViewer["Cirio", d.scriptY, FormatPrompt, InterpretTextLine, ShutDown, d];
d.stopFlag ¬ NEW[BOOLEAN¬FALSE];
InstallRules[d];
InstallGeneralButtons[d];
RETURN[d]
END;
Interpret
FormatPrompt: PROC [counter: INT, clientData: REF ANY] RETURNS [ROPE] ~ {
d: MyViewerData ¬ NARROW[clientData];
IF d.stack=NIL THEN RETURN ["can't set the language without a stack"];
RETURN StackCirio.FormatPrompt[d.stack, counter]};
We do not pass a stack to CreateViewer, because the remote tool will be changing stacks from time to time. So we use a call back for interpret line.
InterpretTextLine: PROC[line: ROPE, reports: IO.STREAM, clientData: REF ANY] RETURNS[ROPE] =
BEGIN
d: MyViewerData ¬ NARROW[clientData];
result: ROPE;
interpret: PROC = {result ¬ StackCirio.InterpretTextLine[d.stack, line, reports]};
IF d.stack = NIL THEN
BEGIN
IO.PutRope[reports, "can't interpret without a stack"];
RETURN[NIL]
END
ELSE {LocalCirio.DoUnderMonitorLock[d.connection, interpret]; RETURN[result]};
END;
Rules
InstallRules: PROC[d: MyViewerData] =
BEGIN
ruleButtonSet: CirioButtons.ButtonSet ¬ CirioButtons.CreateButtonSet[d.vc.self, d.vc, 0, d.ruleY, 0, d.lineH, 0];
because we throw this away, no one will do a KillButtonSet, hence it is alright to use d.vc.self as the container.
CirioButtons.MoveToY[ruleButtonSet, d.ruleY];
CirioButtons.InstallRule[ruleButtonSet];
END;
General Buttons
InstallGeneralButtons: PROC[d: MyViewerData] =
BEGIN
genButtonsViewer: ViewerClasses.Viewer ¬ Containers.Create[
info: [parent: d.vc.self, border: FALSE, scrollable: FALSE, wx: 0, wy: d.genButtonsY, ww: d.vc.self.cw, wh: d.genButtonsAreaH] ];
bs: CirioButtons.ButtonSet ¬ d.genButtonsButtonSet ¬ CirioButtons.CreateButtonSet[genButtonsViewer, d.vc, 0, 0, 0, d.lineH, 0];
Containers.ChildXBound[d.vc.self, genButtonsViewer];
[] ¬ CirioButtons.InstallCommandButton[
bs: bs,
name: "SetBreak",
clientData1: d,
choices: LIST[[$SetBreakAtPosition, "set breakpoint at selected source position"], [$SetBreakAtAddr, "set breakpoint at selected address"]],
proc1: SetBreakAction1,
proc2: SetBreakAction2];
[] ¬ CirioButtons.InstallCommandButton[
bs: bs,
name: "ListBreaks",
clientData1: d,
proc2: ListBreaksAction];
[] ¬ CirioButtons.InstallCommandButton[
bs: bs,
name: "ClearBreak(s)",
clientData1: d,
choices: LIST[[$ThisOne, "clear the active break"], [$All, "clear all breaks"], [$All, "clear all breaks"]],
proc2: ClearBreakAction];
[] ¬ CirioButtons.InstallCommandButton[
bs: bs,
name: "AddDir",
clientData1: d,
proc1: AddDirAction1,
proc2: AddDirAction2];
[] ¬ CirioButtons.InstallCommandButton[
bs: bs,
name: "ListDir",
clientData1: d,
proc2: ListDirAction];
[] ← CirioButtons.InstallCommandButton[
bs: bs,
name: "ClearDir",
clientData1: d,
proc2: ClearDirAction];
[] ¬ CirioButtons.InstallCommandButton[
bs: bs,
name: "FlushCache",
clientData1: d,
proc2: FlushCacheAction];
[] ¬ CirioButtons.InstallCommandButton[
bs: bs,
name: "Stop",
clientData1: d,
proc1: StopAction1,
proc2: StopAction2];
END;
SetBreakAction1: PROC[button: ViewerClasses.Viewer, vc: CirioButtons.ViewerControl, key, clientData1: REF ANY] RETURNS [clientData2: REF ANY] ~ {
SELECT key FROM
$SetBreakAtPosition => {
pos: SourceFileOps.Position ~ SourceFileOps.GetSelection[].pos;
RETURN [NEW[SourceFileOps.Position ¬ pos]]};
$SetBreakAtAddr => {
addrope: ROPE ~ WindowSystemInterface.GetSelectionContents[];
RETURN[addrope]};
ENDCASE => ERROR};
SetBreakAction2: PROC[button: ViewerClasses.Viewer, vc: CirioButtons.ViewerControl, key, clientData1, clientData2: REF ANY] =
BEGIN
d: MyViewerData ~ NARROW[clientData1];
SELECT key FROM
$SetBreakAtPosition => {
pos: REF SourceFileOps.Position ~ NARROW[clientData2];
corresp: SourceFileOps.Position ¬ pos­;
set: PROC = {
corresp ¬ StackCirio.SetBreakPointAtPosition[d.stack, pos­, d.vc.out, FALSE]
};
IO.PutRope[d.vc.out, "Setting break ... "];
LocalCirio.DoUnderMonitorLock[d.connection, set];
IF corresp # SourceFileOps.noPosition THEN SourceFileOps.OpenSource["break set", corresp, d.vc.out];
};
$SetBreakAtAddr => {
addrope: ROPE ~ NARROW[clientData2];
addr: CARD;
set: PROC = {
StackCirio.SetBreakPointAtAddress[d.stack, addr, d.vc.out, FALSE];
};
TRUSTED {addr ¬ DisassembleSPARC.CardFromRope[addrope !Convert.Error => {
d.vc.out.PutF["Syntax error (VAL[%g]) at %g --- selection should be an unsigned number in C or Mesa syntax", [integer[reason.ORD]], [integer[index]] ];
GOTO Bail}]};
d.vc.out.PutF1["Setting break at 0x%08x ...", [cardinal[addr]] ];
LocalCirio.DoUnderMonitorLock[d.connection, set];
EXITS Bail => NULL};
ENDCASE => ERROR;
IO.PutRope[d.vc.out, " done.\n"];
END;
ListBreaksAction: PROC[button: ViewerClasses.Viewer, vc: CirioButtons.ViewerControl, key, clientData1, clientData2: REF ANY] =
BEGIN
d: MyViewerData ¬ NARROW[clientData1];
list: PROC = {StackCirio.ListBreakPoints[d.stack, d.vc.out]};
IO.PutRope[d.vc.out, "Listing breaks ... "];
LocalCirio.DoUnderMonitorLock[d.connection, list];
IO.PutRope[d.vc.out, " done.\n"];
END;
ClearBreakAction: PROC[button: ViewerClasses.Viewer, vc: CirioButtons.ViewerControl, key, clientData1, clientData2: REF ANY] =
BEGIN
d: MyViewerData ¬ NARROW[clientData1];
clearAll: BOOLEAN ¬ key = $All;
IF clearAll THEN
BEGIN
clear: PROC = {StackCirio.ClearAllBreakPoints[d.stack, d.vc.out]};
IO.PutRope[d.vc.out, "Clearing all breaks ... "];
LocalCirio.DoUnderMonitorLock[d.connection, clear];
END
ELSE
BEGIN
clear: PROC = {StackCirio.ClearBreakPoint[d.stack, d.vc.out]};
IO.PutRope[d.vc.out, "Clearing break ... "];
LocalCirio.DoUnderMonitorLock[d.connection, clear];
END;
IO.PutRope[d.vc.out, " done.\n"];
END;
AddDirAction1: PROC[button: ViewerClasses.Viewer, vc: CirioButtons.ViewerControl, key, clientData1: REF ANY] RETURNS[clientData2: REF ANY] =
BEGIN
rope: ROPE ¬ WindowSystemInterface.GetSelectionContents[];
IF rope = NIL THEN RETURN[NIL] ELSE
RETURN[NEW[RopeHolder ¬ rope]];
END;
RopeHolder: TYPE = ROPE;
AddDirAction2: PROC[button: ViewerClasses.Viewer, vc: CirioButtons.ViewerControl, key, clientData1, clientData2: REF ANY] =
BEGIN
d: MyViewerData ¬ NARROW[clientData1];
ropeHolder: REF RopeHolder ¬ NARROW[clientData2];
dirPath: ROPE ¬ IF ropeHolder = NIL THEN NIL ELSE ropeHolder­;
IO.PutRope[d.vc.out, "Adding search directory ... "];
LocalCirio.AddSearchDirectory[d.connection, dirPath, d.vc.out];
IO.PutRope[d.vc.out, "Added.\n"];
END;
ListDirAction: PROC[button: ViewerClasses.Viewer, vc: CirioButtons.ViewerControl, key, clientData1, clientData2: REF ANY] =
BEGIN
d: MyViewerData ¬ NARROW[clientData1];
IO.PutRope[d.vc.out, "Listing directories ... "];
LocalCirio.ListSearchDirectory[d.connection, d.vc.out];
IO.PutRope[d.vc.out, " done.\n"];
END;
ClearDirAction: PROC[button: ViewerClasses.Viewer, vc: CirioButtons.ViewerControl, key, clientData1, clientData2: REF ANY] =
BEGIN
d: MyViewerData ¬ NARROW[clientData1];
LocalCirio.ClearSearchDirectory[d.connection, d.vc.out];
END;
FlushCacheAction: PROC[button: ViewerClasses.Viewer, vc: CirioButtons.ViewerControl, key, clientData1, clientData2: REF ANY] =
BEGIN
d: MyViewerData ¬ NARROW[clientData1];
IO.PutRope[d.vc.out, "Flushing unknown file cache ..."];
LocalCirio.FlushUnknownFileCache[d.connection, d.vc.out];
IO.PutRope[d.vc.out, " done flushing.\n"];
END;
StopAction1: PROC[button: ViewerClasses.Viewer, vc: CirioButtons.ViewerControl, key, clientData1: REF ANY] RETURNS[clientData2: REF ANY] =
BEGIN
d: MyViewerData ¬ NARROW[clientData1];
d.stopFlag­ ¬ TRUE;
RETURN[NIL]
END;
StopAction2: PROC[button: ViewerClasses.Viewer, vc: CirioButtons.ViewerControl, key, clientData1, clientData2: REF ANY] =
BEGIN
just a no op to keep CirioButtons happy.
END;
RemoveGeneralButtons: PROC[d: MyViewerData] =
BEGIN
d.genButtonsButtonSet ¬ CirioButtons.KillButtonSet[d.genButtonsButtonSet, FALSE];
END;
Stack debug buttons
InstallStackDebugButtons: PROC[d: MyViewerData] =
BEGIN
subViewer: ViewerClasses.Viewer ¬ Containers.Create[
info: [parent: d.vc.self, border: FALSE, scrollable: FALSE, wx: 0, wy: d.stackButtonsY, ww: d.vc.self.cw, wh: d.stackButtonsAreaH] ];
subBs: CirioButtons.ButtonSet ¬ CirioButtons.CreateButtonSet[subViewer, d.vc, 0, 0, 0, d.lineH, 0];
Containers.ChildXBound[d.vc.self, subViewer];
d.frameLabel ¬ CirioButtons.InstallLabelButton[subBs, Rope.Cat["frame: ", Convert.RopeFromCard[StackCirio.ResetStack[d.stack, d.vc.out]], " "]];
[] ¬ CirioButtons.InstallCommandButton[
bs: subBs,
name: "Summary",
clientData1: d,
choices: LIST[[$FullSummary, "full summary"], [$ShortSummary, "short summary"]],
proc2: SummaryAction];
CirioButtons.InstallWalkStackButton[subBs, d.stack, NIL, d.frameLabel];
CirioButtons.InstallShowFrameButton[subBs, d.stack];
CirioButtons.InstallSourcePositionButton[subBs, d.stack];
[] ¬ CirioButtons.InstallCommandButton[
bs: subBs,
name: "Proceed",
clientData1: d,
proc2: ProceedAction];
[] ¬ CirioButtons.InstallCommandButton[
bs: subBs,
name: "Abort",
clientData1: d,
proc2: AbortAction];
CirioButtons.InstallSourceLanguageButton[subBs, d.stack];
d.stackButtonSet ¬ subBs;
END;
SummaryAction: PROC[button: ViewerClasses.Viewer, vc: CirioButtons.ViewerControl, key, clientData1, clientData2: REF ANY] =
BEGIN
d: MyViewerData ¬ NARROW[clientData1];
show: PROC = {StackCirio.ShowQuickSummary[d.stack, d.stopFlag, d.vc.out, key=$FullSummary]};
d.stopFlag­ ¬ FALSE;
LocalCirio.DoUnderMonitorLock[d.connection, show];
END;
ProceedAction: PROC[button: ViewerClasses.Viewer, vc: CirioButtons.ViewerControl, key, clientData1, clientData2: REF ANY] =
BEGIN
d: MyViewerData ¬ NARROW[clientData1];
d.stopFlag­ ¬ FALSE;
vc.destroyStarted ¬ vc.okToDestroy ¬ TRUE; -- ugh: there should be documentation in the interface that this will indeed initiate the shutdown mechanism
IO.PutRope[vc.out, "proceed\N"];
d.abortFlag ¬ FALSE;
END;
AbortAction: PROC[button: ViewerClasses.Viewer, vc: CirioButtons.ViewerControl, key, clientData1, clientData2: REF ANY] =
BEGIN
d: MyViewerData ¬ NARROW[clientData1];
d.stopFlag­ ¬ FALSE;
vc.destroyStarted ¬ vc.okToDestroy ¬ TRUE; -- ugh: there should be documentation in the interface that this will indeed initiate the shutdown mechanism
IO.PutRope[vc.out, "abort\N"];
d.abortFlag ¬ TRUE; -- actually, this flag should already be true
END;
RemoveStackDebugButtons: PROC[d: MyViewerData] =
BEGIN
d.stackButtonSet ¬ CirioButtons.KillButtonSet[d.stackButtonSet, FALSE];
d.frameLabel ¬ NIL;
END;
misc
ShutDown: PROC[clientData: REF ANY, reports: IO.STREAM] =
BEGIN
d: MyViewerData ¬ NARROW[clientData];
RemoveGeneralButtons[d];
RemoveStackDebugButtons[d];
END;
Registration as uncaught signal handler and breakpoint handler
forLockingOriginalUCS: MyViewerData ¬ NEW[MyViewerDataBody];
originalUCS: RuntimeError.UCSProc ¬ NIL;
RegisterCirio: Commander.CommandProc =
BEGIN
Inner: PROC[d: MyViewerData] =
BEGIN
IF originalUCS = NIL THEN
originalUCS ¬ RuntimeError.RegisterUncaughtSignalHandler[UncaughtSignalPopUp];
END;
Inner[forLockingOriginalUCS];
END;
DeRegisterCirio: Commander.CommandProc =
BEGIN
Inner: PROC[d: MyViewerData] =
BEGIN
IF originalUCS # NIL THEN
BEGIN
[] ¬ RuntimeError.RegisterUncaughtSignalHandler[originalUCS];
originalUCS ¬ NIL;
END;
END;
Inner[forLockingOriginalUCS];
END;
Main code
Commander.Register["Interpreter", InterpDriver, "<search directory>* --- create a local debugger tool"];
Commander.Register["RegistrationlessInterpreter", InterpDriver, "<search directory list>* --- doesn't include RegisterCirio", $Registrationless];
Commander.Register["RegisterCirio", RegisterCirio, " --- to catch uncaught errors"];
Commander.Register["CirioLocal", RegisterCirio, "= RegisterCirio"];
Commander.Register["DeRegisterCirio", DeRegisterCirio];
END..