DIRECTORY CirioDeltaFace USING[SameWorldGetFileEntry, SameWorldLookupMatchingSymEntryByName, SameWorldLookupMatchingSymEntryByValue, SameWorldLookupSymEntryByID, SameWorldLookupSymEntryByName, SameWorldLookupSymEntryByValue, SameWorldPCtoInfo], CirioNub USING[Block16, Block32, Block32Record, Call, CallResult, Create, Destroy, Error, Handle, ProcID, PutBlock32, PutCard32, PutInt32, PutBlock8Cnt, PutBlock8Next, PutRope, ReturnCode, StartCall], CirioNubAccess USING[AllocatedBytes, Field, Fields, FileEntry, FileEntryBody, Handle, HandleBody, PCInfo, PCInfoBody, ProcRep, RemoteAddress, SizeList, SymEntry, SymEntryBody, ThreadInfo, Typecode, Typestring], CirioNubAccessPrivate USING[AllocatedItems, AllocHandleBody --, HandleBody--], CirioTargets, Convert USING[<>RopeFromCard], ConvertUnsafe, GenericCall, IO, MesaLoadState, NetworkName USING [Error, AddressFromName], PBasics USING [RawBytes, RawChars], PCRMonitorDefs USING [MonitorLock, Thread, nullHolder], PFS USING [PathFromRope], PFSNames USING [PATH], RefText USING[InlineAppendChar, New], Rope, SafeStorage, SameWorldMonitoredCallOps USING [MonitoredCall]<< , Arpa USING[Address, nullAddress] , ConvertExtras USING[ArpaAddressFromRope, RopeFromArpaAddress] , SunYPAgent USING[Handle, Match, ObtainHandle, TextSeq, Tokenize] >>; CirioNubAccessImpl: CEDAR MONITOR LOCKS h USING h: Handle IMPORTS CirioDeltaFace, CirioNub, CirioTargets, Convert, ConvertUnsafe, GenericCall, IO, MesaLoadState, NetworkName, PFS, RefText, Rope, SameWorldMonitoredCallOps<<, ConvertExtras, SunYPAgent>> EXPORTS CirioNubAccess = BEGIN CirioNubBase: CirioNub.ProcID = 0; CedarCirioNubBase: CirioNub.ProcID = 64; Error: PUBLIC ERROR [codes: LIST OF ATOM, msg: Rope.ROPE] = CODE; RemoteNilFault: PUBLIC ERROR[addr: CirioNubAccess.RemoteAddress] = CODE; RemoteAddrFault: PUBLIC ERROR[addr: CirioNubAccess.RemoteAddress] = CODE; RemoteMonitorWouldBlock: PUBLIC ERROR[addr: CirioNubAccess.RemoteAddress] = CODE; Handle: TYPE = CirioNubAccess.Handle; HandleBody: TYPE = CirioNubAccess.HandleBody; RemoteBody: TYPE = RECORD[nub: CirioNub.Handle]; CreateRemoteNub: PUBLIC PROC[debuggee: Rope.ROPE _ NIL, port: CARDINAL _ 0, timeoutMsec: INT _ INT.LAST] RETURNS [Handle] = BEGIN proposedVersionNumber: CARD _ 7; addrRope: Rope.ROPE _ NameToAddress[debuggee]; longAddr: Rope.ROPE _ Rope.Cat[addrRope, ":", Convert.RopeFromCard[port]]; nub: CirioNub.Handle _ CirioNub.Create[NIL, longAddr, timeoutMsec]; h: Handle _ NEW[HandleBody _ [live: TRUE, version: 0, allocatedItems: NIL, contents: NEW[RemoteBody _ [nub]], target: NIL]]; IF NOT Null[h, proposedVersionNumber !UNWIND => CirioNub.Destroy[nub]] THEN { CirioNub.Destroy[nub]; h _ NIL; ERROR CirioNub.Error[$protocolVersionMismatch]}; h.target _ CirioTargets.CreateTarget[h]; RETURN[h]; END; CreateSameWorldNub: PUBLIC PROC RETURNS [Handle] = BEGIN proposedVersionNumber: CARD _ 7; h: Handle _ NEW[HandleBody_[live: TRUE, version: 0, allocatedItems: NIL, contents: NIL, target: NIL ]]; IF NOT Null[h, proposedVersionNumber] THEN ERROR Error[LIST[$protocolMismatch], IO.PutFR["the debuggee doesn't want to speak version %g of the DebugNub protocol", [cardinal[proposedVersionNumber]] ]]; h.target _ CirioTargets.CreateTarget[h]; RETURN[h]; END; DestroyNub: PUBLIC ENTRY PROC[h: Handle] = BEGIN ENABLE UNWIND => NULL; IF NOT h.live THEN ERROR Error[LIST[$notLive], "attempt to use a dead connection"]; IF h.allocatedItems # NIL THEN FOR I: CARD IN [0..h.allocatedItems.nSlots) DO IF h.allocatedItems[I] # NIL THEN InnerReleaseAllocatedBytes[h, h.allocatedItems[I]] ENDLOOP; h.live _ FALSE; IF h.contents # NIL THEN RemoteDestroyNub[NARROW[h.contents, REF RemoteBody].nub] ELSE RETURN; END; GetProtocolVersionNumber: PUBLIC ENTRY PROC[h: Handle] RETURNS[CARD] = BEGIN ENABLE UNWIND => NULL; RETURN[h.version]; END; Null: PUBLIC ENTRY PROC[h: Handle, proposedVersionNumber: CARD] RETURNS[BOOLEAN] = BEGIN ENABLE UNWIND => NULL; IF NOT h.live THEN ERROR Error[LIST[$notLive], "attempt to use a dead connection"]; IF proposedVersionNumber # 4 AND proposedVersionNumber # 5 AND proposedVersionNumber # 6 AND proposedVersionNumber # 7 THEN ERROR Error[LIST[$protocolMismatch], IO.PutFR["attempt to use a non-current (<4 or >7) version of the protocol (%g)", [cardinal[proposedVersionNumber]] ]]; IF h.contents # NIL THEN BEGIN h.version _ RemoteNull[NARROW[h.contents, REF RemoteBody].nub, proposedVersionNumber]; IF h.version # 4 AND h.version # 5 AND h.version # 6 AND h.version # 7 THEN ERROR Error[LIST[$protocolMismatch], IO.PutFR["debuggee uses a non-current (<4 or >7) version of the protocol (%g)", [cardinal[h.version]] ]]; RETURN[TRUE] END ELSE BEGIN h.version _ MIN[6, proposedVersionNumber]; RETURN[h.version = 4 OR h.version = 5 OR h.version = 6 OR h.version = 7]; END; END; WaitSig: PUBLIC ENTRY PROC[h: Handle, timeoutMilliSec: CARD] RETURNS[gotResponse: BOOLEAN] = BEGIN ENABLE UNWIND => NULL; IF NOT h.live THEN ERROR Error[LIST[$notLive], "attempt to use a dead connection"]; IF h.contents # NIL THEN RETURN[RemoteWaitSig[NARROW[h.contents, REF RemoteBody].nub, timeoutMilliSec]] ELSE ERROR Error[LIST[$unimplemented, $local, $WaitSig], "CirioNubAccess.WaitSig is not implemented for local debugging"]; END; SetDBStat: PUBLIC ENTRY PROC[h: Handle, dbStat: INT32, timeoutMilliSec: CARD] RETURNS[ok: BOOLEAN] = BEGIN ENABLE UNWIND => NULL; IF NOT h.live THEN ERROR Error[LIST[$notLive], "attempt to use a dead connection"]; IF h.contents # NIL THEN RETURN[RemoteSetDBStat[NARROW[h.contents, REF RemoteBody].nub, dbStat, timeoutMilliSec]] ELSE ERROR Error[LIST[$unimplemented, $local, $SetDBStat], "CirioNubAccess.SetDBStat is not implemented for local debugging"]; END; ReadBytes: PUBLIC PROC[address: CirioNubAccess.RemoteAddress, count: INT] RETURNS[REF TEXT] = BEGIN Inner: ENTRY PROC[h: Handle] RETURNS[REF TEXT] = BEGIN ENABLE UNWIND => NULL; IF address.nil THEN RemoteNilFault[address]; IF NOT address.valid THEN RemoteAddrFault[address]; IF NOT address.h.live THEN ERROR Error[LIST[$notLive], "attempt to use a dead connection"]; IF address.h.contents # NIL THEN RETURN[RemoteReadBytes[nub: NARROW[address.h.contents, REF RemoteBody].nub, address: address, count: count]] ELSE RETURN[SameWorldReadBytes[address: address, count: count]]; END; RETURN[Inner[address.h]]; END; Read16BitsAsCardinal: PUBLIC PROC[address: CirioNubAccess.RemoteAddress] RETURNS[CARDINAL] = BEGIN Inner: ENTRY PROC[h: Handle] RETURNS[CARDINAL] = BEGIN ENABLE UNWIND => NULL; IF address.nil THEN RemoteNilFault[address]; IF NOT address.valid THEN RemoteAddrFault[address]; IF NOT address.h.live THEN ERROR Error[LIST[$notLive], "attempt to use a dead connection"]; IF address.h.contents # NIL THEN RETURN[RemoteRead16BitsAsCardinal[nub: NARROW[address.h.contents, REF RemoteBody].nub, address: address]] ELSE RETURN[SameWorldRead16BitsAsCardinal[address: address]]; END; RETURN[Inner[address.h]]; END; Read32BitsAsCard: PUBLIC PROC[address: CirioNubAccess.RemoteAddress] RETURNS[CARD] = BEGIN Inner: ENTRY PROC[h: Handle] RETURNS[CARD] = BEGIN ENABLE UNWIND => NULL; IF address.nil THEN RemoteNilFault[address]; IF NOT address.valid THEN RemoteAddrFault[address]; IF NOT address.h.live THEN ERROR Error[LIST[$notLive], "attempt to use a dead connection"]; IF address.h.contents # NIL THEN RETURN[RemoteRead32BitsAsCard[nub: NARROW[address.h.contents, REF RemoteBody].nub, address: address]] ELSE RETURN[SameWorldRead32BitsAsCard[address: address]]; END; RETURN[Inner[address.h]]; END; WriteCardAs32Bits: PUBLIC PROC[address: CirioNubAccess.RemoteAddress, card: CARD32] = BEGIN Inner: ENTRY PROC[h: Handle] = BEGIN ENABLE UNWIND => NULL; IF address.nil THEN RemoteNilFault[address]; IF NOT address.valid THEN RemoteAddrFault[address]; IF NOT address.h.live THEN ERROR Error[LIST[$notLive], "attempt to use a dead connection"]; IF address.h.contents # NIL THEN RemoteWriteCardAs32Bits[nub: NARROW[address.h.contents, REF RemoteBody].nub, address: address, card: card] ELSE SameWorldWriteCardAs32Bits[address: address, card: card]; END; Inner[address.h]; END; Read4Bytes: PUBLIC PROC[address: CirioNubAccess.RemoteAddress] RETURNS[PACKED ARRAY [0..3] OF BYTE] = BEGIN text: REF TEXT _ ReadBytes[address, 4]; IF text.length # 4 THEN ERROR Error[LIST[$cantHappen], "ReadBytes[.., 4] returned a REF TEXT whose length wasn't 4"]; RETURN[[ORD[text[0]], ORD[text[1]], ORD[text[2]], ORD[text[3]]]]; END; Write4Bytes: PUBLIC PROC[address: CirioNubAccess.RemoteAddress, bytes: PACKED ARRAY [0..3] OF BYTE] = BEGIN Inner: ENTRY PROC[h: Handle] = BEGIN ENABLE UNWIND => NULL; IF address.nil THEN RemoteNilFault[address]; IF NOT address.valid THEN RemoteAddrFault[address]; IF NOT address.h.live THEN ERROR Error[LIST[$notLive], "attempt to use a dead connection"]; IF address.h.contents # NIL THEN RemoteWrite4Bytes[nub: NARROW[address.h.contents, REF RemoteBody].nub, address: address, bytes: bytes] ELSE SameWorldWrite4Bytes[address: address, bytes: bytes]; END; Inner[address.h]; END; GetThreads: PUBLIC ENTRY PROC[h: Handle, lowIndex, highIndex: CARD] RETURNS[LIST OF REF CirioNubAccess.ThreadInfo] = BEGIN ENABLE UNWIND => NULL; IF NOT h.live THEN ERROR Error[LIST[$notLive], "attempt to use a dead connection"]; IF h.contents # NIL THEN RETURN[RemoteGetThreads[NARROW[h.contents, REF RemoteBody].nub, lowIndex, highIndex]] ELSE ERROR Error[LIST[$unimplemented, $local, $GetThreads], "CirioNubAccess.GetThreads is not implemented for local debugging"]; END; PCtoInfo: PUBLIC ENTRY PROC[h: Handle, pc: CARD] RETURNS[CirioNubAccess.PCInfo] = BEGIN ENABLE UNWIND => NULL; IF NOT h.live THEN ERROR Error[LIST[$notLive], "attempt to use a dead connection"]; IF h.contents # NIL THEN RETURN[RemotePCtoInfo[NARROW[h.contents, REF RemoteBody].nub, pc]] ELSE RETURN[CirioDeltaFace.SameWorldPCtoInfo[pc]]; END; KillWorld: PUBLIC ENTRY PROC[h: Handle] = BEGIN ENABLE UNWIND => NULL; IF NOT h.live THEN ERROR Error[LIST[$notLive], "attempt to use a dead connection"]; IF h.contents # NIL THEN RemoteKillWorld[NARROW[h.contents, REF RemoteBody].nub] ELSE ERROR Error[LIST[$unimplemented, $local, $KillWorld], "CirioNubAccess.KillWorld is not implemented for local debugging"]; END; IssueThreadCommand: PUBLIC ENTRY PROC[h: Handle, threadIndex: CARD, setFreeze: BOOL, freeze: BOOL, setMsg: BOOL, msg: INT] RETURNS[success: BOOLEAN] = BEGIN ENABLE UNWIND => NULL; IF NOT h.live THEN ERROR Error[LIST[$notLive], "attempt to use a dead connection"]; IF h.contents # NIL THEN RETURN[RemoteIssueThreadCommand[NARROW[h.contents, REF RemoteBody].nub, threadIndex, setFreeze, freeze, setMsg, msg]] ELSE ERROR Error[LIST[$unimplemented, $local, $IssueThreadCommand], "CirioNubAccess.IssueThreadCommand is not implemented for local debugging"]; END; GetDBStat: PUBLIC ENTRY PROC[h: Handle, oldStat: INT32, oldExamineeIndex: INT, timeoutMsec: CARD] RETURNS[dbStab: INT32, examineeIndex: INT32] = BEGIN ENABLE UNWIND => NULL; IF NOT h.live THEN ERROR Error[LIST[$notLive], "attempt to use a dead connection"]; IF h.contents # NIL THEN BEGIN [dbStab, examineeIndex] _ RemoteGetDBStat[NARROW[h.contents, REF RemoteBody].nub, oldStat, oldExamineeIndex, timeoutMsec]; RETURN; END ELSE ERROR Error[LIST[$unimplemented, $local, $GetDBStat], "CirioNubAccess.GetDBStat is not implemented for local debugging"]; END; Call: PUBLIC PROC [h: Handle, proc: CirioNubAccess.ProcRep, formalArgSizes, formalRetSizes: CirioNubAccess.SizeList, actualArgs, actualRets: CirioNubAccess.Fields] ~ { IF h.contents # NIL THEN ERROR Error[LIST[$unimplemented, $remote, $Call], "CirioNubAccess.Call is not implemented for remote debugging"]; TRUSTED {GenericCall.Call[LOOPHOLE[proc], formalArgSizes, formalRetSizes, ConvertFields[actualArgs], ConvertFields[actualRets]]}; RETURN}; ConvertFields: PROC [cfs: CirioNubAccess.Fields] RETURNS [gfs: GenericCall.Fields] ~ { gfs _ NEW [GenericCall.FieldSeq[cfs.length]]; FOR i: NAT IN [0..gfs.length) DO cf: CirioNubAccess.Field ~ cfs[i]; gfs[i] _ [address: cf.address, bitOffset: cf.bitOffset, bits: cf.bits]; ENDLOOP; RETURN}; GetFileEntry: PUBLIC ENTRY PROC[h: Handle, seqNum: CARD] RETURNS[CirioNubAccess.FileEntry] = BEGIN ENABLE UNWIND => NULL; IF NOT h.live THEN ERROR Error[LIST[$notLive], "attempt to use a dead connection"]; IF h.contents # NIL THEN SELECT h.version FROM 0 => ERROR Error[LIST[$noVersionYet], "CirioNubAccess.GetFileEntry called on a Handle whose version has not yet been determined"]; 4 => RETURN[RemoteGetFileEntry4[NARROW[h.contents, REF RemoteBody].nub, seqNum]]; 5, 6, 7 => RETURN[RemoteGetFileEntry5[NARROW[h.contents, REF RemoteBody].nub, seqNum]] ENDCASE => ERROR Error[LIST[$protocolMismatch], IO.PutFR["CirioNubAccess.GetFileEntry called on a handle whose version, %g, is not in the current range, [4..7]", [cardinal[h.version]] ]] ELSE RETURN[CirioDeltaFace.SameWorldGetFileEntry[seqNum]]; END; LookupSymEntryByName: PUBLIC ENTRY PROC[h: Handle, sym: Rope.ROPE, caseSensitive: BOOLEAN, externOnly: BOOLEAN, numToSkip: INT] RETURNS[CirioNubAccess.SymEntry] = BEGIN ENABLE UNWIND => NULL; IF NOT h.live THEN ERROR Error[LIST[$notLive], "attempt to use a dead connection"]; IF h.contents # NIL THEN RETURN[RemoteLookupSymEntryByName[NARROW[h.contents, REF RemoteBody].nub, sym, caseSensitive, externOnly, numToSkip]] ELSE RETURN[CirioDeltaFace.SameWorldLookupSymEntryByName[sym, caseSensitive, externOnly, numToSkip]]; END; LookupSymEntryByValue: PUBLIC ENTRY PROC[h: Handle, val: CARD, numToSkip: INT] RETURNS[CirioNubAccess.SymEntry] = BEGIN ENABLE UNWIND => NULL; IF NOT h.live THEN ERROR Error[LIST[$notLive], "attempt to use a dead connection"]; IF h.contents # NIL THEN RETURN[RemoteLookupSymEntryByValue[NARROW[h.contents, REF RemoteBody].nub, val, numToSkip]] ELSE RETURN[CirioDeltaFace.SameWorldLookupSymEntryByValue[val, numToSkip]]; END; LookupSymEntryByID: PUBLIC ENTRY PROC[h: Handle, symID: CARD] RETURNS[CirioNubAccess.SymEntry] = BEGIN ENABLE UNWIND => NULL; IF NOT h.live THEN ERROR Error[LIST[$notLive], "attempt to use a dead connection"]; IF h.contents # NIL THEN RETURN[RemoteLookupSymEntryByID[NARROW[h.contents, REF RemoteBody].nub, symID]] ELSE RETURN[CirioDeltaFace.SameWorldLookupSymEntryByID[symID]]; END; LookupFileEntryByStemName: PUBLIC PROC[h: Handle, stemName: Rope.ROPE, numToSkip: INT] RETURNS[CirioNubAccess.SymEntry] = BEGIN IF NOT h.live THEN ERROR Error[LIST[$notLive], "attempt to use a dead connection"]; SELECT h.version FROM 0 => ERROR Error[LIST[$noVersionYet], "CirioNubAccess.LookupFileEntryByStemName called on a Handle whose version has not yet been determined"]; 4, 5 => BEGIN direction: INT _ IF numToSkip < 0 THEN -1 ELSE 1; nSkipped: INT _ 0; FOR skip: INT _ 0, skip + direction DO entry: CirioNubAccess.SymEntry _ LookupSymEntryByName[h, Rope.Cat[stemName, ".c2c.o"], FALSE, FALSE, skip]; IF entry = NIL THEN RETURN[entry]; -- no such file in the load state IF entry.type # ModuleType AND entry.type # (ModuleType+1) THEN LOOP; IF nSkipped = numToSkip THEN RETURN[entry]; nSkipped _ nSkipped + direction; ENDLOOP; END; 6, 7 => RETURN[LookupMatchingSymEntryByName[h, 0, Rope.Cat[stemName, ".*"], FALSE, ModuleType, 0, numToSkip]]; ENDCASE => ERROR Error[LIST[$protocolMismatch], IO.PutFR["CirioNubAccess.LookupFileEntryByStemName called on a handle whose version, %g, is not in the current range, [4..7]", [cardinal[h.version]] ]] END; ModuleType: CARD = 1eH; TextType: CARD = 4; LookupMatchingSymEntryByName: PUBLIC ENTRY PROC[h: Handle, symID: CARD, pattern: Rope.ROPE, caseSensitive: BOOLEAN, wantedTypes: CARD, ignoreClasses: CARD, numToSkip: INT] RETURNS[CirioNubAccess.SymEntry] = BEGIN ENABLE UNWIND => NULL; IF NOT h.live THEN ERROR Error[LIST[$notLive], "attempt to use a dead connection"]; IF h.version < 6 THEN ERROR Error[LIST[$protocolMismatch], IO.PutFR["CirioNubAccess.LookupMatchingSymEntryByName called on a Handle whose version, %g, is less than 6", [cardinal[h.version]] ]]; IF h.contents # NIL THEN RETURN[RemoteLookupMatchingSymEntryByName[NARROW[h.contents, REF RemoteBody].nub, symID, pattern, caseSensitive, wantedTypes, ignoreClasses, numToSkip]] ELSE RETURN[CirioDeltaFace.SameWorldLookupMatchingSymEntryByName[symID, pattern, caseSensitive, wantedTypes, ignoreClasses, numToSkip]]; END; LookupMatchingSymEntryByValue: PUBLIC ENTRY PROC[h: Handle, symID: CARD, val: CARD, wantedTypes: CARD, ignoreClasses: CARD, numToSkip: INT] RETURNS[CirioNubAccess.SymEntry] = BEGIN ENABLE UNWIND => NULL; IF NOT h.live THEN ERROR Error[LIST[$notLive], "attempt to use a dead connection"]; IF h.version < 6 THEN ERROR Error[LIST[$protocolMismatch], IO.PutFR["CirioNubAccess.LookupMatchingSymEntryByValue called on a Handle whose version, %g, is less than 6", [cardinal[h.version]] ]]; IF h.contents # NIL THEN RETURN[RemoteLookupMatchingSymEntryByValue[NARROW[h.contents, REF RemoteBody].nub, symID, val, wantedTypes, ignoreClasses, numToSkip]] ELSE RETURN[CirioDeltaFace.SameWorldLookupMatchingSymEntryByValue[symID, val, wantedTypes, ignoreClasses, numToSkip]]; END; AllocHandle: TYPE = REF AllocHandleBody; AllocHandleBody: PUBLIC TYPE = CirioNubAccessPrivate.AllocHandleBody; AllocateBytes: PUBLIC ENTRY PROC[h: Handle, nBytes: CARD] RETURNS[CirioNubAccess.AllocatedBytes] = BEGIN ENABLE UNWIND => NULL; IF NOT h.live THEN ERROR Error[LIST[$notLive], "attempt to use a dead connection"]; IF h.version < 6 THEN ERROR Error[LIST[$protocolMismatch], IO.PutFR["CirioNubAccess.AllocateBytes called on a Handle whose version, %g, is less than 6", [cardinal[h.version]] ]]; IF h.contents # NIL THEN ERROR Error[LIST[$unimplemented, $remote, $AllocateBytes], "CirioNubAccess.AllocateBytes not implemented for remote debugging"] ELSE BEGIN ah: REF CirioNubAccessPrivate.AllocHandleBody _ GetAnAllocHandle[h]; byteAddress: CARD; [ah.data, byteAddress] _ SameWorldAllocateBytes[nBytes]; RETURN[[ah, [h, byteAddress, 0, FALSE, TRUE]]]; END; END; GetAnAllocHandle: PROC[h: Handle] RETURNS[REF CirioNubAccessPrivate.AllocHandleBody] = BEGIN index: CARD; -- will be filled in IF h.allocatedItems = NIL THEN BEGIN count: CARD _ 100; new: REF CirioNubAccessPrivate.AllocatedItems _ NEW[CirioNubAccessPrivate.AllocatedItems[count]]; new.earlyFreeSlots _ NIL; new.firstLateFreeSlot _ 0; FOR I: CARD IN [0..count) DO new[I] _ NIL ENDLOOP; h.allocatedItems _ new; END; IF h.allocatedItems.earlyFreeSlots # NIL THEN BEGIN index _ h.allocatedItems.earlyFreeSlots.first; h.allocatedItems.earlyFreeSlots _ h.allocatedItems.earlyFreeSlots.rest; END ELSE BEGIN IF h.allocatedItems.firstLateFreeSlot = h.allocatedItems.nSlots THEN BEGIN newCount: CARD _ h.allocatedItems.nSlots*2; new: REF CirioNubAccessPrivate.AllocatedItems _ NEW[CirioNubAccessPrivate.AllocatedItems[newCount]]; new.earlyFreeSlots _ NIL; new.firstLateFreeSlot _ h.allocatedItems.nSlots; FOR I: CARD IN [0..h.allocatedItems.nSlots) DO new[I] _ h.allocatedItems[I] ENDLOOP; FOR I: CARD IN [h.allocatedItems.nSlots..newCount) DO new[I] _ NIL ENDLOOP; h.allocatedItems _ new; END; BEGIN index _ h.allocatedItems.firstLateFreeSlot; h.allocatedItems.firstLateFreeSlot _ h.allocatedItems.firstLateFreeSlot+1; END; END; BEGIN ah: REF AllocHandleBody _ NEW[CirioNubAccessPrivate.AllocHandleBody_[h, index, NIL]]; IF h.allocatedItems[index] # NIL THEN ERROR Error[LIST[$cantHappen], "CirioNubAccessImpl.GetAnAllocHandle computed used an index that's not free"]; h.allocatedItems[index] _ ah; RETURN[ah]; END; END; ReleaseAllocatedBytes: PUBLIC PROC[allocHandle: AllocHandle] = { Inner: ENTRY PROC[h: Handle] = { ENABLE UNWIND => NULL; InnerReleaseAllocatedBytes[h, allocHandle]; RETURN}; Inner[allocHandle.h]; RETURN}; InnerReleaseAllocatedBytes: INTERNAL PROC[h: Handle, allocHandle: AllocHandle] ~ { IF NOT h.live THEN ERROR Error[LIST[$notLive], "attempt to use a dead connection"]; IF h.version < 6 THEN ERROR Error[LIST[$protocolMismatch], IO.PutFR["CirioNubAccess.ReleaseAllocatedBytes called on a Handle whose version, %g, is less than 6", [cardinal[h.version]] ]]; ReleaseAnAllocHandle[h, allocHandle]; IF h.contents # NIL THEN Error[LIST[$unimplemented, $remote, $ReleaseAllocatedBytes], "CirioNubAccess.ReleaseAllocatedBytes not implemented for remote debugging"] ELSE SameWorldReleaseAllocatedBytes[allocHandle.data]; RETURN}; ReleaseAnAllocHandle: PROC[h: Handle, ah: REF CirioNubAccessPrivate.AllocHandleBody] = BEGIN IF ah.h # h THEN ERROR; IF h.allocatedItems[ah.index] # ah THEN ERROR Error[LIST[$cantHappen], "attempt to free a broken AllocHandle"]; h.allocatedItems.earlyFreeSlots _ CONS[ah.index, h.allocatedItems.earlyFreeSlots]; h.allocatedItems[ah.index] _ NIL; END; MonitoredCall: PUBLIC PROC[ address: CirioNubAccess.RemoteAddress, proc: PROCEDURE [] RETURNS []] RETURNS [] = BEGIN Inner: -- ENTRY -- PROC[h: Handle] = BEGIN ENABLE UNWIND => NULL; IF address.nil THEN RemoteNilFault[address]; IF NOT address.valid THEN RemoteAddrFault[address]; IF NOT address.bitOffset = 0 THEN RemoteAddrFault[address]; IF NOT address.h.live THEN ERROR Error[LIST[$notLive], "attempt to use a dead connection"]; IF address.h.contents # NIL THEN RemoteMonitoredCall[address: address, proc: proc] ELSE SameWorldMonitoredCall[address: address, proc: proc]; END; Inner[h: address.h]; END; GetConcreteTypecode: PUBLIC PROC[h: Handle, opaque: CirioNubAccess.Typecode] RETURNS[concrete: CirioNubAccess.Typecode, whyNot: Rope.ROPE] ~ { IF NOT h.live THEN ERROR Error[LIST[$notLive], "attempt to use a dead connection"]; IF h.contents#NIL THEN { IF h.version <7 THEN RETURN[[0], IO.PutFR["CirioNubAccess.RemoteGetConcreteTypecode called on a Handle whose version, %g, is less than 7", [cardinal[h.version]] ]]; concrete _ RemoteGetConcreteTypecode[h, opaque]; RETURN[concrete, NIL]; } ELSE { ans: SafeStorage.Type ~ MesaLoadState.ConcreteTypeFromAbstractType[VAL[opaque]]; RETURN[[ans.ORD], NIL]}; }; GetTypestring: PUBLIC PROC[h: Handle, code: CirioNubAccess.Typecode] RETURNS[string: CirioNubAccess.Typestring, whyNot: Rope.ROPE] ~ { IF NOT h.live THEN ERROR Error[LIST[$notLive], "attempt to use a dead connection"]; IF h.contents#NIL THEN { IF h.version <7 THEN RETURN[NIL, IO.PutFR["CirioNubAccess.RemoteGetTypestring called on a Handle whose version, %g, is less than 7", [cardinal[h.version]] ]]; string _ RemoteGetTypestring[h, code]; RETURN[string, NIL]; } ELSE { ts: STRING ~ MesaLoadState.TypeStringFromType[VAL[code]]; ans: Rope.ROPE _ NIL; TRUSTED {ans _ ConvertUnsafe.SubStringToRope[[ts, 0, ts.length]]}; RETURN[ans, NIL]}; }; GetTypecode: PUBLIC PROC[h: Handle, string: CirioNubAccess.Typestring] RETURNS [code: CirioNubAccess.Typecode, whyNot: Rope.ROPE _ NIL] ~ { IF NOT h.live THEN ERROR Error[LIST[$notLive], "attempt to use a dead connection"]; IF h.contents#NIL THEN { IF h.version <7 THEN RETURN[[0], IO.PutFR["CirioNubAccess.RemoteGetTypecode called on a Handle whose version, %g, is less than 7", [cardinal[h.version]] ]]; code _ RemoteGetTypecode[h, string]; RETURN[code, NIL]; } ELSE { ts: REF TEXT ~ RefText.New[string.Length]; ans: SafeStorage.Type; [] _ Rope.AppendChars[ts, string]; ans _ MesaLoadState.TypeFromTypeString[LOOPHOLE[ts, STRING]]; RETURN[[ans.ORD], NIL]}; }; GetInstructionSetAndOperatingSystem: PUBLIC ENTRY PROC [h: Handle] RETURNS[instrSet, opSys: Rope.ROPE] ~ { ENABLE UNWIND => NULL; GetInstrSetAndOpSys: CirioNub.ProcID = CirioNubBase + 30; rc: CirioNub.ReturnCode; result: CirioNub.CallResult; nub: CirioNub.Handle; instrSet3:Rope.ROPE _ "RS6000"; opSys3:Rope.ROPE _ "AIX"; instrSet _ "SPARC"; opSys _ "SunOS4"; IF NOT h.live THEN ERROR Error[LIST[$notLive], "attempt to use a dead connection"]; IF h.version < 7 THEN RETURN; nub _ NARROW[h.contents, REF RemoteBody].nub; CirioNub.StartCall[nub, GetInstrSetAndOpSys]; [rc, result] _ CirioNub.Call[nub]; IF rc # ok THEN ERROR Error[LIST[$something], Rope.Cat["Can't determine the InstructionSet name or OperatingSystem name of the remote target. ReturnCode is ", GetReturnCodeRope[rc], "."]]; IF result.count # 2 THEN ERROR Error[LIST[$something], "Can't determine the InstructionSet name or OperatingSystem name of the remote target. Wrong number of arguments returned."]; instrSet _ Rope.FromRefText[NARROW[result.val[0]]]; opSys _ Rope.FromRefText[NARROW[result.val[1]]]; RETURN; }; RemoteDestroyNub: PROC[nub: CirioNub.Handle] = {CirioNub.Destroy[nub]}; RemoteNull: PROC[nub: CirioNub.Handle, proposedVersionNumber: CARD] RETURNS[actualVersionNumber: CARD32] = BEGIN CirioNubNull: CirioNub.ProcID = CirioNubBase + 0; rc: CirioNub.ReturnCode; result: CirioNub.CallResult; CirioNub.StartCall[nub, CirioNubNull]; CirioNub.PutCard32[nub, proposedVersionNumber]; [rc, result] _ CirioNub.Call[nub]; IF rc # ok THEN ERROR Error[LIST[$something], Rope.Cat["Can't get remote DebugNub version number. ReturnCode is ", GetReturnCodeRope[rc], "."]]; IF result.count # 1 THEN ERROR Error[LIST[$something], "Can't get remote DebugNub version number. Wrong number of arguments returned."]; actualVersionNumber _ NARROW[result[0], REF CARD32]^; END; RemoteWaitSig: PROC[nub: CirioNub.Handle, timeoutMilliSec: CARD] RETURNS[gotResponse: BOOLEAN] = BEGIN CirioNubWaitSig: CirioNub.ProcID = CirioNubBase + 1; rc: CirioNub.ReturnCode; result: CirioNub.CallResult; CirioNub.StartCall[nub, CirioNubWaitSig]; CirioNub.PutCard32[nub, timeoutMilliSec]; [rc, result] _ CirioNub.Call[nub]; IF rc # ok THEN ERROR Error[LIST[$something], Rope.Cat["Error calling WaitSig in the remote target. ReturnCode is ", GetReturnCodeRope[rc], "."]]; IF result.count # 2 THEN ERROR Error[LIST[$something], "Error calling WaitSig in the remote target. Wrong number of arguments returned."]; gotResponse _ (NARROW[result.val[0], REF INT32])^ = 0; END; RemoteSetDBStat: PROC[nub: CirioNub.Handle, dbStat: INT32, timeoutMilliSec: CARD] RETURNS[ok: BOOLEAN] = BEGIN CirioNubSetDBStat: CirioNub.ProcID = CirioNubBase + 2; rc: CirioNub.ReturnCode; result: CirioNub.CallResult; CirioNub.StartCall[nub, CirioNubSetDBStat]; CirioNub.PutInt32[nub, dbStat]; CirioNub.PutCard32[nub, timeoutMilliSec]; [rc, result] _ CirioNub.Call[nub]; IF rc # ok THEN ERROR Error[LIST[$something], Rope.Cat["Error calling SetDBStat in the remote target. ReturnCode is ", GetReturnCodeRope[rc], "."]]; IF result.count # 1 THEN ERROR Error[LIST[$something], "Error calling SetDBStat in the remote target. Wrong number of arguments returned."]; ok _ (NARROW[result.val[0], REF INT32])^ = 0; END; RemoteReadBytes: PROC[nub: CirioNub.Handle, address: CirioNubAccess.RemoteAddress, count: INT] RETURNS[REF TEXT] = { CirioNubGetBytes: CirioNub.ProcID = CirioNubBase + 3; rc: CirioNub.ReturnCode; result: CirioNub.CallResult; text: REF TEXT; IF address.nil THEN RemoteNilFault[address]; IF NOT address.valid THEN RemoteAddrFault[address]; IF address.valid THEN BEGIN CirioNub.StartCall[nub, CirioNubGetBytes]; CirioNub.PutCard32[nub, address.byteAddress+(address.bitOffset/8)]; CirioNub.PutInt32[nub, count]; -- asking for count bytes [rc, result] _ CirioNub.Call[nub]; IF rc # ok THEN ERROR Error[LIST[$something], Rope.Cat["Error calling GetBytes in the remote target. ReturnCode is ", GetReturnCodeRope[rc], "."]]; IF result.count # 1 THEN ERROR Error[LIST[$something], "Error calling GetBytes in the remote target. Wrong number of arguments returned."]; text _ NARROW[result.val[0]]; RETURN[text] END ELSE RETURN[NIL]; }; RemoteRead16BitsAsCardinal: PROC[nub: CirioNub.Handle, address: CirioNubAccess.RemoteAddress] RETURNS[CARDINAL] = { CirioNubGetWords16: CirioNub.ProcID = CirioNubBase + 5; rc: CirioNub.ReturnCode; result: CirioNub.CallResult; block16: CirioNub.Block16; remoteByteAddress: CARD _ address.byteAddress+address.bitOffset/8; IF address.nil THEN RemoteNilFault[address]; IF NOT address.valid THEN RemoteAddrFault[address]; CirioNub.StartCall[nub, CirioNubGetWords16]; CirioNub.PutCard32[nub, remoteByteAddress]; CirioNub.PutInt32[nub, 2]; -- asking for 2 bytes [rc, result] _ CirioNub.Call[nub]; IF rc # ok THEN ERROR Error[LIST[$something], Rope.Cat["Error calling GetWords16 in the remote target. ReturnCode is ", GetReturnCodeRope[rc], "."]]; IF result.count # 1 THEN ERROR Error[LIST[$something], "Error calling GetWords16 in the remote target. Wrong number of arguments returned."]; block16 _ NARROW[result.val[0]]; IF block16.count # 1 THEN RemoteAddrFault[address]; RETURN[block16.val[0]] }; RemoteAddressRangeCheck: PROC[remoteByteAddress: CARD] RETURNS[BOOL] = { RETURN[remoteByteAddress > 0 AND remoteByteAddress < 1000]}; RemoteRead32BitsAsCard: PROC[nub: CirioNub.Handle, address: CirioNubAccess.RemoteAddress] RETURNS[CARD] = { CirioNubGetWords32: CirioNub.ProcID = CirioNubBase + 7; rc: CirioNub.ReturnCode; result: CirioNub.CallResult; block32: CirioNub.Block32; remoteByteAddress: CARD _ address.byteAddress+address.bitOffset/8; IF address.nil THEN RemoteNilFault[address]; IF NOT address.valid THEN RemoteAddrFault[address]; IF RemoteAddressRangeCheck[remoteByteAddress] THEN RemoteAddrFault[address]; CirioNub.StartCall[nub, CirioNubGetWords32]; CirioNub.PutCard32[nub, remoteByteAddress]; CirioNub.PutInt32[nub, 4]; -- asking for 4 bytes [rc, result] _ CirioNub.Call[nub]; IF rc # ok THEN ERROR Error[LIST[$something], Rope.Cat["Error calling GetWords32 in the remote target. ReturnCode is ", GetReturnCodeRope[rc], "."]]; IF result.count # 1 THEN ERROR Error[LIST[$something], "Error calling GetWords32 in the remote target. Wrong number of arguments returned."]; block32 _ NARROW[result.val[0]]; IF block32.count # 1 THEN RemoteAddrFault[address]; RETURN[block32.val[0]] }; RemoteWriteCardAs32Bits: PROC[nub: CirioNub.Handle, address: CirioNubAccess.RemoteAddress, card: CARD32] = { CirioNubPutWords32: CirioNub.ProcID = CirioNubBase + 8; rc: CirioNub.ReturnCode; result: CirioNub.CallResult; block32: CirioNub.Block32 _ NEW[CirioNub.Block32Record[1]]; remoteByteAddress: CARD _ address.byteAddress+address.bitOffset/8; block32.count _ 1; block32[0] _ card; IF address.nil THEN RemoteNilFault[address]; IF NOT address.valid THEN RemoteAddrFault[address]; IF RemoteAddressRangeCheck[remoteByteAddress] THEN RemoteAddrFault[address]; CirioNub.StartCall[nub, CirioNubPutWords32]; CirioNub.PutCard32[nub, remoteByteAddress]; CirioNub.PutBlock32[nub, block32]; [rc, result] _ CirioNub.Call[nub]; IF rc # ok THEN ERROR Error[LIST[$something], Rope.Cat["Error calling PutWords32 in the remote target. ReturnCode is ", GetReturnCodeRope[rc], "."]]; }; RemoteWrite4Bytes: PROC[nub: CirioNub.Handle, address: CirioNubAccess.RemoteAddress, bytes: PACKED ARRAY [0..3] OF BYTE] = { CirioNubPutBytes: CirioNub.ProcID = CirioNubBase + 4; rc: CirioNub.ReturnCode; result: CirioNub.CallResult; remoteByteAddress: CARD _ address.byteAddress+address.bitOffset/8; IF address.nil THEN RemoteNilFault[address]; IF NOT address.valid THEN RemoteAddrFault[address]; IF RemoteAddressRangeCheck[remoteByteAddress] THEN RemoteAddrFault[address]; CirioNub.StartCall[nub, CirioNubPutBytes]; CirioNub.PutCard32[nub, remoteByteAddress]; CirioNub.PutBlock8Cnt[nub, 4]; FOR I: CARDINAL IN [0..4) DO CirioNub.PutBlock8Next[nub, bytes[I]]; ENDLOOP; [rc, result] _ CirioNub.Call[nub]; IF rc # ok THEN ERROR Error[LIST[$something], Rope.Cat["Error calling PutBytes in the remote target. ReturnCode is ", GetReturnCodeRope[rc], "."]]; }; RemoteGetThreads: PROC[nub: CirioNub.Handle, lowIndex, highIndex: CARD] RETURNS[LIST OF REF CirioNubAccess.ThreadInfo] = BEGIN CirioNubGetThreads: CirioNub.ProcID = CirioNubBase + 9; rc: CirioNub.ReturnCode; result: CirioNub.CallResult; nBlocks: INTEGER; cardsPerBlock: CARD = 9; block32: CirioNub.Block32; list: LIST OF REF CirioNubAccess.ThreadInfo _ NIL; CirioNub.StartCall[nub, CirioNubGetThreads]; CirioNub.PutCard32[nub, lowIndex]; CirioNub.PutCard32[nub, highIndex]; [rc, result] _ CirioNub.Call[nub]; IF rc # ok THEN ERROR Error[LIST[$something], "something in CirioNubAccessImpl"]; IF result.count # 1 THEN ERROR Error[LIST[$something], Rope.Cat["Error calling GetThreads in the remote target. ReturnCode is ", GetReturnCodeRope[rc], "."]]; block32 _ NARROW[result.val[0]]; IF block32.count MOD cardsPerBlock # 0 THEN ERROR Error[LIST[$something], "something in CirioNubAccessImpl"]; nBlocks _ block32.count/cardsPerBlock; FOR I: INTEGER DECREASING IN [0..nBlocks) DO blockX: CARD _ I*cardsPerBlock; oneThread: REF CirioNubAccess.ThreadInfo _ NEW[CirioNubAccess.ThreadInfo _[ index: block32.val[blockX], gen: block32.val[blockX+1], schedState: block32.val[blockX+2], priority: block32.val[blockX+3], dbgMsg: LOOPHOLE[block32.val[blockX+4], INT32], frozen: block32.val[blockX+5] # 0, pc: block32.val[blockX+6], stackPointer: block32.val[blockX+7], framePointer: block32.val[blockX+8]]]; list _ CONS[oneThread, list] ENDLOOP; RETURN[list] END; RemotePCtoInfo: PROC[nub: CirioNub.Handle, pc: CARD] RETURNS[CirioNubAccess.PCInfo] = BEGIN CirioNubPCToInfo: CirioNub.ProcID = CirioNubBase + 10; rc: CirioNub.ReturnCode; result: CirioNub.CallResult; info: CirioNubAccess.PCInfo _ NEW[CirioNubAccess.PCInfoBody]; CirioNub.StartCall[nub, CirioNubPCToInfo]; CirioNub.PutCard32[nub, pc]; [rc, result] _ CirioNub.Call[nub]; IF rc # ok THEN ERROR Error[LIST[$something], Rope.Cat["Error calling PCToInfo in the remote target. ReturnCode is ", GetReturnCodeRope[rc], "."]]; IF result.count # 6 THEN ERROR Error[LIST[$something], "Error calling PCToInfo in the remote target. Wrong number of arguments returned."]; info.procName _ Rope.FromRefText[NARROW[result.val[0]]]; info.procSymID _ NARROW[result.val[1], REF CARD]^; info.fileName _ PFS.PathFromRope[ Rope.FromRefText[NARROW[result.val[2]]]]; info.fileSeqNum _ NARROW[result.val[3], REF CARD]^; info.guessedEmbeddedFileName _ PFS.PathFromRope [Rope.FromRefText[NARROW[result.val[4]]]]; info.guessedEmbeddedFileSymID _ NARROW[result.val[5], REF CARD]^; RETURN[info]; END; RemoteKillWorld: PROC[nub: CirioNub.Handle] = BEGIN CirioNubKillWorld: CirioNub.ProcID = CirioNubBase + 11; rc: CirioNub.ReturnCode; result: CirioNub.CallResult; CirioNub.StartCall[nub, CirioNubKillWorld]; [rc, result] _ CirioNub.Call[nub]; IF rc # ok THEN ERROR Error[LIST[$something], Rope.Cat["Error calling KillWorld in the remote target. ReturnCode is ", GetReturnCodeRope[rc], "."]]; IF result.count # 0 THEN ERROR Error[LIST[$something], "Error calling KillWorld in the remote target. Wrong number of arguments returned."]; END; RemoteIssueThreadCommand: PROC[nub: CirioNub.Handle, threadIndex: CARD, setFreeze: BOOL, freeze: BOOL, setMsg: BOOL, msg: INT] RETURNS[success: BOOLEAN] = BEGIN CirioIssueThreadCommand: CirioNub.ProcID = CirioNubBase + 18; rc: CirioNub.ReturnCode; result: CirioNub.CallResult; CirioNub.StartCall[nub, CirioIssueThreadCommand]; CirioNub.PutCard32[nub, threadIndex]; CirioNub.PutCard32[nub, IF setFreeze THEN 1 ELSE 0]; CirioNub.PutCard32[nub, IF freeze THEN 1 ELSE 0]; CirioNub.PutCard32[nub, IF setMsg THEN 1 ELSE 0]; CirioNub.PutCard32[nub, LOOPHOLE[msg, CARD]]; [rc, result] _ CirioNub.Call[nub]; IF rc # ok THEN ERROR Error[LIST[$something], Rope.Cat["Error calling IssueThreadCommand in the remote target. ReturnCode is ", GetReturnCodeRope[rc], "."]]; IF result.count # 1 THEN ERROR Error[LIST[$something], "Error calling IssueThreadCommand in the remote target. Wrong number of arguments returned."]; RETURN[NARROW[result.val[0], REF INT]^ = 0] END; RemoteGetDBStat: PROC[nub: CirioNub.Handle, oldStat: INT32, oldExamineeIndex: INT, timeoutMsec: CARD] RETURNS[dbStab: INT32, examineeIndex: INT32] = BEGIN CirioGetDBStat: CirioNub.ProcID = CirioNubBase + 19; rc: CirioNub.ReturnCode; result: CirioNub.CallResult; CirioNub.StartCall[nub, CirioGetDBStat]; CirioNub.PutInt32[nub, oldStat]; CirioNub.PutInt32[nub, oldExamineeIndex]; CirioNub.PutCard32[nub, timeoutMsec]; [rc, result] _ CirioNub.Call[nub]; IF rc # ok THEN ERROR Error[LIST[$something], Rope.Cat["Error calling GetDBStat in the remote target. ReturnCode is ", GetReturnCodeRope[rc], "."]]; IF result.count # 2 THEN ERROR Error[LIST[$something], "Error calling GetDBStat in the remote target. Wrong number of arguments returned."]; RETURN[NARROW[result.val[0], REF INT]^, NARROW[result.val[1], REF INT]^] END; RemoteGetFileEntry4: PROC[nub: CirioNub.Handle, seqNum: CARD] RETURNS[CirioNubAccess.FileEntry] = BEGIN CirioNubGetFileEntry: CirioNub.ProcID = CirioNubBase + 20; rc: CirioNub.ReturnCode; result: CirioNub.CallResult; entry: CirioNubAccess.FileEntry _ NEW[CirioNubAccess.FileEntryBody]; CirioNub.StartCall[nub, CirioNubGetFileEntry]; CirioNub.PutCard32[nub, seqNum]; [rc, result] _ CirioNub.Call[nub]; IF rc # ok THEN ERROR Error[LIST[$something], Rope.Cat["Error calling GetFileEntry in the remote target. ReturnCode is ", GetReturnCodeRope[rc], "."]]; IF result.count # 21 THEN ERROR Error[LIST[$something], "Error calling GetFileEntry in the remote target. Wrong number of arguments returned."]; entry.seqNum _ NARROW[result.val[0], REF CARD]^; entry.commitPoint _ NARROW[result.val[1], REF CARD]^ # 0; entry.fileName _ PFS.PathFromRope[ Rope.FromRefText[NARROW[result.val[2]]]]; entry.fOffset _ NARROW[result.val[3], REF CARD]^; entry.fmagic _ NARROW[result.val[4], REF CARD]^; entry.size _ NARROW[result.val[5], REF CARD]^; entry.mtime _ NARROW[result.val[6], REF CARD]^; entry.smagic _ NARROW[result.val[7], REF CARD]^; entry.stamp _ Rope.FromRefText[NARROW[result.val[8]]]; entry.readerData _ NARROW[result.val[9], REF CARD]^; entry.readerDataSize _ NARROW[result.val[10], REF CARD]^; entry.patchReloc _ NARROW[result.val[11], REF CARD]^; entry.patchSize _ NARROW[result.val[12], REF CARD]^; entry.textReloc _ NARROW[result.val[13], REF CARD]^; entry.textSize _ NARROW[result.val[14], REF CARD]^; entry.dataReloc _ NARROW[result.val[15], REF CARD]^; entry.dataSize _ NARROW[result.val[16], REF CARD]^; entry.bssReloc _ NARROW[result.val[17], REF CARD]^; entry.bssSize _ NARROW[result.val[18], REF CARD]^; entry.commonReloc _ NARROW[result.val[19], REF CARD]^; entry.commonSize _ NARROW[result.val[20], REF CARD]^; RETURN[entry]; END; RemoteGetFileEntry5: PROC[nub: CirioNub.Handle, seqNum: CARD] RETURNS[CirioNubAccess.FileEntry] = BEGIN CirioNubGetFileEntry: CirioNub.ProcID = CirioNubBase + 20; rc: CirioNub.ReturnCode; result: CirioNub.CallResult; entry: CirioNubAccess.FileEntry _ NEW[CirioNubAccess.FileEntryBody]; stampAddr: CARD32; stampSize: CARD32; CirioNub.StartCall[nub, CirioNubGetFileEntry]; CirioNub.PutCard32[nub, seqNum]; [rc, result] _ CirioNub.Call[nub]; IF rc # ok THEN ERROR Error[LIST[$something], Rope.Cat["Error calling GetFileEntry in the remote target. ReturnCode is ", GetReturnCodeRope[rc], "."]]; IF result.count # 22 THEN ERROR Error[LIST[$something], "Error calling GetFileEntry in the remote target. Wrong number of arguments returned."]; entry.seqNum _ NARROW[result.val[0], REF CARD]^; entry.commitPoint _ NARROW[result.val[1], REF CARD]^ # 0; entry.fileName _ PFS.PathFromRope[ Rope.FromRefText[NARROW[result.val[2]]]]; entry.fOffset _ NARROW[result.val[3], REF CARD]^; entry.fmagic _ NARROW[result.val[4], REF CARD]^; entry.size _ NARROW[result.val[5], REF CARD]^; entry.mtime _ NARROW[result.val[6], REF CARD]^; entry.smagic _ NARROW[result.val[7], REF CARD]^; stampAddr _ NARROW[result.val[8], REF CARD]^; stampSize _ NARROW[result.val[9], REF CARD]^; entry.stamp _ NIL; entry.readerData _ NARROW[result.val[10], REF CARD]^; entry.readerDataSize _ NARROW[result.val[11], REF CARD]^; entry.patchReloc _ NARROW[result.val[12], REF CARD]^; entry.patchSize _ NARROW[result.val[13], REF CARD]^; entry.textReloc _ NARROW[result.val[14], REF CARD]^; entry.textSize _ NARROW[result.val[15], REF CARD]^; entry.dataReloc _ NARROW[result.val[16], REF CARD]^; entry.dataSize _ NARROW[result.val[17], REF CARD]^; entry.bssReloc _ NARROW[result.val[18], REF CARD]^; entry.bssSize _ NARROW[result.val[19], REF CARD]^; entry.commonReloc _ NARROW[result.val[20], REF CARD]^; entry.commonSize _ NARROW[result.val[21], REF CARD]^; RETURN[entry]; END; RemoteLookupSymEntryByName: PROC[nub: CirioNub.Handle, sym: Rope.ROPE, caseSensitive: BOOLEAN, externOnly: BOOLEAN, numToSkip: INT] RETURNS[CirioNubAccess.SymEntry] = BEGIN CirioNubLookupSymEntryByName: CirioNub.ProcID = CirioNubBase + 21; rc: CirioNub.ReturnCode; result: CirioNub.CallResult; CirioNub.StartCall[nub, CirioNubLookupSymEntryByName]; CirioNub.PutRope[nub, sym]; CirioNub.PutCard32[nub, IF caseSensitive THEN 1 ELSE 0]; CirioNub.PutCard32[nub, IF externOnly THEN 1 ELSE 0]; CirioNub.PutInt32[nub, numToSkip]; [rc, result] _ CirioNub.Call[nub]; IF rc # ok THEN ERROR Error[LIST[$something], Rope.Cat["Error calling LookupSymEntryByName in the remote target. ReturnCode is ", GetReturnCodeRope[rc], "."]]; RETURN[RemoteComputeSymEntry[result]]; END; RemoteLookupSymEntryByValue: PROC[nub: CirioNub.Handle, val: CARD, numToSkip: INT] RETURNS[CirioNubAccess.SymEntry] = BEGIN CirioNubLookupSymEntryByValue: CirioNub.ProcID = CirioNubBase + 22; rc: CirioNub.ReturnCode; result: CirioNub.CallResult; CirioNub.StartCall[nub, CirioNubLookupSymEntryByValue]; CirioNub.PutCard32[nub, val]; CirioNub.PutInt32[nub, numToSkip]; [rc, result] _ CirioNub.Call[nub]; IF rc # ok THEN ERROR Error[LIST[$something], Rope.Cat["Error calling LookupSymEntryByValue in the remote target. ReturnCode is ", GetReturnCodeRope[rc], "."]]; RETURN[RemoteComputeSymEntry[result]]; END; RemoteLookupSymEntryByID: PROC[nub: CirioNub.Handle, symID: CARD] RETURNS[CirioNubAccess.SymEntry] = BEGIN CirioNubLookupSymEntryByID: CirioNub.ProcID = CirioNubBase + 23; rc: CirioNub.ReturnCode; result: CirioNub.CallResult; CirioNub.StartCall[nub, CirioNubLookupSymEntryByID]; CirioNub.PutCard32[nub, symID]; [rc, result] _ CirioNub.Call[nub]; IF rc # ok THEN ERROR Error[LIST[$something], Rope.Cat["Error calling LookupSymEntryByID in the remote target. ReturnCode is ", GetReturnCodeRope[rc], "."]]; RETURN[RemoteComputeSymEntry[result]]; END; RemoteLookupMatchingSymEntryByName: PROC[nub: CirioNub.Handle, symID: CARD, sym: Rope.ROPE, caseSensitive: BOOLEAN, wantedTypes: CARD, ignoredClasses: CARD, numToSkip: INT] RETURNS[CirioNubAccess.SymEntry] = BEGIN CirioNubLookupMatchingSymEntryByName: CirioNub.ProcID = CirioNubBase + 26; rc: CirioNub.ReturnCode; result: CirioNub.CallResult; CirioNub.StartCall[nub, CirioNubLookupMatchingSymEntryByName]; CirioNub.PutCard32[nub, symID]; CirioNub.PutRope[nub, sym]; CirioNub.PutCard32[nub, IF caseSensitive THEN 1 ELSE 0]; CirioNub.PutCard32[nub, wantedTypes]; CirioNub.PutCard32[nub, ignoredClasses]; CirioNub.PutInt32[nub, numToSkip]; [rc, result] _ CirioNub.Call[nub]; IF rc # ok THEN ERROR Error[LIST[$something], Rope.Cat["Error calling LookupMatchingSymEntryByName in the remote target. ReturnCode is ", GetReturnCodeRope[rc], "."]]; RETURN[RemoteComputeSymEntry[result]]; END; RemoteLookupMatchingSymEntryByValue: PROC[nub: CirioNub.Handle, symID: CARD, val: CARD, wantedTypes: CARD, ignoredClasses: CARD, numToSkip: INT] RETURNS[CirioNubAccess.SymEntry] = BEGIN CirioNubLookupMatchingSymEntryByValue: CirioNub.ProcID = CirioNubBase + 27; rc: CirioNub.ReturnCode; result: CirioNub.CallResult; CirioNub.StartCall[nub, CirioNubLookupMatchingSymEntryByValue]; CirioNub.PutCard32[nub, symID]; CirioNub.PutCard32[nub, val]; CirioNub.PutCard32[nub, wantedTypes]; CirioNub.PutCard32[nub, ignoredClasses]; CirioNub.PutInt32[nub, numToSkip]; [rc, result] _ CirioNub.Call[nub]; IF rc # ok THEN ERROR Error[LIST[$something], Rope.Cat["Error calling LookupMatchingSymEntryByValue in the remote target. ReturnCode is ", GetReturnCodeRope[rc], "."]]; RETURN[RemoteComputeSymEntry[result]]; END; RemoteComputeSymEntry: PROC[result: CirioNub.CallResult] RETURNS[CirioNubAccess.SymEntry] = BEGIN IF result.count < 1 THEN ERROR Error[LIST[$something], "something in CirioNubAccessImpl"]; BEGIN errCode: INT32 _ NARROW[result.val[0], REF INT32]^; SELECT errCode FROM 0 => BEGIN entry: CirioNubAccess.SymEntry _ NEW[CirioNubAccess.SymEntryBody]; IF result.count # 7 THEN ERROR Error[LIST[$something], "something in CirioNubAccessImpl"]; entry.symID _ NARROW[result.val[1], REF CARD]^; entry.name _ Rope.FromRefText[NARROW[result.val[2]]]; entry.type _ NARROW[result.val[3], REF CARD]^; entry.value _ NARROW[result.val[4], REF CARD]^; entry.size _ NARROW[result.val[5], REF CARD]^; entry.fileSeqNum _ NARROW[result.val[6], REF CARD]^; RETURN[entry]; END; ENDCASE => RETURN[NIL]; END; END; RemoteMonitoredCall: PROC[ address: CirioNubAccess.RemoteAddress, proc: PROC[] RETURNS[]] RETURNS [] = BEGIN HolderOffset: PROCEDURE[] RETURNS [INT] ~ TRUSTED { sampleMonitorLock: PCRMonitorDefs.MonitorLock; sampleAddress: LONG POINTER TO PCRMonitorDefs.MonitorLock ~ @sampleMonitorLock; sampleAddressCard: CARD32 ~ LOOPHOLE[sampleAddress]; holderAddress: LONG POINTER TO PCRMonitorDefs.Thread ~ @sampleMonitorLock.holder; holderAddressCard: CARD32 ~ LOOPHOLE[holderAddress]; offset: INT ~ (holderAddressCard - sampleAddressCard) * BYTES[UNIT]; RETURN [offset]; }; holderAddress: CirioNubAccess.RemoteAddress ~ [ h: address.h, byteAddress: address.byteAddress + HolderOffset[], bitOffset: address.bitOffset, nil: address.nil, valid: address.valid]; holder: PCRMonitorDefs.Thread ~ LOOPHOLE[Read32BitsAsCard[address: holderAddress]]; IF holder = PCRMonitorDefs.nullHolder THEN { proc[]; } ELSE { ERROR RemoteMonitorWouldBlock[addr: address]; }; END; RemoteGetConcreteTypecode: PROC[h: Handle, opaque: CirioNubAccess.Typecode] RETURNS[concrete: CirioNubAccess.Typecode] ~ { nub: CirioNub.Handle ~ NARROW[h.contents, REF RemoteBody].nub; rc: CirioNub.ReturnCode; result: CirioNub.CallResult; CedarCirioNubGetConcreteTypecode: CirioNub.ProcID = CedarCirioNubBase+3; CirioNub.StartCall[nub, CedarCirioNubGetConcreteTypecode]; CirioNub.PutCard32[nub, opaque]; [rc, result] _ CirioNub.Call[nub]; IF rc # ok THEN ERROR Error[LIST[$something], Rope.Cat["Error calling GetConcreteTypecode in the remote target. ReturnCode is ", GetReturnCodeRope[rc], "."]]; IF result.count # 1 THEN ERROR Error[LIST[$something], "Error calling GetConcreteTypecode in the remote target. Wrong number of arguments returned."]; concrete _ [NARROW[result.val[0], REF CARD32]^]; RETURN; }; RemoteGetTypestring: PUBLIC PROC[h: Handle, code: CirioNubAccess.Typecode] RETURNS[string: CirioNubAccess.Typestring] ~ { nub: CirioNub.Handle ~ NARROW[h.contents, REF RemoteBody].nub; rc: CirioNub.ReturnCode; result: CirioNub.CallResult; CedarCirioNubGetTypestring: CirioNub.ProcID = CedarCirioNubBase+1; CirioNub.StartCall[nub, CedarCirioNubGetTypestring]; CirioNub.PutCard32[nub, code]; [rc, result] _ CirioNub.Call[nub]; IF rc # ok THEN ERROR Error[LIST[$something], Rope.Cat["Error calling GetTypestring in the remote target. ReturnCode is ", GetReturnCodeRope[rc], "."]]; IF result.count # 1 THEN ERROR Error[LIST[$something], "Error calling GetTypestring in the remote target. Wrong number of arguments returned."]; string _ Rope.FromRefText[NARROW[result.val[0]]]; RETURN; }; RemoteGetTypecode: PROC[h: Handle, string: CirioNubAccess.Typestring] RETURNS[code: CirioNubAccess.Typecode] ~ { nub: CirioNub.Handle ~ NARROW[h.contents, REF RemoteBody].nub; rc: CirioNub.ReturnCode; result: CirioNub.CallResult; found: BOOL; CedarCirioNubGetTypecode: CirioNub.ProcID = CedarCirioNubBase+2; CirioNub.StartCall[nub, CedarCirioNubGetTypecode]; CirioNub.PutCard32[nub, Rope.Length[string]]; CirioNub.PutRope[nub, string]; [rc, result] _ CirioNub.Call[nub]; IF rc # ok THEN ERROR Error[LIST[$something], Rope.Cat["Error calling GetTypecode in the remote target. ReturnCode is ", GetReturnCodeRope[rc], "."]]; IF result.count # 2 THEN ERROR Error[LIST[$something], "Error calling GetTypecode in the remote target. Wrong number of arguments returned."]; found _ NARROW[result.val[0], REF CARD32]^ # 0; code _ IF found THEN [NARROW[result.val[1], REF CARD32]^] ELSE [0]; RETURN; }; CHARPtr: TYPE ~ RECORD [ptr: LONG POINTER TO PBasics.RawChars _ NIL]; SameWorldReadBytes: PROC[address: CirioNubAccess.RemoteAddress, count: INT] RETURNS[REF TEXT] = TRUSTED { bitsPerByte: CARD = BITS[BYTE]; text: REF TEXT _ RefText.New[count]; byteAddress: CHARPtr; IF address.nil THEN RemoteNilFault[address]; IF NOT address.valid THEN RemoteAddrFault[address]; IF address.valid THEN BEGIN byteAddress _ LOOPHOLE[address.byteAddress + address.bitOffset/bitsPerByte]; FOR i: CARD IN [0..CARD[count]) DO text _ RefText.InlineAppendChar[text, byteAddress[i]]; ENDLOOP; RETURN[text]; END ELSE RETURN[NIL]; }; CARD16Ptr: TYPE ~ LONG POINTER TO CARD16; SameWorldRead16BitsAsCardinal: PROC[address: CirioNubAccess.RemoteAddress] RETURNS[CARDINAL] = TRUSTED { bitsPerByte: CARD = BITS[BYTE]; card16: CARD16; byteAddress: CARD16Ptr _ LOOPHOLE[address.byteAddress + (address.bitOffset/bitsPerByte), CARD16Ptr] ; IF address.nil THEN RemoteNilFault[address]; IF NOT address.valid THEN RemoteAddrFault[address]; card16 _ byteAddress^; RETURN[LOOPHOLE[card16]]; }; CARD32Ptr: TYPE ~ LONG POINTER TO CARD32; LocalAddressRangeCheck: PROC[byteAddress: CARD] RETURNS[BOOL] = { RETURN[byteAddress> 0 AND byteAddress < 1000]}; SameWorldRead32BitsAsCard: PROC[address: CirioNubAccess.RemoteAddress] RETURNS[CARD] = TRUSTED { bitsPerByte: CARD = BITS[BYTE]; byteAddress: CARD32Ptr _ LOOPHOLE[address.byteAddress + (address.bitOffset/bitsPerByte), CARD32Ptr]; IF address.nil THEN RemoteNilFault[address]; IF NOT address.valid THEN RemoteAddrFault[address]; IF LocalAddressRangeCheck[LOOPHOLE[byteAddress, CARD]] THEN RemoteAddrFault[address]; RETURN[LOOPHOLE[byteAddress^]]; }; SameWorldWriteCardAs32Bits: PROC[address: CirioNubAccess.RemoteAddress, card: CARD32] = TRUSTED { bitsPerByte: CARD = BITS[BYTE]; byteAddress: CARD32Ptr _ LOOPHOLE[address.byteAddress + (address.bitOffset/bitsPerByte), CARD32Ptr]; IF address.nil THEN RemoteNilFault[address]; IF NOT address.valid THEN RemoteAddrFault[address]; IF LocalAddressRangeCheck[LOOPHOLE[byteAddress, CARD]] THEN RemoteAddrFault[address]; byteAddress^ _ card; }; BYTEPtr: TYPE ~ RECORD [ptr: LONG POINTER TO PBasics.RawBytes _ NIL]; SameWorldWrite4Bytes: PROC[address: CirioNubAccess.RemoteAddress, bytes: PACKED ARRAY [0..3] OF BYTE] = TRUSTED { bitsPerByte: CARD = BITS[BYTE]; byteAddress: BYTEPtr; IF address.nil THEN RemoteNilFault[address]; IF NOT address.valid THEN RemoteAddrFault[address]; byteAddress _ LOOPHOLE[address.byteAddress + address.bitOffset/bitsPerByte]; IF LocalAddressRangeCheck[LOOPHOLE[byteAddress, CARD]] THEN RemoteAddrFault[address]; FOR i: CARDINAL IN [0..4) DO byteAddress[i] _ bytes[i]; ENDLOOP; }; UntypedDataHolder: TYPE = RECORD[SEQUENCE nCard32: CARDINAL OF CARD32]; SameWorldAllocateBytes: PROC[nBytes: CARD] RETURNS[data: REF ANY, byteAddr: CARD] = BEGIN stuff: REF UntypedDataHolder _ NEW[UntypedDataHolder[((nBytes+3)/4)+1]]; GetByteAddress: PROC RETURNS[CARD] = TRUSTED {RETURN[LOOPHOLE[@stuff[0]]]}; RETURN[stuff, GetByteAddress[]]; END; SameWorldReleaseAllocatedBytes: PROC[data: REF ANY] = BEGIN NULL END; SameWorldMonitoredCall: PROC[ address: CirioNubAccess.RemoteAddress, proc: PROC[] RETURNS []] RETURNS [] = SameWorldMonitoredCallOps.MonitoredCall; NameToAddress: PUBLIC PROC [name: Rope.ROPE] RETURNS [addr: Rope.ROPE] = { addr _ NetworkName.AddressFromName[$ARPA, name, NIL, host ! NetworkName.Error => Error[CONS[$debuggeeNameLookupError, codes], IO.PutFR["%g looking up target %g", [rope[msg]], [rope[name]] ]] ].addr; << { ENABLE Convert.Error => CONTINUE; a: Arpa.Address _ ConvertExtras.ArpaAddressFromRope[name]; IF a # Arpa.nullAddress THEN RETURN[ ConvertExtras.RopeFromArpaAddress[a] ] }; { h: SunYPAgent.Handle ~ SunYPAgent.ObtainHandle[]; val: REF TEXT ~ SunYPAgent.Match[h: h, map: "hosts.byname", key: name]; textseq: SunYPAgent.TextSeq ~ SunYPAgent.Tokenize[in: val]; RETURN[Rope.FromRefText[textseq[0]]]; }>> RETURN}; GetReturnCodeRope: PROC [rc: CirioNub.ReturnCode] RETURNS [rcRope: Rope.ROPE] = { SELECT rc FROM ok => rcRope _ "ok"; noProc => rcRope _ "noProc"; badArgs => rcRope _ "badArgs"; failure => rcRope _ "failure"; commError => rcRope _ "commError"; protocolError => rcRope _ "protocolError"; spaceError => rcRope _ "spaceError"; last => rcRope _ "last"; ENDCASE => rcRope _ "unParsed ReturnCode"; RETURN}; END.. March 10, 1992 3:06:44 pm PSTMarch 10, 1992 3:06:46 pm PST B CirioNubAccessImpl.mesa Copyright ำ 1990, 1991, 1992 by Xerox Corporation. All rights reserved. Sturgis, March 23, 1990 12:20 pm PST Last changed by Theimer on October 9, 1989 3:57:10 pm PDT Linda Howe January 19, 1990 10:51:15 am PST Last tweaked by Mike Spreitzer on January 9, 1992 4:36 pm PST Peter B. Kessler, July 12, 1990 11:03 am PDT Coolidge, July 18, 1990 9:52 am PDT Laurie Horton, March 10, 1992 3:08 pm PST Philip James, February 25, 1992 10:13 am PST Jas, January 6, 1993 1:04 pm PST remarks info used in developing this file are in CirioNubProcs.h which one can see by /palain-ux/jaune/xrhome/DEVELOPMENT/debugnub/INCLUDE/xr/CirioNubProcs.h The "sameworld" version of this interface is /palain-ux/jaune/xrhome/DEVELOPMENT/debugnub/INCLUDE/xr/CirioNubLocalProcs.h and the "inner" interface is /palain-ux/jaune/xrhome/DEVELOPMENT/debugnub/INCLUDE/xr/CirioNubInnerProcs.h additional info in [palain-uX]<>jaune>xrhome>DEVELOPMENT>INCLUDE>xr>Threads.h [palain-uX]<>jaune>xrhome>DEVELOPMENT>INCLUDE>xr>ThreadsBackdoor.h This version (1) differs from the previous version (un-numbered) as follows: Null accepts a proposed protocol version number and returns an actual protocol number PCToFN is renamed PCtoInfo and returns more info (I called it ResolveAbsPC before) IssueThreadCommand is added GetDBStat is added NOTE: Several outstanding issues how do I deliver a Bool (See IssueThreadCommand) what are the args and results for GetDBStat (I believe Alan is changing them) I need to fix the interface file and add appropriate comments. procedure number blocks creation Handle: TYPE = REF HandleBody; HandleBody: PUBLIC TYPE = CirioNubAccessPrivate.HandleBody; The contents will either point to a RemoteBody or will be NIL. remote/sameWorld case selection assumes that creation of h set the version number waits for change from old values or timeout This is here to provide compatibility with remote nubs that are versions 4 and 5. eventually we will re-write to explicitly use the new version 6 operations These two constants come from /jaune/xrhome/DEVELOPMENT/INCLUDE/xr/IncrementalLoad.h don't forget that the bottom bit should be ignored, as it is the "external" bit. symId = 0, is ignored # 0, search starts with given symId pattern either a rope with no asterisk exact match required or a rope with at least one period and exactly one asterisk as the last character asterisk is a wild card caseSensitive if true, capitalization must match wantedTypes -1 for all types are acceptable t for a specific type (external bit is ignored) ignoreClasses 0 accept all types 1 ignore internals 2 ignore externals 3 ignore all types (very fast!) numToSkip presumed non negative search starts with most recent matching entry if 0, accept first matching entry if 1, skip first matching entry, look for next older matching entry etc. symId = 0, search starts with the entry with greatest value less or equal to given val. # 0, search starts with given symId val ignored if symId # 0 wantedTypes (see LookupMatchingSymEntryByName) ignoreClasses 0(see LookupMatchingSymEntryByName) numToSkip if zero, finds entry with greatest value less or equal to given val if greater than zero, searches by increasing value if negative, searches by decreasing value if several entries have same value, then think of the key as the pair . allocate the firstLateFreeSlot here is where we do the construction making this an entry proc deadlocks Cirio when the callback proc tries to use CirioNubAccess ENTRY procedures. Sigh. Nothing here modifies h, so why should it be an ENTRY proc? ... peter IF h.contents#NIL THEN RETURN[[0], "can't get concrete typecodes remotely yet"] IF h.contents#NIL THEN RETURN[NIL, "can't get typestrings remotely yet"] IF h.contents#NIL THEN RETURN[[0], "can't get typecodes remotely yet"] Just return "SPARC", "SunOS4" target for older debugnubs (i.e.versions < 7). This information is checked in CirioTargets. remote procedures We use this to wait for a call from some thread This is probably not what we shall use in the future WaitSig actually returns a second param, DBStat, but this param is not interesting for the present application. Really, shouldn't this show up as rc # ok?? a mild sanity check due to funny things happening with gnu. IF remoteByteAddress < 1000 THEN RemoteAddrFault[address]; a mild sanity check due to funny things happening with gnu. Really, shouldn't this show up as rc # ok?? IF remoteByteAddress < 1000 THEN RemoteAddrFault[address]; a mild sanity check due to funny things happening with gnu. IF remoteByteAddress < 1000 THEN RemoteAddrFault[address]; a mild sanity check due to funny things happening with gnu. Is this how I deliver a Bool? Barry says 1 is true, 0 is false. Alan agrees. (the comments in his dot h files of the form Return ( (success) ? 0 : -1 ) are a standard convention for system calls, they are NOT returning a Boolean.) waits for change from old values or timeout (we should read in the stamp at this point) Watch this! We compute target field offsets using structures we've defined over here! I think this is about the grottiest code I've written, but Russ says it's the most straightforward way of doing it. ... peter We don't have to acquire the monitor lock, since the remote debuggee is frozen. We can't acquire the monitor lock, and the remote world is frozen. same world procedures CHARPtr is copied from UnixTypes.CHARPtr. byteAddress _ LOOPHOLE[address.byteAddress]; byteAddress _ LOOPHOLE[byteAddress + address.bitOffset/bitsPerByte]; a mild sanity check due to funny things happening with gnu. IF LOOPHOLE[byteAddress, INT] < 1000 THEN RemoteAddrFault[address]; a mild sanity check due to funny things happening with gnu. IF LOOPHOLE[byteAddress, INT] < 1000 THEN RemoteAddrFault[address]; a mild sanity check due to funny things happening with gnu. byteAddress _ LOOPHOLE[address.byteAddress]; byteAddress _ LOOPHOLE[byteAddress + address.bitOffset/bitsPerByte]; IF LOOPHOLE[byteAddress, INT] < 1000 THEN RemoteAddrFault[address]; a mild sanity check due to funny things happening with gnu. the plus 1 is so that the subsequent @stuff[0] will not get a bounds fault due to zero length array (i.e., stuff[0] wouldn't exist.) no need to do anything, it will go away when all refs to data^ go away support from Linda Howe note: cirioremote 13.1.101.27 4816 works to debug menhir The following code enables us to connect to a debuggee even if the YP service is unavailable - ajd try without yellow pages so try with the yellow pages Convert the ReturnCode into a Rope. ส=m•NewlineDelimiter – "cedar" style™codešœ™K™HKšœ$™$K™9K™+K™=K™,K™#K™)K™,K™ —K˜šฯk ˜ Kšœœึ˜๊Kšœ œบ˜ศKšœœพ˜าKšœœ!ฯcœ˜NKšœ ˜ Kšœœ˜'K˜K˜ Kšœ˜Kšœ˜Kšœ œ˜+Kšœœ˜#Kšœœ#˜7Kšœœ˜Kšœ œœ˜Kšœœ˜%Kšœ˜K˜ Kšœœ˜1Kšœœ˜"Kšœœ*˜?Kšœ œ0˜BKšœ˜K˜—šฯnœœ˜!Kšœœ ˜KšœNœœI˜มKšœ˜Kšœ˜K˜K™™™MK™G—™,K™M—™K™L——™™Kšœ œœ ™:Kšœ œœ™BK™—™LK™UK™SK™K™K™šœ™ Kšœ1™1KšœM™MK™K™>——K™—K™™K™KšŸ œ˜"KšŸœ˜(K˜K™—K™™KšŸœœœ œœœ œœ˜AKšŸœœœ'œ˜HKšŸœœœ'œ˜IKšŸœœœ'œ˜QK˜Kšœœœ ™Kšœ œœ$™;K™Kšœœ˜%Kšœ œ˜-˜K™Kšœ>™>K™—Kšœ œœ˜0K˜K™šŸœœœœœœœœœœ ˜{Kš˜Kšœœ˜ Kšœœ˜.Kšœœ7˜JKšœ'œ˜CKš œ œœœ œœ˜|šœœ œœ˜MK˜Kšœœ˜Kšœ+˜0—Kšœ(˜(Kšœ˜ Kšœ˜—K˜šŸœœœœ ˜2Kš˜Kšœœ˜ Kš œ œœœ œ œ˜gKš œœ œœœœv˜ศKšœ(˜(Kšœ˜ Kšœ˜—K˜K˜K˜—™K˜šŸ œœœœ ˜*Kš˜Kšœœœ˜Kš œœœœœ0˜Sšœœ˜š œŸœœœ˜.Kšœœœ3˜TKšœ˜——Kšœ œ˜šœ˜Kšœœ œ˜=Kšœœ˜ —Kšœ˜—K˜š Ÿœœœœ œœ˜FKš˜Kšœœœ˜šœ ˜K™1—Kšœ˜—K˜šŸœœœœ#œœœ˜RKš˜Kšœœœ˜Kš œœœœœ0˜SKšœœœœœœœœt˜—K˜šœ˜š˜Kš˜Kšœœ œ)˜VKšœœœœœœœœg˜ฺKšœœ˜ Kš˜—š˜Kš˜Kšœ œ˜*Kšœœœœ˜IKšœ˜—K˜—Kšœ˜—K˜šŸœœœœœœœ˜\Kš˜Kšœœœ˜Kš œœœœœ0˜Sšœ˜Kšœœœ œ#˜SKšœœœe˜z—Kšœ˜K˜—šŸ œœœœœœœœ˜dKš˜Kšœœœ˜Kš œœœœœ0˜Sšœ˜Kšœœœ œ+˜]Kšœœœi˜~—Kšœ˜—K˜šŸ œœœ/œœœœ˜]Kš˜š Ÿœœœ œœœ˜0Kš˜Kšœœœ˜Kšœ œ˜,Kšœœœ˜3Kš œœœœœ0˜[šœ˜Kšœœœœ2˜qKšœœ5˜@—Kšœ˜—Kšœ˜Kšœ˜—K˜K˜š Ÿœœœ(œœ˜\Kš˜š Ÿœœœ œœ˜0Kš˜Kšœœœ˜Kšœ œ˜,Kšœœœ˜3Kš œœœœœ0˜[šœ˜Kšœœ!œœ$˜nKšœœ2˜=—Kšœ˜—Kšœ˜Kšœ˜—K˜K˜š Ÿœœœ(œœ˜TKš˜š Ÿœœœ œœ˜,Kš˜Kšœœœ˜Kšœ œ˜,Kšœœœ˜3Kš œœœœœ0˜[šœ˜Kšœœœœ$˜jKšœœ.˜9—Kšœ˜—Kšœ˜Kšœ˜K˜—K˜šŸœœœ.œ˜UKš˜šŸœœœ ˜Kš˜Kšœœœ˜Kšœ œ˜,Kšœœœ˜3Kš œœœœœ0˜[šœ˜Kšœœœ/˜oKšœ:˜>—Kšœ˜—Kšœ˜Kšœ˜—K˜K˜šŸ œœœ(œœœœœ˜eKš˜˜Kšœœœ˜'KšœœœœM˜uKš œœ œ œ œ ˜AK˜—Kšœ˜K˜—šŸ œœœ/œœœœ˜eKš˜šŸœœœ ˜Kš˜Kšœœœ˜Kšœ œ˜,Kšœœœ˜3Kš œœœœœ0˜[šœ˜Kšœœœ1˜kKšœ6˜:—Kšœ˜—Kšœ˜Kšœ˜—K˜K˜šŸ œœœœ!œœœœœ˜tKš˜Kšœœœ˜Kš œœœœœ0˜Sšœ˜Kšœœœ œ'˜ZKšœœœk˜€—Kšœ˜—K˜K˜š Ÿœœœœœœ˜QKš˜Kšœœœ˜Kš œœœœœ0˜Sšœ˜Kšœœœ œ˜GKšœœ'˜2—Kšœ˜K˜—šŸ œœœœ ˜)Kš˜Kšœœœ˜Kš œœœœœ0˜Sšœ˜Kšœœ œ˜œ˜nKšœœœœ•˜ว—Kšœ˜—K˜KšŸ œœ˜šŸœœ˜K™TK™P—˜™K™K™#—K™™™K™—™QK™——K™™ K™"—K™šœ ™ K™K™/—K™™ K™K™K™K™—K™™ K™K™-K™!K™CK™—K™—šŸœœœœœœœœœ œœ˜ฮKš˜Kšœœœ˜Kš œœœœœ0˜SKš œœœœœ„˜มšœ˜š˜Kšœ$œ œX˜˜—š˜Kšœ}˜ƒ——šœ˜K˜——˜™K™QK™#—K™™K™—K™K™šœ ™ Kšœ"™"—K™™ Kšœ#™#—K™™ K™CK™2K™)K™ฟ——šŸœœœœœœœœ œœ˜ฎKš˜Kšœœœ˜Kš œœœœœ0˜SKš œœœœœ…˜ยšœ˜š˜Kšœ%œ œE˜†—š˜Kšœk˜q——Kšœ˜—K˜K˜—K˜Kšœ œœ˜(Kšœœœ)˜EK˜š Ÿ œœœœœœ!˜bKš˜Kšœœœ˜Kš œœœœœ0˜SKš œœœœœu˜ฒšœ˜š˜Kšœœo˜—š˜Kš˜Kšœœ=˜DKšœ œ˜Kšœ8˜8Kšœœœ˜/Kšœ˜——Kšœ˜—K˜šŸœœ œœ)˜VKš˜Kšœœž˜!šœœ˜Kš˜Kšœœ˜Kšœœ(œ.˜aKšœœ˜Kšœ˜KšœŸœœœ œ œœ˜2Kšœ˜Kšœ˜—šœ#œ˜-Kš˜Kšœ.˜.KšœG˜GKš˜—š˜Kš˜šœ>˜DKš˜Kšœ œ˜+Kšœœ(œ1˜dKšœœ˜Kšœ0˜0Kš œŸœœœœœ˜TKšœŸœœœ%œ œœ˜KKšœ˜Kšœ˜—šœ™Kš˜Kšœ+˜+KšœJ˜JKšœ˜—Kšœ˜—K™šœ$™$Kš˜Kšœœœ2œ˜UKš œœœœœ]˜“Kšœ˜Kšœ˜ Kšœ˜—Kšœ˜—K˜šŸœœœ˜@šŸœœœ˜ Kšœœœ˜Kšœ+˜+Kšœ˜—K˜Kšœ˜—K˜šŸœœœ)˜RKš œœœœœ0˜SKš œœœœœ}˜บK˜%šœ˜š˜Kšœœ˜‰—š˜Kšœ1˜1——Kšœ˜—K˜šŸœœœ)˜VKš˜Kšœ œœ˜Kšœ!œœœ7˜oKšœ"œ,˜RKšœœ˜!Kšœ˜—K˜š Ÿ œœœ/ œœœ˜oKš˜šŸœž œœ ˜$Kšœ]œEœ™ผKš˜Kšœœœ˜Kšœ œ˜,Kšœœœ˜3Kšœœœ˜;Kš œœœœœ0˜[šœ˜Kšœ2˜6Kšœ6˜:—Kšœ˜—K˜Kšœ˜—K˜K˜š Ÿœœœ-œ1œ˜ŽKš œœœœœ0˜SKšœ œœœ2™Ošœ œœ˜Kšœœœœ˜คKšœ0˜0Kšœ œ˜K˜—šœ˜KšœCœ ˜PKšœœœ˜—K˜K˜—K˜š Ÿ œœœ+œ1œ˜†Kš œœœœœ0˜SKš œ œœœœ'™Hšœ œœ˜Kš œœœœœ{˜žKšœ&˜&Kšœ œ˜K˜—šœ˜Kšœœ$œ˜9Kšœ œœ˜Kšœ;˜BKšœœ˜—K˜—K˜K˜š Ÿ œœœ/œ.œœ˜‹Kš œœœœœ0˜SKšœ œœœ)™Fšœ œœ˜Kšœœœœy˜œKšœ$˜$Kšœœ˜K˜—šœ˜Kšœœœ˜*K˜K˜"Kšœ'œœ˜=Kšœœœ˜—K˜K˜—š Ÿ#œœ œ œœ˜jK™Kšœœœ˜K˜KšŸœ&˜9K˜Kšœ˜Kšœ˜K˜K™Lšœ,™,K™Kšœœ ˜Kšœ œ ˜Kšœ˜Kšœ˜—K˜Kš œœœœœ0˜SKšœœœ˜K˜Kšœœ œ˜-Kšœ-˜-Kšœ"˜"Kšœ œœœ˜ฝKšœœœœŒ˜ตK˜Kšœœ˜3Kšœœ˜0Kšœ˜Kšœ˜—K˜™K˜K˜šŸœœ˜.Kšœ˜—K˜š Ÿ œœ.œœœ˜jKš˜KšŸ œ%˜1K˜Kšœ˜K˜K˜Kšœ&˜&Kšœ/˜/Kšœ"˜"Kšœ œœœq˜‘Kšœœœœ`˜‰Kšœœ œœ˜5Kšœ˜—˜K™/K™4—š Ÿ œœ(œœœ˜`Kš˜KšŸœ%˜4K˜Kšœ˜K˜K˜Kšœ)˜)Kšœ)˜)Kšœ"˜"Kšœ œœœs˜“Kšœœœœb˜‹Kšœœœœ˜6K˜K™oK™Kšœ˜K˜—K˜š Ÿœœœœœœ˜hKš˜KšŸœ%˜6K˜Kšœ˜K˜K˜Kšœ+˜+Kšœ˜Kšœ)˜)Kšœ"˜"Kšœ œœœu˜•Kšœœœœd˜Kšœœœœ˜-Kšœ˜—K˜š ŸœœEœœœœ˜tKšŸœ%˜5K˜Kšœ˜Kšœœœ˜K˜Kšœ œ˜,Kšœœœ˜3K˜šœ˜Kš˜Kšœ*˜*KšœC˜CKšœž˜8Kšœ"˜"Kšœ œœœt˜”Kšœœœœc˜ŒKšœœ˜K˜Kšœ˜ Kš˜—Kšœœœœ˜Kšœ˜K˜K™—K˜šŸœœ>œœ˜sKšŸœ%˜7K˜Kšœ˜K˜K˜Kšœœ+˜BK˜Kšœ œ˜,Kšœœœ˜3K˜Kšœ,˜,Kšœ+˜+Kšœž˜0Kšœ"˜"Kšœ œœœv˜–Kšœœœœe˜ŽKšœ œ˜!K˜šœœ˜3K™+K˜—Kšœ˜K˜Kšœ˜—K˜K˜Kšœ;™;š Ÿœœœœœ˜HKšœœ˜<—J˜J˜šŸœœ>œœ˜kKšŸœ%˜7K˜Kšœ˜K˜K˜Kšœœ+˜BK˜Kšœ œ˜,Kšœœœ˜3šœœ™:Kšœ;™;—Kšœ,œ˜LK˜Kšœ,˜,Kšœ+˜+Kšœž˜0Kšœ"˜"Kšœ œœœv˜–Kšœœœœe˜ŽKšœ œ˜!K˜šœœ˜3K™+K˜—Kšœ˜K˜šœ˜K˜—K˜K˜—K˜šŸœœDœ˜lKšŸœ%˜7K˜Kšœ˜Kšœœ˜;K˜Kšœœ+˜BK˜K˜K˜K˜Kšœ œ˜,Kšœœœ˜3šœœ™:Kšœ;™;—Kšœ,œ˜LK˜Kšœ,˜,Kšœ+˜+Kšœ"˜"Kšœ"˜"Kšœ œœœv˜–Kšœ˜K˜K˜—K˜š ŸœœEœœœœ˜|KšŸœ%˜5K˜Kšœ˜K˜Kšœœ+˜BK˜Kšœ œ˜,Kšœœœ˜3šœœ™:Kšœ;™;—Kšœ,œ˜LK™Kšœ*˜*Kšœ+˜+Kšœ˜š œŸœœœ˜Kšœ&˜&Kšœ˜—K˜Kšœ"˜"Kšœ œœœt˜”šœ˜K˜—K˜—K˜šŸœœ,œœœœœ˜xKš˜KšŸœ%˜7K˜Kšœ˜Kšœ œ˜K˜Kšœœ˜K˜K˜K˜Kš œœœœœ˜2K˜K˜Kšœ,˜,Kšœ"˜"Kšœ$˜$Kšœ"˜"Kšœ œœœ1˜QK˜Kšœœœœv˜ŸKšœ œ˜!K˜Kš œœœœœ1˜mK˜Kšœ'˜'K˜š œŸœœ œœ˜-Kšœœ˜šœ œœ˜KKšœ˜Kšœ˜Kšœ"˜"Kšœ ˜ Kšœœœ˜/Kšœ"˜"Kšœ˜Kšœ$˜$Kšœ'˜'—Kšœœ˜Kšœ˜—K˜Kšœ˜ Kšœ˜—˜K˜—šŸœœœœ˜UKš˜KšŸœ&˜6K˜Kšœ˜Kšœœ˜=K˜Kšœ*˜*Kšœ˜Kšœ"˜"Kšœ œœœt˜”Kšœœœœc˜ŒK˜Kšœ!œ˜8Kšœœœœ˜2Kšœœ œ˜KKšœœœœ˜3Kšœœ œ˜ZKšœ œœœ˜AKšœ˜ Kšœ˜K˜—K˜šŸœœ˜-Kš˜KšŸœ&˜7K˜Kšœ˜K˜Kšœ+˜+Kšœ"˜"Kšœ œœœu˜•Kšœœœœe˜ŽK˜Kšœ˜—K˜šŸœœ$œ œ œ œœœ œ˜šKš˜KšŸœ&˜=K˜Kšœ˜K˜Kšœ1˜1K˜Kšœ%˜%šœœ œœ˜4Kšœ@™@KšœŽœ™ง—Kšœœœœ˜1Kšœœœœ˜1Kšœœœ˜-Kšœ"˜"K˜Kšœ œœœ~˜žKšœœœœm˜–Kšœœœœ˜+K˜šœ˜K˜K™+——K˜šŸœœ œœœœ œœ˜”š˜KšŸœ&˜4K˜Kšœ˜K˜Kšœ(˜(K˜Kšœ ˜ Kšœ)˜)Kšœ%˜%K˜K˜Kšœ"˜"Kšœ œœœu˜•Kšœœœœd˜K˜Kšœœœœœœœ˜HK˜Kšœ˜K˜——š œŸœœœœ˜bKš˜KšŸœ&˜:K˜Kšœ˜Kšœ"œ˜DK˜Kšœ.˜.Kšœ ˜ Kšœ"˜"Kšœ œœœx˜˜Kšœœœœg˜‘K˜Kšœœœœ˜0Kšœœœœ˜9Kšœœ œ˜LKšœœœœ˜1Kšœœœœ˜0Kšœ œœœ˜.Kšœœœœ˜/Kšœœœœ˜0Kšœœ˜6Kšœœœœ˜4Kšœœœœ˜9Kšœœœœ˜5Kšœœœœ˜4Kšœœœœ˜4Kšœœœœ˜3Kšœœœœ˜4Kšœœœœ˜3Kšœœœœ˜3Kšœœœœ˜2Kšœœœœ˜6Kšœœœœ˜5K˜Kšœ˜Kšœ˜—K˜šŸœœœœ˜aKš˜KšŸœ&˜:K˜Kšœ˜Kšœ"œ˜DK˜Kšœ œ˜Kšœ œ˜K˜Kšœ.˜.Kšœ ˜ Kšœ"˜"Kšœ œœœx˜˜Kšœœœœg˜‘K˜Kšœœœœ˜0Kšœœœœ˜9Kšœœ œ˜LKšœœœœ˜1Kšœœœœ˜0Kšœ œœœ˜.Kšœœœœ˜/Kšœœœœ˜0Kšœ œœœ˜-Kšœ œœœ˜-šœœ˜K™+—Kšœœœœ˜5Kšœœœœ˜9Kšœœœœ˜5Kšœœœœ˜4Kšœœœœ˜4Kšœœœœ˜3Kšœœœœ˜4Kšœœœœ˜3Kšœœœœ˜3Kšœœœœ˜2Kšœœœœ˜6Kšœœœœ˜5K˜Kšœ˜Kšœ˜—K˜š œœ!œœœ œœ˜ฆKš˜KšŸœ&˜BK˜Kšœ˜K˜Kšœ6˜6Kšœ˜Kšœœœœ˜8Kšœœ œœ˜5Kšœ"˜"Kšœ"˜"Kšœ œœœ€˜ K˜Kšœ ˜&Kšœ˜—K˜š  œœœ œœ˜uKš˜KšŸœ&˜CK˜Kšœ˜K˜Kšœ7˜7Kšœ˜Kšœ"˜"Kšœ"˜"Kšœ œœœ˜กK˜Kšœ ˜&Kšœ˜K˜—K˜š œœœœ˜dKš˜KšŸœ&˜@K˜Kšœ˜K˜Kšœ4˜4Kšœ˜Kšœ"˜"Kšœ œœœ~˜žK˜Kšœ ˜&šœ˜K˜——š "œœœ œœœœ œœ˜ฯKš˜KšŸ$œ&˜JK˜Kšœ˜K˜K˜Kšœ>˜>Kšœ˜Kšœ˜Kšœœœœ˜8Kšœ%˜%Kšœ(˜(Kšœ"˜"Kšœ"˜"Kšœ œœœˆ˜จK˜Kšœ ˜&Kšœ˜K˜—K˜š #œœœœœœ œœ˜ณKš˜KšŸ%œ&˜KK˜Kšœ˜K˜K˜Kšœ?˜?Kšœ˜Kšœ˜Kšœ%˜%Kšœ(˜(Kšœ"˜"Kšœ"˜"Kšœ œœœ‰˜ฉK˜Kšœ ˜&Kšœ˜—K˜—˜šŸœœœ˜[Kš˜šœœœœ1˜ZK˜Kš˜Kš œ œœœœ˜3šœ ˜˜Kš˜Kšœ!œ˜BKšœœœœ1˜ZKšœœœœ˜/Kšœœ˜5Kšœ œœœ˜.Kšœœœœ˜/Kšœ œœœ˜.Kšœœœœ˜4Kšœ˜Kšœ˜—Kšœœœ˜—Kšœ˜—Kšœ˜—K˜š Ÿœœ/œœœ˜fKš˜š Ÿ œ œœœœ˜3™VK™}—Kšœ.˜.šœœœœ˜Kšœ˜Kšœ˜KšŸ œ(˜HKšœ:˜:Kšœ ˜ Kšœ"˜"Kšœ œœœ˜ŸKšœœœœn˜—Kšœ œœœ˜0Kšœ˜K˜—K˜šŸœœœ+œ'˜yKšœœ œ˜>Kšœ˜Kšœ˜KšŸœ(˜BKšœ4˜4Kšœ˜Kšœ"˜"Kšœ œœœy˜™Kšœœœœh˜‘Kšœœ˜1Kšœ˜K˜—K˜šŸœœ/œ#˜pšœœ œ˜>Kšœ˜Kšœ˜Kšœœ˜ KšŸœ(˜@Kšœ2˜2Kšœ-˜-Kšœ˜Kšœ"˜"Kšœ œœœw˜—Kšœœœœf˜Kšœœœœ˜/Kš œœœœœœœ˜CJšœ˜K˜——K˜K˜—K™˜˜K™)Kš œ œœœœœœ˜E—šŸœœ/œœœœœ˜iKšœ œœœ˜Kšœœœ˜$Kšœ˜K˜Kšœ œ˜,Kšœœœ˜3K˜šœ˜Kš˜Kšœœ6˜LKšœœ™,Kšœœ.™Dš œœœœ œ˜#Kšœ6˜6Kšœ˜—Kšœ˜ Kš˜—Kšœœœ˜Kšœ˜K˜—K˜Kš œ œœœœœ˜)š Ÿœœ(œœœ˜hKšœ œœœ˜Kšœœ˜KšœœD˜eK˜Kšœ œ˜,Kšœœœ˜3K˜Kšœ˜K˜Kšœœ ˜šœ˜K˜——K˜Kš œ œœœœœ˜)K˜Kšœ;™;š Ÿœœœœœ˜AKšœœ˜/—K˜š Ÿœœ(œœœ˜`Kšœ œœœ˜KšœœC˜dK˜Kšœ œ˜,Kšœœœ˜3šœœœ œ™CK™;—šœœœœ˜UK™—Kšœœ˜šœ˜K˜—K˜—˜K˜—šŸœœ.œœ˜aKšœ œœœ˜KšœœC˜dK˜Kšœ œ˜,Kšœœœ˜3šœœœ œ™CK™;—šœœœœ˜UK™—K˜Kšœ˜K˜K˜—˜Kš œ œœœœœœ˜E—šŸœœ/œœœœœ˜qKšœ œœœ˜Kšœ˜K˜Kšœ œ˜,Kšœœœ˜3K˜Kšœœ6˜LKšœœ™,Kšœœ.™Dšœœœ œ™CK™;—šœœœœ˜UK™—šœœœ˜K˜Kšœ˜—šœ˜K˜——K˜K˜Kš œœœœ œœœ˜GK˜šŸœœ œœœœ œ˜SKš˜šœœœ&˜HKšœ…™…—š Ÿœœœœ˜,Kšœœœ˜—Kšœ˜ šœ˜˜K™F———šŸœœœœ˜5Kš˜Kš˜Kšœ˜—K˜Kš Ÿœœ/œœœ.˜”K˜—K™K™™K™K™˜šœ™Kšœ™—Kšœ™—K˜š Ÿ œœœ œœ œ˜JK™bšœ0œ˜9Kšœœ#œ>˜„Kšœ˜—Kšœ˜šœ™Kšœœœ˜#K˜:Kšœœœ(˜KKšœ˜—™K˜K˜1Kšœœœ:˜GKšœ;˜;Kšœ˜%K˜—Kšœ˜—K˜šŸœœœœ˜QJ™#šœ˜Jšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ"˜"Kšœ*˜*Kšœ$˜$Kšœ˜Kšœ#˜*—Kšœ˜—K˜K˜—Kšœ˜K˜:——…—หฤ#s