// SwatBreak.bcpl - break points // Copyright Xerox Corporation 1979, 1982 // Last modified April 11, 1982 12:22 AM by Boggs get "Swat.decl" external [ // outgoing procedures InitBreak; IsBreak; CheckAllBreaks BreakSwapOut; BreakSwapIn BreakSysOut; BreakSysIn SetBreak; DelBreak; DelAllBreaks PrintBreak; PrintAllBreaks // incoming procedures AddrToSym; BuildSI ReportFail; VMFetch; VMStore PutTemplate; Ws Endofs; Gets; Puts ReadBlock; WriteBlock Allocate; Free; Zero Enqueue; Unqueue // incoming statics sysZone; dsp ] static [ bpQ // -> queue of active breakpoints nextBrkNum ] //---------------------------------------------------------------------------- structure BP: // BreakPoint //---------------------------------------------------------------------------- [ link word // must be first oneShot word // true if it should be deleted when hit mpbp word // -> mpbp in user space (zero => not mpbp) brkNum word // breakpoint number brkAddr word // address of this breakpoint brokenIns word // instruction which was replaced by bp trap ] manifest lenBP = size BP/16 //---------------------------------------------------------------------------- structure MPBP: // Multiple Proceed Break Point //---------------------------------------------------------------------------- [ si word lenSI brkAddr word // break address for this MPBP (0 => mpbp is free) brkCnt word // proceed count ] compileif size MPBP/16 ne lenSI+2 then [ Error("Change lenMPBP declaration in Swat.decl") ] //---------------------------------------------------------------------------- let InitBreak() be [ bpQ = Allocate(sysZone, 2); bpQ!0 = 0 ] //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- and IsBreak(addr) = valof //---------------------------------------------------------------------------- [ let bp = bpQ!0; while bp ne 0 do [ if bp>>BP.brkAddr eq addr resultis true bp = bp>>BP.link ] resultis false ] //---------------------------------------------------------------------------- and CheckAllBreaks(addr) = valof //---------------------------------------------------------------------------- [ let bp = bpQ!0; while bp ne 0 do [ let link = bp>>BP.link test VMFetch(bp>>BP.brkAddr) eq bp>>BP.brokenIns //did it vanish? ifnot DelBreak(bp>>BP.brkAddr, false) ifso if bp>>BP.brkAddr eq addr test bp>>BP.oneShot ifso DelBreak(bp>>BP.brkAddr, false) ifnot [ if bp>>BP.mpbp ne 0 & VMFetch(bp>>BP.mpbp+offset MPBP.brkCnt/16) eq 0 then [ // downgrade to vanilla breakpoint bp>>BP.mpbp = 0 VMStore(bp>>BP.mpbp+offset MPBP.brkAddr/16, 0) ] PrintBreak(bp) ] bp = link ] ] //---------------------------------------------------------------------------- and PrintBreak(bp, noCR; numargs na) be //---------------------------------------------------------------------------- [ PutTemplate(dsp, "BreakPoint $UO at $P", bp>>BP.brkNum, AddrToSym, bp>>BP.brkAddr) if bp>>BP.mpbp ne 0 then PutTemplate(dsp, ", $UO proceeds left", VMFetch(bp>>BP.mpbp+offset MPBP.brkCnt/16)) unless na gr 1 & noCR do Puts(dsp, $*N) ] //---------------------------------------------------------------------------- and PrintAllBreaks() be //---------------------------------------------------------------------------- [ let bp = bpQ!0; while bp ne 0 do [ PrintBreak(bp) bp = bp>>BP.link ] ] //---------------------------------------------------------------------------- and BreakSwapOut() be //---------------------------------------------------------------------------- // User is about to get control. [ let bp = bpQ!0; while bp ne 0 do [ if VMFetch(bp>>BP.brkAddr) eq bp>>BP.brokenIns then VMStore(bp>>BP.brkAddr, (bp>>BP.mpbp? mpBrkPtTrap, breakPtTrap)) bp = bp>>BP.link ] ] //---------------------------------------------------------------------------- and BreakSwapIn() be //---------------------------------------------------------------------------- // We just got control. [ let bp = bpQ!0; while bp ne 0 do [ test VMFetch(bp>>BP.brkAddr) eq (bp>>BP.mpbp? mpBrkPtTrap, breakPtTrap) ifso VMStore(bp>>BP.brkAddr, bp>>BP.brokenIns) ifnot bp>>BP.brokenIns = 0 bp = bp>>BP.link ] ] //---------------------------------------------------------------------------- and BreakSysOut(sysOut) be //---------------------------------------------------------------------------- [ // count the breakpoints let count, bp = 0, bpQ!0 while bp ne 0 do [ count = count +1 bp = bp>>BP.link ] // write them on the SysOut file Puts(sysOut, count) bp = bpQ!0; while bp ne 0 do [ WriteBlock(sysOut, bp, lenBP) bp = bp>>BP.link ] ] //---------------------------------------------------------------------------- and BreakSysIn(sysIn) be //---------------------------------------------------------------------------- [ DelAllBreaks() // read SysIn file's breakpoint list let count = Endofs(sysIn)? 0, Gets(sysIn) for i = 1 to count do [ let bp = Allocate(sysZone, lenBP) ReadBlock(sysIn, bp, lenBP) bp>>BP.mpbp = 0 // ahem Enqueue(bpQ, bp) ] ] //---------------------------------------------------------------------------- and SetBreak(addr, oneShot, proceedCnt; numargs na) be //---------------------------------------------------------------------------- [ if IsBreak(addr) then ReportFail("Already broken") let mpbp = valof [ if na ls 3 resultis 0 let p = VMFetch(567B) + mpbpOffset for i = 1 to numMPBP do [ if VMFetch(p+offset MPBP.brkAddr/16) eq 0 then [ let si = vec lenSI; BuildSI(si, VMFetch(addr)) for j = 0 to lenSI-1 do VMStore(p+j, si!j) VMStore(p+offset MPBP.brkAddr/16, addr) VMStore(p+offset MPBP.brkCnt/16, proceedCnt) resultis p ] p = p + lenMPBP ] ReportFail("Multiple proceed break point table full") ] let bp = Allocate(sysZone, lenBP) bp>>BP.brkNum = nextBrkNum nextBrkNum = nextBrkNum +1 bp>>BP.oneShot = na ls 2? false, oneShot bp>>BP.brkAddr = addr bp>>BP.brokenIns = VMFetch(addr) bp>>BP.mpbp = mpbp PrintBreak(bp) Enqueue(bpQ, bp) ] //---------------------------------------------------------------------------- and DelBreak(arg, num) be //---------------------------------------------------------------------------- // arg is a breakpoint number if num is true, else an addr [ let bp = bpQ!0; while bp ne 0 do [ if arg eq (num? bp>>BP.brkNum, bp>>BP.brkAddr) then [ Unqueue(bpQ, bp) PrintBreak(bp, true) Ws(" deleted*N") if bp>>BP.mpbp ne 0 then VMStore(bp>>BP.mpbp+offset MPBP.brkAddr/16, 0) Free(sysZone, bp) return ] bp = bp>>BP.link ] ReportFail("Break not found") ] //---------------------------------------------------------------------------- and DelAllBreaks() be //---------------------------------------------------------------------------- [ // The following code is redundant if the breakpoint machinery is working // correctly, and causes a deadlock when detaching from a non-responding // network virtual address space. // let mpbp = VMFetch(567B) + mpbpOffset // for i = 1 to numMPBP do // [ // VMStore(mpbp + offset MPBP.brkAddr/16, 0) // mpbp = mpbp + lenMPBP // ] until bpQ!0 eq 0 do DelBreak((bpQ!0)>>BP.brkAddr, false) nextBrkNum = 0 ]