-- Cedar Remote Debugging: MapLog handling -- WVMMapLog.mesa -- Andrew Birrell August 2, 1983 1:35 pm DIRECTORY CPSwapDefs USING[ ExternalStateVector, SwapInfo ], DebuggerFormat USING[ ExternalStateVector, Run, SwapInfo, VersionID, VMRunTable ], DeviceTypes USING[ sa4000 ], PSB USING[ PDA ], VMMapLog, WorldVM USING[Address, CopyRead, World], WVMPrivate; WVMMapLog: MONITOR IMPORTS WorldVM, WVMPrivate EXPORTS WVMPrivate, WorldVM = BEGIN MapLogObject: PUBLIC TYPE = RECORD[ found: CARDINAL _ 0, -- maplog entries read in so far -- entries: REF DebuggerFormat.VMRunTable]; MapLog: TYPE = REF MapLogObject; CreateMapLog: PUBLIC PROC[world: WorldVM.World] RETURNS[ MapLog ] = BEGIN RETURN[NEW[MapLogObject _ [0,NIL]]] END; oldESVVersion: CARDINAL = 08130; -- Rubicon Pilot ESV format ReadMapLog: PUBLIC PROC[world: WorldVM.World, log: MapLog] RETURNS[patchTable, loadState: WorldVM.Address] = BEGIN swapInfo: DebuggerFormat.SwapInfo; swapInfoAddr: WorldVM.Address = LOOPHOLE[@PSB.PDA.available]; esv: DebuggerFormat.ExternalStateVector; esvAddr: WorldVM.Address; WorldVM.CopyRead[world, swapInfoAddr, SIZE[DebuggerFormat.SwapInfo], @swapInfo]; esvAddr _ LOOPHOLE[swapInfo.externalStateVector]; WorldVM.CopyRead[world, esvAddr, SIZE[DebuggerFormat.ExternalStateVector], @esv]; loadState _ WVMPrivate.PageAddress[esv.loadstatepage]; SELECT esv.versionident FROM oldESVVersion => patchTable _ GetPilotMapLog[world, LOOPHOLE[@esv], log]; DebuggerFormat.VersionID => BEGIN IF esv.vmRunTable # NIL THEN BEGIN temp: ARRAY [0..SIZE[DebuggerFormat.VMRunTable[0]]) OF WORD; cheat: POINTER TO DebuggerFormat.VMRunTable = LOOPHOLE[@temp]; WorldVM.CopyRead[world, LOOPHOLE[esv.vmRunTable, WorldVM.Address], SIZE[DebuggerFormat.VMRunTable[0]], @temp ]; log.entries _ NEW[DebuggerFormat.VMRunTable[cheat.length]]; WorldVM.CopyRead[world, LOOPHOLE[esv.vmRunTable, WorldVM.Address], SIZE[DebuggerFormat.VMRunTable[cheat.length]], LOOPHOLE[log.entries, LONG POINTER] ]; log.found _ log.entries.nRuns; END; patchTable _ LOOPHOLE[LONG[NIL]]; END; ENDCASE => patchTable _ LOOPHOLE[LONG[NIL]]; -- treat as if there was no maplog END; GetPilotMapLog: PROC[world: WorldVM.World, esv: POINTER TO CPSwapDefs.ExternalStateVector, log: MapLog] RETURNS[patchTable: WorldVM.Address] = BEGIN descr: VMMapLog.Descriptor; descrAddr: WorldVM.Address = LOOPHOLE[esv.mapLog]; logBase: WorldVM.Address; logSize: CARDINAL; -- number of entries, excluding self -- mapLogEntry: VMMapLog.Entry; Translate: PROC = BEGIN WITH entry: mapLogEntry SELECT FROM disk => BEGIN log.entries[log.found] _ [ page: mapLogEntry.page, count: mapLogEntry.count, deviceType: DeviceTypes.sa4000, deviceOrdinal: 0, diskPage: [entry.diskPage], labelCheck: entry.labelCheck ]; log.found _ log.found+1; END; ENDCASE => NULL; END; WorldVM.CopyRead[world, descrAddr, SIZE[VMMapLog.Descriptor], @descr]; patchTable _ LOOPHOLE[descr.patchTable]; logBase _ WVMPrivate.PageAddress[descr.self.page]; logSize _ LOOPHOLE[descr.limit, CARDINAL] / SIZE[VMMapLog.Entry]; log.entries _ NEW[DebuggerFormat.VMRunTable[logSize+1--self--]]; log.found _ 0; mapLogEntry _ descr.self; Translate[]; IF logBase # 0 AND logSize > 0 THEN FOR a: WorldVM.Address _ logBase+LOOPHOLE[descr.reader,CARDINAL], a+SIZE[VMMapLog.Entry] UNTIL a = logBase+LOOPHOLE[descr.writer,CARDINAL] DO WorldVM.CopyRead[world, a, SIZE[VMMapLog.Entry], @mapLogEntry]; Translate[]; ENDLOOP; END; LocalPatchTable: PUBLIC PROC RETURNS[patchTable: WorldVM.Address] = BEGIN swapInfo: LONG POINTER TO CPSwapDefs.SwapInfo = LOOPHOLE[@PSB.PDA.available]; descr: LONG POINTER TO VMMapLog.Descriptor = swapInfo.externalStateVector.mapLog; RETURN[LOOPHOLE[descr.patchTable]] END; AddressFault: PUBLIC ERROR[mempage: WVMPrivate.PageNumber] = CODE; lastEntryIndex: CARDINAL _ 0; -- hint for log entry to try first -- GetMapLogEntry: PUBLIC ENTRY PROC[log: MapLog, mempage: WVMPrivate.PageNumber] RETURNS[ WVMPrivate.DiskAddress ] = BEGIN ENABLE UNWIND => NULL; entry: LONG POINTER TO DebuggerFormat.Run _ IF lastEntryIndex IN [0..log.found) -- lastEntryIndex may be for another log! THEN @log.entries[lastEntryIndex] ELSE NIL; IF entry = NIL OR mempage NOT IN [entry.page..entry.page+entry.count) THEN -- sigh! Need to search for it. -- BEGIN FOR i: CARDINAL IN [0..log.found) DO entry _ @log.entries[lastEntryIndex_i]; IF mempage IN [entry.page..entry.page+entry.count) THEN EXIT; REPEAT FINISHED => ERROR AddressFault[mempage] ENDLOOP; END; RETURN[[entry.deviceType, entry.deviceOrdinal, entry.diskPage, mempage-entry.page, entry.labelCheck]]; END; END.