<> <> DIRECTORY AMBridge USING [GFHFromTV, TVForGFHReferent], AMTypes USING [TV, TVToName], BBObjectLocation USING [ EntryLocation, ExitLocation, GFandPCFromLocation, IsLocationAtLocation, Location, LocationFromGFandPC, TVFromLocation], FastBreak USING [ClearFastBreak, FastBreakId, FastBreakProc, SetFastBreak], IO USING [ char, Close, CR, CreateOutputStreamToRope, GetOutputStreamRope, int, Put, rope, STREAM], PrincOps USING [BytePC, FrameCodeBase, GlobalFrameHandle], Rope USING [ROPE], SpyClient USING [], -- for export SpyOps USING [active, StartCounting, StopCounting, starts, stops, UserBreak, watching]; SpyBreaksImpl: MONITOR IMPORTS AMBridge, AMTypes, BBObjectLocation, FastBreak, IO, SpyOps EXPORTS SpyClient, SpyOps = BEGIN OPEN IO; ROPE: TYPE = Rope.ROPE; <<************************************************************>> <> <<************************************************************>> breakList: LIST OF Break _ NIL; totalStarts, totalStops: INTEGER _ 0; StartSpy: PUBLIC PROCEDURE = BEGIN SpyOps.starts _ SpyOps.stops _ 0; IF breakList = NIL THEN [] _ SpyOps.StartCounting[NIL, NIL, NIL]; END; StopSpy: PUBLIC PROCEDURE = BEGIN totalStarts _ SpyOps.starts; totalStops _ SpyOps.stops; WHILE SpyOps.active > 0 DO [] _ SpyOps.StopCounting[NIL, NIL, NIL]; ENDLOOP; END; ClearBreaks: PUBLIC PROCEDURE = BEGIN FOR breakList _ breakList, breakList.rest DO IF breakList = NIL THEN EXIT; [] _ FastBreak.ClearFastBreak[breakList.first.index]; ENDLOOP; END; SetStartBreak: PUBLIC PROCEDURE[procedure: ROPE, loc: BBObjectLocation.Location] RETURNS[ok: BOOLEAN, msg: ROPE] = BEGIN breakId: Break; output: STREAM _ CreateOutputStreamToRope[]; IF loc = NIL THEN { ok _ FALSE; IF procedure # NIL THEN output.Put[rope["Please use 'loc' parameter."]] ELSE output.Put[rope["Could not set break."]]} ELSE { ok _ TRUE; breakId _ SetBreak[loc, SpyOps.StartCounting]; IF breakId = NIL THEN RETURN[FALSE, "Could not set break."]; breakList _ CONS[breakId, breakList]; output.Put[rope["Set Start Break "]]; PrintBreak[output, breakId]; output.Put[char['.]]}; msg _ GetOutputStreamRope[output]; output.Close[]; END; SetStopBreak: PUBLIC PROCEDURE[procedure: ROPE, loc: BBObjectLocation.Location] RETURNS[ok: BOOLEAN, msg: ROPE] = BEGIN OPEN BBObjectLocation; breakId: Break; output: STREAM _ CreateOutputStreamToRope[]; IF loc = NIL THEN { ok _ FALSE; IF procedure # NIL THEN output.Put[rope["Please use 'loc' parameter."]] ELSE output.Put[rope["Could not set break."]]} ELSE { ok _ TRUE; IF IsLocationAtLocation[loc, EntryLocation[loc]] THEN loc _ ExitLocation[loc]; breakId _ SetBreak[loc, SpyOps.StopCounting]; IF breakId = NIL THEN RETURN[FALSE, "Could not set break."]; breakList _ CONS[breakId, breakList]; output.Put[rope["Set Stop Break "]]; PrintBreak[output, breakId]; output.Put[char['.]]}; msg _ GetOutputStreamRope[output]; output.Close[]; END; <<************************************************************>> <> <<************************************************************>> userBreakList: LIST OF Break _ NIL; SetUserBreak: PUBLIC PROCEDURE[procedure: ROPE, loc: BBObjectLocation.Location] RETURNS[ok: BOOLEAN, msg: ROPE] = BEGIN breakId: Break; output: STREAM _ CreateOutputStreamToRope[]; IF loc = NIL THEN { ok _ FALSE; IF procedure # NIL THEN output.Put[rope["Please use 'loc' parameter."]] ELSE output.Put[rope["Could not set break."]]} ELSE { ok _ TRUE; breakId _ SetBreak[loc, SpyOps.UserBreak]; IF breakId = NIL THEN RETURN[FALSE, "Could not set break."]; userBreakList _ CONS[breakId, userBreakList]; output.Put[rope["Set User Break "]]; PrintBreak[output, breakId]; output.Put[char['.]]}; msg _ GetOutputStreamRope[output]; output.Close[]; END; ClearUserBreaks: PUBLIC PROCEDURE = BEGIN FOR userBreakList _ userBreakList, userBreakList.rest DO IF userBreakList = NIL THEN EXIT; [] _ FastBreak.ClearFastBreak[userBreakList.first.index]; ENDLOOP; END; <<>> <<************************************************************>> <> <<************************************************************>> <<>> Break: TYPE = REF BreakRec; BreakRec: TYPE = RECORD[ index: FastBreak.FastBreakId _ NIL, condProc: FastBreak.FastBreakProc _ NIL, loc: BBObjectLocation.Location _ NIL]; SetBreak: PROC[loc: BBObjectLocation.Location, condProc: FastBreak.FastBreakProc] RETURNS[break: Break] = BEGIN gf: AMTypes.TV; pc: PrincOps.BytePC; code: PrincOps.FrameCodeBase; gfh: PrincOps.GlobalFrameHandle; [gf, pc] _ BBObjectLocation.GFandPCFromLocation[loc]; IF gf = NIL OR pc = 0 THEN RETURN[NIL]; gfh _ AMBridge.GFHFromTV[gf]; code _ gfh.code; code.out _ FALSE; break _ NEW[BreakRec _ []]; break.index _ FastBreak.SetFastBreak[LOOPHOLE[code], pc, condProc]; IF break.index = NIL THEN RETURN[NIL]; break.condProc _ condProc; break.loc _ loc; END; PrintBreaks: PUBLIC PROCEDURE[typescript: IO.STREAM] = BEGIN first: BOOLEAN _ TRUE; list: LIST OF Break; IF typescript = NIL THEN RETURN; <> IF SpyOps.watching = userDefined OR breakList # NIL THEN typescript.Put[char[CR]]; IF SpyOps.watching = userDefined THEN { typescript.Put[rope["User Breaks: "]]; FOR list _ userBreakList, list.rest DO IF list = NIL THEN EXIT; IF ~first THEN typescript.Put[rope[", "]]; PrintBreak[typescript, list.first]; first _ FALSE; ENDLOOP; typescript.Put[char['.], char[CR]]}; <> IF breakList # NIL THEN { first _ TRUE; typescript.Put[rope["Start Breaks: "]]; FOR list _ breakList, list.rest DO IF list = NIL THEN EXIT; IF list.first.condProc # SpyOps.StartCounting THEN LOOP; IF ~first THEN typescript.Put[rope[", "]]; PrintBreak[typescript, list.first]; first _ FALSE; ENDLOOP; IF first THEN typescript.Put[char[CR]] ELSE typescript.Put[char['.], char[CR]]; <> first _ TRUE; typescript.Put[rope["Stop Breaks: "]]; FOR list _ breakList, list.rest DO IF list = NIL THEN EXIT; IF list.first.condProc # SpyOps.StopCounting THEN LOOP; IF ~first THEN typescript.Put[rope[", "]]; PrintBreak[typescript, list.first]; first _ FALSE; ENDLOOP; IF first THEN typescript.Put[char[CR]] ELSE typescript.Put[char['.], char[CR]]; typescript.Put[int[totalStarts], rope[" start breaks encountered.\n"]]; typescript.Put[int[totalStops], rope[" stop breaks encountered.\n"]]}; END; PrintBreak: PROCEDURE[stream: IO.STREAM, break: Break] = BEGIN OPEN BBObjectLocation; < stream.Put[rope["exit of "]]; ENDCASE => stream.Put[rope["inside of "]]; stream.Put[rope[AMTypes.TVToName[TVFromLocation[break.loc]]]]; END; ManualSetBreak: PROCEDURE[gf, pc: CARDINAL] RETURNS[ROPE] = BEGIN loc: BBObjectLocation.Location; loc _ LocationFromGFandPC[LOOPHOLE[gf], [pc]]; IF loc = NIL THEN RETURN["no location"]; RETURN[SetUserBreak[NIL, loc].msg]; END; LocationFromGFandPC: PROCEDURE[gf: PrincOps.GlobalFrameHandle, pc: PrincOps.BytePC] RETURNS[BBObjectLocation.Location] = INLINE {RETURN[BBObjectLocation.LocationFromGFandPC[AMBridge.TVForGFHReferent[gf], pc]]}; END.. sensitiveBreaks: LIST OF BreakRecord _ NIL; BreakRecord: TYPE = RECORD[ loc: BBObjectLocation.Location, id: BBObjectLocation.BreakpointId]; loc: ARRAY [0..3] OF RECORD[gf, pc: CARDINAL] _ ALL[[0, 0]]; spaceImplA: PrincOps.GlobalFrameHandle _ LOOPHOLE[25300B]; createAny: PrincOps.BytePC _ [12712B]; deleteAny: PrincOps.BytePC _ [14762B]; ClearSensitiveBreaks: PROCEDURE = BEGIN FOR sensitiveBreaks _ sensitiveBreaks, sensitiveBreaks.rest DO IF sensitiveBreaks = NIL THEN EXIT; [] _ BBObjectLocation.ClearBreakpoint[sensitiveBreaks.first.loc, sensitiveBreaks.first.id]; ENDLOOP; END; SetSensitiveBreak: PUBLIC PROCEDURE[type: SpyClient.DataType] RETURNS[msg: ROPE] = BEGIN ok: BOOLEAN _ TRUE; SetBreak: PROCEDURE[loc: BBObjectLocation.Location] = BEGIN break: BreakRecord; IF loc = NIL THEN ok _ FALSE; IF ok = FALSE THEN RETURN; break.loc _ loc; break.id _ BBObjectLocation.SetBreakpoint[loc, SensitiveBreak]; sensitiveBreaks _ CONS[break, sensitiveBreaks]; END; ClearSensitiveBreaks[]; <> IF TRUE THEN RETURN["Not implemented."]; SELECT TRUE FROM loc[0] # [0, 0] => { -- wizard-defined breaks FOR i: CARDINAL IN [0..3] DO IF ok = FALSE THEN EXIT; IF loc[i] = [0, 0] THEN EXIT; SetBreak[LocationFromGFandPC[LOOPHOLE[loc[i].gf], [loc[i].pc]]]; ENDLOOP; IF ~ok THEN msg _ "Could not set wizard-defined breaks."}; type = wordsAllocated OR type = allocations => { SetBreak[LocationFromName["RTAllocatorImpl.NewQuantizedObject"]]; SetBreak[LocationFromName["RTPrefAllocImpl.NewPrefixedObject"]]; IF ~ok THEN msg _ "Please get RTAllocatorImpl.bcd and RTPrefAllocImpl.bcd from [indigo]Runtime>."}; type = spaces => { SetBreak[LocationFromGFandPC[spaceImplA, createAny]]; SetBreak[LocationFromGFandPC[spaceImplA, deleteAny]]; IF ~ok THEN msg _ "Could not set space allocation breaks."}; ENDCASE; IF ~ok THEN ClearSensitiveBreaks[]; END; SensitiveBreak: ENTRY BBObjectLocation.BreakpointHandler = TRUSTED BEGIN count: CARDINAL _ 1; Parameters: TYPE = RECORD[ zone: ZONE, size: CARDINAL, filler: ARRAY [0..11) OF CARDINAL]; IF SpyOps.spyState # on THEN RETURN; IF SpyOps.watching NOT IN [allocations..spaces] THEN RETURN; <> <> END; LocationFromName: PROCEDURE[name: ROPE] RETURNS[loc: BBObjectLocation.Location _ NIL] = BEGIN OPEN BBObjectLocation; tv: AMTypes.TV _ NIL; module, proc: ROPE _ NIL; <> <> [module, proc] _ Split[name]; IF module = NIL OR proc = NIL THEN RETURN[NIL]; tv _ BBContext.GlobalFrameSearch[NIL, module, proc].tv; IF tv # NIL THEN { loc: Location _ TVToLocation[tv ! ANY => GO TO oops]; RETURN[loc]}; EXITS oops => RETURN[NIL]; END; Split: PROC [name: ROPE] RETURNS [Rope.Text, Rope.Text] = BEGIN length: INT _ name.Length[]; pos: INT _ name.Index[0, "."]; IF pos = length THEN RETURN[NIL, NIL]; RETURN[name.Flatten[0, pos], name.Flatten[pos + 1, length]]; END;