<<>> <> <> <> <> <> <> <> <> <> <> DIRECTORY AmpersandContext USING[CreateAnAmpersandContext, MakeNodeFromNode, StripAMNode], Atom USING [GetPName], BasicTime USING[Now], CCTypes USING[CCError, CCErrorCase, CreateCedarCompilerContext, CreateNodeFromRefAny], CedarCode USING[GetNodeRepresentation, GetTypeOfNode, LoadThroughIndirectNode, SelectFieldFromNode, StoreThroughIndirectNode], CirioBackstop USING[Protect], CirioBreakAccess USING[CirioBreakSet, CreateCirioBreakSet, ClearAllBreaks, ClearBreakAtAbsAddr, ClearBreakAtIndex, ListBreaks, SetBreakAtAbsAddr, BreakSetBroken], CirioDeltaFace USING[IsDMachine], CirioNub USING [Error], CirioNubAccess USING[CreateRemoteNub, DbgMsgNone, DbgMsgNoHandlerRequest, DbgMsgHandlerRequest, DbgMsgAbort, DbgMsgBadProceedRequest, DbgMsgBreakRequest, DbgMsgClientRequest, DbgMsgExit, DbgMsgProceed, DestroyNub, Error, FileEntry, GetFileEntry, GetThreads, Handle, IssueThreadCommand, KillWorld, LookupSymEntryByName, LookupSymEntryByValue, LookupSymEntryByID, Null, PCInfo, PCtoInfo, Read32BitsAsCard, SchedStateFree, SchedStateReady, SchedStateRun, SchedStateWaitML, SchedStateWaitCV, SchedStateHandlee, SetDBStat, SymEntry, ThreadInfo, WaitSig], CirioTargets USING[Target], CirioTypes USING[CirioAddress, CirioAddressBody, CompilerContext, Node, Type], Commander USING[CommandProc, Register], CommandTool USING[ArgumentVector, Parse], Convert USING[CardFromRope, RopeFromCard], FileNames USING[CurrentWorkingDirectory], IO USING[card, char, Close, Error, PutF, PutFR, PutRope, RopeFromROS, ROS, rope, STREAM], LoadStateAccess USING[CreateLoadStateHandle, LoadStateHandle], LocalCirio USING[Connection, ExtractCcFromConnection, GetConnection, nilBreakDest], NewAmpersandProcs USING[Handle, HandleBody, InstallItems], NewRMTW USING[CedarModuleSet, CreateCedarModuleSet, CreateRemoteMimosaTargetWorld, FlushUnknownFileCache, FlushUnknownSymbolCache, FlushUnknownTypeCodes, RemoteMimosaTargetWorld, ResetSearchPaths], ObjectFiles USING[CreateParsed, GetLineNumForPC, GetPCForLineNum, Module, ModuleFromParsedAndPC, Parsed], OneCasabaParser USING[ParserTable], PBasics USING[BITLSHIFT, BITOR, BITRSHIFT], PFS USING [AbsoluteName, RopeFromPath, PathFromRope], PFSNames USING [PATH, Equal], Process USING [Detach, PauseMsec, priorityBackground, SetPriority], RemoteCirio USING[ThreadProperty], Rope USING[Cat, Concat, Equal, FromChar, Length, Map, Substr, ROPE], SourceFileOpsExtras USING [FullOpenSource, Position], StackCirio USING[FrameDiagnosticInfo, InterpretTextLine, NoteFileCacheFlush, OpenDummyStack, OpenStack, QuickGenPossibleModuleNames, ResetStack, ShowCurrentFrame, ShowQuickSummary, Stack, WalkStack, WalkStackToCProcedure], SystemInterface USING [ShowReport, CloseFileSet, CirioFile, CreateFileSet, FileSet, GetCirioFileFromDebuggee]; RemoteCirioImpl: CEDAR MONITOR LOCKS connection USING connection: Connection IMPORTS AmpersandContext, Atom, BasicTime, CCTypes, CedarCode, CirioBackstop, CirioBreakAccess, CirioDeltaFace, CirioNub, CirioNubAccess, Commander, CommandTool, Convert, FileNames, IO, LoadStateAccess, LocalCirio, NewAmpersandProcs, NewRMTW, ObjectFiles, PBasics, PFS, PFSNames, Process, Rope, SourceFileOpsExtras, StackCirio, SystemInterface EXPORTS RemoteCirio = BEGIN OPEN ObjF: ObjectFiles, LSA: LoadStateAccess; <> DebugFlag: BOOLEAN _ FALSE; <> <> <<>> CC: TYPE = CirioTypes.CompilerContext; CCE: ERROR[case: CCTypes.CCErrorCase, msg: Rope.ROPE _ NIL] _ CCTypes.CCError; <<>> Connection: TYPE = REF ConnectionBody; ConnectionBody: PUBLIC TYPE = MONITORED RECORD[ open: BOOLEAN, doradoWorkingDirectory: Rope.ROPE, serverName: Rope.ROPE, searchDirectories: LIST OF PFSNames.PATH, tsOut: IO.STREAM, -- WARNING: this field is very transient. It is only valid during an interpretation of an expression, and was placed here for the convenience of ampersand routines and (local target wrld) user routines called through the interpreter. ampersandContext1: CirioTypes.Node, ampersandContext2: CirioTypes.Node, cc, localCc: CC, localConnection: LocalCirio.Connection, rmtw: NewRMTW.RemoteMimosaTargetWorld, cedarModules: NewRMTW.CedarModuleSet, nub: CirioNubAccess.Handle, target: CirioTargets.Target, daemon: PROCESS, daemonKillFlag: BOOLEAN, breaks: CirioBreakAccess.CirioBreakSet, fileSet: SystemInterface.FileSet, lsh: LoadStateAccess.LoadStateHandle, aph: NewAmpersandProcs.Handle, cParserTable: OneCasabaParser.ParserTable, remoteWorldRunning: BOOLEAN _ TRUE, dbxActive: BOOLEAN _ FALSE, currentThread: CARD _ 0, threads: REF ThreadSet]; ThreadSet: TYPE = RECORD[SEQUENCE nThreads: CARDINAL OF REF ThreadData]; ThreadData: TYPE = RECORD[ thread: REF CirioNubAccess.ThreadInfo, stack: StackCirio.Stack ]; <> < pair until Close has been called. Note: closing the connection invalidates all RemoteAddresses held for connection.nub.>> <> OpenConnection: PUBLIC PROC[remoteName: Rope.ROPE, portNum: CARD, workingDirectories: LIST OF Rope.ROPE, reports: IO.STREAM] RETURNS[connection: Connection] = { outerMsg: Rope.ROPE _ CirioBackstop.Protect[Openit, reports]; Openit: PROC RETURNS[Rope.ROPE] ~ { connection _ FunctionalOpen[]; RETURN[NIL]}; FunctionalOpen: PROC RETURNS[Connection] ~ { nub: CirioNubAccess.Handle _ NIL; target: CirioTargets.Target _ NIL; fileSet: SystemInterface.FileSet; breaks: CirioBreakAccess.CirioBreakSet; searchDirs: LIST OF PFSNames.PATH _ NIL; lastSearchDir: LIST OF PFSNames.PATH _ NIL; defaultSearchDirs: LIST OF PFSNames.PATH _ LIST[ PFS.PathFromRope["/PCedar/Cirio/"], PFS.PathFromRope["/PCedar/CirioThings/"], PFS.PathFromRope["/PCedar/Atom/"], PFS.PathFromRope["/PCedar/Rope/"] ]; <> ClearBreaksForOpen: PROC RETURNS[Rope.ROPE] = { CirioBreakAccess.ClearAllBreaks[breaks]; RETURN[NIL]}; <> searchDirs _ LIST [PFS.PathFromRope["-compiled:/CirioCompiledData/"]]; lastSearchDir _ searchDirs; FOR thisDir: LIST OF Rope.ROPE _ workingDirectories, thisDir.rest WHILE thisDir # NIL DO lastSearchDir.rest _ LIST [PFS.AbsoluteName[PFS.PathFromRope[thisDir.first]]]; lastSearchDir _ lastSearchDir.rest; ENDLOOP; <> lastSearchDir.rest _ defaultSearchDirs; nub _ CirioNubAccess.CreateRemoteNub[debuggee: remoteName, port: portNum, timeoutMsec: 10000 !CirioNub.Error => { reports.PutF["Failed to open DebugNub connection to port %g on %g.\n", [cardinal[portNum]], [rope[remoteName]] ]; CONTINUE}]; IF nub=NIL THEN RETURN [NIL]; <> target _ NARROW[nub.target]; fileSet _ SystemInterface.CreateFileSet[]; breaks _ CirioBreakAccess.CreateCirioBreakSet[nub, "CirioThingsImpl", "CallDebugger"]; IF breaks.BreakSetBroken[] THEN reports.PutRope["You won't be able to set breakpoints in the debuggee, because I was unable to find CirioThingsImpl.CallDebugger in the debuggee. Are you sure you loaded an unoptimized version of CirioThingsImpl into the debuggee somewhere along the line?\n"]; <> { ENABLE UNWIND => { -- all attempts to give a report will be ignored finalMsg: Rope.ROPE _ CirioBackstop.Protect[ClearBreaksForOpen, reports]; CirioNubAccess.DestroyNub[nub]; SystemInterface.CloseFileSet[fileSet]; IF Rope.Length[finalMsg] # 0 THEN IO.PutF[reports, "%g\N", IO.rope[finalMsg]]; }; cc, lcc: CC; cedarModules: NewRMTW.CedarModuleSet; lsh: LoadStateAccess.LoadStateHandle; rmtw: NewRMTW.RemoteMimosaTargetWorld; ampersandContext1, ampersandContext2: CirioTypes.Node; aph: NewAmpersandProcs.Handle; connection: Connection; IF NOT CirioNubAccess.Null[nub, 7] THEN CCE[cirioError, "debuggee doesn't implement debug nub protocol version 7"]; cc _ CCTypes.CreateCedarCompilerContext[]; cedarModules _ NewRMTW.CreateCedarModuleSet[fileSet, remoteName]; NewRMTW.ResetSearchPaths[cedarModules, searchDirs, BasicTime.Now[]]; lsh _ LoadStateAccess.CreateLoadStateHandle[remoteName, nub, fileSet]; rmtw _ NewRMTW.CreateRemoteMimosaTargetWorld[remoteName, nub, cc, cedarModules, lsh, reports, TRUE]; <> <> aph _ NEW[NewAmpersandProcs.HandleBody_[ out: NIL, -- filled in during a line interpretation in StackCirioImpl rmtw: rmtw, cedarModules: cedarModules, nub: nub, fileSet: fileSet, lsh: lsh]]; connection_ NEW[ConnectionBody_[ open: TRUE, doradoWorkingDirectory: workingDirectories.first, serverName: remoteName, searchDirectories: searchDirs, <> <> cc: cc, localCc: lcc, localConnection: LocalCirio.GetConnection[LocalCirio.nilBreakDest, reports], rmtw: rmtw, cedarModules: cedarModules, nub: nub, target: target, daemon: NIL, daemonKillFlag: FALSE, breaks: breaks, fileSet: fileSet, lsh: lsh, aph: aph, cParserTable: NIL]]; connection.localCc _ LocalCirio.ExtractCcFromConnection[connection.localConnection]; connection.ampersandContext1 _ AmpersandContext.CreateAnAmpersandContext[connection.localCc]; connection.ampersandContext2 _ AmpersandContext.CreateAnAmpersandContext[connection.localCc]; ampersandContext1 _ connection.ampersandContext1; ampersandContext2 _ connection.ampersandContext2; NewAmpersandProcs.InstallItems[connection.ampersandContext2, aph, connection.localCc]; <> IF CirioDeltaFace.IsDMachine[] = FALSE THEN RETURN[connection]; IF TRUE THEN RETURN[connection]; <> <<>> InstallOneAmpersandItem[ampersandContext2, "&&H", CCTypes.CreateNodeFromRefAny[NEW[Connection _ connection], cc], cc]; InstallOneAmpersandItem[ampersandContext2, "&&RdCards", CCTypes.CreateNodeFromRefAny[NEW[PROC[a: CirioTypes.CirioAddress, nCards: CARD] _ RdCards], cc], cc]; InstallOneAmpersandItem[ampersandContext2, "&&RdHexCards", CCTypes.CreateNodeFromRefAny[NEW[PROC[a: CirioTypes.CirioAddress, nCards: CARD] _ RdHexCards], cc], cc]; InstallOneAmpersandItem[ampersandContext2, "&&RdBytes", CCTypes.CreateNodeFromRefAny[NEW[PROC[a: CirioTypes.CirioAddress, nBytes: CARD] _ RdBytes], cc], cc]; InstallOneAmpersandItem[ampersandContext2, "&&RdChars", CCTypes.CreateNodeFromRefAny[NEW[PROC[a: CirioTypes.CirioAddress, nChars: CARD] _ RdChars], cc], cc]; InstallOneAmpersandItem[ampersandContext2, "&&RdRope", CCTypes.CreateNodeFromRefAny[NEW[PROC[a: CirioTypes.CirioAddress, nChars: CARD _ 100] _ RdRope], cc], cc]; InstallOneAmpersandItem[ampersandContext2, "&&MkAddress", CCTypes.CreateNodeFromRefAny[NEW[PROC[byteAddress: CARD, h: Connection] RETURNS[CirioTypes.CirioAddress] _ MkAddress], cc], cc]; InstallOneAmpersandItem[ampersandContext2, "&&FrameDiagnosticInfo", CCTypes.CreateNodeFromRefAny[NEW[PROC[h: Connection] _ FrameDiagnosticInfo], cc], cc]; InstallOneAmpersandItem[ampersandContext2, "&&SetBreakAtAbsAddr", CCTypes.CreateNodeFromRefAny[NEW[PROC[h: Connection, absAddr: CARD32, mesaPos: SourceFileOpsExtras.Position, stopAll: BOOLEAN] _ SetBreakAtAbsAddr], cc], cc]; InstallOneAmpersandItem[ampersandContext2, "&&ListBreaks", CCTypes.CreateNodeFromRefAny[NEW[PROC[h: Connection] _ ListBreaks], cc], cc]; InstallOneAmpersandItem[ampersandContext2, "&&ClearBreakAtAbsAddr", CCTypes.CreateNodeFromRefAny[NEW[PROC[h: Connection, absAddr: CARD32] _ ClearBreakAtAbsAddr], cc], cc]; InstallOneAmpersandItem[ampersandContext2, "&&ClearBreakAtIndex", CCTypes.CreateNodeFromRefAny[NEW[PROC[h: Connection, index: CARD] _ ClearBreakAtIndex], cc], cc]; InstallOneAmpersandItem[ampersandContext2, "&&ClearAllBreaks", CCTypes.CreateNodeFromRefAny[NEW[PROC[h: Connection] _ ClearAllBreaks], cc], cc]; InstallOneAmpersandItem[ampersandContext2, "&&AddDir", CCTypes.CreateNodeFromRefAny[NEW[PROC[h: Connection, dirName: Rope.ROPE, reports: IO.STREAM] _ AddDir], cc], cc]; InstallOneAmpersandItem[ampersandContext2, "&&ListDir", CCTypes.CreateNodeFromRefAny[NEW[PROC[h: Connection] _ ListDir], cc], cc]; InstallOneAmpersandItem[ampersandContext2, "&&ClearDir", CCTypes.CreateNodeFromRefAny[NEW[PROC[h: Connection] _ ClearDir], cc], cc]; InstallOneAmpersandItem[ampersandContext2, "&&LookupSym", CCTypes.CreateNodeFromRefAny[NEW[PROC[h: Connection, name: Rope.ROPE, numToSkip: INT _ 0, externOnly: BOOL _ TRUE] RETURNS[CirioNubAccess.SymEntry] _ LookupSym], cc], cc]; InstallOneAmpersandItem[ampersandContext2, "&&LookupAddr", CCTypes.CreateNodeFromRefAny[NEW[PROC[h: Connection, val: CARD, numToSkip: INT _ 0] RETURNS[CirioNubAccess.SymEntry] _ LookupAddr], cc], cc]; InstallOneAmpersandItem[ampersandContext2, "&&LookupID", CCTypes.CreateNodeFromRefAny[NEW[PROC[h: Connection, symID: CARD] RETURNS[CirioNubAccess.SymEntry] _ LookupID], cc], cc]; InstallOneAmpersandItem[ampersandContext2, "&&LookupFile", CCTypes.CreateNodeFromRefAny[NEW[PROC[h: Connection, seqNum: CARD] RETURNS[entry: CirioNubAccess.FileEntry] _ LookupFile], cc], cc]; InstallOneAmpersandItem[ampersandContext2, "&&GetPCInfo", CCTypes.CreateNodeFromRefAny[NEW[PROC[h: Connection, absPC: CARD] RETURNS[CirioNubAccess.PCInfo] _ GetPCInfo], cc], cc]; InstallOneAmpersandItem[ampersandContext2, "&&GetRelPCForCLine", CCTypes.CreateNodeFromRefAny[NEW[PROC[dotOName: Rope.ROPE, cLineNum: CARD, h: Connection] RETURNS[CARD] _ GetRelPCForCLine], cc], cc]; InstallOneAmpersandItem[ampersandContext2, "&&GetCLineForRelPC", CCTypes.CreateNodeFromRefAny[NEW[PROC[dotOName: Rope.ROPE, relPC: CARD, h: Connection] RETURNS[CARD] _ GetCLineForRelPC], cc], cc]; InstallOneAmpersandItem[ampersandContext2, "&&DebugOn", CCTypes.CreateNodeFromRefAny[NEW[PROC[] _ DebugOn], cc], cc]; InstallOneAmpersandItem[ampersandContext2, "&&DebugOff", CCTypes.CreateNodeFromRefAny[NEW[PROC[] _ DebugOff], cc], cc]; RETURN[connection]}}; IF outerMsg#NIL THEN reports.PutF["debug connection not opened with %g (port %g) because of uncaught error (%g).\n", [rope[remoteName]], [cardinal[portNum]], [rope[outerMsg]] ]; RETURN}; FlushUnknownFileCache: PUBLIC ENTRY PROC[connection: Connection, reports: IO.STREAM] = BEGIN ENABLE UNWIND => NULL; IF NOT connection.open THEN RETURN; NewRMTW.FlushUnknownFileCache[connection.cedarModules, BasicTime.Now[]]; NewRMTW.FlushUnknownSymbolCache[connection.rmtw, BasicTime.Now[], reports]; NewRMTW.FlushUnknownTypeCodes[connection.rmtw]; IF connection.threads # NIL THEN FOR ti: CARDINAL IN [0..connection.threads.nThreads) DO td: REF ThreadData _ connection.threads[ti]; StackCirio.NoteFileCacheFlush[td.stack]; ENDLOOP; END; CloseConnection: PUBLIC ENTRY PROC[connection: Connection, reports: IO.STREAM] = { ENABLE UNWIND => NULL; InerCloseConnection[connection, reports]}; InerCloseConnection: INTERNAL PROC[connection: Connection, reports: IO.STREAM] = { ClearBreaksForClose: PROC RETURNS[Rope.ROPE] = {CirioBreakAccess.ClearAllBreaks[connection.breaks]; RETURN[NIL]}; finalMsg: Rope.ROPE _ NIL; IF connection = NIL OR NOT connection.open THEN RETURN; StopBreakCheckDaemon[connection, reports]; connection.open _ FALSE; finalMsg _ CirioBackstop.Protect[ClearBreaksForClose, reports]; CirioNubAccess.DestroyNub[connection.nub]; SystemInterface.CloseFileSet[connection.fileSet]; IF Rope.Length[finalMsg] # 0 THEN IO.PutF[reports, "%g\N", IO.rope[finalMsg]]; }; DestroyRemoteWorld: PUBLIC ENTRY PROC[connection: Connection] = BEGIN ENABLE UNWIND => NULL; IF NOT connection.open THEN RETURN; CirioNubAccess.KillWorld[connection.nub]; connection.open _ FALSE; CirioNubAccess.DestroyNub[connection.nub]; SystemInterface.CloseFileSet[connection.fileSet]; END; <> <<>> StopRemoteWorld: PUBLIC ENTRY PROC[connection: Connection, reports: IO.STREAM] RETURNS[nThreads: CARD] = BEGIN ENABLE UNWIND => NULL; <> IF NOT CirioNubAccess.SetDBStat[connection.nub, -2, 5000] THEN CCE[cirioError]; nThreads _ AcquireThreadInfo[connection, reports]; connection.remoteWorldRunning _ FALSE; RETURN[nThreads]; END; AcquireThreadInfo: PROC[connection: Connection, reports: IO.STREAM] RETURNS[nThreads: CARD] = BEGIN threads: LIST OF REF CirioNubAccess.ThreadInfo; threadX: CARD _ 0; threads _ CirioNubAccess.GetThreads[connection.nub, 0, 100]; nThreads _ 0; FOR ths: LIST OF REF CirioNubAccess.ThreadInfo _ threads, ths.rest WHILE ths # NIL DO nThreads _ nThreads+1 ENDLOOP; connection.threads _ NEW[ThreadSet[nThreads]]; FOR ths: LIST OF REF CirioNubAccess.ThreadInfo _ threads, ths.rest WHILE ths # NIL DO td: REF ThreadData _ connection.threads[threadX] _ NEW[ThreadData]; td.thread _ ths.first; td.stack _ StackCirio.OpenStack[ ampersandContext1: connection.ampersandContext1, ampersandContext2: connection.ampersandContext2, cc: connection.cc, rmtw: connection.rmtw, cedarModules: connection.cedarModules, nub: connection.nub, target: connection.target, fileSet: connection.fileSet, breaks: connection.breaks, lsh: connection.lsh, aph: connection.aph, cParserTable: connection.cParserTable, hotFramePC: ths.first.pc, hotFrameSP: ths.first.stackPointer, skipKFrames: 0, ShowSource: SourceFileOpsExtras.FullOpenSource, reports: reports]; threadX _ threadX + 1; ENDLOOP; RETURN[nThreads]; END; FindThreadsWithProperty: PUBLIC ENTRY PROC[connection: Connection, property: RemoteCirio.ThreadProperty, reports: IO.STREAM] RETURNS[LIST OF -- threadIndex -- CARD] = BEGIN ENABLE UNWIND => NULL; IF NOT connection.open THEN CCE[cirioError]; IF connection.remoteWorldRunning THEN CCE[cirioError]; BEGIN newThreads: LIST OF CARD _ NIL; lastNewThread: LIST OF CARD _ NIL; IO.PutF[reports, "\N\Tchecking thread with index "]; FOR x: CARD IN [0..connection.threads.nThreads) DO IF ThreadSatisfies[connection.threads[x], property, reports] THEN BEGIN cell: LIST OF CARD _ LIST[x]; IF newThreads = NIL THEN newThreads _ cell ELSE lastNewThread.rest _ cell; lastNewThread _ cell; END; ENDLOOP; IO.PutF[reports, "\N"]; RETURN[newThreads]; END; END; ThreadSatisfies: PROC[thread: REF ThreadData, property: RemoteCirio.ThreadProperty, reports: IO.STREAM] RETURNS[BOOLEAN] = BEGIN WITH property SELECT FROM tp: any RemoteCirio.ThreadProperty => RETURN[TRUE]; tp: callingDebugger RemoteCirio.ThreadProperty => RETURN[thread.thread.dbgMsg # 0]; tp: ready RemoteCirio.ThreadProperty => RETURN[thread.thread.schedState = CirioNubAccess.SchedStateReady OR thread.thread.schedState = CirioNubAccess.SchedStateRun]; tp: context RemoteCirio.ThreadProperty => BEGIN found: BOOLEAN _ FALSE; -- tentative CheckName: PROC[name: PFSNames.PATH] RETURNS[--stop-- BOOLEAN] = BEGIN found _ Rope.Equal[PFS.RopeFromPath[name], tp.name, FALSE]; RETURN[found]; END; IO.PutF[reports, "%g ", IO.card[thread.thread.index]]; StackCirio.QuickGenPossibleModuleNames[thread.stack, CheckName, reports]; IF found THEN IO.PutF[reports, "(bingo )"]; RETURN[found]; END; ENDCASE => CCE[cirioError]; END; GetThreadTitleText: PUBLIC ENTRY PROC[connection: Connection, threadIndex: CARD] RETURNS[Rope.ROPE] = BEGIN ENABLE UNWIND => NULL; RETURN[ConstructThreadTitleText[connection, threadIndex]]; END; ConstructThreadTitleText: PROC[connection: Connection, threadIndex: CARD] RETURNS[Rope.ROPE] = BEGIN threadData: REF ThreadData _ connection.threads[threadIndex]; remoteIndex: CARD _ threadData.thread.index; schedStateText: Rope.ROPE _ RopeForSchedState[threadData.thread.schedState]; dbgMsgText: Rope.ROPE _ RopeForDbgMsg[threadData.thread.dbgMsg]; freezeText: Rope.ROPE _ IF threadData.thread.frozen THEN " (frozen)" ELSE NIL; RETURN[IO.PutFR["%g: (%g) (%g)%g (%g)", IO.card[remoteIndex], IO.card[threadData.thread.priority], IO.rope[schedStateText], IO.rope[freezeText], IO.rope[dbgMsgText]]]; END; ThreadIndexFromID: PUBLIC PROC[ID: CARD, connection: Connection] RETURNS [index: CARD _ LAST[CARD]] ~ { FOR i: CARDINAL IN [0..connection.threads.nThreads) DO IF connection.threads[i].thread.index = ID THEN RETURN[i]; ENDLOOP; }; ThreadIDFromIndex: PUBLIC PROC[index: CARD, connection: Connection] RETURNS [ID: CARD _ LAST[CARD]] ~ { IF index < connection.threads.nThreads THEN RETURN[connection.threads[index].thread.index]; }; ShowQuickSummary: PUBLIC ENTRY PROC[connection: Connection, threadIndex: CARD, stopFlag: REF BOOLEAN, on: IO.STREAM, long: BOOL] = BEGIN ENABLE UNWIND => NULL; threadData: REF ThreadData _ connection.threads[threadIndex]; IO.PutF[on, "quick summary for thread with index %g\N", IO.card[connection.threads[threadIndex].thread.index]]; IO.PutF[on, "\Tdebug message = %g\N", IO.rope[RopeForDbgMsg[threadData.thread.dbgMsg]]]; StackCirio.ShowQuickSummary[threadData.stack, stopFlag, on, long]; END; GetThreadDebuggingBanner: PUBLIC ENTRY PROC[connection: Connection, threadIndex: CARD, reports: IO.STREAM] RETURNS[Rope.ROPE] = BEGIN ENABLE UNWIND => NULL; inner: PROC RETURNS[Rope.ROPE] = BEGIN RETURN[IO.PutFR["debugging thread with index %g", IO.card[connection.threads[threadIndex].thread.index]]]; END; RETURN[CirioBackstop.Protect[inner, reports]]; END; AbortThread: PUBLIC ENTRY PROC[connection: Connection, threadIndex: CARD, reports: IO.STREAM] RETURNS[newThreadTitleText: Rope.ROPE] = BEGIN ENABLE UNWIND => NULL; inner: PROC RETURNS[Rope.ROPE] = BEGIN RETURN[IssueFullThreadCommand[connection, threadIndex, TRUE, FALSE, TRUE, -3]]; END; RETURN[CirioBackstop.Protect[inner, reports]]; END; KillThread: PUBLIC ENTRY PROC[connection: Connection, threadIndex: CARD, reports: IO.STREAM] RETURNS[newThreadTitleText: Rope.ROPE] = BEGIN ENABLE UNWIND => NULL; inner: PROC RETURNS[Rope.ROPE] = BEGIN RETURN[IssueFullThreadCommand[connection, threadIndex, TRUE, FALSE, TRUE, -2]]; END; RETURN[CirioBackstop.Protect[inner, reports]]; END; FreezeThread: PUBLIC ENTRY PROC[connection: Connection, threadIndex: CARD, reports: IO.STREAM] RETURNS[newThreadTitleText: Rope.ROPE] = BEGIN ENABLE UNWIND => NULL; inner: PROC RETURNS[Rope.ROPE] = BEGIN RETURN[IssueFullThreadCommand[connection, threadIndex, TRUE, TRUE, FALSE, connection.threads[threadIndex].thread.dbgMsg]]; END; RETURN[CirioBackstop.Protect[inner, reports]]; END; ProceedThread: PUBLIC ENTRY PROC[connection: Connection, threadIndex: CARD, reports: IO.STREAM] RETURNS[newThreadTitleText: Rope.ROPE] = BEGIN ENABLE UNWIND => NULL; inner: PROC RETURNS[Rope.ROPE] = BEGIN RETURN[IssueFullThreadCommand[connection, threadIndex, TRUE, FALSE, TRUE, -1]]; END; RETURN[CirioBackstop.Protect[inner, reports]]; END; <> <jaune>xrhome>DEVELOPMENT>INCLUDE>xr>Threads.h we have:>> <> <> <> IssueFullThreadCommand: PROC[connection: Connection, threadIndex: CARD, setFreeze: BOOL, freeze: BOOLEAN, setMsg: BOOLEAN, msg: INT] RETURNS[--new title text-- Rope.ROPE] = BEGIN remoteIndex: CARD _ connection.threads[threadIndex].thread.index; IF NOT CirioNubAccess.IssueThreadCommand[connection.nub, remoteIndex, setFreeze, freeze, setMsg, msg] THEN CCE[cirioError]; <> BEGIN threads: LIST OF REF CirioNubAccess.ThreadInfo _ CirioNubAccess.GetThreads[connection.nub, 0, 100]; FOR ths: LIST OF REF CirioNubAccess.ThreadInfo _ threads, ths.rest WHILE ths # NIL DO IF ths.first.index = remoteIndex THEN -- here we are BEGIN connection.threads[threadIndex].thread _ ths.first; EXIT; END; ENDLOOP; RETURN[ConstructThreadTitleText[connection, threadIndex]]; END; END; DbxExamineThread: PUBLIC ENTRY PROC[connection: Connection, threadIndex: CARD, reports: IO.STREAM] RETURNS[nThreads: CARD] = BEGIN ENABLE UNWIND => NULL; IF NOT connection.remoteWorldRunning THEN BEGIN remoteIndex: CARD _ connection.threads[threadIndex].thread.index; connection.remoteWorldRunning _ TRUE; connection.dbxActive _ TRUE; connection.threads _ NIL; IF NOT CirioNubAccess.SetDBStat[connection.nub, remoteIndex, 5000] THEN CCE[cirioError]; WHILE NOT CirioNubAccess.SetDBStat[connection.nub, -2, 5000] DO ENDLOOP; nThreads _ AcquireThreadInfo[connection, reports]; connection.dbxActive _ FALSE; connection.remoteWorldRunning _ FALSE; RETURN[nThreads]; END ELSE CCE[cirioError]; END; ResumeRemoteWorldWithOnlyVP0: PUBLIC ENTRY PROC[connection: Connection] = BEGIN ENABLE UNWIND => NULL; IF NOT connection.remoteWorldRunning THEN BEGIN IF NOT CirioNubAccess.SetDBStat[connection.nub, -1, 5000] THEN CCE[cirioError]; connection.threads _ NIL; connection.remoteWorldRunning _ TRUE; END; END; ResumeRemoteWorld: PUBLIC ENTRY PROC[connection: Connection] = BEGIN ENABLE UNWIND => NULL; IF NOT connection.remoteWorldRunning THEN BEGIN IF NOT CirioNubAccess.SetDBStat[connection.nub, 0, 5000] THEN CCE[cirioError]; connection.threads _ NIL; connection.remoteWorldRunning _ TRUE; END; END; <> GetDummyStack: PUBLIC ENTRY PROC[connection: Connection, reports: IO.STREAM]RETURNS[StackCirio.Stack] = { ENABLE UNWIND => NULL; RETURN StackCirio.OpenDummyStack[ ampersandContext1: connection.ampersandContext1, ampersandContext2: connection.ampersandContext2, cc: connection.cc, rmtw: connection.rmtw, cedarModules: connection.cedarModules, nub: connection.nub, target: connection.target, fileSet: connection.fileSet, breaks: connection.breaks, lsh: connection.lsh, aph: connection.aph, cParserTable: connection.cParserTable, ShowSource: SourceFileOpsExtras.FullOpenSource, reports: reports]}; FocusOnThread: PUBLIC ENTRY PROC[connection: Connection, threadIndex: CARD, reports: IO.STREAM] RETURNS[newRemoteThreadIndex: CARD] = { ENABLE UNWIND => NULL; connection.currentThread _ IF threadIndex < connection.threads.nThreads THEN threadIndex ELSE 0; RETURN[connection.threads[connection.currentThread].thread.index]; }; GetStackForCurrentThread: PUBLIC ENTRY PROC[connection: Connection, reports: IO.STREAM] RETURNS[StackCirio.Stack] = BEGIN ENABLE UNWIND => NULL; threadData: REF ThreadData _ connection.threads[connection.currentThread]; RETURN[threadData.stack]; END; <> <<>> RopeForDbgMsg: PROC[msg: INT] RETURNS[Rope.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; RopeForSchedState: PROC[state: CARD] RETURNS[Rope.ROPE] = BEGIN RETURN[SELECT state FROM CirioNubAccess.SchedStateFree => "Free", CirioNubAccess.SchedStateReady => "Ready", CirioNubAccess.SchedStateRun => "Run", CirioNubAccess.SchedStateWaitML => "MLWait", CirioNubAccess.SchedStateWaitCV => "CVWait", CirioNubAccess.SchedStateHandlee => "Handlee", ENDCASE => IO.PutFR["??: %g", IO.card[state]]]; END; <<>> <> << This procedure interfaces to RCTWImpl.GetCCAndFrameFromDotO.>> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <<[cc, node] _ RCTW.GetCCAndFrameFromDotO[serverName, cFrameInfo, nub, symbols.embeddedDotO>> <>> <> <> <> <> <> <> <> <<>> <> InstallOneAmpersandItem: PROC[ampersandContext: CirioTypes.Node, name: Rope.ROPE, item: CirioTypes.Node, cc: CC] = BEGIN IF NOT Rope.Equal[Rope.Substr[name, 0, 2], "&&"] THEN ERROR ELSE BEGIN ampersandContextType: CirioTypes.Type _ CedarCode.GetTypeOfNode[ampersandContext]; indirect: CirioTypes.Node _ CedarCode.SelectFieldFromNode[name, ampersandContextType, ampersandContext, cc]; indirectType: CirioTypes.Type _ CedarCode.GetTypeOfNode[indirect]; encapsulatedItem: CirioTypes.Node _ AmpersandContext.MakeNodeFromNode[item, cc]; encapsulatedType: CirioTypes.Type _ CedarCode.GetTypeOfNode[encapsulatedItem]; CedarCode.StoreThroughIndirectNode[encapsulatedType, encapsulatedItem, indirectType, indirect, cc]; END END; <> <<>> ReadOneAmpersandItem: PROC[name: Rope.ROPE, nameScope: CirioTypes.Node, cc: CC] RETURNS[CirioTypes.Node] = BEGIN IF NOT Rope.Equal[Rope.Substr[name, 0, 2], "&&"] THEN ERROR ELSE BEGIN nameScopeType: CirioTypes.Type _ CedarCode.GetTypeOfNode[nameScope]; indirect: CirioTypes.Node _ CedarCode.SelectFieldFromNode[name, nameScopeType, nameScope, cc]; indirectType: CirioTypes.Type _ CedarCode.GetTypeOfNode[indirect]; encapsulatedItem: CirioTypes.Node _ CedarCode.LoadThroughIndirectNode[indirectType, indirect, cc]; RETURN[AmpersandContext.StripAMNode[encapsulatedItem]] END; END; ReadOneAmpersandInt: PROC[name: Rope.ROPE, defaultVal: INT, nameScope: CirioTypes.Node, cc: CC] RETURNS[INT] = BEGIN valNode: CirioTypes.Node _ NIL; valNode _ ReadOneAmpersandItem[name, nameScope, cc ! CCTypes.CCError => {valNode _ NIL; CONTINUE}]; IF valNode = NIL THEN RETURN[defaultVal] ELSE BEGIN val: REF INT _ NARROW[CedarCode.GetNodeRepresentation[valNode, cc]]; <> RETURN[val^]; END; END; <<>> <<>> <> <<>> AddSearchDirectory: PUBLIC PROC [connection: Connection, directoryPath: Rope.ROPE, reports: IO.STREAM] = <> BEGIN inner: PROC RETURNS[Rope.ROPE] = BEGIN <> AddDir[connection, directoryPath, reports]; IO.PutF[reports, " %g added to search directories\n", IO.rope[directoryPath]]; RETURN [NIL]; END; eMsg: Rope.ROPE; eMsg _ CirioBackstop.Protect[inner, reports]; IF eMsg # NIL THEN IO.PutF[reports, "%g\N", [rope[eMsg]]]; END; RemoveSearchDirectory: PUBLIC PROC [connection: Connection, directoryPath: Rope.ROPE, reports: IO.STREAM] = <> BEGIN inner: PROC RETURNS[Rope.ROPE] = BEGIN <> RemoveDir[connection, directoryPath, reports]; IO.PutF[reports, " %g removed from search directories\n", IO.rope[directoryPath]]; RETURN [NIL]; END; eMsg: Rope.ROPE; eMsg _ CirioBackstop.Protect[inner, reports]; IF eMsg # NIL THEN IO.PutF[reports, "%g\N", [rope[eMsg]]]; END; ListSearchDirectory: PUBLIC PROC [connection: Connection, reports: IO.STREAM] = <> BEGIN inner: PROC RETURNS[Rope.ROPE] = BEGIN ListDir[connection]; RETURN [" done"]; END; eMsg: Rope.ROPE; eMsg _ CirioBackstop.Protect[inner, reports]; IF eMsg # NIL THEN IO.PutF[reports, "%g\N", [rope[eMsg]]]; END; ClearSearchDirectory: PUBLIC PROC [connection: Connection, reports: IO.STREAM] = <> BEGIN inner: PROC RETURNS[Rope.ROPE] = BEGIN ClearDir[connection]; RETURN [" done"]; END; eMsg: Rope.ROPE; eMsg _ CirioBackstop.Protect[inner, reports]; IF eMsg # NIL THEN IO.PutF[reports, "%g\N", [rope[eMsg]]]; END; <> <<>> <> AddressData: TYPE = RECORD[byteAddress: CARD, h: Connection]; MkAddress: PROC[byteAddress: CARD, h: Connection] RETURNS[CirioTypes.CirioAddress] = BEGIN addressData: REF AddressData _ NEW[AddressData_[byteAddress, h]]; RETURN[NEW[CirioTypes.CirioAddressBody_[CirioAddressIsNil, ReadRemoteBits, WriteRemoteBits, FollowRemotePointer, AsCardForRemote, addressData]]]; END; ByteBitSize: CARD = 8; CardByteSize: CARD = 4; CirioAddressIsNil: PROC [data: CirioTypes.CirioAddress] RETURNS [BOOL] ~ { addressData: REF AddressData _ NARROW[data.data]; RETURN [addressData.byteAddress=0]}; <> <> ReadRemoteBits: PROC[byteOffset: INT _ 0, bitOffset: INT _ 0, bitSize: CARD, data: CirioTypes.CirioAddress] RETURNS[CARD] = BEGIN addressData: REF AddressData _ NARROW[data.data]; byteAddress: INT _ addressData.byteAddress + byteOffset + bitOffset/8; remainingBitOffset: INT _ bitOffset MOD 8; <<>> <> IF bitSize > 32 THEN CCE[operation]; <> BEGIN cardAddr: INT _ (byteAddress/CardByteSize)*CardByteSize; finalBitOffset: INT _ (byteAddress MOD CardByteSize )*ByteBitSize + remainingBitOffset; nextBitOffset: INT _ finalBitOffset+bitSize; IF nextBitOffset <= 32 THEN -- no word crossing BEGIN container: CARD _ CirioNubAccess.Read32BitsAsCard[[ addressData.h.nub, cardAddr, 0, FALSE, TRUE]]; RETURN[PBasics.BITRSHIFT[PBasics.BITLSHIFT[container, finalBitOffset], 32-bitSize]]; END ELSE -- splits across 4 byte boundary (I am not sure if this will even get tested in the near future, since the rumor is that Mimosa prevents such splits). BEGIN lContainer: CARD _ CirioNubAccess.Read32BitsAsCard[[ addressData.h.nub, cardAddr, 0, FALSE, TRUE]]; rContainer: CARD _ CirioNubAccess.Read32BitsAsCard[[ addressData.h.nub, cardAddr+1, 0, FALSE, TRUE]]; RETURN[PBasics.BITOR[ PBasics.BITLSHIFT[lContainer, finalBitOffset], PBasics.BITRSHIFT[rContainer, (32*2)-(finalBitOffset+bitSize)]]]; END; END; END; <<>> WriteRemoteBits: PROC[byteOffset: INT _ 0, bitOffset: INT _ 0, bitSize: CARD, data: CirioTypes.CirioAddress, bits: CARD] = BEGIN addressData: REF AddressData _ NARROW[data.data]; CCE[unimplemented]; END; FollowRemotePointer: PROC[byteOffset: INT _ 0, data: CirioTypes.CirioAddress] RETURNS[CirioTypes.CirioAddress] = BEGIN addressData: REF AddressData _ NARROW[data.data]; newAddressVal: CARD _ ReadRemoteBits[0, 0, 32, data]; RETURN[MkAddress[newAddressVal, addressData.h]]; END; AsCardForRemote: PROC[data: CirioTypes.CirioAddress] RETURNS[CARD] = BEGIN addressData: REF AddressData _ NARROW[data.data]; RETURN[addressData.byteAddress]; END; RdCards: PROC[a: CirioTypes.CirioAddress, nCards: CARD] = BEGIN CardsPerLine: CARD = 10; FOR x: CARD IN [0..(nCards+CardsPerLine-1)/CardsPerLine) DO n: CARD _ MIN[CardsPerLine, nCards - CardsPerLine*x]; textLine: IO.STREAM _ IO.ROS[]; IO.PutF[textLine, "\T"]; FOR I: CARD IN [0..n) DO oneCard: CARD _ a.readBits[CardsPerLine*4*x+4*I, 0, 32, a]; IO.PutF[textLine, " %g", IO.card[oneCard]]; ENDLOOP; SystemInterface.ShowReport[IO.RopeFromROS[textLine], $urgent]; ENDLOOP; END; RdHexCards: PROC[a: CirioTypes.CirioAddress, nCards: CARD] = BEGIN CardsPerLine: CARD = 10; FOR x: CARD IN [0..(nCards+CardsPerLine-1)/CardsPerLine) DO n: CARD _ MIN[CardsPerLine, nCards - CardsPerLine*x]; textLine: IO.STREAM _ IO.ROS[]; IO.PutF[textLine, "\T"]; FOR I: CARD IN [0..n) DO oneCard: CARD _ a.readBits[CardsPerLine*4*x+4*I, 0, 32, a]; IO.PutF[textLine, " %g", IO.rope[Convert.RopeFromCard[oneCard, 16]]]; ENDLOOP; SystemInterface.ShowReport[IO.RopeFromROS[textLine], $urgent]; ENDLOOP; END; RdBytes: PROC[a: CirioTypes.CirioAddress, nBytes: CARD] = BEGIN BytesPerLine: CARD = 20; FOR x: CARD IN [0..(nBytes+BytesPerLine-1)/BytesPerLine) DO n: CARD _ MIN[BytesPerLine, nBytes - BytesPerLine*x]; textLine: IO.STREAM _ IO.ROS[]; IO.PutF[textLine, "\T"]; FOR I: CARD IN [0..n) DO oneByte: CARD _ a.readBits[BytesPerLine*x+I, 0, 8, a]; IO.PutF[textLine, " %g", IO.rope[Convert.RopeFromCard[oneByte, 16]]]; ENDLOOP; SystemInterface.ShowReport[IO.RopeFromROS[textLine], $urgent]; ENDLOOP; END; RdChars: PROC[a: CirioTypes.CirioAddress, nChars: CARD] = BEGIN CharsPerLine: CARD = 20; FOR x: CARD IN [0..(nChars+CharsPerLine-1)/CharsPerLine) DO n: CARD _ MIN[CharsPerLine, nChars - CharsPerLine*x]; textLine: IO.STREAM _ IO.ROS[]; IO.PutF[textLine, "\T"]; FOR I: CARD IN [0..n) DO oneChar: CARD _ a.readBits[CharsPerLine*x+I, 0, 8, a]; IO.PutF[textLine, " %g", IO.char[VAL[BYTE[oneChar]]]]; ENDLOOP; SystemInterface.ShowReport[IO.RopeFromROS[textLine], $urgent]; ENDLOOP; END; <> <> RdRope: PROC[a: CirioTypes.CirioAddress, nChars: CARD _ 100] = BEGIN ropeBodyAddr: CirioTypes.CirioAddress _ a.followPointer[0, a]; ropeBodyContents: CARD _ ropeBodyAddr.readBits[0, 0, 32, ropeBodyAddr]; rope: Rope.ROPE _ NIL; SeeOneChar: PROC[c: CHAR] = {rope _ Rope.Cat[rope, Rope.FromChar[c]]}; GenCharsForRope[a.followPointer[0, a], 0, nChars, SeeOneChar]; SystemInterface.ShowReport[rope, $urgent]; END; Field: TYPE = RECORD[offset: INT, size: CARD]; <Rope.mesa)>> <> GenCharsForRope: PROC[a: CirioTypes.CirioAddress, first: CARD, nChars: CARD, for: PROC[CHAR]] = BEGIN tagF: Field = [0, 1]; tag: CARD _ a.readBits[tagF.offset, 0, tagF.size, a]; ShowClient: PROC[c: CHAR] RETURNS[quit: BOOL] = {for[c]; RETURN[FALSE]}; SystemInterface.ShowReport[IO.PutFR["tag = %g", IO.rope[Convert.RopeFromCard[tag, 16]]], $urgent]; SELECT tag FROM 0 => -- we are looking at a text BEGIN lengthF: Field = [1, 15]; maxF: Field = [16, 16]; length: CARD _ a.readBits[0, lengthF.offset, lengthF.size, a]; max: CARD _ a.readBits[0, maxF.offset, maxF.size, a]; n: CARD _ IF first >= length THEN 0 ELSE MIN[length-first, nChars]; FOR I: CARD IN [0..n) DO byte: CARD _ a.readBits[4+first+I, 0, 8, a]; for[VAL[BYTE[byte]]]; ENDLOOP; END; 1 => -- we are looking at a node BEGIN sizeF: Field = [1, 31]; depthF: Field = [32, 30]; casesF: Field = [62, 2]; size: CARD _ a.readBits[0, sizeF.offset, sizeF.size, a]; depth: CARD _ a.readBits[0, depthF.offset, depthF.size, a]; cases: CARD _ a.readBits[0, casesF.offset, casesF.size, a]; n: CARD _ IF first >= size THEN 0 ELSE MIN[size-first, nChars]; IF n > 0 THEN SELECT cases FROM 0 => -- substr BEGIN baseF: Field = [64, 32]; startF: Field = [96, 32]; base: CirioTypes.CirioAddress _ a.followPointer[baseF.offset/8, a]; start: CARD _ a.readBits[0, startF.offset, startF.size, a]; [] _ Rope.Map[base: "??substr??", action: ShowClient]; GenCharsForRope[base, start, n, for]; END; 1 => -- concat BEGIN baseF: Field = [64, 32]; restF: Field = [96, 32]; posF: Field = [128, 32]; base: CirioTypes.CirioAddress _ a.followPointer[baseF.offset/8, a]; rest: CirioTypes.CirioAddress _ a.followPointer[restF.offset/8, a]; pos: CARD _ a.readBits[0, posF.offset, posF.size, a]; [] _ Rope.Map[base: "??concat??", action: ShowClient]; IF first < pos THEN BEGIN GenCharsForRope[base, first, MIN[pos-first, n], for]; IF n > pos-first THEN GenCharsForRope[rest, 0, n-pos+first, for]; END ELSE GenCharsForRope[rest, first-pos, n, for]; END; 2 => BEGIN baseF: Field = [64, 32]; replaceF: Field = [96, 32]; startF: Field = [128, 32]; oldPosF: Field = [160, 32]; newPosF: Field = [192, 32]; base: CirioTypes.CirioAddress _ a.followPointer[baseF.offset/8, a]; replace: CirioTypes.CirioAddress _ a.followPointer[replaceF.offset/8, a]; start: CARD _ a.readBits[0, startF.offset, startF.size, a]; oldPos: CARD _ a.readBits[0, oldPosF.offset, oldPosF.size, a]; newPos: CARD _ a.readBits[0, newPosF.offset, newPosF.size, a]; [] _ Rope.Map[base: "??replace??", action: ShowClient]; IF n > 0 AND first < start THEN BEGIN GenCharsForRope[base, first, MIN[n, start-first], for]; first _ start; n _ n-MIN[n, start-first]; END; IF n > 0 AND first < newPos THEN BEGIN GenCharsForRope[replace, first-start, MIN[n, newPos-first], for]; first _ newPos; n _ n - MIN[n, newPos-first]; END; IF n > 0 AND first < size THEN GenCharsForRope[base, first-newPos+oldPos, n, for]; END; 3 => [] _ Rope.Map[base: "??ObjectRope??", action: ShowClient]; ENDCASE => CCE[cirioError]; END; ENDCASE => CCE[cirioError]; END; FrameDiagnosticInfo: PROC[h: Connection] = BEGIN threadIndex: CARD _ h.currentThread; td: REF ThreadData _ h.threads[threadIndex]; StackCirio.FrameDiagnosticInfo[td.stack, h.tsOut]; END; <> SetBreakAtAbsAddr: PROC[h: Connection, absAddr: CARD32, mesaPos: SourceFileOpsExtras.Position, stopAll: BOOLEAN] = {CirioBreakAccess.SetBreakAtAbsAddr[h.breaks, absAddr, mesaPos, stopAll]}; ListBreaks: PROC[h: Connection] = {CirioBreakAccess.ListBreaks[h.breaks]}; ClearBreakAtAbsAddr: PROC[h: Connection, absAddr: CARD32] = {CirioBreakAccess.ClearBreakAtAbsAddr[h.breaks, absAddr]}; ClearBreakAtIndex: PROC[h: Connection, index: CARD] = {CirioBreakAccess.ClearBreakAtIndex[h.breaks, index]}; ClearAllBreaks: PROC[h: Connection] = {CirioBreakAccess.ClearAllBreaks[h.breaks]}; AddDir: PROC [h: Connection, dirName: Rope.ROPE, reports: IO.STREAM] = BEGIN <> properDirName: PFSNames.PATH _ PFS.PathFromRope[dirName]; prev: LIST OF PFSNames.PATH _ NIL; <> WHILE TRUE DO current: LIST OF PFSNames.PATH _ IF prev # NIL THEN prev.rest ELSE h.searchDirectories; IF current = NIL THEN EXIT; IF current.first.Equal[properDirName] THEN BEGIN IF prev = NIL THEN h.searchDirectories _ current.rest ELSE prev.rest _ current.rest; EXIT; END; prev _ current; ENDLOOP; <> h.searchDirectories _ CONS[properDirName, h.searchDirectories]; <> NewRMTW.ResetSearchPaths[h.cedarModules, h.searchDirectories, BasicTime.Now[]]; IF h.rmtw#NIL THEN NewRMTW.FlushUnknownSymbolCache[h.rmtw, BasicTime.Now[], reports]; IF h.threads # NIL THEN FOR ti: CARDINAL IN [0..h.threads.nThreads) DO td: REF ThreadData _ h.threads[ti]; StackCirio.NoteFileCacheFlush[td.stack]; ENDLOOP; END; RemoveDir: PROC [h: Connection, dirName: Rope.ROPE, reports: IO.STREAM] = BEGIN properDirName: PFSNames.PATH _ PFS.PathFromRope[dirName]; prev: LIST OF PFSNames.PATH _ NIL; <> WHILE TRUE DO current: LIST OF PFSNames.PATH _ IF prev # NIL THEN prev.rest ELSE h.searchDirectories; IF current = NIL THEN EXIT; IF current.first.Equal[properDirName] THEN BEGIN IF prev = NIL THEN h.searchDirectories _ current.rest ELSE prev.rest _ current.rest; EXIT; END; prev _ current; ENDLOOP; <> NewRMTW.ResetSearchPaths[h.cedarModules, h.searchDirectories, BasicTime.Now[]]; NewRMTW.FlushUnknownSymbolCache[h.rmtw, BasicTime.Now[], reports]; IF h.threads # NIL THEN FOR ti: CARDINAL IN [0..h.threads.nThreads) DO td: REF ThreadData _ h.threads[ti]; StackCirio.NoteFileCacheFlush[td.stack]; ENDLOOP; END; ListDir: PROC [h: Connection] = BEGIN searchDirectories: Rope.ROPE _ NIL; FOR paths: LIST OF PFSNames.PATH _ h.searchDirectories, paths.rest WHILE paths # NIL DO searchDirectories _ Rope.Cat[searchDirectories, PFS.RopeFromPath[paths.first], " "]; ENDLOOP; SystemInterface.ShowReport[IO.PutFR["%g", IO.rope[searchDirectories]], $urgent]; END; ClearDir: PROC [h: Connection] = BEGIN SystemInterface.ShowReport[IO.PutFR["Clearing search directory list"], $urgent]; SystemInterface.ShowReport[IO.PutFR["Was: "], $urgent]; ListDir[h]; h.searchDirectories _ NIL; <> NewRMTW.ResetSearchPaths[h.cedarModules, h.searchDirectories, BasicTime.Now[]]; <> END; <> <<>> LookupSym: PROC[h: Connection, name: Rope.ROPE, numToSkip: INT _ 0, externOnly: BOOL _ TRUE] RETURNS[CirioNubAccess.SymEntry] = {RETURN[CirioNubAccess.LookupSymEntryByName[h.nub, name, FALSE, externOnly, numToSkip]]}; LookupAddr: PROC[h: Connection, val: CARD, numToSkip: INT _ 0] RETURNS[CirioNubAccess.SymEntry] = {RETURN[CirioNubAccess.LookupSymEntryByValue[h.nub, val, numToSkip]]}; LookupID: PROC[h: Connection, symID: CARD] RETURNS[CirioNubAccess.SymEntry] = {RETURN[CirioNubAccess.LookupSymEntryByID[h.nub, symID]]}; LookupFile: PROC[h: Connection, seqNum: CARD] RETURNS[entry: CirioNubAccess.FileEntry] = {RETURN[CirioNubAccess.GetFileEntry[h.nub, seqNum]]}; GetPCInfo: PROC[h: Connection, absPC: CARD] RETURNS[CirioNubAccess.PCInfo] = {RETURN[CirioNubAccess.PCtoInfo[h.nub, absPC]]}; <> DebugOn: PROC = BEGIN DebugFlag _ TRUE; END; DebugOff: PROC = BEGIN DebugFlag _ FALSE; END; GetRelPCForCLine: PROC[dotOName: Rope.ROPE, cLineNum: CARD, h: Connection] RETURNS[CARD] = BEGIN <> dotOPath: PFSNames.PATH _ PFS.PathFromRope[dotOName]; file: SystemInterface.CirioFile _ SystemInterface.GetCirioFileFromDebuggee[h.fileSet, dotOPath, h.serverName]; IF file=NIL THEN CCE[cirioError, IO.PutFR["Couldn't access %g", [rope[dotOName]] ]]; {container: ObjF.Parsed _ ObjF.CreateParsed[file]; AcquireModule: PROC RETURNS[ObjF.Module] = BEGIN <> RETURN[ObjF.ModuleFromParsedAndPC[container, [[0, ""], 1]]]; END; dotO: ObjF.Module _ AcquireModule[]; relPC: CARD _ ObjF.GetPCForLineNum[dotO, cLineNum].relPC; RETURN[relPC];} END; <> GetCLineForRelPC: PROC[dotOName: Rope.ROPE, relPC: CARD, h: Connection] RETURNS[CARD] = BEGIN dotOPath: PFSNames.PATH _ PFS.PathFromRope[dotOName]; file: SystemInterface.CirioFile _ SystemInterface.GetCirioFileFromDebuggee[h.fileSet, dotOPath, h.serverName]; IF file=NIL THEN CCE[cirioError, IO.PutFR["Couldn't access %g", [rope[dotOName]] ]]; {container: ObjF.Parsed _ ObjF.CreateParsed[file]; AcquireModule: PROC RETURNS[ObjF.Module] = BEGIN <> RETURN[ObjF.ModuleFromParsedAndPC[container, [[0, ""], 1]]]; END; dotO: ObjF.Module _ AcquireModule[]; cLine: CARD _ ObjF.GetLineNumForPC[dotO, [[0, ""], relPC]]; RETURN[cLine];} END; <> <> <> <> <> <> <> <<>> <> <> <> <> <> <<>> <> <<>> <> <> < CONTINUE];>> <<>> <> <<{May4Exp.ShowReport["unable to open mesa file"]; RETURN};>> <> <<>> <> <> <> <> <> <> < NULL;>> <> <> <> <<>> <> <<>> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <<>> <> <> <<>> <> <> <> <<[] _ CirioBackstop.Protect[inner, reports];>> <> <> <> <> <> <> <> <> <> <> <> <> <> <> < symValue _ ser.symEntry.value;>> < CCE[cirioError, "Bad args to LookupID"];>> <> <> <> <> <> <> <> <> < dotOFileName _ ser.symEntry.name;>> < CCE[cirioError, "Bad args to LookupAddr"];>> <> <> <> <> <> <> <<>> <> keyName: Rope.ROPE _ "_CirioDebuggeeTestFrame_"; <> <> <<>> <sturgis>test>test.mesa>> <sturgis>SturgisLocalSun.df>> <<>> <> RemoteCirioTest: Commander.CommandProc = BEGIN args: CommandTool.ArgumentVector _ CommandTool.Parse[cmd]; serverName: Rope.ROPE _ args[1]; portNum: CARDINAL _ IF args.argc <= 2 THEN 4815 ELSE CARDINAL[Convert.CardFromRope[args[2]]]; reports: IO.STREAM _ IO.ROS[]; connection: Connection _ OpenConnection[serverName, portNum, LIST[FileNames.CurrentWorkingDirectory[]], reports]; remoteWorldStopped: BOOLEAN _ FALSE; CleanUp: PROC = BEGIN IF remoteWorldStopped THEN ResumeRemoteWorld[connection]; remoteWorldStopped _ FALSE; CloseConnection[connection, reports]; IO.Close[reports] END; <> <<(note: we need not lock a monitor, since only one thread has access to the connection data.)>> BEGIN ENABLE UNWIND => CleanUp[]; TestInner: PROC = BEGIN nThreads: CARD _ StopRemoteWorld[connection, reports]; remoteWorldStopped _ TRUE; BEGIN interestingThreads: LIST OF CARD _ FindThreadsWithProperty[connection, [callingDebugger[]], cmd.out]; FOR ts: LIST OF CARD _ interestingThreads, ts.rest WHILE ts # NIL DO x: CARD _ ts.first; stack: StackCirio.Stack; [] _ FocusOnThread[connection, x, cmd.out]; stack _ GetStackForCurrentThread[connection, cmd.out]; [] _ StackCirio.ResetStack[stack, cmd.out]; IO.PutF[cmd.out, "searching thread %g\N", IO.rope[GetThreadTitleText[connection, x]]]; IF StackCirio.WalkStackToCProcedure[stack, keyName, "", cmd.out] THEN BEGIN nUnexpectedResults: CARD _ 0; <<>> <> BEGIN frameText: Rope.ROPE _ StackCirio.ShowCurrentFrame[stack, cmd.out]; IO.PutF[cmd.out, "\n\n%g\n\n", IO.rope[frameText]]; END; <<>> <> BEGIN frame1Tests: LIST OF TestDescriptor _ LIST[ ["key", "44444"], ["inner", "(invalid proc descriptor address)"], ["result", "237864", 0, uninitializedVar], ["b", "[a:6, b:7]"], ["w", "[x:[a:4, b:5], y:[u:6, v:7]]"], ["y", "failure due to illegal operation: y undefined"], ["action", "???"], ["foo", "test.(no name)(pc=D30C4Ch, descr at C7BCC0h, src=1412)", 18], ["bar", "???"], ["x", "10"], ["veryBad", "???"], ["CallDebugger", "failure due to illegal operation: CallDebugger undefined"]]; nUnexpectedResults _ ExamineOneFrame[connection, frame1Tests, cmd.out] + nUnexpectedResults; END; <> [] _ StackCirio.WalkStack[stack, 1, cmd.out]; <> BEGIN frameText: Rope.ROPE _ StackCirio.ShowCurrentFrame[stack, cmd.out]; IO.PutF[cmd.out, "\n\n%g\n\n", IO.rope[frameText]]; END; <> BEGIN frame2Tests: LIST OF TestDescriptor _ LIST[ ["c", "'a"], ["quit", "FALSE"], ["bool1", "FALSE"], ["bool2", "TRUE"], ["charA", "'A"], ["charB", "'b"], ["array1", "(7)[6, 8, 10, 12, 14, 16, 18]"], ["array2", "(6)[11, 13, 15, 17, 19, 21]"], ["refR", "^[a:7, b:8]"], ["bb", "[ref:^[ref:NIL, a:45, b:46], a:47, b:48]"], ["refSeq", "^[x:10, (5)[3, 7, 11, 15, 19]]"], ["refSeq2", "^[y:45, (7)[TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, TRUE]]"], ["ref2Seq2", "^[y:77, (32)[TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, ...]]"], ["b", "[a:6, b:7]"], ["w", "[x:[a:4, b:5], y:[u:6, v:7]]"], ["y", "failure due to illegal operation: y undefined"], ["action", "???"], ["foo", "test.(no name)(pc=D3217Ch, descr at C7BE90h, src=1412)", 18], ["bar", "???"], ["x", "10"], ["veryBad", "???"], ["CallDebugger", "failure due to illegal operation: CallDebugger undefined"]]; nUnexpectedResults _ ExamineOneFrame[connection, frame2Tests, cmd.out] + nUnexpectedResults; END; <> [] _ StackCirio.WalkStack[stack, 2, cmd.out]; <> BEGIN frameText: Rope.ROPE _ StackCirio.ShowCurrentFrame[stack, cmd.out]; IO.PutF[cmd.out, "\n\n%g\n\n", IO.rope[frameText]]; END; <> BEGIN frame3Tests: LIST OF TestDescriptor _ LIST[ ["a", "22222"], ["deep", "1606016"], ["rope", "failure due to internal Cirio error"], ["arg1", "1234"], ["arg2", "5678"], ["res1", "node?"], ["res2", "node?"], ["z", "8518320"], ["yy", "3807"], ["ll", "x"], ["mm", "f"], ["q", "(invalid proc descriptor address)"], ["b", "[a:6, b:7]"], ["w", "[x:[a:4, b:5], y:[u:6, v:7]]"], ["y", "failure due to illegal operation: y undefined"], ["action", "???"], ["foo", "test.(no name)(pc=D3217Ch, descr at C7BE90h, src=1412)", 18], ["bar", "???"], ["x", "10"], ["veryBad", "???"], ["CallDebugger", "failure due to illegal operation: CallDebugger undefined"]]; nUnexpectedResults _ ExamineOneFrame[connection, frame3Tests, cmd.out] + nUnexpectedResults; END; <> IF nUnexpectedResults = 0 THEN IO.PutF[cmd.out, "\N\NThere were NO unexpected results\N\N"] ELSE IO.PutF[cmd.out, "\N\NThere were %g unexpected results\N\N", IO.card[nUnexpectedResults]]; <> EXIT; END; ENDLOOP; END; END; TestInner[]; -- so that unwinds from aborts from breakpoints will be caught END; CleanUp[] END; TestDescriptor: TYPE = RECORD[ expression: Rope.ROPE, expectedResult: Rope.ROPE, compareNCharsOnly: CARD _ 0, validity: Validity _ valid]; Validity: TYPE = {valid, uninitializedVar, WRONG}; ExamineOneFrame: PROC[connection: Connection, tryThis: LIST OF TestDescriptor, reports: IO.STREAM] RETURNS[--nUnexpectedResults-- CARD] = BEGIN ResultDescriptor: TYPE = RECORD[ expression: Rope.ROPE, expectedResult: Rope.ROPE, actualResult: Rope.ROPE]; deltas: LIST OF ResultDescriptor _ NIL; lastDelta: LIST OF ResultDescriptor _ NIL; news: LIST OF TestDescriptor _ NIL; lastNew: LIST OF TestDescriptor _ NIL; nUnexpectedResults: CARD _ 0; stack: StackCirio.Stack _ GetStackForCurrentThread[connection, reports]; FOR tests: LIST OF TestDescriptor _ tryThis, tests.rest WHILE tests # NIL DO result: Rope.ROPE _ StackCirio.InterpretTextLine[stack, tests.first.expression, reports]; new: LIST OF TestDescriptor _ LIST[[tests.first.expression, result, tests.first.compareNCharsOnly, tests.first.validity]]; nChars: CARD _ IF tests.first.compareNCharsOnly > 0 THEN tests.first.compareNCharsOnly ELSE Rope.Length[tests.first.expectedResult]; IF news = NIL THEN news _ new ELSE lastNew.rest _ new; lastNew _ new; IO.PutF[reports, "for expression: %g we get\N\T%g\N", IO.rope[tests.first.expression], IO.rope[result]]; IF (tests.first.validity # uninitializedVar) AND NOT Rope.Equal[Rope.Substr[result, 0, nChars], Rope.Substr[tests.first.expectedResult, 0, nChars]] THEN BEGIN delta: LIST OF ResultDescriptor _ LIST[[tests.first.expression, tests.first.expectedResult, result]]; IO.PutF[reports, " THIS IS WRONG, we expected\N\T%g\N\N", IO.rope[tests.first.expectedResult]]; IF deltas = NIL THEN deltas _ delta ELSE lastDelta.rest _ delta; lastDelta _ delta; nUnexpectedResults _ nUnexpectedResults + 1; END; ENDLOOP; IO.PutF[reports, "\N\Nhere is a list of expressions with their actual results\N"]; FOR items: LIST OF TestDescriptor _ news, items.rest WHILE items # NIL DO IO.PutF[reports, "\T[\"%g\", \"%g\"", IO.rope[items.first.expression], IO.rope[items.first.expectedResult]]; IF items.first.compareNCharsOnly > 0 OR items.first.validity # valid THEN IO.PutF[reports, ", %g", IO.card[items.first.compareNCharsOnly]]; IF items.first.validity # valid THEN IO.PutF[reports, ", %g", IO.rope[SELECT items.first.validity FROM uninitializedVar => "uninitializedVar", WRONG => "WRONG", ENDCASE => ERROR]]; IO.PutF[reports, "],\N"]; ENDLOOP; IF deltas # NIL THEN BEGIN IO.PutF[reports, "\N\Nthere were unexpected results\N"]; FOR items: LIST OF ResultDescriptor _ deltas, items.rest WHILE items # NIL DO IO.PutF[reports, "\Texpression: %g\N", IO.rope[items.first.expression]]; IO.PutF[reports, "\Texpected result: %g\N", IO.rope[items.first.expectedResult]]; IO.PutF[reports, "\Tactual result: %g\N", IO.rope[items.first.actualResult]]; ENDLOOP; END ELSE IO.PutF[reports, "\N\Nthere were NO unexpected results\N\N"]; RETURN[nUnexpectedResults]; END; InstallBreakCheckDaemon: PUBLIC PROC [connection: Connection, reports: IO.STREAM] = BEGIN IO.PutF[reports, "Installing daemon for breakpoint hit ...\n"]; connection.daemonKillFlag _ FALSE; connection.daemon _ FORK BreakCheckDaemon[connection: connection, reports: reports]; Process.Detach[connection.daemon]; IO.PutF[reports, " fork finished.\n"]; END; StopBreakCheckDaemon: PUBLIC PROC [connection: Connection, reports: IO.STREAM] = BEGIN connection.remoteWorldRunning _ FALSE; IO.PutF[reports, "killing BreakCheckDaemon...\n"]; connection.daemonKillFlag _ TRUE; Process.PauseMsec[3000]; END; BreakCheckDaemon: PROC [connection: Connection, reports: IO.STREAM] = BEGIN whichError: Rope.ROPE _ "$unkown"; { Process.SetPriority[Process.priorityBackground]; DO IF connection.daemonKillFlag = TRUE THEN GOTO terminate; WHILE connection.remoteWorldRunning = FALSE DO Process.PauseMsec[2000]; IF connection.daemonKillFlag = TRUE THEN GOTO terminate; ENDLOOP; IF CirioNubAccess.WaitSig[h: connection.nub, timeoutMilliSec: 100 ! CirioNub.Error => { whichError _ Rope.Cat["CirioNub (", Atom.GetPName[code], ")"]; GOTO connectionError; }; CirioNubAccess.Error => { l: LIST OF ATOM _ codes; didAny: CARD _ 0; whichError _ Rope.Cat["CirioNubAccess: ", msg, " ("]; WHILE l # NIL DO IF didAny # 0 THEN whichError _ whichError.Concat[", "]; whichError _ whichError.Concat[Atom.GetPName[l.first]]; l _ l.rest; ENDLOOP; GOTO connectionError; };] = FALSE THEN IO.PutF[reports, "SIGINT: Debuggee needs attention.\n"! IO.Error => GOTO ret]; <> <> Process.PauseMsec[2000]; ENDLOOP; EXITS terminate => {IO.PutF[reports, "BreakCheckDaemon killed.\n"! IO.Error => CONTINUE];RETURN}; connectionError => { IO.PutF[reports, "connection lost! %g BreakCheckDaemon exited.\n", [rope[whichError]]]; connection.open _ FALSE; RETURN}; ret => RETURN; }; END; <
> Commander.Register["RemoteCirioTest", RemoteCirioTest]; END..