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 =
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: ROPE ← LSA.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: CARD ← LAST[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: ROPE ← LSA.GetRopeForBasicPCInfo[basicPCInfo, frame.absPC, FALSE, long, FALSE, FALSE];
IF basicPCInfo #
NIL
THEN {
tmpRope: Rope.ROPE ← NIL;
IF Rope.Equal[basicPCInfo.procedureName, stack.target.CNameToLoaderName[stack.target, "XRllDebugger"]]
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: ROPE ← PFS.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: CARD ← LOOPHOLE[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: CARD ← LOOPHOLE[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: BOOL ← FALSE;
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
BOOL ←
NIL] =
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 BOOLEAN ← NEW[BOOLEAN ← FALSE];
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: BOOLEAN ← FALSE;
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 ROPE ← LSA.GetRopeListForLoadedFileContainingLoadedModule[frame.ledo];
rope: ROPE ← NIL;
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: ROPE ← IO.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: ROPE ← LSA.GetRopeForBasicPCInfo[frame.basicPCInfo, frame.basic.absPC, TRUE, TRUE, detail, detail];
ropes: LIST OF ROPE ← LSA.GetRopeListForLoadedModuleInfo[frame.ledo];
rope: ROPE ← NIL;
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"];
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
BOOL ←
NIL] =
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.STREAM ← NIL;
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.STREAM ← FS.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.
STREAM ←
NIL]
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;