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; DebugFlag: BOOLEAN _ FALSE; CedarCase: TYPE = {yes, unknown, no}; CCE: ERROR[case: CCTypes.CCErrorCase, msg: ROPE _ NIL] _ CCTypes.CCError; Stack: TYPE = REF StackBody; StackBody: PUBLIC TYPE = StackCirioPrivate.StackBody; famousPath: FamousPath.DirectoryList ~ FamousPath.Get["Cirio"]; cParseTable: OneCasabaParser.ParserTable _ NIL; stdMargin: INT _ 60; debugSS: BOOL _ FALSE; 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; 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 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; 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, "XR_CallDebugger"]] 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 { 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 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 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 { breakWorld: BreakWorldArchitecture.BreakWorld _ CirioBreakAccess.BreakWorldFromBreakSet[stack.breaks]; address: BreakWorldArchitecture.Address _ BreakWorldArchitecture.NewAddress[breakWorld, LOOPHOLE[current.absPC+(9*4)]]; breakpointPC: CARD _ LOOPHOLE[BreakWorldArchitecture.PeekContents[address]]; loadedModule _ LSA.GetLoadedModuleInfoFromAbsPC[stack.lsh, breakpointPC]; IF loadedModule = NIL THEN RETURN [NIL]; current.absPC _ breakpointPC; 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; BuildFrameInfo: PROC[stack: Stack, index, absPC, stackPointer: CARD, previous: BasicFrameInfo] RETURNS[BasicFrameInfo] = TRUSTED BEGIN IF stackPointer = 0 THEN GOTO beyondColdestFrame; -- used for dummy stack BEGIN 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 { breakWorld: BreakWorldArchitecture.BreakWorld _ CirioBreakAccess.BreakWorldFromBreakSet[stack.breaks]; address: BreakWorldArchitecture.Address _ BreakWorldArchitecture.NewAddress[breakWorld, LOOPHOLE[absPC+(9*4)]]; breakpointPC: CARD _ LOOPHOLE[BreakWorldArchitecture.PeekContents[address]]; loadedModule _ LSA.GetLoadedModuleInfoFromAbsPC[stack.lsh, breakpointPC]; IF loadedModule = NIL THEN RETURN [NIL]; absPC _ breakpointPC; stackPointer _ stackPointer+288; }; stackPointerBA _ CirioMemory.PtrToBa[stackPointer]; 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 { 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; 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]; 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; 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]; 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"]; 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]; 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]; 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 => 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 ~ ". "; 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]; 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] = 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; 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 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}; 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: ROPE _ SELECT 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: ROPE _ IF Rope.Length[msg] = 0 THEN "" ELSE ": "; RETURN[Rope.Cat["failure due to ", msg1, msg2, msg]]; END; 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 showTypeFlag: BOOLEAN _ FALSE; showCode: BOOL _ FALSE; evalit: BOOL _ TRUE; 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 => line _ Rope.Replace[line, lineLength-1, 1]; Rope.Fetch[line, lineLength-1] = '? => BEGIN IF showTypeFlag THEN evalit _ FALSE; line _ Rope.Replace[line, lineLength-1, 1]; showTypeFlag _ TRUE; END; Rope.Fetch[line, lineLength-1] = '! => BEGIN line _ Rope.Replace[line, lineLength-1, 1]; depth _ depth + 1; width _ width + 10; END; Rope.Fetch[line, lineLength-1] = '$ => BEGIN line _ Rope.Replace[line, lineLength-1, 1]; showCode _ TRUE; debugOut _ reports; END; ENDCASE => EXIT; ENDLOOP; IF lineLength = 0 THEN RETURN; ptree _ parser[line, reports]; IF debugOut # NIL THEN IO.PutF[debugOut, "Parse Tree: %g\n", IO.rope[CirioSyntacticOperations.ShowParseTree[ptree, cc]]]; IF showTypeFlag THEN { ENABLE CCTypes.CCError => { GO TO lhsError; }; IF case = C THEN GOTO lhsError; tc _ CirioSyntacticOperations.CompileForLHS[ptree, cc]; IF showCode THEN IO.PutF[debugOut, "Code: %g\n", [rope[CedarCode.ShowCode[tc.code]]]]; to.PutRope["(type)"]; CCTypes.BreakPrintType[to, tc.type, depth, width, cc, " "]; RETURN; EXITS lhsError => NULL; }; tc _ CirioSyntacticOperations.CompileForRHS[ptree, CCTypes.GetAnyTargetType[cc], cc]; IF showCode THEN IO.PutF[debugOut, "Code: %g\n", [rope[CedarCode.ShowCode[tc.code]]]]; IF NOT evalit THEN { to.PutRope["(type)"]; CCTypes.BreakPrintType[to, tc.type, depth, width, cc, " "]; RETURN}; nd _ CedarCode.Interpret[tc.code, cc, debugOut]; amNdType _ CCTypes.GetNodeType[cc]; showNode _ IF (stripNodes AND CCTypes.Conforms[CedarCode.GetTypeOfNode[nd], amNdType, cc]) THEN AmpersandContext.StripAMNode[nd] ELSE nd; IF showTypeFlag THEN { showType: CirioTypes.Type _ CedarCode.GetTypeOfNode[showNode]; to.PutRope["(type)"]; CCTypes.BreakPrintType[to, showType, depth, width, cc, " "]; RETURN} ELSE { CedarCode.ShowNode[to, showNode, depth, width, cc]; RETURN}; END; treatment: {catch, reject, oz} _ catch; Protect: PUBLIC PROC[inner: PROC RETURNS[ROPE], reports: IO.STREAM] RETURNS[ROPE] = { eCase: CCTypes.CCErrorCase _ none; eMsg: ROPE _ NIL; ToGo: PROC RETURNS [BOOL] ~ { SELECT treatment FROM catch => RETURN [TRUE]; reject => RETURN [FALSE]; oz => {CallDebugger[]; RETURN[TRUE]}; ENDCASE => ERROR}; { ENABLE { SystemInterface.ShowReport => IF reports#NIL THEN { NewRMTW.ShowReportByLevel[reports, msgText, priority]; 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_CallDebugger" }; TreatmentCmd: PROC [cmd: Commander.Handle] RETURNS [result: REF _ NIL, msg: ROPE _ NIL] --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: CARD _ ABS[UserProfile.Number[key: "Cirio.PrintDepth", default: 3]]; printWidth: CARD _ ABS[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.. : 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 Debugging aids Types Variables Stacks The caller is responsible for eventually calling CloseStack. loaded module information is needed by the MIPS target routines nextHotFramePC: CARD _ CirioNubAccess.Read32BitsAsCard[[nub, desiredHotFrameSP+(15*4), 0, FALSE, TRUE]]; nextHotFrameSP: CARD _ FpFromSp[nub, desiredHotFrameSP ! CirioNubAccess.RemoteAddrFault => GOTO beyondColdestFrame]; Start the summary from the "hotter of" either the hotFrame or the currentFrame. 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. FIX: Use PFS Extensions to handle this 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 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. More checking must be done to insure that we are really in a patch space area and that this is an SGI object 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. 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}; basic: REF LSA.BasicPCInfo _ LSA.GetBasicPCInfo[stack.lsh, absPC]; framePointer: CARD _ CirioMemory.PtrToBa[stack.target.FpFromSp[stack.target, CirioMemory.PtrToBa[stackPointer] ! CirioNubAccess.RemoteAddrFault => GOTO beyondColdestFrame]]; 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. More checking must be done to insure that we are really in a patch space area and that this is an SGI object The stack for a patch is a fixed size of 288 bytes. This size is determined in MIPSBreakpoint.mesa during InstallClosureCaller[]. I changed the fourth parameter of FpFromSp to the absPC and not the stack pointer PC. jas additional flush if SunOS5 Stack examination now we compute the kind here is the loop 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. 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. Display the mesa source code point. reports.PutF["C source line = %g; can't yet open it for you.\n", [integer[pos.index[line].first]]]; we try to install Cedar and C contexts. 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. Clears all currently set breakpoints. break points (are here because they are needed by both remote and local tools) Set a breakpoint at the absolute PC corresponding to the specified code point. support 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. given that the name scope has been set in CC, we can continue Strip off the trailing CR process trailing ? character process trailing ! character process trailing $ character do we have any text left? Parse the (stripped) line. Generate typed Cirio code from the parse tree. 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. At present C can't handle left hand sides (gross error) Try compiling the expression as a lefthand side and catch the error if it can't. Show the type of the resulting typed code and return that as result from this procedure. 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. When the user's typed two question-marks, that means just use the compiled type. Interprete the code generated to obtain a result node for the expression. Determine whether we need to strip the result node of an ampersand context "wrapper". Return the result obtained from evaluating the expression. We want to show the type of the evaluated expression. We want to show the value of the evaluated expression. Error Handling 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. nest a block so that eCase and eMsg are visible at error IO.PutF[reports, "%g\N", IO.rope[msgText]]; ΚB/– "cedar" style•NewlineDelimiter ™codešœ™K™NKšœ#™#K™;K™&K™(K™(K™&K™.K™ —K˜šΟk ˜ Kšœœ˜$Kšœœ1˜MKšœœv˜ƒKšœ œ/˜>KšœœC˜\Kšœœ˜.Kšœ˜Kšœœ˜•Kšœ ˜ Kšœ œ ˜Kšœœ’˜¦Kšœœ9˜WKšœ ˜ Kšœ œ)˜9K˜ K˜ Kšœœ˜#Kšœœ˜Kšœ˜Kšœ œ"˜2Kšœœu˜Kšœœ˜Kšœ˜KšœœΖ˜ΫKšœ œ ˜K˜ Kšœœ˜+Kšœœ©˜ΆKšœ œ_˜pKšœœ2˜GKšœœ%˜.Kšœ œ œ ˜,Kšœœ˜K˜ KšœœŸ˜©Kšœ˜K˜ Kšœ ˜ Kšœ œC˜UKšœ œ˜"KšœœH˜aKšœ œ ˜K˜K˜KšœœX˜mK˜Kšœ œ ˜Kšœœ˜Kšœœ˜1Kšœœ˜.K˜—šΟnœœ˜Kšœœ ˜Kš œ™œœfœœ˜œ&˜ιKšœ˜#—Kšœœžœœœœœ œœœ)˜ΊK˜™K˜Kšž œœœ˜—K˜K˜™K™Kšœ œ˜%K˜Kšœœ!œœ˜IK˜Kšœœœ ˜Kšœ œœ˜5˜K˜——™ K™Kšœ?˜?K˜Kšœ+œ˜/K˜Kšœ œ˜Kšœ œœ˜˜K˜——™˜K™Kšœœx˜ŒK˜Kšœ#˜#Kšœ#˜#Kšœ˜—šœ˜Kšœ˜—Kšœ˜K˜šœœ ˜Kšœœ˜ K˜%K˜%Kšœ˜Kšœ ˜ Kšœ˜Kšœ ˜ Kšœ˜Kšœ˜Kšœ˜Kšœ ˜ Kšœ ˜ Kšœ˜Kšœ œ˜Kšœ˜Kšœ˜Kšœ œ˜Kšœœ˜Kšž œ ˜Kšœ˜—K˜-Kšœ˜Kšœ˜——K˜šžœœœMœΧœ\ž œ)œœœ ˜ξKš˜šœœ ˜Kšœœ˜ K˜%K˜%Kšœ˜Kšœ ˜ Kšœ˜Kšœ ˜ Kšœ˜Kšœ˜K˜Kšœ ˜ Kšœ ˜ Kšœ˜Kšœ œ˜K˜K˜Kšœ œ˜Kšœœ˜Kšž œ ˜Kšœ˜—K˜-Kšœ˜Kšœ˜—K˜K˜šžœœœœœœœœœ˜eKšœ˜Kšœœœ˜Kšœœ˜ Kšœœ˜ Kšœ˜K˜Kšœ(˜(Kš œ œœœœ˜GKš œ œœœ%œ˜UK˜K™OK™šœ˜Kš œ œœœœ˜]—Kš œœœœœ˜UK˜š œ=œ œœœ ˜fšœœœœ˜Kšœ œœœ(˜NKš œœœ1œœœ˜\Kš œœœ.œœ˜cKš œœœ8œœ˜qKšœœœ ˜EKšœœ˜ —Kšœœ˜ Kšœœœœ ˜5Kšœ˜—Kšœ œœ˜+Kšœ˜—K˜šž œœœœœœœ˜WK˜Kšœœœ˜K˜Kšœœœœ˜$Kšœœ ˜Kšœœ ˜Kšœœ˜KšœR˜RK˜Kšœœœœ˜$šœBœ œœœœœ ˜„šœœœœ˜Kšœ œœœ(˜NKš œœœ1œœœ˜\K˜šœœœ˜Kšœœœ˜šœhœ˜pKšœ(˜(Kšœ˜—KšœH˜HšœVœ˜^K™¬š œœœœ˜@Kšœ(˜(—š˜Kšœ)˜)—Kšœ˜—KšœB˜BšœVœ˜^Kšœ(˜(Kšœ˜—KšœK˜KšœVœ˜^Kšœ(˜(Kšœ˜—šœaœ˜iKšœ(˜(Kšœ˜—šœaœ˜iKšœ(˜(Kšœ˜—KšœC˜CšœVœ˜^Kšœ(˜(Kšœ˜—KšœF˜FšœVœ˜^Kšœ(˜(Kšœ˜—šœbœ˜jKšœ(˜(Kšœ˜—šœbœ˜jKšœ(˜(Kšœ˜—K˜K˜—šœ%œ˜-Kšœ˜K˜K˜—Kšœœ˜ K˜—Kšœœ˜ Kšœœœœ ˜5Kšœ˜—Kšœ˜K˜KšžœœœœœœœΟcœœ œœ˜ƒKšœ˜Kšœœœ˜šœDœ œ˜[šœœœœ˜Kšœ œœœ(˜NKšœ6œœœ˜Iš œœœœ/œ œ˜ZKšœ'œœœ˜:Kšœ˜—Kšœœ˜ —Kšœœ˜%Kšœœœœ%˜:Kšœ˜—Kšœ˜—K˜šžœœœœœœŸœœœŸœœ˜rKš˜K™&Kšœ œœ˜(Kšœ œ ˜-Kšœ œ#˜1Kšœœœœœœœ˜]Kšœ˜—K˜K˜šž œœœ˜8Kš˜šœœ˜KšœNœ˜S—Kšœ˜Kšœ˜K˜—šžœœœ˜8Kšœ>œ˜J—˜K˜—šž œœ(œ˜XKš˜šœœ˜Kš˜Kšœœ™Kšœœ™Kšœ œ™'KšœœTœœ™mKšœœY™dK™K™K™4K™6K™7K™7K™CK™Kšœ!˜!Kšœ!˜!Kšœ˜Kšœœ˜ Kšœ$˜$Kšœœ˜Kšœœœœ˜.š œœœœœ˜0Kšœœ9˜KKšœœ˜ Kšœ˜—Kšœœ ˜Kšœœ ˜Kšœœ˜KšœR˜RK˜š œœœœ˜@Kšœœ˜$—K˜šœœœœœœœ˜XKšœ˜K™ KšœΧ™Χ—˜Kšœf˜fKšœXœ˜wK™lKšœœœ/˜LKšœœ7˜IKš œœœœœ˜(Kšœ˜Kšœ‚™‚K™CKšœ0˜0Kšœ—˜—Kšœ˜—Kšœ8˜8Kšœ8˜8Kšœc˜cKšœ&˜&Kšœj˜jKšœ3˜3KšœY˜YKšœ›˜›Kšœ!œœœ˜4Kšœ˜—Kšœ˜Kšœ˜—K˜š žœœ"œœœ™LKšœœ™Kšœœ™Kšœ œ™'Kšœ@™F—K˜š žœœ+œœ˜€Kš˜Kšœœœœ"™BšœœœŸ˜IKš˜Kšœœœ™­K™Kšœ˜Kšœ$˜$Kšœ$˜$Kšœœ˜Kšœ(˜(Kšœœœ˜'šœœœœ˜0Kšœœ1˜CKšœœ˜ Kšœ˜—Kšœœ ˜Kšœœ ˜Kšœœ˜KšœR˜Rš œœœœ˜@Kšœœ˜$—K˜Kšœ œœ˜*šœœœœœœœ˜XKšœ˜K™ Kšœ›™›K˜Kšœf˜fKšœXœ˜oK™lKšœœœ/˜LKšœœ7˜IKš œœœœœ˜(Kšœ˜Kšœ‚™‚Kšœ ˜ Kšœ˜—K˜Kšœ3˜3K™YKšœ}œ˜–Kšœ3˜3K˜Kšœl˜lKšœ)œœ˜HK˜šœœ˜Kšœ˜Kšœ˜Kšœ ˜ Kšœ ˜ Kšœ ˜ Kšœ˜—Kšœœœ˜1Kšœ˜ Kšœ˜—K˜š˜Kšœœœ˜"—Kšœ˜—K˜šžœœœœ˜5Kš˜Kšœœœ˜Kšœœ˜5šœœœ˜"Kšœ™šœ$œ!œ˜Ršœ&œ˜0Kšœ œ˜$——K˜GK˜—Kšœ˜—K˜Kšžœœœ˜#šžœœ˜&Kšœ˜Kšœœœ˜Kšœœ˜!š œœœœ˜CKšœ&˜&—šœœœ˜šœ4œ œ˜KKšœ œ˜Kšœ˜—šœ5œ œ˜LKšœ œ˜Kšœ˜—K˜—Kšœ˜—K˜šž œœœœœ œœœœœ˜dKš˜Kšœœœ˜K˜šžœœœœ˜Kšœœ˜!šœœ˜Kšœ0˜0Kš œœœœœ˜Kš œœœ œœ ˜KK˜šœœ œ˜K˜7Kšœ˜ —šœœ˜šœ˜KšœA˜AKšœ˜ —šœœœ ˜2Kšœd˜dKšœ˜ —˜KšœΉ˜ΉKšœ˜ —K˜Kšœ/œ˜5šœ˜KšœFœœ˜_KšœB˜F—Kšœ˜—Kšœ œ˜—KšœR˜VKšœœ˜—K˜Kšœ˜Kšœ˜—K˜K˜K˜—™K˜K˜šž œœœœœœœœ˜`Kšœœœ˜šœœœœ˜Kšœœ ˜Kš œ œœœœœ˜-Kšœ'œ˜.Kšœ3˜3Kšœ˜Kšœœ˜ —K˜Kšœœ˜%Kšœœœœ%˜:šœœœœ%˜LKšœœ˜—Kšœ˜—K˜šž œœœœœ œœœœœ˜Kš˜Kšœœœ˜šœœœœ˜Kš˜Kš œœœœœœ˜[K˜KšœŸ$˜8K˜š œ œœœœ˜GKšœ0˜0Kšœœœœ˜"Kšœ˜K˜$Kšœ˜—K˜š œ œœœœ˜GKšœ9˜9Kšœœœœ˜"Kšœ˜K˜$Kšœ˜K˜—Kšœ4˜4šœœœ˜0Kšœ$œ˜+—Kšœœ˜ Kšœ˜K˜—Kšœœ˜ Kšœ˜Kšœœœœ%˜:Kšœ˜—K˜šžœœœœœ œœœœœ˜”Kš˜Kšœœœ˜šœœœœ˜Kš˜Kšœœ ˜*K˜KšœŸ$˜œ˜ZKšœ˜K˜—Kšœ ˜ Kšœ œ˜%K˜Kšœœœ œœœœ ˜^K˜šœ˜šœ ˜ Kšœœœœœœœ"˜rK˜4Kšœ#˜#—šœ˜šœ œœ˜Kšœ œH˜WKšœ œœœ@˜YKšœG˜GKšœœœœ˜3KšœN˜NKšœ˜Kšœœ˜Kšœ5˜5—šœœœœœœœ˜JKšœ8˜8—Kšœ˜—šœ œœ˜KšœU˜Xšœ˜ Kšœ0˜0Kš œœœœœ&˜œœ˜ŽKš œœœœ6œœ˜zKšœ œ˜Kšœœ˜!——K˜š œœœœœœ˜:Kšœœ˜/Kšœ˜—Kšœ˜—K˜K˜—™OK™š Πbnœœœœœ˜@Kš˜K˜šœœœœ˜Kš˜Kšœ*˜*Kšœœ˜ Kšœ˜—K˜Kšœœ˜%Kšœœœœ%˜:Kšœ˜—K˜šžœœœ;œœ œœL˜ΟKš˜K˜šœœœœ˜Kšœœ˜ KšœB˜Bšœ œ˜K™NKšœK˜KK˜Kšœ˜K˜—Kšœœ˜ Kšœ˜—K˜Kšœœ˜ K˜Kšœœœœ%˜:Kšœ˜K˜—šžœœœœ œœ œ˜eKš˜K˜šœœœœ˜Kšœ`˜`Kšœœ˜ Kšœ˜—K˜Kšœœ˜ K˜Kšœœœœ%˜:Kšœ˜K˜—š žœœ<œœœPœ ˜ΙKšœ œ˜!K˜#Kšœ œ˜)Kšœœœœ˜Kšœ˜Kšœœ ˜Kšœ œ ˜Kšœ`˜bšœœœ˜KšœA˜CKšœ˜—KšœQ˜Qšœ œœ˜Kšœ2˜2Kšœ˜—Kšœ$˜$Kšœœœ˜BKšœ0˜0šœœ˜š œ œœ œœ˜JKšœœ˜+Kšœ œr˜€Kšœ8˜8šœ œœ˜šœ'˜'KšœC˜CKšœ˜—Kšœ˜—Kšœ ˜—šœ œ œ˜#Kšœ œœœQ˜yKšœœ"˜.šœ œœ˜šœ'˜'Kšœ˜Kšœ;˜;—Kšœ˜—Kšœ ˜—šœ˜ K˜SKšœ˜——š œœœœœœ˜:K˜/Kšœ˜—Kšœ˜K˜—K˜—™K™š ž œœœœœ˜-Kš˜šœœ˜Kšœ$˜$Kšœ<˜˜>Kšœ4˜4Kšœ6˜6Kšœ*˜*Kšœ$˜$Kšœ&˜&Kšœ ˜—Kšœ˜—K˜š žœœ!œœœ˜JKš˜šœœœ˜K˜K˜K˜!K˜'K˜)K˜%Kšœ˜"—Kš œœœœœ˜7Kšœ/˜5Kšœ˜——K˜K˜™ ™K™=™™8Kšœg™gKšœG™G—K™Kšœa™a——Kš œ œœœ œœœ%˜cK˜šž œœœœœœœ œœœ.œœ˜¬Kš˜K˜Kšœ*œ™=K˜Kšœœœ˜Kšœ œœ˜Kšœœœ˜Kšœ œ˜K˜*K˜K˜K˜Kšœ˜K˜šœ&˜-šœœ˜šœ'˜'Kšœ™K˜+—šœ&˜&K™Kš˜Kšœœ œ˜$K˜+Kšœœ˜Kšœ˜—šœ&˜&K™Kš˜K˜+K˜K˜Kšœ˜—šœ&˜&K™Kš˜K˜+Kšœ œ˜$Kšœ˜—Kšœœ˜Kšœ˜K˜——™Kšœœœ˜—™Kšœ˜Kš œ œœœ$œ:˜y—™/šœœ˜š œ’œœœœœΪ™Οšœ˜Kšœœ ˜Kšœ˜—™7Kšœ œœ ˜—™PK˜7Kšœ œœC˜V—™XK˜Kšœ;˜;Kšœ˜—š˜K™ΔKšœ œ˜——K˜—K˜UKšœ œœC˜V—K™Pšœœœ˜K˜Kšœ;˜;Kšœ˜—™IK˜0—™UK˜#Kš œ œ œ>œ"œ˜‰—™:šœ˜šœ˜K™5K˜>K˜Kšœ<˜S