Mangers come in (for now) five flavors:
normal for ordinary instructions (non-delayed control transfers),
branch for simple delayed control transfers,
call for call instructions,
jmplO7 for jmpl's that use %o7 as their destination (e.g. indirect calls).
jmplG0 for jmpl's that use %g0 as their destination (e.g. returns).
The tag for which kind of manger it is is kept in a ``sethi %lo(tag), %g0'' instruction in the last instruction of the manger. The tag is used to figure out how to put the original instruction back when the breakpoint is removed.
Normal instruction stream: becomes: normal manger:
sheep ba,a patch sheep
continue: continue: ba,a continue
-- This is the easy case, we just jump to the patch to exeucte the instruction.
Branch instruction stream: becomes: branch manger:
bicc target ba,a patch bicc target
delaySlot delaySlot delaySlot
continue: continue: ba,a continue
-- With a simple delay slot, we just jump to a copy (relocated) of the instruction and its delay slot. If the branch falls through, we just transfer back to the main code stream.
Call instruction stream: becomes: call manger:
call target call patch sethi %hi(target), %g1
delaySlot delaySlot jmpl %g1+%lo(target), %g0
noop
-- The trick here is to call the patch, thus setting up the return address because the callee probably uses it (e.g. to return, or return aggregate results, etc.). We allow the instruction in the delay slot to execute (what if it messes with the return address? So be it, that's what it wanted to do.). In the manger, we move the target address to %g1 (which I think is free at this point), and then jmpl to the callee without setting the return address.
JmplO7 instruction stream: becomes: jmplO7 manger:
jmpl target, %o7 call patch jmpl target, %g0
delaySlot delaySlot noop
-- Again, the trick here is to call the patch, thus setting up the return address because the callee probably uses it (e.g. to return, or return aggregate results, etc.). We allow the instruction in the delay slot to execute. In the manger, we jmpl to the callee without setting the return address.
JmplG0 instruction stream: becomes: jmplG0 manger:
jmpl target, %g0 ba,a patch jmpl target, %g0
delaySlot delaySlot delaySlot
-- ``jmpl target, %g0'' has a standard abbreviation of just ``jmp target'', and there are standard abbreviations of ``ret'' and ``retl'' for ``jmp %i7+8'' and ``jmp %o7+8''.
-- This is just a computed delayed transfer. We branch to a copy of the instruction and it's delay slot, as in the branch instruction case, above, excpet this isn't a conditional branch.
Procedures
Install:
PROCEDURE [
address: BreakWorldArchitecture.Address,
manger: BreakWorldArchitecture.Address,
patchCode: BreakWorldArchitecture.Address]
RETURNS [];
Uninstall:
PROCEDURE [
address: BreakWorldArchitecture.Address,
manger: BreakWorldArchitecture.Address,
patchCode: BreakWorldArchitecture.Address]
RETURNS [];
}.