SoftcardMonitorImpl.mesa
Copyright Ó 1987 by Xerox Corporation. All rights reserved.
written by Ch. Le Cocq, September 6, 1988
Christian Le Cocq October 31, 1988 4:55:43 pm PST
Christophe Cuenod October 19, 1988 4:48:25 pm PDT
Softcard Debugger.
DIRECTORY
CardTab,
Convert,
IO,
FS,
Process,
Rope,
SoftcardMonitor,
SoftcardMonitorExch,
SparcSoftcardLoaderOps,
SparcSoftcardOps,
SparcSymbols,
SymTab,
ViewerIO;
SoftcardMonitorImpl: CEDAR MONITOR
IMPORTS CardTab, Convert, IO, FS, Process, Rope, SoftcardMonitorExch, SparcSoftcardLoaderOps, SparcSoftcardOps, SparcSymbols, SymTab, ViewerIO
EXPORTS SoftcardMonitor
~ BEGIN
QUIT: CARD32 = SoftcardMonitorExch.QUIT;
SPARCDEAD: CARD32 = 0;
MONTRACE: CARD32 = 8;
MONENTER: CARD32 = MONTRACE+1;
MONDISPLAY: CARD32 = MONENTER+1;
MONFILL: CARD32 = MONDISPLAY+1;
MONOPEN8: CARD32 = MONFILL+1;
MONOPEN16: CARD32 = MONOPEN8+1;
MONOPEN32: CARD32 = MONOPEN16+1;
MONDUMP: CARD32 = MONOPEN32+1;
MONBRK: CARD32 = MONDUMP+1;
MONCALL: CARD32 = MONBRK+1;
firstAvailableCode: CARD32MONCALL+1; --so that it can be looked at with the interpreter
ROPE: TYPE ~ Rope.ROPE;
CommandProcHandle: TYPE ~ REF CommandProcHandleRec;
CommandProcHandleRec: TYPE ~ RECORD[
cmd: ROPE,
doc: ROPE,
proc: SoftcardMonitor.CommandProc
];
CheckTool: PROC ~ {
IF in=NIL THEN GOTO CreateOne;
IF IO.EndOf[in ! IO.Error => GOTO CreateOne] THEN GOTO CreateOne;
EXITS
CreateOne => CreateTool[];
};
CreateTool: PROC ~ {
[in, out] ← ViewerIO.CreateViewerStreams[name: "Puff Monitor"];
TRUSTED {
monitorProcess ← FORK DoMonitor[];
Process.Detach[monitorProcess];
};
};
nestingRope: ROPE ← "~";
prompt: ROPE ← "> ";
PutPrompt: PROC ~ {
IO.PutF[out, "%l%g%l", IO.rope["b"], IO.rope[prompt], IO.rope["B"]];
};
DoMonitor: PROC ~ {
Description of the procedure.
state: SoftcardMonitor.State ← NEW[SoftcardMonitor.StateRec];
DO
quit: BOOLEANFALSE;
WaitForMonitorStart[];
UNTIL quit DO
found: BOOLEAN;
val: SymTab.Val;
cmdLine: ROPE ;
args: SoftcardMonitor.Arguments;
PutPrompt[];
cmdLine ← IO.GetLineRope[in];
args ← ParseToTokens[cmdLine];
IF args#NIL THEN {
[found, val] ← SymTab.Fetch[cmdTable, args[0]];
IF found THEN {
ENABLE Convert.Error => {IO.PutRope[out, "Invalid number\n"]; CONTINUE};
proc: SoftcardMonitor.CommandProc ← NARROW[val, CommandProcHandle].proc;
quit ← proc[args, in, out, state];
}
ELSE IO.PutF[out, "*** cmd ""%g"" unknown\n", IO.rope[args[0]]];
};
ENDLOOP;
IO.PutF[out, "%l%gmonitor exited\n%l", IO.rope["b"], IO.rope[prompt], IO.rope["B"]];
prompt ← Rope.Substr[base: prompt, start: Rope.Length[nestingRope]];
DisableMonitor[];
ENDLOOP;
};
ActionDisplay: SoftcardMonitorExch.ActionProc ~ {
i: CARD32 ← 0;
IF data1=0 AND data2=0 THEN {
ReleaseLock[];
RETURN;
};
CheckTool[];
IO.PutF[out, "%l", IO.char['f]];
WHILE r.length>i DO
modulo: NAT ← 0;
lineSize: CARD32MIN[16, r.length-i];
letters: ROPE ← Rope.FromRefText[r, i, lineSize];
IO.PutF[out, "%8x: ", IO.card[data1]];
FOR j: CARD32 IN [i..i+lineSize) DO
IO.PutF[out, "%02x", IO.card[ORD[r[j]]]];
modulo ← modulo+1;
IF modulo=4 THEN {
IO.PutRope[out, " "];
modulo ← 0;
};
ENDLOOP;
FOR j: CARD32 IN [i+lineSize..i+16) DO
IO.PutRope[out, " "];
modulo ← modulo+1;
IF modulo=4 THEN {
IO.PutRope[out, " "];
modulo ← 0;
};
ENDLOOP;
IO.PutF[out, "\t%g\n", IO.rope[letters]];
data1 ← data1+16;
i ← i+16;
ENDLOOP;
IO.PutF[out, "%l", IO.char['F]];
};
ActionDump: SoftcardMonitorExch.ActionProc ~ {
i: CARD32 ← 0;
ireg: NAT ← 0;
CheckTool[];
IO.PutF[out, "%l", IO.rope["f"]];
WHILE r.length>i DO
lineSize: CARD32MIN[4, r.length-i];
IO.PutF[out, "r%02d: ", IO.card[ireg]];
FOR j: CARD32 IN [i..i+lineSize) DO
IO.PutF[out, "%02x", IO.card[ORD[r[j]]]];
ENDLOOP;
i ← i+lineSize;
IF (i MOD 16) =0 THEN IO.PutChar[out, '\n] ELSE IO.PutChar[out, ' ];
ireg ← ireg+1;
ENDLOOP;
IO.PutF[out, "%l", IO.rope["F"]];
ReleaseLock[];
};
ActionTrace: SoftcardMonitorExch.ActionProc ~ {
CheckTool[];
IO.PutF[out, "%8xH, %8xH\n", IO.card[data1], IO.card[data2]];
};
ActionEnter: SoftcardMonitorExch.ActionProc ~ {
CheckTool[];
SELECT data1 FROM
0 => IO.PutF[out, "\n***** UNEXPECTED TRAP # %d *****\n\n", IO.card[data2]];
1 => IO.PutF[out, "\n***** UNCAUGHT ERROR *****\n\n"];
ENDCASE => IO.PutF[out, "\n***** BREAKPOINT # %x *****\n\n", IO.card[data2]];
prompt ← Rope.Concat[nestingRope, prompt];
IF monitorlevel#0 THEN PutPrompt[];
ReleaseLock[];
EnableMonitor[];
};
ActionCall: SoftcardMonitorExch.ActionProc ~ {
CheckTool[];
IO.PutF[out, "returns : %8xH\n", IO.card[data2]];
ReleaseLock[];
};
ActionBrk: SoftcardMonitorExch.ActionProc ~ {
IF data2#0 THEN [] ← CardTab.Insert[brktable, data1, NEW[CARD ← data2]];
};
ActionDead: SoftcardMonitorExch.ActionProc ~ {
CheckTool[];
IO.PutRope[out, "\n***** INTERNAL SPARC ERROR *****\n\n"];
};
Register: PUBLIC PROC [cmd, doc: ROPE, proc: SoftcardMonitor.CommandProc] ~ {
cmdH: CommandProcHandle ← NEW[CommandProcHandleRec ← [cmd, doc, proc]];
[] ← SymTab.Store[cmdTable, cmd, cmdH];
};
Utilities
waitForAnswer: BOOLEANFALSE;
answerReceived: CONDITION;
ReleaseLock: ENTRY PROC ~ {
ENABLE UNWIND => NULL;
waitForAnswer ← FALSE;
BROADCAST answerReceived;
};
WaitForLock: ENTRY PROC ~ {
ENABLE UNWIND => NULL;
WHILE waitForAnswer DO
WAIT answerReceived
ENDLOOP;
};
waitForMonitor: BOOLEANTRUE;
monitorReady: CONDITION;
monitorlevel: NAT ← 0;
DisableMonitor: ENTRY PROC ~ {
ENABLE UNWIND => NULL;
monitorlevel ← monitorlevel-1;
IF monitorlevel=0 THEN waitForMonitor ← TRUE;
};
EnableMonitor: ENTRY PROC ~ {
ENABLE UNWIND => NULL;
monitorlevel ← monitorlevel+1;
waitForMonitor ← FALSE;
BROADCAST monitorReady;
};
WaitForMonitorStart: ENTRY PROC ~ {
ENABLE UNWIND => NULL;
WHILE waitForMonitor DO
WAIT monitorReady
ENDLOOP;
};
ParseToTokens: PROC [line: ROPE] RETURNS [args: SoftcardMonitor.Arguments] ~ {
ris: IO.STREAMIO.RIS[line];
argc: NAT ← 0;
aList: LIST OF ROPENIL;
{UNTIL IO.EndOf[ris] DO
aList ← CONS[IO.GetTokenRope[ris, IO.IDProc ! IO.EndOfStream => GOTO Exit].token, aList];
argc ← argc+1;
ENDLOOP;
EXITS Exit => {};
};
IF argc=0 THEN RETURN;
args ← NEW[SoftcardMonitor.ArgumentsRec[argc]];
FOR i: NAT DECREASING IN [0..argc) DO
args[i] ← aList.first;
aList ← aList.rest;
ENDLOOP;
};
UnixCardFromRope: PROC [r: ROPE] RETURNS [c: CARD] ~ {
IF Rope.Length[r]=1 THEN RETURN[0];
c ← SELECT Rope.Fetch[r, 1] FROM
'x => Convert.CardFromRope[Rope.Substr[base: r, start: 2], 16], -- skip the `0x' part
ENDCASE => Convert.CardFromRope[r, 8];
};
CardFromRope: PROC [r: ROPE, state: SoftcardMonitor.State] RETURNS [c: CARD ← 0] ~ {
c ← SELECT Rope.Fetch[r, 0] FROM
'0 => UnixCardFromRope[r],
'* => state.here,
ENDCASE => Convert.CardFromWholeNumberLiteral[r];
};
PutByteInBuf: PROC [val: CARD32, r: REF TEXT, start: NAT] ~ {
c: [0..100h); --Don't ask me why the compiler asks for an intermediate range variable
r.length ← r.length+1;
c ← val;
r[start] ← VAL[c];
};
PutWordInBuf: PROC [val: CARD32, r: REF TEXT, start: NAT] ~ {
c: [0..100h); --Don't ask me why the compiler asks for an intermediate range variable
r.length ← r.length+2;
c ← val/100h;
r[start] ← VAL[c];
c ← val-100h*c;
r[start+1] ← VAL[c];
};
PutLongInBuf: PROC [val: CARD32, r: REF TEXT, start: CARD32] ~ {
c: [0..100h); --Don't ask me why the compiler asks for an intermediate range variable
r.length ← r.length+4;
c ← val/1000000h;
r[start] ← VAL[c];
val ← val-1000000h*c;
c ← val/10000h;
r[start+1] ← VAL[c];
val ← val-10000h*c;
c ← val/100h;
r[start+2] ← VAL[c];
val ← val-100h*c;
c ← val;
r[start+3] ← VAL[c];
};
FillSymbols: PROC ~ {
s: IO.STREAMNIL;
name: ROPE;
IO.PutRope[out, "Enter file name : "];
name ← IO.GetLineRope[in];
s ← FS.StreamOpen[name ! FS.Error => {
IO.PutF[out, "***** %g\n", IO.rope[error.explanation]];
CONTINUE;
}];
IF s#NIL THEN symbols ← SparcSymbols.GetSymbols[s];
};
savedInputFile: IO.STREAMNIL;
ResetMonitor: PUBLIC PROC [inputFile: IO.STREAMNIL] ~ {
FOR i: NAT IN [0..monitorlevel) DO
prompt ← Rope.Substr[base: prompt, start: Rope.Length[nestingRope]];
ENDLOOP;
monitorlevel ← 0;
waitForMonitor ← TRUE;
waitForAnswer ← FALSE;
IF monitorProcess#NIL THEN TRUSTED {
Process.Abort[monitorProcess
! Process.InvalidProcess => CONTINUE];
monitorProcess ← NIL;
};
IF in#NIL THEN IO.Close[in];
in ← NIL;
symbols ← NIL;
savedInputFile ← inputFile;
SoftcardMonitorExch.Restart[];
};
Break: PUBLIC PROC ~ TRUSTED {
SparcSoftcardOps.SetSparcToSparcInt[]
};
Commands
DisplayCmd: SoftcardMonitor.CommandProc ~ {
first: CARD32IF args.argc<2 THEN state.here ELSE CardFromRope[args[1], state];
last: CARD32IF args.argc<3 THEN first+4 ELSE CardFromRope[args[2], state];
waitForAnswer ← TRUE;
state.here ← last;
SoftcardMonitorExch.PutPacket[MONDISPLAY, first, last];
WaitForLock[];
};
DumpCmd: SoftcardMonitor.CommandProc ~ {
addr: CARD32IF args.argc<2 THEN state.here ELSE CardFromRope[args[1], state];
waitForAnswer ← TRUE;
SoftcardMonitorExch.PutPacket[MONDUMP, addr];
WaitForLock[];
};
FillCmd: SoftcardMonitor.CommandProc ~ {
first: CARD32IF args.argc<2 THEN state.here ELSE CardFromRope[args[1], state];
last: CARD32IF args.argc<3 THEN first+1 ELSE CardFromRope[args[2], state];
val: CARD32IF args.argc<4 THEN 0 ELSE CardFromRope[args[3], state];
format: {b, w, l};
format ← IF args.argc>4 THEN SELECT Rope.Fetch[args[4]] FROM
'b, 'B => b,
'w, 'W => w,
'l, 'L => l,
ENDCASE => b
ELSE SELECT val FROM
IN [0..100h)  => b,
IN [100h..10000h) => w,
ENDCASE => l;
state.here ← last;
IF val# 0 THEN { --beware of the Cedar (weird) byte order...
r: REF TEXTNEW[TEXT[4]];
r.length ← 0;
SELECT format FROM
b => PutByteInBuf[val, r, 0];
w => {
IF first MOD 2#0 THEN {
IO.PutF[out, "%x: invalid 16 bits address\n", IO.card[first]];
RETURN;
};
PutWordInBuf[val, r, 0];
};
ENDCASE => {
IF first MOD 4#0 THEN {
IO.PutF[out, "%x: invalid 32 bits address\n", IO.card[first]];
RETURN;
};
PutLongInBuf[val, r, 0];
};
SoftcardMonitorExch.PutPacket[MONFILL, first, last, r];
}
ELSE SoftcardMonitorExch.PutPacket[MONFILL, first, last];
};
Open8Cmd: SoftcardMonitor.CommandProc ~ {
add: CARD32IF args.argc<2 THEN state.here ELSE CardFromRope[args[1], state];
val: CARD32IF args.argc<3 THEN 0 ELSE CardFromRope[args[2], state];
SoftcardMonitorExch.PutPacket[MONOPEN8, add, val];
};
Open16Cmd: SoftcardMonitor.CommandProc ~ {
add: CARD32IF args.argc<2 THEN state.here ELSE CardFromRope[args[1], state];
val: CARD32IF args.argc<3 THEN 0 ELSE CardFromRope[args[2], state];
IF add MOD 2#0 THEN IO.PutF[out, "%x: invalid 16 bits address\n", IO.card[add]]
ELSE SoftcardMonitorExch.PutPacket[MONOPEN16, add, val];
};
Open32Cmd: SoftcardMonitor.CommandProc ~ {
add: CARD32IF args.argc<2 THEN state.here ELSE CardFromRope[args[1], state];
val: CARD32IF args.argc<3 THEN 0 ELSE CardFromRope[args[2], state];
IF add MOD 4#0 THEN IO.PutF[out, "%x: invalid 32 bits address\n", IO.card[add]]
ELSE SoftcardMonitorExch.PutPacket[MONOPEN32, add, val];
};
SetBrkCmd: SoftcardMonitor.CommandProc ~ {
add: CARD32IF args.argc<2 THEN state.here ELSE CardFromRope[args[1], state];
IF add MOD 4#0 THEN IO.PutF[out, "%x: invalid 32 bits address\n", IO.card[add]]
ELSE SoftcardMonitorExch.PutPacket[MONBRK, add, 0];
};
ClearBrkCmd: SoftcardMonitor.CommandProc ~ {
add: CARD32IF args.argc<2 THEN state.here ELSE CardFromRope[args[1], state];
IF add MOD 4#0 THEN IO.PutF[out, "%x: invalid 32 bits address\n", IO.card[add]]
ELSE {
found: BOOLEAN;
val: CardTab.Val;
[found, val] ← CardTab.Fetch[brktable, add];
IF found THEN {
SoftcardMonitorExch.PutPacket[MONBRK, add, NARROW[val, REF CARD]^];
[] ← CardTab.Delete[brktable, add];
}
ELSE IO.PutF[out, "%x: no break (known) there\n", IO.card[add]];
};
};
CallCmd: SoftcardMonitor.CommandProc ~ {
nArgs, addr: CARD32;
IF args.argc<2 OR args.argc>7 THEN RETURN;
IF symbols=NIL THEN FillSymbols[];
IF symbols=NIL THEN RETURN;
addr ← SparcSymbols.GetAddress[args[1], symbols];
IF addr=0 THEN {
addr ← SparcSymbols.GetAddress[Rope.Cat["←", args[1]], symbols];
IF addr=0 THEN {IO.PutRope[out, "unknown function\n"]; RETURN}
ELSE IO.PutF[out, "using ←%g instead\n", [rope[args[1]]] ];
};
nArgs ← args.argc-2;
r.length ← 0;
FOR i: CARD32 IN [0..nArgs) DO
PutLongInBuf[CardFromRope[args[i+2], state], r, 4*i];
ENDLOOP;
waitForAnswer ← TRUE;
SoftcardMonitorExch.PutPacket[MONCALL, addr, nArgs, r];
WaitForLock[];
};
ContinueCmd: SoftcardMonitor.CommandProc ~ {
SoftcardMonitorExch.PutPacket[QUIT];
quit ← TRUE;
};
local commands
ListBrkCmd: SoftcardMonitor.CommandProc ~ {
PrintOne: CardTab.EachPairAction ~ {
opcode: CARD32NARROW[val, REF CARD]^;
IO.PutF[out, "\t%8x (%8x)\n", IO.card[key], IO.card[opcode]];
};
[] ← CardTab.Pairs[brktable, PrintOne];
};
HelpCmd: SoftcardMonitor.CommandProc ~ {
PrintOne: SymTab.EachPairAction ~ {
doc: ROPENARROW[val, CommandProcHandle].doc;
IO.PutF[out, "\t%g %g\n", IO.rope[key], IO.rope[doc]];
};
IF args.argc<2 THEN [] ← SymTab.Pairs[cmdTable, PrintOne]
ELSE FOR i: NAT IN [1..args.argc) DO
found: BOOLEAN;
val: SymTab.Val;
[found, val] ← SymTab.Fetch[cmdTable, args[i]];
IF found THEN {
doc: ROPENARROW[val, CommandProcHandle].doc;
IO.PutF[out, "\t%g %g\n", IO.rope[args[i]], IO.rope[doc]];
}
ELSE IO.PutF[out, "%g: unknown\n", IO.rope[args[i]]];
ENDLOOP;
};
TranslateCmd: SoftcardMonitor.CommandProc ~ {
IF symbols=NIL THEN FillSymbols[];
IF symbols#NIL THEN {
addr: CARD32 ← SparcSymbols.GetAddress[args[1], symbols];
IF addr=0 THEN addrSparcSymbols.GetAddress[Rope.Cat["←", args[1]], symbols];
IF addr=0 THEN {
IO.PutRope[out, "unknown symbol"];
RETURN;
}
ELSE {
name: ROPE ← SparcSymbols.GetClosestName[addr, symbols];
IO.PutF[out, "%g : %8xH\n", IO.rope[name], IO.card[addr]];
};
};
};
WhereIsCmd: SoftcardMonitor.CommandProc ~ {
name: ROPE;
addr: CARD32IF args.argc<2 THEN state.here ELSE CardFromRope[args[1], state];
state.here ← addr;
IF symbols=NIL THEN FillSymbols[];
IF symbols#NIL THEN {
name ← SparcSymbols.GetClosestName[addr, symbols];
addr ← SparcSymbols.GetAddress[name, symbols];
IO.PutF[out, "%g : %8xH\n", IO.rope[name], IO.card[addr]];
};
};
r: REF TEXTNEW[TEXT[2048]];
in, out: IO.STREAM;
monitorProcess: PROCESSNIL;
cmdTable: SymTab.Ref ← SymTab.Create[];
brktable: CardTab.Ref ← CardTab.Create[];
symbols: SparcSymbols.Tables ← NIL;
Register["h", "cmd1 cmd2 ...: prints doc on commands", HelpCmd];
Register["?", "cmd1 cmd2 ...: prints doc on commands", HelpCmd];
Register["v", "firstAdd lastAdd : displays memory", DisplayCmd];
Register["d", " : dumps register contents", DumpCmd];
Register["f", "firstAdd lastAdd [val 𡤀] [format]: fills memory with val; \n\tuses byte word(16) or long (32) chunks depending on format if specified or val size otherwise", FillCmd];
Register["o", "add [val 𡤀] : puts byte val at add", Open8Cmd];
Register["e", "add [val 𡤀] : puts short val at add", Open16Cmd];
Register["l", "add [val 𡤀] : puts long val at add", Open32Cmd];
Register["c", "gives the control back to the Sparc", ContinueCmd];
Register["cb", "add : clears the breakpoint at add", ClearBrkCmd];
Register["sb", "add : sets a breakpoint at add", SetBrkCmd];
Register["lb", " : lists all breakpoints", ListBrkCmd];
Register["tr", "name: translates a name to hexa", TranslateCmd];
Register["whereis", "add: finds the closest ext name to such add", WhereIsCmd];
Register["call", "name arg0 ...): calls the function(5 32b args max)", CallCmd];
SoftcardMonitorExch.Register[SPARCDEAD, ActionDead, NIL];
SoftcardMonitorExch.Register[MONTRACE, ActionTrace, NIL];
SoftcardMonitorExch.Register[MONENTER, ActionEnter, NIL];
SoftcardMonitorExch.Register[MONDISPLAY, ActionDisplay, r];
SoftcardMonitorExch.Register[MONDUMP, ActionDump, r];
SoftcardMonitorExch.Register[MONBRK, ActionBrk, NIL];
SoftcardMonitorExch.Register[MONCALL, ActionCall, NIL];
SparcSoftcardLoaderOps.RegisterStartProc[$SparcMonitor, ResetMonitor];
END.