<> <> <> <> DIRECTORY AMModel USING [Context, ContextSection, MostRecentNamedContext, ParentSection, RootContext, Section, SectionChildren, SectionClass, SectionName, SectionSource, Source, SourceObj, SourceSection], AMModelLocation USING [CodeLocation, EntryLocations, ExitLocations], BcdDefs USING [NullVersion], FastBreak USING [ClearFastBreak, FastBreakData, FastBreakId, FastBreakProc, SetFastBreak], IO USING [ROS, Put, PutF, STREAM, RopeFromROS], PrincOps USING [BytePC, FrameCodeBase], Rope USING [Cat, Equal, Find, Length, ROPE, Substr], SpyClient USING [], -- for export SpyLog USING [active, WriteTrace], SpyOps USING [active, AllocationBreak, StackType, StartCounting, StopCounting, starts, stops, UserBreak, watching], WorldVM USING [LocalWorld]; SpyBreaksImpl: MONITOR IMPORTS AMModel, AMModelLocation, FastBreak, IO, Rope, SpyLog, SpyOps, WorldVM EXPORTS SpyClient, SpyOps = { ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; <<************************************************************>> <> <<************************************************************>> breakList: LIST OF Break _ NIL; totalStarts, totalStops: INTEGER _ 0; StartSpy: PUBLIC PROC = { SpyOps.starts _ SpyOps.stops _ 0; IF breakList = NIL THEN [] _ SpyOps.StartCounting[NIL, NIL, NIL]; }; StopSpy: PUBLIC PROC = { totalStarts _ SpyOps.starts; totalStops _ SpyOps.stops; WHILE SpyOps.active > 0 DO [] _ SpyOps.StopCounting[NIL, NIL, NIL]; ENDLOOP; ClearAllocationBreak[]; }; ClearBreaks: PUBLIC PROC = { FOR breakList _ breakList, breakList.rest DO IF breakList = NIL THEN EXIT; [] _ ClearSingleBreak[breakList.first]; ENDLOOP; }; SetSingleBreak: PROC [code: LONG POINTER, pc: PrincOps.BytePC, proc: FastBreak.FastBreakProc, data: FastBreak.FastBreakData] RETURNS [break: Break] = { break _ NEW[BreakRec _ [pc: pc, condProc: proc, data: data, breakData: data]]; break.index _ FastBreak.SetFastBreak[code, pc, proc, data]; IF break.index = NIL THEN RETURN [NIL]; }; ClearSingleBreak: PROC [break: Break] RETURNS [ok: BOOL] = { ok _ FastBreak.ClearFastBreak[break.index, break.condProc, break.breakData]; }; SetStartBreak: PUBLIC PROC[section: AMModel.Section, procedure: ROPE, sourceIndex: INT] RETURNS[ok: BOOLEAN, msg: ROPE] = { breakId: Break; output: STREAM; IF section = NIL AND procedure = NIL THEN RETURN[FALSE, "no parameter given."]; IF section = NIL THEN section _ SectionFromName[procedure, sourceIndex]; IF section = NIL THEN RETURN[FALSE, Rope.Cat["Could not set break on ", procedure, "."]]; breakId _ SetBreak[section, SpyOps.StartCounting]; IF breakId = NIL THEN RETURN[FALSE, "Could not set break."]; breakList _ CONS[breakId, breakList]; output _ IO.ROS[]; output.Put[[rope["Set Start Break "]]]; PrintBreak[output, breakId]; output.Put[[character['.]]]; msg _ IO.RopeFromROS[output]; RETURN[TRUE, msg]; }; SetStopBreak: PUBLIC PROC[section: AMModel.Section, procedure: ROPE, sourceIndex: INT] RETURNS[ok: BOOLEAN, msg: ROPE] = { breakId: Break; output: STREAM; IF section = NIL AND procedure = NIL THEN RETURN[FALSE, "no parameter given."]; IF section = NIL THEN section _ SectionFromName[procedure, sourceIndex]; IF section = NIL THEN RETURN[FALSE, Rope.Cat["Could not set break on ", procedure, "."]]; breakId _ SetBreak[section: section, condProc: SpyOps.StopCounting, exitIfEntry: TRUE]; IF breakId = NIL THEN RETURN[FALSE, "Could not set break."]; breakList _ CONS[breakId, breakList]; output _ IO.ROS[]; output.Put[[rope["Set Stop Break "]]]; PrintBreak[output, breakId]; output.Put[[character['.]]]; msg _ IO.RopeFromROS[output]; RETURN[TRUE, msg]; }; <<************************************************************>> <> <<************************************************************>> traceList: LIST OF Break _ NIL; userBreakList: LIST OF Break _ NIL; allocationBreakList: LIST OF Break; SetAllocationBreak: PUBLIC PROC RETURNS[msg: Rope.ROPE _ NIL] = { proc: AMModel.Section; IF allocationBreakList # NIL THEN RETURN; <> proc _ SectionFromName["AllocatorImpl.NewSystemObject"]; IF proc = NIL THEN {ClearAllocationBreak[]; RETURN["Could not set break on AllocatorImpl.NewSystemObject."]}; allocationBreakList _ CONS[SetBreak[proc, SpyOps.AllocationBreak], allocationBreakList]; <> proc _ SectionFromName["AllocatorImpl.NewPermanentObject"]; IF proc = NIL THEN {ClearAllocationBreak[]; RETURN["Could not set break on AllocatorImpl.NewPermanentObject."]}; allocationBreakList _ CONS[SetBreak[section: proc, condProc: SpyOps.AllocationBreak, data: $Permanent], allocationBreakList]; <> proc _ SectionFromName["AllocatorImpl.NewHeapObject"]; IF proc = NIL THEN {ClearAllocationBreak[]; RETURN["Could not set break on AllocatorImpl.NewHeapObject."]}; allocationBreakList _ CONS[SetBreak[section: proc, condProc: SpyOps.AllocationBreak, data: $Unsafe], allocationBreakList]; }; ClearAllocationBreak: PUBLIC PROC = { FOR allocationBreakList _ allocationBreakList, allocationBreakList.rest WHILE allocationBreakList # NIL DO IF ~ClearSingleBreak[allocationBreakList.first] THEN ERROR; ENDLOOP; }; SetUserBreak: PUBLIC PROC[section: AMModel.Section, type: SpyOps.StackType, procedure: ROPE, sourceIndex: INT] RETURNS[ok: BOOLEAN, msg: ROPE] = { breakId: Break; output: STREAM; IF section = NIL AND procedure = NIL THEN RETURN[FALSE, "no parameter given."]; IF section = NIL THEN section _ SectionFromName[procedure, sourceIndex]; IF section = NIL THEN RETURN[FALSE, Rope.Cat["Could not set break on ", procedure, "."]]; breakId _ SetBreak[section: section, condProc: SpyOps.UserBreak, type: type]; IF breakId = NIL THEN RETURN[FALSE, "Could not set break."]; userBreakList _ CONS[breakId, userBreakList]; output _ IO.ROS[]; output.Put[[rope["Set User Break "]]]; PrintBreak[output, breakId]; output.Put[[character['.]]]; msg _ IO.RopeFromROS[output]; RETURN[TRUE, msg]; }; SetTrace: PUBLIC PROC[section: AMModel.Section, procedure: Rope.ROPE, sourceIndex: INT] RETURNS[ok: BOOLEAN, msg: ROPE] = { breakId: Break; output: STREAM; IF section = NIL AND procedure = NIL THEN RETURN[FALSE, "no parameter given."]; IF section = NIL THEN section _ SectionFromName[procedure, sourceIndex]; IF section = NIL THEN RETURN[FALSE, Rope.Cat["Could not set break on ", procedure, "."]]; breakId _ SetBreak[section, TraceExecution]; IF breakId = NIL THEN RETURN[FALSE, "Could not set break."]; traceList _ CONS[breakId, traceList]; output _ IO.ROS[]; output.Put[[rope["Set Trace "]]]; PrintBreak[output, breakId]; output.Put[[rope[" [pc: "]], [cardinal[breakId.pc]], [rope["]"]]]; output.Put[[character['.]]]; msg _ IO.RopeFromROS[output]; RETURN[TRUE, msg]; }; TraceExecution: FastBreak.FastBreakProc = { <> IF SpyOps.watching # userDefined THEN RETURN; IF SpyOps.active = 0 THEN RETURN; IF ~SpyLog.active THEN RETURN; SpyLog.WriteTrace[frame.accesslink, frame.pc]; }; ClearUserBreaks: PUBLIC PROC = { FOR userBreakList _ userBreakList, userBreakList.rest WHILE userBreakList # NIL DO [] _ ClearSingleBreak[userBreakList.first]; ENDLOOP; FOR traceList _ traceList, traceList.rest WHILE traceList # NIL DO IF traceList = NIL THEN EXIT; [] _ ClearSingleBreak[traceList.first]; ENDLOOP; }; <<>> <<************************************************************>> <> <<************************************************************>> <<>> Break: TYPE = REF BreakRec; BreakRec: TYPE = RECORD[ exit: BOOLEAN _ FALSE, index: FastBreak.FastBreakId _ NIL, condProc: FastBreak.FastBreakProc _ NIL, breakData: FastBreak.FastBreakData _ NIL, data: LONG POINTER _ NIL, type: SpyOps.StackType _ 0, pc: PrincOps.BytePC _ [0], section: AMModel.Section _ NIL]; SetBreak: PROC[section: AMModel.Section, condProc: FastBreak.FastBreakProc, type: SpyOps.StackType _ 0, data: REF _ NIL, exitIfEntry: BOOL _ FALSE] RETURNS[break: Break] = { exit: BOOLEAN _ FALSE; locList: LIST OF AMModelLocation.CodeLocation; SELECT AMModel.SectionClass[section] FROM proc => IF exitIfEntry THEN {locList _ AMModelLocation.ExitLocations[section].list; exit _ TRUE} ELSE locList _ AMModelLocation.EntryLocations[section].list; statement => { locList _ AMModelLocation.EntryLocations[section].list; IF locList = NIL THEN RETURN[NIL]; IF exitIfEntry THEN { -- see if this is an entry statement. If it is, use the exit statement. parent: AMModel.Section; list: LIST OF AMModelLocation.CodeLocation; parent _ AMModel.ParentSection[section]; list _ AMModelLocation.EntryLocations[parent].list; IF list # NIL AND list.first = locList.first THEN {locList _ AMModelLocation.ExitLocations[parent].list; exit _ TRUE}}}; ENDCASE => RETURN[NIL]; IF locList = NIL THEN RETURN[NIL]; IF (break _ SetSingleBreak[LOOPHOLE[locList.first.codeBase], locList.first.pc, condProc, LOOPHOLE[data]]) = NIL THEN RETURN; break.type _ type; IF type # 0 AND data = NIL THEN break.data _ @break.type; -- for user defined types break.section _ section; break.exit _ exit; }; SectionFromName: PROC[name: Rope.ROPE, sourceIndex: INT _ 0] RETURNS[section: AMModel.Section] = { dotIndex: INT; module: AMModel.Section; moduleContext: AMModel.Context; moduleName, procName: Rope.ROPE; FindProcedure: PROC[proc: AMModel.Section] RETURNS[stop: BOOL] = { name: Rope.ROPE _ AMModel.SectionName[proc]; RETURN[Rope.Equal[name, procName]]}; IF sourceIndex # 0 THEN { source: AMModel.Source _ NEW[AMModel.SourceObj _ [name, statement, BcdDefs.NullVersion, field[sourceIndex, sourceIndex]]]; section _ AMModel.SourceSection[source, AMModel.RootContext[WorldVM.LocalWorld[]]].section; RETURN}; dotIndex _ Rope.Find[name, "."]; IF dotIndex < 0 THEN RETURN[NIL]; moduleName _ name.Substr[0, dotIndex]; procName _ name.Substr[dotIndex+1, name.Length[]-dotIndex-1]; moduleContext _ AMModel.MostRecentNamedContext[moduleName, AMModel.RootContext[WorldVM.LocalWorld[]]]; IF moduleContext = NIL THEN RETURN[NIL]; module _ AMModel.ContextSection[moduleContext]; IF module = NIL THEN RETURN[NIL]; section _ AMModel.SectionChildren[module, FindProcedure]; }; PrintBreaks: PUBLIC PROC[typescript: STREAM] ={ first: BOOLEAN _ TRUE; list: LIST OF Break; IF typescript = NIL THEN RETURN; <> IF SpyOps.watching = userDefined OR breakList # NIL THEN typescript.Put[[character['\n]]]; IF SpyOps.watching = userDefined AND userBreakList # NIL 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[[character['.]], [character['\n]]]}; IF SpyOps.watching = userDefined AND traceList # NIL THEN { typescript.Put[[rope["Trace Breaks: "]]]; FOR list _ traceList, list.rest DO IF list = NIL THEN EXIT; IF ~first THEN typescript.Put[[rope[",\n\t "]]]; PrintBreak[typescript, list.first]; typescript.Put[[rope[" [pc: "]], [cardinal[list.first.pc]], [rope["]"]]]; first _ FALSE; ENDLOOP; typescript.Put[[character['.]], [character['\n]]]}; <> 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[[character['\n]]] ELSE typescript.Put[[character['.]], [character['\n]]]; <> 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[[character['\n]]] ELSE typescript.Put[[character['.]], [character['\n]]]; typescript.Put[[integer[totalStarts]], [rope[" start breaks encountered.\n"]]]; typescript.Put[[integer[totalStops]], [rope[" stop breaks encountered.\n"]]]}; }; PrintBreak: PROC[stream: STREAM, break: Break] ={ SELECT AMModel.SectionClass[break.section] FROM proc => {IF break.exit THEN stream.Put[[rope["exit of "]], [rope[AMModel.SectionName[break.section]]]] ELSE stream.Put[[rope["entry of "]], [rope[AMModel.SectionName[break.section]]]]}; statement => { parent: AMModel.Section _ AMModel.ParentSection[break.section]; entry, procEntry: LIST OF AMModelLocation.CodeLocation; IF break.exit THEN {stream.Put[[rope["exit of "]], [rope[AMModel.SectionName[parent]]]]; RETURN}; procEntry _ AMModelLocation.EntryLocations[parent].list; entry _ AMModelLocation.EntryLocations[break.section].list; FOR procEntry _ procEntry, procEntry.rest WHILE procEntry # NIL DO FOR list: LIST OF AMModelLocation.CodeLocation _ entry, list.rest WHILE list # NIL DO IF list.first = procEntry.first THEN { stream.Put[[rope["entry of "]], [rope[AMModel.SectionName[parent]]]]; RETURN}; ENDLOOP; ENDLOOP; PrintSource[stream, break.section, AMModel.SectionName[parent]]}; ENDCASE => PrintSource[stream, break.section, AMModel.SectionName[break.section]]; }; PrintSource: PROC[stream: STREAM, section: AMModel.Section, proc: Rope.ROPE] = { source: AMModel.Source _ AMModel.SectionSource[section]; WITH s: source^ SELECT FROM entire => stream.Put[[rope["somewhere inside of "]], [rope[proc]]]; field => stream.PutF["%g [source: %g]", [rope[proc]], [integer[s.firstCharIndex]]]; ENDCASE => ERROR; }; }..