At present, on the PowerPC port, undefined function errors aren't being
terribly well reported:
debugger invoked on condition of type SB-KERNEL:CASE-FAILURE:
#C(2.1219957648426468d-314 5.968123474651662d-315) fell through ETYPECASE expression.
Wanted one of (SB-KERNEL:FDEFN SYMBOL).
Clearly this isn't ideal...
I believe I have a fix, and since it's somewhat involved and the trail
led me to the explanation of some magical constants, I'll explain the
reasoning in a certain amount of detail. Perhaps, though, I can improve
my reputation by presenting the diff first:
--- src/runtime/ppc-assem.S 18 Mar 2002 17:59:37 -0000 1.1
+++ src/runtime/ppc-assem.S 17 Jul 2002 17:08:59 -0000
@@ -360,7 +359,7 @@
- .byte 254, 140, 2 /* 140? sparc says sc_descriptorReg */
+ .byte 254, sc_DescriptorReg+0x40, 1
1: lwz reg_CODE,FDEFN_RAW_ADDR_OFFSET(reg_FDEFN)
Pretty neat, huh? Now, how on /earth/ did I come up with this?
We get booted into assembly (into this trampoline function, undefined_tramp)
when we attempt to call an undefined function. We start executing at the
"twllei" line above, which causes the program to receive a SIGTRAP, and thus go
to the sigtrap_handler defined in ppc-arch.c, and eventually back into lisp
into internal error handlers defined in src/code/interr.lisp. The handler for
undefined-fun-error takes one argument, which is either a symbol or an fdefn
(incidentally explaining the error message above, about ETYPECASE failure) and
passes that as the :NAME initarg to the undefined-function lisp-level error.
How does the lisp system find the argument? After all, all attempts to execute
undefined functions, no matter what their names, end here. Well, after the trap
instruction comes one byte, which code in src/code/ppc-vm.lisp interprets as
the number of following bytes to read. In this case, there are four; the first
is the type of the error that we are hitting (UNDEFINED_FUN_ERROR), so that
lisp can dispatch to the appropriate handler. The remaining three bytes must
therefore carry the information required to find the function name.
At this point, I had no choice but to grovel some code. The system reads off
the arguments as integers. However, 254 is a magical flag, saying "read the
next two bytes, shifting the /second/ by 8". (255 is similar, but for four
bytes). Thus, the remaining three bytes actually make up only one integer. With
sc_DescriptorReg being 14, the number in question is 0x40 + 14 + 0x100 = 334
(or 101001110 in binary). This is then interpreted as an SC-OFFSET; we want it
to be treated as a DescriptorReg, as we are going to be getting a descriptor
object; what next? Well, the remaining 22 bits of an SC-OFFSET (the
SC-OFFSET-OFFSET; see src/code/sc-offset.lisp) are treated as a register
number, and the os_context_t object is grovelled for the register content! So,
then, it was simple to examine what the sparc port did (it grabbed reg_CNAME,
for "current function name") and copy that logic. Of course, logic being what
it is, that didn't work, because the ppc backend actually uses reg_FDEFN for
that (see src/compiler/ppc/call.lisp, the DEFINE-FULL-CALL macro), but once I'd
spotted that and made the necessary adjustment (reg_FDEFN is 10 on the PPC
port), it worked fine :-)
So there you have it.
Jesus College, Cambridge, CB5 8BL +44 1223 510 299
http://www-jcsu.jesus.cam.ac.uk/~csr21/ (defun pling-dollar
(str schar arg) (first (last +))) (make-dispatch-macro-character #\! t)
(set-dispatch-macro-character #\! #\$ #'pling-dollar)