-- File: GateDebug.mesa, Last Edit: HGM December 20, 1980 3:11 PM -- This module lives and runs in the debugger. It looks in the users core image to find and print things. DIRECTORY DebugUsefulDefs USING [ Enumerate, Name, ShortREAD, ShortCopyREAD, LongREAD, LongCopyREAD], Event USING [AddNotifier, Item, Masks, Notifier], Format USING [], Menu USING [ItemObject, MCRType, Create, Instantiate], UserInput USING [GetDefaultWindow], Put USING [Char, CR, Date, Line, LongNumber, Number, Octal, Text], Storage USING [Node, FreeNodeNil], String USING [EquivalentStrings], Window USING [Handle], Boss USING [bigBoy], File USING [nullCapability], StatsDefs USING [StatCounterIndex], Lock USING [Lock, LockObject], BootServerDefs USING [BootFile, BootFileObject, timeNotKnown], NameServerDefs USING [CacheEntry, CacheEntryObject], DriverDefs USING [GiantVector], GateDefs USING [GateDebugRecord], GateInit USING [gateDebug], AltoSlaDefs, BufferDefs USING [PupAddress]; GateDebug: PROGRAM IMPORTS DebugUsefulDefs, Event, Menu, UserInput, Put, Storage, String SHARES Boss, GateInit, GateDefs, BufferDefs = BEGIN OPEN BufferDefs; wh: Window.Handle = NIL; giantVector: POINTER TO DriverDefs.GiantVector ← NIL; gateVector: POINTER TO GateDefs.GateDebugRecord ← NIL; GetThings: PROCEDURE RETURNS [BOOLEAN] = BEGIN IF boss = NIL OR gate = NIL THEN BEGIN Put.Line[NIL, "Scanning GFT...."L]; LookForFrames[]; IF boss = NIL OR gate = NIL THEN BEGIN IF boss = NIL THEN Put.Line[NIL, "**** Can't find Boss!"L]; IF gate = NIL THEN Put.Line[NIL, "**** Can't find GateInit!"L]; RETURN[FALSE]; END; END; CopyRead[ to: giantVector, from: @boss.bigBoy, nwords: SIZE[DriverDefs.GiantVector]]; CopyRead[ to: gateVector, from: @gate.gateDebug, nwords: SIZE[GateDefs.GateDebugRecord]]; RETURN[TRUE]; END; All: PROCEDURE = BEGIN IF ~GetThings[] THEN RETURN; Put.CR[wh]; ShowString[gateVector.version]; Boot[]; Cache[]; Locks[]; END; Boot: PROCEDURE = BEGIN bf: BootServerDefs.BootFile; bfo: BootServerDefs.BootFileObject; IF ~GetThings[] THEN RETURN; bf ← Read[gateVector.boot]; Put.CR[wh]; Put.Line[wh, "Boot File Table:"L]; Put.Line[wh, " Code Count AvgMs Create Time FileName"L]; THROUGH [0..50) UNTIL bf = NIL DO CopyRead[to: @bfo, from: bf, nwords: SIZE[BootServerDefs.BootFileObject]]; O6[bfo.code]; LD6[bfo.count]; IF bfo.count = 0 THEN Put.Text[wh, " "L] ELSE LD6[bfo.ms/bfo.count]; Put.Text[wh, " "L]; SELECT TRUE FROM (bfo.file = File.nullCapability) => Put.Text[wh, "Not on this disk "L]; (bfo.create = BootServerDefs.timeNotKnown) => Put.Text[wh, "Unknown "L]; ENDCASE => Put.Date[wh, bf.create, dateTime]; Put.Text[wh, " "L]; ShowString[bfo.fileName]; Put.CR[wh]; bf ← bfo.next; ENDLOOP; END; Cache: PROCEDURE = BEGIN limit: CARDINAL = 10; ce: NameServerDefs.CacheEntry; ceo: NameServerDefs.CacheEntryObject; i: CARDINAL; names: ARRAY [0..limit) OF STRING; addrs: ARRAY [0..limit) OF PupAddress; IF ~GetThings[] THEN RETURN; Put.CR[wh]; Put.Line[wh, "Cache for Name Lookup Server:"L]; Put.Line[wh, " Count Seq size Name(s) <=> Address(es)"L]; ce ← Read[gateVector.cache]; THROUGH [0..50) UNTIL ce = NIL DO CopyRead[to: @ceo, from: ce, nwords: SIZE[NameServerDefs.CacheEntryObject]]; CopyRead[to: @names, from: BASE[ceo.names], nwords: limit*1]; CopyRead[to: @addrs, from: BASE[ceo.addrs], nwords: limit*SIZE[PupAddress]]; LD6[ceo.count]; D5[ceo.sequence]; D5[ceo.size]; Put.Text[wh, " "L]; IF LENGTH[ceo.names] = 0 THEN Put.Char[wh, '?] ELSE FOR i IN [0..MIN[limit, LENGTH[ceo.names]]) DO IF i # 0 THEN Put.Text[wh, ", "L]; ShowString[names[i]]; ENDLOOP; Put.Text[wh, " <=> "L]; IF LENGTH[ceo.addrs] = 0 THEN Put.Char[wh, '?] ELSE FOR i IN [0..MIN[limit, LENGTH[ceo.addrs]]) DO IF i # 0 THEN Put.Text[wh, ", "L]; A[addrs[i]]; ENDLOOP; Put.CR[wh]; ce ← ceo.next; ENDLOOP; END; Locks: PROCEDURE = BEGIN limit: CARDINAL = 10; lock: Lock.Lock; lo: Lock.LockObject; IF ~GetThings[] THEN RETURN; lock ← Read[gateVector.locks]; IF lock = NIL THEN BEGIN Put.Line[wh, "Nothing is locked."L]; RETURN; END; Put.Line[wh, "Lock table:"L]; Put.Line[wh, " Read W Name"L]; THROUGH [0..30) UNTIL lock = NIL DO CopyRead[to: @lo, from: lock, nwords: SIZE[Lock.LockObject]]; D5[lo.useCount]; Put.Text[wh, IF lo.write THEN " W "L ELSE " "L]; ShowString[lo.name]; Put.CR[wh]; lock ← lo.next; ENDLOOP; END; seconds: LONG CARDINAL; Sla: PROCEDURE = BEGIN OPEN AltoSlaDefs; Counters: TYPE = ARRAY StatsDefs.StatCounterIndex OF LONG CARDINAL; p: LONG POINTER; activeLines: CARDINAL; hisLineTable: LONG POINTER TO ARRAY Line OF LineTableEntry; hisLineInfo: LONG POINTER TO ARRAY Line OF LineInfoBlock; hisRoutingTable: LONG POINTER TO ARRAY SlaHost OF RoutingTableEntry; hisCounters: Counters; IF ~GetThings[] THEN RETURN; LongCopyRead[ to: @hisCounters, from: giantVector.statCounters, nwords: SIZE[Counters]]; seconds ← hisCounters[statSeconds]; p ← giantVector.slaThings; IF p = NIL THEN BEGIN Put.Line[wh, "No SLA Driver."L]; RETURN; END; p ← p + maxByte; -- skip CRC Table activeLines ← LongRead[p]; hisLineTable ← p + 8; p ← 8 + p + maxLine*SIZE[LineTableEntry]; hisRoutingTable ← p; p ← p + maxSlaHost*SIZE[RoutingTableEntry]; hisLineInfo ← p; IF activeLines > maxLine THEN ERROR; PrintSlaStats[activeLines, hisLineInfo, hisRoutingTable]; Put.CR[wh]; END; PrintSlaStats: PUBLIC PROCEDURE [ lines: CARDINAL, hisInfo: LONG POINTER, hisRouting: LONG POINTER] = BEGIN OPEN AltoSlaDefs; line: Line; host: SlaHost; info: ARRAY Line OF LineInfoBlock; lib: POINTER TO LineInfoBlock; routing: ARRAY SlaHost OF RoutingTableEntry; rte: POINTER TO RoutingTableEntry; k: CARDINAL; temp: LONG CARDINAL; Put.CR[wh]; LongCopyRead[to: @info, from: hisInfo, nwords: lines*SIZE[LineInfoBlock]]; LongCopyRead[ to: @routing, from: hisRouting, nwords: maxSlaHost*SIZE[RoutingTableEntry]]; Put.Line[ wh, "SLA Line Statistics: ---Packets---- ------Bytes----- ------Errors----- Line To Sent Received Sent Received CRC Sync Control State"L]; FOR line IN [0..lines) DO lib ← @info[line]; O3[line]; -- find out who this line is connected to FOR host IN SlaHost DO rte ← @routing[host]; IF rte.line = line AND rte.hops = 1 THEN BEGIN O4[host]; EXIT; END; REPEAT FINISHED => Put.Text[wh, " ?"L]; ENDLOOP; LD10[lib.packetsSent]; LD10[lib.packetsRecv]; LD10[lib.bytesSent]; LD10[lib.bytesRecv]; D6[lib.crcErrors]; D6[lib.syncErrors]; D6[lib.controlErrors]; Put.Text[wh, " "L]; SELECT lib.state FROM up => Put.Line[wh, "Up"L]; down => Put.Line[wh, "Down"L]; loopedBack => Put.Line[wh, "Looped back"L]; missing => Put.Line[wh, "Missing"L]; ENDCASE => Put.Line[wh, " ??"L]; ENDLOOP; Put.Line[ wh, " Hi/Lo Q ------Hi-Q------ -------Bits/Sec------- Line Packets Bytes Hi Sent Received"L]; FOR line IN [0..lines) DO lib ← @info[line]; O3[line]; D4[lib.hiPriQueue.length]; D4[lib.lowPriQueue.length]; LD10[lib.hiPacketsSent]; LD10[lib.hiBytesSent]; temp ← lib.hiBytesSent + overheadPerPacket*lib.hiPacketsSent; LD10[temp*8/seconds]; temp ← lib.bytesSent + overheadPerPacket*lib.packetsSent; LD10[temp*8/seconds]; temp ← lib.bytesRecv + overheadPerPacket*lib.packetsRecv; LD10[temp*8/seconds]; Put.CR[wh]; ENDLOOP; Put.Line[ wh, " Routing Table: Host Line Hops Host Line Hops Host Line Hops Host Line Hops"L]; k ← 0; FOR host IN SlaHost DO rte ← @routing[host]; IF rte.hops = longHop THEN LOOP; IF k # 0 THEN Put.Text[wh, " "L]; O4[host]; D5[rte.line]; D5[rte.hops]; IF (k ← k + 1) = 4 THEN BEGIN Put.CR[wh]; k ← 0; END; ENDLOOP; IF k # 0 THEN Put.CR[wh]; END; -- Interface to the debugger Read: PROCEDURE [p: POINTER] RETURNS [UNSPECIFIED] = BEGIN RETURN[DebugUsefulDefs.ShortREAD[p]]; END; LongRead: PROCEDURE [LONG POINTER] RETURNS [UNSPECIFIED] = DebugUsefulDefs.LongREAD; CopyRead: PROCEDURE [to: POINTER, from: POINTER, nwords: CARDINAL] = BEGIN DebugUsefulDefs.ShortCopyREAD[from: from, nwords: nwords, to: to]; END; LongCopyRead: PROCEDURE [to: POINTER, from: LONG POINTER, nwords: CARDINAL] = BEGIN DebugUsefulDefs.LongCopyREAD[from: from, nwords: nwords, to: to]; END; LongReadLong: PROCEDURE [from: LONG POINTER] RETURNS [x: LONG UNSPECIFIED] = BEGIN LongCopyRead[to: @x, from: from, nwords: 2]; END; -- Printout routines A: PROCEDURE [a: PupAddress] = BEGIN Put.Char[wh, ' ]; Put.Octal[wh, a.net]; Put.Char[wh, '#]; Put.Octal[wh, a.host]; Put.Char[wh, '#]; IF a.socket.a # 0 THEN BEGIN Put.Octal[wh, a.socket.a]; Put.Char[wh, '|]; END; Put.Octal[wh, a.socket.b]; END; D2: PROCEDURE [num: UNSPECIFIED] = BEGIN Put.Number[wh, num, [10, FALSE, TRUE, 2]]; END; D4: PROCEDURE [num: UNSPECIFIED] = BEGIN Put.Number[wh, num, [10, FALSE, TRUE, 4]]; END; D3: PROCEDURE [num: UNSPECIFIED] = BEGIN Put.Number[wh, num, [10, FALSE, TRUE, 3]]; END; D5: PROCEDURE [num: UNSPECIFIED] = BEGIN Put.Number[wh, num, [10, FALSE, TRUE, 5]]; END; D6: PROCEDURE [num: UNSPECIFIED] = BEGIN Put.Number[wh, num, [10, FALSE, TRUE, 6]]; END; LP: PROCEDURE [num: LONG POINTER] = BEGIN short: RECORD [p: POINTER, other: WORD] = LOOPHOLE[num]; Put.Char[wh, IF short.other = 0 THEN ' ELSE '?]; Put.Number[wh, short.p, [8, FALSE, TRUE, 6]]; END; LD6: PROCEDURE [num: LONG CARDINAL] = BEGIN Put.LongNumber[wh, num, [10, FALSE, TRUE, 6]]; END; LD10: PROCEDURE [num: LONG CARDINAL] = BEGIN Put.LongNumber[wh, num, [10, FALSE, TRUE, 10]]; END; O3: PROCEDURE [num: UNSPECIFIED] = BEGIN Put.Number[wh, num, [8, FALSE, TRUE, 3]]; END; O4: PROCEDURE [num: UNSPECIFIED] = BEGIN Put.Number[wh, num, [8, FALSE, TRUE, 4]]; END; O6: PROCEDURE [num: UNSPECIFIED] = BEGIN Put.Number[wh, num, [8, FALSE, TRUE, 6]]; END; O7: PROCEDURE [num: UNSPECIFIED] = BEGIN Put.Number[wh, num, [8, FALSE, TRUE, 7]]; END; ShowString: PROCEDURE [s: STRING] = BEGIN temp: STRING = [204]; -- maxlength gets clobbered IF s # NIL THEN BEGIN CopyRead[to: temp, from: s, nwords: 100]; IF temp.length > 200 THEN temp.length ← 25; Put.Text[wh, temp]; END ELSE Put.Text[wh, "NIL"L]; END; SetUp: PROCEDURE = BEGIN giantVector ← Storage.Node[SIZE[DriverDefs.GiantVector]]; gateVector ← Storage.Node[SIZE[GateDefs.GateDebugRecord]]; END; SetDown: PROCEDURE = BEGIN giantVector ← Storage.FreeNodeNil[giantVector]; gateVector ← Storage.FreeNodeNil[gateVector]; END; items: ARRAY [0..4] OF Menu.ItemObject ← [["All", DoInfo], ["SLA", DoInfo], ["Boot", DoInfo], ["Cache", DoInfo], ["Locks", DoInfo]]; all: CARDINAL = 0; sla: CARDINAL = 1; boot: CARDINAL = 2; cache: CARDINAL = 3; locks: CARDINAL = 4; DoInfo: Menu.MCRType = BEGIN SetUp[]; SELECT index FROM all => All[]; sla => Sla[]; boot => Boot[]; cache => Cache[]; locks => Locks[]; ENDCASE; SetDown[]; END; boss: POINTER TO FRAME[Boss] ← NIL; gate: POINTER TO FRAME[GateInit] ← NIL; nMods: CARDINAL = 2; LookForFrames: PROCEDURE = BEGIN moduleName: ARRAY [0..nMods) OF STRING ← ["Boss"L, "GateInit"L]; basePtr: ARRAY [0..nMods) OF POINTER ← [@boss, @gate]; keyString: STRING = [40]; nFound: CARDINAL ← 0; CheckOneFrame: PROCEDURE [han: UNSPECIFIED] RETURNS [BOOLEAN] = BEGIN name: POINTER TO ARRAY [0..nMods) OF STRING = @moduleName; base: POINTER TO ARRAY [0..nMods) OF POINTER = @basePtr; key: STRING = keyString; key.length ← 0; DebugUsefulDefs.Name[name: key, gf: han]; FOR i: CARDINAL IN [0..nMods) DO IF String.EquivalentStrings[key, name[i]] THEN BEGIN IF base[i]↑ = NIL THEN BEGIN base[i]↑ ← han; nFound ← nFound + 1 END ELSE BEGIN Put.Text[NIL, "Duplicate: "L]; Put.Line[NIL, key]; END; EXIT END; ENDLOOP; RETURN[nFound = nMods]; END; FOR i: CARDINAL IN [0..nMods) DO basePtr[i]↑ ← NIL; ENDLOOP; [] ← DebugUsefulDefs.Enumerate[CheckOneFrame]; IF nFound # nMods THEN BEGIN FOR i: CARDINAL IN [0..nMods) DO IF basePtr[i]↑ = NIL THEN BEGIN Put.Text[NIL, "Missing: "L]; Put.Line[NIL, moduleName[i]]; END; ENDLOOP; END; END; notifierItem: Event.Item ← [eventMask: Event.Masks[newSession], eventProc: Notify]; Notify: Event.Notifier = BEGIN SELECT why FROM newSession => BEGIN boss ← NIL; gate ← NIL; END; ENDCASE; END; -- initialization Event.AddNotifier[@notifierItem]; Menu.Instantiate[ Menu.Create[DESCRIPTOR[items], "Gate"], UserInput.GetDefaultWindow[]]; END.