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 [Put, PutF, PutRope, RopeFromROS, ROS, STREAM], 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, starts, StopCounting, stops, UserBreak, watching], WorldVM USING [LocalWorld]; SpyBreaksImpl: MONITOR IMPORTS AMModel, AMModelLocation, FastBreak, IO, Rope, SpyLog, SpyOps, WorldVM EXPORTS SpyClient, SpyOps = { ROPE: TYPE = Rope.ROPE; Section: TYPE = AMModel.Section; 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: Section, procedure: ROPE, sourceIndex: INT] RETURNS [ok: BOOL, 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: Section, procedure: ROPE, sourceIndex: INT] RETURNS [ok: BOOL, 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 _ NIL] = { proc: 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[section: proc, condProc: SpyOps.AllocationBreak, exitIfEntry: TRUE], 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, exitIfEntry: TRUE], 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, exitIfEntry: TRUE], allocationBreakList]; }; ClearAllocationBreak: PUBLIC PROC = { FOR allocationBreakList _ allocationBreakList, allocationBreakList.rest WHILE allocationBreakList # NIL DO IF ~ClearSingleBreak[allocationBreakList.first] THEN ERROR; ENDLOOP; }; SetUserBreak: PUBLIC PROC [section: Section, type: SpyOps.StackType, procedure: ROPE, sourceIndex: INT] RETURNS [ok: BOOL, 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: Section, procedure: ROPE, sourceIndex: INT] RETURNS [ok: BOOL, 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: BOOL _ FALSE, index: FastBreak.FastBreakId _ NIL, condProc: FastBreak.FastBreakProc _ NIL, breakData: FastBreak.FastBreakData _ NIL, data: LONG POINTER _ NIL, type: SpyOps.StackType _ ready, pc: PrincOps.BytePC _ [0], section: Section _ NIL]; SetBreak: PROC [section: Section, condProc: FastBreak.FastBreakProc, type: SpyOps.StackType _ ready, data: REF _ NIL, exitIfEntry: BOOL _ FALSE] RETURNS [break: Break] = { exit: BOOL _ 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 { parent: 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 # ready AND data = NIL THEN break.data _ @break.type; -- for user defined types break.section _ section; break.exit _ exit; }; SectionFromName: PROC [name: ROPE, sourceIndex: INT _ 0] RETURNS [section: Section] = { dotIndex: INT; module: Section; moduleContext: AMModel.Context; moduleName, procName: ROPE; FindProcedure: PROC [proc: Section] RETURNS [stop: BOOL] = { name: 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: BOOL _ 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 IO.PutRope[stream, "exit of "] ELSE IO.PutRope[stream, "entry of "]; IO.PutRope[stream, AMModel.SectionName[break.section]]; }; statement => { parent: Section _ AMModel.ParentSection[break.section]; parentName: ROPE _ AMModel.SectionName[parent]; entry, procEntry: LIST OF AMModelLocation.CodeLocation; IF break.exit THEN { IO.PutRope[stream, "exit of "]; IO.PutRope[stream, parentName]; 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 { IO.PutRope[stream, "entry of "]; IO.PutRope[stream, parentName]; RETURN; }; ENDLOOP; ENDLOOP; PrintSource[stream, break.section, AMModel.SectionName[parent]]; }; ENDCASE => PrintSource[stream, break.section, AMModel.SectionName[break.section]]; }; PrintSource: PROC [stream: STREAM, section: Section, proc: 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; }; }.. HSpyBreaksImpl.mesa Copyright Σ 1985, 1986, 1987 by Xerox Corporation. All rights reserved. John Maxwell on: November 28, 1983 10:52 am Russ Atkinson (RRA) February 16, 1987 11:36:50 am PST Mike Spreitzer September 23, 1986 9:01:40 pm PDT Start and Stop breaks User Breaks safe storage allocation permanent safe storage allocation unsafe storage allocation data: FastBreakData, frame: PrincOps.FrameHandle, sv: PrincOps.SVPointer] Utility procedures see if this is an entry statement. If it is, use the exit statement. print user breaks print start and stop breaks stop breaks ΚŒ˜codešœ™KšœH™HKšœ+™+K™5K™0—˜šΟk ˜ Kšœœ΅˜ΒKšœœ/˜DKšœœ˜Kšœ œK˜ZKšœœ#œœ˜8Kšœ œ˜'Kšœœœ ˜4Kšœ œΟc ˜!Kšœœ˜"Kšœœg˜sKšœœ˜——K˜head2šœœ˜Kšœ'œ˜OKšœ˜—˜Kšœœœ˜Kšœ œ˜ Kšœœœœ˜—šœ™Kšœ œœ œ˜ Kšœœ˜%K˜šΟnœœœ˜Kšœ!˜!Kš œ œœœœœ˜AKšœ˜K˜—šŸœœœ˜Kšœ7˜7Kš œœœœœœ˜LK˜Kšœ˜—K˜šŸ œœœ˜šœ'˜,Kšœ œœœ˜Kšœ'˜'Kšœ˜—Kšœ˜K˜—š ŸœœœœUœ˜—KšœœC˜NKšœ;˜;Kš œœœœœ˜'K˜K˜—šŸœœœœ˜œ˜F———Kšœœœ˜—Kš œ œœœœ˜#Kš œœ6œ œœœ˜|K˜Kš œœœœž˜WKšœ˜Kšœ˜Kšœ˜—K˜š Ÿœœœœœ˜WKšœ œ˜Kšœ˜Kšœ˜Kšœœ˜šŸ œœœœ˜