Debugging tools are generally allowed to violate abstraction in most (all?) language systems. Abstraction in Keykos was designed to protect proprietary assets, even of those whose code had bugs. We designed our debugger, a first cousin of gdb, to respect abstraction boundaries, indeed the debugger lacked the authority to transgress boundaries. Synergy often played a role here. If you allow me to use one of your objects, but not to see inside it, then I may find a situation where that object misbehaves due to your bug. If I cannot demonstrate the bug without revealing my secrets then we may be at an impasse. More often I can drive your object to the broken state so that I have nothing to loose if you see that state. I send you my cap X for the object that obeys your code. In many capability systems you would be no more able to open the object than I. X is as opaque to you as it is to me. The abstraction wall, imposed by factory logic, keeps you out just as it does me. To make a long story short you still have the ‘builder’s capability’ that you got when you created the factory from which I got the object. You can send X to the builder’s cap asking “Did you make this”. In this scenario the answer would be yes accompanied by a cap to the innards of the broken object. You can now use gdb to inspect the real object state. This is only because I gave you my cap, X, to the object, however.

This may sound like excessive folderol but we found that dividing the debugging task along abstraction boundaries a good discipline. The programmer is encouraged to stick to his abstractions and fix the root bugs. Occasionally there would be several gdb’s open at once on some collection of confused abstraction boundaries. One object type, the can opener held a collection of these builder’s keys for developers whose expertise spanned boundaries. You could ask of it, “What sort of thing is this a cap to?”.
Much more about Keykos debugging