Exception handling

The manual has some information on this. Here's some more.

UUOs (by gb)


On the DEC PDP-10, the acronym UUO stood for "Unimplemented User Operation"; UUOs were used to invoke system services and/or to invoke what we'd think of as exception handlers. [...] As it's used in CCL, the term just means "an illegal instruction that'll ultimately cause a lisp-aware handler function to be called."

Implementation details

Executing an "int $n" (#xcd n) instruction transfers control to an entry insome (incredibly complex and baroque) table of handlers maintained by the chip. The OS might use a few entries in this table to implement system calls (though modern x86 CPUs often have faster ways of doing system calls), and some entries are reserved for hardware- related interrupts.

Trying to execute an "int $n" instruction that doesn't have a defined entry in this table causes a General Protection Fault, and this eventually causes (on Unix) a signal to be raised. Exactly what signal depends on the OS; there's a macro called SIGNUM_FOR_INTN_TRAP defined conditionally in ccl/lisp-kernel/x86-exceptions.h that defines this. As you can see, it's generally overloaded on SIGBUS or SIGSEGV, which usually indicates an addressing exception (yes, SIGILL would make more sense, but since it involves a GP fault an undefined "int $n" winds up taking the same path as a memory protection fault) and we need to look at other arguments to the signal handler (as defined by the IS_MAYBE_INT_TRAP macro: if IS_MAYBE_INT_TRAP is true, we believe that we can look at the the byte that the PC in the signal context is pointing to to see if it's #xcd; if not, the SIGSEGV or SIGBUS might have been caused by trying to execute code at an unmapped address.)

We also use "ud2a" instructions (followed by a byte or more of data) for similar purposes, but "int $n" is generally shorter; illegal instructions that use the ud2a opcode (which generally -does- raise SIGILL when executed) are sometimes called "xuuos" (eXtended UUOs).

Once in a while (when doing a port to a new OS), we've found that the OS uses an interrupt that we've previously considered free for our use, and have had to do things differently (reassign UUOs or avoid emitting conflicting ones.) I suppose that that could happen if we ported to some other OS (NetBSD ?), but it's unlikely that x8632 OSes will invoke new functionality via "int $n" (since other means of doing system calls are generally faster/better.) See the comment in x86-asm.lisp:

;;; DON'T use #xcd8x: doing so will make Mach angry and confused.