// 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
]