StackCirioImpl.mesa
Copyright Ó 1990, 1991, 1992, 1993 by Xerox Corporation. All rights reserved.
Sturgis, March 30, 1990 3:11 pm PST
Last tweaked by Mike Spreitzer on July 23, 1992 2:28 pm PDT
Coolidge, July 27, 1990 9:13:45 am PDT
Philip James, March 17, 1992 2:00 pm PST
Laurie Horton, April 9, 1992 2:19 pm PDT
Udagawa, February 12, 1991 6:59 pm PST
Katsuyuki Komatsu January 23, 1993 3:23 pm PST
Jas, January 5, 1993 7:37 pm PST
DIRECTORY
AmpersandContext USING[StripAMNode],
BreakWorldArchitecture USING [Address, BreakWorld, NewAddress, PeekContents],
CCTypes USING[BreakPrintType, CCError, CCErrorCase, Conforms, CreateCompoundNameScope, GetAnyTargetType, GetNodeType, GetRopeType],
CedarCode USING[GetTypeOfNode, Interpret, ShowCode, ShowNode],
CedarOtherPureTypes USING[CreateIndirectToAnUnknownType, CreateRopeNode, CreateUnknownType],
CedarParseSupport USING[ParseCedarExpression],
CirioBackstop,
CirioBreakAccess USING[BreakWorldFromBreakSet, CirioBreakSet, ClearAllBreaks, ClearBreakAtAbsAddr, ClearBreakAtIndex, ListBreaks, SetBreakAtAbsAddr],
CirioMemory,
CirioNub USING [Error],
CirioNubAccess USING[DbgMsgNone, DbgMsgNoHandlerRequest, DbgMsgHandlerRequest, DbgMsgAbort, DbgMsgBadProceedRequest, DbgMsgBreakRequest, DbgMsgClientRequest, DbgMsgExit, DbgMsgProceed, Error, FileEntry, GetFileEntry, GetInstructionSetAndOperatingSystem, Handle, LookupMatchingSymEntryByName, LookupMatchingSymEntryByValue, LookupSymEntryByID, PCInfo, PCtoInfo, Read32BitsAsCard, RemoteAddrFault, RemoteNilFault, SymEntry],
CirioSyntacticOperations USING[CompileForLHS, CompileForRHS, ParseTree, ShowParseTree],
CirioTargets,
CirioTypes USING[CompilerContext, Node, Type, TypedCode],
Commander,
CommanderOps,
Convert USING[CardFromRope, Error],
CParser USING [MakeCParseTree],
DisassembleSPARC,
FamousPath USING [DirectoryList, Get, SearchList],
Frames USING[CreateIndirectGlobalFrameNode, CreateIndirectGlobalFrameType, IndirectGlobalFrameData, IndirectGlobalFrameTypeData],
FS USING [Error, StreamOpen],
IO,
LoadStateAccess USING[BasicPCInfo, GetRopeListForLoadedFileContainingLoadedModule, GetBasicPCInfo, GetLoadedModuleInfoFromAbsPC, GetRopeForBasicPCInfo, GetRopeListForLoadedModuleInfo, LoadedModuleInfo, LoadStateHandle],
MobAccess USING [MobError],
MorePfsNames,
NewAmpersandProcs USING[Handle, GetHandle],
NewRMTW USING[CedarBreakAddress, CedarModuleSet, CedarSourcePosition, FrameNodeInfo, GetAbsAddressForBreak, GetCedarSourcePosition, GetLoadedModuleInfo, GetModuleScope, GetNodeForCedarFrame, GetRopesForCedarBreakAddress, GetRMTWInfo, LoadedModuleInfo, RawFrameInfo, RemoteMimosaTargetWorld, ShowReportByLevel],
ObjectFiles USING[Module, UnreadableDotO, ModuleBody, FindVersionStamp, UnreadableObjectFile, VersionStampInfo],
OneCasabaParser USING[BuildParserTableFromKipperedStream, ParserTable],
PFS USING [Error, PathFromRope, RopeFromPath],
PFSNames USING [Component, PATH, ShortName],
PPTree USING[Link],
PreDebug,
RCTW USING [CBreakAddress, DescribeCBreakAddress, FrameNodeInfo, GetAbsAddressForBreak, GetFrameNodeInfo, GetSourcePosition, ProcedureFrameInfo, ProcedureFrameInfoBody],
Rope,
RopeParts,
RopeSequence,
RuntimeError USING[ArithmeticFault, BoundsFault, DivideCheck, Uncaught, ZeroDivisor],
SafeStorage USING[NarrowRefFault],
SourceFileOpsExtras USING [FullFormatPosition, noIndex, noPosition, noRange, Position, ShowProc],
StackCirio USING[Language],
StackCirioPrivate,
StructuredStreams,
SystemInterface USING [CirioFile, FileSet, GetCirioFile, GetFileInfo, GetNameOfFile, ShowReport, ShowSource],
UnparserBufferExtras,
UserProfile USING[Number],
VM USING[AddressFault],
WalkCedarParseTrees USING[CreatePPTreeParseTree],
WalkCParseTrees USING [CreatePPTreeParseTree];
StackCirioImpl: CEDAR MONITOR
LOCKS stack USING stack: Stack
IMPORTS AmpersandContext, BreakWorldArchitecture, CCTypes, CedarCode, CedarOtherPureTypes, CedarParseSupport, CirioBreakAccess, CirioMemory, CirioNub, CirioNubAccess, CirioSyntacticOperations, CirioTargets, Commander, CommanderOps, Convert, CParser, DisassembleSPARC, FamousPath, Frames, FS, IO, LoadStateAccess, MobAccess, MorePfsNames, NewAmpersandProcs, NewRMTW, ObjectFiles, OneCasabaParser, PFS, PFSNames, PreDebug, RCTW, Rope, RopeParts, RopeSequence, RuntimeError, SafeStorage, SourceFileOpsExtras, StructuredStreams, SystemInterface, UnparserBufferExtras, UserProfile, VM, WalkCedarParseTrees, WalkCParseTrees
EXPORTS CirioBackstop, StackCirio =
BEGIN OPEN Disa:DisassembleSPARC, DOA:ObjectFiles, LSA:LoadStateAccess, MPN:MorePfsNames, RP:RopeParts, RS:RopeSequence, SS:StructuredStreams, UB:UnparserBufferExtras, StackCirioPrivate;
Debugging aids
DebugFlag: BOOLEANFALSE;
Types
CedarCase: TYPE = {yes, unknown, no};
CCE: ERROR[case: CCTypes.CCErrorCase, msg: ROPENIL] ← CCTypes.CCError;
Stack: TYPE = REF StackBody;
StackBody: PUBLIC TYPE = StackCirioPrivate.StackBody;
Variables
famousPath: FamousPath.DirectoryList ~ FamousPath.Get["Cirio"];
cParseTable: OneCasabaParser.ParserTable ← NIL;
stdMargin: INT ← 60;
debugSS: BOOLFALSE;
Stacks
The caller is responsible for eventually calling CloseStack.
OpenStack: PUBLIC PROC[ampersandContext1: CirioTypes.Node, ampersandContext2: CirioTypes.Node, cc: CC, rmtw: NewRMTW.RemoteMimosaTargetWorld, cedarModules: NewRMTW.CedarModuleSet, nub: CirioNubAccess.Handle, target: CirioTargets.Target, fileSet: SystemInterface.FileSet, breaks: CirioBreakAccess.CirioBreakSet, lsh: LSA.LoadStateHandle, aph: NewAmpersandProcs.Handle, cParserTable: OneCasabaParser.ParserTable, hotFramePC: CARD, hotFrameSP: CARD, skipKFrames: CARD, ShowSource: SourceFileOpsExtras.ShowProc, reports: IO.STREAM] RETURNS[Stack] = TRUSTED
BEGIN
desiredHotFramePC: CARD ← hotFramePC;
desiredHotFrameSP: CARD ← hotFrameSP;
stack: Stack;
loaded module information is needed by the MIPS target routines
loadedModule: REF LSA.LoadedModuleInfo ← NIL;
initLoadedModule: PROC RETURNS[ROPE] ~ TRUSTED {
loadedModule ← LSA.GetLoadedModuleInfoFromAbsPC[lsh, desiredHotFramePC];
RETURN[NIL];
};
MIPSEB: Rope.ROPE ← "MIPSEB";
IRIX: Rope.ROPE ← "IRIX";
instrSet, opSys: Rope.ROPE;
[instrSet, opSys] ← CirioNubAccess.GetInstructionSetAndOperatingSystem[nub];
IF Rope.Equal[instrSet, MIPSEB] AND Rope.Equal[opSys, IRIX] THEN
[] ← Protect[initLoadedModule, NIL];
BEGIN
FOR n: CARD IN [0..skipKFrames) DO
nextHotFramePC: CARD ← CirioNubAccess.Read32BitsAsCard[[nub, desiredHotFrameSP+(15*4), 0, FALSE, TRUE]];
nextHotFrameSP: CARD ← FpFromSp[nub, desiredHotFrameSP
! CirioNubAccess.RemoteAddrFault => GOTO beyondColdestFrame];
desiredHotFrameSPBA: CirioMemory.BitAddr ← CirioMemory.PtrToBa[desiredHotFrameSP];
desiredHotFrameFPBA: CirioMemory.BitAddr ← target.FpFromSp[loadedModule, target, desiredHotFrameSPBA, desiredHotFramePC ! CirioNubAccess.RemoteAddrFault => GOTO beyondColdestFrame];
nextHotFramePCBA: CirioMemory.BitAddr ← target.ReadPc[loadedModule, target, desiredHotFrameSPBA, desiredHotFrameFPBA, desiredHotFramePC];
nextHotFramePC: CARD ← CirioMemory.BaToPtr[nextHotFramePCBA];
nextHotFrameSP: CARD ← CirioMemory.BaToPtr[target.NextSp[loadedModule,target, desiredHotFrameSPBA, desiredHotFrameFPBA, desiredHotFramePC]];
desiredHotFramePC ← nextHotFramePC;
desiredHotFrameSP ← nextHotFrameSP;
ENDLOOP;
EXITS
beyondColdestFrame => ERROR
END;
stack ← NEW[StackBody←[
tsOut: NIL,
ampersandContext1: ampersandContext1,
ampersandContext2: ampersandContext2,
cc: cc,
rmtw: rmtw,
cedarModules: cedarModules,
nub: nub,
target: target,
fileSet: fileSet,
breaks: breaks,
lsh: lsh,
aph: aph,
cParserTable: cParserTable,
dummyNode: NIL,
hotFramePC: desiredHotFramePC,
hotFrameSP: desiredHotFrameSP,
hotFrame: NIL,
currentFrame: NIL,
ShowSource: ShowSource,
desiredLang: Cedar]];
stack.dummyNode ← BuildDummyFrameNode[stack];
RETURN[stack];
END;
OpenDummyStack: PUBLIC PROC[ampersandContext1: CirioTypes.Node, ampersandContext2: CirioTypes.Node, cc: CC, rmtw: NewRMTW.RemoteMimosaTargetWorld, cedarModules: NewRMTW.CedarModuleSet, nub: CirioNubAccess.Handle, target: CirioTargets.Target, fileSet: SystemInterface.FileSet, breaks: CirioBreakAccess.CirioBreakSet, lsh: LSA.LoadStateHandle, aph: NewAmpersandProcs.Handle, cParserTable: OneCasabaParser.ParserTable, ShowSource: SourceFileOpsExtras.ShowProc, reports: IO.STREAM] RETURNS[Stack] =
BEGIN
stack: Stack ← NEW[StackBody←[
tsOut: NIL,
ampersandContext1: ampersandContext1,
ampersandContext2: ampersandContext2,
cc: cc,
rmtw: rmtw,
cedarModules: cedarModules,
nub: nub,
target: target,
fileSet: fileSet,
breaks: breaks,
lsh: lsh,
aph: aph,
cParserTable: cParserTable,
dummyNode: NIL,
hotFramePC: 0,
hotFrameSP: 0,
hotFrame: NIL,
currentFrame: NIL,
ShowSource: ShowSource,
desiredLang: Cedar]];
stack.dummyNode ← BuildDummyFrameNode[stack];
RETURN[stack];
END;
ShowQuickSummary: PUBLIC ENTRY PROC[stack: Stack, stopFlag: REF BOOLEAN, on: IO.STREAM, long: BOOL] =
BEGIN
ENABLE UNWIND => NULL;
hFrame: CARD;
cFrame: CARD;
startFrame: BasicFrameInfo;
FindHotFrame[stack, stopFlag, on, long];
hFrame ← IF stack.hotFrame # NIL THEN stack.hotFrame.frameIndex ELSE 0;
cFrame ← IF stack.currentFrame # NIL THEN stack.currentFrame.basic.frameIndex ELSE 0;
Start the summary from the "hotter of" either the hotFrame or the currentFrame.
IF cFrame < hFrame THEN
startFrame ← IF stack.currentFrame # NIL THEN stack.currentFrame.basic ELSE FirstFrame[stack]
ELSE startFrame ← IF stack.hotFrame # NIL THEN stack.hotFrame ELSE FirstFrame[stack];
FOR frame: BasicFrameInfo ← startFrame, NextFrame[frame, stack] WHILE frame # NIL AND NOT stopFlag^ DO
inner: PROC RETURNS[ROPE] = {
basicPCInfo: REF LSA.BasicPCInfo ← LSA.GetBasicPCInfo[stack.lsh, frame.absPC];
rope: ROPELSA.GetRopeForBasicPCInfo[basicPCInfo, frame.absPC, FALSE, long, FALSE, FALSE];
IF stack.hotFrame # NIL AND stack.hotFrame.frameIndex = frame.frameIndex THEN IO.PutRope[on, "=>"];
IF stack.currentFrame # NIL AND stack.currentFrame.basic.frameIndex = frame.frameIndex THEN IO.PutRope[on, "->"];
IO.PutF[on, "\T%g: %g\N", IO.card[frame.frameIndex], IO.rope[rope]];
RETURN[NIL]};
eMsg: ROPE ← Protect[inner, on];
IF eMsg # NIL THEN IO.PutF[on, "%g\N", [rope[eMsg]]];
ENDLOOP;
IF stopFlag^ THEN IO.PutF[on, "stopped\n"];
END;
FindHotFrame: PROC[stack: Stack, stopFlag: REF BOOLEAN, on: IO.STREAM, long: BOOL] = {
ENABLE UNWIND => NULL;
possibleHotFrame: CARDLAST[CARD];
MIPSEB: Rope.ROPE ← "MIPSEB";
IRIX: Rope.ROPE ← "IRIX";
instrSet, opSys: Rope.ROPE;
[instrSet, opSys] ← CirioNubAccess.GetInstructionSetAndOperatingSystem[stack.nub];
IF stack.hotFrame # NIL THEN RETURN;
FOR frame: BasicFrameInfo ← TopFrame[stack], NextFrame[frame, stack] WHILE frame # NIL AND stack.hotFrame = NIL AND NOT stopFlag^ DO
inner: PROC RETURNS[ROPE] = {
basicPCInfo: REF LSA.BasicPCInfo ← LSA.GetBasicPCInfo[stack.lsh, frame.absPC];
rope: ROPELSA.GetRopeForBasicPCInfo[basicPCInfo, frame.absPC, FALSE, long, FALSE, FALSE];
IF basicPCInfo # NIL THEN {
tmpRope: Rope.ROPENIL;
IF Rope.Equal[basicPCInfo.procedureName, stack.target.CNameToLoaderName[stack.target, "XR�llDebugger"]] THEN {
possibleHotFrame ← frame.frameIndex + 1;
};
tmpRope ← stack.target.CNameToLoaderName[stack.target, "CallDebugger←"];
IF Rope.Equal[Rope.Substr[basicPCInfo.procedureName, 0, Rope.Length[tmpRope]], tmpRope] THEN {
Adding two here I assume was to skip the unviewable patch space frame. Well in SGI IRIX, I`ve skipped from adding that frame so only adding one is necessary in that case.
IF Rope.Equal[instrSet, MIPSEB] AND Rope.Equal[opSys, IRIX] THEN
possibleHotFrame ← frame.frameIndex + 1
ELSE
possibleHotFrame ← frame.frameIndex + 2;
};
tmpRope ← stack.target.CNameToLoaderName[stack.target, "Debug←P"];
IF Rope.Equal[Rope.Substr[basicPCInfo.procedureName, 0, Rope.Length[tmpRope]], tmpRope] THEN {
possibleHotFrame ← frame.frameIndex + 3;
};
tmpRope ← stack.target.CNameToLoaderName[stack.target, "BreakPointPopUp←"];
IF Rope.Equal[Rope.Substr[basicPCInfo.procedureName, 0, Rope.Length[tmpRope]], tmpRope] THEN {
possibleHotFrame ← frame.frameIndex + 2;
};
IF Rope.Equal[basicPCInfo.procedureName, stack.target.CNameToLoaderName[stack.target, "XR←Jump5"]] THEN {
possibleHotFrame ← frame.frameIndex + 1;
};
IF Rope.Equal[basicPCInfo.procedureName, stack.target.CNameToLoaderName[stack.target, "XR←Jump6"]] THEN {
possibleHotFrame ← frame.frameIndex + 1;
};
tmpRope ← stack.target.CNameToLoaderName[stack.target, "XR←Raise"];
IF Rope.Equal[Rope.Substr[basicPCInfo.procedureName, 0, Rope.Length[tmpRope]], tmpRope] THEN {
possibleHotFrame ← frame.frameIndex + 1;
};
tmpRope ← stack.target.CNameToLoaderName[stack.target, "UnboundTrap"];
IF Rope.Equal[Rope.Substr[basicPCInfo.procedureName, 0, Rope.Length[tmpRope]], tmpRope] THEN {
possibleHotFrame ← frame.frameIndex + 1;
};
IF Rope.Equal[basicPCInfo.procedureName, stack.target.CNameToLoaderName[stack.target, "XR←Narrow"]] THEN {
possibleHotFrame ← frame.frameIndex + 1;
};
IF Rope.Equal[basicPCInfo.procedureName, stack.target.CNameToLoaderName[stack.target, "←sigtramp"]] THEN {
possibleHotFrame ← frame.frameIndex + 1;
};
};
IF possibleHotFrame = frame.frameIndex THEN {
stack.hotFrame ← frame;
};
RETURN[NIL]};
eMsg: ROPE ← Protect[inner, on];
IF eMsg # NIL THEN IO.PutF[on, "%g\N", [rope[eMsg]]];
ENDLOOP;
};
QuickGenPossibleModuleNames: PUBLIC ENTRY PROC[stack: Stack, for: PROC[name: PATH] RETURNS[--stop-- BOOLEAN], reports: IO.STREAM] =
BEGIN
ENABLE UNWIND => NULL;
FOR frame: BasicFrameInfo ← FirstFrame[stack], NextFrame[frame, stack] WHILE frame # NIL DO
inner: PROC RETURNS[ROPE] = {
basicPCInfo: REF LSA.BasicPCInfo ← LSA.GetBasicPCInfo[stack.lsh, frame.absPC];
IF ExhibitStrippedName[basicPCInfo.loadedFileName, for] THEN RETURN[NIL];
FOR names: LIST OF PATH ← basicPCInfo.possibleModuleNames, names.rest WHILE names # NIL DO
IF ExhibitStrippedName[names.first, for] THEN RETURN[NIL];
ENDLOOP;
RETURN[NIL]};
eMsg: ROPE ← Protect[inner, reports];
IF eMsg # NIL THEN IO.PutF[reports, "%g\N", [rope[eMsg]]];
ENDLOOP;
END;
ExhibitStrippedName: PROC[name: PATH, for: PROC[name: PATH] RETURNS[--stop-- BOOLEAN]] RETURNS[--stop-- BOOLEAN] =
BEGIN
FIX: Use PFS Extensions to handle this
ropeName: ROPEPFS.RopeFromPath[name];
firstDot: INT ← Rope.Index[ropeName, 0, "."];
stripped: ROPE ← Rope.Substr[ropeName, firstDot];
IF Rope.Length[stripped] > 0 THEN RETURN[for[PFS.PathFromRope[stripped]]] ELSE RETURN[FALSE];
END;
FirstFrame: PROC[stack: Stack] RETURNS[BasicFrameInfo] =
BEGIN
IF stack.hotFrame = NIL THEN
stack.hotFrame ← BuildFrameInfo[stack, 0, stack.hotFramePC, stack.hotFrameSP, NIL];
RETURN[stack.hotFrame];
END;
TopFrame: PROC[stack: Stack] RETURNS[BasicFrameInfo] = {
RETURN[BuildFrameInfo[stack, 0, stack.hotFramePC, stack.hotFrameSP, NIL]];
};
NextFrame: PROC[current: BasicFrameInfo, stack: Stack] RETURNS[BasicFrameInfo] = TRUSTED
BEGIN
IF current.next = NIL THEN
BEGIN
pcLocationSPARC: CARD ← 15;
pcLocationRS6000: CARD ← 2;
stackOffset: CARD ← pcLocationRS6000*4;
absPC: CARD ← CirioNubAccess.Read32BitsAsCard[[stack.nub, current.stackPointer+stackOffset, 0, FALSE, TRUE]];
absPC: CARD ← CirioNubAccess.RaFromCi[stack.nub, current.stackPointer+stackOffset].Read32BitsAsCard;
FOR SGI
pcLocationMIPS: CARD ← is not that straightforward,
frameReg+(framesize+frameoffset), unless framereg = 0,
in that case pc is located 4 bytes from the virtual fp.
absPC: CARD ← is similar to SPARC once you find the PC.
The details of the MIPS stack is described in CirioTargetsImpl.mesa
currentSPBA: CirioMemory.BitAddr;
currentFPBA: CirioMemory.BitAddr;
absPCBA: CirioMemory.BitAddr;
absPC: CARD;
stackPointerBA: CirioMemory.BitAddr;
stackPointer: CARD;
loadedModule: REF LSA.LoadedModuleInfo ← NIL;
initLoadedModule: PROC RETURNS[ROPE] ~ TRUSTED {
loadedModule ← LSA.GetLoadedModuleInfoFromAbsPC[stack.lsh, current.absPC];
RETURN[NIL];
};
MIPSEB: Rope.ROPE ← "MIPSEB";
IRIX: Rope.ROPE ← "IRIX";
instrSet, opSys: Rope.ROPE;
[instrSet, opSys] ← CirioNubAccess.GetInstructionSetAndOperatingSystem[stack.nub];
IF Rope.Equal[instrSet, MIPSEB] AND Rope.Equal[opSys, IRIX] THEN
[] ← Protect[initLoadedModule, NIL];
IF loadedModule = NIL AND Rope.Equal[instrSet, MIPSEB] AND Rope.Equal[opSys, IRIX] THEN
{
FOR SGI ONLY
The absPC must be in the breakpoint patch area, so find the breakpoint PC. The breakpoint PC was saved in the last word of the manger. The offset from where the debugger is being called (current absPC) is 9 words.
breakWorld: BreakWorldArchitecture.BreakWorld ← CirioBreakAccess.BreakWorldFromBreakSet[stack.breaks];
address: BreakWorldArchitecture.Address ← BreakWorldArchitecture.NewAddress[breakWorld, LOOPHOLE[current.absPC+(9*4)]];
More checking must be done to insure that we are really in a patch space area and that this is an SGI object
breakpointPC: CARDLOOPHOLE[BreakWorldArchitecture.PeekContents[address]];
loadedModule ← LSA.GetLoadedModuleInfoFromAbsPC[stack.lsh, breakpointPC];
IF loadedModule = NIL THEN RETURN [NIL];
current.absPC ← breakpointPC;
The stack for a patch is a fixed size of 288 bytes. This size is determined in MIPSBreakpoint.mesa during InstallClosureCaller[].
The size here should be determined or some constant should be used.
current.stackPointer ← current.stackPointer+288;
current.framePointer ← CirioMemory.BaToPtr[stack.target.FpFromSp[loadedModule, stack.target, CirioMemory.PtrToBa[current.stackPointer],current.absPC]];
};
currentSPBA ← CirioMemory.PtrToBa[current.stackPointer];
currentFPBA ← CirioMemory.PtrToBa[current.framePointer];
absPCBA ← stack.target.ReadPc[loadedModule, stack.target, currentSPBA, currentFPBA, current.absPC];
absPC ← CirioMemory.BaToPtr[absPCBA];
stackPointerBA ← stack.target.NextSp[loadedModule, stack.target, currentSPBA, currentFPBA, current.absPC];
stackPointer ← CirioMemory.BaToPtr[stackPointerBA];
current.next ← BuildFrameInfo[stack, current.frameIndex+1, absPC, stackPointer, current];
absPCBA ← stack.target.ReadPc[loadedModule, stack.target, stackPointerBA, stack.target.FpFromSp[loadedModule, stack.target, stackPointerBA, absPC], absPC];
IF absPCBA = CirioMemory.unspecdBA THEN RETURN[NIL];
END;
RETURN[current.next];
END;
FpFromSp: PROC [nub: CirioNubAccess.Handle, sp: CARD] RETURNS [fp: CARD] ~ {
fpLocationSPARC: CARD ← 14;
fpLocationRS6000: CARD ← 0;
stackOffset: CARD ← fpLocationRS6000*4;
RETURN CirioNubAccess.RaFromCi[nub, sp+stackOffset].Read32BitsAsCard};
BuildFrameInfo: PROC[stack: Stack, index, absPC, stackPointer: CARD, previous: BasicFrameInfo] RETURNS[BasicFrameInfo] = TRUSTED
BEGIN
basic: REF LSA.BasicPCInfo ← LSA.GetBasicPCInfo[stack.lsh, absPC];
IF stackPointer = 0 THEN GOTO beyondColdestFrame; -- used for dummy stack
BEGIN
framePointer: CARD ← CirioMemory.PtrToBa[stack.target.FpFromSp[stack.target, CirioMemory.PtrToBa[stackPointer] ! CirioNubAccess.RemoteAddrFault => GOTO beyondColdestFrame]];
info: BasicFrameInfo;
stackPointerBA: CirioMemory.BitAddr;
framePointerBA: CirioMemory.BitAddr;
framePointer: CARD;
nextStackPointerBA: CirioMemory.BitAddr;
loadedModule: REF LSA.LoadedModuleInfo;
initLoadedModule: PROC RETURNS[ROPE] ~ TRUSTED {
loadedModule ← LSA.GetLoadedModuleInfoFromAbsPC[stack.lsh, absPC];
RETURN[NIL];
};
MIPSEB: Rope.ROPE ← "MIPSEB";
IRIX: Rope.ROPE ← "IRIX";
instrSet, opSys: Rope.ROPE;
[instrSet, opSys] ← CirioNubAccess.GetInstructionSetAndOperatingSystem[stack.nub];
IF Rope.Equal[instrSet, MIPSEB] AND Rope.Equal[opSys, IRIX] THEN
[] ← Protect[initLoadedModule, NIL];
IF absPC = 0 THEN GOTO beyondColdestFrame;
IF loadedModule = NIL AND Rope.Equal[instrSet, MIPSEB] AND Rope.Equal[opSys, IRIX] THEN
{
FOR SGI ONLY
The absPC must be in the breakpoint patch area, so find the breakpoint PC. The breakpoint PC was saved in the last word of the manger. The offset from where the debugger is being called (current absPC) is 9 words. These constants should be determined somewhere and imported here.
breakWorld: BreakWorldArchitecture.BreakWorld ← CirioBreakAccess.BreakWorldFromBreakSet[stack.breaks];
address: BreakWorldArchitecture.Address ← BreakWorldArchitecture.NewAddress[breakWorld, LOOPHOLE[absPC+(9*4)]];
More checking must be done to insure that we are really in a patch space area and that this is an SGI object
breakpointPC: CARDLOOPHOLE[BreakWorldArchitecture.PeekContents[address]];
loadedModule ← LSA.GetLoadedModuleInfoFromAbsPC[stack.lsh, breakpointPC];
IF loadedModule = NIL THEN RETURN [NIL];
absPC ← breakpointPC;
The stack for a patch is a fixed size of 288 bytes. This size is determined in MIPSBreakpoint.mesa during InstallClosureCaller[].
stackPointer ← stackPointer+288;
};
stackPointerBA ← CirioMemory.PtrToBa[stackPointer];
I changed the fourth parameter of FpFromSp to the absPC and not the stack pointer PC. jas
framePointerBA ← stack.target.FpFromSp[loadedModule, stack.target, stackPointerBA, absPC ! CirioNubAccess.RemoteAddrFault => GOTO beyondColdestFrame];
framePointer ← CirioMemory.BaToPtr[framePointerBA];
nextStackPointerBA ← stack.target.NextSp[loadedModule, stack.target, stackPointerBA, framePointerBA, absPC];
IF nextStackPointerBA = CirioMemory.zeroBA THEN GOTO beyondColdestFrame;
info ← NEW[BasicFrameInfoBody←[
index,
absPC,
framePointer,
stackPointer,
previous,
NIL]];
IF framePointer = 0 THEN GOTO beyondColdestFrame;
RETURN[info];
END;
EXITS
beyondColdestFrame => RETURN[NIL];
END;
NoteFileCacheFlush: PUBLIC ENTRY PROC[stack: Stack] =
BEGIN
ENABLE UNWIND => NULL;
IF FlushStackFramesFlag THEN FlushStackFrames[stack];
IF stack.currentFrame # NIL THEN {
additional flush if SunOS5
IF stack.target.opSys.Equal["SunOS5"] AND stack.currentFrame.basic.data # NIL THEN
IF stack.currentFrame.basic.data.ledo = NIL THEN
stack.currentFrame.basic.data ← NIL;
stack.currentFrame ← FirstFillInFrame[stack.currentFrame.basic, stack];
};
END;
FlushStackFramesFlag: BOOLFALSE;
FlushStackFrames: PROC[stack: Stack] =
{
ENABLE UNWIND => NULL;
startFrame: BasicFrameInfo ← NIL;
IF stack.currentFrame # NIL AND stack.currentFrame.basic # NIL THEN
startFrame ← stack.currentFrame.basic;
IF startFrame # NIL THEN {
FOR frame: BasicFrameInfo ← startFrame, frame.previous WHILE frame # NIL DO
frame.data ← NIL;
ENDLOOP;
FOR frame: BasicFrameInfo ← startFrame.next, frame.next WHILE frame # NIL DO
frame.data ← NIL;
ENDLOOP;
};
};
Disassemble: PUBLIC ENTRY PROC[stack: Stack, text: ROPE, reports: IO.STREAM, stop: REF BOOLNIL] =
BEGIN
ENABLE UNWIND => NULL;
Inner: PROC RETURNS[ROPE] = {
is: ROPE ← stack.target.instrSet;
IF is.Equal["SPARC"] THEN {
dn: Disa.DebugNub ~ MakeDisaDebugNub[stack.nub];
in: IO.STREAM ~ IO.RIS[text];
toke: ROPE ← in.GetTokenRope[IO.IDProc !IO.EndOfStream => GOTO Null].token;
[] ← in.SkipWhitespace[];
IF NOT in.EndOf[] THEN {
reports.PutRope["Only one thing at a time, please.\n"];
GOTO Null};
TRUSTED {ENABLE {
Disa.Failed => {
reports.PutF["%g => Error[%g]\n", [rope[toke]], [rope[errMsg]] ];
GOTO Null};
Disa.AddressFault => {a: CARD ~ LOOPHOLE[address];
reports.PutF["%g => AddressFault on addr %g=0x%08x\n", [rope[toke]], [cardinal[a]], [cardinal[a]] ];
GOTO Null};
CirioNub.Error => {
reports.PutF["You're not going to like this very much. While trying to disassemble %g, CirioNub.Error[%g] was raised. This most commonly results from trying to fetch from an un-mapped address. Sadly, when this happens your connection to your remote debug nub is screwed up --- and the copy of Cirio that you're running is ususally screwed up too. Disconnect this Cirio, or, if necessary, run another debugging world, and then you should be able to reconned to your debuggee. Don't waste your time trying to disassemble this again.\n", [rope[toke]], [atom[code]] ];
GOTO Null};
};
procSE: Disa.SymEntry ~ Disa.FindSym[toke, dn, TRUE];
IF procSE#Disa.nullSymEntry
THEN Disa.DisassembleProc[reports, procSE.value, Disa.EstSize[dn, procSE, TRUE], dn, NIL, stop]
ELSE reports.PutF1["Unable to find a symbol for %g\n", [rope[toke]] ];
}
EXITS Null => NULL}
ELSE reports.PutF1["Can't show machine source for instruction set %g\n", [rope[is]] ];
RETURN [NIL]};
[] ← Protect[Inner, reports];
END;
Stack examination
ResetStack: PUBLIC ENTRY PROC[stack: Stack, reports: IO.STREAM] RETURNS[newFrameIndex: CARD] = {
ENABLE UNWIND => NULL;
inner: PROC RETURNS[ROPE]= {
frame: REF FrameData;
stopFlag: REF BOOLEANNEW[BOOLEANFALSE];
FindHotFrame[stack, stopFlag, reports, FALSE];
frame ← FirstFillInFrame[FirstFrame[stack], stack];
stack.currentFrame ← frame;
RETURN[NIL];
};
eMsg: ROPE ← Protect[inner, reports];
IF eMsg # NIL THEN IO.PutF[reports, "%g\N", [rope[eMsg]]];
IF stack.currentFrame # NIL THEN RETURN[stack.currentFrame.basic.frameIndex]
ELSE RETURN[0];
};
WalkStack: PUBLIC ENTRY PROC[stack: Stack, movement: INT, reports: IO.STREAM] RETURNS[actualMovement: INT, newFrameIndex: CARD] =
BEGIN
ENABLE UNWIND => NULL;
inner: PROC RETURNS[ROPE] =
BEGIN
basic: BasicFrameInfo ← IF stack.currentFrame # NIL THEN stack.currentFrame.basic ELSE NIL;
actualMovement ← 0; -- may be incremented or decremented
IF basic # NIL AND movement < 0 THEN WHILE actualMovement > movement DO
tentativeFrame: BasicFrameInfo ← basic.previous;
IF tentativeFrame = NIL THEN EXIT;
basic ← tentativeFrame;
actualMovement ← actualMovement - 1;
ENDLOOP;
IF basic # NIL AND movement > 0 THEN WHILE actualMovement < movement DO
tentativeFrame: BasicFrameInfo ← NextFrame[basic, stack];
IF tentativeFrame = NIL THEN EXIT;
basic ← tentativeFrame;
actualMovement ← actualMovement + 1;
ENDLOOP;
stack.currentFrame ← FirstFillInFrame[basic, stack];
newFrameIndex ← IF stack.currentFrame # NIL THEN
stack.currentFrame.basic.frameIndex ELSE 0;
RETURN[NIL]
END;
eMsg: ROPE;
eMsg ← Protect[inner, reports];
IF eMsg # NIL THEN IO.PutF[reports, "%g\N", [rope[eMsg]]];
END;
WalkStackCedarFrames: PUBLIC ENTRY PROC[stack: Stack, nCedarFrames: INT, reports: IO.STREAM] RETURNS[actualNCedarFrames: INT, newFrameIndex: CARD] =
BEGIN
ENABLE UNWIND => NULL;
inner: PROC RETURNS[ROPE] =
BEGIN
frame: REF FrameData ← stack.currentFrame;
actualNCedarFrames ← 0; -- may be incremented or decremented
IF frame # NIL AND nCedarFrames < 0 THEN WHILE actualNCedarFrames > nCedarFrames DO
tentativeFrame: BasicFrameInfo ← frame.basic.previous;
IF tentativeFrame = NIL THEN EXIT;
frame ← FirstFillInFrame[tentativeFrame, stack];
IF frame.kind = $Cedar THEN actualNCedarFrames ← actualNCedarFrames - 1;
ENDLOOP;
IF frame # NIL AND nCedarFrames > 0 THEN WHILE actualNCedarFrames < nCedarFrames DO
tentativeFrame: BasicFrameInfo ← NextFrame[frame.basic, stack];
IF tentativeFrame = NIL THEN EXIT;
frame ← FirstFillInFrame[tentativeFrame, stack];
IF frame.kind = $Cedar THEN actualNCedarFrames ← actualNCedarFrames + 1;
ENDLOOP;
stack.currentFrame ← frame;
newFrameIndex ← IF frame # NIL THEN frame.basic.frameIndex ELSE 0;
RETURN[NIL]
END;
eMsg: ROPE;
IF (eMsg ← Protect[inner, reports]) # NIL THEN IO.PutF[reports, "%g\N", [rope[eMsg]]];
END;
FirstFillInFrame: PROC[basic: BasicFrameInfo, stack: Stack] RETURNS[REF FrameData] =
BEGIN
IF basic = NIL THEN
RETURN[NIL]
ELSE
BEGIN
IF basic.data # NIL THEN RETURN[basic.data];
basic.data ← NEW[FrameData ← [basic: basic]];
basic.data.ledo ← LSA.GetLoadedModuleInfoFromAbsPC[stack.lsh, basic.absPC, stack.cedarModules];
basic.data.basicPCInfo ← LSA.GetBasicPCInfo[stack.lsh, basic.absPC];
now we compute the kind
IF basic.data.ledo = NIL THEN basic.data.kind ← $C ELSE
BEGIN
vs: REF DOA.VersionStampInfo ← DOA.FindVersionStamp[basic.data.ledo.module];
IF vs = NIL THEN basic.data.kind ← $C
ELSE basic.data.kind ← $Cedar;
END;
RETURN[basic.data]
END;
END;
WalkStackToCProcedure: PUBLIC ENTRY PROC[stack: Stack, partialProcName: ROPE, moduleName: ROPE, reports: IO.STREAM] RETURNS[BOOLEAN] =
BEGIN
ENABLE UNWIND => NULL;
foundFrame: BOOLEANFALSE;
inner: PROC RETURNS[ROPE] =
BEGIN
frame: REF FrameData ← stack.currentFrame;
here is the loop
IF stack.currentFrame # NIL THEN DO
tentativeFrame: BasicFrameInfo;
IO.PutF[reports, " %g\N", IO.rope[frame.basicPCInfo.procedureName]];
IF Rope.Length[frame.basicPCInfo.procedureName] >= Rope.Length[partialProcName] AND Rope.Equal[partialProcName, Rope.Substr[frame.basicPCInfo.procedureName, 0, Rope.Length[partialProcName]]] THEN
BEGIN
IO.PutF[reports, "key procedure is %g\N", IO.rope[frame.basicPCInfo.procedureName]];
foundFrame ← TRUE;
EXIT;
END;
tentativeFrame ← NextFrame[frame.basic, stack];
IF tentativeFrame = NIL THEN EXIT;
frame ← FirstFillInFrame[tentativeFrame, stack];
note, we do the actual walk here, because WalkStack is an entry procedure and I don't want to go to the trouble of splitting git.
ENDLOOP;
IF foundFrame THEN stack.currentFrame ← frame;
RETURN[NIL]
END;
eMsg: ROPE;
IF (eMsg ← Protect[inner, reports]) # NIL THEN IO.PutF[reports, "%g\N", [rope[eMsg]]];
RETURN[foundFrame];
END;
GetBannerForDotOofCurrentFrame: PUBLIC ENTRY PROC[stack: Stack, reports: IO.STREAM] RETURNS[ROPE] =
BEGIN
ENABLE UNWIND => NULL;
inner: PROC RETURNS[ROPE] =
BEGIN
frame: REF FrameData ← stack.currentFrame;
ropes: LIST OF ROPELSA.GetRopeListForLoadedFileContainingLoadedModule[frame.ledo];
rope: ROPENIL;
FOR rps: LIST OF ROPE ← ropes, rps.rest WHILE rps # NIL DO
rope ← Rope.Cat[rope, rps.first, "\N"];
ENDLOOP;
RETURN[rope];
END;
IF stack.currentFrame # NIL THEN RETURN[Protect[inner, reports]] ELSE RETURN["no frame"];
END;
GetCurrentFrameBanner: PUBLIC ENTRY PROC[stack: Stack, reports: IO.STREAM] RETURNS[ROPE] =
BEGIN
ENABLE UNWIND => NULL;
inner: PROC RETURNS[ROPE] =
BEGIN
frame: REF FrameData ← stack.currentFrame;
absRope: ROPEIO.PutFR["absPC: %08xH, fp: %08xH, sp: %08xH", IO.card[frame.basic.absPC], IO.card[frame.basic.framePointer], IO.card[frame.basic.stackPointer]];
detail: BOOL ← frame.ledo = NIL;
basicRope: ROPELSA.GetRopeForBasicPCInfo[frame.basicPCInfo, frame.basic.absPC, TRUE, TRUE, detail, detail];
ropes: LIST OF ROPELSA.GetRopeListForLoadedModuleInfo[frame.ledo];
rope: ROPENIL;
rope ← Rope.Cat[rope, absRope, "\N"];
rope ← Rope.Cat[rope, basicRope, "\N"];
FOR rps: LIST OF ROPE ← ropes, rps.rest WHILE rps # NIL DO
rope ← Rope.Cat[rope, rps.first, "\N"];
ENDLOOP;
IF frame.kind # $Cedar THEN rope ← rope.Concat["Can't be viewed as a Cedar frame.\n"];
RETURN[rope];
END;
IF stack.currentFrame # NIL THEN RETURN[Protect[inner, reports]] ELSE RETURN["no frame"];
END;
ShowCurrentFrame: PUBLIC ENTRY PROC[stack: Stack, reports: IO.STREAM] RETURNS[ROPE] = {
ENABLE UNWIND => NULL;
Inner: PROC RETURNS[ROPE] = {
buf: IO.STREAM ~ IO.ROS[];
to: IO.STREAM ~ SS.Create[UB.NewInittedHandle[[
margin: stdMargin,
output: [stream[buf]] ]]];
frame: REF FrameData ← stack.currentFrame;
SS.Begin[to];
InstallFrameNode[frame, stack];
UGH: for the moment, we should have connection.cc in td.currentFrameCC for $Cedar. This shows up in the interpreter as well. But in any case, this is all a crock. We should have a single target world. Note that the C world has a new target world per frame, that has to be modified to be a target world per connection. But somehow, we have to combine those target world.
IO.PutF[reports, "(frame address: %g)\N", IO.card[frame.basic.framePointer]];
SELECT stack.desiredLang FROM
$Cedar => IF frame.cedarFrameNode # NIL AND frame.cedarFrameNode.node # NIL THEN CedarCode.ShowNode[to, frame.cedarFrameNode.node, 3, 300, stack.cc]
ELSE to.PutRope["unreadable Cedar frame, no further info"];
$C => IF frame.cFrameNode # NIL AND frame.cFrameNode.node # NIL THEN CedarCode.ShowNode[to, frame.cFrameNode.node, 3, 300, frame.cFrameNode.cc]
ELSE to.PutRope["unreadable C frame, no further info"];
$Machine => ShowMachineFrame[to, stack.nub, frame];
ENDCASE => to.PutRope["unknown frame"];
SS.End[to];
RETURN[buf.RopeFromROS]};
IF stack.currentFrame # NIL
THEN RETURN Protect[Inner, reports]
ELSE RETURN["no frame"];
};
ShowMachineFrame: PROC [to: IO.STREAM, nub: CirioNubAccess.Handle, frame: REF FrameData] ~ {
basic: BasicFrameInfo ~ frame.basic;
IF basic=NIL THEN {to.PutRope["broken frame"]; RETURN};
to.PutF["pc=%08x, sp=%08x", [cardinal[basic.absPC]], [cardinal[basic.stackPointer]] ];
IF basic.stackPointer # 0 THEN {
sp: CARD ~ basic.stackPointer;
spPrev: INT ~ IF basic.previous#NIL THEN LOOPHOLE[basic.previous.stackPointer] ELSE 0;
to.PutRope["\n%i:"];
FOR i: NAT IN [0..8) DO
x: CARD ~ CirioNubAccess.Read32BitsAsCard[
[h: nub, byteAddress: sp+(i+8)*4, bitOffset: 0, nil: FALSE, valid: TRUE]
! CirioNubAccess.Error => {
to.PutF[" (CirioNubAccess.Error[%g])\n", [rope[msg]] ];
GOTO Nomore};
CirioNubAccess.RemoteNilFault, CirioNubAccess.RemoteAddrFault => {
to.PutRope[" (address fault)\n"];
GOTO Nomore}
];
to.PutF[" %08x", [cardinal[x]] ];
ENDLOOP;
to.PutRope["\n%l:"];
FOR i: NAT IN [0..8) DO
x: CARD ~ CirioNubAccess.Read32BitsAsCard[[h: nub, byteAddress: sp+(i+0)*4, bitOffset: 0, nil: FALSE, valid: TRUE] !
CirioNubAccess.Error => {
to.PutF[" (CirioNubAccess.Error[%g])\n", [rope[msg]] ];
GOTO Nomore};
CirioNubAccess.RemoteNilFault, CirioNubAccess.RemoteAddrFault => {
to.PutRope[" (address fault)\n"];
GOTO Nomore}
];
to.PutF[" %08x", [cardinal[x]] ];
ENDLOOP;
to.PutRope["\n%o:"];
FOR i: NAT IN [0..8) DO
x: CARD ~ CirioNubAccess.Read32BitsAsCard[[h: nub, byteAddress: spPrev+(i+8)*4, bitOffset: 0, nil: FALSE, valid: TRUE] !
CirioNubAccess.Error => {
to.PutF[" (CirioNubAccess.Error[%g])\n", [rope[msg]] ];
GOTO Nomore};
CirioNubAccess.RemoteNilFault, CirioNubAccess.RemoteAddrFault => {
to.PutRope[" (address fault)\n"];
GOTO Nomore}
];
to.PutF[" %08x", [cardinal[x]] ];
ENDLOOP;
EXITS Nomore => NULL};
RETURN};
ShowSourcePosition: PUBLIC ENTRY PROC[stack: Stack, reports: IO.STREAM, stop: REF BOOLNIL] =
BEGIN
ENABLE UNWIND => NULL;
pos: SourceFileOpsExtras.Position;
pos ← FindSourcePosition[stack, reports];
Display the mesa source code point.
IF pos # SourceFileOpsExtras.noPosition OR stack.desiredLang=$Machine THEN
SELECT stack.desiredLang FROM
$Cedar => {
SystemInterface.ShowSource[desc: "Cedar source position", pos: pos, feedBack: reports];
};
$C =>
reports.PutF["C source line = %g; can't yet open it for you.\n", [integer[pos.index[line].first]]];
SystemInterface.ShowSource[desc: "C source position", pos: pos, feedBack: reports];
$Machine => {
is: ROPE ← stack.target.instrSet;
IF is.Equal["SPARC"] THEN TRUSTED {
dn: Disa.DebugNub ~ MakeDisaDebugNub[stack.nub];
{ENABLE {
Disa.Failed => {
reports.PutF1["Error[%g]\n", [rope[errMsg]] ];
GOTO Null};
Disa.AddressFault => {a: CARD ~ LOOPHOLE[address];
reports.PutF["AddressFault on addr %g=0x%08x\n", [cardinal[a]], [cardinal[a]] ];
GOTO Null};
CirioNub.Error => {
reports.PutF1["You're not going to like this very much. While trying to disassemble the current procedure, CirioNub.Error[%g] was raised. This most commonly results from trying to fetch from an un-mapped address. Sadly, when this happens your connection to your remote debug nub is screwed up --- and the copy of Cirio that you're running is ususally screwed up too. Disconnect this Cirio, or, if necessary, run another debugging world, and then you should be able to reconned to your debuggee. Don't waste your time trying to disassemble this procedure again.\n", [atom[code]] ];
GOTO Null};
};
procSE: Disa.SymEntry ~ dn.GetMatchingSymEntryByValue[dn, stack.currentFrame.basic.absPC, Disa.typeText, Disa.Classes[all], 0];
IF procSE#Disa.nullSymEntry
THEN Disa.DisassembleProc[reports, procSE.value, Disa.EstSize[dn, procSE, TRUE], dn, NIL, stop]
ELSE IO.PutF1[reports, "Couldn't find entry point for pc=0x%08x\n", [cardinal[stack.currentFrame.basic.absPC]] ];
EXITS Null => is ← is}}
ELSE reports.PutF1["Can't show machine source for instruction set %g\n", [rope[is]] ];
};
ENDCASE => {}
ELSE
IF reports # NIL THEN IO.PutF1[reports, " couldn't ... "];
END;
MakeDisaDebugNub: PROC [nub: CirioNubAccess.Handle] RETURNS [Disa.DebugNub] ~ {
RETURN [NEW[Disa.DebugNubPrivate ← [
DnGetMatchingSymEntryByName,
DnGetMatchingSymEntryByValue,
DnGetSymEntryByID,
DnGetInterfaceSlot,
DnPCtoInfo,
DnFetchWord,
nub]]]};
DnGetMatchingSymEntryByName: PROC [nub: Disa.DebugNub, pattern: ROPE, caseSensitive: BOOLEAN, types: CARD, classes: Disa.Classes, nth: INT, from: Disa.SymID] RETURNS [Disa.SymEntry] ~ {
h: CirioNubAccess.Handle ~ NARROW[nub.data];
RETURN ExportSE[CirioNubAccess.LookupMatchingSymEntryByName[h, from, pattern, caseSensitive, types, classes.ORD, nth]]};
DnGetMatchingSymEntryByValue: PROC [nub: Disa.DebugNub, val, types: CARD, classes: Disa.Classes, nth: INT, from: Disa.SymID] RETURNS [Disa.SymEntry] ~ {
h: CirioNubAccess.Handle ~ NARROW[nub.data];
RETURN ExportSE[CirioNubAccess.LookupMatchingSymEntryByValue[h, from, val, types, classes.ORD, nth]]};
DnGetSymEntryByID: PROC [nub: Disa.DebugNub, id: Disa.SymID] RETURNS [Disa.SymEntry] ~ {
h: CirioNubAccess.Handle ~ NARROW[nub.data];
RETURN ExportSE[CirioNubAccess.LookupSymEntryByID[h, id]]};
ExportSE: PROC [se: CirioNubAccess.SymEntry] RETURNS [Disa.SymEntry] ~ {
IF se=NIL THEN RETURN [Disa.nullSymEntry];
RETURN [[
symID: se.symID,
name: se.name,
type: se.type,
value: se.value,
size: se.size,
fileSeqNum: se.fileSeqNum]]};
DnGetInterfaceSlot: PROC [nub: Disa.DebugNub, ifc, item: ROPE] RETURNS [addr: CARD]
~ {RETURN [Disa.nullAddr]};
DnPCtoInfo: PROC [nub: Disa.DebugNub, pc: CARD] RETURNS [Disa.PCInfo] ~ {
h: CirioNubAccess.Handle ~ NARROW[nub.data];
pci: CirioNubAccess.PCInfo ~ CirioNubAccess.PCtoInfo[h, pc];
IF pci=NIL THEN RETURN [Disa.nullPCInfo];
RETURN [[
procName: pci.procName,
procSymID: pci.procSymID,
fileName: PFS.RopeFromPath[pci.fileName],
fileSeqNum: pci.fileSeqNum,
guessedEmbeddedFileName: PFS.RopeFromPath[pci.guessedEmbeddedFileName],
guessedEmbeddedFileSymID: pci.guessedEmbeddedFileSymID]]};
DnFetchWord: PROC [nub: Disa.DebugNub, addr: CARD] RETURNS [WORD] ~ {
h: CirioNubAccess.Handle ~ NARROW[nub.data];
RETURN CirioNubAccess.Read32BitsAsCard[[h, addr, 0, addr=0, TRUE]
!CirioNubAccess.RemoteNilFault, CirioNubAccess.RemoteAddrFault, CirioNubAccess.Error
=> TRUSTED {Disa.AddressFault[LOOPHOLE[addr]]}
]};
FindSourcePosition: PROC[stack: Stack, reports: IO.STREAM] RETURNS[pos: SourceFileOpsExtras.Position ← SourceFileOpsExtras.noPosition] =
BEGIN
ENABLE UNWIND => NULL;
inner: PROC RETURNS[ROPE] =
BEGIN
frame: REF FrameData ← stack.currentFrame;
sp: REF NewRMTW.CedarSourcePosition ← NewRMTW.GetCedarSourcePosition[stack.cedarModules, frame.ledo, frame.basic.absPC];
SELECT stack.desiredLang FROM
$Cedar => {
IF sp.mesa # NIL THEN {
pos ← [fileName: SystemInterface.GetNameOfFile[sp.mesa], uniqueID: SystemInterface.GetFileInfo[sp.mesa].uniqueID, index: [char: [sp.mesaPosition]]];
}
ELSE {
pos ← SourceFileOpsExtras.noPosition;
}
};
$C => {
IF sp.cFile # NIL THEN
pos ← [fileName: SystemInterface.GetNameOfFile[sp.cFile], uniqueID: SystemInterface.GetFileInfo[sp.cFile].uniqueID, index: [line: [sp.cLineNum]]]
ELSE IF frame.ledo # NIL THEN
pos ← RCTW.GetSourcePosition[frame.basic.absPC, stack.cedarModules, frame.basicPCInfo, frame.ledo]
ELSE
pos ← SourceFileOpsExtras.noPosition;
};
$Machine => pos ← SourceFileOpsExtras.noPosition;
ENDCASE => RETURN["currently we can only show source position for Cedar, C, and some Machine-Language frames"];
RETURN [NIL];
END;
eMsg: ROPE;
IF stack.currentFrame # NIL THEN eMsg ← Protect[inner, reports] ELSE eMsg ← "no frame";
IF eMsg # NIL THEN IO.PutF[reports, "%g\N", [rope[eMsg]]];
END;
InterpretTextLine: PUBLIC ENTRY PROC[stack: Stack, text: ROPE, reports: IO.STREAM] RETURNS[ROPE] = {
ENABLE UNWIND => {stack.tsOut ← stack.aph.out ← NIL};
CedarParse: PROC[line: ROPE, reports: IO.STREAM] RETURNS[CirioSyntacticOperations.ParseTree] =
{RETURN[WalkCedarParseTrees.CreatePPTreeParseTree[CedarParseSupport.ParseCedarExpression[line, reports], stack.cc]]};
Inner: PROC RETURNS[ROPE] = {
buf: IO.STREAM ~ IO.ROS[];
to: IO.STREAM ~ SS.Create[UB.Create[
publics: [
margin: stdMargin,
output: [stream[buf]] ],
debug: debugSS]];
debugOut: IO.STREAMNIL;
frame: REF FrameData ← stack.currentFrame;
node: CirioTypes.Node ← stack.dummyNode; -- tentative worst case
cc: CC ← stack.cc;
CParse: PROC[line: ROPE, reports: IO.STREAM] RETURNS[CirioSyntacticOperations.ParseTree] = {
RETURN[WalkCParseTrees.CreatePPTreeParseTree[
CParser.MakeCParseTree[cParseTable, IO.RIS[line], reports],
cc]]};
Doit: PROC [node: CirioTypes.Node, cc: CC, Parse: ParseProc, lang: Language] ~ {
cc.nameScope ← CCTypes.CreateCompoundNameScope[stack.ampersandContext1, stack.ampersandContext2, node, cc]; -- ugh: side effects up the wazoo
InterpretLine[to, text, printDepth, printWidth, cc, debugOut, TRUE, Parse, lang, reports];
RETURN};
SS.Begin[to];
IF DebugFlag THEN debugOut ← reports;
IF frame#NIL AND (frame.kind=NIL OR frame.cFrameNode=NIL) THEN InstallFrameNode[frame, stack];
SELECT stack.desiredLang FROM
$Cedar => {
IF frame#NIL AND frame.cedarFrameNode#NIL AND frame.cedarFrameNode.node#NIL THEN node ← frame.cedarFrameNode.node;
cc.moduleScope ← NewRMTW.GetModuleScope[stack.rmtw];
Doit[node, cc, CedarParse, Cedar]};
$C => {
IF cParseTable=NIL THEN {
tableName: ROPE ~ FamousPath.SearchList[famousPath, "c.kipperedParseTables"].fullFName;
IF tableName=NIL THEN CCE[cirioError, "Couldn't find famous file c.kipperedParseTables"];
reports.PutF["Loading C parse tables from %g ...", [rope[tableName]] ];
{tableStream: IO.STREAMFS.StreamOpen[tableName];
cParseTable ← OneCasabaParser.BuildParserTableFromKipperedStream[tableStream];
tableStream.Close[];
tableStream ← NIL;
reports.PutRope[" done reading C parse tables.\n"]}};
IF frame#NIL AND frame.cFrameNode#NIL AND frame.cFrameNode.node#NIL THEN {
node ← frame.cFrameNode.node; cc ← frame.cFrameNode.cc};
Doit[node, cc, CParse, C]};
$Machine => SELECT TRUE FROM
NOT mlPrefix.IsPrefix[text] => to.PutRope["Aack! You managed to delete the prompt!\n"];
ENDCASE => {
dn: Disa.DebugNub ~ MakeDisaDebugNub[stack.nub];
in: IO.STREAM ~ IO.RIS[text.Substr[start: mlPrefix.Length]];
toke: ROPE;
se: Disa.SymEntry;
toke ← in.GetTokenRope[IO.IDProc !IO.EndOfStream => GOTO Null].token;
[] ← in.SkipWhitespace[];
IF NOT in.EndOf[] THEN {
to.PutRope["Only one thing at a time, please.\n"];
GOTO Null};
TRUSTED {se ← Disa.FindSym[toke, dn, FALSE !
Disa.Failed => {
to.PutF["%g => Error[%g]\n", [rope[toke]], [rope[errMsg]] ];
GOTO Null};
Disa.AddressFault => {a: CARD ~ LOOPHOLE[address];
to.PutF["%g => AddressFault on addr %g=0x%08x\n", [rope[toke]], [cardinal[a]], [cardinal[a]] ];
GOTO Null};
CirioNub.Error => {
to.PutF["You're not going to like this very much. While trying to interpret %g as a loader symbol, CirioNub.Error[%g] was raised. This most commonly results from trying to fetch from an un-mapped address. Sadly, when this happens your connection to your remote debug nub is screwed up --- and the copy of Cirio that you're running is ususally screwed up too. Disconnect this Cirio, or, if necessary, run another debugging world, and then you should be able to reconned to your debuggee.\n", [rope[toke]], [atom[code]] ];
GOTO Null}]
};
IF se=Disa.nullSymEntry
THEN to.PutF1["Unable to find a symbol for %g\n", [rope[toke]] ]
ELSE {fe: CirioNubAccess.FileEntry;
to.PutFL["%g => %g type=%g val=%g=0x%08x size=%g file=%g", LIST[ [rope[toke]], [rope[se.name]], [cardinal[se.type]], [cardinal[se.value]], [cardinal[se.value]], [cardinal[se.size]], [cardinal[se.fileSeqNum]] ]];
fe ← CirioNubAccess.GetFileEntry[stack.nub, se.fileSeqNum];
to.PutF1[" %g\n", [rope[PFS.RopeFromPath[fe.fileName]]] ]};
EXITS Null => cc ← stack.cc};
ENDCASE => CCE[cirioError, "InterpretTextLine[unrecognized language]"];
SS.End[to];
RETURN[buf.RopeFromROS]};
result: ROPE;
stack.tsOut ← stack.aph.out ← reports; -- transient
result ← Protect[Inner, reports
! NewAmpersandProcs.GetHandle => RESUME[stack.aph]];
stack.tsOut ← stack.aph.out ← NIL; -- clear out the transient
RETURN[result]};
SetDesiredLanguage: PUBLIC PROC [stack: Stack, lang: Language, reports: IO.STREAM] ~ {
stack.desiredLang ← lang;
RETURN};
ReportDesiredLanguage: PUBLIC PROC [stack: Stack, reports: IO.STREAMNIL] RETURNS [Language] ~ {
IF reports#NIL THEN reports.PutF["Current desired language is %g.\n", [rope[SELECT stack.desiredLang FROM $C => "C", $Cedar => "Cedar", $Machine => "Machine", ENDCASE => "Unrecognized!"]] ];
RETURN [stack.desiredLang]};
FormatPrompt: PUBLIC PROC [stack: Stack, counter: INT] RETURNS [ROPE] ~ {
frame: REF FrameData ← stack.currentFrame;
SELECT stack.desiredLang FROM
$C => RETURN IO.PutFR["/* %g */ ", [integer[counter]] ];
$Cedar => RETURN IO.PutFR["&%g ← ", [integer[counter]] ];
$Machine => RETURN [mlPrefix];
ENDCASE => CCE[cirioError, "FormatPrompt[unrecognized language]"]};
mlPrefix: ROPE ~ ". ";
we try to install Cedar and C contexts.
InstallFrameNode: PROC[frame: REF FrameData, stack: Stack] =
BEGIN
IF frame.rawFrameInfo = NIL THEN frame.rawFrameInfo ← NEW[NewRMTW.RawFrameInfo←[
frame.basic.absPC,
frame.basic.framePointer,
frame.basic.stackPointer]];
IF frame.ledo#NIL THEN {
frameInfo: RCTW.ProcedureFrameInfo ~ NEW [RCTW.ProcedureFrameInfoBody ← [
dotOLongName: PFS.RopeFromPath[frame.basicPCInfo.loadedFileName],
mTime: frame.ledo.mtimeOfLoadedFile,
size: frame.ledo.sizeOfLoadedFile,
codeBase: frame.ledo.lsi[text].base,
dataBase: frame.ledo.lsi[data].base,
bssBase: frame.ledo.lsi[bss].base,
relativePC: frame.basic.absPC - frame.ledo.lsi[text].base,
framePointer: frame.basic.framePointer,
stackPointer: frame.basic.stackPointer]];
frame.cFrameNode ← RCTW.GetFrameNodeInfo[ NewRMTW.GetRMTWInfo[stack.rmtw].serverName, frameInfo, stack.nub, stack.lsh, frame.ledo.module]};
IF frame.kind = $Cedar THEN {
frame.loadedCedarModule ← NewRMTW.GetLoadedModuleInfo[stack.cedarModules, frame.ledo];
we repeat the call just in case there have been changes in the search paths since the last call. If there has been no changes in state, the worst we pay is a few procedure calls and an allocation.
IF frame.loadedCedarModule # NIL THEN frame.cedarFrameNode ← NewRMTW.GetNodeForCedarFrame[stack.rmtw, frame.loadedCedarModule, frame.rawFrameInfo];
};
END;
BuildDummyFrameNode: PROC[stack: Stack] RETURNS[CirioTypes.Node] =
BEGIN
gftd: REF Frames.IndirectGlobalFrameTypeData ← BuildDummyGFTD[stack];
dummyFrameType: CirioTypes.Type ← Frames.CreateIndirectGlobalFrameType[gftd, stack.cc];
igfd: REF Frames.IndirectGlobalFrameData ← BuildDummyIGFD[stack];
dummyNode: CirioTypes.Node ← Frames.CreateIndirectGlobalFrameNode[igfd, dummyFrameType, stack.cc];
RETURN[dummyNode];
END;
BuildDummyGFTD: PROC[stack: Stack] RETURNS[REF Frames.IndirectGlobalFrameTypeData] =
BEGIN
cc: CC ← stack.cc;
ut: CirioTypes.Type ← CedarOtherPureTypes.CreateUnknownType[cc, "unknown type involved in dummy frame node type"];
gftd: REF Frames.IndirectGlobalFrameTypeData ← NEW[Frames.IndirectGlobalFrameTypeData];
gftd.globalVars ← ut;
RETURN[gftd]
END;
BuildDummyIGFD: PROC[stack: Stack] RETURNS[REF Frames.IndirectGlobalFrameData] =
BEGIN
cc: CC ← stack.cc;
igfd: REF Frames.IndirectGlobalFrameData ← NEW[Frames.IndirectGlobalFrameData];
ut: CirioTypes.Type ← CedarOtherPureTypes.CreateUnknownType[cc, "unknown type involved in dummy frame node"];
utn: CirioTypes.Node ← CedarOtherPureTypes.CreateIndirectToAnUnknownType[ut, "unknown type node involved in dummy frame node", cc];
IF CCTypes.GetRopeType[cc]=NIL
THEN igfd.descriptor ← utn
ELSE igfd.descriptor ← CedarOtherPureTypes.CreateRopeNode["dummy (global) frame node", cc];
igfd.globalVars ← utn;
RETURN[igfd];
END;
ClearBreakPoint: PUBLIC ENTRY PROC [stack: Stack, reports: IO.STREAM] =
BEGIN
ENABLE UNWIND => NULL;
eMsg: ROPE;
inner: PROC RETURNS[ROPE] =
BEGIN
frame: REF FrameData ← stack.currentFrame;
absAddr: CARD ← frame.basic.absPC;
CirioBreakAccess.ClearBreakAtAbsAddr[stack.breaks, absAddr];
RETURN[NIL];
END;
IF stack = NIL THEN eMsg ← "no stack" ELSE
IF stack.currentFrame # NIL THEN eMsg ← Protect[inner, reports] ELSE eMsg ← "no frame";
IF eMsg # NIL THEN IO.PutF[reports, "%g\N", [rope[eMsg]]];
END;
ClearIthBreakPoint: PUBLIC ENTRY PROC [stack: Stack, i: INT, reports: IO.STREAM] =
BEGIN
ENABLE UNWIND => NULL;
eMsg: ROPE;
inner: PROC RETURNS[ROPE] =
BEGIN
CirioBreakAccess.ClearBreakAtIndex[stack.breaks, CARD[i]];
RETURN[NIL];
END;
eMsg ← Protect[inner, reports];
IF eMsg # NIL THEN IO.PutF[reports, "%g\N", [rope[eMsg]]];
END;
ClearAllBreakPoints: PUBLIC PROC [stack: Stack, reports: IO.STREAM] =
Clears all currently set breakpoints.
BEGIN
inner: PROC RETURNS[ROPE] =
BEGIN
CirioBreakAccess.ClearAllBreaks[stack.breaks];
RETURN [" done"];
END;
eMsg: ROPE;
eMsg ← Protect[inner, reports];
IF eMsg # NIL THEN IO.PutF[reports, "%g\N", [rope[eMsg]]];
END;
ClearBreakPointAtPosition: PUBLIC PROC[stack: Stack, pos: SourceFileOpsExtras.Position, reports: IO.STREAM] = {
inner: PROC RETURNS[ROPE] = {
actual: SourceFileOpsExtras.Position;
absPC: CARD;
[actual, absPC] ← GetBreakAddrFromPosition[stack, pos, reports];
IF absPC # 0 THEN CirioBreakAccess.ClearBreakAtAbsAddr[stack.breaks, absPC];
RETURN [NIL];
};
eMsg: ROPE;
eMsg ← Protect[inner, reports];
IF eMsg # NIL THEN IO.PutF[reports, "%g\N", [rope[eMsg]]];
};
ClearBreakPointAtAddress: PUBLIC PROC[stack: Stack, addr: CARD, reports: IO.STREAM] = {
inner: PROC RETURNS[ROPE] = {
CirioBreakAccess.ClearBreakAtAbsAddr[stack.breaks, addr];
RETURN [NIL];
};
eMsg: ROPE;
eMsg ← Protect[inner, reports];
IF eMsg # NIL THEN IO.PutF[reports, "%g\N", [rope[eMsg]]];
};
GetAbsPC: PUBLIC ENTRY PROC [stack: Stack] RETURNS[CARD] =
BEGIN
ENABLE UNWIND => NULL;
frame: REF FrameData ← stack.currentFrame;
RETURN[frame.basic.absPC];
END;
FrameDiagnosticInfo: PUBLIC ENTRY PROC[stack: Stack, reports: IO.STREAM] =
BEGIN
ENABLE UNWIND => NULL;
frame: REF FrameData ← stack.currentFrame;
ropes: LIST OF ROPE
SELECT frame.kind FROM
$Cedar => IF frame.cedarFrameNode # NIL THEN frame.cedarFrameNode.getDiagnosticInfo[frame.cedarFrameNode] ELSE LIST["unreadable Cedar frame"],
$C => IF frame.cFrameNode # NIL THEN frame.cFrameNode.getDiagnosticInfo[frame.cFrameNode] ELSE LIST["unreadable C frame"],
$none => LIST["unknown frame"],
ENDCASE => LIST["unknown frame"];
FOR rps: LIST OF ROPE ← ropes, rps.rest WHILE rps # NIL DO
IO.PutF[reports, "\t%g\N", IO.rope[rps.first]];
ENDLOOP;
END;
break points (are here because they are needed by both remote and local tools)
ListBreakPoints: PUBLIC PROC[stack: Stack, reports: IO.STREAM] =
BEGIN
inner: PROC RETURNS[ROPE] =
BEGIN
CirioBreakAccess.ListBreaks[stack.breaks];
RETURN [NIL];
END;
eMsg: ROPE ← Protect[inner, reports];
IF eMsg # NIL THEN IO.PutF[reports, "%g\N", [rope[eMsg]]];
END;
SetBreakPointAtPosition: PUBLIC PROC[stack: Stack, pos: SourceFileOpsExtras.Position, reports: IO.STREAM, stopAll: BOOLEAN] RETURNS [whereSet: SourceFileOpsExtras.Position ← SourceFileOpsExtras.noPosition] =
BEGIN
inner: PROC RETURNS[ROPE] = {
absPC: CARD;
[whereSet, absPC] ← GetBreakAddrFromPosition[stack, pos, reports];
IF absPC # 0 THEN BEGIN
Set a breakpoint at the absolute PC corresponding to the specified code point.
CirioBreakAccess.SetBreakAtAbsAddr[stack.breaks, absPC, whereSet, stopAll];
END;
RETURN [NIL];
};
eMsg: ROPE;
eMsg ← Protect[inner, reports];
IF eMsg # NIL THEN IO.PutF[reports, "%g\N", [rope[eMsg]]];
END;
SetBreakPointAtAddress: PUBLIC PROC[stack: Stack, addr: CARD, reports: IO.STREAM, stopAll: BOOLEAN] =
BEGIN
inner: PROC RETURNS[ROPE] = {
CirioBreakAccess.SetBreakAtAbsAddr[stack.breaks, addr, SourceFileOpsExtras.noPosition, stopAll];
RETURN [NIL];
};
eMsg: ROPE;
eMsg ← Protect[inner, reports];
IF eMsg # NIL THEN IO.PutF[reports, "%g\N", [rope[eMsg]]];
END;
GetBreakAddrFromPosition: PROC [stack: Stack, pos: SourceFileOpsExtras.Position, reports: IO.STREAM] RETURNS [actual: SourceFileOpsExtras.Position ← SourceFileOpsExtras.noPosition, absPC: CARD ← 0] = {
srcFileName: PATH ~ pos.fileName;
srcFile: SystemInterface.CirioFile;
breakAddr: REF NewRMTW.CedarBreakAddress;
ropes: LIST OF ROPE;
shortName: PFSNames.Component;
ext: RS.RopePart;
parsedShort: RS.RopeSeq;
IO.PutF[reports, "\Tselection is at %g.\n", [rope[SourceFileOpsExtras.FullFormatPosition[pos]]] ];
IF srcFileName = NIL THEN {
IO.PutRope[reports, "Selection not in a source file; aborting.\N"];
RETURN};
srcFile ← SystemInterface.GetCirioFile[stack.fileSet, srcFileName, pos.uniqueID];
IF srcFile=NIL THEN {
reports.PutRope["Couldn't access source file!\n"];
RETURN};
shortName ← srcFileName.ShortName[];
parsedShort ← RS.ParsePartToSeq[MPN.ComponentName[shortName], '.];
ext ← parsedShort.Fetch[parsedShort.Length[]-1];
SELECT TRUE FROM
ext.Equal[RP.Make["mesa"], FALSE], ext.Equal[RP.Make["cedar"], FALSE] => {
mesaSourcePos: INT ~ pos.index[char].first;
breakAddr: REF NewRMTW.CedarBreakAddress ← NewRMTW.GetAbsAddressForBreak[stack.cedarModules, srcFile, stack.lsh, mesaSourcePos];
ropes ← NewRMTW.GetRopesForCedarBreakAddress[breakAddr];
IF breakAddr#NIL THEN {
actual ← [pos.fileName, pos.uniqueID, [
[breakAddr.correspondingMesaPosition, SourceFileOpsExtras.noIndex],
SourceFileOpsExtras.noRange]];
absPC ← breakAddr.absPC}
ELSE absPC ← 0};
ext.Equal[RP.Make["c"], FALSE] => {
breakAddr: REF RCTW.CBreakAddress ~ RCTW.GetAbsAddressForBreak[stack.fileSet, srcFile, stack.lsh, pos.index[line].first];
ropes ← RCTW.DescribeCBreakAddress[breakAddr];
IF breakAddr#NIL THEN {
actual ← [pos.fileName, pos.uniqueID, [
SourceFileOpsExtras.noRange,
[breakAddr.stmtLineNumber, SourceFileOpsExtras.noIndex] ]];
absPC ← breakAddr.absPC}
ELSE absPC ← 0};
ENDCASE => {
reports.PutRope["Source is not in a recognized language (Mesa or C); aborting.\n"];
RETURN};
FOR rps: LIST OF ROPE ← ropes, rps.rest WHILE rps # NIL DO
SystemInterface.ShowReport[rps.first, $normal];
ENDLOOP;
RETURN};
support
RopeForDbgMsg: PROC[msg: INT] RETURNS[ROPE] =
BEGIN
RETURN[SELECT msg FROM
CirioNubAccess.DbgMsgNone => "None",
CirioNubAccess.DbgMsgNoHandlerRequest => "NoHandlerRequest",
CirioNubAccess.DbgMsgHandlerRequest => "HandlerRequest",
CirioNubAccess.DbgMsgBadProceedRequest => "BadProceedRequest",
CirioNubAccess.DbgMsgBreakRequest => "BreakRequest",
CirioNubAccess.DbgMsgClientRequest => "ClientRequest",
CirioNubAccess.DbgMsgProceed => "Proceed",
CirioNubAccess.DbgMsgExit => "Kill",
CirioNubAccess.DbgMsgAbort => "Abort",
ENDCASE => "??"];
END;
RopeForCCError: PROC[case: CCTypes.CCErrorCase, msg: ROPE] RETURNS[ROPE] =
BEGIN
msg1: ROPESELECT case FROM
none => "internal Cirio error",
syntax => "syntax error",
operation => "illegal operation",
typeConformity => "incompatible types",
unimplemented => "unimplemented feature",
cirioError => "internal Cirio error",
ENDCASE => "internal Cirio error";
msg2: ROPEIF Rope.Length[msg] = 0 THEN "" ELSE ": ";
RETURN[Rope.Cat["failure due to ", msg1, msg2, msg]];
END;
Interpreter
note: calls on this procedure should be protected by Protect.
we assume that cc has been prepared with a name scope by
cc.nameScope ← CCTypes.CreateCompoundNameScope[ampersandContext1, ampersandContext2, frameNode, cc], or
cc.nameScope ← CCTypes.CreateCompoundNameScope[NIL, NIL, frameNode, cc]
In addition, we assume that the connection (reachable as &&H) has its tsOut field set to reports.
ParseProc: TYPE ~ PROC[line: ROPE, reports: IO.STREAM] RETURNS[CirioSyntacticOperations.ParseTree];
InterpretLine: PROC[to: IO.STREAM, line: ROPE, depth, width: INT, cc: CC, debugOut: IO.STREAM, stripNodes: BOOLEAN, parser: ParseProc, case: Language, reports: IO.STREAM] =
BEGIN
given that the name scope has been set in CC, we can continue
showTypeFlag: BOOLEANFALSE;
showCode: BOOLFALSE;
evalit: BOOLTRUE;
lineLength: INT;
ptree: CirioSyntacticOperations.ParseTree;
tc: CirioTypes.TypedCode;
nd: CirioTypes.Node;
amNdType: CirioTypes.Type;
showNode: CirioTypes.Node;
WHILE (lineLength ← Rope.Length[line]) # 0 DO
SELECT TRUE FROM
Rope.Fetch[line, lineLength-1] = '\n =>
Strip off the trailing CR
line ← Rope.Replace[line, lineLength-1, 1];
Rope.Fetch[line, lineLength-1] = '? =>
process trailing ? character
BEGIN
IF showTypeFlag THEN evalit ← FALSE;
line ← Rope.Replace[line, lineLength-1, 1];
showTypeFlag ← TRUE;
END;
Rope.Fetch[line, lineLength-1] = '! =>
process trailing ! character
BEGIN
line ← Rope.Replace[line, lineLength-1, 1];
depth ← depth + 1;
width ← width + 10;
END;
Rope.Fetch[line, lineLength-1] = '$ =>
process trailing $ character
BEGIN
line ← Rope.Replace[line, lineLength-1, 1];
showCode ← TRUE; debugOut ← reports;
END;
ENDCASE => EXIT;
ENDLOOP;
do we have any text left?
IF lineLength = 0 THEN RETURN;
Parse the (stripped) line.
ptree ← parser[line, reports];
IF debugOut # NIL THEN IO.PutF[debugOut, "Parse Tree: %g\n", IO.rope[CirioSyntacticOperations.ShowParseTree[ptree, cc]]];
Generate typed Cirio code from the parse tree.
IF showTypeFlag THEN {
To show the type of the expression typed by the user we use the following algorithm: If the expression can be interpreted as a lefthand side expression then we do so and show the type of that (this allows users to see the type of a variable independent of what its value is; in particular, REF T variables whose value is NIL will be shown with type REF T instead of REF NIL). If the expression cannot be interpreted as a lefthand side expression then we evaluate it as a righthand side expression (just as if we were going to show its value) and show the type of that. We determine whether an expression can be treated as a lefthand side expression by trying to compile it that way and catching the error if it can't.
ENABLE CCTypes.CCError => {
GO TO lhsError;
};
At present C can't handle left hand sides (gross error)
IF case = C THEN GOTO lhsError;
Try compiling the expression as a lefthand side and catch the error if it can't.
tc ← CirioSyntacticOperations.CompileForLHS[ptree, cc];
IF showCode THEN IO.PutF[debugOut, "Code: %g\n", [rope[CedarCode.ShowCode[tc.code]]]];
Show the type of the resulting typed code and return that as result from this procedure.
to.PutRope["(type)"];
CCTypes.BreakPrintType[to, tc.type, depth, width, cc, " "];
RETURN;
EXITS
We failed in trying to treat the expression as a lefthand side. Just fall through to the case of evaluating the expression and then show the type of the result instead of the value of the result.
lhsError => NULL;
};
tc ← CirioSyntacticOperations.CompileForRHS[ptree, CCTypes.GetAnyTargetType[cc], cc];
IF showCode THEN IO.PutF[debugOut, "Code: %g\n", [rope[CedarCode.ShowCode[tc.code]]]];
When the user's typed two question-marks, that means just use the compiled type.
IF NOT evalit THEN {
to.PutRope["(type)"];
CCTypes.BreakPrintType[to, tc.type, depth, width, cc, " "];
RETURN};
Interprete the code generated to obtain a result node for the expression.
nd ← CedarCode.Interpret[tc.code, cc, debugOut];
Determine whether we need to strip the result node of an ampersand context "wrapper".
amNdType ← CCTypes.GetNodeType[cc];
showNode ← IF (stripNodes AND CCTypes.Conforms[CedarCode.GetTypeOfNode[nd], amNdType, cc]) THEN AmpersandContext.StripAMNode[nd] ELSE nd;
Return the result obtained from evaluating the expression.
IF showTypeFlag
THEN {
We want to show the type of the evaluated expression.
showType: CirioTypes.Type ← CedarCode.GetTypeOfNode[showNode];
to.PutRope["(type)"];
CCTypes.BreakPrintType[to, showType, depth, width, cc, " "];
RETURN}
ELSE {
We want to show the value of the evaluated expression.
CedarCode.ShowNode[to, showNode, depth, width, cc];
RETURN};
END;
Error Handling
treatment: {catch, reject, oz} ← catch;
returns what inner returns if no problem, otherwise returns an error report
it is up to the client to figure out what to do with the report.
if the client would be returning a rope, then the client will probably return this rope.
if the client would not be returning a rope, then the client should feed it to report.
Protect: PUBLIC PROC[inner: PROC RETURNS[ROPE], reports: IO.STREAM] RETURNS[ROPE] = {
eCase: CCTypes.CCErrorCase ← none;
eMsg: ROPENIL;
ToGo: PROC RETURNS [BOOL] ~ {
SELECT treatment FROM
catch => RETURN [TRUE];
reject => RETURN [FALSE];
oz => {CallDebugger[]; RETURN[TRUE]};
ENDCASE => ERROR};
nest a block so that eCase and eMsg are visible at error
{
ENABLE {
SystemInterface.ShowReport => IF reports#NIL THEN {
NewRMTW.ShowReportByLevel[reports, msgText, priority];
IO.PutF[reports, "%g\N", IO.rope[msgText]];
RESUME};
CCTypes.CCError => {
eCase ← case;
eMsg ← msg;
IF ToGo[] THEN GOTO error ELSE REJECT};
MobAccess.MobError => {
eCase ← cirioError;
eMsg ← IO.PutFR["MobAccess.MobError[%g] (should be handled lower in Cirio)", [rope[msg]] ];
IF ToGo[] THEN GOTO error ELSE REJECT};
CirioMemory.Error => {
eCase ← cirioError;
eMsg ← msg;
IF ToGo[] THEN GOTO error ELSE REJECT};
CirioTargets.Error => {
eCase ← cirioError;
eMsg ← msg;
IF ToGo[] THEN GOTO error ELSE REJECT};
CirioNub.Error => {
eCase ← cirioError;
eMsg ← IO.PutFR["CirioNub.Error[%g] - you're probably pretty dead", [atom[code]] ];
IF ToGo[] THEN GOTO error ELSE REJECT};
CirioNubAccess.RemoteNilFault => {
eCase ← operation;
eMsg ← "debuggee NIL fault";
IF ToGo[] THEN GOTO error ELSE REJECT};
CirioNubAccess.RemoteAddrFault => {
eCase ← cirioError;
eMsg ← "debuggee Address fault";
IF ToGo[] THEN GOTO error ELSE REJECT};
CirioNubAccess.Error => {
eCase ← cirioError;
eMsg ← msg;
IF ToGo[] THEN GOTO error ELSE REJECT};
ObjectFiles.UnreadableDotO => {
eCase ← cirioError;
eMsg ← IO.PutFR["ObjectFiles.UnreadableDotO[%g] (should be handled lower in Cirio)", [rope[msg]] ];
IF ToGo[] THEN GOTO error ELSE REJECT};
ObjectFiles.UnreadableObjectFile => {
eCase ← cirioError;
eMsg ← IO.PutFR["ObjectFiles.UnreadableObjectFile[%g] (should be handled lower in Cirio)", [rope[msg]] ];
IF ToGo[] THEN GOTO error ELSE REJECT};
FS.Error => {
eCase ← cirioError;
eMsg ← IO.PutFR["FS.Error[%g, %g]", [atom[error.code]], [rope[error.explanation]] ];
IF ToGo[] THEN GOTO error ELSE REJECT};
PFS.Error => {
eCase ← cirioError;
eMsg ← IO.PutFR["PFS.Error[%g, %g]", [atom[error.code]], [rope[error.explanation]] ];
IF ToGo[] THEN GOTO error ELSE REJECT};
VM.AddressFault => {
eCase ← cirioError;
eMsg ← "local debugger Address fault";
IF ToGo[] THEN GOTO error ELSE REJECT};
SafeStorage.NarrowRefFault => {
eCase ← cirioError;
eMsg ← "local debugger NarrowRefFault";
IF ToGo[] THEN GOTO error ELSE REJECT};
RuntimeError.ArithmeticFault => {
eCase ← cirioError;
eMsg ← "local debugger ArithmeticFault";
IF ToGo[] THEN GOTO error ELSE REJECT};
RuntimeError.BoundsFault => {
eCase ← cirioError;
eMsg ← "local debugger BoundsFault";
IF ToGo[] THEN GOTO error ELSE REJECT};
RuntimeError.DivideCheck => {
eCase ← cirioError;
eMsg ← "local debugger DivideCheck";
IF ToGo[] THEN GOTO error ELSE REJECT};
RuntimeError.ZeroDivisor => {
eCase ← cirioError;
eMsg ← "local debugger ZeroDivisor";
IF ToGo[] THEN GOTO error ELSE REJECT};
RuntimeError.Uncaught => {
eCase ← cirioError;
TRUSTED {eMsg ← PreDebug.Explain[signal, LOOPHOLE[parameters]]};
IF ToGo[] THEN GOTO error ELSE REJECT};
ABORTED => {
eCase ← cirioError;
eMsg ← "aborted";
IF ToGo[] THEN GOTO error ELSE REJECT};
};
RETURN[inner[]];
EXITS
error => RETURN[RopeForCCError[eCase, eMsg]];
};
};
CallDebugger: PROC [] RETURNS [] ~ TRUSTED MACHINE CODE {
"XR�llDebugger"
};
TreatmentCmd: PROC [cmd: Commander.Handle] RETURNS [result: REFNIL, msg: ROPENIL] --Commander.CommandProc-- ~ {
argv: CommanderOps.ArgumentVector ~ CommanderOps.Parse[cmd];
SELECT argv.argc FROM
2 => SELECT TRUE FROM
argv[1].Equal["catch"] => treatment ← catch;
argv[1].Equal["reject"] => treatment ← reject;
argv[1].Equal["oz"] => treatment ← oz;
ENDCASE => RETURN[$Failure, "Usage: CirioBugTreatment [catch|reject|oz]"];
1 => NULL;
ENDCASE => RETURN[$Failure, "Usage: CirioBugTreatment [catch|reject|oz]"];
cmd.out.PutF["Cirio's bug treatment now = %g.\n", [rope[SELECT treatment FROM catch => "catch", reject => "reject", oz => "oz", ENDCASE => ERROR]] ];
RETURN};
printDepth: CARDABS[UserProfile.Number[key: "Cirio.PrintDepth", default: 3]];
printWidth: CARDABS[UserProfile.Number[key: "Cirio.PrintWidth", default: 30]];
ChangePrintDepthAndWidth: Commander.CommandProc ~ {
ENABLE Convert.Error => GOTO usage;
numArgs:CARD ← CommanderOps.NumArgs[cmd];
IF numArgs = 3 THEN {
depth: CARD ← Convert.CardFromRope[CommanderOps.NextArgument[cmd]];
width: CARD ← Convert.CardFromRope[CommanderOps.NextArgument[cmd]];
IO.PutF[cmd.out, "Print depth changed from %g to %g.\nPrint width changed from %g to %g.\n", IO.card[printDepth], IO.card[depth], IO.card[printWidth], IO.card[width]];
printDepth ← depth;
printWidth ← width;
}
ELSE
{
IF numArgs # 1 THEN GOTO usage;
IO.PutF[cmd.out, "Current depth: %g width: %g\n", IO.int[printDepth], IO.int[printWidth]];
};
EXITS
usage => IO.PutF[cmd.out, "Usage: ChangeCirioPrintDepthAndWidth [depth width\n"];
};
Commander.Register["CirioBugTreatment", TreatmentCmd, "[catch|reject|oz] -- set or query Cirio's bug treatment"];
Commander.Register["ChangeCirioPrintDepthAndWidth", ChangePrintDepthAndWidth, "Set or query Cirio's print depth and width."];
END..