CirioNubAccess.mesa
Sturgis, March 23, 1990 3:18 pm PST
Last changed by Theimer on October 9, 1989 3:31:11 pm PDT
Linda Howe December 27, 1989 3:54:21 pm PST
Peter B. Kessler, July 10, 1990 11:48 am PDT
Coolidge, July 18, 1990 9:54 am PDT
Spreitze, December 23, 1991 9:38 am PST
Laurie Horton, September 27, 1991 12:55 pm PDT
Philip James, February 24, 1992 9:55 am PST
DIRECTORY
CirioNubAccessPrivate,
PFSNames USING [PATH],
Rope USING[ROPE];
CirioNubAccess: CEDAR DEFINITIONS =
BEGIN
Handle: TYPE = REF HandleBody;
HandleBody: TYPE = CirioNubAccessPrivate.HandleBody;
These procedures provide access to the target world through the remote procedures described in /demsun-UX/home/demers/cirio/CirioNubProcs.h
Some of those procedures that provide for the transmission of blocks of data have been represented here as supplying only a single item. Block access can be added as needed.
The following form of remote address is convenient for the interior of Cirio
The procedures which accept this address will compute a byte address by adding bitOffset/8 to the byte address.
If nil = TRUE, then the procedures will generate RemoteNilFault.
If valid = FALSE, then the procedures will generate RemoteNilFault.
RemoteAddress: TYPE = RECORD[
h: Handle,
byteAddress: CARD,
bitOffset: CARD,
nil: BOOLEAN,
valid: BOOLEAN];
RemoteNilFault: ERROR[addr: RemoteAddress];
RemoteAddrFault: ERROR[addr: RemoteAddress]; -- other than NIL
RemoteMonitorWouldBlock: ERROR[addr: RemoteAddress];
only raised by RemoteMonitoredCall.
RaFromCi: PROC [h: Handle, byteAddress: CARD, bitOffset: INT ← 0, nil: BOOLFALSE, valid: BOOLTRUE] RETURNS [RemoteAddress]
~ INLINE {RETURN [[h, LOOPHOLE[byteAddress], bitOffset, nil OR byteAddress=0, valid]]};
CreateRemoteNub: PROC[debuggee: Rope.ROPENIL, port: CARDINAL ← 0, timeoutMsec: INTINT.LAST] RETURNS [Handle];
Create a handle for talking to specified debuggee.
Default debuggee name is local host.
Default port is well-known PCR debugging port.
! Error[$connectError, $debuggeeNameLookupError, $timeout]
CreateSameWorldNub: PROC RETURNS [Handle];
DestroyNub: PROC[h: Handle];
GetProtocolVersionNumber: PROC[h: Handle] RETURNS[CARD];
Null: PROC[h: Handle, proposedVersionNumber: CARD] RETURNS[BOOLEAN];
id = 0
We use this to wait for a call from some thread
This is probably not what we shall use in the future
WaitSig: PROC[h: Handle, timeoutMilliSec: CARD] RETURNS[gotResponse: BOOLEAN];
id = 1
dbStat = -2 applies a club to the head of the pcr world
dbStat = -1 revives the pcr world with only virtual processor 0 running.
dbStat = 0 revives the pcr world
(other values may be seen in /jaune/xrhome/DEVELOPMENT/INCLUDE/xr/ThreadsBackdoor.h)
SetDBStat: PROC[h: Handle, dbStat: INT32, timeoutMilliSec: CARD] RETURNS[ok: BOOLEAN];
id = 2
ReadBytes: PROC[address: RemoteAddress, count: INT] RETURNS[REF TEXT];
id = 3
Read16BitsAsCardinal: PROC[address: RemoteAddress] RETURNS[CARDINAL];
id = 5
Read32BitsAsCard: PROC[address: RemoteAddress] RETURNS[CARD];
id = 7
WriteCardAs32Bits: PROC[address: RemoteAddress, card: CARD];
id = 8
Read4Bytes: PROC[address: RemoteAddress] RETURNS[PACKED ARRAY [0..3] OF BYTE];
id = 3
Write4Bytes: PROC[address: RemoteAddress, bytes: PACKED ARRAY [0..3] OF BYTE];
id = 4
ThreadInfo: TYPE = RECORD[
index: CARD,
gen: CARD,
schedState: CARD,
priority: CARD,
dbgMsg: INT,
frozen: BOOLEAN,
pc: CARD,
stackPointer: CARD,
framePointer: CARD];
dbgMsg contains (see [palain-uX]<>jaune>xrhome>DEVELOPMENT>INCLUDE>xr>Threads.h)
(e.g., XR�←MSG𡤌LIENT←REQUEST)
DbgMsgNone: INT = 0;
DbgMsgNoHandlerRequest: INT = 1;
DbgMsgHandlerRequest: INT = 2;
DbgMsgBadProceedRequest: INT = 3;
DbgMsgBreakRequest: INT = 4;
DbgMsgClientRequest: INT = 5;
schedState contains (see /xrhome/INSTALLED/INCLUDE/xr/CirioNubTypes.h and /xrhome/INSTALLED/INCLUDE/xr/Threads.h)
SchedStateNone: CARD = 0;
SchedStateFree: CARD = 1;
SchedStateReady: CARD = 2;
SchedStateRun: CARD = 3;
SchedStateWaitML: CARD = 4;
SchedStateWaitCV: CARD = 5;
SchedStateHandlee: CARD = 6;
GetThreads: PROC[h: Handle, lowIndex, highIndex: CARD] RETURNS[LIST OF REF ThreadInfo];
id = 9
PCInfo: TYPE = REF PCInfoBody;
PCInfoBody: TYPE = RECORD[
procName: Rope.ROPE,
procSymID: CARD,
fileName: PFSNames.PATH,
fileSeqNum: CARD,
guessedEmbeddedFileName: PFSNames.PATH,
guessedEmbeddedFileSymID: CARD];
PCtoInfo: PROC[h: Handle, pc: CARD] RETURNS[PCInfo];
id = 10
This destroys the PCedar world to which the nub is attached.
KillWorld: PROC[h: Handle];
id = 11
possible values of msg can be seen at
[palain-uX]<>jaune>xrhome>DEVELOPMENT>INCLUDE>xr>Threads.h
XRDBMSGPROCEEDREPLY, etc
DbgMsgAbort: INT = -3;
DbgMsgExit: INT = -2;
DbgMsgProceed: INT = -1;
IssueThreadCommand: PROC[h: Handle, threadIndex: CARD, setFreeze: BOOL, freeze: BOOL, setMsg: BOOL, msg: INT] RETURNS[success: BOOLEAN];
id = 18
waits for change from old values or timeout
GetDBStat: PROC[h: Handle, oldStat: INT32, oldExamineeIndex: INT, timeoutMsec: CARD] RETURNS[dbStab: INT32, examineeIndex: INT32];
id = 19
Size: TYPE ~ INT--I'd like to say [0..INT.LAST], but PrincOps can't compile that--;
Pointer: TYPE ~ INT--not a POINTER 'cause Cirio can't handle those yet, and not a CARD because RemoteAddress uses INT--;
Nil: Pointer ~ 0;
Fields: TYPE ~ REF FieldSeq;
FieldSeq: TYPE ~ RECORD [SEQUENCE length: NAT OF Field];
Field: TYPE ~ RECORD [
address: Pointer,
bitOffset: Size,
bits: Size];
nilField: Field ~ [Nil, 0, 0];
SizeList: TYPE ~ LIST OF Size;
ProcRep: TYPE ~ LONG POINTER TO ProcPair;
ProcPair: TYPE ~ RECORD [startPC, flag: Pointer];
Call: PROC [h: Handle, proc: ProcRep, formalArgSizes, formalRetSizes: SizeList, actualArgs, actualRets: Fields];
FileEntry: TYPE = REF FileEntryBody;
FileEntryBody: TYPE = RECORD[
seqNum: CARD,
commitPoint: BOOL,
fileName: PFSNames.PATH,
fOffset: CARD,
fmagic: CARD,
size: CARD,
mtime: CARD,
smagic: CARD,
stamp: Rope.ROPE,
readerData: CARD,
readerDataSize: CARD,
patchReloc: CARD,
patchSize: CARD,
textReloc: CARD,
textSize: CARD,
dataReloc: CARD,
dataSize: CARD,
bssReloc: CARD,
bssSize: CARD,
commonReloc: CARD,
commonSize: CARD];
Return file entry with largest seqNum <= the specified one.
Claim: can't fail.
GetFileEntry: PROC[h: Handle, seqNum: CARD] RETURNS[entry: FileEntry];
id = 20
SymEntry: TYPE = REF SymEntryBody;
SymEntryBody: TYPE = RECORD[
symID: CARD,
name: Rope.ROPE,
type: CARD,
value: CARD,
size: CARD,
fileSeqNum: CARD];
Here are some SymEntry types
ModuleType: CARD = 1eH;
TextType: CARD = 4;
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.
That is, ModuleType and ModuleType+1 are both module types.
The following procedures return NIL if no appropriate SymEntry can be found.
LookupSymEntryByName: PROC[h: Handle, sym: Rope.ROPE, caseSensitive: BOOLEAN, externOnly: BOOLEAN, numToSkip: INT] RETURNS[SymEntry];
id = 21
(numToSkip > 0) ~ GetNextByValue
(numToSkip < 0) ~ GetPrevByValue
LookupSymEntryByValue: PROC[h: Handle, val: CARD, numToSkip: INT] RETURNS[SymEntry];
id = 22
LookupSymEntryByID: PROC[h: Handle, symID: CARD] RETURNS[SymEntry];
id = 23
LookupFileEntryByStemName: PROC[h: Handle, stemName: Rope.ROPE, numToSkip: INT] RETURNS[SymEntry];
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
following two operations are only available on version 6 protocol
NOTE WELL: The algorithm for the following two procedures is as follows:
(1) find highest entry less or equal to the starting point that satisfies the conditions
(2) set skipped to 0
(3) if skipped = numToSkip then return found entry
(4) if skip < 0 then find highest entry less than the previously found entry that satisfies the conditions and set skipped to skipped - 1
(5) if skip > 0 then find lowest entry greater than the previously found entry that satisfites the conditions and set skipped to skipped + 1
(6) go to (3)
The effect is that if one is supplied as an initial symID the id of an entry that does not satisfy the conditions, and has set numToSkip = -1, then one will skip over the highest entry less or equal to the starting point, whereas if one has set numToSkip to +1, one will find the lowest entry greater or equal to the starting point.
Thus, if one wants to search successively lower entries than a given non matching entry, one first tries numToSkip=0, then uses numToSkip=-1 for successive moves. On the other hand, if one wants to search successively higher entries than a given non matching entry, one uses numToSKip=1 for each move.
I guess this is also true if one starts with a value that does not match a given entry. For examining successively lower entries starting with the highest entry less or equal to the given value, one first uses numToSkip = 0, then successive numToSkip = -1. For examining successively higher entries greater than the given value, one uses numToSkip = 1 for all calls.
i.e., use of these procedures is delicate.
LookupMatchingSymEntryByName: PROC[h: Handle, symID: CARD, pattern: Rope.ROPE, caseSensitive: BOOLEAN, wantedTypes: CARD, ignoreClasses: CARD, numToSkip: INT] RETURNS[SymEntry];
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.
LookupMatchingSymEntryByValue: PROC[h: Handle, symID: CARD, val: CARD, wantedTypes: CARD, ignoreClasses: CARD, numToSkip: INT] RETURNS[SymEntry];
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 <value, entry time). These keys are ordered by value first, then by entry time. The search key is <the given val, now>.
AllocatedBytes: TYPE = RECORD[allocHandle: AllocHandle, bytes: RemoteAddress];
AllocHandle: TYPE = REF AllocHandleBody;
AllocHandleBody: TYPE;
AllocateBytes: PROC[h: Handle, nBytes: CARD] RETURNS[AllocatedBytes];
ReleaseAllocatedBytes: PROC[allocHandle: AllocHandle];
This mechanism is intended for the implementation of interpreted procedure calls. The client swears that no load or store references will be made to the allocated bytes after calling ReleaseAllocatedBytes or after calling DestroyNub. This is probably not the appropriate mechanism for allocating REF targets.
MonitoredCall: PROC[address: RemoteAddress, proc: PROCEDURE [] RETURNS []];
While holding the monitor lock pointed to by the given address, call the given procedure (in the debugger world).
Typecode: TYPE ~ RECORD [CARD];
Typestring: TYPE ~ Rope.ROPE;
GetConcreteTypecode: PROC[h: Handle, opaque: Typecode] RETURNS[concrete: Typecode, whyNot: Rope.ROPENIL];
GetTypestring: PROC[h: Handle, code: Typecode] RETURNS[string: Typestring, whyNot: Rope.ROPENIL];
GetTypecode: PROC [h: Handle, string: Typestring] RETURNS [code: Typecode, whyNot: Rope.ROPENIL];
GetInstructionSetAndOperatingSystem: PROC[h: Handle] RETURNS[instrSet, opSys: Rope.ROPE];
id = 30
Error: ERROR [codes: LIST OF ATOM, msg: Rope.ROPE];
END..