-- CGenDebugGlobals.mesa Edited by Bruce, September 22, 1980 10:55 AM DIRECTORY AllocDebugDefs USING [], AltoDefs USING [wordlength], CGenDebugDefs USING [ccInfo, cd, UpdateConstDest], CGenDebugGlobalDefs USING [ AllocatorbaseOffset, AllocatortopOffset, CodecodeptrOffset, CodecurctxlvlOffset, CodeframeszOffset, CodestkingOffset, CodetempcontextOffset, CodetempstartOffset, ComDatabodyIndexOffset, ComDatasourceFileOffset, ComDatatextIndexOffset, ConstructorcdOffset, DrivercodestartOffset, ExpressionrecentExpOffset, FinalccInfoOffset, FlowlabelStackOffset, StackImplstkHeadOffset, StackImplstkPtrOffset, StatementrecentStmtOffset, TempheapListOffset, TemppendTempListOffset], CodeDefs USING [ CCIndex, CCInfoType, ConsDestination, LabelInfoIndex, StackIndex, StackItem, StackNull], ControlDefs USING [GlobalFrameHandle], DebugUsefulDefs USING [Enumerate, Name, ShortCopyREAD, ShortREAD, window], Event USING [AddNotifier, Item, Masks, Notifier], IODefs USING [ControlZ, CR], OpCodeParams USING [GlobalBase, GlobalLoadSlots, LocalBase, LocalLoadSlots], Process USING [Detach, Yield], RESOut USING [ cancelAction, Complain, PChar, PCr, PNext, PNextUnsigned, POctal, PString, PUnsigned], SegmentDefs USING [FileNameError], StreamDefs USING [ GetIndex, ModifyIndex, NewByteStream, NormalizeIndex, Read, SetIndex, StreamHandle, StreamIndex], StringDefs USING [AppendChar, AppendDecimal, AppendString, CompareStrings], Symbols USING [ BitAddress, ContextLevel, CTXRecord, ctxType, ISEIndex, ISENull, lG, lZ, SERecord, seType], Storage USING [String, FreeString], Table USING [Base, chunkType, Selector], UserInput USING [ CancelPeriodicNotify, CreatePeriodicNotify, PeriodicNotifyHandle, PeriodicProcType]; CGenDebugGlobals: PROGRAM IMPORTS CGenDebugDefs, DebugUsefulDefs, Event, Process, RESOut, SegmentDefs, StreamDefs, StringDefs, Storage, UserInput EXPORTS CGenDebugDefs, AllocDebugDefs = BEGIN OPEN CodeDefs, DebugUsefulDefs, RESOut, CGenDebugDefs, CGenDebugGlobalDefs; basesValid: BOOLEAN ← FALSE; al: POINTER ← NIL; constructor: POINTER ← NIL; CPtr: POINTER ← NIL; driver: POINTER ← NIL; expression: POINTER ← NIL; final: POINTER ← NIL; flow: POINTER ← NIL; MPtr: POINTER ← NIL; stack: POINTER ← NIL; statement: POINTER ← NIL; temp: POINTER ← NIL; StackBottom: PUBLIC PROCEDURE RETURNS [StackIndex] = BEGIN OPEN CodeDefs; sHead: StackIndex; sir: StackItem; cb: Table.Base = TableBase[]; IF stack = NIL THEN BEGIN RESOut.Complain["Base of StackImpl unknown"L]; ERROR cancelAction; END; sHead ← ShortREAD[stack+StackImplstkHeadOffset]; IF sHead = StackNull THEN RETURN [StackNull]; ShortCopyREAD[to: @sir, from: @cb[sHead], nwords: SIZE[StackItem]]; RETURN [sir.uplink]; END; StackState: PUBLIC PROCEDURE RETURNS [BOOLEAN] = BEGIN IF stack = NIL THEN BEGIN RESOut.Complain["Base of StackImpl unknown"L]; ERROR cancelAction; END; RETURN [ShortREAD[CPtr+CodestkingOffset]]; END; StackTop: PUBLIC PROCEDURE RETURNS [StackIndex] = BEGIN OPEN CodeDefs; IF stack = NIL THEN BEGIN RESOut.Complain["Base of StackImpl unknown"L]; ERROR cancelAction; END; RETURN [ShortREAD[stack+StackImplstkPtrOffset]]; END; PutTempState: PUBLIC PROCEDURE = BEGIN OPEN Symbols; seb: Table.Base = TableBase[seType]; ser: id SERecord; name: STRING ← [20]; ShowList: PROCEDURE [sei: ISEIndex, heading: STRING] = BEGIN first: BOOLEAN ← TRUE; IF sei = ISENull THEN RETURN; PCr[]; PString[" "L]; PString[heading]; PString[": {"L]; WHILE sei # ISENull DO ShortCopyREAD[to: @ser, from: @seb[sei], nwords: SIZE[id SERecord]]; GetVarName[name, sei]; IF first THEN PString[name] ELSE PNext[name,,6]; first ← FALSE; WITH ser SELECT FROM linked => sei ← link; ENDCASE => sei ← ISENull; ENDLOOP; PChar['}]; END; IF temp = NIL THEN BEGIN RESOut.Complain["Base of Temp unknown"L]; ERROR cancelAction; END; PCr[]; PString["Temp ctx: "L]; PUnsigned[ShortREAD[CPtr+CodetempcontextOffset]]; PNextUnsigned["start"L, ShortREAD[CPtr+CodetempstartOffset]]; PNextUnsigned["framesz"L, ShortREAD[CPtr+CodeframeszOffset]]; ShowList[ShortREAD[temp+TemppendTempListOffset], "Pending"L]; ShowList[ShortREAD[temp+TempheapListOffset], "Heap"L]; END; GetVarName: PROCEDURE [s: STRING, sei: Symbols.ISEIndex] = BEGIN OPEN StringDefs, Symbols; ctxb: Table.Base = TableBase[ctxType]; seb: Table.Base = TableBase[seType]; ser: id SERecord; ctr: CTXRecord; addr: BitAddress; ShortCopyREAD[to: @ser, from: @seb[sei], nwords: SIZE [id SERecord]]; ShortCopyREAD[to: @ctr, from: @ctxb[ser.idCtx], nwords: SIZE[CTXRecord]]; addr ← ser.idValue; s.length ← 0; GetFrameName[s, addr.wd, ctr.level, CARDINAL[ser.idInfo+AltoDefs.wordlength-1]/AltoDefs.wordlength]; END; GetFrameName: PUBLIC PROCEDURE [s: STRING, wd: CARDINAL, level: Symbols.ContextLevel, wSize: CARDINAL] = BEGIN OPEN StringDefs, Symbols; curlvl: ContextLevel = CurContext[]; levadj: STRING ← [10]; SELECT level FROM lZ => AppendString[s, "Field "L]; lG => AppendChar[s, 'G]; curlvl => AppendChar[s, 'L]; ENDCASE => BEGIN AppendChar[s, 'L]; AppendString[levadj,"(up "L]; AppendDecimal[levadj, curlvl-level]; AppendChar[levadj,')]; END; SELECT level FROM lZ => NULL; lG => IF wd IN OpCodeParams.GlobalLoadSlots THEN wd ← wd - OpCodeParams.GlobalBase ELSE AppendString[s, "B "L]; ENDCASE => IF wd IN OpCodeParams.LocalLoadSlots THEN wd ← wd - OpCodeParams.LocalBase ELSE AppendString[s, "B "L]; AppendDecimal[s, wd]; IF wSize > 1 THEN BEGIN AppendString[s, ".."L]; AppendDecimal[s, wd + wSize - 1]; END; AppendString[s, levadj]; END; TableBase: PUBLIC PROCEDURE [table: Table.Selector ← Table.chunkType] RETURNS [Table.Base] = BEGIN base: DESCRIPTOR FOR ARRAY Table.Selector OF Table.Base; IF al = NIL THEN BEGIN RESOut.Complain["Base of Allocator unknown"L]; ERROR cancelAction; END; ShortCopyREAD[to: @base, from: al+AllocatorbaseOffset, nwords: SIZE[DESCRIPTOR FOR ARRAY Table.Selector OF Table.Base]]; RETURN [ShortREAD[@base[table]]]; END; TableSize: PUBLIC PROCEDURE [table: Table.Selector ← Table.chunkType] RETURNS [CARDINAL] = BEGIN top: DESCRIPTOR FOR ARRAY Table.Selector OF CARDINAL; IF al = NIL THEN BEGIN RESOut.Complain["Base of Allocator unknown"L]; ERROR cancelAction; END; DebugUsefulDefs.ShortCopyREAD[to: @top, from: al+AllocatortopOffset, nwords: SIZE[DESCRIPTOR FOR ARRAY Table.Selector OF CARDINAL]]; RETURN [ShortREAD[@top[table]]]; END; -- following two procedures should be called from StringDefs -- whenever CompareStrings gets fixed UpperCase: PROCEDURE [c: CHARACTER] RETURNS [CHARACTER] = BEGIN IF c IN ['a..'z] THEN c ← c + ('A-'a); RETURN[c] END; nMods: CARDINAL = 11; LookForFrames: PROCEDURE = BEGIN moduleName: ARRAY [0..nMods) OF STRING ← [ "Allocator"L, "Code"L, "ComData"L, "Constructor"L, "Driver"L, "Expression"L, "Final"L, "Flow"L, "StackImpl"L, "Statement"L, "Temp"L]; basePtr: ARRAY [0..nMods) OF POINTER ← [ @al, @CPtr, @MPtr, @constructor, @driver, @expression, @final, @flow, @stack, @statement, @temp]; keyString: STRING = [40]; firstOut: BOOLEAN ← TRUE; i, nFound: CARDINAL; CheckOneFrame: PROCEDURE [han: ControlDefs.GlobalFrameHandle] RETURNS [BOOLEAN] = BEGIN l, u, i: CARDINAL; 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]; l ← 0; u ← nMods-1; WHILE l <= u DO i ← (l+u)/2; SELECT StringDefs.CompareStrings[key, name[i], FALSE] FROM < 0 => u ← i-1; > 0 => l ← i+1; ENDCASE => BEGIN IF base[i]↑ = NIL THEN BEGIN base[i]↑ ← han; nFound ← nFound + 1 END ELSE BEGIN IF firstOut THEN BEGIN firstOut ← FALSE; RESOut.Complain["Duplicate: "L]; END ELSE RESOut.Complain[", "L, FALSE]; RESOut.Complain[key, FALSE]; END; EXIT END; ENDLOOP; Process.Yield[]; RETURN[nFound = nMods]; END; FOR i IN [0..nMods) DO basePtr[i]↑ ← NIL; ENDLOOP; nFound ← 0; [] ← DebugUsefulDefs.Enumerate[CheckOneFrame]; IF nFound # nMods THEN BEGIN IF ~firstOut THEN RESOut.Complain[", "L, FALSE]; RESOut.Complain["Missing: "L, ~firstOut]; firstOut ← TRUE; FOR i IN [0..nMods) DO IF basePtr[i]↑ = NIL THEN BEGIN IF firstOut THEN firstOut ← FALSE ELSE RESOut.Complain[", "L, FALSE]; RESOut.Complain[moduleName[i], FALSE]; END; ENDLOOP; END; CopyGlobalData[]; END; FindFrames: PUBLIC PROCEDURE = BEGIN END; CurContext: PUBLIC PROCEDURE RETURNS [Symbols.ContextLevel] = BEGIN IF CPtr = NIL THEN BEGIN RESOut.Complain["Base of Code unknown"L]; ERROR cancelAction; END; RETURN [ShortREAD[CPtr+CodecurctxlvlOffset]]; END; CCCur: PUBLIC PROCEDURE RETURNS [CodeDefs.CCIndex] = BEGIN IF CPtr = NIL THEN BEGIN RESOut.Complain["Base of Code unknown"L]; ERROR cancelAction; END; RETURN [ShortREAD[CPtr+CodecodeptrOffset]]; END; CCFirst: PUBLIC PROCEDURE RETURNS [CodeDefs.CCIndex] = BEGIN IF driver = NIL THEN BEGIN RESOut.Complain["Base of Driver unknown"L]; ERROR cancelAction; END; RETURN [ShortREAD[driver+DrivercodestartOffset]]; END; LabelStack: PUBLIC PROCEDURE RETURNS [CodeDefs.LabelInfoIndex] = BEGIN IF flow = NIL THEN BEGIN RESOut.Complain["Base of Driver unknown"L]; ERROR cancelAction; END; RETURN [ShortREAD[flow+FlowlabelStackOffset]]; END; PutCurrentBody: PUBLIC PROCEDURE = BEGIN IF MPtr = NIL THEN BEGIN RESOut.Complain["Base of ComData unknown"L]; ERROR cancelAction; END; PCr[]; PString["Current body bti = "L]; PUnsigned[ShortREAD[MPtr+ComDatabodyIndexOffset]]; END; PutCurrentSource: PUBLIC PROCEDURE = BEGIN index: CARDINAL; IF sourceName # NIL THEN Storage.FreeString[sourceName]; IF MPtr = NIL THEN BEGIN RESOut.Complain["Base of ComData unknown"L]; ERROR cancelAction; END; sourceName ← CopyUserString[ShortREAD[MPtr+ComDatasourceFileOffset]]; index ← ShortREAD[MPtr+ComDatatextIndexOffset]; PCr[]; PString["Current source: "L]; PString[sourceName]; PString[" ["L]; POctal[index]; PChar[']]; IF index # LAST[CARDINAL] THEN BEGIN PCr[]; PrintTextLine[sourceName, index]; END; END; sourceName: STRING ← NIL; firstPrinted, lastPrinted: StreamDefs.StreamIndex ← [0,0]; PrintNextLine: PUBLIC PROCEDURE = BEGIN OPEN StreamDefs, IODefs; in: StreamHandle; ch: CHARACTER; IF sourceName = NIL THEN RETURN; in ← NewByteStream[sourceName, Read ! SegmentDefs.FileNameError => GO TO bad]; SetIndex[in, lastPrinted]; IF in.endof[in] THEN RETURN; ch ← in.get[in]; IF ch = ControlZ THEN WHILE ~in.endof[in] AND in.get[in] # CR DO ENDLOOP; IF in.endof[in] THEN RETURN; PCr[]; firstPrinted ← lastPrinted ← GetIndex[in]; THROUGH [0..80] WHILE ~in.endof[in] DO lastPrinted ← GetIndex[in]; SELECT (ch ← in.get[in]) FROM CR, ControlZ => EXIT; ENDCASE => PChar[ch]; ENDLOOP; EXITS bad => BEGIN RESOut.Complain["Bad File Name"L]; ERROR cancelAction; END; END; PrintPrevLine: PUBLIC PROCEDURE = BEGIN OPEN StreamDefs, IODefs; in: StreamHandle; ch: CHARACTER; again: BOOLEAN; lineIndex: StreamIndex; IF sourceName = NIL OR firstPrinted = [0,0] THEN RETURN; in ← NewByteStream[sourceName, Read ! SegmentDefs.FileNameError => GO TO bad]; lineIndex ← lastPrinted ← firstPrinted ← ModifyIndex[firstPrinted, -1]; again ← TRUE; WHILE again DO again ← FALSE; THROUGH [1..80] UNTIL lineIndex = [0, 0] DO lineIndex ← ModifyIndex[lineIndex, -1]; SetIndex[in, lineIndex]; SELECT in.get[in] FROM CR => EXIT; ControlZ => GO TO skipTrailer; ENDCASE; firstPrinted ← lineIndex; REPEAT skipTrailer => BEGIN lastPrinted ← firstPrinted ← lineIndex; again ← TRUE; END; ENDLOOP; ENDLOOP; PCr[]; SetIndex[in, firstPrinted]; DO SELECT (ch ← in.get[in]) FROM CR, ControlZ => EXIT; ENDCASE => PChar[ch]; IF GetIndex[in] = lastPrinted THEN EXIT; ENDLOOP; EXITS bad => BEGIN RESOut.Complain["Bad File Name"L]; ERROR cancelAction; END; END; PrintTextLine: PROCEDURE [source: STRING, i: CARDINAL] = BEGIN OPEN StreamDefs, IODefs; in: StreamHandle; start, lineIndex, mark: StreamIndex; char: CHARACTER; n: [1..100]; in ← NewByteStream[source, Read ! SegmentDefs.FileNameError => GO TO bad]; start ← lineIndex ← mark ← NormalizeIndex[[page:0, byte:i]]; FOR n IN [1..40] UNTIL lineIndex = [0, 0] DO lineIndex ← ModifyIndex[lineIndex, -1]; SetIndex[in, lineIndex]; IF in.get[in] = CR THEN EXIT; start ← lineIndex; ENDLOOP; firstPrinted ← lastPrinted ← start; SetIndex[in, start]; FOR n IN [1..80] WHILE ~in.endof[in] DO IF GetIndex[in] = mark THEN PString["<>"L]; lastPrinted ← GetIndex[in]; SELECT (char ← in.get[in]) FROM CR, ControlZ => EXIT; ENDCASE => PChar[char]; ENDLOOP; in.destroy[in]; EXITS bad => BEGIN RESOut.Complain["Bad File Name"L]; ERROR cancelAction; END; END; CopyUserString: PRIVATE PROCEDURE [us: STRING] RETURNS [s: STRING] = BEGIN sb: StringBody; IF us = NIL THEN GO TO bad; ShortCopyREAD[to: @sb, from: us, nwords: SIZE[StringBody]]; IF sb.length > 40 THEN GO TO bad; s ← Storage.String[sb.length]; ShortCopyREAD[to: @s.text, from: @us.text, nwords: (sb.length+1)/2]; s.length ← sb.length; EXITS bad => BEGIN RESOut.Complain["Bad String"L]; ERROR cancelAction; END; END; PutCurrentStmt: PUBLIC PROCEDURE = BEGIN IF statement = NIL THEN BEGIN RESOut.Complain["Base of Statement unknown"L]; ERROR cancelAction; END; PCr[]; PString["Current stmt tree = "L]; PUnsigned[ShortREAD[statement+StatementrecentStmtOffset]]; END; PutCurrentExpr: PUBLIC PROCEDURE = BEGIN IF expression = NIL THEN BEGIN RESOut.Complain["Base of Expression unknown"L]; ERROR cancelAction; END; PCr[]; PString["Current expr tree = "L]; PUnsigned[ShortREAD[expression+ExpressionrecentExpOffset]]; END; CopyGlobalData: PROCEDURE = BEGIN info: CodeDefs.CCInfoType ← generating; IF final # NIL THEN info ← ShortREAD[final+FinalccInfoOffset]; CGenDebugDefs.ccInfo ← IF info IN CodeDefs.CCInfoType THEN info ELSE generating; IF constructor # NIL THEN BEGIN ShortCopyREAD[to: @CGenDebugDefs.cd, from: constructor+ConstructorcdOffset, nwords: SIZE[CodeDefs.ConsDestination]]; UpdateConstDest[]; END; END; LookupTheFrames: UserInput.PeriodicProcType = BEGIN periodic ← UserInput.CancelPeriodicNotify[periodic]; Process.Detach[FORK LookForFrames[]]; END; periodic: UserInput.PeriodicNotifyHandle ← UserInput.CreatePeriodicNotify[LookupTheFrames, DebugUsefulDefs.window, 1]; Notify: Event.Notifier = BEGIN SELECT why FROM newSession => IF periodic = NIL THEN periodic ← UserInput.CreatePeriodicNotify[LookupTheFrames, DebugUsefulDefs.window, 1]; resumeSession => CopyGlobalData[]; ENDCASE; SELECT why FROM newSession, resumeSession => BEGIN firstPrinted ← lastPrinted ← [0,0]; IF sourceName # NIL THEN Storage.FreeString[sourceName]; sourceName ← NIL; END; ENDCASE; END; notifierItem: Event.Item ← [ eventMask: Event.Masks[newSession] + Event.Masks[resumeSession], eventProc: Notify]; Event.AddNotifier[@notifierItem]; END.